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 of the majority of codec time units (70ms is the nominal
DTMF tone length for most systems). */ DTMF tone length for most systems). */
unsigned char code = digit <<4; 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 */ /* Called when we have received an entire data sample */
c->state=MONITOR_STATE_COMMAND; 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); struct vomp_call_state *call=vomp_find_call_by_session(c->sample_call_session_token);
if (!call) { if (!call) {
write_str(c->alarm.poll.fd,"\nERROR:No such call\n"); write_str(c->alarm.poll.fd,"\nERROR:No such call\n");
RETURN(-1); 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); RETURN(0);
} }

View File

@ -1009,13 +1009,6 @@ void _serval_debug_free(void *p,char *file,const char *func,int line);
#endif #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;
struct vomp_call_state *vomp_find_call_by_session(int session_token); struct vomp_call_state *vomp_find_call_by_session(int session_token);
int vomp_mdp_received(overlay_mdp_frame *mdp); 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_pickup(struct vomp_call_state *call);
int vomp_hangup(struct vomp_call_state *call); int vomp_hangup(struct vomp_call_state *call);
int vomp_ringing(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 { 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; 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 vomp_call_state {
struct sched_ent alarm; struct sched_ent alarm;
struct vomp_call_half local; struct vomp_call_half local;
@ -115,7 +123,7 @@ struct vomp_call_state {
int last_sent_status; int last_sent_status;
unsigned char remote_codec_list[256]; unsigned char remote_codec_list[256];
int recent_sample_rotor; 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; int sample_pos;
unsigned int seen_samples[VOMP_MAX_RECENT_SAMPLES *4]; 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 /* send updated call status to end-point and to any interested listeners as
appropriate */ 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; overlay_mdp_frame mdp;
unsigned short *len=&mdp.out.payload_length; 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; mdp.out.payload[(*len)++]=0;
if (call->initiated_call){ if (call->initiated_call){
didLen = snprintf((char *)(mdp.out.payload + *len), sizeof(mdp.out.payload) - *len, "%s",call->local.did); DEBUGF("Sending phone numbers %s, %s",call->local.did,call->remote.did);
*len+=didLen; 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); 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) if (debug & DEBUG_VOMP)
DEBUGF("mdp frame with codec list is %d bytes", mdp.out.payload_length); 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]; 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. /* stuff frame with most recent sample blocks as a form of preemptive
XXX - What timestamp to attach to the sample? 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: Two obvious choices:
1. The sample is for the most recent n milliseconds; or 1. The sample is for the most recent n milliseconds; or
2. The sample is for the next n milliseconds following the 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, recorder of audio. Basically if the audio queue starts to bank up,
then the player needs to drop samples. 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].codec=audio_codec;
sb[rotor].endtime=call->audio_clock+vomp_codec_timespan(sb[rotor].codec)-1; sb[rotor].endtime=call->audio_clock+vomp_codec_timespan(sb[rotor].codec)-1;
sb[rotor].starttime=call->audio_clock; sb[rotor].starttime=call->audio_clock;
call->audio_clock=sb[rotor].endtime+1; call->audio_clock=sb[rotor].endtime+1;
bcopy(audio,&sb[rotor].bytes[0],audio_length); }else if(sb[rotor].codec!=audio_codec){
WHY("Did not finish previous audio buffer!!");
/* 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;
} }
/* XXX Here we act as our own client. This used to be able to block. int copy_size = (audio_length - offset);
We should really refactor overlay_mdp_poll() so that we can deliver if (copy_size > codec_block_size - sb[rotor].len)
the frame directly. copy_size=codec_block_size - sb[rotor].len;
Make sure that we don't want (just drop the message if there is
congestion) */
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; 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) int monitor_call_status(struct vomp_call_state *call)
{ {
char msg[1024]; 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){ int vomp_ringing(struct vomp_call_state *call){
if (call){ if (call){
if ((!call->initiated_call) && call->local.state<VOMP_STATE_RINGINGIN && call->remote.state==VOMP_STATE_RINGINGOUT){
if (debug & DEBUG_VOMP) if (debug & DEBUG_VOMP)
DEBUGF("RING RING!"); 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_local_state(call, VOMP_STATE_RINGINGIN);
vomp_update(call); vomp_update(call);
} }else
return WHY("Can't ring, call is not being dialled");
} }
return 0; return 0;
} }
@ -657,13 +694,14 @@ int vomp_pickup(struct vomp_call_state *call)
if (call){ if (call){
if (debug & DEBUG_VOMP) if (debug & DEBUG_VOMP)
DEBUG("Picking up"); DEBUG("Picking up");
if (call->local.state!=VOMP_STATE_RINGINGIN) if (call->local.state<=VOMP_STATE_RINGINGIN && call->remote.state==VOMP_STATE_RINGINGOUT){
return WHY("Call is not ringing");
vomp_update_local_state(call, VOMP_STATE_INCALL); vomp_update_local_state(call, VOMP_STATE_INCALL);
call->create_time=gettime_ms(); call->create_time=gettime_ms();
/* state machine does job of starting audio stream, just tell everyone about /* state machine does job of starting audio stream, just tell everyone about
the changed state. */ the changed state. */
vomp_update(call); vomp_update(call);
}else
return WHY("Can't pickup, call is not ringing");
} }
return 0; return 0;
} }
@ -693,7 +731,7 @@ int vomp_extract_remote_codec_list(struct vomp_call_state *call,overlay_mdp_fram
if (!call->initiated_call){ if (!call->initiated_call){
ofs++; ofs++;
if (ofs<mdp->in.payload_length) 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) if (ofs<mdp->in.payload_length)
ofs+=strlcpy(call->local.did, (char *)(mdp->in.payload+ofs), sizeof(call->local.did)); ofs+=strlcpy(call->local.did, (char *)(mdp->in.payload+ofs), sizeof(call->local.did));
} }