diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 12b6a48bab..2ea19fb535 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -228,6 +228,38 @@ SWITCH_DECLARE(void) switch_rtp_set_invald_handler(switch_rtp_t *rtp_session, sw */ SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void *data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags); +/*! + \brief Queue RFC2833 DTMF data into an RTP Session + \param rtp_session the rtp session to use + \param digits the digit string to queue + \param duration the duration of the dtmf +*/ +SWITCH_DECLARE(switch_status_t) switch_rtp_queue_rfc2833(switch_rtp_t *rtp_session, char *digits, uint32_t duration); + +/*! + \brief Test for presence of DTMF on a given RTP session + \param rtp_session session to test + \return number of digits in the queue +*/ +SWITCH_DECLARE(switch_size_t) switch_rtp_has_dtmf(switch_rtp_t *rtp_session); + +/*! + \brief Queue DTMF on a given RTP session + \param rtp_session RTP session to queue DTMF to + \param dtmf string of digits to queue + \return SWITCH_STATUS_SUCCESS if successful +*/ +SWITCH_DECLARE(switch_status_t) switch_rtp_queue_dtmf(switch_rtp_t *rtp_session, char *dtmf); + +/*! + \brief Retrieve DTMF digits from a given RTP session + \param rtp_session RTP session to retrieve digits from + \param dtmf buffer to write dtmf to + \param len max size in bytes of the buffer + \return number of bytes read into the buffer +*/ +SWITCH_DECLARE(switch_size_t) switch_rtp_dequeue_dtmf(switch_rtp_t *rtp_session, char *dtmf, switch_size_t len); + /*! \brief Read data from a given RTP session without copying \param rtp_session the RTP session to read from @@ -237,7 +269,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void \param flags flags \return the number of bytes read */ -SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session, void **data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags); +SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session, + void **data, + uint32_t *datalen, + switch_payload_t *payload_type, + switch_frame_flag_t *flags); /*! \brief Read data from a given RTP session without copying diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 4bbae27ec6..d33f6f6f23 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -517,6 +517,8 @@ typedef enum { SWITCH_EVENT_TALK - Talking Detected SWITCH_EVENT_NOTALK - Not Talking Detected SWITCH_EVENT_SESSION_CRASH - Session Crashed + SWITCH_EVENT_MODULE_LOAD - Module was loaded + SWITCH_EVENT_DTMF - DTMF was sent SWITCH_EVENT_ALL - All events at once @@ -543,6 +545,7 @@ typedef enum { SWITCH_EVENT_NOTALK, SWITCH_EVENT_SESSION_CRASH, SWITCH_EVENT_MODULE_LOAD, + SWITCH_EVENT_DTMF, SWITCH_EVENT_ALL } switch_event_types_t; diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index a884b88d14..06aedbff0a 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -85,6 +85,13 @@ SWITCH_DECLARE(char) switch_rfc2833_to_char(int event); */ SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key); +/*! + \brief determine if a character is a valid DTMF key + \param key the key to test + \return TRUE or FALSE + */ +#define is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42) + /*! \brief Duplicate a string */ diff --git a/src/mod/endpoints/mod_dingaling/mod_dingaling.c b/src/mod/endpoints/mod_dingaling/mod_dingaling.c index dddb6f83ea..b4da2407e4 100644 --- a/src/mod/endpoints/mod_dingaling/mod_dingaling.c +++ b/src/mod/endpoints/mod_dingaling/mod_dingaling.c @@ -124,18 +124,9 @@ struct private_object { char *remote_user; unsigned int cand_id; unsigned int desc_id; - char last_digit; unsigned int dc; - time_t last_digit_time; - switch_queue_t *dtmf_queue; - char out_digit; - unsigned char out_digit_packet[4]; - unsigned int out_digit_sofar; - unsigned int out_digit_dur; - uint16_t out_digit_seq; int32_t timestamp_send; int32_t timestamp_recv; - int32_t timestamp_dtmf; uint32_t last_read; char *codec_name; switch_payload_t codec_num; @@ -718,11 +709,14 @@ static switch_status_t channel_send_dtmf(switch_core_session_t *session, char *d assert(tech_pvt != NULL); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "DTMF [%s]\n", dtmf); - snprintf(digits, sizeof(digits), "+%s\n", dtmf); - ldl_handle_send_msg(tech_pvt->profile->handle, tech_pvt->recip, NULL, digits); - + //snprintf(digits, sizeof(digits), "+%s\n", dtmf); + //ldl_handle_send_msg(tech_pvt->profile->handle, tech_pvt->recip, NULL, digits); - return SWITCH_STATUS_SUCCESS; + return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, + digits, + 100 * (tech_pvt->read_codec.implementation->samples_per_second / 1000)); + + //return SWITCH_STATUS_SUCCESS; } static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, @@ -769,41 +763,16 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch return SWITCH_STATUS_BREAK; } - /* RFC2833 ... TBD try harder to honor the duration etc.*/ - if (payload == 101) { - unsigned char *packet = tech_pvt->read_frame.data; - int end = packet[1]&0x80; - int duration = (packet[2]<<8) + packet[3]; - char key = switch_rfc2833_to_char(packet[0]); - - /* SHEESH.... Curse you RFC2833 inventors!!!!*/ - if ((time(NULL) - tech_pvt->last_digit_time) > 2) { - tech_pvt->last_digit = 0; - tech_pvt->dc = 0; - } - if (duration && end) { - if (key != tech_pvt->last_digit) { - char digit_str[] = {key, 0}; - time(&tech_pvt->last_digit_time); - switch_channel_queue_dtmf(channel, digit_str); - switch_set_flag(tech_pvt, TFLAG_DTMF); - } - if (++tech_pvt->dc >= 3) { - tech_pvt->last_digit = 0; - tech_pvt->dc = 0; - } - - tech_pvt->last_digit = key; - } else { - tech_pvt->last_digit = 0; - tech_pvt->dc = 0; - } - } - if (switch_test_flag(&tech_pvt->read_frame, SFF_CNG)) { tech_pvt->read_frame.datalen = tech_pvt->last_read ? tech_pvt->last_read : tech_pvt->read_codec.implementation->encoded_bytes_per_frame; } + if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { + char dtmf[128]; + switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf)); + switch_channel_queue_dtmf(channel, dtmf); + } + if (tech_pvt->read_frame.datalen > 0) { bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame; frames = (tech_pvt->read_frame.datalen / bytes); @@ -867,66 +836,6 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc frames = ((int) frame->datalen / bytes); samples = frames * tech_pvt->read_codec.implementation->samples_per_frame; - if (tech_pvt->out_digit_dur > 0) { - int x, ts, loops = 1, duration; - - tech_pvt->out_digit_sofar += samples; - - if (tech_pvt->out_digit_sofar >= tech_pvt->out_digit_dur) { - duration = tech_pvt->out_digit_dur; - tech_pvt->out_digit_packet[1] |= 0x80; - tech_pvt->out_digit_dur = 0; - loops = 3; - } else { - duration = tech_pvt->out_digit_sofar; - } - - ts = tech_pvt->timestamp_dtmf += samples; - tech_pvt->out_digit_packet[2] = (unsigned char) (duration >> 8); - tech_pvt->out_digit_packet[3] = (unsigned char) duration; - - - for (x = 0; x < loops; x++) { - switch_rtp_write_manual(tech_pvt->rtp_session, tech_pvt->out_digit_packet, 4, 0, 101, ts, tech_pvt->out_digit_seq, &frame->flags); - /* - printf("Send %s packet for [%c] ts=%d sofar=%u dur=%d\n", loops == 1 ? "middle" : "end", tech_pvt->out_digit, ts, - tech_pvt->out_digit_sofar, duration); - */ - } - } - - if (!tech_pvt->out_digit_dur && tech_pvt->dtmf_queue && switch_queue_size(tech_pvt->dtmf_queue)) { - void *pop; - - if (switch_queue_trypop(tech_pvt->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) { - int x, ts; - struct rfc2833_digit *rdigit = pop; - - memset(tech_pvt->out_digit_packet, 0, 4); - tech_pvt->out_digit_sofar = 0; - tech_pvt->out_digit_dur = rdigit->duration; - tech_pvt->out_digit = rdigit->digit; - tech_pvt->out_digit_packet[0] = (unsigned char)switch_char_to_rfc2833(rdigit->digit); - tech_pvt->out_digit_packet[1] = 7; - - ts = tech_pvt->timestamp_dtmf += samples; - tech_pvt->out_digit_seq++; - for (x = 0; x < 3; x++) { - switch_rtp_write_manual(tech_pvt->rtp_session, tech_pvt->out_digit_packet, 4, 1, 101, ts, tech_pvt->out_digit_seq, &frame->flags); - /* - printf("Send start packet for [%c] ts=%d sofar=%u dur=%d\n", tech_pvt->out_digit, ts, - tech_pvt->out_digit_sofar, 0); - */ - } - - free(rdigit); - } - } - - - - - //printf("%s send %d bytes %d samples in %d frames ts=%d\n", switch_channel_get_name(channel), frame->datalen, samples, frames, tech_pvt->timestamp_send); if (switch_rtp_write_frame(tech_pvt->rtp_session, frame, samples) < 0) { diff --git a/src/mod/endpoints/mod_exosip/mod_exosip.c b/src/mod/endpoints/mod_exosip/mod_exosip.c index 5a7a08c6b0..f4df159ba0 100644 --- a/src/mod/endpoints/mod_exosip/mod_exosip.c +++ b/src/mod/endpoints/mod_exosip/mod_exosip.c @@ -108,7 +108,6 @@ struct private_object { int tid; int32_t timestamp_send; int32_t timestamp_recv; - int32_t timestamp_dtmf; int payload_num; switch_rtp_t *rtp_session; struct osip_rfc3264 *sdp_config; @@ -120,24 +119,12 @@ struct private_object { switch_port_t local_sdp_audio_port; char call_id[50]; int ssrc; - char last_digit; - unsigned int dc; - time_t last_digit_time; - switch_queue_t *dtmf_queue; - char out_digit; switch_time_t last_read; - unsigned char out_digit_packet[4]; - unsigned int out_digit_sofar; - unsigned int out_digit_dur; - uint16_t out_digit_seq; char *realm; }; -struct rfc2833_digit { - char digit; - int duration; -}; + SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan) SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_extrtpip, globals.extrtpip) @@ -642,34 +629,10 @@ static switch_status_t exosip_read_frame(switch_core_session_t *session, switch_ return SWITCH_STATUS_BREAK; } - /* RFC2833 ... TBD try harder to honor the duration etc.*/ - if (payload == 101) { - unsigned char *packet = tech_pvt->read_frame.data; - int end = packet[1]&0x80; - int duration = (packet[2]<<8) + packet[3]; - char key = switch_rfc2833_to_char(packet[0]); - - /* SHEESH.... Curse you RFC2833 inventors!!!!*/ - if ((time(NULL) - tech_pvt->last_digit_time) > 2) { - tech_pvt->last_digit = 0; - tech_pvt->dc = 0; - } - if (duration && end) { - if (key != tech_pvt->last_digit) { - char digit_str[] = {key, 0}; - time(&tech_pvt->last_digit_time); - switch_channel_queue_dtmf(channel, digit_str); - } - if (++tech_pvt->dc >= 3) { - tech_pvt->last_digit = 0; - tech_pvt->dc = 0; - } - - tech_pvt->last_digit = key; - } else { - tech_pvt->last_digit = 0; - tech_pvt->dc = 0; - } + if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) { + char dtmf[128]; + switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf)); + switch_channel_queue_dtmf(channel, dtmf); } @@ -740,67 +703,6 @@ static switch_status_t exosip_write_frame(switch_core_session_t *session, switch } - if (tech_pvt->out_digit_dur > 0) { - int x, ts, loops = 1, duration; - - tech_pvt->out_digit_sofar += samples; - - if (tech_pvt->out_digit_sofar >= tech_pvt->out_digit_dur) { - duration = tech_pvt->out_digit_dur; - tech_pvt->out_digit_packet[1] |= 0x80; - tech_pvt->out_digit_dur = 0; - loops = 3; - } else { - duration = tech_pvt->out_digit_sofar; - } - - ts = tech_pvt->timestamp_dtmf += samples; - tech_pvt->out_digit_packet[2] = (unsigned char) (duration >> 8); - tech_pvt->out_digit_packet[3] = (unsigned char) duration; - - - for (x = 0; x < loops; x++) { - frame->flags = 0; - switch_rtp_write_manual(tech_pvt->rtp_session, - tech_pvt->out_digit_packet, 4, 0, 101, ts, - loops == 1 ? tech_pvt->out_digit_seq++ : tech_pvt->out_digit_seq, &frame->flags); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s packet for [%c] ts=%d sofar=%u dur=%d\n", - loops == 1 ? "middle" : "end", - tech_pvt->out_digit, - ts, - tech_pvt->out_digit_sofar, - duration); - } - } - - if (!tech_pvt->out_digit_dur && tech_pvt->dtmf_queue && switch_queue_size(tech_pvt->dtmf_queue)) { - void *pop; - - if (switch_queue_trypop(tech_pvt->dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) { - int x, ts; - struct rfc2833_digit *rdigit = pop; - - memset(tech_pvt->out_digit_packet, 0, 4); - tech_pvt->out_digit_sofar = 0; - tech_pvt->out_digit_dur = rdigit->duration; - tech_pvt->out_digit = rdigit->digit; - tech_pvt->out_digit_packet[0] = (unsigned char)switch_char_to_rfc2833(rdigit->digit); - tech_pvt->out_digit_packet[1] = 7; - - ts = tech_pvt->timestamp_dtmf += samples; - tech_pvt->out_digit_seq++; - for (x = 0; x < 3; x++) { - frame->flags = 0; - switch_rtp_write_manual(tech_pvt->rtp_session, tech_pvt->out_digit_packet, 4, 1, 101, ts, tech_pvt->out_digit_seq, &frame->flags); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send start packet for [%c] ts=%d sofar=%u dur=%d\n", tech_pvt->out_digit, ts, - tech_pvt->out_digit_sofar, 0); - } - - free(rdigit); - } - } - - //printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, tech_pvt->timestamp_send); @@ -869,29 +771,14 @@ static switch_status_t exosip_waitfor_write(switch_core_session_t *session, int static switch_status_t exosip_send_dtmf(switch_core_session_t *session, char *digits) { struct private_object *tech_pvt; - char *c; tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - if (!tech_pvt->dtmf_queue) { - switch_queue_create(&tech_pvt->dtmf_queue, 100, switch_core_session_get_pool(session)); - } - - for(c = digits; *c; c++) { - struct rfc2833_digit *rdigit; - - if ((rdigit = malloc(sizeof(*rdigit))) != 0) { - memset(rdigit, 0, sizeof(*rdigit)); - rdigit->digit = *c; - rdigit->duration = globals.dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000); - switch_queue_push(tech_pvt->dtmf_queue, rdigit); - } else { - return SWITCH_STATUS_MEMERR; - } - } - - return SWITCH_STATUS_SUCCESS; + return switch_rtp_queue_rfc2833(tech_pvt->rtp_session, + digits, + globals.dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000)); + } static switch_status_t exosip_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg) diff --git a/src/switch_channel.c b/src/switch_channel.c index d38e7bc9c5..e6fd9a76d8 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -238,7 +238,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_queue_dtmf(switch_channel_t *chan p = dtmf; while(wr < len && p) { - if (*p > 47 && *p < 58) { + if (is_dtmf(*p)) { wr++; } else { break; @@ -265,7 +265,7 @@ SWITCH_DECLARE(switch_size_t) switch_channel_dequeue_dtmf(switch_channel_t *chan } switch_mutex_unlock(channel->dtmf_mutex); - if (bytes && switch_event_create(&event, SWITCH_EVENT_CHANNEL_ANSWER) == SWITCH_STATUS_SUCCESS) { + if (bytes && switch_event_create(&event, SWITCH_EVENT_DTMF) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "DTMF-String", dtmf); switch_event_fire(&event); diff --git a/src/switch_event.c b/src/switch_event.c index f3cb34e4ac..6eb3e1fab3 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -111,6 +111,7 @@ static char *EVENT_NAMES[] = { "NOTALK", "SESSION_CRASH", "MODULE_LOAD", + "DTMF", "ALL" }; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 255296b7be..176c6a4496 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -58,6 +58,11 @@ typedef struct { } rtp_msg_t; +struct rfc2833_digit { + char digit; + int duration; +}; + struct switch_rtp_vad_data { switch_core_session_t *session; switch_codec_t vad_codec; @@ -80,6 +85,22 @@ struct switch_rtp_vad_data { time_t next_scan; }; + +struct switch_rtp_rfc2833_data { + switch_queue_t *dtmf_queue; + char out_digit; + unsigned char out_digit_packet[4]; + unsigned int out_digit_sofar; + unsigned int out_digit_dur; + uint16_t out_digit_seq; + int32_t timestamp_dtmf; + char last_digit; + unsigned int dc; + time_t last_digit_time; + switch_buffer_t *dtmf_buffer; + switch_mutex_t *dtmf_mutex; +}; + struct switch_rtp { switch_socket_t *sock; @@ -113,6 +134,7 @@ struct switch_rtp { uint8_t stuncount; switch_buffer_t *packet_buffer; struct switch_rtp_vad_data vad_data; + struct switch_rtp_rfc2833_data dtmf_data; }; static int global_init = 0; @@ -298,7 +320,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session rtp_session->pool = pool; rtp_session->flags = flags; - + switch_mutex_init(&rtp_session->dtmf_data.dtmf_mutex, SWITCH_MUTEX_NESTED, rtp_session->pool); + switch_buffer_create(rtp_session->pool, &rtp_session->dtmf_data.dtmf_buffer, 128); /* for from address on recvfrom calls */ switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, rtp_session->pool); @@ -514,6 +537,82 @@ SWITCH_DECLARE(void) switch_rtp_clear_flag(switch_rtp_t *rtp_session, switch_rtp } + +static void do_2833(switch_rtp_t *rtp_session) +{ + switch_frame_flag_t flags = 0; + uint32_t samples = rtp_session->packet_size; + + if (rtp_session->dtmf_data.out_digit_dur > 0) { + int x, ts, loops = 1, duration; + rtp_session->dtmf_data.out_digit_sofar += samples; + + if (rtp_session->dtmf_data.out_digit_sofar >= rtp_session->dtmf_data.out_digit_dur) { + duration = rtp_session->dtmf_data.out_digit_dur; + rtp_session->dtmf_data.out_digit_packet[1] |= 0x80; + rtp_session->dtmf_data.out_digit_dur = 0; + loops = 3; + } else { + duration = rtp_session->dtmf_data.out_digit_sofar; + } + + ts = rtp_session->dtmf_data.timestamp_dtmf += samples; + rtp_session->dtmf_data.out_digit_packet[2] = (unsigned char) (duration >> 8); + rtp_session->dtmf_data.out_digit_packet[3] = (unsigned char) duration; + + + for (x = 0; x < loops; x++) { + switch_rtp_write_manual(rtp_session, + rtp_session->dtmf_data.out_digit_packet, 4, 0, 101, ts, + loops == 1 ? rtp_session->dtmf_data.out_digit_seq++ : rtp_session->dtmf_data.out_digit_seq, &flags); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Send %s packet for [%c] ts=%d sofar=%u dur=%d\n", + loops == 1 ? "middle" : "end", + rtp_session->dtmf_data.out_digit, + ts, + rtp_session->dtmf_data.out_digit_sofar, + duration); + } + } + + if (!rtp_session->dtmf_data.out_digit_dur && rtp_session->dtmf_data.dtmf_queue && switch_queue_size(rtp_session->dtmf_data.dtmf_queue)) { + void *pop; + + if (switch_queue_trypop(rtp_session->dtmf_data.dtmf_queue, &pop) == SWITCH_STATUS_SUCCESS) { + int x, ts; + struct rfc2833_digit *rdigit = pop; + + memset(rtp_session->dtmf_data.out_digit_packet, 0, 4); + rtp_session->dtmf_data.out_digit_sofar = 0; + rtp_session->dtmf_data.out_digit_dur = rdigit->duration; + rtp_session->dtmf_data.out_digit = rdigit->digit; + rtp_session->dtmf_data.out_digit_packet[0] = (unsigned char)switch_char_to_rfc2833(rdigit->digit); + rtp_session->dtmf_data.out_digit_packet[1] = 7; + + ts = rtp_session->dtmf_data.timestamp_dtmf += samples; + rtp_session->dtmf_data.out_digit_seq++; + for (x = 0; x < 3; x++) { + switch_rtp_write_manual(rtp_session, + rtp_session->dtmf_data.out_digit_packet, + 4, + 1, + 101, + ts, + rtp_session->dtmf_data.out_digit_seq, + &flags); + switch_log_printf(SWITCH_CHANNEL_LOG, + SWITCH_LOG_DEBUG, + "Send start packet for [%c] ts=%d sofar=%u dur=%d\n", + rtp_session->dtmf_data.out_digit, + ts, + rtp_session->dtmf_data.out_digit_sofar, + 0); + } + + free(rdigit); + } + } +} + static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, switch_frame_flag_t *flags) { switch_size_t bytes; @@ -562,6 +661,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ rtp_session->next_read += rtp_session->ms_per_packet; } *payload_type = SWITCH_RTP_CNG_PAYLOAD; + do_2833(rtp_session); return SWITCH_RTP_CNG_PAYLOAD; } @@ -610,13 +710,138 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ rtp_session->next_read += rtp_session->ms_per_packet; *payload_type = rtp_session->recv_msg.header.pt; + + /* RFC2833 ... TBD try harder to honor the duration etc.*/ + if (*payload_type == 101) { + unsigned char *packet = rtp_session->recv_msg.body; + int end = packet[1]&0x80; + int duration = (packet[2]<<8) + packet[3]; + char key = switch_rfc2833_to_char(packet[0]); + + /* SHEESH.... Curse you RFC2833 inventors!!!!*/ + if ((time(NULL) - rtp_session->dtmf_data.last_digit_time) > 2) { + rtp_session->dtmf_data.last_digit = 0; + rtp_session->dtmf_data.dc = 0; + } + if (duration && end) { + if (key != rtp_session->dtmf_data.last_digit) { + char digit_str[] = {key, 0}; + time(&rtp_session->dtmf_data.last_digit_time); + switch_rtp_queue_dtmf(rtp_session, digit_str); + } + if (++rtp_session->dtmf_data.dc >= 3) { + rtp_session->dtmf_data.last_digit = 0; + rtp_session->dtmf_data.dc = 0; + } + + rtp_session->dtmf_data.last_digit = key; + } else { + rtp_session->dtmf_data.last_digit = 0; + rtp_session->dtmf_data.dc = 0; + } + } + + + if (*payload_type == SWITCH_RTP_CNG_PAYLOAD) { *flags |= SFF_CNG; } - + + if (bytes > 0) { + do_2833(rtp_session); + } return (int) bytes; } + + +SWITCH_DECLARE(switch_size_t) switch_rtp_has_dtmf(switch_rtp_t *rtp_session) +{ + switch_size_t has; + + assert(rtp_session != NULL); + switch_mutex_lock(rtp_session->dtmf_data.dtmf_mutex); + has = switch_buffer_inuse(rtp_session->dtmf_data.dtmf_buffer); + switch_mutex_unlock(rtp_session->dtmf_data.dtmf_mutex); + + return has; +} + +SWITCH_DECLARE(switch_status_t) switch_rtp_queue_dtmf(switch_rtp_t *rtp_session, char *dtmf) +{ + switch_status_t status; + register switch_size_t len, inuse; + switch_size_t wr = 0; + char *p; + + assert(rtp_session != NULL); + + switch_mutex_lock(rtp_session->dtmf_data.dtmf_mutex); + + inuse = switch_buffer_inuse(rtp_session->dtmf_data.dtmf_buffer); + len = strlen(dtmf); + + if (len + inuse > switch_buffer_len(rtp_session->dtmf_data.dtmf_buffer)) { + switch_buffer_toss(rtp_session->dtmf_data.dtmf_buffer, strlen(dtmf)); + } + + p = dtmf; + while(wr < len && p) { + if (is_dtmf(*p)) { + wr++; + } else { + break; + } + p++; + } + status = switch_buffer_write(rtp_session->dtmf_data.dtmf_buffer, dtmf, wr) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_MEMERR; + switch_mutex_unlock(rtp_session->dtmf_data.dtmf_mutex); + + return status; +} + + +SWITCH_DECLARE(switch_size_t) switch_rtp_dequeue_dtmf(switch_rtp_t *rtp_session, char *dtmf, switch_size_t len) +{ + switch_size_t bytes; + + assert(rtp_session != NULL); + + switch_mutex_lock(rtp_session->dtmf_data.dtmf_mutex); + if ((bytes = switch_buffer_read(rtp_session->dtmf_data.dtmf_buffer, dtmf, len)) > 0) { + *(dtmf + bytes) = '\0'; + } + switch_mutex_unlock(rtp_session->dtmf_data.dtmf_mutex); + + return bytes; + +} + + +SWITCH_DECLARE(switch_status_t) switch_rtp_queue_rfc2833(switch_rtp_t *rtp_session, char *digits, uint32_t duration) +{ + char *c; + + if (!rtp_session->dtmf_data.dtmf_queue) { + switch_queue_create(&rtp_session->dtmf_data.dtmf_queue, 100, rtp_session->pool); + } + + for(c = digits; *c; c++) { + struct rfc2833_digit *rdigit; + + if ((rdigit = malloc(sizeof(*rdigit))) != 0) { + memset(rdigit, 0, sizeof(*rdigit)); + rdigit->digit = *c; + rdigit->duration = duration; + switch_queue_push(rtp_session->dtmf_data.dtmf_queue, rdigit); + } else { + return SWITCH_STATUS_MEMERR; + } + } + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void *data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags) { @@ -664,7 +889,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp } -SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session, void **data, uint32_t *datalen, switch_payload_t *payload_type, switch_frame_flag_t *flags) +SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_session, + void **data, + uint32_t *datalen, + switch_payload_t *payload_type, + switch_frame_flag_t *flags) { int bytes = rtp_common_read(rtp_session, payload_type, flags);