From 48ae14726b687539b0e240d5d233e6c75432fd99 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 27 Jan 2006 01:46:14 +0000 Subject: [PATCH] make test 'record' app in app_playback.c You are best off doing wav (trust me) It can record at 8 16 22 and 32 khz if you can manage to have a channel at that speed. syntax [record /tmp/blah.wav] dial * to end (dtmf only works in iax and portaudio {beg file to add it to mod_exosip}) git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@453 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_core.h | 18 +++- src/include/switch_ivr.h | 13 +++ .../applications/mod_playback/mod_playback.c | 22 ++++- src/mod/formats/mod_sndfile/mod_sndfile.c | 71 +++++++++----- src/switch_core.c | 11 ++- src/switch_ivr.c | 93 ++++++++++++++++++- 6 files changed, 196 insertions(+), 32 deletions(-) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 1221e3ff2c..a9562b28b1 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -641,6 +641,13 @@ SWITCH_DECLARE(switch_status) switch_core_codec_destroy(switch_codec *codec); */ SWITCH_DECLARE(switch_status) switch_core_session_set_read_codec(switch_core_session *session, switch_codec *codec); +/*! + \brief Retrieve the read codec from a given session + \param session session to retrieve from + \return a pointer to the codec +*/ +SWITCH_DECLARE(switch_codec *) switch_core_session_get_read_codec(switch_core_session *session); + /*! \brief Assign the write codec to a given session \param session session to add the codec to @@ -648,8 +655,15 @@ SWITCH_DECLARE(switch_status) switch_core_session_set_read_codec(switch_core_ses \return SWITCH_STATUS_SUCCESS if successful */ SWITCH_DECLARE(switch_status) switch_core_session_set_write_codec(switch_core_session *session, switch_codec *codec); -///\} +/*! + \brief Retrieve the write codec from a given session + \param session session to retrieve from + \return a pointer to the codec +*/ +SWITCH_DECLARE(switch_codec *) switch_core_session_get_write_codec(switch_core_session *session); + +///\} ///\defgroup db Database Functions ///\ingroup core1 ///\{ @@ -684,7 +698,7 @@ SWITCH_DECLARE(switch_status) switch_core_file_open(switch_file_handle *fh, char /*! \brief Read media from a file handle - \param fh the file handle to read from + \param fh the file handle to read from (must be initilized by you memset all 0 for read, fill in channels and rate for write) \param data the buffer to read the data to \param len the max size of the buffer \return SWITCH_STATUS_SUCCESS with len adjusted to the bytes read if successful diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 890360f34d..0f0209e090 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -64,6 +64,19 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, char *file, char *timer_name, switch_dtmf_callback_function dtmf_callback); + + + +/*! + \brief record a file from the session to a file + \param session the session to record from + \param file the path to the file + \param dtmf_callback code to execute if any dtmf is dialed during the recording + \return SWITCH_STATUS_SUCCESS if all is well +*/ +SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *session, + char *file, + switch_dtmf_callback_function dtmf_callback); /** @} */ diff --git a/src/mod/applications/mod_playback/mod_playback.c b/src/mod/applications/mod_playback/mod_playback.c index b1aafcc4c4..9f06cb52d4 100644 --- a/src/mod/applications/mod_playback/mod_playback.c +++ b/src/mod/applications/mod_playback/mod_playback.c @@ -73,9 +73,29 @@ void playback_function(switch_core_session *session, char *data) } + +void record_function(switch_core_session *session, char *data) +{ + switch_channel *channel; + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + if (switch_ivr_record_file(session, data, on_dtmf) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel); + } + +} + +static const switch_application_interface record_application_interface = { + /*.interface_name */ "record", + /*.application_function */ record_function +}; + static const switch_application_interface playback_application_interface = { /*.interface_name */ "playback", - /*.application_function */ playback_function + /*.application_function */ playback_function, + NULL,NULL,NULL, + /*.next*/ &record_application_interface }; static const switch_loadable_module_interface mod_playback_module_interface = { diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c index c76e6b0d49..99faee6285 100644 --- a/src/mod/formats/mod_sndfile/mod_sndfile.c +++ b/src/mod/formats/mod_sndfile/mod_sndfile.c @@ -46,7 +46,8 @@ switch_status sndfile_file_open(switch_file_handle *handle, char *path) sndfile_context *context; int mode = 0; char *ext; - + int ready = 1; + if (!(ext = strrchr(path, '.'))) { switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Invalid Format\n"); return SWITCH_STATUS_GENERR; @@ -67,40 +68,60 @@ switch_status sndfile_file_open(switch_file_handle *handle, char *path) return SWITCH_STATUS_GENERR; } - if (!(context = switch_core_alloc(handle->memory_pool, sizeof(*context)))) { return SWITCH_STATUS_MEMERR; } - if (!strcmp(ext, "r8") || !strcmp(ext, "raw")) { - context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16; - context->sfinfo.channels = 1; - context->sfinfo.samplerate = 8000; + if (mode & SFM_WRITE) { + context->sfinfo.channels = handle->channels; + context->sfinfo.samplerate = handle->samplerate; + if (handle->samplerate == 8000 || handle->samplerate == 16000) { + context->sfinfo.format |= SF_FORMAT_PCM_16; + } else if (handle->samplerate == 24000) { + context->sfinfo.format |= SF_FORMAT_PCM_24; + } else if (handle->samplerate == 32000) { + context->sfinfo.format |= SF_FORMAT_PCM_32; + } + + /* Could add more else if() but i am too lazy atm.. */ + if (!strcasecmp(ext, "wav")) { + context->sfinfo.format |= SF_FORMAT_WAV; + } else { + ready = 0; + } } - if (!strcmp(ext, "r16")) { - context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16; - context->sfinfo.channels = 1; - context->sfinfo.samplerate = 16000; + + if (!ready) { + if (!strcmp(ext, "r8") || !strcmp(ext, "raw")) { + context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16; + context->sfinfo.channels = 1; + context->sfinfo.samplerate = 8000; + } else if (!strcmp(ext, "r16")) { + context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16; + context->sfinfo.channels = 1; + context->sfinfo.samplerate = 16000; + } else if (!strcmp(ext, "r24")) { + context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_24; + context->sfinfo.channels = 1; + context->sfinfo.samplerate = 24000; + } else if (!strcmp(ext, "r32")) { + context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_32; + context->sfinfo.channels = 1; + context->sfinfo.samplerate = 32000; + } else if (!strcmp(ext, "gsm")) { + context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_GSM610; + context->sfinfo.channels = 1; + context->sfinfo.samplerate = 8000; + } } - if (!strcmp(ext, "r24")) { - context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_24; - context->sfinfo.channels = 1; - context->sfinfo.samplerate = 24000; - } - if (!strcmp(ext, "r32")) { - context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_32; - context->sfinfo.channels = 1; - context->sfinfo.samplerate = 32000; - } + if ((mode & SFM_WRITE) && sf_format_check (&context->sfinfo) == 0) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Error : file format is invalid (0x%08X).\n", context->sfinfo.format); + return SWITCH_STATUS_GENERR; + }; - if (!strcmp(ext, "gsm")) { - context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_GSM610; - context->sfinfo.channels = 1; - context->sfinfo.samplerate = 8000; - } if (!(context->handle = sf_open(path, mode, &context->sfinfo))) { switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Error Opening File [%s] [%s]\n", path, diff --git a/src/switch_core.c b/src/switch_core.c index 8f6b7e322c..294c54bdd6 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -212,6 +212,10 @@ SWITCH_DECLARE(switch_status) switch_core_session_set_read_codec(switch_core_ses return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_codec *) switch_core_session_get_read_codec(switch_core_session *session) +{ + return session->read_codec; +} SWITCH_DECLARE(switch_status) switch_core_session_set_write_codec(switch_core_session *session, switch_codec *codec) { @@ -221,6 +225,11 @@ SWITCH_DECLARE(switch_status) switch_core_session_set_write_codec(switch_core_se return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_codec *) switch_core_session_get_write_codec(switch_core_session *session) +{ + return session->write_codec; +} + SWITCH_DECLARE(switch_status) switch_core_codec_init(switch_codec *codec, char *codec_name, int rate, int ms, int channels, switch_codec_flag flags, const switch_codec_settings *codec_settings, @@ -361,8 +370,6 @@ SWITCH_DECLARE(switch_status) switch_core_file_open(switch_file_handle *fh, char char *ext; switch_status status; - memset(fh, 0, sizeof(*fh)); - if (!(ext = strrchr(file_path, '.'))) { switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Invalid Format\n"); return SWITCH_STATUS_FALSE; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 566b4cec37..71dc8bbaa7 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -33,7 +33,93 @@ #include -/* TBD (Lots! there is only 1 function in here lol) */ +/* TBD (Lots! there are only 2 functions in here lol) */ + + +SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *session, + char *file, + switch_dtmf_callback_function dtmf_callback) +{ + switch_channel *channel; + char dtmf[128]; + switch_file_handle fh; + switch_frame *read_frame; + switch_codec codec, *read_codec; + char *codec_name; + switch_status status = SWITCH_STATUS_SUCCESS; + + memset(&fh, 0, sizeof(fh)); + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + read_codec = switch_core_session_get_read_codec(session); + assert(read_codec != NULL); + + fh.channels = read_codec->implementation->number_of_channels; + fh.samplerate = read_codec->implementation->samples_per_second; + + + if (switch_core_file_open(&fh, + file, + SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, + switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(channel); + return SWITCH_STATUS_GENERR; + } + + switch_channel_answer(channel); + + + codec_name = "L16"; + if (switch_core_codec_init(&codec, + codec_name, + read_codec->implementation->samples_per_second, + read_codec->implementation->microseconds_per_frame / 1000, + read_codec->implementation->number_of_channels, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, + NULL, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activated\n"); + switch_core_session_set_read_codec(session, &codec); + } else { + switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activation Failed %s@%dhz %d channels %dms\n", + codec_name, fh.samplerate, fh.channels, read_codec->implementation->microseconds_per_frame / 1000); + switch_core_file_close(&fh); + return SWITCH_STATUS_GENERR; + } + + + while (switch_channel_get_state(channel) == CS_EXECUTE) { + int len; + + if (dtmf_callback) { + /* + dtmf handler function you can hook up to be executed when a digit is dialed during playback + if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. + */ + if (switch_channel_has_dtmf(channel)) { + switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf)); + status = dtmf_callback(session, dtmf); + } + + if (status != SWITCH_STATUS_SUCCESS) { + break; + } + } + + if (switch_core_session_read_frame(session, &read_frame, -1, 0) != SWITCH_STATUS_SUCCESS) { + break; + } + + len = read_frame->datalen / 2; + switch_core_file_write(&fh, read_frame->data, &len); + } + + switch_core_session_set_read_codec(session, read_codec); + switch_core_file_close(&fh); + + return status; +} SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, char *file, @@ -56,6 +142,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, int stream_id; switch_status status = SWITCH_STATUS_SUCCESS; + memset(&fh, 0, sizeof(fh)); channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -165,7 +252,9 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, } } else { /* time off the channel (if you must) */ switch_frame *read_frame; - switch_core_session_read_frame(session, &read_frame, -1, 0); + if (switch_core_session_read_frame(session, &read_frame, -1, 0) != SWITCH_STATUS_SUCCESS) { + break; + } } }