diff --git a/tools/python/apixml2python/handwritten.mustache b/tools/python/apixml2python/handwritten.mustache index fd25b0a72..6f826a913 100644 --- a/tools/python/apixml2python/handwritten.mustache +++ b/tools/python/apixml2python/handwritten.mustache @@ -79,15 +79,30 @@ static PyObject * pylinphone_module_method_set_log_handler(PyObject *self, PyObj Py_RETURN_NONE; } +static void pylinphone_Core_callback_global_state_changed(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message) { + pylinphone_CoreObject *pylc = (pylinphone_CoreObject *)linphone_core_get_user_data(lc); + PyObject *func = PyDict_GetItemString(pylc->vtable_dict, "global_state_changed"); + if ((func != NULL) && PyFunction_Check(func)) { + if (PyEval_CallFunction(func, "Ois", pylc, gstate, message) == NULL) { + PyErr_Print(); + } + } +} + static PyObject * pylinphone_Core_class_method_new(PyObject *cls, PyObject *args) { LinphoneCore * cresult; pylinphone_CoreObject *self; PyObject * pyret; LinphoneCoreVTable _vtable = { 0 }; + PyObject * _vtable_dict; const char * _config_path; const char * _factory_config_path; - if (!PyArg_ParseTuple(args, "zz", &_config_path, &_factory_config_path)) { + if (!PyArg_ParseTuple(args, "Ozz", &_vtable_dict, &_config_path, &_factory_config_path)) { + return NULL; + } + if (!PyDict_Check(_vtable_dict)) { + PyErr_SetString(PyExc_TypeError, "The first argument must be a dictionary"); return NULL; } @@ -95,6 +110,9 @@ static PyObject * pylinphone_Core_class_method_new(PyObject *cls, PyObject *args if (self == NULL) { return NULL; } + Py_INCREF(_vtable_dict); + self->vtable_dict = _vtable_dict; + _vtable.global_state_changed = pylinphone_Core_callback_global_state_changed; pylinphone_trace(1, "[PYLINPHONE] >>> %s(\"%s\", \"%s\")", __FUNCTION__, _config_path, _factory_config_path); cresult = linphone_core_new(&_vtable, _config_path, _factory_config_path, self); diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py index 7e3816410..561c840ec 100644 --- a/tools/python/apixml2python/linphone.py +++ b/tools/python/apixml2python/linphone.py @@ -578,6 +578,9 @@ class LinphoneModule(object): c['class_has_user_data'] = False c['class_type_methods'] = [] c['class_type_hand_written_methods'] = [] + c['class_object_members'] = '' + if c['class_name'] == 'Core': + c['class_object_members'] = "\tPyObject *vtable_dict;" xml_type_methods = xml_class.findall("./classmethods/classmethod") for xml_type_method in xml_type_methods: if xml_type_method.get('deprecated') == 'true': diff --git a/tools/python/apixml2python/linphone_module.mustache b/tools/python/apixml2python/linphone_module.mustache index ce222015f..3879d1194 100644 --- a/tools/python/apixml2python/linphone_module.mustache +++ b/tools/python/apixml2python/linphone_module.mustache @@ -42,6 +42,7 @@ static PyTypeObject pylinphone_{{class_name}}Type; typedef struct { PyObject_HEAD {{class_cname}} *native_ptr; +{{{class_object_members}}} } pylinphone_{{class_name}}Object; {{/classes}} diff --git a/tools/python/test.py b/tools/python/test.py index d291d1f65..627f8cad9 100644 --- a/tools/python/test.py +++ b/tools/python/test.py @@ -1,7 +1,5 @@ import linphone import logging -import signal -import sys import threading import time @@ -36,44 +34,39 @@ logging.addLevelName(logging.DEBUG, "\033[1;37m%s\033[1;0m" % logging.getLevelNa logging.addLevelName(logging.INFO, "\033[1;36m%s\033[1;0m" % logging.getLevelName(logging.INFO)) logging.addLevelName(logging.WARNING, "\033[1;31m%s\033[1;0m" % logging.getLevelName(logging.WARNING)) logging.addLevelName(logging.ERROR, "\033[1;41m%s\033[1;0m" % logging.getLevelName(logging.ERROR)) -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s.%(msecs)-3d %(levelname)s: %(message)s", datefmt="%H:%M:%S") +logging.basicConfig(level=logging.INFO, format="%(asctime)s.%(msecs)03d %(levelname)s: %(message)s", datefmt="%H:%M:%S") # Define the linphone module log handler def log_handler(level, msg): method = getattr(logging, level) + if not msg.strip().startswith('[PYLINPHONE]'): + msg = '[CORE] ' + msg method(msg) - -def test_friend(): - f = linphone.Friend.new() - print(f.address) - a1 = linphone.Address.new("sip:cotcot@sip.linphone.org") - print(a1.username) - print(a1.domain) - a1.domain = "sip2.linphone.org" - print(a1.domain) - f.address = a1 - a2 = f.address - - -def signal_handler(signal, frame): - cont = False - raise KeyError("Ctrl+C") - # Define the iteration function def iterate(kwargs): core = kwargs['core'] core.iterate() +def interact(): + choice = raw_input('> ') + if choice == "quit": + return False + return True + +def global_state_changed(core, state, message): + logging.warning("[PYTHON] global_state_changed: " + str(state) + ", " + message) + if state == linphone.GlobalState.GlobalOn: + logging.warning("[PYTHON] core version: " + str(core.version)) + # Create a linphone core and iterate every 20 ms linphone.set_log_handler(log_handler) -core = linphone.Core.new(None, None) +callbacks = { + 'global_state_changed':global_state_changed +} +core = linphone.Core.new(callbacks, None, None) interval = IntervalTimer(0.02, iterate, kwargs={'core':core}) -signal.signal(signal.SIGINT, signal_handler) -try: - interval.start() - signal.pause() -except KeyError: - interval.stop() - del interval -del core +interval.start() +while interact(): + pass +interval.stop()