diff --git a/daemon/call.c b/daemon/call.c index d8532f827..69267e1ae 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -3444,6 +3444,7 @@ void call_media_free(struct call_media **mdp) { mutex_destroy(&md->dtmf_lock); g_slice_free1(sizeof(*md), md); g_queue_clear_full(&md->dtmf_recv, dtmf_event_free); + g_queue_clear_full(&md->dtmf_send, dtmf_event_free); mutex_destroy(&md->dtmf_lock); *mdp = NULL; } diff --git a/daemon/codec.c b/daemon/codec.c index 99d0abfd1..5aeab5cbb 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -2511,44 +2511,54 @@ static void delay_frame_manipulate(struct delay_frame *dframe) { AVFrame *frame = dframe->frame; - if (is_in_dtmf_event(&media->dtmf_recv, dframe->ts, frame->sample_rate, media->buffer_delay, - media->buffer_delay)) - { - struct call_monologue *ml = media->monologue; - enum block_dtmf_mode mode = dtmf_get_block_mode(dframe->mp.call, ml); + struct call_monologue *ml = media->monologue; + enum block_dtmf_mode mode = dtmf_get_block_mode(dframe->mp.call, ml); - switch (mode) { - case BLOCK_DTMF_SILENCE: + if (mode == BLOCK_DTMF_OFF) + return; + + mutex_lock(&media->dtmf_lock); + struct dtmf_event *dtmf_recv = is_in_dtmf_event(&media->dtmf_recv, dframe->ts, frame->sample_rate, + media->buffer_delay, media->buffer_delay); + struct dtmf_event *dtmf_send = is_in_dtmf_event(&media->dtmf_send, dframe->ts, frame->sample_rate, + media->buffer_delay, media->buffer_delay); + mutex_unlock(&media->dtmf_lock); + + if (!dtmf_send) { + if (!dtmf_recv) + return; + mode = BLOCK_DTMF_SILENCE; + } + + switch (mode) { + case BLOCK_DTMF_SILENCE: + memset(frame->extended_data[0], 0, frame->linesize[0]); + break; + case BLOCK_DTMF_TONE: + frame_fill_tone_samples(frame->format, frame->extended_data[0], dframe->ts, + frame->nb_samples, ml->tone_freq ? : 400, + ml->tone_vol ? : 10, frame->sample_rate, frame->channels); + break; + case BLOCK_DTMF_ZERO: + case BLOCK_DTMF_DTMF: + // if we have DTMF output, use silence, otherwise use a DTMF zero + if (dframe->ch->handler->dtmf_payload_type != -1) memset(frame->extended_data[0], 0, frame->linesize[0]); - break; - case BLOCK_DTMF_TONE: - frame_fill_tone_samples(frame->format, frame->extended_data[0], dframe->ts, - frame->nb_samples, ml->tone_freq ? : 400, - ml->tone_vol ? : 10, frame->sample_rate, frame->channels); - break; - case BLOCK_DTMF_ZERO: - case BLOCK_DTMF_DTMF: - // if we have DTMF output, use silence, otherwise use a DTMF zero - if (dframe->ch->handler->dtmf_payload_type != -1) - memset(frame->extended_data[0], 0, frame->linesize[0]); - else - frame_fill_dtmf_samples(frame->format, frame->extended_data[0], - dframe->ts, - frame->nb_samples, dtmf_code_from_char(ml->dtmf_digit), - ml->tone_vol ? : 10, frame->sample_rate, - frame->channels); - break; - case BLOCK_DTMF_RANDOM: - if (!media->dtmf_event_state) - media->dtmf_event_state = '0' + (ssl_random() % 10); - frame_fill_dtmf_samples(frame->format, frame->extended_data[0], dframe->ts, - frame->nb_samples, media->dtmf_event_state - '0', - 10, frame->sample_rate, + else + frame_fill_dtmf_samples(frame->format, frame->extended_data[0], + dframe->ts, + frame->nb_samples, dtmf_code_from_char(ml->dtmf_digit), + ml->tone_vol ? : 10, frame->sample_rate, frame->channels); - break; - default: - break; - } + break; + case BLOCK_DTMF_RANDOM: + frame_fill_dtmf_samples(frame->format, frame->extended_data[0], dframe->ts, + frame->nb_samples, dtmf_send->rand_code - '0', + 10, frame->sample_rate, + frame->channels); + break; + default: + break; } } static void delay_packet_manipulate(struct delay_frame *dframe) { diff --git a/daemon/dtmf.c b/daemon/dtmf.c index c2faab05a..0d82272cc 100644 --- a/daemon/dtmf.c +++ b/daemon/dtmf.c @@ -136,6 +136,10 @@ static void dtmf_end_event(struct call_media *media, unsigned int event, unsigne *ev = (struct dtmf_event) { .code = 0, .ts = ts, .volume = 0 }; g_queue_push_tail(&media->dtmf_recv, ev); + ev = g_slice_alloc0(sizeof(*ev)); + *ev = (struct dtmf_event) { .code = 0, .ts = ts, .volume = 0 }; + g_queue_push_tail(&media->dtmf_send, ev); + if (!dtmf_do_logging()) return; @@ -275,16 +279,20 @@ static void dtmf_code_event(struct call_media *media, char event, uint64_t ts, i // check trigger before setting new dtmf_start dtmf_check_trigger(media, event, ts, clockrate); - media->dtmf_event_state = 0; ev = g_slice_alloc0(sizeof(*ev)); *ev = (struct dtmf_event) { .code = event, .ts = ts, .volume = volume }; g_queue_push_tail(&media->dtmf_recv, ev); + ev = g_slice_alloc0(sizeof(*ev)); + *ev = (struct dtmf_event) { .code = event, .ts = ts, .volume = volume, + .rand_code = '0' + (ssl_random() % 10) }; + g_queue_push_tail(&media->dtmf_send, ev); + mutex_unlock(&media->dtmf_lock); } -bool is_in_dtmf_event(GQueue *events, uint32_t ts, int clockrate, unsigned int head, +struct dtmf_event *is_in_dtmf_event(GQueue *events, uint32_t ts, int clockrate, unsigned int head, unsigned int trail) { if (!clockrate) @@ -308,7 +316,7 @@ bool is_in_dtmf_event(GQueue *events, uint32_t ts, int clockrate, unsigned int h continue; // diff >= 0 and less than 10 seconds? that's a match. if (start_diff <= cutoff) - return true; + return ev; // anything else is a bad/outdated TS. stop. break; } @@ -320,12 +328,12 @@ bool is_in_dtmf_event(GQueue *events, uint32_t ts, int clockrate, unsigned int h if (end_diff == 0) // for end events, we wait until after the end continue; if (end_diff <= cutoff) - return false; + return NULL; break; } } - return false; + return NULL; } diff --git a/include/call.h b/include/call.h index f79bc42a2..d7eca02cf 100644 --- a/include/call.h +++ b/include/call.h @@ -407,7 +407,7 @@ struct call_media { unsigned long dtmf_ts; // TS of last processed end event // lists are append-only GQueue dtmf_recv; - unsigned int dtmf_event_state; + GQueue dtmf_send; #ifdef WITH_TRANSCODING union { diff --git a/include/dtmf.h b/include/dtmf.h index 8f8b6c95c..2bf1c1587 100644 --- a/include/dtmf.h +++ b/include/dtmf.h @@ -19,6 +19,7 @@ struct dtmf_event { int code; // char for start, zero for end int volume; uint64_t ts; + int rand_code; // state for random replace mode }; void dtmf_init(void); @@ -35,6 +36,6 @@ void dtmf_dsp_event(const struct dtmf_event *new_event, struct dtmf_event *cur_e enum block_dtmf_mode dtmf_get_block_mode(struct call *call, struct call_monologue *ml); bool is_pcm_dtmf_block_mode(enum block_dtmf_mode mode); bool is_dtmf_replace_mode(enum block_dtmf_mode mode); -bool is_in_dtmf_event(GQueue *, uint32_t ts, int clockrate, unsigned int head, unsigned int trail); +struct dtmf_event *is_in_dtmf_event(GQueue *, uint32_t ts, int clockrate, unsigned int head, unsigned int trail); #endif