]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Stings of files
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 28 Apr 2009 23:46:18 +0000 (23:46 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 28 Apr 2009 23:46:18 +0000 (23:46 +0000)
method 1 high level (core most funcs that use switch_ivr_playback)

Delimiter is set by a var which also enables the parser
<action application="set" data="playback_delimiter=!"/>
<action application="set" data="playback_sleep_val=500"/>
<action application="playback" data="/ram/sr8k.wav!/ram/swimp.wav"/>

method 2 low level (mod_file_string lower level code that uses direct file handles)

Delimiter is always !
<action application="playback" data="file_string:///ram/sr8k.wav!/ram/swimp.wav"/>

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@13182 d0543943-73ff-0310-b7d9-9358b9ac24b2

build/modules.conf.in
conf/autoload_configs/modules.conf.xml
src/mod/applications/mod_dptools/mod_dptools.c
src/mod/formats/mod_file_string/Makefile [new file with mode: 0644]
src/mod/formats/mod_file_string/mod_file_string.2008.vcproj [new file with mode: 0644]
src/mod/formats/mod_file_string/mod_file_string.c [new file with mode: 0644]
src/mod/formats/mod_file_string/mod_file_string.vcproj [new file with mode: 0644]
src/switch_ivr_play_say.c

index b460814aa2b2448a782847d78f9f4cadc22a19b7..dc0b834d4f6c56f51a031b21a128ac5a3c7a2b85 100644 (file)
@@ -59,6 +59,7 @@ formats/mod_sndfile
 #formats/mod_shout
 formats/mod_local_stream
 formats/mod_tone_stream
+formats/mod_file_string
 #languages/mod_python
 languages/mod_spidermonkey
 languages/mod_spidermonkey_teletone
index 2c244c93d4119b0d57cbfc5cef96fed72d619cd0..265e0dd491a681e45bc0e59c4569adbb2ba96881 100644 (file)
@@ -79,6 +79,7 @@
     <!--For local streams (play all the files in a directory)-->
     <load module="mod_local_stream"/>
     <load module="mod_tone_stream"/>
+    <load module="mod_file_string"/>
 
     <!-- Timers -->
 
index 4b11e7fdbd6c06257595e9ad5597ab08a543ef34..72b09fe06666b1d3910a8ad586ba152ace67fa1b 100644 (file)
@@ -40,8 +40,6 @@ SWITCH_MODULE_DEFINITION(mod_dptools, mod_dptools_load, NULL, NULL);
 SWITCH_STANDARD_DIALPLAN(inline_dialplan_hunt)
 {
        switch_caller_extension_t *extension = NULL;
-       char *argv[128] = { 0 };
-       int argc;
        switch_channel_t *channel = switch_core_session_get_channel(session);
        int x = 0;
        char *lbuf;
@@ -1834,7 +1832,7 @@ SWITCH_STANDARD_APP(playback_function)
 {
        switch_input_args_t args = { 0 };
        switch_channel_t *channel = switch_core_session_get_channel(session);
-       switch_status_t status;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
 
        args.input_callback = on_dtmf;
 
diff --git a/src/mod/formats/mod_file_string/Makefile b/src/mod/formats/mod_file_string/Makefile
new file mode 100644 (file)
index 0000000..2c35e6e
--- /dev/null
@@ -0,0 +1,2 @@
+BASE=../../../..
+include $(BASE)/build/modmake.rules
diff --git a/src/mod/formats/mod_file_string/mod_file_string.2008.vcproj b/src/mod/formats/mod_file_string/mod_file_string.2008.vcproj
new file mode 100644 (file)
index 0000000..02d3dea
--- /dev/null
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="9.00"\r
+       Name="mod_file_string"\r
+       ProjectGUID="{2CA40887-1622-46A1-A7F9-17FD7E7E545B}"\r
+       RootNamespace="mod_file_string"\r
+       Keyword="Win32Proj"\r
+       TargetFrameworkVersion="131072"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+               <Platform\r
+                       Name="x64"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               UsePrecompiledHeader="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               RandomizedBaseAddress="1"\r
+                               DataExecutionPrevention="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Debug|x64"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               TargetEnvironment="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               UsePrecompiledHeader="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"\r
+                               RandomizedBaseAddress="1"\r
+                               DataExecutionPrevention="0"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               UsePrecompiledHeader="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               RandomizedBaseAddress="1"\r
+                               DataExecutionPrevention="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|x64"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               TargetEnvironment="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               UsePrecompiledHeader="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"\r
+                               RandomizedBaseAddress="1"\r
+                               DataExecutionPrevention="0"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <File\r
+                       RelativePath=".\mod_file_string.c"\r
+                       >\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/formats/mod_file_string/mod_file_string.c b/src/mod/formats/mod_file_string/mod_file_string.c
new file mode 100644 (file)
index 0000000..6ce064b
--- /dev/null
@@ -0,0 +1,188 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Cesar Cepeda <cesar@auronix.com>
+ *
+ *
+ * mod_file_string.c -- Local Streaming Audio
+ *
+ */
+#include <switch.h>
+/* for apr_pstrcat */
+#define DEFAULT_PREBUFFER_SIZE 1024 * 64
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_file_string_load);
+
+SWITCH_MODULE_DEFINITION(mod_file_string, mod_file_string_load, NULL, NULL);
+
+
+struct file_string_source;
+
+static struct {
+       switch_mutex_t *mutex;
+       switch_hash_t *source_hash;
+} globals;
+
+struct file_string_context {
+       char *argv[128];
+       int argc;
+       int index;
+       int samples;
+       switch_file_handle_t fh;
+};
+
+typedef struct file_string_context file_string_context_t;
+
+
+static int next_file(switch_file_handle_t *handle)
+{
+       file_string_context_t *context = handle->private_info;
+
+       context->index++;
+       
+       if (switch_test_flag((&context->fh), SWITCH_FILE_OPEN)) {
+               switch_core_file_close(&context->fh);
+       }
+
+       if (context->index == context->argc) {
+               return 0;
+       }
+
+       if (switch_core_file_open(&context->fh,
+                                                         context->argv[context->index],
+                                                         handle->channels,
+                                                         handle->samplerate,
+                                                         SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
+               return 0;
+       }
+       
+       handle->samples = context->fh.samples;
+       handle->samplerate = context->fh.samplerate;
+       handle->channels = context->fh.channels;
+       handle->format = context->fh.format;
+       handle->sections = context->fh.sections;
+       handle->seekable = context->fh.seekable;
+       handle->speed = context->fh.speed;
+       handle->interval = context->fh.interval;
+       
+       if (context->index == 0) {
+               context->samples = (handle->samplerate / 1000) * 250;
+       }
+
+       return 1;
+}
+
+static switch_status_t file_string_file_open(switch_file_handle_t *handle, const char *path)
+{
+       file_string_context_t *context;
+       char *file_dup;
+
+       if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing!\n");
+               return SWITCH_STATUS_FALSE;
+       }
+       
+       context = switch_core_alloc(handle->memory_pool, sizeof(*context));
+       
+       file_dup = switch_core_strdup(handle->memory_pool, path);
+       context->argc = switch_separate_string(file_dup, '!', context->argv, (sizeof(context->argv) / sizeof(context->argv[0])));
+       context->index = -1;
+       
+       handle->private_info = context;
+       
+       return next_file(handle) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
+}
+
+static switch_status_t file_string_file_close(switch_file_handle_t *handle)
+{
+       file_string_context_t *context = handle->private_info;
+
+       switch_core_file_close(&context->fh);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t file_string_file_read(switch_file_handle_t *handle, void *data, size_t *len)
+{
+       file_string_context_t *context = handle->private_info;
+       switch_status_t status;
+       size_t llen = *len;
+
+       if (context->samples > 0) {
+               if (*len > (size_t)context->samples) {
+                       *len = context->samples;
+               }
+               
+               context->samples -= *len;
+               switch_generate_sln_silence((int16_t *) data, *len, 400);
+               status = SWITCH_STATUS_SUCCESS;
+       } else {
+               status = switch_core_file_read(&context->fh, data, len);
+       }
+       
+       if (status != SWITCH_STATUS_SUCCESS) {
+               if (!next_file(handle)) {
+                       return SWITCH_STATUS_FALSE;
+               }
+               *len = llen;
+               status = switch_core_file_read(&context->fh, data, len);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/* Registration */
+
+static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_file_string_load)
+{
+       switch_file_interface_t *file_interface;
+       supported_formats[0] = "file_string";
+
+       *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+       file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
+       file_interface->interface_name = modname;
+       file_interface->extens = supported_formats;
+       file_interface->file_open = file_string_file_open;
+       file_interface->file_close = file_string_file_close;
+       file_interface->file_read = file_string_file_read;
+
+       memset(&globals, 0, sizeof(globals));
+       /* indicate that the module should continue to be loaded */
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
diff --git a/src/mod/formats/mod_file_string/mod_file_string.vcproj b/src/mod/formats/mod_file_string/mod_file_string.vcproj
new file mode 100644 (file)
index 0000000..6393002
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_file_string"\r
+       ProjectGUID="{2CA40887-1622-46A1-A7F9-17FD7E7E545B}"\r
+       RootNamespace="mod_file_string"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               UsePrecompiledHeader="0"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               UsePrecompiledHeader="0"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <File\r
+                       RelativePath=".\mod_file_string.c"\r
+                       >\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
index 12e496afe0c9afdfcd5b3ddd406c33c5aa91b04c..7825764c7b8a6dd06fbd92348f87577626b32125 100644 (file)
@@ -354,7 +354,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro(switch_core_session_t *s
                input = input->next;
        }
 
 done:
+ done:
 
        if (hint_data) {
                switch_event_destroy(&hint_data);
@@ -588,9 +588,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se
 
                if (args && (args->input_callback || args->buf || args->buflen)) {
                        /*
-                          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.
-                        */
+                         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)) {
                                if (!args->input_callback && !args->buf) {
                                        status = SWITCH_STATUS_BREAK;
@@ -769,9 +769,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_gentones(switch_core_session_t *sessi
 
                if (args && (args->input_callback || args->buf || args->buflen)) {
                        /*
-                          dtmf handler function you can hook up to be executed when a digit is dialed during gentones 
-                          if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
-                        */
+                         dtmf handler function you can hook up to be executed when a digit is dialed during gentones 
+                         if you return anything but SWITCH_STATUS_SUCCESS the playback will stop.
+                       */
                        if (switch_channel_has_dtmf(channel)) {
                                if (!args->input_callback && !args->buf) {
                                        status = SWITCH_STATUS_BREAK;
@@ -848,12 +848,34 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
        const char *timer_name;
        const char *prebuf;
        const char *alt = NULL;
+       const char *sleep_val;
+       const char *play_delimiter_val;
+       char play_delimiter = 0;
+       int sleep_val_i = 250;
        int eof = 0;
        switch_size_t bread = 0;
        int l16 = 0;
     switch_codec_implementation_t read_impl = {0};
+       char *file_dup;
+       char *argv[128] = { 0 };
+       int argc;
+       int cur;
+       switch_status_t rst;
+
+       
     switch_core_session_get_read_impl(session, &read_impl);
 
+       if ((play_delimiter_val = switch_channel_get_variable(channel, "playback_delimiter"))) {
+               play_delimiter = *play_delimiter_val;
+
+               if ((sleep_val = switch_channel_get_variable(channel, "playback_sleep_val"))) {
+                       int tmp = atoi(sleep_val);
+                       if (tmp >= 0) {
+                               sleep_val_i = tmp;
+                       }
+               }
+       }
+
        if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
                return SWITCH_STATUS_FALSE;
        }
@@ -862,489 +884,528 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
        timer_name = switch_channel_get_variable(channel, "timer_name");
 
        if (switch_strlen_zero(file) || !switch_channel_media_ready(channel)) {
-               status = SWITCH_STATUS_FALSE;
-               goto end;
+               return SWITCH_STATUS_FALSE;
        }
 
        if (!strcasecmp(read_impl.iananame, "l16")) {
                l16++;
        }
 
-       if ((alt = strchr(file, ':'))) {
-               char *dup;
+       
+       if (play_delimiter) {
+               file_dup = switch_core_session_strdup(session, file);
+               argc = switch_separate_string(file_dup, play_delimiter, argv, (sizeof(argv) / sizeof(argv[0])));
+       } else {
+               argc = 1;
+               argv[0] = (char *)file;
+       }
+
+       for(cur = 0; switch_channel_ready(channel) && cur < argc; cur++) {
+               file = argv[cur];
+               asis = 0;
+               eof = 0;
+               
+               if (cur) {
+                       fh->samples = sample_start = 0;
+                       if (sleep_val_i) {
+                               switch_ivr_sleep(session, sleep_val_i, SWITCH_FALSE, args);
+                       }
+               }
+               
+               status = SWITCH_STATUS_SUCCESS;
+
+               if ((alt = strchr(file, ':'))) {
+                       char *dup;
 
-               if (!strncasecmp(file, "phrase:", 7)) {
-                       char *arg = NULL;
-                       const char *lang = switch_channel_get_variable(channel, "language");
-                       alt = file + 7;
-                       dup = switch_core_session_strdup(session, alt);
+                       if (!strncasecmp(file, "phrase:", 7)) {
+                               char *arg = NULL;
+                               const char *lang = switch_channel_get_variable(channel, "language");
+                               alt = file + 7;
+                               dup = switch_core_session_strdup(session, alt);
 
-                       if (dup) {
-                               if ((arg = strchr(dup, ':'))) {
-                                       *arg++ = '\0';
+                               if (dup) {
+                                       if ((arg = strchr(dup, ':'))) {
+                                               *arg++ = '\0';
+                                       }
+                                       if ((rst = switch_ivr_phrase_macro(session, dup, arg, lang, args) != SWITCH_STATUS_SUCCESS)) {
+                                               return rst;
+                                       }
+                                       continue;
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Args\n");
+                                       continue;
                                }
-                               return switch_ivr_phrase_macro(session, dup, arg, lang, args);
-                       } else {
-                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Args\n");
-                               return SWITCH_STATUS_FALSE;
-                       }
-               } else if (!strncasecmp(file, "say:", 4)) {
-                       char *engine = NULL, *voice = NULL, *text = NULL;
-                       alt = file + 4;
-                       dup = switch_core_session_strdup(session, alt);
-                       engine = dup;
-
-                       if (!switch_strlen_zero(engine)) {
-                               if ((voice = strchr(engine, ':'))) {
-                                       *voice++ = '\0';
-                                       if (!switch_strlen_zero(voice) && (text = strchr(voice, ':'))) {
-                                               *text++ = '\0';
+                       } else if (!strncasecmp(file, "say:", 4)) {
+                               char *engine = NULL, *voice = NULL, *text = NULL;
+                               alt = file + 4;
+                               dup = switch_core_session_strdup(session, alt);
+                               engine = dup;
+
+                               if (!switch_strlen_zero(engine)) {
+                                       if ((voice = strchr(engine, ':'))) {
+                                               *voice++ = '\0';
+                                               if (!switch_strlen_zero(voice) && (text = strchr(voice, ':'))) {
+                                                       *text++ = '\0';
+                                               }
                                        }
                                }
-                       }
 
-                       if (!switch_strlen_zero(engine) && !switch_strlen_zero(voice) && !switch_strlen_zero(text)) {
-                               return switch_ivr_speak_text(session, engine, voice, text, args);
-                       } else if (!switch_strlen_zero(engine) && !(voice && text)) {
-                               text = engine;
-                               engine = (char *) switch_channel_get_variable(channel, "tts_engine");
-                               voice = (char *) switch_channel_get_variable(channel, "tts_voice");
-                               if (engine && text) {
-                                       return switch_ivr_speak_text(session, engine, voice, text, args);
+                               if (!switch_strlen_zero(engine) && !switch_strlen_zero(voice) && !switch_strlen_zero(text)) {
+                                       if ((rst = switch_ivr_speak_text(session, engine, voice, text, args)) != SWITCH_STATUS_SUCCESS) {
+                                               return rst;
+                                       }
+                                       continue;
+                               } else if (!switch_strlen_zero(engine) && !(voice && text)) {
+                                       text = engine;
+                                       engine = (char *) switch_channel_get_variable(channel, "tts_engine");
+                                       voice = (char *) switch_channel_get_variable(channel, "tts_voice");
+                                       if (engine && text) {
+                                               if ((rst = switch_ivr_speak_text(session, engine, voice, text, args)) != SWITCH_STATUS_SUCCESS) {
+                                                       return rst;
+                                               }
+                                               continue;
+                                       }
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Args\n");
+                                       continue;
                                }
+                       }
+
+               }
+
+               if (!prefix) {
+                       prefix = SWITCH_GLOBAL_dirs.base_dir;
+               }
+
+               if (!strstr(file, SWITCH_URL_SEPARATOR)) {
+                       if (!switch_is_file_path(file)) {
+                               file = switch_core_session_sprintf(session, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, file);
+                       }
+                       if ((ext = strrchr(file, '.'))) {
+                               ext++;
                        } else {
-                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Args\n");
-                               return SWITCH_STATUS_FALSE;
+                               ext = read_impl.iananame;
+                               file = switch_core_session_sprintf(session, "%s.%s", file, ext);
+                               asis = 1;
                        }
                }
 
-       }
+       
+               if (!fh) {
+                       fh = &lfh;
+                       memset(fh, 0, sizeof(lfh));
+               }
 
-       if (!prefix) {
-               prefix = SWITCH_GLOBAL_dirs.base_dir;
-       }
+               if (fh->samples > 0) {
+                       sample_start = fh->samples;
+                       fh->samples = 0;
+               }
 
-       if (!strstr(file, SWITCH_URL_SEPARATOR)) {
-               if (!switch_is_file_path(file)) {
-                       file = switch_core_session_sprintf(session, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, file);
+               if ((prebuf = switch_channel_get_variable(channel, "stream_prebuffer"))) {
+                       int maybe = atoi(prebuf);
+                       if (maybe > 0) {
+                               fh->prebuf = maybe;
+                       }
                }
-               if ((ext = strrchr(file, '.'))) {
-                       ext++;
-               } else {
-                       ext = read_impl.iananame;
-                       file = switch_core_session_sprintf(session, "%s.%s", file, ext);
+               
+               if (switch_core_file_open(fh,
+                                                                 file,
+                                                                 read_impl.number_of_channels,
+                                                                 read_impl.actual_samples_per_second,
+                                                                 SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
+                       switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
+                       status = SWITCH_STATUS_NOTFOUND;
+                       continue;
+               }
+               if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) {
                        asis = 1;
                }
-       }
 
-       if (!fh) {
-               fh = &lfh;
-               memset(fh, 0, sizeof(lfh));
-       }
-
-       if (fh->samples > 0) {
-               sample_start = fh->samples;
-               fh->samples = 0;
-       }
-
-       if ((prebuf = switch_channel_get_variable(channel, "stream_prebuffer"))) {
-               int maybe = atoi(prebuf);
-               if (maybe > 0) {
-                       fh->prebuf = maybe;
+               if (!abuf) {
+                       switch_zmalloc(abuf, FILE_STARTSAMPLES * sizeof(*abuf));
+                       write_frame.data = abuf;
+                       write_frame.buflen = FILE_STARTSAMPLES;
                }
-       }
 
-       if (switch_core_file_open(fh,
-                                                         file,
-                                                         read_impl.number_of_channels,
-                                                         read_impl.actual_samples_per_second,
-                                                         SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
-               switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
-               status = SWITCH_STATUS_NOTFOUND;
-               goto end;
-       }
-       if (switch_test_flag(fh, SWITCH_FILE_NATIVE)) {
-               asis = 1;
-       }
+               if (sample_start > 0) {
+                       uint32_t pos = 0;
+                       switch_core_file_seek(fh, &pos, 0, SEEK_SET);
+                       switch_core_file_seek(fh, &pos, sample_start, SEEK_CUR);
+               }
 
-       switch_zmalloc(abuf, FILE_STARTSAMPLES * sizeof(*abuf));
-       write_frame.data = abuf;
-       write_frame.buflen = FILE_STARTSAMPLES;
+               if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_TITLE, &p) == SWITCH_STATUS_SUCCESS) {
+                       title = switch_core_session_strdup(session, p);
+                       switch_channel_set_variable(channel, "RECORD_TITLE", p);
+               }
 
-       if (sample_start > 0) {
-               uint32_t pos = 0;
-               switch_core_file_seek(fh, &pos, 0, SEEK_SET);
-               switch_core_file_seek(fh, &pos, sample_start, SEEK_CUR);
-       }
+               if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, &p) == SWITCH_STATUS_SUCCESS) {
+                       copyright = switch_core_session_strdup(session, p);
+                       switch_channel_set_variable(channel, "RECORD_COPYRIGHT", p);
+               }
 
-       if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_TITLE, &p) == SWITCH_STATUS_SUCCESS) {
-               title = switch_core_session_strdup(session, p);
-               switch_channel_set_variable(channel, "RECORD_TITLE", p);
-       }
+               if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, &p) == SWITCH_STATUS_SUCCESS) {
+                       software = switch_core_session_strdup(session, p);
+                       switch_channel_set_variable(channel, "RECORD_SOFTWARE", p);
+               }
 
-       if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, &p) == SWITCH_STATUS_SUCCESS) {
-               copyright = switch_core_session_strdup(session, p);
-               switch_channel_set_variable(channel, "RECORD_COPYRIGHT", p);
-       }
+               if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, &p) == SWITCH_STATUS_SUCCESS) {
+                       artist = switch_core_session_strdup(session, p);
+                       switch_channel_set_variable(channel, "RECORD_ARTIST", p);
+               }
 
-       if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, &p) == SWITCH_STATUS_SUCCESS) {
-               software = switch_core_session_strdup(session, p);
-               switch_channel_set_variable(channel, "RECORD_SOFTWARE", p);
-       }
+               if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, &p) == SWITCH_STATUS_SUCCESS) {
+                       comment = switch_core_session_strdup(session, p);
+                       switch_channel_set_variable(channel, "RECORD_COMMENT", p);
+               }
 
-       if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, &p) == SWITCH_STATUS_SUCCESS) {
-               artist = switch_core_session_strdup(session, p);
-               switch_channel_set_variable(channel, "RECORD_ARTIST", p);
-       }
+               if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_DATE, &p) == SWITCH_STATUS_SUCCESS) {
+                       date = switch_core_session_strdup(session, p);
+                       switch_channel_set_variable(channel, "RECORD_DATE", p);
+               }
 
-       if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, &p) == SWITCH_STATUS_SUCCESS) {
-               comment = switch_core_session_strdup(session, p);
-               switch_channel_set_variable(channel, "RECORD_COMMENT", p);
-       }
+               interval = read_impl.microseconds_per_packet / 1000;
 
