[Freeswitch-svn] [commit] r7599 - freeswitch/trunk/src
Freeswitch SVN
anthm at freeswitch.org
Tue Feb 12 19:32:09 EST 2008
Author: anthm
Date: Tue Feb 12 19:32:09 2008
New Revision: 7599
Modified:
freeswitch/trunk/src/switch_ivr_async.c
freeswitch/trunk/src/switch_rtp.c
Log:
fix inband DTMF generation issue
Modified: freeswitch/trunk/src/switch_ivr_async.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr_async.c (original)
+++ freeswitch/trunk/src/switch_ivr_async.c Tue Feb 12 19:32:09 2008
@@ -878,9 +878,11 @@
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 @@
{
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 @@
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 {
Modified: freeswitch/trunk/src/switch_rtp.c
==============================================================================
--- freeswitch/trunk/src/switch_rtp.c (original)
+++ freeswitch/trunk/src/switch_rtp.c Tue Feb 12 19:32:09 2008
@@ -1038,6 +1038,8 @@
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 @@
}
}
- 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 @@
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 @@
}
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;
More information about the Freeswitch-svn
mailing list