*/
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
\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
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
</pre>
SWITCH_EVENT_NOTALK,
SWITCH_EVENT_SESSION_CRASH,
SWITCH_EVENT_MODULE_LOAD,
+ SWITCH_EVENT_DTMF,
SWITCH_EVENT_ALL
} switch_event_types_t;
*/
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
*/
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;
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,
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);
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) {
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;
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)
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);
}
}
- 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);
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)
p = dtmf;
while(wr < len && p) {
- if (*p > 47 && *p < 58) {
+ if (is_dtmf(*p)) {
wr++;
} else {
break;
}
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);
"NOTALK",
"SESSION_CRASH",
"MODULE_LOAD",
+ "DTMF",
"ALL"
};
} 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;
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;
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;
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);
}
+
+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;
rtp_session->next_read += rtp_session->ms_per_packet;
}
*payload_type = SWITCH_RTP_CNG_PAYLOAD;
+ do_2833(rtp_session);
return SWITCH_RTP_CNG_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)
{
}
-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);