-       if (switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_DATE, &p) == SWITCH_STATUS_SUCCESS) {
-               date = switch_core_session_strdup(session, p);
-               switch_channel_set_variable(channel, "RECORD_DATE", p);
-       }
+               if (!fh->audio_buffer) {
+                       switch_buffer_create_dynamic(&fh->audio_buffer, FILE_BLOCKSIZE, FILE_BUFSIZE, 0);
+                       switch_assert(fh->audio_buffer);
+               }
 
-       interval = read_impl.microseconds_per_packet / 1000;
+               if (asis) {
+                       write_frame.codec = switch_core_session_get_read_codec(session);
+                       samples = read_impl.samples_per_packet;
+                       framelen = read_impl.encoded_bytes_per_packet;
+               } else {
+                       codec_name = "L16";
+
+                       if (!switch_core_codec_ready((&codec))) {
+                               if (switch_core_codec_init(&codec,
+                                                                                  codec_name,
+                                                                                  NULL,
+                                                                                  fh->samplerate,
+                                                                                  interval, fh->channels, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG,
+                                                                         SWITCH_LOG_DEBUG, "Codec Activated %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval);
+                               
 
-       if (!fh->audio_buffer) {
-               switch_buffer_create_dynamic(&fh->audio_buffer, FILE_BLOCKSIZE, FILE_BUFSIZE, 0);
-               if (!fh->audio_buffer) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Setup buffer failed\n");
+                               } else {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+                                                                         "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval);
+                                       switch_core_file_close(fh);
+                                       switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
+                                       status = SWITCH_STATUS_GENERR;
+                                       continue;
+                               }
+                       }
 
-                       switch_core_file_close(fh);
-                       switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
+                       write_frame.codec = &codec;
 
-                       status = SWITCH_STATUS_GENERR;
-                       goto end;
+                       samples = codec.implementation->samples_per_packet;
+                       framelen = codec.implementation->decoded_bytes_per_packet;
                }
-       }
 
-       if (asis) {
-               write_frame.codec = switch_core_session_get_read_codec(session);
-               samples = read_impl.samples_per_packet;
-               framelen = read_impl.encoded_bytes_per_packet;
-       } else {
-               codec_name = "L16";
+               if (timer_name && !timer.samplecount) {
+                       uint32_t len;
 
-               if (switch_core_codec_init(&codec,
-                                                                  codec_name,
-                                                                  NULL,
-                                                                  fh->samplerate,
-                                                                  interval, fh->channels, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG,
-                                                         SWITCH_LOG_DEBUG, "Codec Activated %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval);
+                       len = samples * 2;
+                       if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Setup timer failed!\n");
+                               switch_core_codec_destroy(&codec);
+                               switch_core_file_close(fh);
+                               switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
+                               status = SWITCH_STATUS_GENERR;
+                               continue;
+                       }
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setup timer success %u bytes per %d ms!\n", len, interval);
+               }
+               write_frame.rate = fh->samplerate;
 
-                       write_frame.codec = &codec;
-               } else {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
-                                                         "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval);
-                       switch_core_file_close(fh);
-                       switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
-                       status = SWITCH_STATUS_GENERR;
-                       goto end;
+               if (timer_name) {
+                       /* start a thread to absorb incoming audio */
+                       switch_core_service_session(session);
                }
-               samples = codec.implementation->samples_per_packet;
-               framelen = codec.implementation->decoded_bytes_per_packet;
-       }
 
-       if (timer_name) {
-               uint32_t len;
+               ilen = samples;
 
-               len = samples * 2;
-               if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Setup timer failed!\n");
-                       switch_core_codec_destroy(&codec);
-                       switch_core_file_close(fh);
-                       switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
-                       status = SWITCH_STATUS_GENERR;
-                       goto end;
-               }
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setup timer success %u bytes per %d ms!\n", len, interval);
-       }
-       write_frame.rate = fh->samplerate;
+               for (;;) {
+                       int done = 0;
+                       int do_speed = 1;
+                       int last_speed = -1;
 
-       if (timer_name) {
-               /* start a thread to absorb incoming audio */
-               switch_core_service_session(session);
-       }
+                       if (!switch_channel_ready(channel)) {
+                               status = SWITCH_STATUS_FALSE;
+                               break; 
+                       }
 
-       ilen = samples;
+                       if (switch_channel_test_flag(channel, CF_BREAK)) {
+                               switch_channel_clear_flag(channel, CF_BREAK);
+                               status = SWITCH_STATUS_BREAK;
+                               break; 
+                       }
 
-       for (;;) {
-               int done = 0;
-               int do_speed = 1;
-               int last_speed = -1;
+                       if (switch_core_session_private_event_count(session)) {
+                               switch_ivr_parse_all_events(session);
+                       }
 
-               if (!switch_channel_ready(channel)) {
-                       status = SWITCH_STATUS_FALSE;
-                       break; 
-               }
+                       if (args && (args->input_callback || args->buf || args->buflen)) {
+                               /*
+                                 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)) {
+                                       if (!args->input_callback && !args->buf) {
+                                               status = SWITCH_STATUS_BREAK;
+                                               done = 1;
+                                               break; 
+                                       }
+                                       switch_channel_dequeue_dtmf(channel, &dtmf);
+                                       if (args->input_callback) {
+                                               status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen);
+                                       } else {
+                                               *((char *) args->buf) = dtmf.digit;
+                                               status = SWITCH_STATUS_BREAK;
+                                       }
+                               }
 
-               if (switch_channel_test_flag(channel, CF_BREAK)) {
-                       switch_channel_clear_flag(channel, CF_BREAK);
-                       status = SWITCH_STATUS_BREAK;
-                       break; 
-               }
+                               if (args->input_callback) {
+                                       switch_event_t *event;
 
-               if (switch_core_session_private_event_count(session)) {
-                       switch_ivr_parse_all_events(session);
-               }
+                                       if (switch_core_session_dequeue_event(session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+                                               status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
+                                               switch_event_destroy(&event);
+                                       }
+                               }
 
-               if (args && (args->input_callback || args->buf || args->buflen)) {
-                       /*
-                          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)) {
-                               if (!args->input_callback && !args->buf) {
-                                       status = SWITCH_STATUS_BREAK;
+                               if (status != SWITCH_STATUS_SUCCESS) {
                                        done = 1;
                                        break; 
                                }
-                               switch_channel_dequeue_dtmf(channel, &dtmf);
-                               if (args->input_callback) {
-                                       status = args->input_callback(session, (void *) &dtmf, SWITCH_INPUT_TYPE_DTMF, args->buf, args->buflen);
-                               } else {
-                                       *((char *) args->buf) = dtmf.digit;
-                                       status = SWITCH_STATUS_BREAK;
-                               }
                        }
 
-                       if (args->input_callback) {
-                               switch_event_t *event;
-
-                               if (switch_core_session_dequeue_event(session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
-                                       status = args->input_callback(session, event, SWITCH_INPUT_TYPE_EVENT, args->buf, args->buflen);
-                                       switch_event_destroy(&event);
+                       if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
+                               if (framelen > FILE_STARTSAMPLES) {
+                                       framelen = FILE_STARTSAMPLES;
+                               }
+                               memset(abuf, 0, framelen);
+                               olen = ilen;
+                               do_speed = 0;
+                       } else if (fh->sp_audio_buffer && (eof || (switch_buffer_inuse(fh->sp_audio_buffer) > (switch_size_t) (framelen)))) {
+                               if (!(bread = switch_buffer_read(fh->sp_audio_buffer, abuf, framelen))) {
+                                       if (eof) {
+                                               continue;
+                                       } else {
+                                               break; 
+                                       }
                                }
-                       }
 
-                       if (status != SWITCH_STATUS_SUCCESS) {
-                               done = 1;
-                               break; 
-                       }
-               }
+                               if (bread < framelen) {
+                                       memset(abuf + bread, 0, framelen - bread);
+                               }
 
-               if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
-                       if (framelen > FILE_STARTSAMPLES) {
-                               framelen = FILE_STARTSAMPLES;
-                       }
-                       memset(abuf, 0, framelen);
-                       olen = ilen;
-                       do_speed = 0;
-               } else if (fh->sp_audio_buffer && (eof || (switch_buffer_inuse(fh->sp_audio_buffer) > (switch_size_t) (framelen)))) {
-                       if (!(bread = switch_buffer_read(fh->sp_audio_buffer, abuf, framelen))) {
-                               if (eof) {
-                                       continue;
-                               } else {
-                                       break; 
+                               olen = asis ? framelen : ilen;
+                               do_speed = 0;
+                       } else if (fh->audio_buffer && (eof || (switch_buffer_inuse(fh->audio_buffer) > (switch_size_t) (framelen)))) {
+                               if (!(bread = switch_buffer_read(fh->audio_buffer, abuf, framelen))) {
+                                       if (eof) {
+                                               break; 
+                                       } else {
+                                               continue;
+                                       }
                                }
-                       }
 
-                       if (bread < framelen) {
-                               memset(abuf + bread, 0, framelen - bread);
-                       }
+                               if (bread < framelen) {
+                                       memset(abuf + bread, 0, framelen - bread);
+                               }
 
-                       olen = asis ? framelen : ilen;
-                       do_speed = 0;
-               } else if (fh->audio_buffer && (eof || (switch_buffer_inuse(fh->audio_buffer) > (switch_size_t) (framelen)))) {
-                       if (!(bread = switch_buffer_read(fh->audio_buffer, abuf, framelen))) {
+                               olen = asis ? framelen : ilen;
+                       } else {
                                if (eof) {
-                                       break; 
-                               } else {
+                                       break;
+                               }
+                               olen = FILE_STARTSAMPLES;
+                               if (!asis) {
+                                       olen /= 2;
+                               }
+                               if (switch_core_file_read(fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
+                                       eof++;
                                        continue;
                                }
+                               switch_buffer_write(fh->audio_buffer, abuf, asis ? olen : olen * 2);
+                               olen = switch_buffer_read(fh->audio_buffer, abuf, framelen);
+                               if (!asis) {
+                                       olen /= 2;
+                               }
                        }
 
-                       if (bread < framelen) {
-                               memset(abuf + bread, 0, framelen - bread);
+                       if (done || olen <= 0) {
+                               break; 
                        }
 
-                       olen = asis ? framelen : ilen;
-               } else {
-                       if (eof) {
-                               break;
-                       }
-                       olen = FILE_STARTSAMPLES;
                        if (!asis) {
-                               olen /= 2;
-                       }
-                       if (switch_core_file_read(fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
-                               eof++;
-                               continue;
-                       }
-                       switch_buffer_write(fh->audio_buffer, abuf, asis ? olen : olen * 2);
-                       olen = switch_buffer_read(fh->audio_buffer, abuf, framelen);
-                       if (!asis) {
-                               olen /= 2;
+                               if (fh->speed > 2) {
+                                       fh->speed = 2;
+                               } else if (fh->speed < -2) {
+                                       fh->speed = -2;
+                               }
                        }
-               }
-
-               if (done || olen <= 0) {
-                       break; 
-               }
 
-               if (!asis) {
-                       if (fh->speed > 2) {
-                               fh->speed = 2;
-                       } else if (fh->speed < -2) {
-                               fh->speed = -2;
+                       if (!asis && fh->audio_buffer && last_speed > -1 && last_speed != fh->speed) {
+                               switch_buffer_zero(fh->sp_audio_buffer);
                        }
-               }
 
-               if (!asis && fh->audio_buffer && last_speed > -1 && last_speed != fh->speed) {
-                       switch_buffer_zero(fh->sp_audio_buffer);
-               }
-
-               if (switch_test_flag(fh, SWITCH_FILE_SEEK)) {
-                       /* file position has changed flush the buffer */
-                       switch_buffer_zero(fh->audio_buffer);
-                       switch_clear_flag(fh, SWITCH_FILE_SEEK);
-               }
+                       if (switch_test_flag(fh, SWITCH_FILE_SEEK)) {
+                               /* file position has changed flush the buffer */
+                               switch_buffer_zero(fh->audio_buffer);
+                               switch_clear_flag(fh, SWITCH_FILE_SEEK);
+                       }
 
 
-               if (!asis && fh->speed && do_speed) {
-                       float factor = 0.25f * abs(fh->speed);
-                       switch_size_t newlen, supplement, step;
-                       short *bp = write_frame.data;
-                       switch_size_t wrote = 0;
+                       if (!asis && fh->speed && do_speed) {
+                               float factor = 0.25f * abs(fh->speed);
+                               switch_size_t newlen, supplement, step;
+                               short *bp = write_frame.data;
+                               switch_size_t wrote = 0;
 
-                       supplement = (int) (factor * olen);
-                       if (!supplement) {
-                               supplement = 1;
-                       }
-                       newlen = (fh->speed > 0) ? olen - supplement : olen + supplement;
+                               supplement = (int) (factor * olen);
+                               if (!supplement) {
+                                       supplement = 1;
+                               }
+                               newlen = (fh->speed > 0) ? olen - supplement : olen + supplement;
 
-                       step = (fh->speed > 0) ? (newlen / supplement) : (olen / supplement);
+                               step = (fh->speed > 0) ? (newlen / supplement) : (olen / supplement);
 
-                       if (!fh->sp_audio_buffer) {
-                               switch_buffer_create_dynamic(&fh->sp_audio_buffer, 1024, 1024, 0);
-                       }
+                               if (!fh->sp_audio_buffer) {
+                                       switch_buffer_create_dynamic(&fh->sp_audio_buffer, 1024, 1024, 0);
+                               }
 
-                       while ((wrote + step) < newlen) {
-                               switch_buffer_write(fh->sp_audio_buffer, bp, step * 2);
-                               wrote += step;
-                               bp += step;
-                               if (fh->speed > 0) {
-                                       bp++;
-                               } else {
-                                       float f;
-                                       short s;
-                                       f = (float) (*bp + *(bp + 1) + *(bp - 1));
-                                       f /= 3;
-                                       s = (short) f;
-                                       switch_buffer_write(fh->sp_audio_buffer, &s, 2);
-                                       wrote++;
+                               while ((wrote + step) < newlen) {
+                                       switch_buffer_write(fh->sp_audio_buffer, bp, step * 2);
+                                       wrote += step;
+                                       bp += step;
+                                       if (fh->speed > 0) {
+                                               bp++;
+                                       } else {
+                                               float f;
+                                               short s;
+                                               f = (float) (*bp + *(bp + 1) + *(bp - 1));
+                                               f /= 3;
+                                               s = (short) f;
+                                               switch_buffer_write(fh->sp_audio_buffer, &s, 2);
+                                               wrote++;
+                                       }
+                               }
+                               if (wrote < newlen) {
+                                       switch_size_t r = newlen - wrote;
+                                       switch_buffer_write(fh->sp_audio_buffer, bp, r * 2);
+                                       wrote += r;
                                }
+                               last_speed = fh->speed;
+                               continue;
                        }
-                       if (wrote < newlen) {
-                               switch_size_t r = newlen - wrote;
-                               switch_buffer_write(fh->sp_audio_buffer, bp, r * 2);
-                               wrote += r;
+
+                       if (olen < llen) {
+                               uint8_t *dp = (uint8_t *) write_frame.data;
+                               memset(dp + (int) olen, 0, (int) (llen - olen));
+                               olen = llen;
                        }
-                       last_speed = fh->speed;
-                       continue;
-               }
-               if (olen < llen) {
-                       uint8_t *dp = (uint8_t *) write_frame.data;
-                       memset(dp + (int) olen, 0, (int) (llen - olen));
-                       olen = llen;
-               }
 
-               write_frame.samples = (uint32_t) olen;
+                       write_frame.samples = (uint32_t) olen;
 
-               if (asis) {
-                       write_frame.datalen = (uint32_t) olen;
-               } else {
-                       write_frame.datalen = write_frame.samples * 2;
-               }
+                       if (asis) {
+                               write_frame.datalen = (uint32_t) olen;
+                       } else {
+                               write_frame.datalen = write_frame.samples * 2;
+                       }
 
-               llen = olen;
+                       llen = olen;
 
-               if (timer_name) {
-                       write_frame.timestamp = timer.samplecount;
-               }
+                       if (timer_name) {
+                               write_frame.timestamp = timer.samplecount;
+                       }
 #ifndef WIN32
 #if SWITCH_BYTE_ORDER == __BIG_ENDIAN
-               if (!asis && l16) {
-                       switch_swap_linear(write_frame.data, (int) write_frame.datalen / 2);
-               }
+                       if (!asis && l16) {
+                               switch_swap_linear(write_frame.data, (int) write_frame.datalen / 2);
+                       }
 #endif
 #endif
-               if (fh->vol) {
-                       switch_change_sln_volume(write_frame.data, write_frame.datalen / 2, fh->vol);
-               }
-
-               fh->offset_pos += write_frame.samples / 2;
-               status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
-
-               if (status == SWITCH_STATUS_MORE_DATA) {
-                       status = SWITCH_STATUS_SUCCESS;
-                       continue;
-               } else if (status != SWITCH_STATUS_SUCCESS) {
-                       done = 1;
-                       break; 
-               }
+                       if (fh->vol) {
+                               switch_change_sln_volume(write_frame.data, write_frame.datalen / 2, fh->vol);
+                       }
 
-               if (done) {
-                       break; 
-               }
+                       fh->offset_pos += write_frame.samples / 2;
+                       status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
 
-               if (timer_name) {
-                       if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) {
+                       if (status == SWITCH_STATUS_MORE_DATA) {
+                               status = SWITCH_STATUS_SUCCESS;
+                               continue;
+                       } else if (status != SWITCH_STATUS_SUCCESS) {
+                               done = 1;
                                break; 
                        }
-               } else {                                /* time off the channel (if you must) */
-                       switch_frame_t *read_frame;
-                       switch_status_t tstatus;
-                       while (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_HOLD)) {
-                               switch_yield(10000);
-                       }
 
-                       tstatus = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
-
-                       if (!SWITCH_READ_ACCEPTABLE(tstatus)) {
+                       if (done) {
                                break; 
                        }
 
-                       if (args && (args->read_frame_callback)) {
-                               int ok = 1;
-                               switch_set_flag(fh, SWITCH_FILE_CALLBACK);
-                               if (args->read_frame_callback(session, read_frame, args->user_data) != SWITCH_STATUS_SUCCESS) {
-                                       ok = 0;
+                       if (timer_name) {
+                               if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) {
+                                       break; 
                                }
-                               switch_clear_flag(fh, SWITCH_FILE_CALLBACK);
-                               if (!ok) {
+                       } else {                                /* time off the channel (if you must) */
+                               switch_frame_t *read_frame;
+                               switch_status_t tstatus;
+                               while (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_HOLD)) {
+                                       switch_yield(10000);
+                               }
+
+                               tstatus = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
+
+                               if (!SWITCH_READ_ACCEPTABLE(tstatus)) {
                                        break; 
                                }
+
+                               if (args && (args->read_frame_callback)) {
+                                       int ok = 1;
+                                       switch_set_flag(fh, SWITCH_FILE_CALLBACK);
+                                       if (args->read_frame_callback(session, read_frame, args->user_data) != SWITCH_STATUS_SUCCESS) {
+                                               ok = 0;
+                                       }
+                                       switch_clear_flag(fh, SWITCH_FILE_CALLBACK);
+                                       if (!ok) {
+                                               break; 
+                                       }
+                               }
                        }
                }
-       }
 
-       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done playing file\n");
-       //switch_core_file_seek(fh, &fh->last_pos, 0, SEEK_CUR);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done playing file\n");
+               
+               switch_channel_set_variable_printf(channel, "playback_ms", "%d", fh->samples_out / read_impl.samples_per_second);
+               switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_out);
 
+               switch_core_file_close(fh);
 
-       switch_channel_set_variable_printf(channel, "playback_ms", "%d", fh->samples_out / read_impl.samples_per_second);
-       switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_out);
+               if (fh->audio_buffer) {
+                       switch_buffer_destroy(&fh->audio_buffer);
+               }
+               
+               if (fh->sp_audio_buffer) {
+                       switch_buffer_destroy(&fh->sp_audio_buffer);
+               }
+       }
 
-       switch_core_file_close(fh);
-       switch_buffer_destroy(&fh->audio_buffer);
-       switch_buffer_destroy(&fh->sp_audio_buffer);
-       if (!asis) {
+       if (switch_core_codec_ready((&codec))) {
                switch_core_codec_destroy(&codec);
        }
-       if (timer_name) {
+
+       if (timer.samplecount) {
                /* End the audio absorbing thread */
                switch_core_thread_session_end(session);
                switch_core_timer_destroy(&timer);
        }
 
 
-  end:
+
        switch_safe_free(abuf);
 
        switch_core_session_reset(session, SWITCH_FALSE, SWITCH_TRUE);
@@ -1600,7 +1661,7 @@ SWITCH_DECLARE(switch_status_t) switch_play_and_get_digits(switch_core_session_t
                memset(digit_buffer, 0, digit_buffer_length);
                switch_channel_flush_dtmf(channel);
                status = switch_ivr_read(session, min_digits, max_digits, prompt_audio_file, var_name, 
-                                                                                                digit_buffer, digit_buffer_length, timeout, valid_terminators);
+                                                                digit_buffer, digit_buffer_length, timeout, valid_terminators);
                if (status == SWITCH_STATUS_TIMEOUT && strlen(digit_buffer) >= min_digits) {
                        status = SWITCH_STATUS_SUCCESS;
                }