freeswitch/src/mod/languages/mod_python3/freeswitch_python.cpp
2022-12-06 20:07:19 +03:00

353 lines
6.7 KiB
C++

#include <switch.h>
#include "freeswitch_python.h"
using namespace PYTHON;
#define py_init_vars() cb_function = cb_arg = hangup_func = hangup_func_arg = NULL; hh = mark = 0; TS = NULL
#define PyString_AsString PyUnicode_AsUTF8
#define PyString_Check PyUnicode_Check
Session::Session():CoreSession()
{
py_init_vars();
}
Session::Session(char *nuuid, CoreSession *a_leg):CoreSession(nuuid, a_leg)
{
py_init_vars();
}
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 Session::destroy(void)
{
if (!allocated) {
return;
}
if (session) {
if (!channel) {
channel = switch_core_session_get_channel(session);
}
switch_channel_set_private(channel, "CoreSession", NULL);
switch_core_event_hook_remove_state_change(session, python_hanguphook);
}
if (hangup_func) {
Py_DECREF(hangup_func);
hangup_func = NULL;
}
if (hangup_func_arg) {
Py_DECREF(hangup_func_arg);
hangup_func_arg = NULL;
}
if (cb_function) {
Py_DECREF(cb_function);
cb_function = NULL;
}
if (cb_arg) {
Py_DECREF(cb_arg);
cb_arg = NULL;
}
CoreSession::destroy();
}
Session::~Session()
{
destroy();
}
bool Session::begin_allow_threads()
{
do_hangup_hook();
if (!TS) {
TS = PyEval_SaveThread();
if (channel) {
switch_channel_set_private(channel, "SwapInThreadState", TS);
}
return true;
}
return false;
}
bool Session::end_allow_threads()
{
if (!TS) {
return false;
}
PyEval_RestoreThread(TS);
TS = NULL;
if (channel) {
switch_channel_set_private(channel, "SwapInThreadState", 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;
/*! 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. */
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 *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);
}
if (hangup_func_arg) {
arglist = Py_BuildValue("(OsO)", Self, what, hangup_func_arg);
} else {
arglist = Py_BuildValue("(Os)", Self, what);
}
#if PY_VERSION_HEX <= 0x03080000
if (!PyEval_CallObject(hangup_func, arglist)) {
PyErr_Print();
}
#else
if (!PyObject_CallObject(hangup_func, arglist)) {
PyErr_Print();
}
#endif
Py_XDECREF(arglist);
Py_XDECREF(hangup_func_arg);
}
}
}
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;
}
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 Session::unsetInputCallback(void)
{
if (cb_function) {
Py_XDECREF(cb_function);
cb_function = NULL;
}
if (cb_arg) {
Py_XDECREF(cb_arg);
cb_arg = NULL;
}
args.input_callback = NULL;
ap = NULL;
}
void Session::setInputCallback(PyObject *cbfunc, PyObject *funcargs)
{
if (!PyCallable_Check(cbfunc)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Hangup hook is not a python function.\n");
return;
}
if (cb_function) {
Py_XDECREF(cb_function);
cb_function = NULL;
}
if (cb_arg) {
Py_XDECREF(cb_arg);
cb_arg = NULL;
}
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);
}
args.input_callback = dtmf_callback;
ap = &args;
}
switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t itype)
{
PyObject *pyresult, *arglist, *io = NULL;
int ts = 0;
char *str = NULL, *what = (char*)"";
if (TS) {
ts++;
end_allow_threads();
}
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 = (char*)"dtmf";
} else if (itype == SWITCH_INPUT_TYPE_EVENT){
what = (char*)"event";
io = mod_python_conjure_event((switch_event_t *) input);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unsupported type!\n");
return SWITCH_STATUS_FALSE;
}
if (!Self) {
mod_python_conjure_session(NULL, session);
}
if (cb_arg) {
arglist = Py_BuildValue("(OsOO)", Self, what, io, cb_arg);
} else {
arglist = Py_BuildValue("(OsO)", Self, what, io);
}
#if PY_VERSION_HEX <= 0x03080000
pyresult = PyEval_CallObject(cb_function, arglist);
#else
pyresult = PyObject_CallObject(cb_function, arglist);
#endif
if (pyresult) {
str = (char *) PyString_AsString(pyresult);
} else {
PyErr_Print();
}
Py_XDECREF(arglist);
Py_XDECREF(io);
if (ts) {
begin_allow_threads();
}
if (str) {
return process_callback_result(str);
}
return SWITCH_STATUS_FALSE;
}