implement flushEvents() flushDigits() setAutoHangup() and setHangupHook(). reworked dtmfhandler and some aspects relating to threadstate. folded in memory pool thing from mishehu. added more asserts to switch_core_file (coordinated w/ anthony on this)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5442 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
34d6c49870
commit
6f78befac9
|
@ -11,6 +11,50 @@ extern "C" {
|
|||
|
||||
#include <switch.h>
|
||||
|
||||
//
|
||||
// C++ Interface: switch_to_cpp_mempool
|
||||
//
|
||||
// Description: This class allows for overloading the new operator to allocate from a switch_memory_pool_t
|
||||
//
|
||||
// Author: Yossi Neiman <freeswitch@cartissolutions.com>, (C) 2007
|
||||
//
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
|
||||
|
||||
#ifndef SWITCHTOMEMPOOL
|
||||
#define SWITCHTOMEMPOOL
|
||||
class SwitchToMempool {
|
||||
public:
|
||||
SwitchToMempool() { }
|
||||
SwitchToMempool(switch_memory_pool_t *mem) { memorypool = mem; }
|
||||
void *operator new(switch_size_t num_bytes, switch_memory_pool_t *mem)
|
||||
{
|
||||
void *ptr = switch_core_alloc(mem, (switch_size_t) num_bytes);
|
||||
return ptr;
|
||||
}
|
||||
protected:
|
||||
switch_memory_pool_t *memorypool;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Overview: once you create an object that inherits this class, since
|
||||
the memory pool is then a class data member, you can continue to
|
||||
allocate objects from the memory pool.
|
||||
objects from within the class
|
||||
|
||||
Notes on usage:
|
||||
|
||||
1. The derived class will need to also overload the ctor so that it accepts a memory pool object as a parameter.
|
||||
2. Instantiation of a class would then look something like this: Foo *bar = new(memory_pool) Foo(memory_pool);
|
||||
|
||||
Note that the first parameter to the new operator is implicitly handled by c++... not sure I like that but it's how it is...
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void console_log(char *level_str, char *msg);
|
||||
void console_clean_log(char *msg);
|
||||
|
@ -40,6 +84,12 @@ typedef struct input_callback_state {
|
|||
char *funcargs; // extra string that will be passed to callback function
|
||||
} input_callback_state_t;
|
||||
|
||||
typedef enum {
|
||||
S_HUP = (1 << 0),
|
||||
S_FREE = (1 << 1),
|
||||
S_RDLOCK = (1 << 2)
|
||||
} session_flag_t;
|
||||
|
||||
|
||||
class CoreSession {
|
||||
protected:
|
||||
|
@ -52,6 +102,9 @@ class CoreSession {
|
|||
char *tts_name;
|
||||
char *voice_name;
|
||||
void store_file_handle(switch_file_handle_t *fh);
|
||||
void *on_hangup; // language specific callback function, cast as void *
|
||||
|
||||
|
||||
public:
|
||||
CoreSession();
|
||||
CoreSession(char *uuid);
|
||||
|
@ -59,12 +112,14 @@ class CoreSession {
|
|||
virtual ~CoreSession();
|
||||
switch_core_session_t *session;
|
||||
switch_channel_t *channel;
|
||||
unsigned int flags;
|
||||
input_callback_state cb_state; // callback state, always pointed to by the buf
|
||||
// field in this->args
|
||||
switch_channel_state_t hook_state; // store hookstate for on_hangup callback
|
||||
|
||||
int answer();
|
||||
int preAnswer();
|
||||
void hangup(char *cause);
|
||||
virtual void hangup(char *cause);
|
||||
void setVariable(char *var, char *val);
|
||||
char *getVariable(char *var);
|
||||
|
||||
|
@ -118,19 +173,16 @@ class CoreSession {
|
|||
* 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);
|
||||
void setDTMFCallback(void *cbfunc, char *funcargs);
|
||||
|
||||
|
||||
int speak(char *text);
|
||||
void set_tts_parms(char *tts_name, char *voice_name);
|
||||
|
||||
int getDigits(char *dtmf_buf,
|
||||
int len,
|
||||
int buflen,
|
||||
int maxdigits,
|
||||
char *terminators,
|
||||
char *terminator,
|
||||
int timeout);
|
||||
|
@ -165,11 +217,26 @@ class CoreSession {
|
|||
*/
|
||||
int streamfile(char *file, int starting_sample_count);
|
||||
|
||||
/** \brief flush any pending events
|
||||
*/
|
||||
int flushEvents();
|
||||
|
||||
/** \brief flush any pending digits
|
||||
*/
|
||||
int flushDigits();
|
||||
|
||||
int setAutoHangup(bool val);
|
||||
|
||||
/** \brief Set the hangup callback function
|
||||
* \param hangup_func - language specific function ptr cast into void *
|
||||
*/
|
||||
void setHangupHook(void *hangup_func);
|
||||
|
||||
bool ready();
|
||||
|
||||
void execute(char *app, char *data);
|
||||
virtual void begin_allow_threads();
|
||||
virtual void end_allow_threads();
|
||||
virtual bool begin_allow_threads() = 0;
|
||||
virtual bool end_allow_threads() = 0;
|
||||
|
||||
/** \brief Get the uuid of this session
|
||||
* \return the uuid of this session
|
||||
|
@ -181,6 +248,12 @@ class CoreSession {
|
|||
*/
|
||||
const switch_input_args_t& get_cb_args() const { return args; };
|
||||
|
||||
/** \brief Callback to the language specific hangup callback
|
||||
*/
|
||||
virtual void check_hangup_hook() = 0;
|
||||
|
||||
virtual switch_status_t run_dtmf_callback(void *input,
|
||||
switch_input_type_t itype) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -200,6 +273,19 @@ void api_reply_delete(char *reply);
|
|||
void bridge(CoreSession &session_a, CoreSession &session_b);
|
||||
|
||||
|
||||
/** \brief the actual hangup hook called back by freeswitch core
|
||||
* which in turn gets the session and calls the appropriate
|
||||
* instance method to complete the callback.
|
||||
*/
|
||||
switch_status_t hanguphook(switch_core_session_t *session);
|
||||
|
||||
switch_status_t dtmf_callback(switch_core_session_t *session,
|
||||
void *input,
|
||||
switch_input_type_t itype,
|
||||
void *buf,
|
||||
unsigned int buflen);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -80,16 +80,16 @@ class input_callback_state_t(_object):
|
|||
input_callback_state_t_swigregister = _freeswitch.input_callback_state_t_swigregister
|
||||
input_callback_state_t_swigregister(input_callback_state_t)
|
||||
|
||||
S_HUP = _freeswitch.S_HUP
|
||||
S_FREE = _freeswitch.S_FREE
|
||||
S_RDLOCK = _freeswitch.S_RDLOCK
|
||||
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)
|
||||
def __init__(self): raise AttributeError, "No constructor defined"
|
||||
__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
|
||||
|
@ -98,9 +98,15 @@ class CoreSession(_object):
|
|||
__swig_setmethods__["channel"] = _freeswitch.CoreSession_channel_set
|
||||
__swig_getmethods__["channel"] = _freeswitch.CoreSession_channel_get
|
||||
if _newclass:channel = _swig_property(_freeswitch.CoreSession_channel_get, _freeswitch.CoreSession_channel_set)
|
||||
__swig_setmethods__["flags"] = _freeswitch.CoreSession_flags_set
|
||||
__swig_getmethods__["flags"] = _freeswitch.CoreSession_flags_get
|
||||
if _newclass:flags = _swig_property(_freeswitch.CoreSession_flags_get, _freeswitch.CoreSession_flags_set)
|
||||
__swig_setmethods__["cb_state"] = _freeswitch.CoreSession_cb_state_set
|
||||
__swig_getmethods__["cb_state"] = _freeswitch.CoreSession_cb_state_get
|
||||
if _newclass:cb_state = _swig_property(_freeswitch.CoreSession_cb_state_get, _freeswitch.CoreSession_cb_state_set)
|
||||
__swig_setmethods__["hook_state"] = _freeswitch.CoreSession_hook_state_set
|
||||
__swig_getmethods__["hook_state"] = _freeswitch.CoreSession_hook_state_get
|
||||
if _newclass:hook_state = _swig_property(_freeswitch.CoreSession_hook_state_get, _freeswitch.CoreSession_hook_state_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)
|
||||
|
@ -117,17 +123,26 @@ class CoreSession(_object):
|
|||
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 flushEvents(*args): return _freeswitch.CoreSession_flushEvents(*args)
|
||||
def flushDigits(*args): return _freeswitch.CoreSession_flushDigits(*args)
|
||||
def setAutoHangup(*args): return _freeswitch.CoreSession_setAutoHangup(*args)
|
||||
def setHangupHook(*args): return _freeswitch.CoreSession_setHangupHook(*args)
|
||||
def ready(*args): return _freeswitch.CoreSession_ready(*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)
|
||||
def get_uuid(*args): return _freeswitch.CoreSession_get_uuid(*args)
|
||||
def get_cb_args(*args): return _freeswitch.CoreSession_get_cb_args(*args)
|
||||
def check_hangup_hook(*args): return _freeswitch.CoreSession_check_hangup_hook(*args)
|
||||
def run_dtmf_callback(*args): return _freeswitch.CoreSession_run_dtmf_callback(*args)
|
||||
CoreSession_swigregister = _freeswitch.CoreSession_swigregister
|
||||
CoreSession_swigregister(CoreSession)
|
||||
|
||||
bridge = _freeswitch.bridge
|
||||
PythonDTMFCallback = _freeswitch.PythonDTMFCallback
|
||||
hanguphook = _freeswitch.hanguphook
|
||||
dtmf_callback = _freeswitch.dtmf_callback
|
||||
S_SWAPPED_IN = _freeswitch.S_SWAPPED_IN
|
||||
S_SWAPPED_OUT = _freeswitch.S_SWAPPED_OUT
|
||||
class PySession(CoreSession):
|
||||
__swig_setmethods__ = {}
|
||||
for _s in [CoreSession]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))
|
||||
|
@ -143,8 +158,12 @@ class PySession(CoreSession):
|
|||
__swig_destroy__ = _freeswitch.delete_PySession
|
||||
__del__ = lambda self : None;
|
||||
def setDTMFCallback(*args): return _freeswitch.PySession_setDTMFCallback(*args)
|
||||
def setHangupHook(*args): return _freeswitch.PySession_setHangupHook(*args)
|
||||
def check_hangup_hook(*args): return _freeswitch.PySession_check_hangup_hook(*args)
|
||||
def hangup(*args): return _freeswitch.PySession_hangup(*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 run_dtmf_callback(*args): return _freeswitch.PySession_run_dtmf_callback(*args)
|
||||
PySession_swigregister = _freeswitch.PySession_swigregister
|
||||
PySession_swigregister(PySession)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "freeswitch_python.h"
|
||||
|
||||
#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 init_vars() do { caller_profile.source = "mod_python"; } while(0)
|
||||
#define init_vars() do { caller_profile.source = "mod_python"; swapstate = S_SWAPPED_IN; } while(0)
|
||||
|
||||
PySession::PySession() : CoreSession()
|
||||
{
|
||||
|
@ -24,80 +24,107 @@ void PySession::setDTMFCallback(PyObject *pyfunc, char *funcargs)
|
|||
sanity_check();
|
||||
|
||||
if (!PyCallable_Check(pyfunc)) {
|
||||
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.\n");
|
||||
return;
|
||||
}
|
||||
else {
|
||||
cb_state.funcargs = funcargs;
|
||||
cb_state.function = (void *) pyfunc;
|
||||
Py_XINCREF(pyfunc);
|
||||
CoreSession::setDTMFCallback((void *) pyfunc, funcargs);
|
||||
|
||||
args.buf = &cb_state;
|
||||
args.buflen = sizeof(cb_state); // not sure what this is used for, copy mod_spidermonkey
|
||||
|
||||
// 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;
|
||||
|
||||
}
|
||||
|
||||
void PySession::setHangupHook(PyObject *pyfunc) {
|
||||
|
||||
if (!PyCallable_Check(pyfunc)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hangup hook is not a python function.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dtmf callback was set, pyfunc: %p. cb_state: %p\n", pyfunc, &cb_state);
|
||||
// without this Py_XINCREF, there will be segfaults. basically the python
|
||||
// interpreter will not know that it should not GC this object.
|
||||
// callback example: http://docs.python.org/ext/callingPython.html
|
||||
Py_XINCREF(pyfunc);
|
||||
CoreSession::setHangupHook((void *) pyfunc);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PySession::begin_allow_threads(void) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::begin_allow_threads() called\n");
|
||||
|
||||
// swap out threadstate and store in instance variable
|
||||
threadState = (void *) PyEval_SaveThread();
|
||||
cb_state.threadState = threadState;
|
||||
args.buf = &cb_state;
|
||||
ap = &args;
|
||||
}
|
||||
|
||||
void PySession::end_allow_threads(void) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::end_allow_threads() called\n");
|
||||
// swap in threadstate from instance variable saved earlier
|
||||
PyEval_RestoreThread(((PyThreadState *)threadState));
|
||||
}
|
||||
|
||||
PySession::~PySession() {
|
||||
// Should we do any cleanup here?
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::~PySession desctructor\n");
|
||||
}
|
||||
|
||||
|
||||
/* ----- functions not bound to PySession instance ------ */
|
||||
|
||||
|
||||
switch_status_t PythonDTMFCallback(switch_core_session_t *session,
|
||||
void *input,
|
||||
switch_input_type_t itype,
|
||||
void *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
PyObject *func, *arglist;
|
||||
void PySession::check_hangup_hook() {
|
||||
PyObject *func;
|
||||
PyObject *result;
|
||||
char *resultStr;
|
||||
char *funcargs;
|
||||
input_callback_state_t *cb_state;
|
||||
switch_file_handle_t *fh = NULL;
|
||||
PyThreadState *threadState = NULL;
|
||||
bool did_swap_in = false;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "check_hangup_hook called\n");
|
||||
|
||||
if (!session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No valid session\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// The did_swap_in boolean was added to fix the following problem:
|
||||
// Design flaw - we swap in threadstate based on the assumption that thread state
|
||||
// is currently _swapped out_ when this hangup hook is called. However, nothing known to
|
||||
// guarantee that, and if thread state is already swapped in when this is invoked,
|
||||
// bad things will happen.
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "check hangup hook end_allow_threads\n");
|
||||
did_swap_in = end_allow_threads();
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PythonDTMFCallback\n");
|
||||
if (on_hangup == NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "on_hangup is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!buf) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buf pointer is null");
|
||||
func = (PyObject *) on_hangup;
|
||||
|
||||
// TODO: to match js implementation, should pass the _python_ PySession
|
||||
// object instance wrapping this C++ PySession instance. but how do we do that?
|
||||
// for now, pass the uuid since its better than nothing
|
||||
PyObject* func_arg = Py_BuildValue("(s)", uuid);
|
||||
|
||||
result = PyEval_CallObject(func, func_arg);
|
||||
Py_XDECREF(func_arg);
|
||||
|
||||
if (result) {
|
||||
resultStr = (char *) PyString_AsString(result);
|
||||
// currently just ignore the result
|
||||
}
|
||||
else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to call python hangup callback\n");
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "check hangup hook begin_allow_threads\n");
|
||||
if (did_swap_in) {
|
||||
begin_allow_threads();
|
||||
}
|
||||
|
||||
Py_XDECREF(result);
|
||||
|
||||
}
|
||||
|
||||
switch_status_t PySession::run_dtmf_callback(void *input,
|
||||
switch_input_type_t itype) {
|
||||
|
||||
PyObject *func, *arglist;
|
||||
PyObject *pyresult;
|
||||
char *resultStr;
|
||||
char *funcargs;
|
||||
switch_file_handle_t *fh = NULL;
|
||||
bool did_swap_in = false;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "run_dtmf_callback\n");
|
||||
|
||||
|
||||
if (!cb_state.function) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "cb_state->function is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
cb_state = (input_callback_state *) buf;
|
||||
}
|
||||
|
||||
func = (PyObject *) cb_state->function;
|
||||
func = (PyObject *) cb_state.function;
|
||||
if (!func) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cb_state->function is null\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "cb_state->function is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
else {
|
||||
|
@ -108,7 +135,7 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session,
|
|||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
funcargs = (char *) cb_state->funcargs;
|
||||
funcargs = (char *) cb_state.funcargs;
|
||||
|
||||
arglist = Py_BuildValue("(sis)", input, itype, funcargs);
|
||||
if (!arglist) {
|
||||
|
@ -116,36 +143,127 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session,
|
|||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
threadState = (PyThreadState *) cb_state->threadState;
|
||||
if (!threadState) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error, invalid threadstate\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "restoring threadstate: %p\n", threadState);
|
||||
}
|
||||
|
||||
PyEval_RestoreThread(threadState); // nasty stuff happens when py interp has no thread state
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "restored threadstate, calling python function: %p\n", func);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "run_dtmf_callback end_allow_threads\n");
|
||||
did_swap_in = end_allow_threads();
|
||||
|
||||
result = PyEval_CallObject(func, arglist);
|
||||
pyresult = PyEval_CallObject(func, arglist);
|
||||
|
||||
threadState = PyEval_SaveThread();
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "called python function\n");
|
||||
|
||||
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);
|
||||
Py_XDECREF(arglist); // Trash arglist
|
||||
if (pyresult && pyresult != Py_None) {
|
||||
resultStr = (char *) PyString_AsString(pyresult);
|
||||
switch_status_t cbresult = process_callback_result(resultStr, &cb_state, session);
|
||||
return cbresult;
|
||||
}
|
||||
else {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error calling python callback\n");
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "run_dtmf_callback begin_allow_threads\n");
|
||||
if (did_swap_in) {
|
||||
begin_allow_threads();
|
||||
}
|
||||
|
||||
Py_XDECREF(pyresult);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
bool PySession::begin_allow_threads(void) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::begin_allow_threads() called\n");
|
||||
|
||||
// swap out threadstate and store in instance variable
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
PyThreadState *swapin_tstate = (PyThreadState *) switch_channel_get_private(channel, "SwapInThreadState");
|
||||
// so lets assume the thread state was swapped in when the python script was started,
|
||||
// therefore swapin_tstate will be NULL (because there is nothing to swap in, since its
|
||||
// _already_ swapped in.)
|
||||
if (swapin_tstate == NULL) {
|
||||
// currently swapped in
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Threadstate swap-out!\n");
|
||||
swapin_tstate = PyEval_SaveThread();
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "swapin_tstate: %p\n", swapin_tstate);
|
||||
// give future swapper-inners something to actually swap in
|
||||
switch_channel_set_private(channel, "SwapInThreadState", (void *) swapin_tstate);
|
||||
cb_state.threadState = threadState; // TODO: get rid of this
|
||||
args.buf = &cb_state;
|
||||
ap = &args;
|
||||
return true;
|
||||
|
||||
}
|
||||
else {
|
||||
// currently swapped out
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Threadstate already swapd-out! Skipping\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool PySession::end_allow_threads(void) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::end_allow_threads() called\n");
|
||||
// swap in threadstate from instance variable saved earlier
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
PyThreadState *swapin_tstate = (PyThreadState *) switch_channel_get_private(channel, "SwapInThreadState");
|
||||
if (swapin_tstate == NULL) {
|
||||
// currently swapped in
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Threadstate double swap-in! Skipping\n");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// currently swapped out
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Threadstate swap-in!\n");
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "swapin_tstate: %p\n", swapin_tstate);
|
||||
PyEval_RestoreThread(swapin_tstate);
|
||||
// dont give any swapper-inners the opportunity to do a double swap
|
||||
switch_channel_set_private(channel, "SwapInThreadState", NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PySession::hangup(char *cause) {
|
||||
|
||||
|
||||
// since we INCREF'd this function pointer earlier (so the py gc didnt reclaim it)
|
||||
// we have to DECREF it, or else the PySession dtor will never get called and
|
||||
// a zombie channel will be left over using up resources
|
||||
|
||||
if (cb_state.function != NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "xdecref on cb_state_function\n");
|
||||
PyObject * func = (PyObject *) cb_state.function;
|
||||
Py_XDECREF(func);
|
||||
}
|
||||
else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cb_state.function is null\n");
|
||||
}
|
||||
|
||||
|
||||
CoreSession::hangup(cause);
|
||||
|
||||
}
|
||||
|
||||
|
||||
PySession::~PySession() {
|
||||
// Should we do any cleanup here?
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::~PySession started\n");
|
||||
|
||||
if (on_hangup) {
|
||||
PyObject * func = (PyObject *) on_hangup;
|
||||
Py_XDECREF(func);
|
||||
}
|
||||
|
||||
|
||||
if (cb_state.function != NULL) {
|
||||
PyObject * func = (PyObject *) cb_state.function;
|
||||
Py_XDECREF(func);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "PySession::~PySession finished\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,3 +272,6 @@ switch_status_t PythonDTMFCallback(switch_core_session_t *session,
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,12 +14,10 @@ extern "C" {
|
|||
|
||||
|
||||
|
||||
switch_status_t PythonDTMFCallback(switch_core_session *session,
|
||||
void *input,
|
||||
switch_input_type_t itype,
|
||||
void *buf,
|
||||
unsigned int buflen);
|
||||
|
||||
typedef enum {
|
||||
S_SWAPPED_IN = (1 << 0),
|
||||
S_SWAPPED_OUT = (1 << 1)
|
||||
} swap_state_t;
|
||||
|
||||
void console_log(char *level_str, char *msg);
|
||||
void console_clean_log(char *msg);
|
||||
|
@ -29,14 +27,21 @@ void api_reply_delete(char *reply);
|
|||
class PySession : public CoreSession {
|
||||
private:
|
||||
void *threadState;
|
||||
int swapstate;
|
||||
public:
|
||||
PySession();
|
||||
PySession(char *uuid);
|
||||
PySession(switch_core_session_t *session);
|
||||
~PySession();
|
||||
void setDTMFCallback(PyObject *pyfunc, char *funcargs);
|
||||
void begin_allow_threads();
|
||||
void end_allow_threads();
|
||||
void setHangupHook(PyObject *pyfunc);
|
||||
void check_hangup_hook();
|
||||
void hangup(char *cause);
|
||||
bool begin_allow_threads();
|
||||
bool end_allow_threads();
|
||||
|
||||
switch_status_t run_dtmf_callback(void *input,
|
||||
switch_input_type_t itype);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -49,11 +49,12 @@ PyThreadState *mainThreadState = NULL;
|
|||
void init_freeswitch(void);
|
||||
static switch_api_interface_t python_run_interface;
|
||||
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_python_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_python_shutdown);
|
||||
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, switch_core_session_t *session)
|
||||
{
|
||||
PyThreadState *tstate = NULL;
|
||||
char *dupargs = NULL;
|
||||
|
@ -92,6 +93,11 @@ static void eval_some_python(char *uuid, char *args)
|
|||
|
||||
// swap in thread state
|
||||
PyEval_AcquireThread(tstate);
|
||||
if (session) {
|
||||
// record the fact that thread state is swapped in
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_channel_set_private(channel, "SwapInThreadState", NULL);
|
||||
}
|
||||
init_freeswitch();
|
||||
|
||||
// import the module
|
||||
|
@ -138,7 +144,9 @@ static void eval_some_python(char *uuid, char *args)
|
|||
}
|
||||
|
||||
// invoke the handler
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call python script \n");
|
||||
result = PyEval_CallObjectWithKeywords(function, arg, (PyObject *)NULL);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Finished calling python script \n");
|
||||
|
||||
// check the result and print out any errors
|
||||
if (!result) {
|
||||
|
@ -160,7 +168,29 @@ static void eval_some_python(char *uuid, char *args)
|
|||
Py_XDECREF(result);
|
||||
|
||||
// swap out thread state
|
||||
PyEval_ReleaseThread(tstate);
|
||||
if (session) {
|
||||
// record the fact that thread state is swapped in
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
PyThreadState *swapin_tstate = (PyThreadState *) switch_channel_get_private(channel, "SwapInThreadState");
|
||||
// so lets assume nothing in the python script swapped any thread state in
|
||||
// or out .. thread state will currently be swapped in, and the SwapInThreadState
|
||||
// will be null
|
||||
if (swapin_tstate == NULL) {
|
||||
// swap it out
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Threadstate mod_python.c swap-out! \n");
|
||||
// PyEval_ReleaseThread(cur_tstate);
|
||||
swapin_tstate = (void *) PyEval_SaveThread();
|
||||
switch_channel_set_private(channel, "SwapInThreadState", (void *) swapin_tstate);
|
||||
}
|
||||
else {
|
||||
// thread state is already swapped out, so, nothing for us to do
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "according to chan priv data, already swapped out \n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Threadstate mod_python.c swap-out! \n");
|
||||
PyEval_ReleaseThread(tstate);
|
||||
}
|
||||
|
||||
switch_safe_free(dupargs);
|
||||
|
||||
|
@ -169,7 +199,7 @@ static void eval_some_python(char *uuid, char *args)
|
|||
|
||||
static void python_function(switch_core_session_t *session, char *data)
|
||||
{
|
||||
eval_some_python(switch_core_session_get_uuid(session), (char *)data);
|
||||
eval_some_python(switch_core_session_get_uuid(session), (char *)data, session);
|
||||
|
||||
}
|
||||
|
||||
|
@ -183,7 +213,7 @@ static void *SWITCH_THREAD_FUNC py_thread_run(switch_thread_t *thread, void *obj
|
|||
switch_memory_pool_t *pool;
|
||||
struct switch_py_thread *pt = (struct switch_py_thread *) obj;
|
||||
|
||||
eval_some_python(NULL, strdup(pt->args));
|
||||
eval_some_python(NULL, strdup(pt->args), NULL);
|
||||
|
||||
pool = pt->pool;
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
|
|
|
@ -9,12 +9,16 @@
|
|||
%cstring_bounded_mutable(char *dtmf_buf, 128);
|
||||
%cstring_bounded_mutable(char *terminator, 8);
|
||||
|
||||
|
||||
/** insert the following includes into generated code so it compiles */
|
||||
%{
|
||||
#include "switch_cpp.h"
|
||||
#include "freeswitch_python.h"
|
||||
%}
|
||||
|
||||
|
||||
%ignore SwitchToMempool;
|
||||
|
||||
/**
|
||||
* tell swig to grok everything defined in these header files and
|
||||
* build all sorts of c wrappers and python shadows of the c wrappers.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -95,6 +95,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_open(switch_file_handle_t *fh,
|
|||
SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, void *data, switch_size_t *len)
|
||||
{
|
||||
assert(fh != NULL);
|
||||
assert(fh->file_interface != NULL);
|
||||
|
||||
return fh->file_interface->file_read(fh, data, len);
|
||||
}
|
||||
|
@ -102,6 +103,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh,
|
|||
SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, void *data, switch_size_t *len)
|
||||
{
|
||||
assert(fh != NULL);
|
||||
assert(fh->file_interface != NULL);
|
||||
|
||||
return fh->file_interface->file_write(fh, data, len);
|
||||
}
|
||||
|
@ -109,6 +111,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh,
|
|||
SWITCH_DECLARE(switch_status_t) switch_core_file_seek(switch_file_handle_t *fh, unsigned int *cur_pos, int64_t samples, int whence)
|
||||
{
|
||||
assert(fh != NULL);
|
||||
assert(fh->file_interface != NULL);
|
||||
|
||||
switch_set_flag(fh, SWITCH_FILE_SEEK);
|
||||
return fh->file_interface->file_seek(fh, cur_pos, samples, whence);
|
||||
|
@ -117,6 +120,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_seek(switch_file_handle_t *fh,
|
|||
SWITCH_DECLARE(switch_status_t) switch_core_file_set_string(switch_file_handle_t *fh, switch_audio_col_t col, const char *string)
|
||||
{
|
||||
assert(fh != NULL);
|
||||
assert(fh->file_interface != NULL);
|
||||
|
||||
return fh->file_interface->file_set_string(fh, col, string);
|
||||
}
|
||||
|
@ -124,6 +128,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_set_string(switch_file_handle_t
|
|||
SWITCH_DECLARE(switch_status_t) switch_core_file_get_string(switch_file_handle_t *fh, switch_audio_col_t col, const char **string)
|
||||
{
|
||||
assert(fh != NULL);
|
||||
assert(fh->file_interface != NULL);
|
||||
|
||||
return fh->file_interface->file_get_string(fh, col, string);
|
||||
|
||||
|
@ -132,6 +137,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_get_string(switch_file_handle_t
|
|||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh)
|
||||
{
|
||||
assert(fh != NULL);
|
||||
assert(fh->file_interface != NULL);
|
||||
|
||||
switch_clear_flag(fh, SWITCH_FILE_OPEN);
|
||||
return fh->file_interface->file_close(fh);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#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_noreturn do { if (!session) { switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_ERROR, "session is not initalized\n"); return;}} while(0)
|
||||
#define init_vars() do { session = NULL; channel = NULL; uuid = NULL; tts_name = NULL; voice_name = NULL; memset(&args, 0, sizeof(args)); ap = NULL; caller_profile.source = "mod_unknown"; caller_profile.dialplan = ""; caller_profile.context = ""; caller_profile.caller_id_name = ""; caller_profile.caller_id_number = ""; caller_profile.network_addr = ""; caller_profile.ani = ""; caller_profile.aniii = ""; caller_profile.rdnis = ""; caller_profile.username = ""; } while(0)
|
||||
#define init_vars() do { session = NULL; channel = NULL; uuid = NULL; tts_name = NULL; voice_name = NULL; memset(&args, 0, sizeof(args)); ap = NULL; caller_profile.source = "mod_unknown"; caller_profile.dialplan = ""; caller_profile.context = ""; caller_profile.caller_id_name = ""; caller_profile.caller_id_number = ""; caller_profile.network_addr = ""; caller_profile.ani = ""; caller_profile.aniii = ""; caller_profile.rdnis = ""; caller_profile.username = ""; on_hangup = NULL; cb_state.function = NULL; } while(0)
|
||||
|
||||
|
||||
|
||||
|
@ -36,8 +36,13 @@ CoreSession::CoreSession(switch_core_session_t *new_session)
|
|||
CoreSession::~CoreSession()
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::~CoreSession desctructor");
|
||||
switch_channel_t *channel = NULL;
|
||||
|
||||
if (session) {
|
||||
channel = switch_core_session_get_channel(session);
|
||||
if (channel && switch_test_flag(this, S_HUP)) {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
|
||||
}
|
||||
switch_core_session_rwunlock(session);
|
||||
}
|
||||
|
||||
|
@ -103,30 +108,35 @@ int CoreSession::playFile(char *file, char *timer_name)
|
|||
timer_name = NULL;
|
||||
}
|
||||
store_file_handle(&fh);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "playFile begin_allow_threads\n");
|
||||
begin_allow_threads();
|
||||
status = switch_ivr_play_file(session, &fh, file, ap);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "playFile end_allow_threads\n");
|
||||
end_allow_threads();
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
|
||||
}
|
||||
|
||||
void CoreSession::setDTMFCallback(switch_input_callback_function_t cb,
|
||||
void *buf,
|
||||
uint32_t buflen)
|
||||
{
|
||||
sanity_check_noreturn;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::setDTMFCallback.");
|
||||
if (cb) {
|
||||
args.buf = buf;
|
||||
args.buflen = buflen;
|
||||
args.input_callback = cb;
|
||||
ap = &args;
|
||||
} else {
|
||||
memset(&args, 0, sizeof(args));
|
||||
ap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CoreSession::setDTMFCallback(void *cbfunc, char *funcargs) {
|
||||
|
||||
cb_state.funcargs = funcargs;
|
||||
cb_state.function = cbfunc;
|
||||
|
||||
args.buf = &cb_state;
|
||||
args.buflen = sizeof(cb_state); // not sure what this is used for, copy mod_spidermonkey
|
||||
|
||||
switch_channel_set_private(channel, "CoreSession", this);
|
||||
|
||||
// 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 = dtmf_callback;
|
||||
ap = &args;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int CoreSession::speak(char *text)
|
||||
{
|
||||
|
@ -134,6 +144,12 @@ int CoreSession::speak(char *text)
|
|||
switch_codec_t *codec;
|
||||
|
||||
sanity_check(-1);
|
||||
|
||||
// create and store an empty filehandle in callback args
|
||||
// to workaround a bug in the presumptuous process_callback_result()
|
||||
switch_file_handle_t fh = { 0 };
|
||||
store_file_handle(&fh);
|
||||
|
||||
if (!tts_name) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No TTS engine specified");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
@ -161,7 +177,8 @@ void CoreSession::set_tts_parms(char *tts_name_p, char *voice_name_p)
|
|||
}
|
||||
|
||||
int CoreSession::getDigits(char *dtmf_buf,
|
||||
int len,
|
||||
int buflen,
|
||||
int maxdigits,
|
||||
char *terminators,
|
||||
char *terminator,
|
||||
int timeout)
|
||||
|
@ -169,13 +186,16 @@ int CoreSession::getDigits(char *dtmf_buf,
|
|||
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,
|
||||
(uint32_t) buflen,
|
||||
(uint32_t) maxdigits,
|
||||
terminators,
|
||||
terminator,
|
||||
(uint32_t) timeout);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "getDigits dtmf_buf: %s\n", dtmf_buf);
|
||||
end_allow_threads();
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
@ -213,6 +233,9 @@ int CoreSession::playAndGetDigits(int min_digits,
|
|||
bad_input_audio_files,
|
||||
dtmf_buf, 128,
|
||||
digits_regex);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "playAndGetDigits dtmf_buf: %s\n", dtmf_buf);
|
||||
|
||||
end_allow_threads();
|
||||
return status == SWITCH_STATUS_SUCCESS ? 1 : 0;
|
||||
}
|
||||
|
@ -318,6 +341,52 @@ int CoreSession::recordFile(char *file_name, int max_len, int silence_threshold,
|
|||
|
||||
}
|
||||
|
||||
int CoreSession::flushEvents()
|
||||
{
|
||||
switch_event_t *event;
|
||||
switch_channel_t *channel;
|
||||
|
||||
if (!session) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
|
||||
while (switch_core_session_dequeue_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_destroy(&event);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int CoreSession::flushDigits()
|
||||
{
|
||||
char buf[256];
|
||||
switch_size_t has;
|
||||
switch_channel_t *channel;
|
||||
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
|
||||
while ((has = switch_channel_has_dtmf(channel))) {
|
||||
switch_channel_dequeue_dtmf(channel, buf, sizeof(buf));
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int CoreSession::setAutoHangup(bool val)
|
||||
{
|
||||
if (!session) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
if (val) {
|
||||
switch_set_flag(this, S_HUP);
|
||||
} else {
|
||||
switch_clear_flag(this, S_HUP);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void CoreSession::setCallerData(char *var, char *val) {
|
||||
|
||||
if (strcmp(var, "dialplan") == 0) {
|
||||
|
@ -350,12 +419,17 @@ void CoreSession::setCallerData(char *var, char *val) {
|
|||
|
||||
}
|
||||
|
||||
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::setHangupHook(void *hangup_func) {
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CoreSession::seHangupHook, hangup_func: %p\n", hangup_func);
|
||||
on_hangup = hangup_func;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
assert(channel != NULL);
|
||||
|
||||
hook_state = switch_channel_get_state(channel);
|
||||
switch_channel_set_private(channel, "CoreSession", this);
|
||||
switch_core_event_hook_add_state_change(session, hanguphook);
|
||||
|
||||
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
|
||||
|
@ -424,6 +498,64 @@ void bridge(CoreSession &session_a, CoreSession &session_b)
|
|||
}
|
||||
|
||||
|
||||
switch_status_t hanguphook(switch_core_session_t *session_hungup)
|
||||
{
|
||||
switch_channel_t *channel;
|
||||
CoreSession *coresession = NULL;
|
||||
switch_channel_state_t state;
|
||||
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "hangup_hook called\n");
|
||||
fflush(stdout);
|
||||
|
||||
channel = switch_core_session_get_channel(session_hungup);
|
||||
assert(channel != NULL);
|
||||
|
||||
state = switch_channel_get_state(channel);
|
||||
|
||||
if ((coresession = (CoreSession *) switch_channel_get_private(channel, "CoreSession"))) {
|
||||
if (coresession->hook_state != state) {
|
||||
coresession->hook_state = state;
|
||||
coresession->check_hangup_hook();
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
switch_status_t dtmf_callback(switch_core_session_t *session_cb,
|
||||
void *input,
|
||||
switch_input_type_t itype,
|
||||
void *buf,
|
||||
unsigned int buflen) {
|
||||
|
||||
switch_channel_t *channel;
|
||||
CoreSession *coresession = NULL;
|
||||
switch_status_t result;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "dtmf_callback called\n");
|
||||
fflush(stdout);
|
||||
|
||||
channel = switch_core_session_get_channel(session_cb);
|
||||
assert(channel != NULL);
|
||||
|
||||
coresession = (CoreSession *) switch_channel_get_private(channel, "CoreSession");
|
||||
if (!coresession) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid CoreSession\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
result = coresession->run_dtmf_callback(input, itype);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "process_callback_result returned\n");
|
||||
if (result) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "process_callback_result returned: %d\n", result);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch_status_t process_callback_result(char *ret,
|
||||
struct input_callback_state *cb_state,
|
||||
|
@ -431,16 +563,40 @@ switch_status_t process_callback_result(char *ret,
|
|||
{
|
||||
|
||||
switch_file_handle_t *fh = NULL;
|
||||
|
||||
if (!cb_state) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Process callback result aborted because cb_state is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!cb_state->extra) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Process callback result aborted because cb_state->extra is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
fh = (switch_file_handle_t *) cb_state->extra;
|
||||
|
||||
if (!fh) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Process callback result aborted because fh is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!fh->file_interface) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Process callback result aborted because fh->file_interface is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Process callback result aborted because ret is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Process callback result aborted because session is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (!strncasecmp(ret, "speed", 4)) {
|
||||
char *p;
|
||||
|
||||
|
@ -481,7 +637,7 @@ switch_status_t process_callback_result(char *ret,
|
|||
unsigned int pos = 0;
|
||||
char *p;
|
||||
codec = switch_core_session_get_read_codec(session);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got codec\n");
|
||||
if ((p = strchr(ret, ':'))) {
|
||||
p++;
|
||||
if (*p == '+' || *p == '-') {
|
||||
|
@ -491,14 +647,20 @@ switch_status_t process_callback_result(char *ret,
|
|||
}
|
||||
if (step > 0) {
|
||||
samps = step * (codec->implementation->samples_per_second / 1000);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "going to seek\n");
|
||||
switch_core_file_seek(fh, &pos, samps, SEEK_CUR);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done seek\n");
|
||||
} else {
|
||||
samps = step * (codec->implementation->samples_per_second / 1000);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "going to seek\n");
|
||||
switch_core_file_seek(fh, &pos, fh->pos - samps, SEEK_SET);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done seek\n");
|
||||
}
|
||||
} else {
|
||||
samps = atoi(p) * (codec->implementation->samples_per_second / 1000);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "going to seek\n");
|
||||
switch_core_file_seek(fh, &pos, samps, SEEK_SET);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "done seek\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,9 +668,11 @@ switch_status_t process_callback_result(char *ret,
|
|||
}
|
||||
|
||||
if (!strcmp(ret, "true") || !strcmp(ret, "undefined")) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "return success\n");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no match, return false\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue