]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Add more IVR stuff and a test app (mod_ivrtest)
authorAnthony Minessale <anthony.minessale@gmail.com>
Fri, 27 Jan 2006 21:33:45 +0000 (21:33 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Fri, 27 Jan 2006 21:33:45 +0000 (21:33 +0000)
in dialplan (ivrtest <path to file>)
if the file is valid it will play the file and you will be expected to dial digits
until you dial 10 digits or press # or * (* will end the call) (# will repeat the test endlessly)

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

checkversion.sh
modules.conf
src/include/switch_ivr.h
src/include/switch_types.h
src/mod/applications/mod_ivrtest/mod_ivrtest.c [new file with mode: 0644]
src/mod/applications/mod_ivrtest/mod_ivrtest.vcproj [new file with mode: 0644]
src/mod/applications/mod_playback/mod_playback.c
src/mod/dialplans/mod_pcre/mod_pcre.c
src/mod/formats/mod_sndfile/mod_sndfile.c
src/switch_ivr.c

index ef6184141d85c415f7313da380cfab986f06f72e..04f7cfc5f7fc0daf6eff840331d32d26ca6a450a 100755 (executable)
@@ -6,10 +6,12 @@ if [ ! -z $1 ] ; then
     fi
 fi
 
+force=0
 version=`svnversion . -n || echo hacked`
 oldversion=`cat .version 2>/dev/null || echo "0"`
+grep "@SVN_VERSION@" src/include/switch_version.h && force=1
 
-if [ $oldversion != $version ] ; then
+if [ $oldversion != $version ] || [ $force = 1 ] ; then
     cat src/include/switch_version.h.in | sed "s/@SVN_VERSION@/$version/g" > src/include/switch_version.h
     echo $version > .version
     make modclean
index 3cb24fd49d27483d2cd9b66a51118659ad1bad2a..7f5ea66536a9822cefb2681b86ff570f34a17390 100644 (file)
@@ -1,5 +1,6 @@
 applications/mod_bridgecall
 applications/mod_playback
+applications/mod_ivrtest
 #applications/mod_skel
 #codecs/mod_g729
 codecs/mod_gsm
index 0f0209e09099fb7f81c2ae2e4b35601de45ca769..9b0560c42735f96634a3ee1e34b6befb9dd529e3 100644 (file)
@@ -52,6 +52,34 @@ extern "C" {
  * @{
  */
 
+/*!
+  \brief Wait for DTMF digits calling a pluggable callback function when digits are collected.
+  \param session the session to read.
+  \param dtmf_collection_callback code to execute if any dtmf is dialed during the recording
+  \return SWITCH_STATUS_SUCCESS to keep the collection moving.
+*/
+SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_callback(switch_core_session *session,
+                                                                                                                                switch_dtmf_callback_function dtmf_callback,
+                                                                                                                                void *buf,
+                                                                                                                                unsigned int buflen);
+
+/*!
+  \brief Wait for specified number of DTMF digits, untile terminator is received or until the channel hangs up.
+  \param session the session to read.
+  \param buf strig to write to
+  \param buflen max size of buf
+  \param maxdigits max number of digits to read
+  \param terminators digits to end the collection
+  \param terminator actual digit that caused the collection to end (if any)
+  \return SWITCH_STATUS_SUCCESS to keep the collection moving.
+*/
+SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_session *session,
+                                                                                                                         char *buf,
+                                                                                                                         unsigned int buflen,
+                                                                                                                         int maxdigits,
+                                                                                                                         const char *terminators,
+                                                                                                                         char *terminator);
+       
 /*!
   \brief play a file from the disk to the session
   \param session the session to play the file too
@@ -59,11 +87,14 @@ extern "C" {
   \param timer_name the name of a timer to use input will be absorbed (NULL to time off the session input).
   \param dtmf_callback code to execute if any dtmf is dialed during the playback
   \return SWITCH_STATUS_SUCCESS if all is well
+  \note passing a NULL dtmf_callback nad a not NULL buf indicates to copy any dtmf to buf and stop playback.
 */
 SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
                                                                                                   char *file,
                                                                                                   char *timer_name,
-                                                                                                  switch_dtmf_callback_function dtmf_callback);
+                                                                                                  switch_dtmf_callback_function dtmf_callback,
+                                                                                                  void *buf,
+                                                                                                  unsigned int buflen);
 
 
 
@@ -73,11 +104,15 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
   \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
+  \note passing a NULL dtmf_callback nad a not NULL buf indicates to copy any dtmf to buf and stop recording.
 */
 SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *session,
                                                                                                         char *file,
