From 8cac85e9605766be1a5d062234b82fe22abb2105 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Thu, 23 Nov 2006 21:50:02 +0000 Subject: Updated Python project with base PJSUA API git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@824 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip-apps/src/py_pjsua/pjsua.py | 81 +- pjsip-apps/src/py_pjsua/py_pjsua.c | 2321 ++++++++++++++++++++++++++++++++++-- 2 files changed, 2313 insertions(+), 89 deletions(-) (limited to 'pjsip-apps/src/py_pjsua') diff --git a/pjsip-apps/src/py_pjsua/pjsua.py b/pjsip-apps/src/py_pjsua/pjsua.py index cae3480f..d5b9af36 100644 --- a/pjsip-apps/src/py_pjsua/pjsua.py +++ b/pjsip-apps/src/py_pjsua/pjsua.py @@ -1,17 +1,82 @@ -# import module py_pjsua import py_pjsua -print '''Testing py_pjsua.create : ''' status = py_pjsua.create() print "py status " + `status` -# perror -print '''Testing error code 70006 : ''' -py_pjsua.perror("py_pjsua","hello",70006) -# test py_pjsua.destroy -print '''Testing py_pjsua.destroy : ''' +# +# Create configuration objects +# +ua_cfg = py_pjsua.Config() +log_cfg = py_pjsua.Logging_Config() +media_cfg = py_pjsua.Media_Config() + +# +# Logging callback. +# +def logging_cb1(level, str, len): + print str, + + +# +# Initialize configs with default values. +# +py_pjsua.config_default(ua_cfg) +py_pjsua.logging_config_default(log_cfg) +py_pjsua.media_config_default(media_cfg) + +# +# Configure logging +# +log_cfg.cb = logging_cb1 +log_cfg.console_level = 4 + +# +# Initialize pjsua! +# +status = py_pjsua.init(ua_cfg, log_cfg, media_cfg); +print "py status after initialization :" + `status` + + +# +# Start pjsua! +# +status = py_pjsua.start() +if status != 0: + exit(1) + + +message = py_pjsua.Msg_Data() +py_pjsua.msg_data_init(message) +print "identitas object message data :" + `message` + +sipaddr = 'sip:167.205.34.99' +print "checking sip address [%s] : %d" % (sipaddr, py_pjsua.verify_sip_url(sipaddr)) + +sipaddr = '167.205.34.99' +print "checking invalid sip address [%s] : %d" % (sipaddr, py_pjsua.verify_sip_url(sipaddr)) + +object = py_pjsua.get_pjsip_endpt() +print "identitas Endpoint :" + `object` + "" + +mediaend = py_pjsua.get_pjmedia_endpt() +print "identitas Media Endpoint :" + `mediaend` + "" + +pool = py_pjsua.get_pool_factory() +print "identitas pool factory :" + `pool` + "" + +status = py_pjsua.handle_events(3000) +print "py status after 3 second of blocking wait :" + `status` + + + +# end of new testrun + +# + +py_pjsua.perror("saya","hallo",70006) + status = py_pjsua.destroy() print "py status " + `status` -print '''End Of py_pjsua''' + diff --git a/pjsip-apps/src/py_pjsua/py_pjsua.c b/pjsip-apps/src/py_pjsua/py_pjsua.c index 4ca49b82..427fda7e 100644 --- a/pjsip-apps/src/py_pjsua/py_pjsua.c +++ b/pjsip-apps/src/py_pjsua/py_pjsua.c @@ -1,88 +1,2247 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2006 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #include +#include "structmember.h" #include +#define THIS_FILE "main.c" -static PyObject *py_pjsua_perror(PyObject *pSelf, PyObject *pArgs) { - const char *sender; - const char *title; - pj_status_t status; - if (!PyArg_ParseTuple(pArgs, "ssi", &sender, &title, &status)) { - return NULL; - } - pjsua_perror(sender, title, status); - Py_INCREF(Py_None); - return Py_None; -} -static PyObject *py_pjsua_create(PyObject *pSelf, PyObject *pArgs) { - pj_status_t status; - if (!PyArg_ParseTuple(pArgs, "")) { - return NULL; - } - status = pjsua_create(); - printf("status %d\n",status); - return Py_BuildValue("i",status); -} -static PyObject *py_pjsua_start(PyObject *pSelf, PyObject *pArgs) { - pj_status_t status; - if (!PyArg_ParseTuple(pArgs, "")) { - return NULL; - } - status = pjsua_start(); - printf("status %d\n",status); - return Py_BuildValue("i",status); -} - -static PyObject *py_pjsua_destroy(PyObject *pSelf, PyObject *pArgs) { - pj_status_t status; - if (!PyArg_ParseTuple(pArgs, "")) { - return NULL; - } - status = pjsua_destroy(); - printf("status %d\n",status); - return Py_BuildValue("i",status); -} -static PyObject *py_pjsua_handle_events(PyObject *pSelf, PyObject *pArgs) { - int ret; - unsigned msec; - if (!PyArg_ParseTuple(pArgs, "i", &msec)) { - return NULL; - } - ret = pjsua_handle_events(msec); - printf("return %d\n",ret); - return Py_BuildValue("i",ret); -} -static PyObject *py_pjsua_verify_sip_url(PyObject *pSelf, PyObject *pArgs) { - pj_status_t status; - const char *url; - if (!PyArg_ParseTuple(pArgs, "s", &url)) { - return NULL; - } - status = pjsua_verify_sip_url(url); - printf("status %d\n",status); - return Py_BuildValue("i",status); -} -/* doc string */ -static char pjsua_perror_doc[] = "Display error message for the specified error code"; -static char pjsua_create_doc[] = "Instantiate pjsua application"; -static char pjsua_start_doc[] = "Application is recommended to call this function after all initialization is done, so that the library can do additional checking set up additional"; -static char pjsua_destroy_doc[] = "Destroy pjsua"; -static char pjsua_handle_events_doc[] = "Poll pjsua for events, and if necessary block the caller thread for the specified maximum interval (in miliseconds)"; -static char pjsua_verify_sip_url_doc[] = "Verify that valid SIP url is given"; - -/* Map of function names to functions */ -static PyMethodDef py_pjsua_methods[] = { - {"perror", py_pjsua_perror, METH_VARARGS, pjsua_perror_doc}, - {"create", py_pjsua_create, METH_VARARGS, pjsua_create_doc}, - {"start", py_pjsua_start, METH_VARARGS, pjsua_start_doc}, - {"destroy", py_pjsua_destroy, METH_VARARGS, pjsua_destroy_doc}, - {"handle_events", py_pjsua_handle_events, METH_VARARGS, pjsua_handle_events_doc}, - {"verify_sip_url", py_pjsua_verify_sip_url, METH_VARARGS, pjsua_verify_sip_url_doc}, - {NULL, NULL} /* End of functions */ -}; - - -PyMODINIT_FUNC +static PyObject* obj_reconfigure_logging; +static PyObject* obj_logging_init; + +/* + * cb_reconfigure_logging + * declares method for reconfiguring logging process for callback struct + */ +static void cb_reconfigure_logging(int level, const char *data, pj_size_t len) +{ + if (PyCallable_Check(obj_reconfigure_logging)) + { + PyObject_CallFunctionObjArgs( + obj_reconfigure_logging, Py_BuildValue("i",level), + PyString_FromString(data), Py_BuildValue("i",len), NULL + ); + } +} + + +/* + * cb_logging_init + * declares method logging_init for callback struct + */ +static void cb_logging_init(int level, const char *data, pj_size_t len) +{ + if (PyCallable_Check(obj_logging_init)) + { + //PyObject_CallFunction(obj_logging_init,"iSi",level,data,len); + //printf("level : %d data : %s len : %d\n",level, data, len); + PyObject_CallFunctionObjArgs( + obj_logging_init, Py_BuildValue("i",level), + PyString_FromString(data), Py_BuildValue("i",len), NULL + ); + } +} + + +/* + * pjsip_event_Object + * C/python typewrapper for event struct + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pjsip_event * event; +} pjsip_event_Object; + + +/* + * pjsip_event_Type + * event struct signatures + */ +static PyTypeObject pjsip_event_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.PJSIP_Event", /*tp_name*/ + sizeof(pjsip_event_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "pjsip_event objects", /*tp_doc */ +}; + + +/* + * pjsip_rx_data_Object + * C/python typewrapper for RX data struct + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pjsip_rx_data * rdata; +} pjsip_rx_data_Object; + + +/* + * pjsip_rx_data_Type + */ +static PyTypeObject pjsip_rx_data_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.PJSIP_RX_Data", /*tp_name*/ + sizeof(pjsip_rx_data_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "pjsip_rx_data objects", /*tp_doc*/ +}; + + +/* + * callback_Object + * C/python typewrapper for callback struct + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + PyObject * on_call_state; + PyObject * on_incoming_call; + PyObject * on_call_media_state; + PyObject * on_call_transfer_request; + PyObject * on_call_transfer_status; + PyObject * on_call_replace_request; + PyObject * on_call_replaced; + PyObject * on_reg_state; + PyObject * on_buddy_state; + PyObject * on_pager; + PyObject * on_pager_status; + PyObject * on_typing; + +} callback_Object; + + +/* + * The global callback object. + */ +static callback_Object * obj_callback; + + +/* + * cb_on_call_state + * declares method on_call_state for callback struct + */ +static void cb_on_call_state(pjsua_call_id call_id, pjsip_event *e) +{ + if (PyCallable_Check(obj_callback->on_call_state)) + { + pjsip_event_Object * obj = + (pjsip_event_Object *)PyType_GenericNew(&pjsip_event_Type, + NULL, NULL); + obj->event = e; + + PyObject_CallFunctionObjArgs( + obj_callback->on_call_state,Py_BuildValue("i",call_id),obj,NULL + ); + } +} + + +/* + * cb_on_incoming_call + * declares method on_incoming_call for callback struct + */ +static void cb_on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, + pjsip_rx_data *rdata) +{ + if (PyCallable_Check(obj_callback->on_incoming_call)) + { + pjsip_rx_data_Object * obj = (pjsip_rx_data_Object *) + PyType_GenericNew(&pjsip_rx_data_Type, + NULL, NULL); + obj->rdata = rdata; + + PyObject_CallFunctionObjArgs( + obj_callback->on_incoming_call, + Py_BuildValue("i",acc_id), + Py_BuildValue("i",call_id), + obj, + NULL + ); + } +} + + +/* + * cb_on_call_media_state + * declares method on_call_media_state for callback struct + */ +static void cb_on_call_media_state(pjsua_call_id call_id) +{ + if (PyCallable_Check(obj_callback->on_call_media_state)) + { + PyObject_CallFunction(obj_callback->on_call_media_state,"i",call_id); + } +} + + +/* + * Notify application on call being transfered. + */ +static void cb_on_call_transfer_request(pjsua_call_id call_id, + const pj_str_t *dst, + pjsip_status_code *code) +{ + if (PyCallable_Check(obj_callback->on_call_transfer_request)) + { + PyObject_CallFunctionObjArgs( + obj_callback->on_call_transfer_request, + Py_BuildValue("i",call_id), + PyString_FromStringAndSize(dst->ptr, dst->slen), + Py_BuildValue("i",*code), + NULL + ); + } +} + + +/* + * Notify application of the status of previously sent call + * transfer request. Application can monitor the status of the + * call transfer request, for example to decide whether to + * terminate existing call. + */ +static void cb_on_call_transfer_status( pjsua_call_id call_id, + int status_code, + const pj_str_t *status_text, + pj_bool_t final, + pj_bool_t *p_cont) +{ + if (PyCallable_Check(obj_callback->on_call_transfer_status)) + { + PyObject_CallFunctionObjArgs( + obj_callback->on_call_transfer_status, + Py_BuildValue("i",call_id), + Py_BuildValue("i",status_code), + PyString_FromStringAndSize(status_text->ptr, status_text->slen), + Py_BuildValue("i",final), + Py_BuildValue("i",*p_cont), + NULL + ); + } +} + + +/* + * Notify application about incoming INVITE with Replaces header. + * Application may reject the request by setting non-2xx code. + */ +static void cb_on_call_replace_request( pjsua_call_id call_id, + pjsip_rx_data *rdata, + int *st_code, + pj_str_t *st_text) +{ + if (PyCallable_Check(obj_callback->on_call_replace_request)) + { + pjsip_rx_data_Object * obj = (pjsip_rx_data_Object *) + PyType_GenericNew(&pjsip_rx_data_Type, + NULL, NULL); + obj->rdata = rdata; + + PyObject_CallFunctionObjArgs( + obj_callback->on_call_replace_request, + Py_BuildValue("i",call_id), + obj, + Py_BuildValue("i",*st_code), + PyString_FromStringAndSize(st_text->ptr, st_text->slen), + NULL + ); + } +} + + +/* + * Notify application that an existing call has been replaced with + * a new call. This happens when PJSUA-API receives incoming INVITE + * request with Replaces header. + */ +static void cb_on_call_replaced(pjsua_call_id old_call_id, + pjsua_call_id new_call_id) +{ + if (PyCallable_Check(obj_callback->on_call_replaced)) + { + PyObject_CallFunctionObjArgs( + obj_callback->on_call_replaced, + Py_BuildValue("i",old_call_id), + Py_BuildValue("i",old_call_id), + NULL + ); + } +} + + +/* + * cb_on_reg_state + * declares method on_reg_state for callback struct + */ +static void cb_on_reg_state(pjsua_acc_id acc_id) +{ + if (PyCallable_Check(obj_callback->on_reg_state)) + { + PyObject_CallFunction(obj_callback->on_reg_state,"i",acc_id); + } +} + + +/* + * cb_on_buddy_state + * declares method on_buddy state for callback struct + */ +static void cb_on_buddy_state(pjsua_buddy_id buddy_id) +{ + if (PyCallable_Check(obj_callback->on_buddy_state)) + { + PyObject_CallFunction(obj_callback->on_buddy_state,"i",buddy_id); + } +} + +/* + * cb_on_pager + * * declares method on_pager for callback struct + */ +static void cb_on_pager(pjsua_call_id call_id, const pj_str_t *from, + const pj_str_t *to, const pj_str_t *contact, + const pj_str_t *mime_type, const pj_str_t *body) +{ + if (PyCallable_Check(obj_callback->on_pager)) + { + PyObject_CallFunctionObjArgs( + obj_callback->on_pager,Py_BuildValue("i",call_id), + PyString_FromStringAndSize(from->ptr, from->slen), + PyString_FromStringAndSize(to->ptr, to->slen), + PyString_FromStringAndSize(contact->ptr, contact->slen), + PyString_FromStringAndSize(mime_type->ptr, mime_type->slen), + PyString_FromStringAndSize(body->ptr, body->slen), NULL + ); + } +} + + +/* + * cb_on_pager_status + * declares method on_pager_status for callback struct + */ +static void cb_on_pager_status(pjsua_call_id call_id, const pj_str_t *to, + const pj_str_t *body, void *user_data, + pjsip_status_code status, + const pj_str_t *reason) +{ + PyObject * obj = PyType_GenericNew(user_data, NULL, NULL); + if (PyCallable_Check(obj_callback->on_pager)) + { + PyObject_CallFunctionObjArgs( + obj_callback->on_pager,Py_BuildValue("i",call_id), + PyString_FromStringAndSize(to->ptr, to->slen), + PyString_FromStringAndSize(body->ptr, body->slen),obj, + Py_BuildValue("i",status),PyString_FromStringAndSize(reason->ptr, + reason->slen),NULL + ); + } +} + + +/* + * cb_on_typing + * declares method on_typing for callback struct + */ +static void cb_on_typing(pjsua_call_id call_id, const pj_str_t *from, + const pj_str_t *to, const pj_str_t *contact, + pj_bool_t is_typing) +{ + if (PyCallable_Check(obj_callback->on_typing)) + { + PyObject_CallFunctionObjArgs( + obj_callback->on_typing,Py_BuildValue("i",call_id), + PyString_FromStringAndSize(from->ptr, from->slen), + PyString_FromStringAndSize(to->ptr, to->slen), + PyString_FromStringAndSize(contact->ptr, contact->slen), + Py_BuildValue("i",is_typing),NULL + ); + } +} + + +/* + * callback_dealloc + * destructor function for callback struct + */ +static void callback_dealloc(callback_Object* self) +{ + Py_XDECREF(self->on_call_state); + Py_XDECREF(self->on_incoming_call); + Py_XDECREF(self->on_call_media_state); + Py_XDECREF(self->on_call_transfer_request); + Py_XDECREF(self->on_call_transfer_status); + Py_XDECREF(self->on_call_replace_request); + Py_XDECREF(self->on_call_replaced); + Py_XDECREF(self->on_reg_state); + Py_XDECREF(self->on_buddy_state); + Py_XDECREF(self->on_pager); + Py_XDECREF(self->on_pager_status); + Py_XDECREF(self->on_typing); + self->ob_type->tp_free((PyObject*)self); +} + + +/* + * callback_new + * * declares constructor for callback struct + */ +static PyObject * callback_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + callback_Object *self; + + self = (callback_Object *)type->tp_alloc(type, 0); + if (self != NULL) + { + Py_INCREF(Py_None); + self->on_call_state = Py_None; + if (self->on_call_state == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_incoming_call = Py_None; + if (self->on_incoming_call == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_call_media_state = Py_None; + if (self->on_call_media_state == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_call_transfer_request = Py_None; + if (self->on_call_transfer_request == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_call_transfer_status = Py_None; + if (self->on_call_transfer_status == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_call_replace_request = Py_None; + if (self->on_call_replace_request == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_call_replaced = Py_None; + if (self->on_call_replaced == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_reg_state = Py_None; + if (self->on_reg_state == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_buddy_state = Py_None; + if (self->on_buddy_state == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_pager = Py_None; + if (self->on_pager == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_pager_status = Py_None; + if (self->on_pager_status == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + Py_INCREF(Py_None); + self->on_typing = Py_None; + if (self->on_typing == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + } + + return (PyObject *)self; +} + + +/* + * callback_members + * declares available functions for callback object + */ +static PyMemberDef callback_members[] = +{ + { + "on_call_state", T_OBJECT_EX, offsetof(callback_Object, on_call_state), + 0, "Notify application when invite state has changed. Application may " + "then query the call info to get the detail call states." + }, + { + "on_incoming_call", T_OBJECT_EX, + offsetof(callback_Object, on_incoming_call), 0, + "Notify application on incoming call." + }, + { + "on_call_media__state", T_OBJECT_EX, + offsetof(callback_Object, on_call_media_state), 0, + "Notify application when media state in the call has changed. Normal " + "application would need to implement this callback, e.g. to connect " + "the call's media to sound device." + }, + { + "on_call_transfer_request", T_OBJECT_EX, + offsetof(callback_Object, on_call_transfer_request), 0, + "Notify application on call being transfered. " + "Application can decide to accept/reject transfer request " + "by setting the code (default is 200). When this callback " + "is not defined, the default behavior is to accept the " + "transfer." + }, + { + "on_call_transfer_status", T_OBJECT_EX, + offsetof(callback_Object, on_call_transfer_status), 0, + "Notify application of the status of previously sent call " + "transfer request. Application can monitor the status of the " + "call transfer request, for example to decide whether to " + "terminate existing call." + }, + { + "on_call_replace_request", T_OBJECT_EX, + offsetof(callback_Object, on_call_replace_request), 0, + "Notify application about incoming INVITE with Replaces header. " + "Application may reject the request by setting non-2xx code." + }, + { + "on_call_replaced", T_OBJECT_EX, + offsetof(callback_Object, on_call_replaced), 0, + "Notify application that an existing call has been replaced with " + "a new call. This happens when PJSUA-API receives incoming INVITE " + "request with Replaces header." + " " + "After this callback is called, normally PJSUA-API will disconnect " + "old_call_id and establish new_call_id." + }, + { + "on_reg_state", T_OBJECT_EX, + offsetof(callback_Object, on_reg_state), 0, + "Notify application when registration status has changed. Application " + "may then query the account info to get the registration details." + }, + { + "on_buddy_state", T_OBJECT_EX, + offsetof(callback_Object, on_buddy_state), 0, + "Notify application when the buddy state has changed. Application may " + "then query the buddy into to get the details." + }, + { + "on_pager", T_OBJECT_EX, offsetof(callback_Object, on_pager), 0, + "Notify application on incoming pager (i.e. MESSAGE request). " + "Argument call_id will be -1 if MESSAGE request is not related to an " + "existing call." + }, + { + "on_pager_status", T_OBJECT_EX, + offsetof(callback_Object, on_pager_status), 0, + "Notify application about the delivery status of outgoing pager " + "request." + }, + { + "on_typing", T_OBJECT_EX, offsetof(callback_Object, on_typing), 0, + "Notify application about typing indication." + }, + {NULL} /* Sentinel */ +}; + + +/* + * callback_Type + * callback class definition + */ +static PyTypeObject callback_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.Callback", /*tp_name*/ + sizeof(callback_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)callback_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Callback objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + callback_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + callback_new, /* tp_new */ + +}; + + +/* + * media_config_Object + * C/Python wrapper for media_config object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + unsigned clock_rate; + unsigned max_media_ports; + int has_ioqueue; + unsigned thread_cnt; + unsigned quality; + unsigned ptime; + int no_vad; + unsigned ilbc_mode; + unsigned tx_drop_pct; + unsigned rx_drop_pct; + unsigned ec_options; + unsigned ec_tail_len; +} media_config_Object; + + +/* + * media_config_members + * declares attributes accessible from both C and Python for media_config file + */ +static PyMemberDef media_config_members[] = +{ + { + "clock_rate", T_INT, offsetof(media_config_Object, clock_rate), 0, + "Clock rate to be applied to the conference bridge. If value is zero, " + "default clock rate will be used (16KHz)." + }, + { + "max_media_ports", T_INT, + offsetof(media_config_Object, max_media_ports), 0, + "Specify maximum number of media ports to be created in the " + "conference bridge. Since all media terminate in the bridge (calls, " + "file player, file recorder, etc), the value must be large enough to " + "support all of them. However, the larger the value, the more " + "computations are performed." + }, + { + "has_ioqueue", T_INT, offsetof(media_config_Object, has_ioqueue), 0, + "Specify whether the media manager should manage its own ioqueue for " + "the RTP/RTCP sockets. If yes, ioqueue will be created and at least " + "one worker thread will be created too. If no, the RTP/RTCP sockets " + "will share the same ioqueue as SIP sockets, and no worker thread is " + "needed." + }, + { + "thread_cnt", T_INT, offsetof(media_config_Object, thread_cnt), 0, + "Specify the number of worker threads to handle incoming RTP packets. " + "A value of one is recommended for most applications." + }, + { + "quality", T_INT, offsetof(media_config_Object, quality), 0, + "The media quality also sets speex codec quality/complexity to the " + "number." + }, + { + "ptime", T_INT, offsetof(media_config_Object, ptime), 0, + "Specify default ptime." + }, + { + "no_vad", T_INT, offsetof(media_config_Object, no_vad), 0, + "Disable VAD?" + }, + { + "ilbc_mode", T_INT, offsetof(media_config_Object, ilbc_mode), 0, + "iLBC mode (20 or 30)." + }, + { + "tx_drop_pct", T_INT, offsetof(media_config_Object, tx_drop_pct), 0, + "Percentage of RTP packet to drop in TX direction (to simulate packet " + "lost)." + }, + { + "rx_drop_pct", T_INT, offsetof(media_config_Object, rx_drop_pct), 0, + "Percentage of RTP packet to drop in RX direction (to simulate packet " + "lost)."}, + { + "ec_options", T_INT, offsetof(media_config_Object, ec_options), 0, + "Echo canceller options (see #pjmedia_echo_create())" + }, + { + "ec_tail_len", T_INT, offsetof(media_config_Object, ec_tail_len), 0, + "Echo canceller tail length, in miliseconds." + }, + {NULL} /* Sentinel */ +}; + + +/* + * media_config_Type + */ +static PyTypeObject media_config_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.Media_Config", /*tp_name*/ + sizeof(media_config_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Media Config objects", /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + media_config_members, /* tp_members */ + +}; + + +/* + * config_Object + * attribute list for config object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + unsigned max_calls; + unsigned thread_cnt; + unsigned outbound_proxy_cnt; + pj_str_t outbound_proxy[4]; + unsigned cred_count; + pjsip_cred_info cred_info[PJSUA_ACC_MAX_PROXIES]; + callback_Object * cb; + PyObject * user_agent; +} config_Object; + + +/* + * config_dealloc + * deallocates a config object + */ +static void config_dealloc(config_Object* self) +{ + Py_XDECREF(self->cb); + Py_XDECREF(self->user_agent); + self->ob_type->tp_free((PyObject*)self); +} + +/* + * config_new + * config object constructor + */ +static PyObject *config_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + config_Object *self; + + self = (config_Object *)type->tp_alloc(type, 0); + if (self != NULL) + { + self->user_agent = PyString_FromString(""); + if (self->user_agent == NULL) + { + Py_DECREF(self); + return NULL; + } + self->cb = (callback_Object *)PyType_GenericNew( + &callback_Type, NULL, NULL + ); + if (self->cb == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + } + return (PyObject *)self; +} + + +/* + * config_members + * attribute list accessible from Python/C + */ +static PyMemberDef config_members[] = +{ + { + "max_calls", T_INT, offsetof(config_Object, max_calls), 0, + "Maximum calls to support (default: 4) " + }, + { + "thread_cnt", T_INT, offsetof(config_Object, thread_cnt), 0, + "Number of worker threads. Normally application will want to have at " + "least one worker thread, unless when it wants to poll the library " + "periodically, which in this case the worker thread can be set to " + "zero." + }, + { + "outbound_proxy_cnt", T_INT, + offsetof(config_Object, outbound_proxy_cnt), 0, + "Number of outbound proxies in the array." + }, + { + "cred_count", T_INT, offsetof(config_Object, cred_count), 0, + "Number of credentials in the credential array." + }, + { + "user_agent", T_OBJECT_EX, offsetof(config_Object, user_agent), 0, + "User agent string (default empty)" + }, + { + "cb", T_OBJECT_EX, offsetof(config_Object, cb), 0, + "Application callback." + }, + {NULL} /* Sentinel */ +}; + + +/* + * config_Type + * type wrapper for config class + */ +static PyTypeObject config_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.Config", /*tp_name*/ + sizeof(config_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)config_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Config objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + config_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + config_new, /* tp_new */ + +}; + + +/* + * logging_config_Object + * configuration class for logging_config object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + int msg_logging; + unsigned level; + unsigned console_level; + unsigned decor; + PyObject * log_filename; + PyObject * cb; +} logging_config_Object; + + +/* + * logging_config_dealloc + * deletes a logging config from memory + */ +static void logging_config_dealloc(logging_config_Object* self) +{ + Py_XDECREF(self->log_filename); + Py_XDECREF(self->cb); + self->ob_type->tp_free((PyObject*)self); +} + + +/* + * logging_config_new + * constructor for logging_config object + */ +static PyObject * logging_config_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + logging_config_Object *self; + + self = (logging_config_Object *)type->tp_alloc(type, 0); + if (self != NULL) + { + self->log_filename = PyString_FromString(""); + if (self->log_filename == NULL) + { + Py_DECREF(self); + return NULL; + } + Py_INCREF(Py_None); + self->cb = Py_None; + if (self->cb == NULL) + { + Py_DECREF(Py_None); + return NULL; + } + } + + return (PyObject *)self; +} + + +/* + * logging_config_members + */ +static PyMemberDef logging_config_members[] = +{ + { + "msg_logging", T_INT, offsetof(logging_config_Object, msg_logging), 0, + "Log incoming and outgoing SIP message? Yes!" + }, + { + "level", T_INT, offsetof(logging_config_Object, level), 0, + "Input verbosity level. Value 5 is reasonable." + }, + { + "console_level", T_INT, offsetof(logging_config_Object, console_level), + 0, "Verbosity level for console. Value 4 is reasonable." + }, + { + "decor", T_INT, offsetof(logging_config_Object, decor), 0, + "Log decoration" + }, + { + "log_filename", T_OBJECT_EX, + offsetof(logging_config_Object, log_filename), 0, + "Optional log filename" + }, + { + "cb", T_OBJECT_EX, offsetof(logging_config_Object, cb), 0, + "Optional callback function to be called to write log to application " + "specific device. This function will be called forlog messages on " + "input verbosity level." + }, + {NULL} /* Sentinel */ +}; + + + + +/* + * logging_config_Type + */ +static PyTypeObject logging_config_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.Logging_Config", /*tp_name*/ + sizeof(logging_config_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)logging_config_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Logging Config objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + logging_config_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + logging_config_new, /* tp_new */ + +}; + + +/* + * msg_data_Object + * typewrapper for MessageData class + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pjsip_hdr hdr_list; + PyObject * content_type; + PyObject * msg_body; +} msg_data_Object; + + +/* + * msg_data_dealloc + * deletes a msg_data + */ +static void msg_data_dealloc(msg_data_Object* self) +{ + Py_XDECREF(self->content_type); + Py_XDECREF(self->msg_body); + self->ob_type->tp_free((PyObject*)self); +} + + +/* + * msg_data_new + * constructor for msg_data object + */ +static PyObject * msg_data_new(PyTypeObject *type, PyObject *args, + PyObject *kwds) +{ + msg_data_Object *self; + + self = (msg_data_Object *)type->tp_alloc(type, 0); + if (self != NULL) + { + self->content_type = PyString_FromString(""); + if (self->content_type == NULL) + { + Py_DECREF(self); + return NULL; + } + self->msg_body = PyString_FromString(""); + if (self->msg_body == NULL) + { + Py_DECREF(self); + return NULL; + } + } + + return (PyObject *)self; +} + + +/* + * msg_data_members + */ +static PyMemberDef msg_data_members[] = +{ + { + "content_type", T_OBJECT_EX, offsetof(msg_data_Object, content_type), + 0, "MIME type of optional message body." + }, + { + "msg_body", T_OBJECT_EX, offsetof(msg_data_Object, msg_body), 0, + "Optional message body." + }, + {NULL} /* Sentinel */ +}; + + +/* + * msg_data_Type + */ +static PyTypeObject msg_data_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.Msg_Data", /*tp_name*/ + sizeof(msg_data_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)msg_data_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "msg_data objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + msg_data_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + msg_data_new, /* tp_new */ + +}; + + +/* + * pj_pool_Object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pj_pool_t * pool; +} pj_pool_Object; + + +/* + * pj_pool_Type + */ +static PyTypeObject pj_pool_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.PJ_Pool", /*tp_name*/ + sizeof(pj_pool_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "pj_pool_t objects", /* tp_doc */ + +}; + + +/* + * pjsip_endpoint_Object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pjsip_endpoint * endpt; +} pjsip_endpoint_Object; + + +/* + * pjsip_endpoint_Type + */ +static PyTypeObject pjsip_endpoint_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.PJSIP_Endpoint", /*tp_name*/ + sizeof(pjsip_endpoint_Object),/*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "pjsip_endpoint objects", /* tp_doc */ +}; + + +/* + * pjmedia_endpt_Object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pjmedia_endpt * endpt; +} pjmedia_endpt_Object; + + +/* + * pjmedia_endpt_Type + */ +static PyTypeObject pjmedia_endpt_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.PJMedia_Endpt", /*tp_name*/ + sizeof(pjmedia_endpt_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "pjmedia_endpt objects", /* tp_doc */ + +}; + + +/* + * pj_pool_factory_Object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pj_pool_factory * pool_fact; +} pj_pool_factory_Object; + + + +/* + * pj_pool_factory_Type + */ +static PyTypeObject pj_pool_factory_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.PJ_Pool_Factory",/*tp_name*/ + sizeof(pj_pool_factory_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "pj_pool_factory objects", /* tp_doc */ + +}; + + +/* + * pjsip_cred_info_Object + */ +typedef struct +{ + PyObject_HEAD + /* Type-specific fields go here. */ + pjsip_cred_info * cred; +} pjsip_cred_info_Object; + + +/* + * pjsip_cred_info_Type + */ +static PyTypeObject pjsip_cred_info_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "py_pjsua.PJSIP_Cred_Info",/*tp_name*/ + sizeof(pjsip_cred_info_Object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "pjsip_cred_info objects", /* tp_doc */ + +}; + + +/* + * py_pjsua_logging_config_default + */ +static PyObject *py_pjsua_logging_config_default(PyObject *pSelf, + PyObject *pArgs) +{ + logging_config_Object *obj; + pjsua_logging_config cfg; + + if (!PyArg_ParseTuple(pArgs, "O", &obj)) + { + return NULL; + } + /*pj_bzero(cfg, sizeof(*cfg)); + + cfg->msg_logging = obj->msg_logging; + cfg->level = obj->level; + cfg->console_level = obj->console_level; + cfg->decor = obj->decor;*/ + pjsua_logging_config_default(&cfg); + obj->msg_logging = cfg.msg_logging; + obj->level = cfg.level; + obj->console_level = cfg.console_level; + obj->decor = cfg.decor; + /*printf("msg logging : %d\n",obj->msg_logging); + printf("level : %d\n",obj->level); + printf("console level : %d\n",obj->console_level); + printf("decor : %d\n",obj->decor); + printf("str sebelum "); + printf(PyString_AsString(obj->log_filename)); + + Py_XDECREF(obj->log_filename); + obj->log_filename = PyString_FromString("oke"); + printf("\nstr sesudah "); + printf(PyString_AsString(obj->log_filename));*/ + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsua_config_default + */ +static PyObject *py_pjsua_config_default(PyObject *pSelf, PyObject *pArgs) +{ + config_Object *obj; + pjsua_config cfg; + + if (!PyArg_ParseTuple(pArgs, "O", &obj)) + { + return NULL; + } + pjsua_config_default(&cfg); + obj->max_calls = cfg.max_calls; + obj->thread_cnt = cfg.thread_cnt; + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsua_media_config_default + */ +static PyObject * py_pjsua_media_config_default(PyObject *pSelf, + PyObject *pArgs) +{ + media_config_Object *obj; + pjsua_media_config cfg; + if (!PyArg_ParseTuple(pArgs, "O", &obj)) + { + return NULL; + } + pjsua_media_config_default(&cfg); + obj->clock_rate = cfg.clock_rate; + obj->ec_options = cfg.ec_options; + obj->ec_tail_len = cfg.ec_tail_len; + obj->has_ioqueue = cfg.has_ioqueue; + obj->ilbc_mode = cfg.ilbc_mode; + obj->max_media_ports = cfg.max_media_ports; + obj->no_vad = cfg.no_vad; + obj->ptime = cfg.ptime; + obj->quality = cfg.quality; + obj->rx_drop_pct = cfg.rx_drop_pct; + obj->thread_cnt = cfg.thread_cnt; + obj->tx_drop_pct = cfg.tx_drop_pct; + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsua_msg_data_init + */ +static PyObject *py_pjsua_msg_data_init(PyObject *pSelf, PyObject *pArgs) +{ + msg_data_Object *obj; + pjsua_msg_data msg; + if (!PyArg_ParseTuple(pArgs, "O", &obj)) + { + return NULL; + } + pjsua_msg_data_init(&msg); + Py_XDECREF(obj->content_type); + obj->content_type = PyString_FromStringAndSize( + msg.content_type.ptr, msg.content_type.slen + ); + Py_XDECREF(obj->msg_body); + obj->msg_body = PyString_FromStringAndSize( + msg.msg_body.ptr, msg.msg_body.slen + ); + obj->hdr_list = msg.hdr_list; + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsua_logging_config_dup + */ +static PyObject *py_pjsua_logging_config_dup(PyObject *pSelf, PyObject *pArgs) +{ + pj_pool_Object *pool; + logging_config_Object *src; + logging_config_Object *dest; + pj_str_t strdest; + pj_str_t strsrc; + int len; + + if (!PyArg_ParseTuple(pArgs, "OOO", &pool, &dest, &src)) + { + return NULL; + } + pj_memcpy(dest, src, sizeof(*src)); + len = strlen(PyString_AsString(src->log_filename)); + strsrc.ptr = PyString_AsString(src->log_filename); + strsrc.slen = len; + pj_strdup_with_null(pool->pool, &strdest, &strsrc); + Py_XDECREF(dest->log_filename); + dest->log_filename = PyString_FromStringAndSize(strdest.ptr, strdest.slen); + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsua_config_dup + */ +static PyObject *py_pjsua_config_dup(PyObject *pSelf, PyObject *pArgs) +{ + pj_pool_Object *pool; + config_Object *src; + config_Object *dest; + pj_str_t strdest; + pj_str_t strsrc; + int len; + unsigned i; + + if (!PyArg_ParseTuple(pArgs, "OOO", &pool, &dest, &src)) + { + return NULL; + } + pj_memcpy(dest, src, sizeof(*src)); + + for (i=0; ioutbound_proxy_cnt; ++i) + { + pj_strdup_with_null( + pool->pool, &dest->outbound_proxy[i], &src->outbound_proxy[i] + ); + } + + for (i=0; icred_count; ++i) + { + pjsip_cred_dup(pool->pool, &dest->cred_info[i], &src->cred_info[i]); + } + len = strlen(PyString_AsString(src->user_agent)); + strsrc.ptr = PyString_AsString(src->user_agent); + strsrc.slen = len; + pj_strdup_with_null(pool->pool, &strdest, &strsrc); + Py_XDECREF(dest->user_agent); + dest->user_agent = PyString_FromStringAndSize(strdest.ptr, strdest.slen); + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsip_cred_dup + */ +static PyObject *py_pjsip_cred_dup(PyObject *pSelf, PyObject *pArgs) +{ + pj_pool_Object *pool; + pjsip_cred_info_Object *src; + pjsip_cred_info_Object *dest; + if (!PyArg_ParseTuple(pArgs, "OOO", &pool, &dest, &src)) + { + return NULL; + } + pjsip_cred_dup(pool->pool, dest->cred, src->cred); + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsua_reconfigure_logging + */ +static PyObject *py_pjsua_reconfigure_logging(PyObject *pSelf, PyObject *pArgs) +{ + logging_config_Object *log; + pjsua_logging_config cfg; + pj_status_t status; + + if (!PyArg_ParseTuple(pArgs, "O", &log)) + { + return NULL; + } + cfg.msg_logging = log->msg_logging; + cfg.level = log->level; + cfg.console_level = log->console_level; + cfg.decor = log->decor; + cfg.log_filename.ptr = PyString_AsString(log->log_filename); + cfg.log_filename.slen = strlen(cfg.log_filename.ptr); + Py_XDECREF(obj_reconfigure_logging); + obj_reconfigure_logging = log->cb; + Py_INCREF(obj_reconfigure_logging); + cfg.cb = &cb_reconfigure_logging; + status = pjsua_reconfigure_logging(&cfg); + return Py_BuildValue("i",status); +} + + +/* + * py_pjsua_pool_create + */ +static PyObject *py_pjsua_pool_create(PyObject *pSelf, PyObject *pArgs) +{ + pj_size_t init_size; + pj_size_t increment; + const char * name; + pj_pool_t *p; + pj_pool_Object *pool; + + if (!PyArg_ParseTuple(pArgs, "sII", &name, &init_size, &increment)) + { + return NULL; + } + /*printf("name : %s\n",name); + printf("init : %d\n", init_size); + printf("increment : %d\n", increment);*/ + p = pjsua_pool_create(name, init_size, increment); + pool = (pj_pool_Object *)PyType_GenericNew(&pj_pool_Type, NULL, NULL); + pool->pool = p; + return (PyObject *)pool; + +} + + +/* + * py_pjsua_get_pjsip_endpt + */ +static PyObject *py_pjsua_get_pjsip_endpt(PyObject *pSelf, PyObject *pArgs) +{ + pjsip_endpoint_Object *endpt; + pjsip_endpoint *e; + + if (!PyArg_ParseTuple(pArgs, "")) + { + return NULL; + } + e = pjsua_get_pjsip_endpt(); + endpt = (pjsip_endpoint_Object *)PyType_GenericNew( + &pjsip_endpoint_Type, NULL, NULL + ); + endpt->endpt = e; + return (PyObject *)endpt; +} + + +/* + * py_pjsua_get_pjmedia_endpt + */ +static PyObject *py_pjsua_get_pjmedia_endpt(PyObject *pSelf, PyObject *pArgs) +{ + pjmedia_endpt_Object *endpt; + pjmedia_endpt *e; + + if (!PyArg_ParseTuple(pArgs, "")) + { + return NULL; + } + e = pjsua_get_pjmedia_endpt(); + endpt = (pjmedia_endpt_Object *)PyType_GenericNew( + &pjmedia_endpt_Type, NULL, NULL + ); + endpt->endpt = e; + return (PyObject *)endpt; +} + + +/* + * py_pjsua_get_pool_factory + */ +static PyObject *py_pjsua_get_pool_factory(PyObject *pSelf, PyObject *pArgs) +{ + pj_pool_factory_Object *pool; + pj_pool_factory *p; + + if (!PyArg_ParseTuple(pArgs, "")) + { + return NULL; + } + p = pjsua_get_pool_factory(); + pool = (pj_pool_factory_Object *)PyType_GenericNew( + &pj_pool_factory_Type, NULL, NULL + ); + pool->pool_fact = p; + return (PyObject *)pool; +} + + +/* + * py_pjsua_perror + */ +static PyObject *py_pjsua_perror(PyObject *pSelf, PyObject *pArgs) +{ + const char *sender; + const char *title; + pj_status_t status; + if (!PyArg_ParseTuple(pArgs, "ssi", &sender, &title, &status)) + { + return NULL; + } + pjsua_perror(sender, title, status); + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * py_pjsua_create + */ +static PyObject *py_pjsua_create(PyObject *pSelf, PyObject *pArgs) +{ + pj_status_t status; + if (!PyArg_ParseTuple(pArgs, "")) + { + return NULL; + } + status = pjsua_create(); + printf("status %d\n",status); + return Py_BuildValue("i",status); +} + + +/* + * py_pjsua_init + */ +static PyObject *py_pjsua_init(PyObject *pSelf, PyObject *pArgs) +{ + pj_status_t status; + config_Object * ua_cfg; + logging_config_Object * log_cfg; + media_config_Object * media_cfg; + pjsua_config cfg_ua; + pjsua_logging_config cfg_log; + pjsua_media_config cfg_media; + unsigned i; + + if (!PyArg_ParseTuple(pArgs, "OOO", &ua_cfg, &log_cfg, &media_cfg)) + { + return NULL; + } + + pjsua_config_default(&cfg_ua); + pjsua_logging_config_default(&cfg_log); + pjsua_media_config_default(&cfg_media); + cfg_ua.cred_count = ua_cfg->cred_count; + for (i = 0; i < 4; i++) + { + cfg_ua.cred_info[i] = ua_cfg->cred_info[i]; + } + cfg_ua.max_calls = ua_cfg->max_calls; + for (i = 0; i < PJSUA_ACC_MAX_PROXIES; i++) + { + cfg_ua.outbound_proxy[i] = ua_cfg->outbound_proxy[i]; + } + + cfg_ua.outbound_proxy_cnt = ua_cfg->outbound_proxy_cnt; + cfg_ua.thread_cnt = ua_cfg->thread_cnt; + cfg_ua.user_agent.ptr = PyString_AsString(ua_cfg->user_agent); + cfg_ua.user_agent.slen = strlen(cfg_ua.user_agent.ptr); + + obj_callback = ua_cfg->cb; + cfg_ua.cb.on_call_state = &cb_on_call_state; + cfg_ua.cb.on_incoming_call = &cb_on_incoming_call; + cfg_ua.cb.on_call_media_state = &cb_on_call_media_state; + cfg_ua.cb.on_call_transfer_request = &cb_on_call_transfer_request; + cfg_ua.cb.on_call_transfer_status = &cb_on_call_transfer_status; + cfg_ua.cb.on_call_replace_request = &cb_on_call_replace_request; + cfg_ua.cb.on_call_replaced = &cb_on_call_replaced; + cfg_ua.cb.on_reg_state = &cb_on_reg_state; + cfg_ua.cb.on_buddy_state = &cb_on_buddy_state; + cfg_ua.cb.on_pager = &cb_on_pager; + cfg_ua.cb.on_pager_status = &cb_on_pager_status; + cfg_ua.cb.on_typing = &cb_on_typing; + + cfg_log.msg_logging = log_cfg->msg_logging; + cfg_log.level = log_cfg->level; + cfg_log.console_level = log_cfg->console_level; + cfg_log.decor = log_cfg->decor; + cfg_log.log_filename.ptr = PyString_AsString(log_cfg->log_filename); + cfg_log.log_filename.slen = strlen(cfg_log.log_filename.ptr); + Py_XDECREF(obj_logging_init); + obj_logging_init = log_cfg->cb; + Py_INCREF(obj_logging_init); + cfg_log.cb = &cb_logging_init; + + + cfg_media.clock_rate = media_cfg->clock_rate; + cfg_media.ec_options = media_cfg->ec_options; + cfg_media.ec_tail_len = media_cfg->ec_tail_len; + cfg_media.has_ioqueue = media_cfg->has_ioqueue; + cfg_media.ilbc_mode = media_cfg->ilbc_mode; + cfg_media.max_media_ports = media_cfg->max_media_ports; + cfg_media.no_vad = media_cfg->no_vad; + cfg_media.ptime = media_cfg->ptime; + cfg_media.quality = media_cfg->quality; + cfg_media.rx_drop_pct = media_cfg->rx_drop_pct; + cfg_media.thread_cnt = media_cfg->thread_cnt; + cfg_media.tx_drop_pct = media_cfg->tx_drop_pct; + + status = pjsua_init(&cfg_ua, &cfg_log, &cfg_media); + return Py_BuildValue("i",status); +} + + +/* + * py_pjsua_start + */ +static PyObject *py_pjsua_start(PyObject *pSelf, PyObject *pArgs) +{ + pj_status_t status; + if (!PyArg_ParseTuple(pArgs, "")) + { + return NULL; + } + status = pjsua_start(); + printf("status %d\n",status); + return Py_BuildValue("i",status); +} + + +/* + * py_pjsua_destroy + */ +static PyObject *py_pjsua_destroy(PyObject *pSelf, PyObject *pArgs) +{ + pj_status_t status; + if (!PyArg_ParseTuple(pArgs, "")) + { + return NULL; + } + status = pjsua_destroy(); + printf("status %d\n",status); + return Py_BuildValue("i",status); +} + + +/* + * py_pjsua_handle_events + */ +static PyObject *py_pjsua_handle_events(PyObject *pSelf, PyObject *pArgs) +{ + int ret; + unsigned msec; + if (!PyArg_ParseTuple(pArgs, "i", &msec)) + { + return NULL; + } + ret = pjsua_handle_events(msec); + printf("return %d\n",ret); + return Py_BuildValue("i",ret); +} + + +/* + * py_pjsua_verify_sip_url + */ +static PyObject *py_pjsua_verify_sip_url(PyObject *pSelf, PyObject *pArgs) +{ + pj_status_t status; + const char *url; + if (!PyArg_ParseTuple(pArgs, "s", &url)) + { + return NULL; + } + status = pjsua_verify_sip_url(url); + printf("status %d\n",status); + return Py_BuildValue("i",status); +} + + + + + + +/* + * error messages + */ + +static char pjsua_perror_doc[] = + "void py_pjsua.perror (string sender, string title, int status) " + "Display error message for the specified error code. Parameters: " + "sender: The log sender field; " + "title: Message title for the error; " + "status: Status code."; + +static char pjsua_create_doc[] = + "int py_pjsua.create (void) " + "Instantiate pjsua application. Application " + "must call this function before calling any other functions, to make sure " + "that the underlying libraries are properly initialized. Once this " + "function has returned success, application must call pjsua_destroy() " + "before quitting."; + +static char pjsua_init_doc[] = + "int py_pjsua.init (py_pjsua.Config ua_cfg, " + "py_pjsua.Logging_Config log_cfg, py_pjsua.Media_Config media_cfg) " + "Initialize pjsua with the specified settings. All the settings are " + "optional, and the default values will be used when the config is not " + "specified. Parameters: " + "ua_cfg : User agent configuration; " + "log_cfg : Optional logging configuration; " + "media_cfg : Optional media configuration."; + +static char pjsua_start_doc[] = + "int py_pjsua.start (void) " + "Application is recommended to call this function after all " + "initialization is done, so that the library can do additional checking " + "set up additional"; + +static char pjsua_destroy_doc[] = + "int py_pjsua.destroy (void) " + "Destroy pjsua This function must be called once PJSUA is created. To " + "make it easier for application, application may call this function " + "several times with no danger."; + +static char pjsua_handle_events_doc[] = + "int py_pjsua.handle_events (int msec_timeout) " + "Poll pjsua for events, and if necessary block the caller thread for the " + "specified maximum interval (in miliseconds) Parameters: " + "msec_timeout: Maximum time to wait, in miliseconds. " + "Returns: The number of events that have been handled during the poll. " + "Negative value indicates error, and application can retrieve the error " + "as (err = -return_value)."; + +static char pjsua_verify_sip_url_doc[] = + "int py_pjsua.verify_sip_url (string c_url) " + "Verify that valid SIP url is given Parameters: " + "c_url: The URL, as NULL terminated string."; + +static char pjsua_pool_create_doc[] = + "py_pjsua.PJ_Pool py_pjsua.pool_create (string name, int init_size, " + "int increment) " + "Create memory pool Parameters: " + "name: Optional pool name; " + "init_size: Initial size of the pool; " + "increment: Increment size."; + +static char pjsua_get_pjsip_endpt_doc[] = + "py_pjsua.PJSIP_Endpoint py_pjsua.get_pjsip_endpt (void) " + "Internal function to get SIP endpoint instance of pjsua, which is needed " + "for example to register module, create transports, etc. Probably is only " + "valid after pjsua_init() is called."; + +static char pjsua_get_pjmedia_endpt_doc[] = + "py_pjsua.PJMedia_Endpt py_pjsua.get_pjmedia_endpt (void) " + "Internal function to get media endpoint instance. Only valid after " + "pjsua_init() is called."; + +static char pjsua_get_pool_factory_doc[] = + "py_pjsua.PJ_Pool_Factory py_pjsua.get_pool_factory (void) " + "Internal function to get PJSUA pool factory. Only valid after " + "pjsua_init() is called."; + +static char pjsua_reconfigure_logging_doc[] = + "int py_pjsua.reconfigure_logging (py_pjsua.Logging_Config c) " + "Application can call this function at any time (after pjsua_create(), of " + "course) to change logging settings. Parameters: " + "c: Logging configuration."; + +static char pjsua_logging_config_default_doc[] = + "void py_pjsua.logging_config_default (py_pjsua.Logging_Config cfg) " + "Use this function to initialize logging config."; + +static char pjsua_config_default_doc[] = + "void py_pjsua.config_default (py_pjsua.Config cfg). Use this function to " + "initialize pjsua config. Parameters: " + "cfg: pjsua config to be initialized."; + +static char pjsua_media_config_default_doc[] = + "Use this function to initialize media config."; + +static char pjsua_logging_config_dup_doc[] = + "void py_pjsua.logging_config_dup (py_pjsua.PJ_Pool pool, " + "py_pjsua.Logging_Config dst, py_pjsua.Logging_Config src) " + "Use this function to duplicate logging config. Parameters: " + "pool: Pool to use; " + "dst: Destination config; " + "src: Source config."; + +static char pjsua_config_dup_doc[] = + "void py_pjsua.config_dup (py_pjsua.PJ_Pool pool, py_pjsua.Config dst, " + "py_pjsua.Config src) " + "Duplicate pjsua_config. "; + +static char pjsip_cred_dup_doc[] = + "void py_pjsua.pjsip_cred_dup (py_pjsua.PJ_Pool pool, " + "py_pjsua.PJSIP_Cred_Info dst, " + "py_pjsua.PJSIP_Cred_Info src) " + "Duplicate credential."; + +static char pjsua_msg_data_init_doc[] = + "void py_pjsua.msg_data_init (py_pjsua.Msg_Data msg_data) " + "Initialize message data Parameters: " + "msg_data: Message data to be initialized."; + + +/* + * Map of function names to functions + */ +static PyMethodDef py_pjsua_methods[] = +{ + { + "perror", py_pjsua_perror, METH_VARARGS, pjsua_perror_doc + }, + { + "create", py_pjsua_create, METH_VARARGS, pjsua_create_doc + }, + { + "init", py_pjsua_init, METH_VARARGS, pjsua_init_doc + }, + { + "start", py_pjsua_start, METH_VARARGS, pjsua_start_doc + }, + { + "destroy", py_pjsua_destroy, METH_VARARGS, pjsua_destroy_doc + }, + { + "handle_events", py_pjsua_handle_events, METH_VARARGS, + pjsua_handle_events_doc + }, + { + "verify_sip_url", py_pjsua_verify_sip_url, METH_VARARGS, + pjsua_verify_sip_url_doc + }, + { + "pool_create", py_pjsua_pool_create, METH_VARARGS, + pjsua_pool_create_doc + }, + { + "get_pjsip_endpt", py_pjsua_get_pjsip_endpt, METH_VARARGS, + pjsua_get_pjsip_endpt_doc + }, + { + "get_pjmedia_endpt", py_pjsua_get_pjmedia_endpt, METH_VARARGS, + pjsua_get_pjmedia_endpt_doc + }, + { + "get_pool_factory", py_pjsua_get_pool_factory, METH_VARARGS, + pjsua_get_pool_factory_doc + }, + { + "reconfigure_logging", py_pjsua_reconfigure_logging, METH_VARARGS, + pjsua_reconfigure_logging_doc + }, + { + "logging_config_default", py_pjsua_logging_config_default, + METH_VARARGS, pjsua_logging_config_default_doc + }, + { + "config_default", py_pjsua_config_default, METH_VARARGS, + pjsua_config_default_doc + }, + { + "media_config_default", py_pjsua_media_config_default, METH_VARARGS, + pjsua_media_config_default_doc + }, + { + "logging_config_dup", py_pjsua_logging_config_dup, METH_VARARGS, + pjsua_logging_config_dup_doc + }, + { + "config_dup", py_pjsua_config_dup, METH_VARARGS, pjsua_config_dup_doc + }, + { + "pjsip_cred_dup", py_pjsip_cred_dup, METH_VARARGS, pjsip_cred_dup_doc + }, + { + "msg_data_init", py_pjsua_msg_data_init, METH_VARARGS, + pjsua_msg_data_init_doc + }, + {NULL, NULL} /* end of function list */ +}; + + + +/* + * Mapping C structs from and to Python objects & initializing object + */ +DL_EXPORT(void) initpy_pjsua(void) { - Py_InitModule("py_pjsua", py_pjsua_methods); + PyObject* m = NULL; + + if (PyType_Ready(&callback_Type) < 0) + return; + if (PyType_Ready(&config_Type) < 0) + return; + if (PyType_Ready(&logging_config_Type) < 0) + return; + if (PyType_Ready(&msg_data_Type) < 0) + return; + media_config_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&media_config_Type) < 0) + return; + pjsip_event_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&pjsip_event_Type) < 0) + return; + pjsip_rx_data_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&pjsip_rx_data_Type) < 0) + return; + pj_pool_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&pj_pool_Type) < 0) + return; + pjsip_endpoint_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&pjsip_endpoint_Type) < 0) + return; + pjmedia_endpt_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&pjmedia_endpt_Type) < 0) + return; + pj_pool_factory_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&pj_pool_factory_Type) < 0) + return; + pjsip_cred_info_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&pjsip_cred_info_Type) < 0) + return; + + m = Py_InitModule3( + "py_pjsua", py_pjsua_methods,"PJSUA-lib module for python" + ); + + Py_INCREF(&callback_Type); + PyModule_AddObject(m, "Callback", (PyObject *)&callback_Type); + + Py_INCREF(&config_Type); + PyModule_AddObject(m, "Config", (PyObject *)&config_Type); + + Py_INCREF(&media_config_Type); + PyModule_AddObject(m, "Media_Config", (PyObject *)&media_config_Type); + + Py_INCREF(&logging_config_Type); + PyModule_AddObject(m, "Logging_Config", (PyObject *)&logging_config_Type); + + Py_INCREF(&msg_data_Type); + PyModule_AddObject(m, "Msg_Data", (PyObject *)&msg_data_Type); + + Py_INCREF(&pjsip_event_Type); + PyModule_AddObject(m, "PJSIP_Event", (PyObject *)&pjsip_event_Type); + + Py_INCREF(&pjsip_rx_data_Type); + PyModule_AddObject(m, "PJSIP_RX_Data", (PyObject *)&pjsip_rx_data_Type); + + Py_INCREF(&pj_pool_Type); + PyModule_AddObject(m, "PJ_Pool", (PyObject *)&pj_pool_Type); + + Py_INCREF(&pjsip_endpoint_Type); + PyModule_AddObject(m, "PJSIP_Endpoint", (PyObject *)&pjsip_endpoint_Type); + + Py_INCREF(&pjmedia_endpt_Type); + PyModule_AddObject(m, "PJMedia_Endpt", (PyObject *)&pjmedia_endpt_Type); + + Py_INCREF(&pj_pool_factory_Type); + PyModule_AddObject( + m, "PJ_Pool_Factory", (PyObject *)&pj_pool_factory_Type + ); + + Py_INCREF(&pjsip_cred_info_Type); + PyModule_AddObject(m, "PJSIP_Cred_Info", + (PyObject *)&pjsip_cred_info_Type + ); + + +#ifdef PJSUA_INVALID_ID + /* + * Constant to identify invalid ID for all sorts of IDs. + */ + PyModule_AddIntConstant(m, "PJSUA_INVALID_ID", PJSUA_INVALID_ID); +#endif + +#ifdef PJSUA_ACC_MAX_PROXIES + /* + * Maximum proxies in account. + */ + PyModule_AddIntConstant( + m, "PJSUA_ACC_MAX_PROXIES ", PJSUA_ACC_MAX_PROXIES + ); +#endif } -- cgit v1.2.3