From 2b7efedc483362d3afc2ae71dfb716ac5427f600 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 31 Jul 2022 07:55:14 +0200 Subject: [PATCH] Refactoring jitter buffer Features are: * Packet based buffer * Random in, first out * Adaptive delay compensation (voice) * Fixed delay (data, optionally MODEM/FAX) * Interpolation of missing frames * Any sample size --- src/amps/amps.c | 6 +- src/amps/dsp.c | 6 +- src/anetz/anetz.c | 9 +- src/anetz/dsp.c | 5 +- src/bnetz/bnetz.c | 6 +- src/bnetz/dsp.c | 6 +- src/cnetz/cnetz.c | 4 +- src/cnetz/dsp.c | 13 +- src/eurosignal/eurosignal.c | 2 +- src/fuenf/dsp.c | 6 +- src/fuenf/fuenf.c | 9 +- src/fuvst/fuvst.c | 17 +- src/fuvst/sniffer.c | 2 +- src/imts/dsp.c | 6 +- src/imts/imts.c | 6 +- src/jolly/dsp.c | 10 +- src/jolly/jolly.c | 9 +- src/jolly/voice.c | 8 +- src/libdebug/debug.c | 9 +- src/libdebug/debug.h | 2 + src/libjitter/jitter.c | 405 ++++++++++++++++++++++++++++----- src/libjitter/jitter.h | 62 ++++- src/libmobile/call.c | 4 +- src/libmobile/call.h | 2 +- src/libmobile/console.c | 20 +- src/libmobile/sender.c | 13 +- src/libmobile/sender.h | 1 + src/libosmocc/helper.c | 4 +- src/libosmocc/helper.h | 4 +- src/libosmocc/rtp.c | 11 +- src/libosmocc/session.c | 4 +- src/libosmocc/session.h | 8 +- src/libsamplerate/samplerate.h | 4 +- src/mpt1327/dsp.c | 9 +- src/mpt1327/mpt1327.c | 9 +- src/nmt/dsp.c | 6 +- src/nmt/nmt.c | 6 +- src/pocsag/pocsag.c | 2 +- src/r2000/dsp.c | 6 +- src/r2000/r2000.c | 6 +- src/radio/radio.c | 21 +- src/zeitansage/zeitansage.c | 2 +- 42 files changed, 544 insertions(+), 206 deletions(-) diff --git a/src/amps/amps.c b/src/amps/amps.c index 875c993..f140f5c 100644 --- a/src/amps/amps.c +++ b/src/amps/amps.c @@ -1065,7 +1065,7 @@ void call_down_release(int callref, int cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; amps_t *amps; @@ -1079,10 +1079,8 @@ void call_down_audio(int callref, sample_t *samples, int count) return; if (amps->dsp_mode == DSP_MODE_AUDIO_RX_AUDIO_TX) { - sample_t up[(int)((double)count * amps->sender.srstate.factor + 0.5) + 10]; compress_audio(&s->cstate, samples, count); - count = samplerate_upsample(&s->sender.srstate, samples, count, up); - jitter_save(&s->sender.dejitter, up, count); + jitter_save(&s->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } } diff --git a/src/amps/dsp.c b/src/amps/dsp.c index 445c2c3..26bc633 100644 --- a/src/amps/dsp.c +++ b/src/amps/dsp.c @@ -473,7 +473,7 @@ static void sat_encode(amps_t *amps, sample_t *samples, int length) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { amps_t *amps = (amps_t *) sender; - int count; + int count, input_num; again: switch (amps->dsp_mode) { @@ -483,7 +483,9 @@ again: break; case DSP_MODE_AUDIO_RX_AUDIO_TX: memset(power, 1, length); - jitter_load(&s->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); /* pre-emphasis */ if (amps->pre_emphasis) pre_emphasis(&s->estate, samples, length); diff --git a/src/anetz/anetz.c b/src/anetz/anetz.c index d5e1a76..3af185b 100644 --- a/src/anetz/anetz.c +++ b/src/anetz/anetz.c @@ -513,7 +513,7 @@ void call_down_release(int callref, __attribute__((unused)) int cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; anetz_t *anetz; @@ -526,11 +526,8 @@ void call_down_audio(int callref, sample_t *samples, int count) if (!sender) return; - if (anetz->dsp_mode == DSP_MODE_AUDIO) { - sample_t up[(int)((double)count * anetz->sender.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&anetz->sender.srstate, samples, count, up); - jitter_save(&anetz->sender.dejitter, up, count); - } + if (anetz->dsp_mode == DSP_MODE_AUDIO) + jitter_save(&anetz->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } void call_down_clock(void) {} diff --git a/src/anetz/dsp.c b/src/anetz/dsp.c index 1bc20a1..e9a4dbb 100644 --- a/src/anetz/dsp.c +++ b/src/anetz/dsp.c @@ -357,6 +357,7 @@ static void fsk_tone(anetz_t *anetz, sample_t *samples, int length) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { anetz_t *anetz = (anetz_t *) sender; + int input_num; memset(power, 1, length); @@ -365,7 +366,9 @@ void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length memset(samples, 0, length * sizeof(*samples)); break; case DSP_MODE_AUDIO: - jitter_load(&anetz->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); break; case DSP_MODE_TONE: fsk_tone(anetz, samples, length); diff --git a/src/bnetz/bnetz.c b/src/bnetz/bnetz.c index 6788ded..caa7b2e 100644 --- a/src/bnetz/bnetz.c +++ b/src/bnetz/bnetz.c @@ -816,7 +816,7 @@ void call_down_release(int callref, int __attribute__((unused)) cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; bnetz_t *bnetz; @@ -831,9 +831,7 @@ void call_down_audio(int callref, sample_t *samples, int count) if (bnetz->dsp_mode == DSP_MODE_AUDIO || bnetz->dsp_mode == DSP_MODE_AUDIO_METER) { - sample_t up[(int)((double)count * bnetz->sender.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&bnetz->sender.srstate, samples, count, up); - jitter_save(&bnetz->sender.dejitter, up, count); + jitter_save(&bnetz->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } } diff --git a/src/bnetz/dsp.c b/src/bnetz/dsp.c index 73b70a7..809cb53 100644 --- a/src/bnetz/dsp.c +++ b/src/bnetz/dsp.c @@ -361,7 +361,7 @@ static void metering_tone(bnetz_t *bnetz, sample_t *samples, int length) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { bnetz_t *bnetz = (bnetz_t *) sender; - int count; + int count, input_num; memset(power, 1, length); @@ -372,7 +372,9 @@ again: break; case DSP_MODE_AUDIO: case DSP_MODE_AUDIO_METER: - jitter_load(&bnetz->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); if (bnetz->dsp_mode == DSP_MODE_AUDIO_METER) metering_tone(bnetz, samples, length); break; diff --git a/src/cnetz/cnetz.c b/src/cnetz/cnetz.c index 49b0ca3..734a3e7 100644 --- a/src/cnetz/cnetz.c +++ b/src/cnetz/cnetz.c @@ -576,7 +576,7 @@ static void cnetz_release(transaction_t *trans, uint8_t cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; cnetz_t *cnetz; @@ -591,7 +591,7 @@ void call_down_audio(int callref, sample_t *samples, int count) if (cnetz->dsp_mode == DSP_MODE_SPK_V) { /* store as is, since we convert rate when processing FSK frames */ - jitter_save(&cnetz->sender.dejitter, samples, count); + jitter_save(&cnetz->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } } diff --git a/src/cnetz/dsp.c b/src/cnetz/dsp.c index 02ae6b9..c5658e5 100644 --- a/src/cnetz/dsp.c +++ b/src/cnetz/dsp.c @@ -158,12 +158,6 @@ int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2], en scrambler_setup(&cnetz->scrambler_tx, (double)cnetz->sender.samplerate / 1.1); scrambler_setup(&cnetz->scrambler_rx, (double)cnetz->sender.samplerate / 1.1); - /* reinit jitter buffer for 8000 kHz */ - jitter_destroy(&cnetz->sender.dejitter); - rc = jitter_create(&cnetz->sender.dejitter, 8000 / 5); - if (rc < 0) - goto error; - /* init compandor, according to C-Netz specs, attack and recovery time * shall not exceed according to ITU G.162 */ init_compandor(&cnetz->cstate, 8000, 5.0, 22.5); @@ -172,7 +166,7 @@ int dsp_init_sender(cnetz_t *cnetz, int measure_speed, double clock_speed[2], en cnetz->offset_range = ceil(cnetz->fsk_bitduration); #ifdef TEST_SCRAMBLE - rc = jitter_create(&scrambler_test_jb, cnetz->sender.samplerate / 5); + rc = jitter_create(&scrambler_test_jb, "scramble", cnetz->sender.samplerate, sizeof(sample_t), JITTER_AUDIO); if (rc < 0) { PDEBUG_CHAN(DDSP, DEBUG_ERROR, "Failed to init jitter buffer for scrambler test!\n"); exit(0); @@ -577,7 +571,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double rf_l #ifdef TEST_UNSCRAMBLE scrambler(&scrambler_test_scrambler1, samples, length); #endif - jitter_save(&scrambler_test_jb, samples, length); + jitter_save(&scrambler_test_jb, samples, length, 0, 0, 0, 0); return; #endif @@ -598,7 +592,8 @@ static int shrink_speech(cnetz_t *cnetz, sample_t *speech_buffer) /* 1. compress dynamics */ compress_audio(&cnetz->cstate, speech_buffer, 100); /* 2. upsample */ - speech_length = samplerate_upsample(&cnetz->sender.srstate, speech_buffer, 100, speech_buffer); + speech_length = samplerate_upsample_output_num(&cnetz->sender.srstate, 100); + samplerate_upsample(&cnetz->sender.srstate, speech_buffer, 100, speech_buffer, speech_length); /* 3. scramble */ if (cnetz->scrambler) scrambler(&cnetz->scrambler_tx, speech_buffer, speech_length); diff --git a/src/eurosignal/eurosignal.c b/src/eurosignal/eurosignal.c index 5ad37d1..e1a3093 100644 --- a/src/eurosignal/eurosignal.c +++ b/src/eurosignal/eurosignal.c @@ -760,7 +760,7 @@ void call_down_release(int callref, int cause) } /* Receive audio from call instance. */ -void call_down_audio(int __attribute__((unused)) callref, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) +void call_down_audio(int __attribute__((unused)) callref, uint16_t __attribute__((unused)) sequence, uint32_t __attribute__((unused)) timestamp, uint32_t __attribute__((unused)) ssrc, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) { } diff --git a/src/fuenf/dsp.c b/src/fuenf/dsp.c index b3f10f8..7985fb9 100644 --- a/src/fuenf/dsp.c +++ b/src/fuenf/dsp.c @@ -595,15 +595,17 @@ void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length fuenf_t *fuenf = (fuenf_t *) sender; sample_t *orig_samples = samples; int orig_length = length; - int count; + int count, input_num; sample_t *spl; int pos; int i; /* speak through */ if (fuenf->state == FUENF_STATE_DURCHSAGE && fuenf->callref) { - jitter_load(&fuenf->sender.dejitter, samples, length); memset(power, 1, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); } else { /* send if something has to be sent. else turn transmitter off */ while ((count = encode(fuenf, samples, length))) { diff --git a/src/fuenf/fuenf.c b/src/fuenf/fuenf.c index 4a3eb90..4466094 100644 --- a/src/fuenf/fuenf.c +++ b/src/fuenf/fuenf.c @@ -390,7 +390,7 @@ void call_down_release(int callref, int cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; fuenf_t *fuenf; @@ -403,11 +403,8 @@ void call_down_audio(int callref, sample_t *samples, int count) if (!sender) return; - if (fuenf->state == FUENF_STATE_DURCHSAGE) { - sample_t up[(int)((double)count * fuenf->sender.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&fuenf->sender.srstate, samples, count, up); - jitter_save(&fuenf->sender.dejitter, up, count); - } + if (fuenf->state == FUENF_STATE_DURCHSAGE) + jitter_save(&fuenf->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } void dump_info(void) {} diff --git a/src/fuvst/fuvst.c b/src/fuvst/fuvst.c index dc5da16..f86b0a8 100755 --- a/src/fuvst/fuvst.c +++ b/src/fuvst/fuvst.c @@ -1240,13 +1240,17 @@ void fuvst_destroy(sender_t *sender) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { fuvst_t *fuvst = (fuvst_t *) sender; + int input_num; memset(power, 1, length); if (fuvst->chan_type == CHAN_TYPE_ZZK) v27_modem_send(&fuvst->modem, samples, length); - else - jitter_load(&fuvst->sender.dejitter, samples, length); + else { + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); + } } void sender_receive(sender_t *sender, sample_t *samples, int length, double __attribute__((unused)) rf_level_db) @@ -1280,7 +1284,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; fuvst_t *fuvst; @@ -1293,11 +1297,8 @@ void call_down_audio(int callref, sample_t *samples, int count) if (!sender) return; - if (fuvst->callref) { - sample_t up[(int)((double)count * fuvst->sender.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&fuvst->sender.srstate, samples, count, up); - jitter_save(&fuvst->sender.dejitter, up, count); - } + if (fuvst->callref) + jitter_save(&fuvst->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } void call_down_clock(void) {} diff --git a/src/fuvst/sniffer.c b/src/fuvst/sniffer.c index 570919d..f7fd656 100644 --- a/src/fuvst/sniffer.c +++ b/src/fuvst/sniffer.c @@ -255,7 +255,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at v27_modem_receive(&sniffer->modem, samples, length); } -void call_down_audio(int __attribute__((unused)) callref, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) { } +void call_down_audio(int __attribute__((unused)) callref, uint16_t __attribute__((unused)) sequence, uint32_t __attribute__((unused)) timestamp, uint32_t __attribute__((unused)) ssrc, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) { } void call_down_clock(void) {} diff --git a/src/imts/dsp.c b/src/imts/dsp.c index 94366fa..9e08da2 100644 --- a/src/imts/dsp.c +++ b/src/imts/dsp.c @@ -276,7 +276,7 @@ static int generate_tone(imts_t *imts, sample_t *samples, int length) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { imts_t *imts = (imts_t *) sender; - int count; + int count, input_num; memset(power, 1, length); @@ -296,7 +296,9 @@ again: break; case DSP_MODE_AUDIO: memset(power, 1, length); - jitter_load(&imts->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); if (imts->pre_emphasis) pre_emphasis(&imts->estate, samples, length); break; diff --git a/src/imts/imts.c b/src/imts/imts.c index 8a33123..8395a78 100644 --- a/src/imts/imts.c +++ b/src/imts/imts.c @@ -1284,7 +1284,7 @@ void call_down_release(int callref, __attribute__((unused)) int cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; imts_t *imts; @@ -1298,9 +1298,7 @@ void call_down_audio(int callref, sample_t *samples, int count) return; if (imts->dsp_mode == DSP_MODE_AUDIO) { - sample_t up[(int)((double)count * imts->sender.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&imts->sender.srstate, samples, count, up); - jitter_save(&imts->sender.dejitter, up, count); + jitter_save(&imts->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } } diff --git a/src/jolly/dsp.c b/src/jolly/dsp.c index dfd694b..9d2ab41 100644 --- a/src/jolly/dsp.c +++ b/src/jolly/dsp.c @@ -113,7 +113,7 @@ int dsp_init_sender(jolly_t *jolly, int nbfm, double squelch_db, int repeater) /* repeater */ jolly->repeater = repeater; jolly->repeater_max = (int)((double)jolly->sender.samplerate * REPEATER_TIME); - rc = jitter_create(&jolly->repeater_dejitter, jolly->sender.samplerate / 5); + rc = jitter_create(&jolly->repeater_dejitter, "repeater", jolly->sender.samplerate, sizeof(sample_t), 0.050, 0.500, JITTER_FLAG_NONE); if (rc < 0) { PDEBUG(DDSP, DEBUG_ERROR, "Failed to create and init repeater buffer!\n"); goto error; @@ -319,7 +319,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double rf_l /* if repeater mode, store sample in jitter buffer */ if (jolly->repeater) - jitter_save(&jolly->repeater_dejitter, samples, length); + jitter_save(&jolly->repeater_dejitter, samples, length, 0, 0, 0, 0); /* downsample, decode DTMF */ count = samplerate_downsample(&jolly->sender.srstate, samples, length); @@ -346,7 +346,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double rf_l void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { jolly_t *jolly = (jolly_t *) sender; - int count; + int count, input_num; switch (jolly->state) { case STATE_IDLE: @@ -368,7 +368,9 @@ void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length case STATE_CALL: case STATE_CALL_DIALING: memset(power, 1, length); - jitter_load(&jolly->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); break; case STATE_OUT_VERIFY: case STATE_IN_PAGING: diff --git a/src/jolly/jolly.c b/src/jolly/jolly.c index a979806..115d561 100644 --- a/src/jolly/jolly.c +++ b/src/jolly/jolly.c @@ -594,7 +594,7 @@ void call_down_release(int callref, __attribute__((unused)) int cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; jolly_t *jolly; @@ -607,11 +607,8 @@ void call_down_audio(int callref, sample_t *samples, int count) if (!sender) return; - if (jolly->state == STATE_CALL || jolly->state == STATE_CALL_DIALING) { - sample_t up[(int)((double)count * jolly->sender.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&jolly->sender.srstate, samples, count, up); - jitter_save(&jolly->sender.dejitter, up, count); - } + if (jolly->state == STATE_CALL || jolly->state == STATE_CALL_DIALING) + jitter_save(&jolly->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } void call_down_clock(void) {} diff --git a/src/jolly/voice.c b/src/jolly/voice.c index 2822608..e24e0b5 100644 --- a/src/jolly/voice.c +++ b/src/jolly/voice.c @@ -11072,7 +11072,7 @@ int init_voice(int samplerate) { samplerate_t srstate; sample_t spl_in[CHUNK], *spl_out; - int i, s, j, chunk, count; + int i, s, j, chunk, count, output_num; int rc; jolly_voice.spl[0] = (sample_t *)digit_0; @@ -11109,7 +11109,8 @@ int init_voice(int samplerate) } for (i = 0; i < 13; i++) { - spl_out = calloc(((double)jolly_voice.size[i] * srstate.factor + 0.5) + 10, sizeof(*spl_out)); + output_num = samplerate_upsample_output_num(&srstate, jolly_voice.size[i]); + spl_out = calloc(output_num, sizeof(*spl_out)); count = 0; for (s = 0; s < jolly_voice.size[i]; s += CHUNK) { chunk = jolly_voice.size[i] - s; @@ -11117,7 +11118,8 @@ int init_voice(int samplerate) chunk = CHUNK; for (j = 0; j < chunk; j++) spl_in[j] = (double)(((int16_t *)(jolly_voice.spl[i]))[s + j]) / 32767.0 * GAIN; - count += samplerate_upsample(&srstate, spl_in, chunk, spl_out + count); + samplerate_upsample(&srstate, spl_in, chunk, spl_out + count, output_num); + count += output_num; } jolly_voice.spl[i] = spl_out; jolly_voice.size[i] = count; diff --git a/src/libdebug/debug.c b/src/libdebug/debug.c index bc3ac12..bf23035 100755 --- a/src/libdebug/debug.c +++ b/src/libdebug/debug.c @@ -93,12 +93,13 @@ struct debug_cat { { "uk0", "\033[1;34m" }, { "ph", "\033[0;33m" }, { "dcf77", "\033[1;34m" }, + { "jitter", "\033[0;36m" }, { NULL, NULL } }; int debuglevel = DEBUG_INFO; int debug_date = 0; -uint64_t debug_mask = ~0; +uint64_t debug_mask[2] = { ~0, ~0 }; extern int num_kanal; void (*clear_console_text)(void) = NULL; @@ -155,7 +156,7 @@ void _printdebug(const char *file, const char __attribute__((unused)) *function, if (debuglevel > level) return; - if (!(debug_mask & ((uint64_t)1 << cat))) + if (!(debug_mask[cat >> 6] & ((uint64_t)1 << (cat & 63)))) return; lock_debug(); @@ -289,7 +290,7 @@ int parse_debug_opt(const char *optarg) return -EINVAL; } if (dstring) - debug_mask = 0; + memset(debug_mask, 0, sizeof(debug_mask)); while((p = strsep(&dstring, ","))) { for (i = 0; debug_cat[i].name; i++) { if (!strcasecmp(p, debug_cat[i].name)) @@ -300,7 +301,7 @@ int parse_debug_opt(const char *optarg) free(dup); return -EINVAL; } - debug_mask |= ((uint64_t)1 << i); + debug_mask[i >> 6] |= ((uint64_t)1 << (i & 63)); } free(dup); diff --git a/src/libdebug/debug.h b/src/libdebug/debug.h index 3c13f7d..ba55fdb 100644 --- a/src/libdebug/debug.h +++ b/src/libdebug/debug.h @@ -55,6 +55,8 @@ #define DUK0 48 #define DPH 49 #define DDCF77 50 +#define DJITTER 51 +//NOTE: increment mask array, if 127 is exceeded void lock_debug(void); void unlock_debug(void); diff --git a/src/libjitter/jitter.c b/src/libjitter/jitter.c index c3af715..f9de625 100644 --- a/src/libjitter/jitter.c +++ b/src/libjitter/jitter.c @@ -1,6 +1,6 @@ /* Jitter buffering functions * - * (C) 2016 by Andreas Eversberg + * (C) 2022 by Andreas Eversberg * All Rights Reserved * * This program is free software: you can redistribute it and/or modify @@ -17,6 +17,59 @@ * along with this program. If not, see . */ +/* How does it work: + * + * Storing: + * + * Each saved frame is sorted into the list of packages by their sequence + * number. + * + * The first packet will be stored with a delay of minimum jitter window size. + * + * Packets with the same sequence are dropped. + * + * Early packts that exceed maximum jitter window size cause jitter + * window to shift into the future. + * + * Late packets cause jitter window to shift into the past (allowing more + * delay). Minimum jitter window size is added also, to prevent subsequent + * packets from beeing late too. + * + * If no sequence is provided (autosequence), the sequence number is generated + * by a counter. Also the timestamp is generated by counting the length of each + * frame. + * + * If ssrc changes, the buffer is reset. + * + * + * Playout: + * + * The caller of the playout function can request any length of samples from + * the packet list. The packt's time stamp and the jitter window time stamp + * indicate what portion of a packet is already provided to the caller. + * Complete packet, sent to the caller, are removed. + * + * Missing packets are interpolated by repeating last 20ms of audio (optional) + * or by inserting zeroes (sample size > 1 byte) or by inserting 0xff (sample + * size = 1). + * + * Optionally the constant delay will be measured continuously and lowered if + * greater than minimum window size. (adaptive jitter buffer size) + * + * Note that the delay is measured with time stamp of frame, no matter what + * the length is. Length is an extra delay, but not considered here. + * + * + * Unlocking: + * + * If the buffer is created or reset, the buffer is locked, so no packets are + * stored. When the playout routine is called, the buffer is unlocked. This + * prevents from filling the buffer before playout is performed, which would + * cause high delay. + * + */ + +#include #include #include #include @@ -26,35 +79,97 @@ #include "../libdebug/debug.h" #include "jitter.h" +#define INITIAL_DELAY_INTERVAL 0.5 +#define REPEAT_DELAY_INTERVAL 3.0 +#define EXTRA_BUFFER 0.020 // 20 ms + +/* uncomment to enable heavy debugging */ +//#define HEAVY_DEBUG + +static int unnamed_count = 1; + /* create jitter buffer */ -int jitter_create(jitter_t *jitter, int length) +int jitter_create(jitter_t *jb, const char *name, double samplerate, int sample_size, double target_window_duration, double max_window_duration, uint32_t window_flags) { - memset(jitter, 0, sizeof(*jitter)); - jitter->spl = malloc(length * sizeof(sample_t)); - if (!jitter->spl) { - PDEBUG(DDSP, DEBUG_ERROR, "No memory for jitter buffer.\n"); - return -ENOMEM; + int rc = 0; + memset(jb, 0, sizeof(*jb)); + jb->sample_duration = 1.0 / samplerate; + jb->sample_size = sample_size; + jb->target_window_size = (int)(samplerate * target_window_duration); + jb->max_window_size = (int)(samplerate * max_window_duration); + jb->window_flags = window_flags; + + jb->extra_size = (int)(EXTRA_BUFFER * samplerate); + jb->extra_samples = calloc(sample_size, jb->extra_size); + if (!jb->extra_samples) { + PDEBUG(DJITTER, DEBUG_ERROR, "No memory for frame.\n"); + rc = -ENOMEM; + goto error; } - jitter->len = length; - jitter_reset(jitter); - return 0; + /* optionally give a string to be show with the debug */ + if (name && *name) + snprintf(jb->name, sizeof(jb->name) - 1, "(%s) ", name); + else + snprintf(jb->name, sizeof(jb->name) - 1, "(unnamed %d) ", unnamed_count++); + + jitter_reset(jb); + + PDEBUG(DJITTER, DEBUG_INFO, "%sCreated jitter buffer. (samplerate=%.0f, target_window=%.0fms, max_window=%.0fms, flag:latency=%s flag:repeat=%s)\n", jb->name, samplerate, target_window_duration * 1000.0, max_window_duration * 1000.0, (window_flags & JITTER_FLAG_LATENCY) ? "true" : "false", (window_flags & JITTER_FLAG_REPEAT) ? "true" : "false"); + +error: + if (rc) + jitter_destroy(jb); + return rc; } -void jitter_reset(jitter_t *jitter) +/* reset jitter buffer */ +void jitter_reset(jitter_t *jb) { - memset(jitter->spl, 0, jitter->len * sizeof(sample_t)); + jitter_frame_t *jf, *temp; - /* put write pointer ahead by half of the buffer length */ - jitter->inptr = jitter->len / 2; + PDEBUG(DJITTER, DEBUG_INFO, "%sReset jitter buffer.\n", jb->name); + + /* jitter buffer locked */ + jb->unlocked = 0; + + /* window becomes invalid */ + jb->window_valid = 0; + + /* remove all pending frames */ + jf = jb->frame_list; + while(jf) { + temp = jf; + jf = jf->next; + free(temp); + } + jb->frame_list = NULL; + + /* clear extrapolation buffer */ + if (jb->extra_samples) { + if (jb->sample_size == 1) + memset(jb->extra_samples, 0xff, jb->sample_size * jb->extra_size); + else + memset(jb->extra_samples, 0, jb->sample_size * jb->extra_size); + } + jb->extra_index = 0; + + /* delay measurement and reduction */ + jb->delay_counter = 0.0; + jb->delay_interval = INITIAL_DELAY_INTERVAL; + jb->min_delay_value = -1; } -void jitter_destroy(jitter_t *jitter) +void jitter_destroy(jitter_t *jb) { - if (jitter->spl) { - free(jitter->spl); - jitter->spl = NULL; + jitter_reset(jb); + + PDEBUG(DJITTER, DEBUG_INFO, "%sDestroying jitter buffer.\n", jb->name); + + if (jb->extra_samples) { + free(jb->extra_samples); + jb->extra_samples = NULL; } } @@ -62,64 +177,230 @@ void jitter_destroy(jitter_t *jitter) * * stop if buffer is completely filled */ -void jitter_save(jitter_t *jb, sample_t *samples, int length) +void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint16_t sequence, uint32_t timestamp, uint32_t ssrc) { - sample_t *spl; - int inptr, outptr, len, space; - int i; + jitter_frame_t *jf, **jfp; + int16_t offset_sequence; + int32_t offset_timestamp; - spl = jb->spl; - inptr = jb->inptr; - outptr = jb->outptr; - len = jb->len; - space = (outptr - inptr + len - 1) % len; + /* ignore frames until the buffer is unlocked by jitter_load() */ + if (!jb->unlocked) + return; - if (space < length) - length = space; - for (i = 0; i < length; i++) { - spl[inptr++] = *samples++; - if (inptr == len) - inptr = 0; + /* omit frames with no data */ + if (length < 1) + return; + + /* generate sequence and timestamp automatically, if enabled */ + if (!has_sequence) { +#ifdef DEBUG_JITTER + PDEBUG(DJITTER, DEBUG_DEBUG, "%sSave frame of %d samples (no seqence).\n", jb->name, length); +#endif + sequence = jb->next_sequence; + jb->next_sequence++; + timestamp = jb->next_timestamp; + jb->next_timestamp += length; + ssrc = jb->window_ssrc; + } else { +#ifdef HEAVY_DEBUG + PDEBUG(DJITTER, DEBUG_DEBUG, "%sSave frame of %d samples (seqence=%u timestamp=%u ssrc=0x%02x).\n", jb->name, length, sequence, timestamp, ssrc); +#endif + jb->next_sequence = sequence + 1; + jb->next_timestamp = timestamp + length; } - jb->inptr = inptr; + /* first packet (with this ssrc) sets window size to target_window_size */ + if (!jb->window_valid || jb->window_ssrc != ssrc) { + if (!jb->window_valid) + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Initial frame after init or reset.\n", jb->name); + else + PDEBUG(DJITTER, DEBUG_DEBUG, "%s SSRC changed.\n", jb->name); + // NOTE: Reset must be called before finding the frame location below, because there will be no frame in list anymore! + jitter_reset(jb); + jb->unlocked = 1; + /* when using dynamic jitter buffer, we use half of the target delay */ + if ((jb->window_flags & JITTER_FLAG_LATENCY)) { + jb->window_timestamp = timestamp - (uint32_t)jb->target_window_size / 2; + } else { + jb->window_timestamp = timestamp - (uint32_t)jb->target_window_size; + } + jb->window_valid = 1; + jb->window_ssrc = ssrc; + } + + /* find location where to put frame into the list, depending on sequence number */ + jfp = &jb->frame_list; + while(*jfp) { + offset_sequence = (int16_t)(sequence - (*jfp)->sequence); + /* found double entry */ + if (offset_sequence == 0) { + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Dropping double packet (sequence = %d)\n", jb->name, sequence); + return; + } + /* offset is negative, so we found the position to insert frame */ + if (offset_sequence < 0) + break; + jfp = &((*jfp)->next); + } + + offset_timestamp = timestamp - jb->window_timestamp; +#ifdef HEAVY_DEBUG + PDEBUG(DJITTER, DEBUG_DEBUG, "%sFrame has offset of %.0fms in jitter buffer.\n", jb->name, (double)offset_timestamp * jb->sample_duration * 1000.0); +#endif + + /* measure delay */ + if (jb->min_delay_value < 0 || offset_timestamp < jb->min_delay_value) + jb->min_delay_value = offset_timestamp; + + /* if frame is too early (delay ceases), shift window to the future */ + if (offset_timestamp > jb->max_window_size) { + if ((jb->window_flags & JITTER_FLAG_LATENCY)) { + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too early: Shift jitter buffer to the future, to make the frame fit to the end. (offset_timestamp(%d) > max_window_size(%d))\n", jb->name, offset_timestamp, jb->max_window_size); + /* shift window so it fits to the end of window */ + jb->window_timestamp = timestamp - jb->max_window_size; + } else { + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too early: Shift jitter buffer to the future, to make the frame fit to the target delay. (offset_timestamp(%d) > max_window_size(%d))\n", jb->name, offset_timestamp, jb->max_window_size); + /* shift window so frame fits to the start of window + target delay */ + jb->window_timestamp = timestamp - (uint32_t)(jb->target_window_size); + } + } + + /* is frame is too late, shift window to the past. */ + if (offset_timestamp < 0) { + if ((jb->window_flags & JITTER_FLAG_LATENCY)) { + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too late: Shift jitter buffer to the past, and add target window size. (offset_timestamp(%d) < 0)\n", jb->name, offset_timestamp); + /* shift window so frame fits to the start of window + half of target delay */ + jb->window_timestamp = timestamp - (uint32_t)(jb->target_window_size) / 2; + } else { + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Frame too late: Shift jitter buffer to the past, and add half target window size. (offset_timestamp(%d) < 0)\n", jb->name, offset_timestamp); + /* shift window so frame fits to the start of window + target delay */ + jb->window_timestamp = timestamp - (uint32_t)(jb->target_window_size); + } + } + + /* insert or append frame */ +#ifdef HEAVY_DEBUG + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Store frame\n", jb->name); +#endif + jf = malloc(sizeof(*jf) + length * jb->sample_size); + if (!jf) { + PDEBUG(DJITTER, DEBUG_ERROR, "No memory for frame.\n"); + return; + } + memset(jf, 0, sizeof(*jf)); // note: clear header only + jf->sequence = sequence; + jf->timestamp = timestamp; + memcpy(jf->samples, samples, length * jb->sample_size); + jf->length = length; + jf->next = *jfp; + *jfp = jf; } /* get audio from jitterbuffer */ -void jitter_load(jitter_t *jb, sample_t *samples, int length) +void jitter_load(jitter_t *jb, void *samples, int length) { - sample_t *spl; - int inptr, outptr, len, fill; - int i, ii; + jitter_frame_t *jf; + int32_t count, count2, index; - spl = jb->spl; - inptr = jb->inptr; - outptr = jb->outptr; - len = jb->len; - fill = (inptr - outptr + len) % len; +#ifdef HEAVY_DEBUG + PDEBUG(DJITTER, DEBUG_DEBUG, "%sLoad chunk of %d samples.\n", jb->name, length); +#endif - if (fill < length) - ii = fill; - else - ii = length; + /* now unlock jitter buffer */ + jb->unlocked = 1; - /* fill what we got */ - for (i = 0; i < ii; i++) { - *samples++ = spl[outptr++]; - if (outptr == len) - outptr = 0; - } - /* on underrun, fill with silence */ - for (; i < length; i++) { - *samples++ = 0; + /* reduce delay */ + jb->delay_counter += jb->sample_duration * (double)length; + if (jb->delay_counter >= jb->delay_interval) { + if (jb->min_delay_value >= 0) + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Statistics: target_window_delay=%.0fms max_window_delay=%.0fms current min_delay=%.0fms\n", jb->name, (double)jb->target_window_size * jb->sample_duration * 1000.0, (double)jb->max_window_size * jb->sample_duration * 1000.0, (double)jb->min_delay_value * jb->sample_duration * 1000.0); + /* delay reduction, if maximum delay is greater than target jitter window size */ + if ((jb->window_flags & JITTER_FLAG_LATENCY) && jb->min_delay_value > jb->target_window_size) { + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Reducing current minimum delay of %.0fms, because maximum delay is greater than target window size of %.0fms.\n", jb->name, (double)jb->min_delay_value * jb->sample_duration * 1000.0, (double)jb->target_window_size * jb->sample_duration * 1000.0); + /* only reduce delay to half of the target window size */ + jb->window_timestamp += jb->min_delay_value - jb->target_window_size / 2; + + } + jb->delay_counter -= jb->delay_interval; + jb->delay_interval = REPEAT_DELAY_INTERVAL; + jb->min_delay_value = -1; } - jb->outptr = outptr; -} - -void jitter_clear(jitter_t *jb) -{ - jb->inptr = jb->outptr = 0; + /* process all frames until output buffer is loaded */ + while (length) { + /* always get frame with the lowest sequence number (1st frame) */ + jf = jb->frame_list; + + if (jf) { + count = jf->timestamp - jb->window_timestamp; + if (count > length) + count = length; + } else + count = length; + /* if there is no frame or we have not reached frame's time stamp, extrapolate */ + if (count > 0) { +#ifdef HEAVY_DEBUG + if (jf) + PDEBUG(DJITTER, DEBUG_DEBUG, "%s There is a frame ahead in buffer after %d samples. Interpolating gap.\n", jb->name, jf->timestamp - jb->window_timestamp); + else + PDEBUG(DJITTER, DEBUG_DEBUG, "%s There is no frame ahead in buffer. Interpolating gap.\n", jb->name); +#endif + /* extrapolate by playing the extrapolation buffer */ + while (count) { + count2 = count; + if (count2 > jb->extra_size - jb->extra_index) + count2 = jb->extra_size - jb->extra_index; + memcpy(samples, (uint8_t *)jb->extra_samples + jb->extra_index * jb->sample_size, count2 * jb->sample_size); + jb->extra_index += count2; + if (jb->extra_index == jb->extra_size) + jb->extra_index = 0; + samples = (uint8_t *)samples + count2 * jb->sample_size; + length -= count2; + jb->window_timestamp += count2; + count -= count2; + } + if (length == 0) + return; + } + + /* copy samples from frame (what is not in the past) */ + index = jb->window_timestamp - jf->timestamp; + while (index < jf->length) { + /* use the lowest value of 'playout length' or 'remaining packet length' */ + count = length; + if (jf->length - index < count) + count = jf->length - index; + /* if extrapolation is used, limit count to what we can store into buffer */ + if (jb->extra_samples && jb->extra_size - jb->extra_index < count) + count = jb->extra_size - jb->extra_index; + /* copy samples from packet to play out, increment sample pointer and decrement length */ +#ifdef HEAVY_DEBUG + PDEBUG(DJITTER, DEBUG_DEBUG, "%s Copy data (offset=%u count=%u) from frame (sequence=%u timestamp=%u length=%u).\n", jb->name, index, count, jf->sequence, jf->timestamp, jf->length); +#endif + memcpy(samples, (uint8_t *)jf->samples + index * jb->sample_size, count * jb->sample_size); + samples = (uint8_t *)samples + count * jb->sample_size; + length -= count; + /* copy frame data to extrapolation buffer also, increment index */ + if ((jb->window_flags & JITTER_FLAG_REPEAT)) { + memcpy((uint8_t *)jb->extra_samples + jb->extra_index * jb->sample_size, (uint8_t *)jf->samples + index * jb->sample_size, count * jb->sample_size); + jb->extra_index += count; + if (jb->extra_index == jb->extra_size) + jb->extra_index = 0; + } + /* increment time stamp */ + jb->window_timestamp += count; + index += count; + /* if there was enough to play out, we are done */ + if (length == 0) + return; + } + + /* free frame, because all samples are now in the past */ + jb->frame_list = jf->next; + free(jf); + + /* now go for next loop, in case there is still date to play out */ + } } diff --git a/src/libjitter/jitter.h b/src/libjitter/jitter.h index e344d8a..b4cb15f 100644 --- a/src/libjitter/jitter.h +++ b/src/libjitter/jitter.h @@ -1,14 +1,58 @@ +#define JITTER_FLAG_NONE 0 // no flags at all +#define JITTER_FLAG_LATENCY (1 << 0) // keep latency close to target_window_duration +#define JITTER_FLAG_REPEAT (1 << 1) // repeat audio to extrapolate gaps + +/* window settings for low latency audio and extrapolation of gaps */ +#define JITTER_AUDIO 0.050, 1.000, JITTER_FLAG_LATENCY | JITTER_FLAG_REPEAT +/* window settings for analog data (fax/modem) or digial data (HDLC) */ +#define JITTER_DATA 0.100, 0.200, JITTER_FLAG_NONE + +typedef struct jitter_frame { + struct jitter_frame *next; + uint16_t sequence; + uint32_t timestamp; + int length; + uint8_t samples[0]; +} jitter_frame_t; + typedef struct jitter { - sample_t *spl; /* pointer to sample buffer */ - int len; /* buffer size: number of samples */ - int inptr, outptr; /* write pointer and read pointer */ + char name[64]; + + /* sample properties */ + int sample_size; + double sample_duration; + + /* automatic sequence generation */ + uint16_t next_sequence; + uint32_t next_timestamp; + + /* window properties */ + int unlocked; + uint32_t window_flags; + int target_window_size; + int max_window_size; + int window_valid; + uint32_t window_ssrc; + uint32_t window_timestamp; + + /* reduction of delay */ + double delay_interval; + double delay_counter; + int32_t min_delay_value; + + /* extrapolation */ + int extra_size; + int extra_index; + void *extra_samples; + + /* list of frames */ + jitter_frame_t *frame_list; } jitter_t; -int jitter_create(jitter_t *jitter, int length); -void jitter_reset(jitter_t *jitter); -void jitter_destroy(jitter_t *jitter); -void jitter_save(jitter_t *jb, sample_t *samples, int length); -void jitter_load(jitter_t *jb, sample_t *samples, int length); -void jitter_clear(jitter_t *jb); +int jitter_create(jitter_t *jb, const char *name, double samplerate, int sample_size, double target_window_duration, double max_window_duration, uint32_t window_flags); +void jitter_reset(jitter_t *jb); +void jitter_destroy(jitter_t *jb); +void jitter_save(jitter_t *jb, void *samples, int length, int has_sequence, uint16_t sequence, uint32_t timestamp, uint32_t ssrc); +void jitter_load(jitter_t *jb, void *samples, int length); diff --git a/src/libmobile/call.c b/src/libmobile/call.c index 4f9049b..208a4b9 100644 --- a/src/libmobile/call.c +++ b/src/libmobile/call.c @@ -387,7 +387,7 @@ static void process_timeout(struct timer *timer) } } -void down_audio(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unused)) sequence_number, uint32_t __attribute__((unused)) timestamp, uint8_t *data, int len) +void down_audio(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len) { process_t *process = codec->media->session->priv; sample_t samples[len / 2]; @@ -400,7 +400,7 @@ void down_audio(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unu double lev = level_of(samples, len / 2); printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev))); #endif - call_down_audio(process->callref, samples, len / 2); + call_down_audio(process->callref, sequence_number, timestamp, ssrc, samples, len / 2); } static void indicate_setup(process_t *process, const char *callerid, const char *dialing, uint8_t network_type, const char *network_id) diff --git a/src/libmobile/call.h b/src/libmobile/call.h index c63882a..d38f8ab 100644 --- a/src/libmobile/call.h +++ b/src/libmobile/call.h @@ -37,7 +37,7 @@ void call_down_release(int callref, int cause); /* send and receive audio */ void call_up_audio(int callref, sample_t *samples, int count); -void call_down_audio(int callref, sample_t *samples, int count); +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count); /* clock to transmit to */ void call_clock(void); /* from main loop */ diff --git a/src/libmobile/console.c b/src/libmobile/console.c index 7e63422..4365402 100755 --- a/src/libmobile/console.c +++ b/src/libmobile/console.c @@ -141,17 +141,15 @@ static void free_console(void) console.callref = 0; } -void up_audio(struct osmo_cc_session_codec *codec, uint16_t __attribute__((unused)) sequence_number, uint32_t __attribute__((unused)) timestamp, uint8_t *data, int len) +void up_audio(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len) { int count = len / 2; sample_t samples[count]; /* save audio from transceiver to jitter buffer */ if (console.sound) { - sample_t up[(int)((double)count * console.srstate.factor + 0.5) + 10]; int16_to_samples(samples, (int16_t *)data, count); - count = samplerate_upsample(&console.srstate, samples, count, up); - jitter_save(&console.dejitter, up, count); + jitter_save(&console.dejitter, samples, count, 1, sequence_number, timestamp, ssrc); return; } /* if echo test is used, send echo back to mobile */ @@ -398,7 +396,7 @@ int console_init(const char *audiodev, int samplerate, int buffer, int loopback, goto error; } - rc = jitter_create(&console.dejitter, samplerate / 5); + rc = jitter_create(&console.dejitter, "console", 8000, sizeof(sample_t), 0.050, 0.200, JITTER_FLAG_NONE); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init dejitter buffer!\n"); goto error; @@ -580,7 +578,7 @@ void process_console(int c) /* handle audio, if sound device is used */ sample_t samples[console.buffer_size + 10], *samples_list[1]; uint8_t *power_list[1]; - int count; + int count, input_num; int rc; count = sound_get_tosend(console.sound, console.buffer_size); @@ -591,7 +589,11 @@ void process_console(int c) return; } if (count > 0) { - jitter_load(&console.dejitter, samples, count); + /* load and upsample */ + input_num = samplerate_upsample_input_num(&console.srstate, count); + jitter_load(&console.dejitter, samples, input_num); + samplerate_upsample(&console.srstate, samples, input_num, samples, count); + /* write to sound device */ samples_list[0] = samples; power_list[0] = NULL; rc = sound_write(console.sound, samples_list, power_list, count, NULL, NULL, 1); @@ -613,9 +615,9 @@ void process_console(int c) if (count) { int i; - if (console.loopback == 3) - jitter_save(&console.dejitter, samples, count); count = samplerate_downsample(&console.srstate, samples, count); + if (console.loopback == 3) + jitter_save(&console.dejitter, samples, count, 0, 0, 0, 0); /* put samples into ring buffer */ for (i = 0; i < count; i++) { console.tx_buffer[console.tx_buffer_pos] = samples[i]; diff --git a/src/libmobile/sender.c b/src/libmobile/sender.c index beb1f42..8b62f3c 100644 --- a/src/libmobile/sender.c +++ b/src/libmobile/sender.c @@ -149,7 +149,13 @@ int sender_create(sender_t *sender, const char *kanal, double sendefrequenz, dou goto error; } - rc = jitter_create(&sender->dejitter, samplerate / 5); + rc = jitter_create(&sender->dejitter, sender->kanal, 8000, sizeof(sample_t), JITTER_AUDIO); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init audio buffer!\n"); + goto error; + } + + rc = jitter_create(&sender->loop_dejitter, sender->kanal, samplerate, sizeof(sample_t), JITTER_AUDIO); if (rc < 0) { PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init audio buffer!\n"); goto error; @@ -288,6 +294,7 @@ void sender_destroy(sender_t *sender) wave_destroy_playback(&sender->wave_tx_play); jitter_destroy(&sender->dejitter); + jitter_destroy(&sender->loop_dejitter); } /* set frequency modulation and parameters */ @@ -373,7 +380,7 @@ cant_recover: for (i = 0, inst = sender; inst; i++, inst = inst->slave) { /* load TX data from audio loop or from sender instance */ if (inst->loopback == 3) - jitter_load(&inst->dejitter, samples[i], count); + jitter_load(&inst->loop_dejitter, samples[i], count); else sender_send(inst, samples[i], power[i], count); /* internal loopback: loop back TX audio to RX */ @@ -458,7 +465,7 @@ cant_recover: sender_receive(inst, samples[i], count, rf_level_db[i]); } if (inst->loopback == 3) - jitter_save(&inst->dejitter, samples[i], count); + jitter_save(&inst->loop_dejitter, samples[i], count, 0, 0, 0, 0); } } #ifdef DEBUG_TIME_CONSUMPTION diff --git a/src/libmobile/sender.h b/src/libmobile/sender.h index 3118516..944ae75 100644 --- a/src/libmobile/sender.h +++ b/src/libmobile/sender.h @@ -73,6 +73,7 @@ typedef struct sender { /* audio buffer for audio to send to transmitter (also used as loopback buffer) */ jitter_t dejitter; + jitter_t loop_dejitter; /* audio buffer for audio to send to caller (20ms = 160 samples @ 8000Hz) */ sample_t rxbuf[160]; diff --git a/src/libosmocc/helper.c b/src/libosmocc/helper.c index 807542e..8917917 100644 --- a/src/libosmocc/helper.c +++ b/src/libosmocc/helper.c @@ -29,7 +29,7 @@ #include "endpoint.h" #include "helper.h" -osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), osmo_cc_msg_t *msg, int debug) +osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, int debug) { osmo_cc_session_t *session; osmo_cc_session_media_t *media; @@ -52,7 +52,7 @@ osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, vo return session; } -const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p, int force_our_codec) +const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p, int force_our_codec) { char offer_sdp[65536]; const char *accept_sdp; diff --git a/src/libosmocc/helper.h b/src/libosmocc/helper.h index c12a50a..97a284f 100644 --- a/src/libosmocc/helper.h +++ b/src/libosmocc/helper.h @@ -7,7 +7,7 @@ struct osmo_cc_helper_audio_codecs { void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len); }; -osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), osmo_cc_msg_t *msg, int debug); -const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p, int force_our_codec); +osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, int debug); +const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p, int force_our_codec); int osmo_cc_helper_audio_negotiate(osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p); diff --git a/src/libosmocc/rtp.c b/src/libosmocc/rtp.c index 3363372..f6572ca 100644 --- a/src/libosmocc/rtp.c +++ b/src/libosmocc/rtp.c @@ -52,7 +52,7 @@ struct rtp_x_hdr { uint16_t length; } __attribute__((packed)); -static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_t *marker_p, uint8_t *pt_p, uint16_t *sequence_p, uint32_t *timestamp_p) +static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_t *marker_p, uint8_t *pt_p, uint16_t *sequence_p, uint32_t *timestamp_p, uint32_t *ssrc_p) { static uint8_t data[2048]; int len; @@ -83,6 +83,7 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_ payload_type = rtph->byte1 & 0x7f; *sequence_p = ntohs(rtph->sequence); *timestamp_p = ntohl(rtph->timestamp); + *ssrc_p = ntohl(rtph->ssrc); if (version != RTP_VERSION) { PDEBUG(DCC, DEBUG_NOTICE, "Received RTP version %d not supported.\n", version); @@ -172,7 +173,7 @@ int osmo_cc_rtp_open(osmo_cc_session_media_t *media) int flags; int rc; - media->rtp_ssrc = rand(); + media->tx_ssrc = rand(); osmo_cc_rtp_close(media); @@ -335,7 +336,7 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, in payload_len = len; } - rtp_send(codec->media->rtp_socket, payload, payload_len, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->rtp_ssrc); + rtp_send(codec->media->rtp_socket, payload, payload_len, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc); codec->media->tx_sequence += inc_sequence; codec->media->tx_timestamp += inc_timestamp; @@ -358,7 +359,7 @@ int osmo_cc_rtp_receive(osmo_cc_session_media_t *media) if (!media || media->rtp_socket <= 0) return -EIO; - rc = rtp_receive(media->rtp_socket, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp); + rc = rtp_receive(media->rtp_socket, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc); if (rc < 0) return rc; @@ -381,7 +382,7 @@ int osmo_cc_rtp_receive(osmo_cc_session_media_t *media) } if (codec->media->receive) - codec->media->receiver(codec, media->rx_sequence, media->rx_timestamp, data, len); + codec->media->receiver(codec, media->rx_sequence, media->rx_timestamp, media->rx_ssrc, data, len); if (codec->decoder) free(data); diff --git a/src/libosmocc/session.c b/src/libosmocc/session.c index 59fb2c7..3546900 100644 --- a/src/libosmocc/session.c +++ b/src/libosmocc/session.c @@ -127,7 +127,7 @@ void osmo_cc_free_session(osmo_cc_session_t *session) free(session); } -osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, enum osmo_cc_session_media_type type, uint16_t port, enum osmo_cc_session_media_proto proto, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), int debug) +osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, enum osmo_cc_session_media_type type, uint16_t port, enum osmo_cc_session_media_proto proto, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), int debug) { osmo_cc_session_config_t *conf = session->config; osmo_cc_session_media_t *media, **mediap; @@ -374,7 +374,7 @@ osmo_cc_session_t *osmo_cc_session_receive_offer(osmo_cc_session_config_t *conf, return session; } -void osmo_cc_session_accept_media(osmo_cc_session_media_t *media, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len)) +void osmo_cc_session_accept_media(osmo_cc_session_media_t *media, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)) { osmo_cc_session_config_t *conf = media->session->config; diff --git a/src/libosmocc/session.h b/src/libosmocc/session.h index c0717c0..0464cc9 100644 --- a/src/libosmocc/session.h +++ b/src/libosmocc/session.h @@ -79,10 +79,10 @@ typedef struct osmo_cc_session_media { osmo_cc_session_connection_data_t connection_data_local, connection_data_remote; struct osmo_cc_session_codec *codec_list; int send, receive; - void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len); + void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len); int rtp_socket; int rtcp_socket; - uint32_t rtp_ssrc; + uint32_t tx_ssrc, rx_ssrc; uint16_t tx_sequence, rx_sequence; uint32_t tx_timestamp, rx_timestamp; int accepted; @@ -110,14 +110,14 @@ typedef struct osmo_cc_session_codec { void osmo_cc_set_local_peer(osmo_cc_session_config_t *conf, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address); osmo_cc_session_t *osmo_cc_new_session(osmo_cc_session_config_t *conf, void *priv, const char *username, const char *sess_id, const char *sess_version, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *unicast_address, const char *session_name, int debug); void osmo_cc_free_session(osmo_cc_session_t *session); -osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, enum osmo_cc_session_media_type type, uint16_t port, enum osmo_cc_session_media_proto proto, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), int debug); +osmo_cc_session_media_t *osmo_cc_add_media(osmo_cc_session_t *session, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, enum osmo_cc_session_media_type type, uint16_t port, enum osmo_cc_session_media_proto proto, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len), int debug); void osmo_cc_free_media(osmo_cc_session_media_t *media); osmo_cc_session_codec_t *osmo_cc_add_codec(osmo_cc_session_media_t *media, const char *playload_name, uint32_t playload_rate, int playload_channels, void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len), void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len), int debug); void osmo_cc_free_codec(osmo_cc_session_codec_t *codec); int osmo_cc_session_check(struct osmo_cc_session *session, int remote); const char *osmo_cc_session_send_offer(osmo_cc_session_t *session); osmo_cc_session_t *osmo_cc_session_receive_offer(osmo_cc_session_config_t *conf, void *priv, const char *sdp); -void osmo_cc_session_accept_media(osmo_cc_session_media_t *media, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len)); +void osmo_cc_session_accept_media(osmo_cc_session_media_t *media, enum osmo_cc_session_nettype nettype, enum osmo_cc_session_addrtype addrtype, const char *address, int send, int receive, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len)); void osmo_cc_session_accept_codec(osmo_cc_session_codec_t *codec, void (*encoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len), void (*decoder)(uint8_t *src_data, int src_len, uint8_t **dst_data, int *dst_len)); const char *osmo_cc_session_send_answer(osmo_cc_session_t *session); int osmo_cc_session_receive_answer(osmo_cc_session_t *session, const char *sdp); diff --git a/src/libsamplerate/samplerate.h b/src/libsamplerate/samplerate.h index 4911ced..6844585 100644 --- a/src/libsamplerate/samplerate.h +++ b/src/libsamplerate/samplerate.h @@ -17,4 +17,6 @@ typedef struct samplerate { int init_samplerate(samplerate_t *state, double low_samplerate, double high_samplerate, double filter_cutoff); int samplerate_downsample(samplerate_t *state, sample_t *samples, int input_num); -int samplerate_upsample(samplerate_t *state, sample_t *input, int input_num, sample_t *output); +int samplerate_upsample_input_num(samplerate_t *state, int output_num); +int samplerate_upsample_output_num(samplerate_t *state, int input_num); +void samplerate_upsample(samplerate_t *state, sample_t *input, int input_num, sample_t *output, int output_num); diff --git a/src/mpt1327/dsp.c b/src/mpt1327/dsp.c index 4b6b7dc..066ce55 100644 --- a/src/mpt1327/dsp.c +++ b/src/mpt1327/dsp.c @@ -85,7 +85,7 @@ int dsp_init_sender(mpt1327_t *mpt1327, double squelch_db) mpt1327->dmp_frame_quality = display_measurements_add(&mpt1327->sender.dispmeas, "Frame Quality", "%.1f %% (last)", DISPLAY_MEAS_LAST, DISPLAY_MEAS_LEFT, 0.0, 100.0, 100.0); /* repeater */ - rc = jitter_create(&mpt1327->repeater_dejitter, mpt1327->sender.samplerate / 5); + rc = jitter_create(&mpt1327->repeater_dejitter, "repeater", mpt1327->sender.samplerate, sizeof(sample_t), 0.050, 0.500, JITTER_FLAG_NONE); if (rc < 0) { PDEBUG(DDSP, DEBUG_ERROR, "Failed to create and init repeater buffer!\n"); goto error; @@ -235,7 +235,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at if (mpt1327->dsp_mode == DSP_MODE_TRAFFIC) { /* if repeater mode, store sample in jitter buffer */ if (mpt1327->repeater) - jitter_save(&mpt1327->repeater_dejitter, samples, length); + jitter_save(&mpt1327->repeater_dejitter, samples, length, 0, 0, 0, 0); if (mpt1327->unit && mpt1327->unit->callref) { int count; @@ -279,6 +279,7 @@ static int fsk_send_bit(void *inst) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { mpt1327_t *mpt1327 = (mpt1327_t *) sender; + int input_num; if (mpt1327->dsp_mode == DSP_MODE_OFF) { memset(power, 0, length); @@ -289,7 +290,9 @@ void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length memset(power, 1, length); if (mpt1327->dsp_mode == DSP_MODE_TRAFFIC) { - jitter_load(&mpt1327->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); /* if repeater mode, sum samples from jitter buffer to samples */ if (mpt1327->repeater) { sample_t uplink[length]; diff --git a/src/mpt1327/mpt1327.c b/src/mpt1327/mpt1327.c index d87d476..5fdc2f4 100755 --- a/src/mpt1327/mpt1327.c +++ b/src/mpt1327/mpt1327.c @@ -1642,7 +1642,7 @@ void call_down_release(int callref, __attribute__((unused)) int cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { mpt1327_unit_t *unit; @@ -1652,11 +1652,8 @@ void call_down_audio(int callref, sample_t *samples, int count) if (!unit->tc) return; - if (unit->tc->state == STATE_BUSY && unit->tc->dsp_mode == DSP_MODE_TRAFFIC) { - sample_t up[(int)((double)count * unit->tc->sender.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&unit->tc->sender.srstate, samples, count, up); - jitter_save(&unit->tc->sender.dejitter, up, count); - } + if (unit->tc->state == STATE_BUSY && unit->tc->dsp_mode == DSP_MODE_TRAFFIC) + jitter_save(&unit->tc->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } void dump_info(void) diff --git a/src/nmt/dsp.c b/src/nmt/dsp.c index 627c120..072607c 100644 --- a/src/nmt/dsp.c +++ b/src/nmt/dsp.c @@ -446,7 +446,7 @@ static void dial_tone(nmt_t *nmt, sample_t *samples, int length) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { nmt_t *nmt = (nmt_t *) sender; - int count; + int count, input_num; memset(power, 1, length); @@ -454,7 +454,9 @@ again: switch (nmt->dsp_mode) { case DSP_MODE_AUDIO: case DSP_MODE_DTMF: - jitter_load(&nmt->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); /* send after dejitter, so audio is flushed */ if (nmt->dms.tx_frame_valid) { fsk_mod_send(&nmt->fsk_mod, samples, length, 0); diff --git a/src/nmt/nmt.c b/src/nmt/nmt.c index 26a3f77..287f3fb 100644 --- a/src/nmt/nmt.c +++ b/src/nmt/nmt.c @@ -1954,7 +1954,7 @@ void call_down_release(int callref, int __attribute__((unused)) cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { transaction_t *trans; nmt_t *nmt; @@ -1967,11 +1967,9 @@ void call_down_audio(int callref, sample_t *samples, int count) return; if (nmt->dsp_mode == DSP_MODE_AUDIO || nmt->dsp_mode == DSP_MODE_DTMF) { - sample_t up[(int)((double)count * nmt->sender.srstate.factor + 0.5) + 10]; if (nmt->compandor) compress_audio(&nmt->cstate, samples, count); - count = samplerate_upsample(&nmt->sender.srstate, samples, count, up); - jitter_save(&nmt->sender.dejitter, up, count); + jitter_save(&nmt->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } } diff --git a/src/pocsag/pocsag.c b/src/pocsag/pocsag.c index 1fb93f3..40da522 100644 --- a/src/pocsag/pocsag.c +++ b/src/pocsag/pocsag.c @@ -565,7 +565,7 @@ void call_down_release(int callref, int cause) } /* Receive audio from call instance. */ -void call_down_audio(int __attribute__((unused)) callref, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) +void call_down_audio(int __attribute__((unused)) callref, uint16_t __attribute__((unused)) sequence, uint32_t __attribute__((unused)) timestamp, uint32_t __attribute__((unused)) ssrc, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) { } diff --git a/src/r2000/dsp.c b/src/r2000/dsp.c index 4d28685..79ae05b 100644 --- a/src/r2000/dsp.c +++ b/src/r2000/dsp.c @@ -335,7 +335,7 @@ static int super_send_bit(void *inst) void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length) { r2000_t *r2000 = (r2000_t *) sender; - int count; + int count, input_num; again: switch (r2000->dsp_mode) { @@ -346,7 +346,9 @@ again: case DSP_MODE_AUDIO_TX: case DSP_MODE_AUDIO_TX_RX: memset(power, 1, length); - jitter_load(&r2000->sender.dejitter, samples, length); + input_num = samplerate_upsample_input_num(&sender->srstate, length); + jitter_load(&sender->dejitter, samples, input_num); + samplerate_upsample(&sender->srstate, samples, input_num, samples, length); iir_process(&r2000->super_tx_hp, samples, length); /* do pre-emphasis */ if (r2000->pre_emphasis) diff --git a/src/r2000/r2000.c b/src/r2000/r2000.c index ec5f5e7..d0397fb 100644 --- a/src/r2000/r2000.c +++ b/src/r2000/r2000.c @@ -1529,7 +1529,7 @@ void call_down_release(int callref, int __attribute__((unused)) cause) } /* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, uint16_t sequence, uint32_t timestamp, uint32_t ssrc, sample_t *samples, int count) { sender_t *sender; r2000_t *r2000; @@ -1544,11 +1544,9 @@ void call_down_audio(int callref, sample_t *samples, int count) if (r2000->dsp_mode == DSP_MODE_AUDIO_TX || r2000->dsp_mode == DSP_MODE_AUDIO_TX_RX) { - sample_t up[(int)((double)count * r2000->sender.srstate.factor + 0.5) + 10]; if (r2000->compandor) compress_audio(&r2000->cstate, samples, count); - count = samplerate_upsample(&r2000->sender.srstate, samples, count, up); - jitter_save(&r2000->sender.dejitter, up, count); + jitter_save(&r2000->sender.dejitter, samples, count, 1, sequence, timestamp, ssrc); } } diff --git a/src/radio/radio.c b/src/radio/radio.c index 5354622..cf2c233 100644 --- a/src/radio/radio.c +++ b/src/radio/radio.c @@ -106,8 +106,8 @@ int radio_init(radio_t *radio, int buffer_size, int samplerate, double frequency PDEBUG(DRADIO, DEBUG_ERROR, "Failed to open sound device!\n"); goto error; } - jitter_create(&radio->tx_dejitter[0], radio->tx_audio_samplerate / 5); - jitter_create(&radio->tx_dejitter[1], radio->tx_audio_samplerate / 5); + jitter_create(&radio->tx_dejitter[0], "left", radio->tx_audio_samplerate, sizeof(sample_t), 0.050, 0.500, JITTER_FLAG_NONE); + jitter_create(&radio->tx_dejitter[1], "right", radio->tx_audio_samplerate, sizeof(sample_t), 0.050, 0.500, JITTER_FLAG_NONE); radio->tx_audio_mode = AUDIO_MODE_AUDIODEV; #else rc = -ENOTSUP; @@ -173,8 +173,8 @@ int radio_init(radio_t *radio, int buffer_size, int samplerate, double frequency PDEBUG(DRADIO, DEBUG_ERROR, "Failed to open sound device!\n"); goto error; } - jitter_create(&radio->rx_dejitter[0], radio->rx_audio_samplerate / 5); - jitter_create(&radio->rx_dejitter[1], radio->rx_audio_samplerate / 5); + jitter_create(&radio->rx_dejitter[0], "left", radio->rx_audio_samplerate, sizeof(sample_t), 0.050, 0.500, JITTER_FLAG_NONE); + jitter_create(&radio->rx_dejitter[1], "right", radio->rx_audio_samplerate, sizeof(sample_t), 0.050, 0.500, JITTER_FLAG_NONE); radio->rx_audio_mode |= AUDIO_MODE_AUDIODEV; #else rc = -ENOTSUP; @@ -494,10 +494,10 @@ int radio_tx(radio_t *radio, float *baseband, int signal_num) else return 0; } - jitter_save(&radio->tx_dejitter[0], audio_samples[0], rc); + jitter_save(&radio->tx_dejitter[0], audio_samples[0], rc, 0, 0, 0 ,0); jitter_load(&radio->tx_dejitter[0], audio_samples[0], audio_num); if (radio->tx_audio_channels == 2) { - jitter_save(&radio->tx_dejitter[1], audio_samples[1], rc); + jitter_save(&radio->tx_dejitter[1], audio_samples[1], rc, 0, 0, 0 ,0); jitter_load(&radio->tx_dejitter[1], audio_samples[1], audio_num); } break; @@ -554,9 +554,10 @@ int radio_tx(radio_t *radio, float *baseband, int signal_num) } /* upsample */ - signal_num = samplerate_upsample(&radio->tx_resampler[0], audio_samples[0], audio_num, signal_samples[0]); + signal_num = samplerate_upsample_output_num(&radio->tx_resampler[0], audio_num); + samplerate_upsample(&radio->tx_resampler[0], audio_samples[0], audio_num, signal_samples[0], signal_num); if (radio->stereo) - samplerate_upsample(&radio->tx_resampler[1], audio_samples[1], audio_num, signal_samples[1]); + samplerate_upsample(&radio->tx_resampler[1], audio_samples[1], audio_num, signal_samples[1], signal_num); /* prepare baseband */ memset(baseband, 0, sizeof(float) * 2 * signal_num); @@ -727,9 +728,9 @@ int radio_rx(radio_t *radio, float *baseband, int signal_num) wave_write(&radio->wave_rx_rec, samples, audio_num); #ifdef HAVE_ALSA if ((radio->rx_audio_mode & AUDIO_MODE_AUDIODEV)) { - jitter_save(&radio->rx_dejitter[0], samples[0], audio_num); + jitter_save(&radio->rx_dejitter[0], samples[0], audio_num, 0, 0, 0 ,0); if (radio->rx_audio_channels == 2) - jitter_save(&radio->rx_dejitter[1], samples[1], audio_num); + jitter_save(&radio->rx_dejitter[1], samples[1], audio_num, 0, 0, 0 ,0); audio_num = sound_get_tosend(radio->rx_sound, radio->signal_buffer_size); jitter_load(&radio->rx_dejitter[0], samples[0], audio_num); if (radio->rx_audio_channels == 2) diff --git a/src/zeitansage/zeitansage.c b/src/zeitansage/zeitansage.c index 835e5af..5d036f1 100644 --- a/src/zeitansage/zeitansage.c +++ b/src/zeitansage/zeitansage.c @@ -395,7 +395,7 @@ void call_down_release(int callref, int cause) } /* Receive audio from call instance. */ -void call_down_audio(int __attribute__((unused)) callref, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) +void call_down_audio(int __attribute__((unused)) callref, uint16_t __attribute__((unused)) sequence, uint32_t __attribute__((unused)) timestamp, uint32_t __attribute__((unused)) ssrc, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) { }