-                                                                                                        switch_dtmf_callback_function dtmf_callback);
-       
+                                                                                                        switch_dtmf_callback_function dtmf_callback,
+                                                                                                        void *buf,
+                                                                                                        unsigned int buflen);
+
+
 /** @} */
 
 #ifdef __cplusplus
index 4c8a411762747c9270ec844f14a304ed7d0ba14f..aff3a6f4a86c3eb5db708ed41df3d1d3c5029f97 100644 (file)
@@ -102,6 +102,7 @@ typedef enum {
     SWITCH_STATUS_RESAMPLE     - An indication that a resample has occured
     SWITCH_STATUS_GENERR       - A general Error
     SWITCH_STATUS_INUSE                - An indication that requested resource is in use
+       SWITCH_STATUS_BREAK     - A non-fatal break of an operation
 </pre>
  */
 typedef enum {
@@ -115,7 +116,8 @@ typedef enum {
        SWITCH_STATUS_NOOP,
        SWITCH_STATUS_RESAMPLE,
        SWITCH_STATUS_GENERR,
-       SWITCH_STATUS_INUSE
+       SWITCH_STATUS_INUSE,
+       SWITCH_STATUS_BREAK,
 } switch_status;
 
 /*!
@@ -392,7 +394,7 @@ typedef switch_status (*switch_waitfor_read_hook)(switch_core_session *, int, in
 typedef switch_status (*switch_waitfor_write_hook)(switch_core_session *, int, int);
 typedef switch_status (*switch_send_dtmf_hook)(switch_core_session *, char *);
 typedef switch_status (*switch_api_function)(char *in, char *out, size_t outlen);
-typedef switch_status (*switch_dtmf_callback_function)(switch_core_session *session, char *dtmf);
+typedef switch_status (*switch_dtmf_callback_function)(switch_core_session *session, char *dtmf, void *buf, unsigned int buflen);
 
 /* things we don't deserve to know about */
 
diff --git a/src/mod/applications/mod_ivrtest/mod_ivrtest.c b/src/mod/applications/mod_ivrtest/mod_ivrtest.c
new file mode 100644 (file)
index 0000000..31600fe
--- /dev/null
@@ -0,0 +1,127 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * 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 <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_ivrtest.c -- Raw Audio File Streaming Application Module
+ *
+ */
+#include <switch.h>
+#include <switch_ivr.h>
+
+
+
+static const char modname[] = "mod_ivrtest";
+
+
+/*
+  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.
+*/
+static switch_status on_dtmf(switch_core_session *session, char *dtmf, void *buf, unsigned int buflen)
+{
+       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Digits %s\n", dtmf);
+       
+       switch_copy_string((char *)buf, dtmf, buflen);
+       return SWITCH_STATUS_BREAK;
+
+}
+
+static void ivrtest_function(switch_core_session *session, char *data)
+{
+       switch_channel *channel;
+       switch_status status = SWITCH_STATUS_SUCCESS;
+       char buf[10] = "";
+       char term;
+
+       channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+       switch_channel_answer(channel);
+       
+       
+       while (switch_channel_get_state(channel) == CS_EXECUTE) {
+               memset(buf, 0, sizeof(buf));
+               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Enter up to 10 digits, press # to terminate, * to hangup\n");
+
+               if (data) {
+                       /* you could have passed NULL instead of on_dtmf to get this exact behaviour (copy the digits to buf and stop playing)
+                          but you may want to pass the function if you have something cooler to do...
+                       */
+                       status = switch_ivr_play_file(session, data, NULL, on_dtmf, buf, sizeof(buf));
+                       
+                       if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+                               switch_channel_hangup(channel);
+                               break;
+                       }
+               }
+
+               if (switch_ivr_collect_digits_count(session, buf, sizeof(buf), 10, "#*", &term) != SWITCH_STATUS_SUCCESS) {
+                       switch_channel_hangup(channel);
+                       break;
+               }
+
+               if (term && term == '*') {
+                       break;
+               }
+
+               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "You Dialed [%s]\n", buf);
+       }
+       
+}
+
+
+static const switch_application_interface ivrtest_application_interface = {
+       /*.interface_name */ "ivrtest",
+       /*.application_function */ ivrtest_function
+};
+
+static const switch_loadable_module_interface mod_ivrtest_module_interface = {
+       /*.module_name = */ modname,
+       /*.endpoint_interface = */ NULL,
+       /*.timer_interface = */ NULL,
+       /*.dialplan_interface = */ NULL,
+       /*.codec_interface = */ NULL,
+       /*.application_interface */ &ivrtest_application_interface
+};
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename)
+{
+
+       /* connect my internal structure to the blank pointer passed to me */
+       *interface = &mod_ivrtest_module_interface;
+
+
+       /* indicate that the module should continue to be loaded */
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/* 'switch_module_runtime' will start up in a thread by itself just by having it exist 
+   if it returns anything but SWITCH_STATUS_TERM it will be called again automaticly
+*/
+
+
+//switch_status switch_module_runtime(void)
diff --git a/src/mod/applications/mod_ivrtest/mod_ivrtest.vcproj b/src/mod/applications/mod_ivrtest/mod_ivrtest.vcproj
new file mode 100644 (file)
index 0000000..32d316e
--- /dev/null
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_ivrtest"\r
+       ProjectGUID="{78100236-7CEA-4948-96CC-E8ED3160329C}"\r
+       RootNamespace="mod_ivrtest"\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
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.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
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\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="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_ivrtest.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_ivrtest.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_ivrtest.lib"\r
+                               TargetMachine="1"\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="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.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
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\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="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_ivrtest.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_ivrtest.lib"\r
+                               TargetMachine="1"\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="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_ivrtest.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
index 9f06cb52d4f81f0d2cf24f9864e608352bfefab6..1035ee4603efeb25fbea13d5086f9ddde3982684 100644 (file)
@@ -40,7 +40,7 @@ static const char modname[] = "mod_playback";
   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.
 */
-static switch_status on_dtmf(switch_core_session *session, char *dtmf)
+static switch_status on_dtmf(switch_core_session *session, char *dtmf, void *buf, unsigned int buflen)
 {
        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Digits %s\n", dtmf);
 
@@ -52,7 +52,7 @@ static switch_status on_dtmf(switch_core_session *session, char *dtmf)
 }
 
 
-void playback_function(switch_core_session *session, char *data)
+static void playback_function(switch_core_session *session, char *data)
 {
        switch_channel *channel;
        char *timer_name = NULL;
@@ -67,20 +67,20 @@ void playback_function(switch_core_session *session, char *data)
        channel = switch_core_session_get_channel(session);
     assert(channel != NULL);
 
-       if (switch_ivr_play_file(session, file_name, timer_name, on_dtmf) != SWITCH_STATUS_SUCCESS) {
+       if (switch_ivr_play_file(session, file_name, timer_name, on_dtmf, NULL, 0) != SWITCH_STATUS_SUCCESS) {
                switch_channel_hangup(channel);
        }
        
 }
 
 
-void record_function(switch_core_session *session, char *data)
+static 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) {
+       if (switch_ivr_record_file(session, data, on_dtmf, NULL, 0) != SWITCH_STATUS_SUCCESS) {
                switch_channel_hangup(channel);
        }
        
index 3c5731428f762fd9e7c88b5dc2fd8c08594d9447..3539559a72580fb9a0a7f56472cabdb3189e4c28 100644 (file)
@@ -147,11 +147,7 @@ switch_caller_extension *dialplan_hunt(switch_core_session *session)
                                if ((data = strchr(app, ' '))) {
                                        *data = '\0';
                                        data++;
-                               } else {
-                                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "invalid extension on line %d\n", cfg.lineno);
-                                       continue;
-                               }
-
+                               } 
 
                                if (!extension) {
                                        if (!
index 99faee6285bf2e0729d6238db3cb29f8c14d0390..0feb5c2cad38aad061b1a8ea335606aab3f36083 100644 (file)
@@ -89,6 +89,8 @@ switch_status sndfile_file_open(switch_file_handle *handle, char *path)
                } else {
                        ready = 0;
                }
+       } else {
+               ready = 0;
        }
 
 
index 9b2778865ad162458c17c15f62bfa064b03e05f6..4bbdfca8f3b14039c85389461081a17bd694f3fe 100644 (file)
 
 /* TBD (Lots! there are not very many functions in here lol) */
 
+SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_callback(switch_core_session *session,
+                                                                                                               switch_dtmf_callback_function dtmf_callback,
+                                                                                                               void *buf,
+                                                                                                               unsigned int buflen)
+{
+       switch_channel *channel;
+       switch_status status = SWITCH_STATUS_SUCCESS;
+       
+       channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+       if (!dtmf_callback) {
+               return SWITCH_STATUS_GENERR;
+       }
+
+       while (switch_channel_get_state(channel) == CS_EXECUTE) {
+               switch_frame *read_frame;
+               char dtmf[128];
+
+               if (switch_channel_has_dtmf(channel)) {
+                       switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
+                       status = dtmf_callback(session, dtmf, buf, buflen);
+               }
+
+               if (status != SWITCH_STATUS_SUCCESS) {
+                       break;
+               }
+
+               if (switch_core_session_read_frame(session, &read_frame, -1, 0) != SWITCH_STATUS_SUCCESS) {
+                       break;
+               }
+       }
+
+       return status;
+}
+
+
+SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_session *session,
+                                                                                                                         char *buf,
+                                                                                                                         unsigned int buflen,
+                                                                                                                         int maxdigits,
+                                                                                                                         const char *terminators,
+                                                                                                                         char *terminator)
+{
+       int i = 0, x = strlen(buf);
+       switch_channel *channel;
+       switch_status status = SWITCH_STATUS_SUCCESS;
+       
+       channel = switch_core_session_get_channel(session);
+    assert(channel != NULL);
+
+       *terminator = '\0';
+       while (switch_channel_get_state(channel) == CS_EXECUTE) {
+               switch_frame *read_frame;
+               
+               if (switch_channel_has_dtmf(channel)) {
+                       char dtmf[128];
+                       switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
+
+                       for(i =0 ; i < strlen(dtmf); i++) {
+
+                               if (strchr(terminators, dtmf[i])) {
+                                       *terminator = dtmf[i];
+                                       return SWITCH_STATUS_SUCCESS;
+                               }
+
+                               buf[x++] = dtmf[i];
+                               buf[x] = '\0';
+                               if (x >= buflen || x >= maxdigits) {
+                                       return SWITCH_STATUS_SUCCESS;
+                               }
+                       }
+               }
+               
+               if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
+                       break;
+               }
+       }
+
+       return status;
+}
+
+
+
 SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *session, 
                                                                                                         char *file,
