mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-07-08 05:11:51 +00:00
snake charming
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@8998 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
@@ -11,19 +11,20 @@ include ../../../../build/modmake.rules
|
||||
LINK=$(CXXLINK)
|
||||
|
||||
PYMOD=freeswitch
|
||||
PYTHON_SITE_DIR=@PYTHON_SITE_DIR@
|
||||
PYTHON_SITE_DIR=/usr/lib/python2.4/site-packages
|
||||
|
||||
SWIGCFILE=../../../switch_swig.c
|
||||
SWIGIFILE=../../../switch_swig.i
|
||||
|
||||
reswig:
|
||||
swig -python -shadow -c++ -I../../../../src/include -o mod_python_wrap.cpp mod_python.i
|
||||
reswig: swigclean mod_python_wrap.cpp
|
||||
|
||||
switch_swig_wrap.o: switch_swig_wrap.c Makefile
|
||||
$(CC) -w $(CFLAGS) -c $< -o $@
|
||||
swigclean: clean
|
||||
rm -f mod_python_wrap.* freeswitch.py
|
||||
|
||||
switch_swig.o: $(SWIGCFILE) Makefile
|
||||
$(CC) -w $(CFLAGS) -c $< -o $@
|
||||
mod_python_wrap.cpp: mod_python_extra.c
|
||||
swig -python -c++ -I../../../../src/include -oh mod_python_wrap.h -o mod_python_wrap.cpp mod_python.i
|
||||
echo "#include \"mod_python_extra.c\"" >> mod_python_wrap.cpp
|
||||
patch -s -p0 -i hack.diff
|
||||
|
||||
local_install:
|
||||
mkdir -m755 -p $(DESTDIR)$(PYTHON_SITE_DIR)
|
||||
|
||||
@@ -114,6 +114,27 @@ 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 DTMF(_object):
|
||||
__swig_setmethods__ = {}
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, DTMF, name, value)
|
||||
__swig_getmethods__ = {}
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, DTMF, name)
|
||||
__repr__ = _swig_repr
|
||||
__swig_setmethods__["digit"] = _freeswitch.DTMF_digit_set
|
||||
__swig_getmethods__["digit"] = _freeswitch.DTMF_digit_get
|
||||
if _newclass:digit = _swig_property(_freeswitch.DTMF_digit_get, _freeswitch.DTMF_digit_set)
|
||||
__swig_setmethods__["duration"] = _freeswitch.DTMF_duration_set
|
||||
__swig_getmethods__["duration"] = _freeswitch.DTMF_duration_get
|
||||
if _newclass:duration = _swig_property(_freeswitch.DTMF_duration_get, _freeswitch.DTMF_duration_set)
|
||||
def __init__(self, *args):
|
||||
this = _freeswitch.new_DTMF(*args)
|
||||
try: self.this.append(this)
|
||||
except: self.this = this
|
||||
__swig_destroy__ = _freeswitch.delete_DTMF
|
||||
__del__ = lambda self : None;
|
||||
DTMF_swigregister = _freeswitch.DTMF_swigregister
|
||||
DTMF_swigregister(DTMF)
|
||||
|
||||
class Stream(_object):
|
||||
__swig_setmethods__ = {}
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, Stream, name, value)
|
||||
@@ -274,31 +295,43 @@ console_clean_log = _freeswitch.console_clean_log
|
||||
bridge = _freeswitch.bridge
|
||||
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):
|
||||
class Session(CoreSession):
|
||||
__swig_setmethods__ = {}
|
||||
for _s in [CoreSession]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, PySession, name, value)
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, Session, name, value)
|
||||
__swig_getmethods__ = {}
|
||||
for _s in [CoreSession]: __swig_getmethods__.update(getattr(_s,'__swig_getmethods__',{}))
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, PySession, name)
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, Session, name)
|
||||
__repr__ = _swig_repr
|
||||
def __init__(self, *args):
|
||||
this = _freeswitch.new_PySession(*args)
|
||||
this = _freeswitch.new_Session(*args)
|
||||
try: self.this.append(this)
|
||||
except: self.this = this
|
||||
__swig_destroy__ = _freeswitch.delete_PySession
|
||||
__swig_destroy__ = _freeswitch.delete_Session
|
||||
__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)
|
||||
def begin_allow_threads(*args): return _freeswitch.Session_begin_allow_threads(*args)
|
||||
def end_allow_threads(*args): return _freeswitch.Session_end_allow_threads(*args)
|
||||
def check_hangup_hook(*args): return _freeswitch.Session_check_hangup_hook(*args)
|
||||
def run_dtmf_callback(*args): return _freeswitch.Session_run_dtmf_callback(*args)
|
||||
def setInputCallback(*args): return _freeswitch.Session_setInputCallback(*args)
|
||||
def setHangupHook(*args): return _freeswitch.Session_setHangupHook(*args)
|
||||
def ready(*args): return _freeswitch.Session_ready(*args)
|
||||
__swig_setmethods__["cb_function"] = _freeswitch.Session_cb_function_set
|
||||
__swig_getmethods__["cb_function"] = _freeswitch.Session_cb_function_get
|
||||
if _newclass:cb_function = _swig_property(_freeswitch.Session_cb_function_get, _freeswitch.Session_cb_function_set)
|
||||
__swig_setmethods__["cb_arg"] = _freeswitch.Session_cb_arg_set
|
||||
__swig_getmethods__["cb_arg"] = _freeswitch.Session_cb_arg_get
|
||||
if _newclass:cb_arg = _swig_property(_freeswitch.Session_cb_arg_get, _freeswitch.Session_cb_arg_set)
|
||||
__swig_setmethods__["hangup_func"] = _freeswitch.Session_hangup_func_set
|
||||
__swig_getmethods__["hangup_func"] = _freeswitch.Session_hangup_func_get
|
||||
if _newclass:hangup_func = _swig_property(_freeswitch.Session_hangup_func_get, _freeswitch.Session_hangup_func_set)
|
||||
__swig_setmethods__["hangup_func_arg"] = _freeswitch.Session_hangup_func_arg_set
|
||||
__swig_getmethods__["hangup_func_arg"] = _freeswitch.Session_hangup_func_arg_get
|
||||
if _newclass:hangup_func_arg = _swig_property(_freeswitch.Session_hangup_func_arg_get, _freeswitch.Session_hangup_func_arg_set)
|
||||
def setPython(*args): return _freeswitch.Session_setPython(*args)
|
||||
def setSelf(*args): return _freeswitch.Session_setSelf(*args)
|
||||
Session_swigregister = _freeswitch.Session_swigregister
|
||||
Session_swigregister(Session)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,320 +1,301 @@
|
||||
|
||||
#include <switch.h>
|
||||
#include "freeswitch_python.h"
|
||||
using namespace PYTHON;
|
||||
|
||||
#define py_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 py_init_vars() do { caller_profile.source = "mod_python"; swapstate = S_SWAPPED_IN; } while(0)
|
||||
#define py_init_vars() cb_function = cb_arg = hangup_func = hangup_func_arg = NULL; hh = mark = 0; TS = NULL
|
||||
|
||||
PySession::PySession():CoreSession()
|
||||
Session::Session():CoreSession()
|
||||
{
|
||||
py_init_vars();
|
||||
}
|
||||
|
||||
PySession::PySession(char *uuid):CoreSession(uuid)
|
||||
Session::Session(char *uuid):CoreSession(uuid)
|
||||
{
|
||||
py_init_vars();
|
||||
}
|
||||
|
||||
PySession::PySession(switch_core_session_t *new_session):CoreSession(new_session)
|
||||
Session::Session(switch_core_session_t *new_session):CoreSession(new_session)
|
||||
{
|
||||
py_init_vars();
|
||||
}
|
||||
static switch_status_t python_hanguphook(switch_core_session_t *session_hungup);
|
||||
|
||||
|
||||
void PySession::setDTMFCallback(PyObject * pyfunc, char *funcargs)
|
||||
Session::~Session()
|
||||
{
|
||||
py_sanity_check();
|
||||
|
||||
if (!PyCallable_Check(pyfunc)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "DTMF function is not a python function.\n");
|
||||
return;
|
||||
|
||||
if (hangup_func) {
|
||||
if (session) {
|
||||
switch_core_event_hook_remove_state_change(session, python_hanguphook);
|
||||
}
|
||||
Py_XDECREF(hangup_func);
|
||||
hangup_func = NULL;
|
||||
}
|
||||
|
||||
if (hangup_func_arg) {
|
||||
Py_XDECREF(hangup_func_arg);
|
||||
hangup_func_arg = NULL;
|
||||
}
|
||||
Py_XINCREF(pyfunc);
|
||||
CoreSession::setDTMFCallback((void *) pyfunc, funcargs);
|
||||
|
||||
if (cb_function) {
|
||||
Py_XDECREF(cb_function);
|
||||
cb_function = NULL;
|
||||
}
|
||||
|
||||
if (cb_arg) {
|
||||
Py_XDECREF(cb_arg);
|
||||
cb_arg = NULL;
|
||||
}
|
||||
|
||||
if (Self) {
|
||||
Py_XDECREF(Self);
|
||||
}
|
||||
}
|
||||
|
||||
bool Session::begin_allow_threads()
|
||||
{
|
||||
|
||||
do_hangup_hook();
|
||||
|
||||
if (!TS) {
|
||||
TS = PyEval_SaveThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Session::end_allow_threads()
|
||||
{
|
||||
|
||||
if (!TS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PyEval_RestoreThread(TS);
|
||||
TS = NULL;
|
||||
|
||||
do_hangup_hook();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::setPython(PyObject *state)
|
||||
{
|
||||
Py = state;
|
||||
}
|
||||
|
||||
void Session::setSelf(PyObject *state)
|
||||
{
|
||||
Self = state;
|
||||
}
|
||||
|
||||
PyObject *Session::getPython()
|
||||
{
|
||||
return Py;
|
||||
}
|
||||
|
||||
|
||||
bool Session::ready()
|
||||
{
|
||||
bool r;
|
||||
|
||||
sanity_check(false);
|
||||
r = switch_channel_ready(channel) != 0;
|
||||
do_hangup_hook();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void Session::check_hangup_hook()
|
||||
{
|
||||
if (hangup_func && (hook_state == CS_HANGUP || hook_state == CS_ROUTING)) {
|
||||
hh++;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::do_hangup_hook()
|
||||
{
|
||||
PyObject *result, *arglist;
|
||||
const char *what = hook_state == CS_HANGUP ? "hangup" : "transfer";
|
||||
|
||||
if (hh && !mark) {
|
||||
mark++;
|
||||
|
||||
if (hangup_func) {
|
||||
|
||||
if (!PyCallable_Check(hangup_func)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "function not callable\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Self) {
|
||||
mod_python_conjure_session(NULL, session, NULL);
|
||||
}
|
||||
|
||||
if (hangup_func_arg) {
|
||||
arglist = Py_BuildValue("(OsO)", Self, what, hangup_func_arg);
|
||||
} else {
|
||||
arglist = Py_BuildValue("(Os)", Self, what);
|
||||
}
|
||||
|
||||
if (!(result = PyEval_CallObject(hangup_func, arglist))) {
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
Py_XDECREF(arglist);
|
||||
Py_XDECREF(hangup_func_arg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PySession::setHangupHook(PyObject * pyfunc)
|
||||
static switch_status_t python_hanguphook(switch_core_session_t *session_hungup)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session_hungup);
|
||||
CoreSession *coresession = NULL;
|
||||
switch_channel_state_t 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;
|
||||
}
|
||||
|
||||
|
||||
void Session::setHangupHook(PyObject *pyfunc, PyObject *arg)
|
||||
{
|
||||
|
||||
if (!PyCallable_Check(pyfunc)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hangup hook is not a python function.\n");
|
||||
return;
|
||||
}
|
||||
// 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);
|
||||
|
||||
if (hangup_func) {
|
||||
if (session) {
|
||||
switch_core_event_hook_remove_state_change(session, python_hanguphook);
|
||||
}
|
||||
Py_XDECREF(hangup_func);
|
||||
hangup_func = NULL;
|
||||
}
|
||||
|
||||
if (hangup_func_arg) {
|
||||
Py_XDECREF(hangup_func_arg);
|
||||
hangup_func_arg = NULL;
|
||||
}
|
||||
|
||||
hangup_func = pyfunc;
|
||||
hangup_func_arg = arg;
|
||||
|
||||
Py_XINCREF(hangup_func);
|
||||
|
||||
if (hangup_func_arg) {
|
||||
Py_XINCREF(hangup_func_arg);
|
||||
}
|
||||
|
||||
switch_channel_set_private(channel, "CoreSession", this);
|
||||
hook_state = switch_channel_get_state(channel);
|
||||
switch_core_event_hook_add_state_change(session, python_hanguphook);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void PySession::check_hangup_hook()
|
||||
void Session::setInputCallback(PyObject *cbfunc, PyObject *funcargs)
|
||||
{
|
||||
#if 0
|
||||
PyObject *func;
|
||||
PyObject *result;
|
||||
char *resultStr;
|
||||
bool did_swap_in = false;
|
||||
#endif
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"check_hangup_hook has been DISABLED, please do not use hangup hooks in python code until further notice!\n");
|
||||
|
||||
if (!session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No valid session\n");
|
||||
if (!PyCallable_Check(cbfunc)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hangup hook is not a python function.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
if (cb_function) {
|
||||
Py_XDECREF(cb_function);
|
||||
cb_function = NULL;
|
||||
}
|
||||
|
||||
/*! NEEDS TO BE FIXED:
|
||||
if (cb_arg) {
|
||||
Py_XDECREF(cb_arg);
|
||||
cb_arg = NULL;
|
||||
}
|
||||
|
||||
// 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();
|
||||
cb_function = cbfunc;
|
||||
cb_arg = funcargs;
|
||||
args.buf = this;
|
||||
switch_channel_set_private(channel, "CoreSession", this);
|
||||
|
||||
if (on_hangup == NULL) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "on_hangup is null\n");
|
||||
return;
|
||||
}
|
||||
Py_XINCREF(cb_function);
|
||||
|
||||
func = (PyObject *) on_hangup;
|
||||
if (cb_arg) {
|
||||
Py_XINCREF(cb_arg);
|
||||
}
|
||||
|
||||
// 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);
|
||||
args.input_callback = dtmf_callback;
|
||||
ap = &args;
|
||||
|
||||
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)
|
||||
switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t itype)
|
||||
{
|
||||
|
||||
PyObject *func, *arglist;
|
||||
PyObject *pyresult;
|
||||
PyObject *headerdict;
|
||||
PyObject *pyresult, *arglist, *io = NULL;
|
||||
int ts = 0;
|
||||
char *str = NULL, *what = "";
|
||||
|
||||
char *resultStr;
|
||||
char *funcargs;
|
||||
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;
|
||||
if (TS) {
|
||||
ts++;
|
||||
end_allow_threads();
|
||||
}
|
||||
|
||||
func = (PyObject *) cb_state.function;
|
||||
if (!func) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "cb_state->function is null\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cb_state->function is NOT null\n");
|
||||
}
|
||||
if (!PyCallable_Check(func)) {
|
||||
if (!PyCallable_Check(cb_function)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "function not callable\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
funcargs = (char *) cb_state.funcargs;
|
||||
|
||||
|
||||
if (itype == SWITCH_INPUT_TYPE_DTMF) {
|
||||
|
||||
arglist = Py_BuildValue("(sis)", input, itype, funcargs);
|
||||
} else if (itype == SWITCH_INPUT_TYPE_EVENT) {
|
||||
// DUNNO if this is correct in the case we have an event
|
||||
// will be of type switch_event_t *event;
|
||||
// http://www.freeswitch.org/docs/structswitch__event.html
|
||||
switch_event_t *event = (switch_event_t *) input;
|
||||
arglist = Py_BuildValue("({s:s}is)", "body", event->body, itype, funcargs);
|
||||
|
||||
// build a dictionary with all the headers
|
||||
|
||||
switch_event_header_t *hp;
|
||||
headerdict = PyDict_New();
|
||||
for (hp = event->headers; hp; hp = hp->next) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding event header to result");
|
||||
|
||||
// TODO: create PyObject pointers for name and value
|
||||
// and explicitly decref them. all ref counting stuff is
|
||||
// a mess and needs to be tested and looked at closer.
|
||||
PyDict_SetItem(headerdict, Py_BuildValue("s", hp->name), Py_BuildValue("s", hp->value));
|
||||
|
||||
}
|
||||
|
||||
// add it to the main event dictionary (first arg in list)
|
||||
// under key 'headers'
|
||||
PyObject *dict = PyTuple_GetItem(arglist, 0);
|
||||
PyDict_SetItemString(dict, "headers", headerdict);
|
||||
|
||||
Py_XDECREF(headerdict);
|
||||
|
||||
|
||||
switch_dtmf_t *dtmf = (switch_dtmf_t *) input;
|
||||
io = mod_python_conjure_DTMF(dtmf->digit, dtmf->duration);
|
||||
what = "dtmf";
|
||||
} else if (itype == SWITCH_INPUT_TYPE_EVENT){
|
||||
what = "event";
|
||||
io = mod_python_conjure_event(NULL, (switch_event_t *) input, NULL);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown input type: %d\n", itype);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unsupported type!\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (!arglist) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error building arglist");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
if (!Self) {
|
||||
mod_python_conjure_session(NULL, session, NULL);
|
||||
}
|
||||
|
||||
if (cb_arg) {
|
||||
arglist = Py_BuildValue("(OsOO)", Self, what, io, cb_arg);
|
||||
} else {
|
||||
arglist = Py_BuildValue("(OsO)", Self, what, io);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "run_dtmf_callback end_allow_threads\n");
|
||||
did_swap_in = end_allow_threads();
|
||||
|
||||
pyresult = PyEval_CallObject(func, arglist);
|
||||
|
||||
|
||||
Py_XDECREF(arglist); // Trash arglist
|
||||
|
||||
if (pyresult && pyresult != Py_None) {
|
||||
resultStr = (char *) PyString_AsString(pyresult);
|
||||
switch_status_t cbresult = process_callback_result(resultStr);
|
||||
return cbresult;
|
||||
if ((pyresult = PyEval_CallObject(cb_function, arglist))) {
|
||||
str = (char *) PyString_AsString(pyresult);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Python callback\n returned None");
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "run_dtmf_callback begin_allow_threads\n");
|
||||
if (did_swap_in) {
|
||||
Py_XDECREF(arglist);
|
||||
Py_XDECREF(io);
|
||||
|
||||
if (cb_arg) {
|
||||
Py_XDECREF(cb_arg);
|
||||
}
|
||||
|
||||
if (ts) {
|
||||
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");
|
||||
|
||||
if (!session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No valid session\n");
|
||||
return false;
|
||||
}
|
||||
// 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
|
||||
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
|
||||
if (!session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No valid session\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
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");
|
||||
if (str) {
|
||||
return process_callback_result(str);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
@@ -1,61 +1,45 @@
|
||||
#ifndef FREESWITCH_PYTHON_H
|
||||
#define FREESWITCH_PYTHON_H
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef DOH
|
||||
#include <Python.h>
|
||||
#include "mod_python_extra.h"
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <switch_cpp.h>
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
class PySession : public CoreSession {
|
||||
namespace PYTHON {
|
||||
class Session : public CoreSession {
|
||||
private:
|
||||
void *threadState;
|
||||
int swapstate;
|
||||
virtual void do_hangup_hook();
|
||||
PyObject *getPython();
|
||||
PyObject *Py;
|
||||
PyObject *Self;
|
||||
int hh;
|
||||
int mark;
|
||||
PyThreadState *TS;
|
||||
public:
|
||||
PySession();
|
||||
PySession(char *uuid);
|
||||
PySession(switch_core_session_t *session);
|
||||
~PySession();
|
||||
void setDTMFCallback(PyObject *pyfunc, char *funcargs);
|
||||
void setHangupHook(PyObject *pyfunc);
|
||||
void check_hangup_hook();
|
||||
void hangup(char *cause);
|
||||
bool begin_allow_threads();
|
||||
bool end_allow_threads();
|
||||
Session();
|
||||
Session(char *uuid);
|
||||
Session(switch_core_session_t *session);
|
||||
virtual ~Session();
|
||||
|
||||
virtual bool begin_allow_threads();
|
||||
virtual bool end_allow_threads();
|
||||
virtual void check_hangup_hook();
|
||||
|
||||
/**
|
||||
* Run DTMF callback
|
||||
*
|
||||
* A static method in CoreSession is the first thing called
|
||||
* upon receving a dtmf/event callback from fs engine, and then
|
||||
* it gets the PySession instance and calls this method with
|
||||
* dtmf/event object.
|
||||
*
|
||||
* @param input - a dtmf char buffer, or an event 'object' (not sure..)
|
||||
* @param itype - a SWITCH_INPUT_TYPE_DTMF or a SWITCH_INPUT_TYPE_EVENT
|
||||
*/
|
||||
switch_status_t run_dtmf_callback(void *input,
|
||||
switch_input_type_t itype);
|
||||
virtual switch_status_t run_dtmf_callback(void *input, switch_input_type_t itype);
|
||||
void setInputCallback(PyObject *cbfunc, PyObject *funcargs = NULL);
|
||||
void setHangupHook(PyObject *pyfunc, PyObject *arg = NULL);
|
||||
bool ready();
|
||||
|
||||
PyObject *cb_function;
|
||||
PyObject *cb_arg;
|
||||
PyObject *hangup_func;
|
||||
PyObject *hangup_func_arg;
|
||||
|
||||
void setPython(PyObject *state);
|
||||
void setSelf(PyObject *state);
|
||||
};
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
--- mod_python_wrap.cpp 2008-07-10 13:14:21.000000000 -0500
|
||||
+++ old.cpp 2008-07-10 13:13:57.000000000 -0500
|
||||
@@ -8150,20 +8150,20 @@
|
||||
}
|
||||
|
||||
|
||||
-SWIGINTERN PyObject *_wrap_new_Session__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
|
||||
+SWIGINTERN PyObject *_wrap_new_Session__SWIG_0(PyObject *self, PyObject *args) {
|
||||
PyObject *resultobj = 0;
|
||||
PYTHON::Session *result = 0 ;
|
||||
|
||||
if (!PyArg_ParseTuple(args,(char *)":new_Session")) SWIG_fail;
|
||||
result = (PYTHON::Session *)new PYTHON::Session();
|
||||
- resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PYTHON__Session, SWIG_POINTER_NEW | 0 );
|
||||
+ resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PYTHON__Session, SWIG_POINTER_NEW | 0 ); result->setPython(self);
|
||||
return resultobj;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
-SWIGINTERN PyObject *_wrap_new_Session__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
|
||||
+SWIGINTERN PyObject *_wrap_new_Session__SWIG_1(PyObject *self, PyObject *args) {
|
||||
PyObject *resultobj = 0;
|
||||
char *arg1 = (char *) 0 ;
|
||||
PYTHON::Session *result = 0 ;
|
||||
@@ -8179,7 +8179,7 @@
|
||||
}
|
||||
arg1 = reinterpret_cast< char * >(buf1);
|
||||
result = (PYTHON::Session *)new PYTHON::Session(arg1);
|
||||
- resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PYTHON__Session, SWIG_POINTER_NEW | 0 );
|
||||
+ resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PYTHON__Session, SWIG_POINTER_NEW | 0 ); result->setPython(self);
|
||||
if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
|
||||
return resultobj;
|
||||
fail:
|
||||
@@ -8188,7 +8188,7 @@
|
||||
}
|
||||
|
||||
|
||||
-SWIGINTERN PyObject *_wrap_new_Session__SWIG_2(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
|
||||
+SWIGINTERN PyObject *_wrap_new_Session__SWIG_2(PyObject *self, PyObject *args) {
|
||||
PyObject *resultobj = 0;
|
||||
switch_core_session_t *arg1 = (switch_core_session_t *) 0 ;
|
||||
PYTHON::Session *result = 0 ;
|
||||
@@ -8203,7 +8203,7 @@
|
||||
}
|
||||
arg1 = reinterpret_cast< switch_core_session_t * >(argp1);
|
||||
result = (PYTHON::Session *)new PYTHON::Session(arg1);
|
||||
- resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PYTHON__Session, SWIG_POINTER_NEW | 0 );
|
||||
+ resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PYTHON__Session, SWIG_POINTER_NEW | 0 ); result->setPython(self);
|
||||
return resultobj;
|
||||
fail:
|
||||
return NULL;
|
||||
@@ -42,7 +42,7 @@
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#include "mod_python_extra.h"
|
||||
|
||||
PyThreadState *mainThreadState = NULL;
|
||||
|
||||
@@ -62,7 +62,7 @@ static void eval_some_python(char *uuid, char *args, switch_core_session_t *sess
|
||||
int argc;
|
||||
int lead = 0;
|
||||
char *script = NULL;
|
||||
PyObject *module = NULL;
|
||||
PyObject *module = NULL, *sp = NULL;
|
||||
PyObject *function = NULL;
|
||||
PyObject *arg = NULL;
|
||||
PyObject *result = NULL;
|
||||
@@ -139,6 +139,10 @@ static void eval_some_python(char *uuid, char *args, switch_core_session_t *sess
|
||||
PyTuple_SetItem(arg, 0, nada);
|
||||
}
|
||||
|
||||
if (session) {
|
||||
sp = mod_python_conjure_session(module, session, "session");
|
||||
}
|
||||
|
||||
// invoke the handler
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call python script \n");
|
||||
result = PyEval_CallObjectWithKeywords(function, arg, (PyObject *) NULL);
|
||||
@@ -150,21 +154,26 @@ static void eval_some_python(char *uuid, char *args, switch_core_session_t *sess
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
goto done_swap_out;
|
||||
|
||||
|
||||
done:
|
||||
switch_safe_free(dupargs);
|
||||
|
||||
if (sp) {
|
||||
Py_XDECREF(sp);
|
||||
}
|
||||
|
||||
done_swap_out:
|
||||
|
||||
|
||||
// decrement ref counts
|
||||
Py_XDECREF(module);
|
||||
Py_XDECREF(function);
|
||||
Py_XDECREF(arg);
|
||||
Py_XDECREF(result);
|
||||
|
||||
|
||||
// swap out thread state
|
||||
if (session) {
|
||||
//switch_core_session_rwunlock(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");
|
||||
@@ -189,7 +198,7 @@ static void eval_some_python(char *uuid, char *args, switch_core_session_t *sess
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No session: Threadstate mod_python.c swap-out! \n");
|
||||
PyEval_ReleaseThread(tstate);
|
||||
}
|
||||
|
||||
|
||||
switch_safe_free(dupargs);
|
||||
|
||||
|
||||
|
||||
@@ -26,5 +26,3 @@
|
||||
%include switch_swigable_cpp.h
|
||||
%include freeswitch_python.h
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
PyObject *mod_python_conjure_event(PyObject *module, switch_event_t *event, const char *name)
|
||||
{
|
||||
PyObject *obj;
|
||||
Event *result = new Event(event, 0);
|
||||
|
||||
obj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Event, SWIG_POINTER_OWN );
|
||||
if (module && name) {
|
||||
PyDict_SetItem(PyModule_GetDict(module), Py_BuildValue("s", name), obj);
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
PyObject *mod_python_conjure_stream(PyObject *module, switch_stream_handle_t *stream, const char *name)
|
||||
{
|
||||
PyObject *obj;
|
||||
Stream *result = new Stream(stream);
|
||||
|
||||
obj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Stream, SWIG_POINTER_OWN );
|
||||
|
||||
if (module && name) {
|
||||
PyDict_SetItem(PyModule_GetDict(module), Py_BuildValue("s", name), obj);
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
PyObject *mod_python_conjure_session(PyObject *module, switch_core_session_t *session, const char *name)
|
||||
{
|
||||
PyObject *obj;
|
||||
|
||||
PYTHON::Session *result = new PYTHON::Session(session);
|
||||
obj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_PYTHON__Session, SWIG_POINTER_OWN);
|
||||
|
||||
result->setPython(module);
|
||||
result->setSelf(obj);
|
||||
|
||||
if (module && name) {
|
||||
PyDict_SetItem(PyModule_GetDict(module), Py_BuildValue("s", name), obj);
|
||||
Py_DECREF(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
PyObject *mod_python_conjure_DTMF(char digit, int32_t duration)
|
||||
{
|
||||
PyObject *obj;
|
||||
|
||||
DTMF *result = new DTMF(digit, duration);
|
||||
obj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_DTMF, SWIG_POINTER_OWN);
|
||||
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef MOD_PYTHON_EXTRA
|
||||
#define MOD_PYTHON_EXTRA
|
||||
SWITCH_BEGIN_EXTERN_C
|
||||
|
||||
PyObject *mod_python_conjure_event(PyObject *module, switch_event_t *event, const char *name);
|
||||
PyObject *mod_python_conjure_stream(PyObject *module, switch_stream_handle_t *stream, const char *name);
|
||||
PyObject *mod_python_conjure_session(PyObject *module, switch_core_session_t *session, const char *name);
|
||||
PyObject *mod_python_conjure_DTMF(char digit, int32_t duration);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user