Add more IVR stuff and a test app (mod_ivrtest)

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
This commit is contained in:
Anthony Minessale 2006-01-27 21:33:45 +00:00
parent 4a98cfbb88
commit 534db1947e
10 changed files with 504 additions and 29 deletions

View File

@ -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

View File

@ -1,5 +1,6 @@
applications/mod_bridgecall
applications/mod_playback
applications/mod_ivrtest
#applications/mod_skel
#codecs/mod_g729
codecs/mod_gsm

View 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

View 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 */

View File

@ -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)

View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="mod_ivrtest"
ProjectGUID="{78100236-7CEA-4948-96CC-E8ED3160329C}"
RootNamespace="mod_ivrtest"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_ivrtest.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\apr\Debug"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/mod_ivrtest.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/mod_ivrtest.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_ivrtest.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Release&quot;"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/mod_ivrtest.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\mod_ivrtest.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View 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);
}

View 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 (!

View File

@ -89,6 +89,8 @@ switch_status sndfile_file_open(switch_file_handle *handle, char *path)
} else {
ready = 0;
}
} else {
ready = 0;
}

View File

@ -35,9 +35,95 @@
/* 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;
}