diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 9123633638..60f8ca6d29 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -878,9 +878,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_inband_dtmf_session(switch_core_sessi typedef struct { switch_core_session_t *session; teletone_generation_session_t ts; + switch_queue_t *digit_queue; switch_buffer_t *audio_buffer; switch_mutex_t *mutex; int read; + int ready; } switch_inband_dtmf_generate_t; static int teletone_dtmf_generate_handler(teletone_generation_session_t * ts, teletone_tone_map_t * map) @@ -902,22 +904,36 @@ static switch_status_t generate_on_dtmf(switch_core_session_t *session, const sw { switch_channel_t *channel = switch_core_session_get_channel(session); switch_media_bug_t *bug = switch_channel_get_private(channel, "dtmf_generate"); - + switch_status_t status = SWITCH_STATUS_SUCCESS; + if (bug) { switch_inband_dtmf_generate_t *pvt = (switch_inband_dtmf_generate_t *) switch_core_media_bug_get_user_data(bug); if (pvt) { - char buf[2] = ""; switch_mutex_lock(pvt->mutex); - buf[0] = dtmf->digit; - teletone_run(&pvt->ts, buf); + if (pvt->ready) { + switch_dtmf_t *dt = NULL; + switch_zmalloc(dt, sizeof(*dt)); + *dt = *dtmf; + if (switch_queue_trypush(pvt->digit_queue, dt) == SWITCH_STATUS_SUCCESS) { + dt = NULL; + /* + SWITCH_STATUS_FALSE indicates pretend there never was a DTMF + since we will be generating it inband now. + */ + status = SWITCH_STATUS_FALSE; + } else { + free(dt); + } + } switch_mutex_unlock(pvt->mutex); - return SWITCH_STATUS_FALSE; } } - return SWITCH_STATUS_SUCCESS; + + return status; } + static switch_bool_t inband_dtmf_generate_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) { switch_inband_dtmf_generate_t *pvt = (switch_inband_dtmf_generate_t *) user_data; @@ -929,37 +945,63 @@ static switch_bool_t inband_dtmf_generate_callback(switch_media_bug_t *bug, void switch (type) { case SWITCH_ABC_TYPE_INIT: { + switch_queue_create(&pvt->digit_queue, 100, switch_core_session_get_pool(pvt->session)); switch_buffer_create_dynamic(&pvt->audio_buffer, 512, 1024, 0); teletone_init_session(&pvt->ts, 0, teletone_dtmf_generate_handler, pvt->audio_buffer); pvt->ts.rate = read_codec->implementation->actual_samples_per_second; pvt->ts.channels = 1; switch_mutex_init(&pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(pvt->session)); switch_core_event_hook_add_recv_dtmf(pvt->session, generate_on_dtmf); + switch_mutex_lock(pvt->mutex); + pvt->ready = 1; + switch_mutex_unlock(pvt->mutex); } break; case SWITCH_ABC_TYPE_CLOSE: { + switch_mutex_lock(pvt->mutex); + pvt->ready = 0; + switch_core_event_hook_remove_recv_dtmf(pvt->session, generate_on_dtmf); switch_buffer_destroy(&pvt->audio_buffer); teletone_destroy_session(&pvt->ts); - switch_core_event_hook_remove_recv_dtmf(pvt->session, generate_on_dtmf); + switch_mutex_unlock(pvt->mutex); } break; case SWITCH_ABC_TYPE_READ_REPLACE: case SWITCH_ABC_TYPE_WRITE_REPLACE: { switch_size_t bytes; + void *pop; + switch_mutex_lock(pvt->mutex); + + if (!pvt->ready) { + switch_mutex_unlock(pvt->mutex); + return SWITCH_FALSE; + } + if (pvt->read) { frame = switch_core_media_bug_get_read_replace_frame(bug); } else { frame = switch_core_media_bug_get_write_replace_frame(bug); } + + while (switch_queue_trypop(pvt->digit_queue, &pop) == SWITCH_STATUS_SUCCESS) { + switch_dtmf_t *dtmf = (switch_dtmf_t *) pop; + char buf[2] = ""; + + buf[0] = dtmf->digit; + pvt->ts.duration = dtmf->duration; + teletone_run(&pvt->ts, buf); + } + if (switch_buffer_inuse(pvt->audio_buffer) && (bytes = switch_buffer_read(pvt->audio_buffer, frame->data, frame->datalen))) { if (bytes < frame->datalen) { switch_byte_t *dp = frame->data; memset(dp + bytes, 0, frame->datalen - bytes); } } + if (pvt->read) { switch_core_media_bug_set_read_replace_frame(bug, frame); } else { diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 805ab36d38..8362021008 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -1038,6 +1038,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ READ_INC(rtp_session); while (switch_rtp_ready(rtp_session)) { + int do_cng = 0; + bytes = sizeof(rtp_msg_t); status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock, 0, (void *) &rtp_session->recv_msg, &bytes); @@ -1102,7 +1104,64 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } } - if (!bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_BREAK)) { + + /* RFC2833 ... like all RFC RE: VoIP, guarenteed to drive you to insanity! + We know the real rules here, but if we enforce them, it's an interop nightmare so, + we put up with as much as we can so we don't have to deal with being punished for + doing it right. Nice guys finish last! + */ + if (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->te) { + unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body; + int end = packet[1] & 0x80 ? 1 : 0; + uint16_t duration = (packet[2] << 8) + packet[3]; + char key = switch_rfc2833_to_char(packet[0]); + uint16_t in_digit_seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq); + + if (in_digit_seq > rtp_session->dtmf_data.in_digit_seq) { + uint32_t ts = htonl(rtp_session->recv_msg.header.ts); + //int m = rtp_session->recv_msg.header.m; + + rtp_session->dtmf_data.in_digit_seq = in_digit_seq; + + //printf("%c %u %u %u\n", key, in_digit_seq, ts, duration); + + if (rtp_session->dtmf_data.last_duration > duration && ts == rtp_session->dtmf_data.in_digit_ts) { + rtp_session->dtmf_data.flip++; + } + + if (end) { + if (rtp_session->dtmf_data.in_digit_ts) { + switch_dtmf_t dtmf = { key, duration }; + + if (ts > rtp_session->dtmf_data.in_digit_ts) { + dtmf.duration += (ts - rtp_session->dtmf_data.in_digit_ts); + } + if (rtp_session->dtmf_data.flip) { + dtmf.duration += rtp_session->dtmf_data.flip * 0xFFFF; + rtp_session->dtmf_data.flip = 0; + //printf("you're welcome!\n"); + } + + //printf("done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n", + //dtmf.digit, ts, rtp_session->dtmf_data.in_digit_ts, duration, dtmf.duration); + switch_rtp_queue_rfc2833_in(rtp_session, &dtmf); + switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_BREAK); + rtp_session->dtmf_data.last_digit = rtp_session->dtmf_data.first_digit; + } + rtp_session->dtmf_data.in_digit_ts = 0; + } else if (!rtp_session->dtmf_data.in_digit_ts) { + rtp_session->dtmf_data.in_digit_ts = ts; + rtp_session->dtmf_data.first_digit = key; + } + + rtp_session->dtmf_data.last_duration = duration; + + } + + do_cng = 1; + } + + if (do_cng || (!bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_BREAK))) { switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_BREAK); memset(&rtp_session->recv_msg.body, 0, 2); @@ -1239,69 +1298,15 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ rtp_session->rpayload = (switch_payload_t) rtp_session->recv_msg.header.pt; - /* RFC2833 ... like all RFC RE: VoIP, guarenteed to drive you to insanity! - We know the real rules here, but if we enforce them, it's an interop nightmare so, - we put up with as much as we can so we don't have to deal with being punished for - doing it right. Nice guys finish last! - */ - if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->te) { - unsigned char *packet = (unsigned char *) rtp_session->recv_msg.body; - int end = packet[1] & 0x80 ? 1 : 0; - uint16_t duration = (packet[2] << 8) + packet[3]; - char key = switch_rfc2833_to_char(packet[0]); - uint16_t in_digit_seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq); - - if (in_digit_seq > rtp_session->dtmf_data.in_digit_seq) { - uint32_t ts = htonl(rtp_session->recv_msg.header.ts); - //int m = rtp_session->recv_msg.header.m; - - rtp_session->dtmf_data.in_digit_seq = in_digit_seq; - - //printf("%c %u %u %u\n", key, in_digit_seq, ts, duration); - - if (rtp_session->dtmf_data.last_duration > duration && ts == rtp_session->dtmf_data.in_digit_ts) { - rtp_session->dtmf_data.flip++; - } - - if (end) { - if (rtp_session->dtmf_data.in_digit_ts) { - switch_dtmf_t dtmf = { key, duration }; - - if (ts > rtp_session->dtmf_data.in_digit_ts) { - dtmf.duration += (ts - rtp_session->dtmf_data.in_digit_ts); - } - if (rtp_session->dtmf_data.flip) { - dtmf.duration += rtp_session->dtmf_data.flip * 0xFFFF; - rtp_session->dtmf_data.flip = 0; - //printf("you're welcome!\n"); - } - - //printf("done digit=%c ts=%u start_ts=%u dur=%u ddur=%u\n", - //dtmf.digit, ts, rtp_session->dtmf_data.in_digit_ts, duration, dtmf.duration); - switch_rtp_queue_rfc2833_in(rtp_session, &dtmf); - switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_BREAK); - rtp_session->dtmf_data.last_digit = rtp_session->dtmf_data.first_digit; - } - rtp_session->dtmf_data.in_digit_ts = 0; - } else if (!rtp_session->dtmf_data.in_digit_ts) { - rtp_session->dtmf_data.in_digit_ts = ts; - rtp_session->dtmf_data.first_digit = key; - } - - rtp_session->dtmf_data.last_duration = duration; - - } - goto do_continue; - } break; do_continue: if (rtp_session->ms_per_packet) { - switch_yield((rtp_session->ms_per_packet / 1000) * 750); - } else { - switch_yield(1000); - } + switch_yield((rtp_session->ms_per_packet / 1000) * 750); + } else { + switch_yield(1000); + } } *payload_type = (switch_payload_t) rtp_session->recv_msg.header.pt; @@ -1437,7 +1442,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp } bytes = rtp_common_read(rtp_session, &frame->payload, &frame->flags); - + frame->data = rtp_session->recv_msg.body; frame->packet = &rtp_session->recv_msg; frame->packetlen = bytes;