diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 6caa84fa83..eacb3c330e 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -90,6 +90,7 @@ SWITCH_DECLARE(switch_status) switch_core_session_write_frame(switch_core_sessio SWITCH_DECLARE(switch_status) switch_core_session_kill_channel(switch_core_session *session, switch_signal sig); SWITCH_DECLARE(switch_status) switch_core_session_waitfor_read(switch_core_session *session, int timeout); SWITCH_DECLARE(switch_status) switch_core_session_waitfor_write(switch_core_session *session, int timeout); +SWITCH_DECLARE(switch_status) switch_core_session_send_dtmf(switch_core_session *session, char *dtmf); SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_outgoing(switch_core_session *session, switch_outgoing_channel_hook outgoing_channel); SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_answer_channel(switch_core_session *session, switch_answer_channel_hook answer_channel); SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_read_frame(switch_core_session *session, switch_read_frame_hook read_frame); @@ -97,6 +98,7 @@ SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_write_frame(swi SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_kill_channel(switch_core_session *session, switch_kill_channel_hook kill_channel); SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_waitfor_read(switch_core_session *session, switch_waitfor_read_hook waitfor_read); SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_waitfor_write(switch_core_session *session, switch_waitfor_write_hook waitfor_write); +SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_send_dtmf(switch_core_session *session, switch_send_dtmf_hook send_dtmf); SWITCH_DECLARE(switch_status) switch_core_codec_init(switch_codec *codec, char *codec_name, int rate, int ms, switch_codec_flag flags, const switch_codec_settings *codec_settings); SWITCH_DECLARE(switch_status) switch_core_codec_encode(switch_codec *codec, switch_codec *other_codec, diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 2fa9dea4b8..378ebe3371 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -83,6 +83,11 @@ struct switch_io_event_hook_waitfor_write { struct switch_io_event_hook_waitfor_write *next; }; +struct switch_io_event_hook_send_dtmf { + switch_send_dtmf_hook send_dtmf; + struct switch_io_event_hook_send_dtmf *next; +}; + struct switch_io_event_hooks { struct switch_io_event_hook_outgoing_channel *outgoing_channel; struct switch_io_event_hook_answer_channel *answer_channel; @@ -91,6 +96,7 @@ struct switch_io_event_hooks { struct switch_io_event_hook_kill_channel *kill_channel; struct switch_io_event_hook_waitfor_read *waitfor_read; struct switch_io_event_hook_waitfor_write *waitfor_write; + struct switch_io_event_hook_send_dtmf *send_dtmf; }; struct switch_io_routines { @@ -101,6 +107,7 @@ struct switch_io_routines { switch_status (*kill_channel)(switch_core_session *, int); switch_status (*waitfor_read)(switch_core_session *, int); switch_status (*waitfor_write)(switch_core_session *, int); + switch_status (*send_dtmf)(switch_core_session *, char *); }; /* diff --git a/src/include/switch_types.h b/src/include/switch_types.h index a45be31339..14574c03b7 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -148,6 +148,7 @@ typedef struct switch_io_event_hook_write_frame switch_io_event_hook_write_frame typedef struct switch_io_event_hook_kill_channel switch_io_event_hook_kill_channel; typedef struct switch_io_event_hook_waitfor_read switch_io_event_hook_waitfor_read; typedef struct switch_io_event_hook_waitfor_write switch_io_event_hook_waitfor_write; +typedef struct switch_io_event_hook_send_dtmf switch_io_event_hook_send_dtmf; typedef struct switch_io_routines switch_io_routines; typedef struct switch_io_event_hooks switch_io_event_hooks; typedef struct switch_buffer switch_buffer; @@ -162,6 +163,7 @@ typedef switch_status (*switch_write_frame_hook)(switch_core_session *, switch_f typedef switch_status (*switch_kill_channel_hook)(switch_core_session *, int); typedef switch_status (*switch_waitfor_read_hook)(switch_core_session *, int); typedef switch_status (*switch_waitfor_write_hook)(switch_core_session *, int); +typedef switch_status (*switch_send_dtmf_hook)(switch_core_session *, char *); /* The pieces of apr we allow ppl to pass around between modules we typedef into our namespace and wrap all the functions diff --git a/src/mod/mod_iaxchan/mod_iaxchan.c b/src/mod/mod_iaxchan/mod_iaxchan.c index 3b84f8ae6a..7bf2bf9e64 100644 --- a/src/mod/mod_iaxchan/mod_iaxchan.c +++ b/src/mod/mod_iaxchan/mod_iaxchan.c @@ -353,9 +353,6 @@ static switch_status channel_write_frame(switch_core_session *session, switch_fr static switch_status channel_kill_channel(switch_core_session *session, int sig); - - - static void iax_err_cb(const char *s) { switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s", s); @@ -591,6 +588,22 @@ static switch_status channel_waitfor_write(switch_core_session *session, int ms) } +static switch_status channel_send_dtmf(switch_core_session *session, char *dtmf) +{ + struct private_object *tech_pvt = NULL; + char *digit; + + tech_pvt = switch_core_session_get_private(session); + assert(tech_pvt != NULL); + if (tech_pvt->iax_session) { + for(digit = dtmf; *digit; digit++) { + iax_send_dtmf(tech_pvt->iax_session, *digit); + } + } + + return SWITCH_STATUS_SUCCESS; +} + static switch_status channel_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) { switch_channel *channel = NULL; @@ -674,7 +687,8 @@ static const switch_io_routines channel_io_routines = { /*.write_frame*/ channel_write_frame, /*.kill_channel*/ channel_kill_channel, /*.waitfor_read*/ channel_waitfor_read, - /*.waitfor_write*/ channel_waitfor_write + /*.waitfor_write*/ channel_waitfor_write, + /*.send_dtmf*/ channel_send_dtmf }; static const switch_endpoint_interface channel_endpoint_interface = { @@ -938,6 +952,19 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void) break; case IAX_EVENT_REJECT: switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Rejected call.\n"); + break; + case IAX_EVENT_DTMF: + if ((tech_pvt = iax_get_private(iaxevent->session))) { + switch_channel *channel; + if ((channel = switch_core_session_get_channel(tech_pvt->session))) { + char str[2] = {iaxevent->subclass}; + if (globals.debug) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s DTMF %s\n", str, switch_channel_get_name(channel)); + } + switch_channel_queue_dtmf(channel, str); + } + } + break; default: switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Don't know what to do with IAX event %d.\n", iaxevent->etype); diff --git a/src/mod/mod_playback/mod_playback.c b/src/mod/mod_playback/mod_playback.c index d88e30125c..4f2f83d1d9 100644 --- a/src/mod/mod_playback/mod_playback.c +++ b/src/mod/mod_playback/mod_playback.c @@ -43,6 +43,7 @@ void playback_function(switch_core_session *session, char *data) switch_channel *channel; switch_file_t *fd; char buf[960]; + char dtmf[128]; int interval = 0, samples = 0; size_t len = 0, ilen = 0; switch_frame write_frame; @@ -99,7 +100,25 @@ void playback_function(switch_core_session *session, char *data) switch_core_service_session(session, &thread_session); ilen = len; while(switch_channel_get_state(channel) == CS_EXECUTE) { - if(switch_file_read(fd, buf, &ilen) != SWITCH_STATUS_SUCCESS) { + int done = 0; + + if (switch_channel_has_dtmf(channel)) { + switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf)); + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "DTMF [%s]\n", dtmf); + + switch (*dtmf) { + case '*': + done = 1; + break; + default: + break; + } + } + + if (done) { + break; + } + if (switch_file_read(fd, buf, &ilen) != SWITCH_STATUS_SUCCESS) { break; } diff --git a/src/switch_buffer.c b/src/switch_buffer.c index 8c70ad4a5a..2008839e7a 100644 --- a/src/switch_buffer.c +++ b/src/switch_buffer.c @@ -103,6 +103,7 @@ SWITCH_DECLARE(int) switch_buffer_read(switch_buffer *buffer, void *data, size_t if (buffer->used < 1) { + buffer->used = 0; return 0; } else if (buffer->used >= datalen) { reading = datalen; @@ -112,7 +113,7 @@ SWITCH_DECLARE(int) switch_buffer_read(switch_buffer *buffer, void *data, size_t memcpy(data, buffer->data, reading); memmove(buffer->data, buffer->data + reading, buffer->datalen - reading); - buffer->used -= datalen; + buffer->used -= reading; //printf("o %d = %d\n", reading, buffer->used); return (int)reading; } diff --git a/src/switch_channel.c b/src/switch_channel.c index acce3e909e..b25aa9ac46 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -35,6 +35,7 @@ struct switch_channel { time_t initiated; char *name; switch_buffer *dtmf_buffer; + switch_mutex_t *dtmf_mutex; switch_core_session *session; switch_channel_state state; switch_channel_flag flags; @@ -63,7 +64,8 @@ SWITCH_DECLARE(switch_status) switch_channel_alloc(switch_channel **channel, swi switch_core_hash_init(&(*channel)->variables, pool); switch_buffer_create(pool, &(*channel)->dtmf_buffer, 128); - + switch_mutex_init(&(*channel)->dtmf_mutex, SWITCH_MUTEX_NESTED, pool); + return SWITCH_STATUS_SUCCESS; } @@ -107,20 +109,31 @@ SWITCH_DECLARE(switch_status) switch_channel_get_raw_mode (switch_channel *chann SWITCH_DECLARE(int) switch_channel_has_dtmf(switch_channel *channel) { + int has; assert(channel != NULL); - return switch_buffer_inuse(channel->dtmf_buffer); + switch_mutex_lock(channel->dtmf_mutex); + has = switch_buffer_inuse(channel->dtmf_buffer); + switch_mutex_unlock(channel->dtmf_mutex); + + return has; } SWITCH_DECLARE(switch_status) switch_channel_queue_dtmf(switch_channel *channel, char *dtmf) { + switch_status status; + assert(channel != NULL); + switch_mutex_lock(channel->dtmf_mutex); if (switch_buffer_inuse(channel->dtmf_buffer) + strlen(dtmf) > (size_t)switch_buffer_len(channel->dtmf_buffer)) { switch_buffer_toss(channel->dtmf_buffer, strlen(dtmf)); } - return switch_buffer_write(channel->dtmf_buffer, dtmf, strlen(dtmf)); + status = switch_buffer_write(channel->dtmf_buffer, dtmf, strlen(dtmf)); + switch_mutex_unlock(channel->dtmf_mutex); + + return status; } @@ -129,9 +142,14 @@ SWITCH_DECLARE(int) switch_channel_dequeue_dtmf(switch_channel *channel, char *d int bytes; assert(channel != NULL); + + switch_mutex_lock(channel->dtmf_mutex); if ((bytes = switch_buffer_read(channel->dtmf_buffer, dtmf, len)) > 0) { *(dtmf + bytes) = '\0'; } + switch_mutex_unlock(channel->dtmf_mutex); + + return bytes; } diff --git a/src/switch_core.c b/src/switch_core.c index 2de1705c3b..2dbc93f995 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -816,6 +816,25 @@ SWITCH_DECLARE(switch_status) switch_core_session_waitfor_write(switch_core_sess return status; } + +SWITCH_DECLARE(switch_status) switch_core_session_send_dtmf(switch_core_session *session, char *dtmf) +{ + struct switch_io_event_hook_send_dtmf *ptr; + switch_status status = SWITCH_STATUS_FALSE; + + if (session->endpoint_interface->io_routines->send_dtmf) { + if ((status = session->endpoint_interface->io_routines->send_dtmf(session, dtmf)) == SWITCH_STATUS_SUCCESS) { + for (ptr = session->event_hooks.send_dtmf; ptr ; ptr = ptr->next) { + if ((status = ptr->send_dtmf(session, dtmf)) != SWITCH_STATUS_SUCCESS) { + break; + } + } + } + } + + return status; +} + SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_outgoing(switch_core_session *session, switch_outgoing_channel_hook outgoing_channel) { switch_io_event_hook_outgoing_channel *hook, *ptr; @@ -970,6 +989,29 @@ SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_waitfor_write(s } +SWITCH_DECLARE(switch_status) switch_core_session_add_event_hook_send_dtmf(switch_core_session *session, switch_send_dtmf_hook send_dtmf) +{ + switch_io_event_hook_send_dtmf *hook, *ptr; + + assert(send_dtmf != NULL); + if ((hook = switch_core_session_alloc(session, sizeof(*hook)))) { + hook->send_dtmf = send_dtmf; + if (!session->event_hooks.send_dtmf) { + session->event_hooks.send_dtmf = hook; + } else { + for(ptr = session->event_hooks.send_dtmf ; ptr && ptr->next; ptr = ptr->next); + ptr->next = hook; + + } + + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_MEMERR; + +} + + SWITCH_DECLARE(switch_status) switch_core_new_memory_pool(switch_memory_pool **pool) { assert(runtime.memory_pool != NULL);