From 1a2990a8b65389578320c9a289fdd9c6bd7d2e79 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 29 Jul 2014 18:11:14 +0200 Subject: [PATCH] Beginning of the implementation of linphone_core_new() wrapper + Allow setting log handler from python. --- tools/python/apixml2python.py | 9 +- .../python/apixml2python/handwritten.mustache | 108 ++++++++++++++++++ tools/python/apixml2python/linphone.py | 10 +- .../apixml2python/linphone_module.mustache | 84 +++----------- 4 files changed, 134 insertions(+), 77 deletions(-) create mode 100644 tools/python/apixml2python/handwritten.mustache diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py index 56aeb275a..fda7a9262 100755 --- a/tools/python/apixml2python.py +++ b/tools/python/apixml2python.py @@ -72,13 +72,12 @@ blacklisted_functions = [ 'linphone_core_get_supported_video_sizes', 'linphone_core_get_video_codecs', 'linphone_core_get_video_policy', - 'linphone_core_new', 'linphone_core_new_with_config', 'linphone_core_payload_type_enabled', 'linphone_core_payload_type_is_vbr', 'linphone_core_publish', 'linphone_core_set_log_file', - 'linphone_core_set_log_handler', + 'linphone_core_set_log_handler', # Hand-written but put directly in the linphone module 'linphone_core_set_log_level', 'linphone_core_set_payload_type_bitrate', 'linphone_core_set_preferred_video_size', @@ -107,12 +106,16 @@ blacklisted_functions = [ 'lp_config_load_dict_to_section', 'lp_config_section_to_dict' ] +hand_written_functions = [ + 'linphone_core_new' +] def generate(apixmlfile): tree = ET.parse(apixmlfile) renderer = pystache.Renderer() - m = LinphoneModule(tree, blacklisted_classes, blacklisted_functions) + m = LinphoneModule(tree, blacklisted_classes, blacklisted_functions, hand_written_functions) f = open("linphone.c", "w") + os.chdir('apixml2python') f.write(renderer.render(m)) diff --git a/tools/python/apixml2python/handwritten.mustache b/tools/python/apixml2python/handwritten.mustache new file mode 100644 index 000000000..fd25b0a72 --- /dev/null +++ b/tools/python/apixml2python/handwritten.mustache @@ -0,0 +1,108 @@ +static void pylinphone_log(const char *level, int indent, const char *fmt, va_list args) { + static int current_indent = 1; + PyObject *linphone_module = PyImport_ImportModule("linphone"); + if ((linphone_module != NULL) && PyObject_HasAttrString(linphone_module, "__log_handler")) { + PyObject *log_handler = PyObject_GetAttrString(linphone_module, "__log_handler"); + if ((log_handler != NULL) && PyFunction_Check(log_handler)) { + char logstr[4096]; + int i = 0; + if (indent == -1) current_indent--; + if (current_indent < 1) current_indent = 1; + if ((indent >= -1) && (indent <= 1)) { + for (i = 0; i < current_indent; i++) { + logstr[i] = '\t'; + } + } + if (indent == 1) current_indent++; + if (vsnprintf(logstr + i, sizeof(logstr) - i, fmt, args) > 0) { + PyEval_CallFunction(log_handler, "ss", level, logstr); + } + } + } +} + +static PYLINPHONE_INLINE void pylinphone_trace(int indent, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + pylinphone_log("debug", indent, fmt, args); + va_end(args); +} + +static const char * pylinphone_ortp_log_level_to_string(OrtpLogLevel lev) { + switch (lev) { + default: + case ORTP_DEBUG: + return "debug"; + case ORTP_MESSAGE: + return "info"; + case ORTP_WARNING: + return "warning"; + case ORTP_ERROR: + return "error"; + case ORTP_FATAL: + return "critical"; + case ORTP_TRACE: + return "debug"; + } +} + +static void pylinphone_module_log_handler(OrtpLogLevel lev, const char *fmt, va_list args) { + PyObject *linphone_module = PyImport_ImportModule("linphone"); + const char *level = pylinphone_ortp_log_level_to_string(lev); + if ((linphone_module != NULL) && PyObject_HasAttrString(linphone_module, "__log_handler")) { + PyObject *log_handler = PyObject_GetAttrString(linphone_module, "__log_handler"); + if ((log_handler != NULL) && PyFunction_Check(log_handler)) { + char logstr[4096]; + if (vsnprintf(logstr, sizeof(logstr), fmt, args) > 0) { + PyEval_CallFunction(log_handler, "ss", level, logstr); + } + } + } +} + +static void pylinphone_init_logging(void) { + linphone_core_set_log_handler(pylinphone_module_log_handler); + linphone_core_set_log_level(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL); +} + + +static PyObject * pylinphone_module_method_set_log_handler(PyObject *self, PyObject *args) { + PyObject *linphone_module = PyImport_ImportModule("linphone"); + PyObject *callback; + if (!PyArg_ParseTuple(args, "O", &callback)) { + return NULL; + } + if (linphone_module != NULL) { + Py_INCREF(callback); + PyObject_SetAttrString(linphone_module, "__log_handler", callback); + } + Py_RETURN_NONE; +} + +static PyObject * pylinphone_Core_class_method_new(PyObject *cls, PyObject *args) { + LinphoneCore * cresult; + pylinphone_CoreObject *self; + PyObject * pyret; + LinphoneCoreVTable _vtable = { 0 }; + const char * _config_path; + const char * _factory_config_path; + + if (!PyArg_ParseTuple(args, "zz", &_config_path, &_factory_config_path)) { + return NULL; + } + + self = (pylinphone_CoreObject *)PyObject_New(pylinphone_CoreObject, &pylinphone_CoreType); + if (self == NULL) { + return NULL; + } + + pylinphone_trace(1, "[PYLINPHONE] >>> %s(\"%s\", \"%s\")", __FUNCTION__, _config_path, _factory_config_path); + cresult = linphone_core_new(&_vtable, _config_path, _factory_config_path, self); + self->native_ptr = cresult; + + pyret = Py_BuildValue("O", self); + + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, pyret); + Py_DECREF(self); + return pyret; +} diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py index bdffdba13..7e3816410 100644 --- a/tools/python/apixml2python/linphone.py +++ b/tools/python/apixml2python/linphone.py @@ -537,7 +537,7 @@ class SetterMethodDefinition(MethodDefinition): class LinphoneModule(object): - def __init__(self, tree, blacklisted_classes, blacklisted_functions): + def __init__(self, tree, blacklisted_classes, blacklisted_functions, hand_written_functions): self.internal_instance_method_names = ['destroy', 'ref', 'unref'] self.internal_property_names = ['user_data'] self.enums = [] @@ -577,6 +577,7 @@ class LinphoneModule(object): c['class_destroyable'] = (xml_class.get('destroyable') == 'true') c['class_has_user_data'] = False c['class_type_methods'] = [] + c['class_type_hand_written_methods'] = [] xml_type_methods = xml_class.findall("./classmethods/classmethod") for xml_type_method in xml_type_methods: if xml_type_method.get('deprecated') == 'true': @@ -586,8 +587,11 @@ class LinphoneModule(object): continue m = {} m['method_name'] = method_name.replace(c['class_c_function_prefix'], '') - m['method_xml_node'] = xml_type_method - c['class_type_methods'].append(m) + if method_name in hand_written_functions: + c['class_type_hand_written_methods'].append(m) + else: + m['method_xml_node'] = xml_type_method + c['class_type_methods'].append(m) c['class_instance_methods'] = [] xml_instance_methods = xml_class.findall("./instancemethods/instancemethod") for xml_instance_method in xml_instance_methods: diff --git a/tools/python/apixml2python/linphone_module.mustache b/tools/python/apixml2python/linphone_module.mustache index 2fc006def..ce222015f 100644 --- a/tools/python/apixml2python/linphone_module.mustache +++ b/tools/python/apixml2python/linphone_module.mustache @@ -30,76 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif -static PyObject *logging_module = NULL; -static int current_indent = 1; - - -static void init_logging(void) { - logging_module = PyImport_ImportModule("logging"); - if (logging_module != NULL) { - PyObject *constant; - PyObject *func; - PyObject *kws; - long level = 0; - - constant = PyObject_GetAttrString(logging_module, "DEBUG"); - if (PyInt_Check(constant)) { - level = PyInt_AsLong(constant); - } - Py_DECREF(constant); - func = PyObject_GetAttrString(logging_module, "basicConfig"); - kws = Py_BuildValue("{s:i,s:s}", "level", level, "format", "%(levelname)s: %(message)s"); - PyEval_CallObjectWithKeywords(func, NULL, kws); - Py_DECREF(kws); - Py_DECREF(func); - } -} - -static void pylinphone_log(const char *level, int indent, const char *fmt, va_list args) { - if (logging_module != NULL) { - char logstr[4096]; - int i = 0; - if (indent == -1) current_indent--; - if (current_indent < 1) current_indent = 1; - if ((indent >= -1) && (indent <= 1)) { - for (i = 0; i < current_indent; i++) { - logstr[i] = '\t'; - } - } - if (indent == 1) current_indent++; - if (vsnprintf(logstr + i, sizeof(logstr) - i, fmt, args) > 0) { - PyEval_CallMethod(logging_module, level, "(s)", logstr); - } - } -} - -static PYLINPHONE_INLINE void pylinphone_debug(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - pylinphone_log("debug", 0xff, fmt, args); - va_end(args); -} - -static PYLINPHONE_INLINE void pylinphone_info(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - pylinphone_log("info", 0xff, fmt, args); - va_end(args); -} - -static PYLINPHONE_INLINE void pylinphone_warning(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - pylinphone_log("warning", 0xff, fmt, args); - va_end(args); -} - -static PYLINPHONE_INLINE void pylinphone_trace(int indent, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - pylinphone_log("debug", indent, fmt, args); - va_end(args); -} +static PYLINPHONE_INLINE void pylinphone_trace(int indent, const char *fmt, ...); {{#classes}} @@ -118,6 +49,9 @@ typedef struct { {{#classes}} static {{class_cname}} * pylinphone_{{class_name}}_get_native_ptr(PyObject *self); static PyObject * pylinphone_{{class_name}}_new_from_native_ptr(PyTypeObject *type, const {{class_cname}} *native_ptr); +{{#class_type_hand_written_methods}} +static PyObject * pylinphone_{{class_name}}_class_method_{{method_name}}(PyObject *cls, PyObject *args); +{{/class_type_hand_written_methods}} {{/classes}} {{#classes}} @@ -157,6 +91,9 @@ static PyObject * pylinphone_{{class_name}}_instance_method_{{method_name}}(PyOb static PyMethodDef pylinphone_{{class_name}}_instance_methods[] = { // TODO: Handle doc /* Class methods */ +{{#class_type_hand_written_methods}} + { "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "" }, +{{/class_type_hand_written_methods}} {{#class_type_methods}} { "{{method_name}}", pylinphone_{{class_name}}_class_method_{{method_name}}, METH_VARARGS | METH_CLASS, "" }, {{/class_type_methods}} @@ -234,8 +171,13 @@ static PyTypeObject pylinphone_{{class_name}}Type = { {{/classes}} + +{{> handwritten}} + + static PyMethodDef pylinphone_ModuleMethods[] = { /* Sentinel */ + { "set_log_handler", pylinphone_module_method_set_log_handler, METH_VARARGS, "" }, { NULL, NULL, 0, NULL } }; @@ -248,7 +190,7 @@ PyMODINIT_FUNC initlinphone(void) { PyObject *m; PyObject *menum; - init_logging(); + pylinphone_init_logging(); {{#classes}} if (PyType_Ready(&pylinphone_{{class_name}}Type) < 0) return;