merge changes from branch http://svn.freeswitch.org/svn/freeswitch/branches/greenlizard/ that changes the session container implementation to use the one in the core, and an inherited class in python. Please note that this changes the python script api to more closely match (it is still a subset) the one already in place and documented for spidermonkey, and will break all your scripts that are currently working.. Fix a fatal bug causing segfaults in mod_python when using the callbacks.
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5242 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
f0573f0607
commit
fedefcb69f
|
@ -10,17 +10,17 @@ def onDTMF(input, itype, buf, buflen):
|
|||
return 0
|
||||
console_log("1","test from my python program\n")
|
||||
session.answer()
|
||||
session.set_dtmf_callback(onDTMF)
|
||||
session.setDTMFCallback(onDTMF)
|
||||
session.set_tts_parms("cepstral", "david")
|
||||
session.play_file("/root/test.gsm", "")
|
||||
session.speak_text("Please enter telephone number with area code and press pound sign. ")
|
||||
input = session.get_digits("", 11, "*#", 10000)
|
||||
session.playFile("/root/test.gsm", "")
|
||||
session.speakText("Please enter telephone number with area code and press pound sign. ")
|
||||
input = session.getDigits("", 11, "*#", 10000)
|
||||
console_log("1","result from get digits is "+ input +"\n")
|
||||
phone_number = session.play_and_get_digits(5, 11, 3, 10000, "*#",
|
||||
"/sounds/test.gsm",
|
||||
"/sounds/invalid.gsm",
|
||||
"",
|
||||
"^17771112222$");
|
||||
phone_number = session.playAndGetDigits(5, 11, 3, 10000, "*#",
|
||||
"/sounds/test.gsm",
|
||||
"/sounds/invalid.gsm",
|
||||
"",
|
||||
"^17771112222$");
|
||||
console_log("1","result from play_and_get_digits is "+ phone_number +"\n")
|
||||
session.transfer("1000", "XML", "default")
|
||||
session.hangup("1")
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
#ifndef SWITCH_CPP_H
|
||||
#define SWITCH_CPP_H
|
||||
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef DOH
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
|
||||
void console_log(char *level_str, char *msg);
|
||||
void console_clean_log(char *msg);
|
||||
char *api_execute(char *cmd, char *arg);
|
||||
void api_reply_delete(char *reply);
|
||||
switch_status_t process_callback_result(char *raw_result,
|
||||
struct input_callback_state *cb_state,
|
||||
switch_core_session_t *session);
|
||||
|
||||
class CoreSession {
|
||||
private:
|
||||
char *uuid;
|
||||
char *tts_name;
|
||||
char *voice_name;
|
||||
switch_input_args_t args;
|
||||
switch_input_args_t *ap;
|
||||
public:
|
||||
|
@ -33,14 +41,25 @@ class CoreSession {
|
|||
void set_tts_parms(char *tts_name, char *voice_name);
|
||||
int getDigits(char *dtmf_buf, int len, char *terminators, char *terminator, int timeout);
|
||||
int transfer(char *extensions, char *dialplan, char *context);
|
||||
int playAndgetDigits(int min_digits, int max_digits, int max_tries, int timeout, char *terminators,
|
||||
char *audio_files, char *bad_input_audio_files, char *dtmf_buf, char *digits_regex);
|
||||
int playAndGetDigits(int min_digits, int max_digits, int max_tries, int timeout, char *terminators,
|
||||
char *audio_files, char *bad_input_audio_files, char *dtmf_buf,
|
||||
char *digits_regex);
|
||||
int streamfile(char *file, void *cb_func, char *funcargs, int starting_sample_count);
|
||||
void execute(char *app, char *data);
|
||||
void begin_allow_threads();
|
||||
void end_allow_threads();
|
||||
|
||||
protected:
|
||||
char *uuid;
|
||||
char *tts_name;
|
||||
char *voice_name;
|
||||
};
|
||||
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
|
|
|
@ -17,7 +17,7 @@ local_depend:
|
|||
MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install Python-2.5.1.tgz --prefix=$(PREFIX) --enable-threads CFLAGSFORSHARED="-fPIC"
|
||||
|
||||
reswig:
|
||||
swig -python -shadow -c++ -o mod_python_wrap.cpp mod_python.i
|
||||
swig -python -shadow -c++ -I../../../../src/include -o mod_python_wrap.cpp mod_python.i
|
||||
|
||||
switch_swig_wrap.o: switch_swig_wrap.c Makefile
|
||||
$(CC) -w $(CFLAGS) -c $< -o $@
|
||||
|
|
|
@ -1,25 +1,37 @@
|
|||
# This file was created automatically by SWIG.
|
||||
# This file was created automatically by SWIG 1.3.29.
|
||||
# Don't modify this file, modify the SWIG interface instead.
|
||||
# This file is compatible with both classic and new-style classes.
|
||||
|
||||
import _freeswitch
|
||||
|
||||
def _swig_setattr(self,class_type,name,value):
|
||||
import new
|
||||
new_instancemethod = new.instancemethod
|
||||
def _swig_setattr_nondynamic(self,class_type,name,value,static=1):
|
||||
if (name == "thisown"): return self.this.own(value)
|
||||
if (name == "this"):
|
||||
if isinstance(value, class_type):
|
||||
self.__dict__[name] = value.this
|
||||
if hasattr(value,"thisown"): self.__dict__["thisown"] = value.thisown
|
||||
del value.thisown
|
||||
if type(value).__name__ == 'PySwigObject':
|
||||
self.__dict__[name] = value
|
||||
return
|
||||
method = class_type.__swig_setmethods__.get(name,None)
|
||||
if method: return method(self,value)
|
||||
self.__dict__[name] = value
|
||||
if (not static) or hasattr(self,name):
|
||||
self.__dict__[name] = value
|
||||
else:
|
||||
raise AttributeError("You cannot add attributes to %s" % self)
|
||||
|
||||
def _swig_setattr(self,class_type,name,value):
|
||||
return _swig_setattr_nondynamic(self,class_type,name,value,0)
|
||||
|
||||
def _swig_getattr(self,class_type,name):
|
||||
if (name == "thisown"): return self.this.own()
|
||||
method = class_type.__swig_getmethods__.get(name,None)
|
||||
if method: return method(self)
|
||||
raise AttributeError,name
|
||||
|
||||
def _swig_repr(self):
|
||||
try: strthis = "proxy of " + self.this.__repr__()
|
||||
except: strthis = ""
|
||||
return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
|
||||
|
||||
import types
|
||||
try:
|
||||
_object = types.ObjectType
|
||||
|
@ -30,52 +42,95 @@ except AttributeError:
|
|||
del types
|
||||
|
||||
|
||||
console_log = _freeswitch.console_log
|
||||
console_clean_log = _freeswitch.console_clean_log
|
||||
api_execute = _freeswitch.api_execute
|
||||
api_reply_delete = _freeswitch.api_reply_delete
|
||||
process_callback_result = _freeswitch.process_callback_result
|
||||
class CoreSession(_object):
|
||||
__swig_setmethods__ = {}
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, CoreSession, name, value)
|
||||
__swig_getmethods__ = {}
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, CoreSession, name)
|
||||
__repr__ = _swig_repr
|
||||
def __init__(self, *args):
|
||||
this = _freeswitch.new_CoreSession(*args)
|
||||
try: self.this.append(this)
|
||||
except: self.this = this
|
||||
__swig_destroy__ = _freeswitch.delete_CoreSession
|
||||
__del__ = lambda self : None;
|
||||
__swig_setmethods__["session"] = _freeswitch.CoreSession_session_set
|
||||
__swig_getmethods__["session"] = _freeswitch.CoreSession_session_get
|
||||
if _newclass:session = property(_freeswitch.CoreSession_session_get, _freeswitch.CoreSession_session_set)
|
||||
__swig_setmethods__["channel"] = _freeswitch.CoreSession_channel_set
|
||||
__swig_getmethods__["channel"] = _freeswitch.CoreSession_channel_get
|
||||
if _newclass:channel = property(_freeswitch.CoreSession_channel_get, _freeswitch.CoreSession_channel_set)
|
||||
def answer(*args): return _freeswitch.CoreSession_answer(*args)
|
||||
def preAnswer(*args): return _freeswitch.CoreSession_preAnswer(*args)
|
||||
def hangup(*args): return _freeswitch.CoreSession_hangup(*args)
|
||||
def setVariable(*args): return _freeswitch.CoreSession_setVariable(*args)
|
||||
def getVariable(*args): return _freeswitch.CoreSession_getVariable(*args)
|
||||
def playFile(*args): return _freeswitch.CoreSession_playFile(*args)
|
||||
def setDTMFCallback(*args): return _freeswitch.CoreSession_setDTMFCallback(*args)
|
||||
def speakText(*args): return _freeswitch.CoreSession_speakText(*args)
|
||||
def set_tts_parms(*args): return _freeswitch.CoreSession_set_tts_parms(*args)
|
||||
def getDigits(*args): return _freeswitch.CoreSession_getDigits(*args)
|
||||
def transfer(*args): return _freeswitch.CoreSession_transfer(*args)
|
||||
def playAndGetDigits(*args): return _freeswitch.CoreSession_playAndGetDigits(*args)
|
||||
def streamfile(*args): return _freeswitch.CoreSession_streamfile(*args)
|
||||
def execute(*args): return _freeswitch.CoreSession_execute(*args)
|
||||
def begin_allow_threads(*args): return _freeswitch.CoreSession_begin_allow_threads(*args)
|
||||
def end_allow_threads(*args): return _freeswitch.CoreSession_end_allow_threads(*args)
|
||||
CoreSession_swigregister = _freeswitch.CoreSession_swigregister
|
||||
CoreSession_swigregister(CoreSession)
|
||||
|
||||
PythonDTMFCallback = _freeswitch.PythonDTMFCallback
|
||||
|
||||
console_log = _freeswitch.console_log
|
||||
|
||||
console_clean_log = _freeswitch.console_clean_log
|
||||
|
||||
api_execute = _freeswitch.api_execute
|
||||
|
||||
api_reply_delete = _freeswitch.api_reply_delete
|
||||
class SessionContainer(_object):
|
||||
class input_callback_state(_object):
|
||||
__swig_setmethods__ = {}
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, SessionContainer, name, value)
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, input_callback_state, name, value)
|
||||
__swig_getmethods__ = {}
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, SessionContainer, name)
|
||||
def __repr__(self):
|
||||
return "<C SessionContainer instance at %s>" % (self.this,)
|
||||
def __init__(self, *args):
|
||||
_swig_setattr(self, SessionContainer, 'this', _freeswitch.new_SessionContainer(*args))
|
||||
_swig_setattr(self, SessionContainer, 'thisown', 1)
|
||||
def __del__(self, destroy=_freeswitch.delete_SessionContainer):
|
||||
try:
|
||||
if self.thisown: destroy(self)
|
||||
except: pass
|
||||
__swig_setmethods__["uuid"] = _freeswitch.SessionContainer_uuid_set
|
||||
__swig_getmethods__["uuid"] = _freeswitch.SessionContainer_uuid_get
|
||||
if _newclass:uuid = property(_freeswitch.SessionContainer_uuid_get, _freeswitch.SessionContainer_uuid_set)
|
||||
def answer(*args): return _freeswitch.SessionContainer_answer(*args)
|
||||
def pre_answer(*args): return _freeswitch.SessionContainer_pre_answer(*args)
|
||||
def hangup(*args): return _freeswitch.SessionContainer_hangup(*args)
|
||||
def set_variable(*args): return _freeswitch.SessionContainer_set_variable(*args)
|
||||
def get_variable(*args): return _freeswitch.SessionContainer_get_variable(*args)
|
||||
def play_file(*args): return _freeswitch.SessionContainer_play_file(*args)
|
||||
def set_dtmf_callback(*args): return _freeswitch.SessionContainer_set_dtmf_callback(*args)
|
||||
def speak_text(*args): return _freeswitch.SessionContainer_speak_text(*args)
|
||||
def set_tts_parms(*args): return _freeswitch.SessionContainer_set_tts_parms(*args)
|
||||
def get_digits(*args): return _freeswitch.SessionContainer_get_digits(*args)
|
||||
def transfer(*args): return _freeswitch.SessionContainer_transfer(*args)
|
||||
def play_and_get_digits(*args): return _freeswitch.SessionContainer_play_and_get_digits(*args)
|
||||
def execute(*args): return _freeswitch.SessionContainer_execute(*args)
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, input_callback_state, name)
|
||||
__repr__ = _swig_repr
|
||||
__swig_setmethods__["function"] = _freeswitch.input_callback_state_function_set
|
||||
__swig_getmethods__["function"] = _freeswitch.input_callback_state_function_get
|
||||
if _newclass:function = property(_freeswitch.input_callback_state_function_get, _freeswitch.input_callback_state_function_set)
|
||||
__swig_setmethods__["threadState"] = _freeswitch.input_callback_state_threadState_set
|
||||
__swig_getmethods__["threadState"] = _freeswitch.input_callback_state_threadState_get
|
||||
if _newclass:threadState = property(_freeswitch.input_callback_state_threadState_get, _freeswitch.input_callback_state_threadState_set)
|
||||
__swig_setmethods__["extra"] = _freeswitch.input_callback_state_extra_set
|
||||
__swig_getmethods__["extra"] = _freeswitch.input_callback_state_extra_get
|
||||
if _newclass:extra = property(_freeswitch.input_callback_state_extra_get, _freeswitch.input_callback_state_extra_set)
|
||||
__swig_setmethods__["funcargs"] = _freeswitch.input_callback_state_funcargs_set
|
||||
__swig_getmethods__["funcargs"] = _freeswitch.input_callback_state_funcargs_get
|
||||
if _newclass:funcargs = property(_freeswitch.input_callback_state_funcargs_get, _freeswitch.input_callback_state_funcargs_set)
|
||||
def __init__(self, *args):
|
||||
this = _freeswitch.new_input_callback_state(*args)
|
||||
try: self.this.append(this)
|
||||
except: self.this = this
|
||||
__swig_destroy__ = _freeswitch.delete_input_callback_state
|
||||
__del__ = lambda self : None;
|
||||
input_callback_state_swigregister = _freeswitch.input_callback_state_swigregister
|
||||
input_callback_state_swigregister(input_callback_state)
|
||||
|
||||
class PySession(CoreSession):
|
||||
__swig_setmethods__ = {}
|
||||
for _s in [CoreSession]: __swig_setmethods__.update(_s.__swig_setmethods__)
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, PySession, name, value)
|
||||
__swig_getmethods__ = {}
|
||||
for _s in [CoreSession]: __swig_getmethods__.update(_s.__swig_getmethods__)
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, PySession, name)
|
||||
__repr__ = _swig_repr
|
||||
def __init__(self, *args):
|
||||
this = _freeswitch.new_PySession(*args)
|
||||
try: self.this.append(this)
|
||||
except: self.this = this
|
||||
__swig_destroy__ = _freeswitch.delete_PySession
|
||||
__del__ = lambda self : None;
|
||||
def streamfile(*args): return _freeswitch.PySession_streamfile(*args)
|
||||
def begin_allow_threads(*args): return _freeswitch.PySession_begin_allow_threads(*args)
|
||||
def end_allow_threads(*args): return _freeswitch.PySession_end_allow_threads(*args)
|
||||
PySession_swigregister = _freeswitch.PySession_swigregister
|
||||
PySession_swigregister(PySession)
|
||||
|
||||
class SessionContainerPtr(SessionContainer):
|
||||
def __init__(self, this):
|
||||
_swig_setattr(self, SessionContainer, 'this', this)
|
||||
if not hasattr(self,"thisown"): _swig_setattr(self, SessionContainer, 'thisown', 0)
|
||||
_swig_setattr(self, SessionContainer,self.__class__,SessionContainer)
|
||||
_freeswitch.SessionContainer_swigregister(SessionContainerPtr)
|
||||
|
||||
|
||||
|
|
|
@ -2,172 +2,55 @@
|
|||
|
||||
#define sanity_check(x) do { if (!session) { switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_ERROR, "session is not initalized\n"); return x;}} while(0)
|
||||
|
||||
SessionContainer::SessionContainer(char *nuuid)
|
||||
{
|
||||
uuid = nuuid;
|
||||
dtmfCallbackFunction = NULL;
|
||||
tts_name = NULL;
|
||||
voice_name = NULL;
|
||||
|
||||
if (session = switch_core_session_locate(uuid)) {
|
||||
channel = switch_core_session_get_channel(session);
|
||||
}
|
||||
}
|
||||
|
||||
SessionContainer::~SessionContainer()
|
||||
{
|
||||
|
||||
if (session) {
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
}
|
||||
|
||||
int SessionContainer::answer()
|
||||
{
|
||||
switch_status_t status;
|
||||
|
||||
sanity_check(-1);
|
||||
status = switch_channel_answer(channel);
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
int SessionContainer::pre_answer()
|
||||
{
|
||||
switch_status_t status;
|
||||
sanity_check(-1);
|
||||
switch_channel_pre_answer(channel);
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
void SessionContainer::hangup(char *cause)
|
||||
{
|
||||
sanity_check();
|
||||
switch_channel_hangup(channel, switch_channel_str2cause(cause));
|
||||
}
|
||||
|
||||
void SessionContainer::set_variable(char *var, char *val)
|
||||
{
|
||||
sanity_check();
|
||||
switch_channel_set_variable(channel, var, val);
|
||||
}
|
||||
|
||||
char *SessionContainer::get_variable(char *var)
|
||||
{
|
||||
sanity_check(NULL);
|
||||
return switch_channel_get_variable(channel, var);
|
||||
}
|
||||
|
||||
void SessionContainer::execute(char *app, char *data)
|
||||
{
|
||||
const switch_application_interface_t *application_interface;
|
||||
sanity_check();
|
||||
|
||||
if ((application_interface = switch_loadable_module_get_application_interface(app))) {
|
||||
switch_core_session_exec(session, application_interface, data);
|
||||
}
|
||||
}
|
||||
|
||||
int SessionContainer::play_file(char *file, char *timer_name)
|
||||
int PySession::streamfile(char *file, PyObject *pyfunc, char *funcargs, int starting_sample_count)
|
||||
{
|
||||
switch_status_t status;
|
||||
switch_input_args_t args = { 0 }, *ap = NULL;
|
||||
sanity_check(-1);
|
||||
struct input_callback_state cb_state = { 0 };
|
||||
switch_file_handle_t fh = { 0 };
|
||||
|
||||
if (switch_strlen_zero(timer_name)) {
|
||||
timer_name = NULL;
|
||||
}
|
||||
sanity_check(-1);
|
||||
cb_state.funcargs = funcargs;
|
||||
fh.samples = starting_sample_count;
|
||||
|
||||
if (dtmfCallbackFunction) {
|
||||
args.buf = dtmfCallbackFunction;
|
||||
args.input_callback = PythonDTMFCallback;
|
||||
ap = &args;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
status = switch_ivr_play_file(session, NULL, file, ap);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
void SessionContainer::set_dtmf_callback(PyObject *pyfunc)
|
||||
{
|
||||
sanity_check();
|
||||
if (!PyCallable_Check(pyfunc)) {
|
||||
dtmfCallbackFunction = NULL;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "DTMF function is not a python function.");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "DTMF function is not a python function.");
|
||||
}
|
||||
else {
|
||||
dtmfCallbackFunction = pyfunc;
|
||||
}
|
||||
}
|
||||
|
||||
int SessionContainer::speak_text(char *text)
|
||||
{
|
||||
switch_status_t status;
|
||||
switch_codec_t *codec;
|
||||
switch_input_args_t args = { 0 }, *ap = NULL;
|
||||
|
||||
sanity_check(-1);
|
||||
|
||||
codec = switch_core_session_get_read_codec(session);
|
||||
if (dtmfCallbackFunction) {
|
||||
args.buf = dtmfCallbackFunction;
|
||||
args.input_callback = PythonDTMFCallback;
|
||||
ap = &args;
|
||||
cb_state.function = dtmfCallbackFunction;
|
||||
cb_state.extra = &fh;
|
||||
args.buf = &cb_state;
|
||||
args.buflen = sizeof(cb_state); // not sure what this is used for, copy mod_spidermonkey
|
||||
args.input_callback = PythonDTMFCallback; // defined in mod_python.i, will use ptrs in cb_state
|
||||
ap = &args;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
status = switch_ivr_speak_text(session, tts_name, voice_name, codec->implementation->samples_per_second, text, ap);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
this->begin_allow_threads();
|
||||
cb_state.threadState = threadState; // pass threadState so the dtmfhandler can pick it up
|
||||
status = switch_ivr_play_file(session, &fh, file, ap);
|
||||
this->end_allow_threads();
|
||||
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
void SessionContainer::set_tts_parms(char *tts_name_p, char *voice_name_p)
|
||||
{
|
||||
sanity_check();
|
||||
tts_name = tts_name_p;
|
||||
voice_name = voice_name_p;
|
||||
}
|
||||
|
||||
int SessionContainer::get_digits(char *dtmf_buf, int len, char *terminators, char *terminator, int timeout)
|
||||
{
|
||||
switch_status_t status;
|
||||
sanity_check(-1);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
status = switch_ivr_collect_digits_count(session, dtmf_buf,(uint32_t) len,(uint32_t) len, terminators, terminator, (uint32_t) timeout);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
int SessionContainer::transfer(char *extension, char *dialplan, char *context)
|
||||
{
|
||||
switch_status_t status;
|
||||
sanity_check(-1);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
status = switch_ivr_session_transfer(session, extension, dialplan, context);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
int SessionContainer::play_and_get_digits(int min_digits, int max_digits, int max_tries, int timeout, char *terminators,
|
||||
char *audio_files, char *bad_input_audio_files, char *dtmf_buf, char *digits_regex)
|
||||
{
|
||||
switch_status_t status;
|
||||
sanity_check(-1);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
status = switch_play_and_get_digits( session, (uint32_t) min_digits,(uint32_t) max_digits,
|
||||
(uint32_t) max_tries, (uint32_t) timeout,
|
||||
terminators, audio_files, bad_input_audio_files, dtmf_buf, 128, digits_regex);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void PySession::begin_allow_threads(void) {
|
||||
threadState = PyEval_SaveThread();
|
||||
}
|
||||
|
||||
void PySession::end_allow_threads(void) {
|
||||
PyEval_RestoreThread(threadState);
|
||||
}
|
||||
|
||||
PySession::~PySession() {
|
||||
// Should we do any cleanup here?
|
||||
}
|
||||
|
||||
|
|
|
@ -10,40 +10,41 @@ extern "C" {
|
|||
}
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
#include <switch_cpp.h>
|
||||
|
||||
|
||||
|
||||
// declaration for function that is defined in mod_python.i
|
||||
extern switch_status_t PythonDTMFCallback(switch_core_session *session,
|
||||
void *input,
|
||||
switch_input_type_t itype,
|
||||
void *buf,
|
||||
unsigned int buflen);
|
||||
|
||||
extern switch_status_t PythonDTMFCallback(switch_core_session * session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen);
|
||||
void console_log(char *level_str, char *msg);
|
||||
void console_clean_log(char *msg);
|
||||
char *api_execute(char *cmd, char *arg);
|
||||
void api_reply_delete(char *reply);
|
||||
|
||||
class SessionContainer {
|
||||
private:
|
||||
switch_core_session_t *session;
|
||||
switch_channel_t *channel;
|
||||
PyObject *dtmfCallbackFunction;
|
||||
char *tts_name;
|
||||
char *voice_name;
|
||||
public:
|
||||
SessionContainer(char *uuid);
|
||||
~SessionContainer();
|
||||
char *uuid;
|
||||
struct input_callback_state {
|
||||
PyObject *function;
|
||||
PyThreadState *threadState;
|
||||
void *extra;
|
||||
char *funcargs;
|
||||
};
|
||||
|
||||
class PySession : public CoreSession {
|
||||
private:
|
||||
PyObject *dtmfCallbackFunction;
|
||||
PyThreadState *threadState;
|
||||
public:
|
||||
PySession(char *uuid) : CoreSession(uuid) {};
|
||||
PySession(switch_core_session_t *session) : CoreSession(session) {};
|
||||
~PySession();
|
||||
int streamfile(char *file, PyObject *pyfunc, char *funcargs, int starting_sample_count);
|
||||
void begin_allow_threads();
|
||||
void end_allow_threads();
|
||||
|
||||
int answer();
|
||||
int pre_answer();
|
||||
void hangup(char *cause);
|
||||
void set_variable(char *var, char *val);
|
||||
char *get_variable(char *var);
|
||||
int play_file(char *file, char *timer_name);
|
||||
void set_dtmf_callback(PyObject * pyfunc);
|
||||
int speak_text(char *text);
|
||||
void set_tts_parms(char *tts_name, char *voice_name);
|
||||
int get_digits(char *dtmf_buf, int len, char *terminators, char *terminator, int timeout);
|
||||
int transfer(char *extensions, char *dialplan, char *context);
|
||||
int play_and_get_digits(int min_digits, int max_digits, int max_tries, int timeout, char *terminators,
|
||||
char *audio_files, char *bad_input_audio_files, char *dtmf_buf, char *digits_regex);
|
||||
void execute(char *app, char *data);
|
||||
protected:
|
||||
};
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include <switch.h>
|
||||
|
||||
|
||||
static PyThreadState *mainThreadState = NULL;
|
||||
PyThreadState *mainThreadState = NULL;
|
||||
|
||||
void init_freeswitch(void);
|
||||
static switch_api_interface_t python_run_interface;
|
||||
|
@ -111,7 +111,7 @@ static void eval_some_python(char *uuid, char *args)
|
|||
PyRun_SimpleString("from freeswitch import *");
|
||||
if (uuid) {
|
||||
char code[128];
|
||||
snprintf(code, sizeof(code), "session = SessionContainer(\"%s\");", uuid);
|
||||
snprintf(code, sizeof(code), "session = PySession(\"%s\");", uuid);
|
||||
PyRun_SimpleString(code);
|
||||
}
|
||||
PySys_SetArgv(argc - lead, &argv[lead]);
|
||||
|
|
|
@ -5,32 +5,165 @@
|
|||
%cstring_bounded_mutable(char *terminator, 8);
|
||||
|
||||
%{
|
||||
#include "switch_cpp.h"
|
||||
#include "freeswitch_python.h"
|
||||
%}
|
||||
|
||||
%include switch_cpp.h
|
||||
%include freeswitch_python.h
|
||||
|
||||
%{
|
||||
|
||||
|
||||
|
||||
switch_status_t PythonDTMFCallback(switch_core_session_t *session,
|
||||
void *input,
|
||||
switch_input_type_t itype,
|
||||
void *buf,
|
||||
void *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
PyObject *func, *arglist;
|
||||
PyObject *result;
|
||||
switch_status_t dres = SWITCH_STATUS_FALSE;
|
||||
char *resultStr;
|
||||
char *funcargs;
|
||||
struct input_callback_state *cb_state;
|
||||
switch_file_handle_t *fh = NULL;
|
||||
PyThreadState *threadState = NULL;
|
||||
|
||||
if (!buf) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buf pointer is null");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
func = (PyObject *) buf; // Get Python function
|
||||
arglist = Py_BuildValue("(si)", input, itype); // Build argument list
|
||||
result = PyEval_CallObject(func, arglist); // Call Python
|
||||
Py_DECREF(arglist); // Trash arglist
|
||||
if (result) { // If no errors, return double
|
||||
dres = (switch_status_t) PyInt_AsLong(result);
|
||||
cb_state = (input_callback_state *) buf;
|
||||
|
||||
func = (PyObject *) cb_state->function;
|
||||
if (!func) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cb_state->function is null");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
Py_XDECREF(result);
|
||||
return dres;
|
||||
if (!PyCallable_Check(func)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "function not callable");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
funcargs = (char *) cb_state->funcargs;
|
||||
|
||||
arglist = Py_BuildValue("(sis)", input, itype, funcargs);
|
||||
if (!arglist) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error building arglist");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
threadState = (PyThreadState *) cb_state->threadState;
|
||||
if (!threadState) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error, invalid threadstate");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
PyEval_RestoreThread(threadState); // nasty stuff happens when py interp has no thread state
|
||||
result = PyEval_CallObject(func, arglist);
|
||||
threadState = PyEval_SaveThread();
|
||||
|
||||
|
||||
Py_DECREF(arglist); // Trash arglist
|
||||
if (result && result != Py_None) {
|
||||
resultStr = (char *) PyString_AsString(result);
|
||||
Py_XDECREF(result);
|
||||
return process_callback_result(resultStr, cb_state, session);
|
||||
}
|
||||
else {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
switch_status_t process_callback_result(char *ret,
|
||||
struct input_callback_state *cb_state,
|
||||
switch_core_session_t *session)
|
||||
{
|
||||
|
||||
switch_file_handle_t *fh = NULL;
|
||||
fh = (switch_file_handle_t *) cb_state->extra;
|
||||
|
||||
|
||||
if (!ret) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!strncasecmp(ret, "speed", 4)) {
|
||||
char *p;
|
||||
|
||||
if ((p = strchr(ret, ':'))) {
|
||||
p++;
|
||||
if (*p == '+' || *p == '-') {
|
||||
int step;
|
||||
if (!(step = atoi(p))) {
|
||||
step = 1;
|
||||
}
|
||||
fh->speed += step;
|
||||
} else {
|
||||
int speed = atoi(p);
|
||||
fh->speed = speed;
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
} else if (!strcasecmp(ret, "pause")) {
|
||||
if (switch_test_flag(fh, SWITCH_FILE_PAUSE)) {
|
||||
switch_clear_flag(fh, SWITCH_FILE_PAUSE);
|
||||
} else {
|
||||
switch_set_flag(fh, SWITCH_FILE_PAUSE);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else if (!strcasecmp(ret, "stop")) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
} else if (!strcasecmp(ret, "restart")) {
|
||||
unsigned int pos = 0;
|
||||
fh->speed = 0;
|
||||
switch_core_file_seek(fh, &pos, 0, SEEK_SET);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else if (!strncasecmp(ret, "seek", 4)) {
|
||||
switch_codec_t *codec;
|
||||
unsigned int samps = 0;
|
||||
unsigned int pos = 0;
|
||||
char *p;
|
||||
codec = switch_core_session_get_read_codec(session);
|
||||
|
||||
if ((p = strchr(ret, ':'))) {
|
||||
p++;
|
||||
if (*p == '+' || *p == '-') {
|
||||
int step;
|
||||
if (!(step = atoi(p))) {
|
||||
step = 1000;
|
||||
}
|
||||
if (step > 0) {
|
||||
samps = step * (codec->implementation->samples_per_second / 1000);
|
||||
switch_core_file_seek(fh, &pos, samps, SEEK_CUR);
|
||||
} else {
|
||||
samps = step * (codec->implementation->samples_per_second / 1000);
|
||||
switch_core_file_seek(fh, &pos, fh->pos - samps, SEEK_SET);
|
||||
}
|
||||
} else {
|
||||
samps = atoi(p) * (codec->implementation->samples_per_second / 1000);
|
||||
switch_core_file_seek(fh, &pos, samps, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!strcmp(ret, "true") || !strcmp(ret, "undefined")) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -77,7 +77,9 @@ void CoreSession::execute(char *app, char *data)
|
|||
sanity_check();
|
||||
|
||||
if ((application_interface = switch_loadable_module_get_application_interface(app))) {
|
||||
begin_allow_threads();
|
||||
switch_core_session_exec(session, application_interface, data);
|
||||
end_allow_threads();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,9 +90,11 @@ int CoreSession::playFile(char *file, char *timer_name)
|
|||
if (switch_strlen_zero(timer_name)) {
|
||||
timer_name = NULL;
|
||||
}
|
||||
|
||||
begin_allow_threads();
|
||||
status = switch_ivr_play_file(session, NULL, file, ap);
|
||||
end_allow_threads();
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
void CoreSession::setDTMFCallback(switch_input_callback_function_t cb, void *buf, uint32_t buflen)
|
||||
|
@ -114,7 +118,9 @@ int CoreSession::speakText(char *text)
|
|||
|
||||
sanity_check(-1);
|
||||
codec = switch_core_session_get_read_codec(session);
|
||||
begin_allow_threads();
|
||||
status = switch_ivr_speak_text(session, tts_name, voice_name, codec->implementation->samples_per_second, text, ap);
|
||||
end_allow_threads();
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -131,7 +137,9 @@ int CoreSession::getDigits(char *dtmf_buf, int len, char *terminators, char *ter
|
|||
{
|
||||
switch_status_t status;
|
||||
sanity_check(-1);
|
||||
begin_allow_threads();
|
||||
status = switch_ivr_collect_digits_count(session, dtmf_buf,(uint32_t) len,(uint32_t) len, terminators, terminator, (uint32_t) timeout);
|
||||
end_allow_threads();
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
|
@ -143,17 +151,37 @@ int CoreSession::transfer(char *extension, char *dialplan, char *context)
|
|||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
int CoreSession::playAndgetDigits(int min_digits, int max_digits, int max_tries, int timeout, char *terminators,
|
||||
int CoreSession::playAndGetDigits(int min_digits, int max_digits, int max_tries, int timeout, char *terminators,
|
||||
char *audio_files, char *bad_input_audio_files, char *dtmf_buf, char *digits_regex)
|
||||
{
|
||||
switch_status_t status;
|
||||
sanity_check(-1);
|
||||
status = switch_play_and_get_digits( session, (uint32_t) min_digits,(uint32_t) max_digits,
|
||||
(uint32_t) max_tries, (uint32_t) timeout,
|
||||
terminators, audio_files, bad_input_audio_files, dtmf_buf, 128, digits_regex);
|
||||
begin_allow_threads();
|
||||
status = switch_play_and_get_digits( session,
|
||||
(uint32_t) min_digits,
|
||||
(uint32_t) max_digits,
|
||||
(uint32_t) max_tries,
|
||||
(uint32_t) timeout,
|
||||
terminators,
|
||||
audio_files,
|
||||
bad_input_audio_files,
|
||||
dtmf_buf, 128,
|
||||
digits_regex);
|
||||
end_allow_threads();
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
||||
int CoreSession::streamfile(char *file, void *cb_func, char *funcargs, int starting_sample_count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CoreSession::begin_allow_threads() {
|
||||
}
|
||||
|
||||
void CoreSession::end_allow_threads() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
|
|
Loading…
Reference in New Issue