Allow for audio to arrive in variable sized blocks

This commit is contained in:
Jeremy Lakeman 2012-08-13 16:15:10 +09:30
parent e69a492c2b
commit dcb2da45fa
3 changed files with 107 additions and 82 deletions

View File

@ -462,7 +462,7 @@ int monitor_process_command(struct monitor_context *c)
of the majority of codec time units (70ms is the nominal
DTMF tone length for most systems). */
unsigned char code = digit <<4;
vomp_send_status_remote_audio(call, VOMP_CODEC_DTMF, &code, 1);
vomp_received_audio(call, VOMP_CODEC_DTMF, &code, 1);
}
}
}
@ -479,19 +479,13 @@ int monitor_process_data(struct monitor_context *c)
/* Called when we have received an entire data sample */
c->state=MONITOR_STATE_COMMAND;
if (vomp_sample_size(c->sample_codec)!=c->data_offset) {
WARNF("Ignoring sample block of incorrect size (expected %d, got %d bytes for codec %d)",
vomp_sample_size(c->sample_codec), c->data_offset, c->sample_codec);
RETURN(-1);
}
struct vomp_call_state *call=vomp_find_call_by_session(c->sample_call_session_token);
if (!call) {
write_str(c->alarm.poll.fd,"\nERROR:No such call\n");
RETURN(-1);
}
vomp_send_status_remote_audio(call, c->sample_codec, &c->buffer[0], vomp_sample_size(c->sample_codec));
vomp_received_audio(call, c->sample_codec, &c->buffer[0], vomp_sample_size(c->sample_codec));
RETURN(0);
}

View File