-                                                                                                        switch_dtmf_callback_function dtmf_callback)
+                                                                                                        switch_dtmf_callback_function dtmf_callback,
+                                                                                                        void *buf,
+                                                                                                        unsigned int buflen)
 {
        switch_channel *channel;
     char dtmf[128];
@@ -91,22 +177,27 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio
        while (switch_channel_get_state(channel) == CS_EXECUTE) {
                size_t len;
 
-               if (dtmf_callback) {
+               if (dtmf_callback || buf) {
                        /*
                          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 (dtmf_callback) {
+                                       status = dtmf_callback(session, dtmf, buf, buflen);
+                               } else {
+                                       switch_copy_string((char *)buf, dtmf, buflen);
+                                       status = SWITCH_STATUS_BREAK;
+                               }
                        }
 
                        if (status != SWITCH_STATUS_SUCCESS) {
                                break;
                        }
                }
-
-               if (switch_core_session_read_frame(session, &read_frame, -1, 0) != SWITCH_STATUS_SUCCESS) {
+               
+               if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
                        break;
                }
 
@@ -123,10 +214,12 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio
 SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session, 
                                                                                                   char *file,
                                                                                                   char *timer_name,
-                                                                                                  switch_dtmf_callback_function dtmf_callback)
+                                                                                                  switch_dtmf_callback_function dtmf_callback,
+                                                                                                  void *buf,
+                                                                                                  unsigned int buflen)
 {
        switch_channel *channel;
-       short buf[960];
+       short abuf[960];
        char dtmf[128];
        int interval = 0, samples = 0;
        size_t len = 0, ilen = 0;
@@ -156,8 +249,8 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
 
        switch_channel_answer(channel);
 
-       write_frame.data = buf;
-       write_frame.buflen = sizeof(buf);
+       write_frame.data = abuf;
+       write_frame.buflen = sizeof(abuf);
 
 
        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OPEN FILE %s %dhz %d channels\n", file, fh.samplerate, fh.channels);
@@ -206,23 +299,30 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
        while (switch_channel_get_state(channel) == CS_EXECUTE) {
                int done = 0;
 
-               if (dtmf_callback) {
+               if (dtmf_callback || buf) {
+
+
                        /*
                          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 (dtmf_callback) {
+                                       status = dtmf_callback(session, dtmf, buf, buflen);
+                               } else {
+                                       switch_copy_string((char *)buf, dtmf, buflen);
+                                       status = SWITCH_STATUS_BREAK;
+                               }
                        }
-
+                       
                        if (status != SWITCH_STATUS_SUCCESS) {
                                done = 1;
                                break;
                        }
                }
                
-               switch_core_file_read(&fh, buf, &ilen);
+               switch_core_file_read(&fh, abuf, &ilen);
 
                if (done || ilen <= 0) {
                        break;
@@ -270,3 +370,6 @@ SWITCH_DECLARE(switch_status) switch_ivr_play_file(switch_core_session *session,
 
        return status;
 }
+
+
+