提交 f45d0601 authored 作者: Michael Jerris's avatar Michael Jerris

merge fix for MODLANG-33 and MODLANG-34.

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5374 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 27561c65
# Please see latest version of this script at
# http://wiki.freeswitch.org/wiki/Mod_python
# before reporting errors
import sys, time import sys, time
def onDTMF(input, itype, buf, buflen): from freeswitch import *
print "input=",input
print "itype=",itype def onDTMF(input, itype, funcargs):
print "buf=",buf console_log("1","\n\nonDTMF input: %s\n" % input)
print "buflen",buflen if input == "5":
if input == "#": return "pause"
return 1 if input == "3":
else: return "seek:+60000"
return 0 if input == "1":
console_log("1","test from my python program\n") return "seek:-60000"
session.answer() if input == "0":
session.setDTMFCallback(onDTMF) return "stop"
session.set_tts_parms("cepstral", "david") return None # will make the streamfile audio stop
session.playFile("/root/test.gsm", "")
session.speakText("Please enter telephone number with area code and press pound sign. ") def handler(uuid):
input = session.getDigits("", 11, "*#", 10000)
console_log("1","result from get digits is "+ input +"\n") console_log("1","... test from my python program\n")
phone_number = session.playAndGetDigits(5, 11, 3, 10000, "*#", session = PySession(uuid)
"/sounds/test.gsm", session.answer()
"/sounds/invalid.gsm", session.setDTMFCallback(onDTMF, "")
"", session.set_tts_parms("cepstral", "david")
"^17771112222$"); session.playFile("/path/to/your.mp3", "")
console_log("1","result from play_and_get_digits is "+ phone_number +"\n") session.speak("Please enter telephone number with area code and press pound sign. ")
session.transfer("1000", "XML", "default") input = session.getDigits("", 11, "*#", "#", 10000)
session.hangup("1") console_log("1","result from get digits is %s\n" % input)
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 %s\n" % phone_number)
session.transfer("1000", "XML", "default")
session.hangup("1")
...@@ -20,39 +20,112 @@ switch_status_t process_callback_result(char *raw_result, ...@@ -20,39 +20,112 @@ switch_status_t process_callback_result(char *raw_result,
struct input_callback_state *cb_state, struct input_callback_state *cb_state,
switch_core_session_t *session); switch_core_session_t *session);
typedef struct input_callback_state {
void *function; // pointer to the language specific callback function
// eg, PyObject *pyfunc
void *threadState; // pointer to the language specific thread state
// eg, PyThreadState *threadState
void *extra; // currently used to store a switch_file_handle_t
char *funcargs; // extra string that will be passed to callback function
};
class CoreSession { class CoreSession {
private: protected:
switch_input_args_t args; switch_input_args_t args;
switch_input_args_t *ap; switch_input_args_t *ap;
char *uuid;
char *tts_name;
char *voice_name;
void store_file_handle(switch_file_handle_t *fh);
public: public:
CoreSession(char *uuid); CoreSession(char *uuid);
CoreSession(switch_core_session_t *new_session); CoreSession(switch_core_session_t *new_session);
~CoreSession(); virtual ~CoreSession();
switch_core_session_t *session; switch_core_session_t *session;
switch_channel_t *channel; switch_channel_t *channel;
input_callback_state cb_state;
int answer(); int answer();
int preAnswer(); int preAnswer();
void hangup(char *cause); void hangup(char *cause);
void setVariable(char *var, char *val); void setVariable(char *var, char *val);
char *getVariable(char *var); char *getVariable(char *var);
/** \brief Play a file that resides on disk into the channel
*
* \param file - the path to the .wav/.mp3 to be played
* \param timer_name - ?? does not seem to be used, what is this?
* \return an int status code indicating success or failure
*
* NOTE: if a dtmf callback is installed before calling this
* function, that callback will be called upon receiving any
* dtmfs
*/
int playFile(char *file, char *timer_name); int playFile(char *file, char *timer_name);
void setDTMFCallback(switch_input_callback_function_t cb, void *buf, uint32_t buflen);
int speakText(char *text);
/** \brief set a DTMF callback function
*
* The DTMF callback function will be set and persist
* for the life of the session, and be called when a dtmf
* is pressed by user during playFile(), streamfile(), and
* certain other methods are executing.
*
* Note that language specific sessions might need to create
* their own version of this with a slightly different signature
* (as done in freeswitch_python.h)
*/
void setDTMFCallback(switch_input_callback_function_t cb,
void *buf,
uint32_t buflen);
int speak(char *text);
void set_tts_parms(char *tts_name, char *voice_name); void set_tts_parms(char *tts_name, char *voice_name);
int getDigits(char *dtmf_buf, int len, char *terminators, char *terminator, int timeout);
int getDigits(char *dtmf_buf,
int len,
char *terminators,
char *terminator,
int timeout);
int transfer(char *extensions, char *dialplan, char *context); 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, /** \brief Play a file into channel and collect dtmfs
*
* See API docs in switch_ivr.h: switch_play_and_get_digits(..)
*
* NOTE: this does not call any dtmf callbacks set by
* setDTMFCallback(..) as it uses its own internal callback
* handler.
*/
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); char *digits_regex);
int streamfile(char *file, void *cb_func, char *funcargs, int starting_sample_count);
/** \brief Play a file that resides on disk into the channel
*
* \param file - the path to the .wav/.mp3 to be played
* \param starting_sample_count - the index of the sample to
* start playing from
* \return an int status code indicating success or failure
*
*/
int streamfile(char *file, int starting_sample_count);
bool ready();
void execute(char *app, char *data); void execute(char *app, char *data);
void begin_allow_threads(); virtual void begin_allow_threads();
void end_allow_threads(); virtual void end_allow_threads();
protected:
char *uuid;
char *tts_name;
char *voice_name;
}; };
......
...@@ -47,6 +47,33 @@ console_clean_log = _freeswitch.console_clean_log ...@@ -47,6 +47,33 @@ console_clean_log = _freeswitch.console_clean_log
api_execute = _freeswitch.api_execute api_execute = _freeswitch.api_execute
api_reply_delete = _freeswitch.api_reply_delete api_reply_delete = _freeswitch.api_reply_delete
process_callback_result = _freeswitch.process_callback_result process_callback_result = _freeswitch.process_callback_result
class input_callback_state(_object):
__swig_setmethods__ = {}
__setattr__ = lambda self, name, value: _swig_setattr(self, input_callback_state, name, value)
__swig_getmethods__ = {}
__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 CoreSession(_object): class CoreSession(_object):
__swig_setmethods__ = {} __swig_setmethods__ = {}
__setattr__ = lambda self, name, value: _swig_setattr(self, CoreSession, name, value) __setattr__ = lambda self, name, value: _swig_setattr(self, CoreSession, name, value)
...@@ -65,6 +92,9 @@ class CoreSession(_object): ...@@ -65,6 +92,9 @@ class CoreSession(_object):
__swig_setmethods__["channel"] = _freeswitch.CoreSession_channel_set __swig_setmethods__["channel"] = _freeswitch.CoreSession_channel_set
__swig_getmethods__["channel"] = _freeswitch.CoreSession_channel_get __swig_getmethods__["channel"] = _freeswitch.CoreSession_channel_get
if _newclass:channel = property(_freeswitch.CoreSession_channel_get, _freeswitch.CoreSession_channel_set) if _newclass:channel = property(_freeswitch.CoreSession_channel_get, _freeswitch.CoreSession_channel_set)
__swig_setmethods__["cb_state"] = _freeswitch.CoreSession_cb_state_set
__swig_getmethods__["cb_state"] = _freeswitch.CoreSession_cb_state_get
if _newclass:cb_state = property(_freeswitch.CoreSession_cb_state_get, _freeswitch.CoreSession_cb_state_set)
def answer(*args): return _freeswitch.CoreSession_answer(*args) def answer(*args): return _freeswitch.CoreSession_answer(*args)
def preAnswer(*args): return _freeswitch.CoreSession_preAnswer(*args) def preAnswer(*args): return _freeswitch.CoreSession_preAnswer(*args)
def hangup(*args): return _freeswitch.CoreSession_hangup(*args) def hangup(*args): return _freeswitch.CoreSession_hangup(*args)
...@@ -72,12 +102,13 @@ class CoreSession(_object): ...@@ -72,12 +102,13 @@ class CoreSession(_object):
def getVariable(*args): return _freeswitch.CoreSession_getVariable(*args) def getVariable(*args): return _freeswitch.CoreSession_getVariable(*args)
def playFile(*args): return _freeswitch.CoreSession_playFile(*args) def playFile(*args): return _freeswitch.CoreSession_playFile(*args)
def setDTMFCallback(*args): return _freeswitch.CoreSession_setDTMFCallback(*args) def setDTMFCallback(*args): return _freeswitch.CoreSession_setDTMFCallback(*args)
def speakText(*args): return _freeswitch.CoreSession_speakText(*args) def speak(*args): return _freeswitch.CoreSession_speak(*args)
def set_tts_parms(*args): return _freeswitch.CoreSession_set_tts_parms(*args) def set_tts_parms(*args): return _freeswitch.CoreSession_set_tts_parms(*args)
def getDigits(*args): return _freeswitch.CoreSession_getDigits(*args) def getDigits(*args): return _freeswitch.CoreSession_getDigits(*args)
def transfer(*args): return _freeswitch.CoreSession_transfer(*args) def transfer(*args): return _freeswitch.CoreSession_transfer(*args)
def playAndGetDigits(*args): return _freeswitch.CoreSession_playAndGetDigits(*args) def playAndGetDigits(*args): return _freeswitch.CoreSession_playAndGetDigits(*args)
def streamfile(*args): return _freeswitch.CoreSession_streamfile(*args) def streamfile(*args): return _freeswitch.CoreSession_streamfile(*args)
def ready(*args): return _freeswitch.CoreSession_ready(*args)
def execute(*args): return _freeswitch.CoreSession_execute(*args) def execute(*args): return _freeswitch.CoreSession_execute(*args)
def begin_allow_threads(*args): return _freeswitch.CoreSession_begin_allow_threads(*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) def end_allow_threads(*args): return _freeswitch.CoreSession_end_allow_threads(*args)
...@@ -85,33 +116,6 @@ CoreSession_swigregister = _freeswitch.CoreSession_swigregister ...@@ -85,33 +116,6 @@ CoreSession_swigregister = _freeswitch.CoreSession_swigregister
CoreSession_swigregister(CoreSession) CoreSession_swigregister(CoreSession)
PythonDTMFCallback = _freeswitch.PythonDTMFCallback PythonDTMFCallback = _freeswitch.PythonDTMFCallback
class input_callback_state(_object):
__swig_setmethods__ = {}
__setattr__ = lambda self, name, value: _swig_setattr(self, input_callback_state, name, value)
__swig_getmethods__ = {}
__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): class PySession(CoreSession):
__swig_setmethods__ = {} __swig_setmethods__ = {}
for _s in [CoreSession]: __swig_setmethods__.update(_s.__swig_setmethods__) for _s in [CoreSession]: __swig_setmethods__.update(_s.__swig_setmethods__)
...@@ -126,7 +130,7 @@ class PySession(CoreSession): ...@@ -126,7 +130,7 @@ class PySession(CoreSession):
except: self.this = this except: self.this = this
__swig_destroy__ = _freeswitch.delete_PySession __swig_destroy__ = _freeswitch.delete_PySession
__del__ = lambda self : None; __del__ = lambda self : None;
def streamfile(*args): return _freeswitch.PySession_streamfile(*args) def setDTMFCallback(*args): return _freeswitch.PySession_setDTMFCallback(*args)
def begin_allow_threads(*args): return _freeswitch.PySession_begin_allow_threads(*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) def end_allow_threads(*args): return _freeswitch.PySession_end_allow_threads(*args)
PySession_swigregister = _freeswitch.PySession_swigregister PySession_swigregister = _freeswitch.PySession_swigregister
......
...@@ -3,62 +3,53 @@ ...@@ -3,62 +3,53 @@
#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) #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)
int PySession::streamfile(char *file, PyObject *pyfunc, char *funcargs, int starting_sample_count) void PySession::setDTMFCallback(PyObject *pyfunc, char *funcargs)
{ {
switch_status_t status; sanity_check();
switch_input_args_t args = { 0 }, *ap = NULL;
struct input_callback_state cb_state = { 0 };
switch_file_handle_t fh = { 0 };
char *prebuf;
sanity_check(-1);
cb_state.funcargs = funcargs;
fh.samples = starting_sample_count;
if (!PyCallable_Check(pyfunc)) { if (!PyCallable_Check(pyfunc)) {
dtmfCallbackFunction = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "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;
} }
else {
cb_state.funcargs = funcargs;
cb_state.function = (void *) pyfunc;
if (dtmfCallbackFunction) {
cb_state.function = dtmfCallbackFunction;
cb_state.extra = &fh;
args.buf = &cb_state; args.buf = &cb_state;
args.buflen = sizeof(cb_state); // not sure what this is used for, copy mod_spidermonkey 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
// we cannot set the actual callback to a python function, because
// the callback is a function pointer with a specific signature.
// so, set it to the following c function which will act as a proxy,
// finding the python callback in the args callback args structure
args.input_callback = PythonDTMFCallback; // defined in mod_python.i
ap = &args; ap = &args;
}
if ((prebuf = switch_channel_get_variable(this->channel, "stream_prebuffer"))) {
int maybe = atoi(prebuf);
if (maybe > 0) {
fh.prebuf = maybe;
}
} }
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dtmf callback was set, pyfunc: %p. cb_state: %p\n", pyfunc, &cb_state);
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 PySession::begin_allow_threads(void) { void PySession::begin_allow_threads(void) {
threadState = PyEval_SaveThread(); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::begin_allow_threads() called\n");
threadState = (void *) PyEval_SaveThread();
cb_state.threadState = threadState;
// cb_state.extra = &fh;
args.buf = &cb_state;
ap = &args;
} }
void PySession::end_allow_threads(void) { void PySession::end_allow_threads(void) {
PyEval_RestoreThread(threadState); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::end_allow_threads() called\n");
PyEval_RestoreThread(((PyThreadState *)threadState));
} }
PySession::~PySession() { PySession::~PySession() {
// Should we do any cleanup here? // Should we do any cleanup here?
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::~PySession desctructor\n");
} }
...@@ -26,26 +26,17 @@ void console_clean_log(char *msg); ...@@ -26,26 +26,17 @@ void console_clean_log(char *msg);
char *api_execute(char *cmd, char *arg); char *api_execute(char *cmd, char *arg);
void api_reply_delete(char *reply); void api_reply_delete(char *reply);
struct input_callback_state {
PyObject *function;
PyThreadState *threadState;
void *extra;
char *funcargs;
};
class PySession : public CoreSession { class PySession : public CoreSession {
private: private:
PyObject *dtmfCallbackFunction; void *threadState;
PyThreadState *threadState;
public: public:
PySession(char *uuid) : CoreSession(uuid) {}; PySession(char *uuid) : CoreSession(uuid) {}
PySession(switch_core_session_t *session) : CoreSession(session) {}; PySession(switch_core_session_t *session) : CoreSession(session) {}
~PySession(); ~PySession();
int streamfile(char *file, PyObject *pyfunc, char *funcargs, int starting_sample_count); void setDTMFCallback(PyObject *pyfunc, char *funcargs);
void begin_allow_threads(); void begin_allow_threads();
void end_allow_threads(); void end_allow_threads();
protected:
}; };
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -56,87 +56,115 @@ SWITCH_MODULE_DEFINITION(mod_python, mod_python_load, mod_python_shutdown, NULL) ...@@ -56,87 +56,115 @@ SWITCH_MODULE_DEFINITION(mod_python, mod_python_load, mod_python_shutdown, NULL)
static void eval_some_python(char *uuid, char *args) static void eval_some_python(char *uuid, char *args)
{ {
PyThreadState *tstate = NULL; PyThreadState *tstate = NULL;
FILE *pythonfile = NULL;
char *dupargs = NULL; char *dupargs = NULL;
char *argv[128] = {0}; char *argv[128] = {0};
int argc; int argc;
int lead = 0; int lead = 0;
char *script = NULL, *script_path = NULL, *path = NULL; char *script = NULL;
PyObject *module = NULL;
PyObject *function = NULL;
PyObject *arg = NULL;
PyObject *result = NULL;
if (args) { if (args) {
dupargs = strdup(args); dupargs = strdup(args);
} else { } else {
return; return;
} }
assert(dupargs != NULL); assert(dupargs != NULL);
if (!(argc = switch_separate_string(dupargs, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { if (!(argc = switch_separate_string(dupargs, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No script name specified!\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No module name specified!\n");
goto done; goto done;
} }
script = argv[0]; script = argv[0];
lead = 1; lead = 1;
if (switch_is_file_path(script)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Invoking py module: %s\n", script);
script_path = script;
if ((script = strrchr(script_path, *SWITCH_PATH_SEPARATOR))) { tstate = PyThreadState_New(mainThreadState->interp);
script++; if (!tstate) {
} else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error acquiring tstate\n");
script = script_path; goto done;
} }
} else if ((path = switch_mprintf("%s%s%s", SWITCH_GLOBAL_dirs.script_dir, SWITCH_PATH_SEPARATOR, script))) {
script_path = path; // swap in thread state
PyEval_AcquireThread(tstate);
init_freeswitch();
// import the module
module = PyImport_ImportModule( (char *) script);
if (!module) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error importing module\n");
PyErr_Print();
PyErr_Clear();
goto done_swap_out;
}
// reload the module
module = PyImport_ReloadModule(module);
if (!module) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error reloading module\n");
PyErr_Print();
PyErr_Clear();
goto done_swap_out;
}
// get the handler function to be called
function = PyObject_GetAttrString(module, "handler");
if (!function) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Module does not define handler(uuid)\n");
PyErr_Print();
PyErr_Clear();
goto done_swap_out;
}
if (uuid) {
// build a tuple to pass the args, the uuid of session
arg = Py_BuildValue("(s)", uuid);
if (!arg) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error building args\n");
PyErr_Print();
PyErr_Clear();
goto done_swap_out;
}
} }
if (script_path) { else {
if (!switch_file_exists(script_path, NULL) == SWITCH_STATUS_SUCCESS) { arg = PyTuple_New(1);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Open File: %s\n", script_path); PyObject *nada = Py_BuildValue("");
goto done; PyTuple_SetItem(arg, 0, nada);
}
} }
// invoke the handler
result = PyEval_CallObjectWithKeywords(function, arg, (PyObject *)NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "running %s\n", script_path); // check the result and print out any errors
if (!result) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error calling python script\n");
if ((pythonfile = fopen(script_path, "r"))) { PyErr_Print();
PyErr_Clear();
PyEval_AcquireLock();
tstate = PyThreadState_New(mainThreadState->interp);
if (!tstate) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error acquiring tstate\n");
goto done;
}
PyThreadState_Swap(tstate);
init_freeswitch();
PyRun_SimpleString("from freeswitch import *");
if (uuid) {
char code[128];
snprintf(code, sizeof(code), "session = PySession(\"%s\");", uuid);
PyRun_SimpleString(code);
}
PySys_SetArgv(argc - lead, &argv[lead]);
PyRun_SimpleFile(pythonfile, script);
PyThreadState_Swap(NULL);
PyThreadState_Clear(tstate);
PyThreadState_Delete(tstate);
PyEval_ReleaseLock();
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error running %s\n", script_path);
} }
goto done_swap_out;
done: done:
switch_safe_free(dupargs);
if (pythonfile) { done_swap_out:
fclose(pythonfile); // decrement ref counts
} Py_XDECREF(module);
Py_XDECREF(function);
Py_XDECREF(arg);
Py_XDECREF(result);
// swap out thread state
PyEval_ReleaseThread(tstate);
switch_safe_free(dupargs); switch_safe_free(dupargs);
switch_safe_free(path);
} }
static void python_function(switch_core_session_t *session, char *data) static void python_function(switch_core_session_t *session, char *data)
...@@ -229,14 +257,25 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_python_load) ...@@ -229,14 +257,25 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_python_load)
*module_interface = &python_module_interface; *module_interface = &python_module_interface;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Python Framework Loading...\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Python Framework Loading...\n");
Py_Initialize(); if (!Py_IsInitialized()) {
PyEval_InitThreads();
mainThreadState = PyThreadState_Get(); // initialize python system
Py_Initialize();
PyThreadState_Swap(NULL); // create GIL and a threadstate
PyEval_InitThreads();
PyEval_ReleaseLock(); // save threadstate since it's interp field will be needed
// to create new threadstates, and will be needed for shutdown
mainThreadState = PyThreadState_Get();
// swap out threadstate since the call threads will create
// their own and swap in their threadstate
PyThreadState_Swap(NULL);
// release GIL
PyEval_ReleaseLock();
}
/* indicate that the module should continue to be loaded */ /* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
......
...@@ -30,6 +30,8 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session, ...@@ -30,6 +30,8 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session,
switch_file_handle_t *fh = NULL; switch_file_handle_t *fh = NULL;
PyThreadState *threadState = NULL; PyThreadState *threadState = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "PythonDTMFCallback\n");
if (!buf) { if (!buf) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buf pointer is null"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buf pointer is null");
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
...@@ -39,11 +41,14 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session, ...@@ -39,11 +41,14 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session,
func = (PyObject *) cb_state->function; func = (PyObject *) cb_state->function;
if (!func) { if (!func) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cb_state->function is null"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cb_state->function is null\n");
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "cb_state->function is NOT null\n");
}
if (!PyCallable_Check(func)) { if (!PyCallable_Check(func)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "function not callable"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "function not callable\n");
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
...@@ -57,14 +62,22 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session, ...@@ -57,14 +62,22 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session,
threadState = (PyThreadState *) cb_state->threadState; threadState = (PyThreadState *) cb_state->threadState;
if (!threadState) { if (!threadState) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error, invalid threadstate"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error, invalid threadstate\n");
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "restoring threadstate: %p\n", threadState);
}
PyEval_RestoreThread(threadState); // nasty stuff happens when py interp has no thread state PyEval_RestoreThread(threadState); // nasty stuff happens when py interp has no thread state
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "restored threadstate, calling python function: %p\n", func);
result = PyEval_CallObject(func, arglist); result = PyEval_CallObject(func, arglist);
threadState = PyEval_SaveThread(); threadState = PyEval_SaveThread();
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "called python function\n");
Py_DECREF(arglist); // Trash arglist Py_DECREF(arglist); // Trash arglist
if (result && result != Py_None) { if (result && result != Py_None) {
...@@ -88,6 +101,9 @@ switch_status_t process_callback_result(char *ret, ...@@ -88,6 +101,9 @@ switch_status_t process_callback_result(char *ret,
switch_file_handle_t *fh = NULL; switch_file_handle_t *fh = NULL;
fh = (switch_file_handle_t *) cb_state->extra; fh = (switch_file_handle_t *) cb_state->extra;
if (!fh) {
return SWITCH_STATUS_FALSE;
}
if (!ret) { if (!ret) {
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -28,6 +28,7 @@ CoreSession::CoreSession(switch_core_session_t *new_session) ...@@ -28,6 +28,7 @@ CoreSession::CoreSession(switch_core_session_t *new_session)
CoreSession::~CoreSession() CoreSession::~CoreSession()
{ {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::~CoreSession desctructor");
if (session) { if (session) {
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
...@@ -57,6 +58,7 @@ int CoreSession::preAnswer() ...@@ -57,6 +58,7 @@ int CoreSession::preAnswer()
void CoreSession::hangup(char *cause) void CoreSession::hangup(char *cause)
{ {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::hangup\n");
sanity_check_noreturn; sanity_check_noreturn;
switch_channel_hangup(channel, switch_channel_str2cause(cause)); switch_channel_hangup(channel, switch_channel_str2cause(cause));
} }
...@@ -88,20 +90,25 @@ void CoreSession::execute(char *app, char *data) ...@@ -88,20 +90,25 @@ void CoreSession::execute(char *app, char *data)
int CoreSession::playFile(char *file, char *timer_name) int CoreSession::playFile(char *file, char *timer_name)
{ {
switch_status_t status; switch_status_t status;
switch_file_handle_t fh = { 0 };
sanity_check(-1); sanity_check(-1);
if (switch_strlen_zero(timer_name)) { if (switch_strlen_zero(timer_name)) {
timer_name = NULL; timer_name = NULL;
} }
store_file_handle(&fh);
begin_allow_threads(); begin_allow_threads();
status = switch_ivr_play_file(session, NULL, file, ap); status = switch_ivr_play_file(session, &fh, file, ap);
end_allow_threads(); end_allow_threads();
return status == SWITCH_STATUS_SUCCESS ? 1 : 0; return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
} }
void CoreSession::setDTMFCallback(switch_input_callback_function_t cb, void *buf, uint32_t buflen) void CoreSession::setDTMFCallback(switch_input_callback_function_t cb,
void *buf,
uint32_t buflen)
{ {
sanity_check_noreturn; sanity_check_noreturn;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::setDTMFCallback.");
if (cb) { if (cb) {
args.buf = buf; args.buf = buf;
args.buflen = buflen; args.buflen = buflen;
...@@ -113,12 +120,23 @@ void CoreSession::setDTMFCallback(switch_input_callback_function_t cb, void *buf ...@@ -113,12 +120,23 @@ void CoreSession::setDTMFCallback(switch_input_callback_function_t cb, void *buf
} }
} }
int CoreSession::speakText(char *text)
int CoreSession::speak(char *text)
{ {
switch_status_t status; switch_status_t status;
switch_codec_t *codec; switch_codec_t *codec;
sanity_check(-1); sanity_check(-1);
if (!tts_name) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No TTS engine specified");
return SWITCH_STATUS_FALSE;
}
if (!voice_name) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No TTS voice specified");
return SWITCH_STATUS_FALSE;
}
codec = switch_core_session_get_read_codec(session); codec = switch_core_session_get_read_codec(session);
begin_allow_threads(); begin_allow_threads();
status = switch_ivr_speak_text(session, tts_name, voice_name, codec->implementation->samples_per_second, text, ap); status = switch_ivr_speak_text(session, tts_name, voice_name, codec->implementation->samples_per_second, text, ap);
...@@ -135,12 +153,22 @@ void CoreSession::set_tts_parms(char *tts_name_p, char *voice_name_p) ...@@ -135,12 +153,22 @@ void CoreSession::set_tts_parms(char *tts_name_p, char *voice_name_p)
voice_name = strdup(voice_name_p); voice_name = strdup(voice_name_p);
} }
int CoreSession::getDigits(char *dtmf_buf, int len, char *terminators, char *terminator, int timeout) int CoreSession::getDigits(char *dtmf_buf,
int len,
char *terminators,
char *terminator,
int timeout)
{ {
switch_status_t status; switch_status_t status;
sanity_check(-1); sanity_check(-1);
begin_allow_threads(); begin_allow_threads();
status = switch_ivr_collect_digits_count(session, dtmf_buf,(uint32_t) len,(uint32_t) len, terminators, terminator, (uint32_t) timeout); status = switch_ivr_collect_digits_count(session,
dtmf_buf,
(uint32_t) len,
(uint32_t) len,
terminators,
terminator,
(uint32_t) timeout);
end_allow_threads(); end_allow_threads();
return status == SWITCH_STATUS_SUCCESS ? 1 : 0; return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
} }
...@@ -153,8 +181,15 @@ int CoreSession::transfer(char *extension, char *dialplan, char *context) ...@@ -153,8 +181,15 @@ int CoreSession::transfer(char *extension, char *dialplan, char *context)
return status == SWITCH_STATUS_SUCCESS ? 1 : 0; 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,
char *audio_files, char *bad_input_audio_files, char *dtmf_buf, char *digits_regex) 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; switch_status_t status;
sanity_check(-1); sanity_check(-1);
...@@ -173,16 +208,72 @@ int CoreSession::playAndGetDigits(int min_digits, int max_digits, int max_tries, ...@@ -173,16 +208,72 @@ int CoreSession::playAndGetDigits(int min_digits, int max_digits, int max_tries,
return status == SWITCH_STATUS_SUCCESS ? 1 : 0; return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
} }
int CoreSession::streamfile(char *file, void *cb_func, char *funcargs, int starting_sample_count) { int CoreSession::streamfile(char *file, int starting_sample_count) {
return 0;
switch_status_t status;
switch_file_handle_t fh = { 0 };
unsigned int samps;
unsigned int pos = 0;
char *prebuf;
sanity_check(-1);
fh.samples = starting_sample_count;
store_file_handle(&fh);
begin_allow_threads();
status = switch_ivr_play_file(session, &fh, file, ap);
end_allow_threads();
if ((prebuf = switch_channel_get_variable(this->channel, "stream_prebuffer"))) {
int maybe = atoi(prebuf);
if (maybe > 0) {
fh.prebuf = maybe;
}
}
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
}
bool CoreSession::ready() {
switch_channel_t *channel;
if (!session) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "You must call the session.originate method before calling this method!\n");
return false;
}
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
return switch_channel_ready(channel) != 0;
} }
void CoreSession::begin_allow_threads() { void CoreSession::begin_allow_threads() {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::begin_allow_threads() called and does nothing\n");
} }
void CoreSession::end_allow_threads() { void CoreSession::end_allow_threads() {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::end_allow_threads() called and does nothing\n");
} }
/** \brief Store a file handle in the callback args
*
* In a few of the methods like playFile and streamfile,
* an empty switch_file_handle_t is created and passed
* to core, and stored in callback args so that the callback
* handler can retrieve it for pausing, ff, rewinding file ptr.
*
* \param fh - a switch_file_handle_t
*/
void CoreSession::store_file_handle(switch_file_handle_t *fh) {
cb_state.extra = fh; // set a file handle so callback handler can pause
args.buf = &cb_state;
ap = &args;
}
/* For Emacs: /* For Emacs:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论