From 8d0a8a0d479e41bc0e5caf288453e58199e98cb4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 15 Jun 2007 01:47:48 +0000 Subject: [PATCH] add session_displace api and app git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5366 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_ivr.h | 3 + .../applications/mod_commands/mod_commands.c | 79 ++++++++- .../applications/mod_dptools/mod_dptools.c | 59 ++++++- .../mod_soundtouch/mod_soundtouch.cpp | 9 +- src/switch_core_codec.c | 2 + src/switch_core_io.c | 4 +- src/switch_ivr_async.c | 155 +++++++++++++++++- 7 files changed, 302 insertions(+), 9 deletions(-) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 73e8d02dda..d4e8b51b5d 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -200,6 +200,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_unload_grammar(switch_c */ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, char *file, uint32_t limit, switch_file_handle_t *fh); +SWITCH_DECLARE(switch_status_t) switch_ivr_displace_session(switch_core_session_t *session, char *file, uint32_t limit, const char *flags); +SWITCH_DECLARE(switch_status_t) switch_ivr_stop_displace_session(switch_core_session_t *session, char *file); + /*! \brief Stop Recording a session \param session the session to stop recording diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 2773fb71be..c130332cf3 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -565,7 +565,7 @@ SWITCH_STANDARD_API(session_record_function) goto usage; } - if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) != 3) { + if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 3) { goto usage; } @@ -609,6 +609,73 @@ SWITCH_STANDARD_API(session_record_function) return SWITCH_STATUS_SUCCESS; } + +SWITCH_STANDARD_API(session_displace_function) +{ + switch_core_session_t *rsession = NULL; + char *mycmd = NULL, *argv[5] = { 0 }; + char *uuid = NULL, *action = NULL, *path = NULL; + int argc = 0; + uint32_t limit = 0; + char *flags = NULL; + + if (session) { + return SWITCH_STATUS_FALSE; + } + + if (switch_strlen_zero(cmd)) { + goto usage; + } + + if (!(mycmd = strdup(cmd))) { + goto usage; + } + + if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 3) { + goto usage; + } + + uuid = argv[0]; + action = argv[1]; + path = argv[2]; + limit = argv[3] ? atoi(argv[3]) : 0; + flags = argv[4]; + + if (!(rsession = switch_core_session_locate(uuid))) { + stream->write_function(stream, "-Error Cannot locate session!\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (switch_strlen_zero(action) || switch_strlen_zero(path)) { + goto usage; + } + + if (!strcasecmp(action, "start")) { + switch_ivr_displace_session(rsession, path, limit, flags); + } else if (!strcasecmp(action, "stop")) { + switch_ivr_stop_displace_session(rsession, path); + } else { + goto usage; + } + + goto done; + + usage: + + stream->write_function(stream, "INVALID SYNTAX\n"); + switch_safe_free(mycmd); + + + done: + + if (rsession) { + switch_core_session_rwunlock(rsession); + } + + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_API(pause_function) { switch_core_session_t *psession = NULL; @@ -1237,12 +1304,20 @@ static switch_api_interface_t session_record_api_interface = { /*.next */ &broadcast_api_interface }; +static switch_api_interface_t session_displace_api_interface = { + /*.interface_name */ "session_displace", + /*.desc */ "session displace", + /*.function */ session_displace_function, + /*.syntax */ " [start|stop] [] [mux]", + /*.next */ &broadcast_api_interface +}; + static switch_api_interface_t uuid_bridge_api_interface = { /*.interface_name */ "uuid_bridge", /*.desc */ "uuid_bridge", /*.function */ uuid_bridge_function, /*.syntax */ " ", - /*.next */ &session_record_api_interface + /*.next */ &session_displace_api_interface }; static switch_api_interface_t status_api_interface = { diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 80941fd42b..babfc9937e 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -789,6 +789,43 @@ static void playback_function(switch_core_session_t *session, char *data) } +static void displace_session_function(switch_core_session_t *session, char *data) +{ + switch_channel_t *channel; + char *path = NULL; + uint32_t limit = 0; + char *argv[6]; + int x, argc; + char *lbuf = NULL; + char *flags = NULL; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + if (data && (lbuf = switch_core_session_strdup(session, data)) + && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + path = argv[0]; + for(x = 0; x < argc; x++) { + if (strchr(argv[x], '+')) { + limit = atoi(argv[x]); + } else if (!switch_strlen_zero(argv[x])) { + flags = argv[x]; + } + } + switch_ivr_displace_session(session, path, limit, flags); + } +} + + +static void stop_displace_session_function(switch_core_session_t *session, char *data) +{ + switch_channel_t *channel; + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + switch_ivr_stop_displace_session(session, data); +} + static void record_function(switch_core_session_t *session, char *data) { @@ -995,6 +1032,26 @@ static switch_application_interface_t speak_application_interface = { &bridge_application_interface }; +static switch_application_interface_t displace_application_interface = { + /*.interface_name */ "displace", + /*.application_function */ displace_session_function, + /* long_desc */ "Displace audio from a file to the channels input", + /* short_desc */ "Displace File", + /* syntax */ " [+time_limit_ms] [mux]", + /* flags */ SAF_NONE, + &speak_application_interface +}; + +static switch_application_interface_t stop_displace_application_interface = { + /*.interface_name */ "displace", + /*.application_function */ stop_displace_session_function, + /* long_desc */ "Stop Displacing to a file", + /* short_desc */ "Stop Displace File", + /* syntax */ "", + /* flags */ SAF_NONE, + &displace_application_interface +}; + static switch_application_interface_t record_application_interface = { /*.interface_name */ "record", /*.application_function */ record_function, @@ -1002,7 +1059,7 @@ static switch_application_interface_t record_application_interface = { /* short_desc */ "Record File", /* syntax */ " [+time_limit_ms]", /* flags */ SAF_NONE, - &speak_application_interface + &stop_displace_application_interface }; diff --git a/src/mod/applications/mod_soundtouch/mod_soundtouch.cpp b/src/mod/applications/mod_soundtouch/mod_soundtouch.cpp index 62816f274e..2bb1e03c4a 100644 --- a/src/mod/applications/mod_soundtouch/mod_soundtouch.cpp +++ b/src/mod/applications/mod_soundtouch/mod_soundtouch.cpp @@ -257,8 +257,13 @@ static void soundtouch_start_function(switch_core_session_t *session, char *data char *lbuf = NULL; int x; - if (switch_channel_get_private(channel, "_soundtouch_")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n"); + if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_soundtouch_"))) { + if (!switch_strlen_zero(data) && !strcasecmp(data, "stop")) { + switch_channel_set_private(channel, "_soundtouch_", NULL); + switch_core_media_bug_remove(session, &bug); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n"); + } return; } diff --git a/src/switch_core_codec.c b/src/switch_core_codec.c index 770e11ff3a..3b840a354d 100644 --- a/src/switch_core_codec.c +++ b/src/switch_core_codec.c @@ -50,6 +50,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_codec(switch_core_s session->read_codec = codec; session->raw_read_frame.codec = session->read_codec; session->raw_write_frame.codec = session->read_codec; + session->enc_read_frame.codec = session->read_codec; + session->enc_write_frame.codec = session->read_codec; return SWITCH_STATUS_SUCCESS; } diff --git a/src/switch_core_io.c b/src/switch_core_io.c index fc827bb4d5..ea46448f81 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -241,7 +241,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi do_bugs = 0; if (bp->callback) { bp->read_replace_frame_in = read_frame; - bp->read_replace_frame_out = NULL; + bp->read_replace_frame_out = read_frame; if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_REPLACE)) == SWITCH_TRUE) { read_frame = bp->read_replace_frame_out; } @@ -509,7 +509,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess do_bugs = 0; if (bp->callback) { bp->write_replace_frame_in = write_frame; - bp->write_replace_frame_out = NULL; + bp->write_replace_frame_out = write_frame; if ((ok = bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE_REPLACE)) == SWITCH_TRUE) { write_frame = bp->write_replace_frame_out; } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index e081667e8b..537eeb945a 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -96,6 +96,151 @@ SWITCH_DECLARE(void) switch_ivr_session_echo(switch_core_session_t *session) } +typedef struct { + switch_file_handle_t fh; + int mux; +} displace_helper_t; + +static switch_bool_t displace_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) +{ + displace_helper_t *dh = (displace_helper_t *) user_data; + uint8_t data[SWITCH_RECOMMENDED_BUFFER_SIZE]; + switch_frame_t frame = { 0 }; + + frame.data = data; + frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE; + + switch (type) { + case SWITCH_ABC_TYPE_INIT: + break; + case SWITCH_ABC_TYPE_CLOSE: + if (dh) { + switch_core_file_close(&dh->fh); + } + break; + case SWITCH_ABC_TYPE_READ_REPLACE: + { + switch_frame_t *frame = switch_core_media_bug_get_read_replace_frame(bug); + if (dh && !dh->mux) { + memset(frame->data, 255, frame->datalen); + } + switch_core_media_bug_set_read_replace_frame(bug, frame); + } + break; + case SWITCH_ABC_TYPE_WRITE_REPLACE: + if (dh) { + switch_frame_t *frame = NULL; + switch_size_t len; + + frame = switch_core_media_bug_get_write_replace_frame(bug); + len = frame->samples; + + if (dh->mux) { + int16_t buf[1024]; + int16_t *fp = frame->data; + int x; + + switch_core_file_read(&dh->fh, buf, &len); + + for(x = 0; x < len; x++) { + int32_t mixed = fp[x] + buf[x]; + switch_normalize_to_16bit(mixed); + fp[x] = (int16_t) mixed; + } + } else { + switch_core_file_read(&dh->fh, frame->data, &len); + frame->samples = len; + frame->datalen = frame->samples * 2; + } + switch_core_media_bug_set_write_replace_frame(bug, frame); + } + break; + case SWITCH_ABC_TYPE_WRITE: + default: + break; + } + + return SWITCH_TRUE; +} + +SWITCH_DECLARE(switch_status_t) switch_ivr_stop_displace_session(switch_core_session_t *session, char *file) +{ + switch_media_bug_t *bug; + switch_channel_t *channel = switch_core_session_get_channel(session); + + assert(channel != NULL); + if ((bug = switch_channel_get_private(channel, file))) { + switch_channel_set_private(channel, file, NULL); + switch_core_media_bug_remove(session, &bug); + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; + +} + +SWITCH_DECLARE(switch_status_t) switch_ivr_displace_session(switch_core_session_t *session, char *file, uint32_t limit, const char *flags) +{ + switch_channel_t *channel; + switch_codec_t *read_codec; + switch_media_bug_t *bug; + switch_status_t status; + time_t to = 0; + displace_helper_t *dh; + + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + if ((bug = switch_channel_get_private(channel, file))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only 1 of the same file per channel please!\n"); + return SWITCH_STATUS_FALSE; + } + + if (!(dh = switch_core_session_alloc(session, sizeof(*dh)))) { + return SWITCH_STATUS_MEMERR; + } + + + + read_codec = switch_core_session_get_read_codec(session); + assert(read_codec != NULL); + + dh->fh.channels = read_codec->implementation->number_of_channels; + dh->fh.samplerate = read_codec->implementation->samples_per_second; + + + if (switch_core_file_open(&dh->fh, + file, + read_codec->implementation->number_of_channels, + read_codec->implementation->samples_per_second, + SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, + switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_core_session_reset(session); + return SWITCH_STATUS_GENERR; + } + + switch_channel_answer(channel); + + if (limit) { + to = time(NULL) + limit; + } + + if (flags && strchr(flags, 'm')) { + dh->mux++; + } + + if ((status = switch_core_media_bug_add(session, displace_callback, dh, to, SMBF_WRITE_REPLACE | SMBF_READ_REPLACE, &bug)) != SWITCH_STATUS_SUCCESS) { + switch_core_file_close(&dh->fh); + return status; + } + + switch_channel_set_private(channel, file, bug); + + return SWITCH_STATUS_SUCCESS; +} + static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) { @@ -158,14 +303,20 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t switch_status_t status; time_t to = 0; + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + if ((bug = switch_channel_get_private(channel, file))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Only 1 of the same file per channel please!\n"); + return SWITCH_STATUS_FALSE; + } + if (!fh) { if (!(fh = switch_core_session_alloc(session, sizeof(*fh)))) { return SWITCH_STATUS_MEMERR; } } - channel = switch_core_session_get_channel(session); - assert(channel != NULL); read_codec = switch_core_session_get_read_codec(session); assert(read_codec != NULL);