2008-07-11 19:42:52 +00:00
|
|
|
|
|
|
|
#include <switch.h>
|
2006-12-21 17:11:43 +00:00
|
|
|
#include "freeswitch_python.h"
|
2008-07-11 19:42:52 +00:00
|
|
|
using namespace PYTHON;
|
2006-12-21 17:11:43 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
#define py_init_vars() cb_function = cb_arg = hangup_func = hangup_func_arg = NULL; hh = mark = 0; TS = NULL
|
2007-06-20 08:56:34 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
Session::Session():CoreSession()
|
2007-06-20 08:56:34 +00:00
|
|
|
{
|
2008-07-08 03:25:31 +00:00
|
|
|
py_init_vars();
|
2007-06-20 08:56:34 +00:00
|
|
|
}
|
|
|
|
|
2008-07-16 21:06:14 +00:00
|
|
|
Session::Session(char *nuuid, CoreSession *a_leg):CoreSession(nuuid, a_leg)
|
2007-06-20 08:56:34 +00:00
|
|
|
{
|
2008-07-08 03:25:31 +00:00
|
|
|
py_init_vars();
|
2007-06-20 08:56:34 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
Session::Session(switch_core_session_t *new_session):CoreSession(new_session)
|
2007-06-20 08:56:34 +00:00
|
|
|
{
|
2008-07-08 03:25:31 +00:00
|
|
|
py_init_vars();
|
2007-06-20 08:56:34 +00:00
|
|
|
}
|
2008-07-11 19:42:52 +00:00
|
|
|
static switch_status_t python_hanguphook(switch_core_session_t *session_hungup);
|
2006-12-21 17:11:43 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
Session::~Session()
|
2006-12-21 17:11:43 +00:00
|
|
|
{
|
2008-07-11 19:42:52 +00:00
|
|
|
|
|
|
|
if (hangup_func) {
|
|
|
|
if (session) {
|
|
|
|
switch_core_event_hook_remove_state_change(session, python_hanguphook);
|
|
|
|
}
|
2008-07-16 14:58:00 +00:00
|
|
|
Py_DECREF(hangup_func);
|
2008-07-11 19:42:52 +00:00
|
|
|
hangup_func = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hangup_func_arg) {
|
2008-07-16 14:58:00 +00:00
|
|
|
Py_DECREF(hangup_func_arg);
|
2008-07-11 19:42:52 +00:00
|
|
|
hangup_func_arg = NULL;
|
|
|
|
}
|
2006-12-21 17:11:43 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (cb_function) {
|
2008-07-16 14:58:00 +00:00
|
|
|
Py_DECREF(cb_function);
|
2008-07-11 19:42:52 +00:00
|
|
|
cb_function = NULL;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (cb_arg) {
|
2008-07-16 14:58:00 +00:00
|
|
|
Py_DECREF(cb_arg);
|
2008-07-11 19:42:52 +00:00
|
|
|
cb_arg = NULL;
|
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (Self) {
|
2008-07-16 14:58:00 +00:00
|
|
|
Py_DECREF(Self);
|
2008-07-11 19:42:52 +00:00
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
bool Session::begin_allow_threads()
|
2008-05-27 04:54:52 +00:00
|
|
|
{
|
2007-06-09 23:07:00 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
do_hangup_hook();
|
2007-05-10 18:51:47 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (!TS) {
|
|
|
|
TS = PyEval_SaveThread();
|
2008-07-16 21:06:14 +00:00
|
|
|
if (channel) {
|
|
|
|
switch_channel_set_private(channel, "SwapInThreadState", TS);
|
|
|
|
}
|
2008-07-11 19:42:52 +00:00
|
|
|
return true;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2006-12-21 17:11:43 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
return false;
|
2007-06-22 19:14:53 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
bool Session::end_allow_threads()
|
2008-05-27 04:54:52 +00:00
|
|
|
{
|
2007-06-20 08:56:34 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (!TS) {
|
|
|
|
return false;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2007-06-20 08:56:34 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
PyEval_RestoreThread(TS);
|
|
|
|
TS = NULL;
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-16 21:06:14 +00:00
|
|
|
if (channel) {
|
|
|
|
switch_channel_set_private(channel, "SwapInThreadState", NULL);
|
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
do_hangup_hook();
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
return true;
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
void Session::setPython(PyObject *state)
|
|
|
|
{
|
|
|
|
Py = state;
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
void Session::setSelf(PyObject *state)
|
|
|
|
{
|
|
|
|
Self = state;
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
PyObject *Session::getPython()
|
|
|
|
{
|
|
|
|
return Py;
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
bool Session::ready()
|
|
|
|
{
|
|
|
|
bool r;
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
sanity_check(false);
|
|
|
|
r = switch_channel_ready(channel) != 0;
|
2008-07-11 21:56:18 +00:00
|
|
|
|
|
|
|
/*! this is called every time ready is called as a workaround to
|
|
|
|
make it threadsafe. it sets a flag, and all the places where it
|
|
|
|
comes in and out of threadswap, check it. so the end result is
|
|
|
|
you still get the hangup hook executed pretty soon after you
|
|
|
|
hangup. */
|
2008-07-11 19:42:52 +00:00
|
|
|
do_hangup_hook();
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
return r;
|
|
|
|
}
|
2007-06-20 08:56:34 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
void Session::check_hangup_hook()
|
|
|
|
{
|
|
|
|
if (hangup_func && (hook_state == CS_HANGUP || hook_state == CS_ROUTING)) {
|
|
|
|
hh++;
|
|
|
|
}
|
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
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) {
|
2008-07-16 14:58:00 +00:00
|
|
|
mod_python_conjure_session(NULL, session);
|
2008-07-11 19:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
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();
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
void Session::setHangupHook(PyObject *pyfunc, PyObject *arg)
|
|
|
|
{
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (!PyCallable_Check(pyfunc)) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hangup hook is not a python function.\n");
|
|
|
|
return;
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (hangup_func) {
|
|
|
|
if (session) {
|
|
|
|
switch_core_event_hook_remove_state_change(session, python_hanguphook);
|
|
|
|
}
|
|
|
|
Py_XDECREF(hangup_func);
|
|
|
|
hangup_func = NULL;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (hangup_func_arg) {
|
|
|
|
Py_XDECREF(hangup_func_arg);
|
|
|
|
hangup_func_arg = NULL;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2008-07-11 19:42:52 +00:00
|
|
|
|
|
|
|
hangup_func = pyfunc;
|
|
|
|
hangup_func_arg = arg;
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
Py_XINCREF(hangup_func);
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
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);
|
2007-06-22 19:14:53 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
void Session::setInputCallback(PyObject *cbfunc, PyObject *funcargs)
|
2008-05-27 04:54:52 +00:00
|
|
|
{
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (!PyCallable_Check(cbfunc)) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hangup hook is not a python function.\n");
|
|
|
|
return;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (cb_function) {
|
|
|
|
Py_XDECREF(cb_function);
|
|
|
|
cb_function = NULL;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (cb_arg) {
|
|
|
|
Py_XDECREF(cb_arg);
|
|
|
|
cb_arg = NULL;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
cb_function = cbfunc;
|
|
|
|
cb_arg = funcargs;
|
|
|
|
args.buf = this;
|
|
|
|
switch_channel_set_private(channel, "CoreSession", this);
|
|
|
|
|
|
|
|
Py_XINCREF(cb_function);
|
|
|
|
|
|
|
|
if (cb_arg) {
|
|
|
|
Py_XINCREF(cb_arg);
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
args.input_callback = dtmf_callback;
|
|
|
|
ap = &args;
|
2007-06-22 19:14:53 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t itype)
|
2008-05-27 04:54:52 +00:00
|
|
|
{
|
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
PyObject *pyresult, *arglist, *io = NULL;
|
|
|
|
int ts = 0;
|
|
|
|
char *str = NULL, *what = "";
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (TS) {
|
|
|
|
ts++;
|
|
|
|
end_allow_threads();
|
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (!PyCallable_Check(cb_function)) {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "function not callable\n");
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itype == SWITCH_INPUT_TYPE_DTMF) {
|
|
|
|
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";
|
2008-07-16 14:58:00 +00:00
|
|
|
io = mod_python_conjure_event((switch_event_t *) input);
|
2008-05-27 04:54:52 +00:00
|
|
|
} else {
|
2008-07-11 19:42:52 +00:00
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unsupported type!\n");
|
|
|
|
return SWITCH_STATUS_FALSE;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (!Self) {
|
2008-07-16 14:58:00 +00:00
|
|
|
mod_python_conjure_session(NULL, session);
|
2008-07-11 19:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cb_arg) {
|
|
|
|
arglist = Py_BuildValue("(OsOO)", Self, what, io, cb_arg);
|
|
|
|
} else {
|
|
|
|
arglist = Py_BuildValue("(OsO)", Self, what, io);
|
|
|
|
}
|
2007-06-22 19:14:53 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if ((pyresult = PyEval_CallObject(cb_function, arglist))) {
|
|
|
|
str = (char *) PyString_AsString(pyresult);
|
|
|
|
} else {
|
|
|
|
PyErr_Print();
|
|
|
|
}
|
2007-06-20 08:56:34 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
Py_XDECREF(arglist);
|
|
|
|
Py_XDECREF(io);
|
2007-06-20 08:56:34 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (cb_arg) {
|
|
|
|
Py_XDECREF(cb_arg);
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2007-06-20 08:56:34 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (ts) {
|
|
|
|
begin_allow_threads();
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|
2007-06-15 17:25:41 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
if (str) {
|
|
|
|
return process_callback_result(str);
|
|
|
|
}
|
2008-05-27 04:54:52 +00:00
|
|
|
|
2008-07-11 19:42:52 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
2008-05-27 04:54:52 +00:00
|
|
|
}
|