]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
fix inband DTMF generation issue
authorAnthony Minessale <anthony.minessale@gmail.com>
Wed, 13 Feb 2008 00:32:09 +0000 (00:32 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Wed, 13 Feb 2008 00:32:09 +0000 (00:32 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7599 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/switch_ivr_async.c
src/switch_rtp.c

index 9123633638ed6304b70a7648d207e8cb9b1e6dac..60f8ca6d2998fe58d36cf4eb188d58252ad5df2f 100644 (file)
@@ -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 {
index 805ab36d383b95dcfa6d3d7a3281d818b8df2ec7..836202100841a0e0ee340a7dd0864ec74c38f951 100644 (file)
@@ -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;