提交 c0b192be authored 作者: Anthony Minessale's avatar Anthony Minessale

fix inband DTMF generation issue

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7599 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 57d9670a
......@@ -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 {
......
......@@ -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;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论