]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
gather 2833 into RTP core and a few tweaks
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 4 May 2006 17:51:53 +0000 (17:51 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 4 May 2006 17:51:53 +0000 (17:51 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1351 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_rtp.h
src/include/switch_types.h
src/include/switch_utils.h
src/mod/endpoints/mod_dingaling/mod_dingaling.c
src/mod/endpoints/mod_exosip/mod_exosip.c
src/switch_channel.c
src/switch_event.c
src/switch_rtp.c

index 12b6a48bab69742dc8fb96a8f5fba12f2778d21d..2ea19fb53570be9f5dac8440457ca70a894ddd3c 100644 (file)
@@ -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
index 4bbae27ec652a0517fc27180cbd7da473f53d26d..d33f6f6f23bbb662f486c5958a00a6c32ab07e56 100644 (file)
@@ -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
 </pre>
 
@@ -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;
 
index a884b88d1436ff3384c4e054661c33179a411c32..06aedbff0ab090359300ab1065665458308d3c57 100644 (file)
@@ -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 
 */
index dddb6f83ea41a2ab1f015a2e7b4d92aed5a4b8da..b4da2407e49f1e2306304729a1939d6c3cb37b3f 100644 (file)
@@ -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) {
index 5a7a08c6b057c0f92f2995bc08555f4c3bdb53ee..f4df159ba0e589e3a5f50771dfcff5bbc47fa47c 100644 (file)
@@ -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)
index d38e7bc9c5d96a7a5093be0b70dd86a28de97898..e6fd9a76d81daa957975a45a3b981d1413e9a743 100644 (file)
@@ -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);
index f3cb34e4ac419051936459dcd47cec54b4a72c7c..6eb3e1fab315e6d5e439ff4412ea46cfaf3df1e6 100644 (file)
@@ -111,6 +111,7 @@ static char *EVENT_NAMES[] = {
        "NOTALK",
        "SESSION_CRASH",
        "MODULE_LOAD",
+       "DTMF",
        "ALL"
 };
 
index 255296b7be18ac18ffb704ea2e9f9da26df2d036..176c6a4496dc5c64702dee2ce0135c31e6a7d6bd 100644 (file)
@@ -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);