mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-07 03:29:15 +00:00
Allow for audio to arrive in variable sized blocks
This commit is contained in:
parent
e69a492c2b
commit
dcb2da45fa
10
monitor.c
10
monitor.c
@ -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);
|
||||||
}
|
}
|
||||||
|
9
serval.h
9
serval.h
@ -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 {
|
||||||
|
140
vomp.c
140
vomp.c
@ -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){
|
||||||
|
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);
|
didLen = snprintf((char *)(mdp.out.payload + *len), sizeof(mdp.out.payload) - *len, "%s", call->local.did);
|
||||||
*len+=didLen;
|
*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));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user