@ -1009,13 +1009,6 @@ void _serval_debug_free(void *p,char *file,const char *func,int line);
#endif
typedef struct vomp_sample_block {
unsigned int codec;
time_ms_t starttime;
time_ms_t endtime;
unsigned char bytes[1024];
} vomp_sample_block;
struct vomp_call_state;
struct vomp_call_state *vomp_find_call_by_session(int session_token);
int vomp_mdp_received(overlay_mdp_frame *mdp);
@ -1027,7 +1020,7 @@ int vomp_dial(unsigned char *local_sid, unsigned char *remote_sid, char *local_d
int vomp_pickup(struct vomp_call_state *call);
int vomp_hangup(struct vomp_call_state *call);
int vomp_ringing(struct vomp_call_state *call);
int vomp_send_status_remote_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length);
int vomp_received_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length);
typedef struct command_line_option {

142
vomp.c
View File

@ -101,6 +101,14 @@ struct vomp_call_half {
unsigned long long milliseconds_since_call_start;
};
struct vomp_sample_block {
unsigned int codec;
int len;
time_ms_t starttime;
time_ms_t endtime;
unsigned char bytes[1024];
};
struct vomp_call_state {
struct sched_ent alarm;
struct vomp_call_half local;
@ -115,7 +123,7 @@ struct vomp_call_state {
int last_sent_status;
unsigned char remote_codec_list[256];
int recent_sample_rotor;
vomp_sample_block recent_samples[VOMP_MAX_RECENT_SAMPLES];
struct vomp_sample_block recent_samples[VOMP_MAX_RECENT_SAMPLES];
int sample_pos;
unsigned int seen_samples[VOMP_MAX_RECENT_SAMPLES *4];
@ -274,7 +282,7 @@ struct vomp_call_state *vomp_find_or_create_call(unsigned char *remote_sid,
/* send updated call status to end-point and to any interested listeners as
appropriate */
int vomp_send_status_remote_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length)
int vomp_send_status_remote(struct vomp_call_state *call)
{
overlay_mdp_frame mdp;
unsigned short *len=&mdp.out.payload_length;
@ -319,23 +327,74 @@ int vomp_send_status_remote_audio(struct vomp_call_state *call, int audio_codec,
mdp.out.payload[(*len)++]=0;
if (call->initiated_call){
didLen = snprintf((char *)(mdp.out.payload + *len), sizeof(mdp.out.payload) - *len, "%s",call->local.did);
*len+=didLen;
DEBUGF("Sending phone numbers %s, %s",call->local.did,call->remote.did);
didLen = snprintf((char *)(mdp.out.payload + *len), sizeof(mdp.out.payload) - *len, "%s", call->local.did);
*len+=didLen+1;
didLen = snprintf((char *)(mdp.out.payload + *len), sizeof(mdp.out.payload) - *len, "%s", call->remote.did);
*len+=didLen;
*len+=didLen+1;
}
if (debug & DEBUG_VOMP)
DEBUGF("mdp frame with codec list is %d bytes", mdp.out.payload_length);
}
if (call->local.state==VOMP_STATE_INCALL && audio && audio_length && vomp_sample_size(audio_codec)==audio_length) {
if (call->local.state==VOMP_STATE_INCALL) {
unsigned char *p=&mdp.out.payload[0];
struct vomp_sample_block *sb=call->recent_samples;
int rotor=call->recent_sample_rotor%VOMP_MAX_RECENT_SAMPLES;
// DEBUG("Including audio sample block");
if (sb[rotor].len==vomp_sample_size(sb[rotor].codec)){
/* write the sample end-time in milliseconds since call establishment */
p[(*len)++]=(call->audio_clock>>24)&0xff;
p[(*len)++]=(call->audio_clock>>16)&0xff;
p[(*len)++]=(call->audio_clock>>8)&0xff;
p[(*len)++]=(call->audio_clock>>0)&0xff;
/* record sample in recent list.
XXX - What timestamp to attach to the sample?
/* stuff frame with most recent sample blocks as a form of preemptive
retransmission. But don't make the packets too large. */
while (((*len)+1+sb[rotor].len) <VOMP_STUFF_BYTES && sb[rotor].len==vomp_sample_size(sb[rotor].codec)) {
p[(*len)++]=sb[rotor].codec;
bcopy(&sb[rotor].bytes[0],&p[*len],sb[rotor].len);
(*len)+=sb[rotor].len;
sb[rotor].len=0;
rotor--; if (rotor<0) rotor+=VOMP_MAX_RECENT_SAMPLES;
rotor%=VOMP_MAX_RECENT_SAMPLES;
// stop if we've run out of samples before we ran out of bytes
if ((!sb[rotor].endtime)||(sb[rotor].endtime+1==call->audio_clock)) break;
}
call->recent_sample_rotor++;
call->recent_sample_rotor%=VOMP_MAX_RECENT_SAMPLES;
}
}
/* XXX Here we act as our own client. This used to be able to block.
We should really refactor overlay_mdp_poll() so that we can deliver
the frame directly.
Make sure that we don't want (just drop the message if there is
congestion) */
overlay_mdp_dispatch(&mdp,1,NULL,0);
call->local.sequence++;
return 0;
}
// copy audio into the rotor buffers
int vomp_received_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length)
{
int codec_block_size=vomp_sample_size(audio_codec);
int offset=0;
struct vomp_sample_block *sb=call->recent_samples;
while(offset<audio_length){
int rotor=call->recent_sample_rotor%VOMP_MAX_RECENT_SAMPLES;
if (sb[rotor].len==0){
/*
What timestamp to attach to the sample?
Two obvious choices:
1. The sample is for the most recent n milliseconds; or
2. The sample is for the next n milliseconds following the
@ -351,55 +410,32 @@ int vomp_send_status_remote_audio(struct vomp_call_state *call, int audio_codec,
recorder of audio. Basically if the audio queue starts to bank up,
then the player needs to drop samples.
*/
vomp_sample_block *sb=call->recent_samples;
int rotor=call->recent_sample_rotor%VOMP_MAX_RECENT_SAMPLES;
sb[rotor].codec=audio_codec;
sb[rotor].endtime=call->audio_clock+vomp_codec_timespan(sb[rotor].codec)-1;
sb[rotor].starttime=call->audio_clock;
call->audio_clock=sb[rotor].endtime+1;
bcopy(audio,&sb[rotor].bytes[0],audio_length);
/* write the sample end-time in milliseconds since call establishment */
p[(*len)++]=(call->audio_clock>>24)&0xff;
p[(*len)++]=(call->audio_clock>>16)&0xff;
p[(*len)++]=(call->audio_clock>>8)&0xff;
p[(*len)++]=(call->audio_clock>>0)&0xff;
/* stuff frame with most recent sample blocks as a form of preemptive
retransmission. But don't make the packets too large. */
while (((*len)+1+audio_length)
<VOMP_STUFF_BYTES) {
p[(*len)++]=sb[rotor].codec;
bcopy(&sb[rotor].bytes[0],&p[*len],vomp_sample_size(sb[rotor].codec));
(*len)+=vomp_sample_size(sb[rotor].codec);
rotor--; if (rotor<0) rotor+=VOMP_MAX_RECENT_SAMPLES;
rotor%=VOMP_MAX_RECENT_SAMPLES;
// stop if we've run out of samples before we ran out of bytes
if ((!sb[rotor].endtime)||(sb[rotor].endtime+1==call->audio_clock)) break;
}
call->recent_sample_rotor++;
call->recent_sample_rotor%=VOMP_MAX_RECENT_SAMPLES;
}else if(sb[rotor].codec!=audio_codec){
WHY("Did not finish previous audio buffer!!");
}
/* XXX Here we act as our own client. This used to be able to block.
We should really refactor overlay_mdp_poll() so that we can deliver
the frame directly.
Make sure that we don't want (just drop the message if there is
congestion) */
int copy_size = (audio_length - offset);
if (copy_size > codec_block_size - sb[rotor].len)
copy_size=codec_block_size - sb[rotor].len;
overlay_mdp_dispatch(&mdp,1,NULL,0);
bcopy(audio + offset,&sb[rotor].bytes[sb[rotor].len],copy_size);
sb[rotor].len+=copy_size;
offset+=copy_size;
// send audio whenever we get the right number of bytes.
if (sb[rotor].len>=codec_block_size){
vomp_send_status_remote(call);
}
}
call->local.sequence++;
return 0;
}
int vomp_send_status_remote(struct vomp_call_state *call)
{
return vomp_send_status_remote_audio(call, 0, NULL, 0);
}
int monitor_call_status(struct vomp_call_state *call)
{
char msg[1024];
@ -580,12 +616,13 @@ int vomp_call_stop_audio(struct vomp_call_state *call)
int vomp_ringing(struct vomp_call_state *call){
if (call){
if ((!call->initiated_call) && call->local.state<VOMP_STATE_RINGINGIN && call->remote.state==VOMP_STATE_RINGINGOUT){
if (debug & DEBUG_VOMP)
DEBUGF("RING RING!");
if (call->local.state<VOMP_STATE_RINGINGIN && call->remote.state==VOMP_STATE_RINGINGOUT){
vomp_update_local_state(call, VOMP_STATE_RINGINGIN);
vomp_update(call);
}
}else
return WHY("Can't ring, call is not being dialled");
}
return 0;
}
@ -657,13 +694,14 @@ int vomp_pickup(struct vomp_call_state *call)
if (call){
if (debug & DEBUG_VOMP)
DEBUG("Picking up");
if (call->local.state!=VOMP_STATE_RINGINGIN)
return WHY("Call is not ringing");
if (call->local.state<=VOMP_STATE_RINGINGIN && call->remote.state==VOMP_STATE_RINGINGOUT){
vomp_update_local_state(call, VOMP_STATE_INCALL);
call->create_time=gettime_ms();
/* state machine does job of starting audio stream, just tell everyone about
the changed state. */
vomp_update(call);
}else
return WHY("Can't pickup, call is not ringing");
}
return 0;
}
@ -693,7 +731,7 @@ int vomp_extract_remote_codec_list(struct vomp_call_state *call,overlay_mdp_fram
if (!call->initiated_call){
ofs++;
if (ofs<mdp->in.payload_length)
ofs+=strlcpy(call->remote.did, (char *)(mdp->in.payload+ofs), sizeof(call->remote.did));
ofs+=strlcpy(call->remote.did, (char *)(mdp->in.payload+ofs), sizeof(call->remote.did))+1;
if (ofs<mdp->in.payload_length)
ofs+=strlcpy(call->local.did, (char *)(mdp->in.payload+ofs), sizeof(call->local.did));
}