From 1208a71955166636396e7b3f8c44305eb359bb81 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 12 Aug 2014 12:11:11 +0200 Subject: [PATCH] Implement VideoSize class in the Python wrapper. --- tools/python/apixml2python.py | 5 - .../handwritten_declarations.mustache | 10 ++ ...tache => handwritten_definitions.mustache} | 116 +++++++++++++++++- tools/python/apixml2python/linphone.py | 100 +++++++-------- .../apixml2python/linphone_module.mustache | 14 ++- 5 files changed, 178 insertions(+), 67 deletions(-) create mode 100644 tools/python/apixml2python/handwritten_declarations.mustache rename tools/python/apixml2python/{handwritten.mustache => handwritten_definitions.mustache} (61%) diff --git a/tools/python/apixml2python.py b/tools/python/apixml2python.py index 29a2904c2..a5b9d46e6 100755 --- a/tools/python/apixml2python.py +++ b/tools/python/apixml2python.py @@ -45,9 +45,7 @@ blacklisted_functions = [ 'linphone_call_log_get_start_date', # missing time_t 'linphone_call_log_get_user_pointer', # rename to linphone_call_log_get_user_data 'linphone_call_log_set_user_pointer', # rename to linphone_call_log_set_user_data - 'linphone_call_params_get_received_video_size', # missing MSVideoSize 'linphone_call_params_get_privacy', # missing LinphonePrivacyMask - 'linphone_call_params_get_sent_video_size', # missing MSVideoSize 'linphone_call_params_get_used_audio_codec', # missing PayloadType 'linphone_call_params_get_used_video_codec', # missing PayloadType 'linphone_call_params_set_privacy', # missing LinphonePrivacyMask @@ -68,7 +66,6 @@ blacklisted_functions = [ 'linphone_core_get_chat_rooms', # missing MSList 'linphone_core_get_default_proxy', # to be handwritten because of double pointer indirection 'linphone_core_get_payload_type_bitrate', # missing PayloadType - 'linphone_core_get_preferred_video_size', # missing MSVideoSize 'linphone_core_get_friend_list', # missing MSList 'linphone_core_get_proxy_config_list', # missing MSList 'linphone_core_get_sip_transports', # missing LCSipTransports @@ -84,12 +81,10 @@ blacklisted_functions = [ 'linphone_core_set_log_handler', # Hand-written but put directly in the linphone module 'linphone_core_set_log_level', # There is no use to wrap this function 'linphone_core_set_payload_type_bitrate', # missing PayloadType - 'linphone_core_set_preferred_video_size', # missing MSVideoSize 'linphone_core_set_video_policy', # missing LinphoneVideoPolicy 'linphone_core_play_dtmf', # handling of char 'linphone_core_send_dtmf', # handling of char 'linphone_core_set_audio_codecs', # missing PayloadType and MSList - 'linphone_core_set_preview_video_size', # missing MSVideoSize 'linphone_core_set_sip_transports', # missing LCSipTransports 'linphone_core_subscribe', # missing LinphoneContent 'linphone_event_notify', # missing LinphoneContent diff --git a/tools/python/apixml2python/handwritten_declarations.mustache b/tools/python/apixml2python/handwritten_declarations.mustache new file mode 100644 index 000000000..1d27b9963 --- /dev/null +++ b/tools/python/apixml2python/handwritten_declarations.mustache @@ -0,0 +1,10 @@ +static PyTypeObject pylinphone_VideoSizeType; + +typedef struct { + PyObject_HEAD + MSVideoSize vs; +} pylinphone_VideoSizeObject; + +int PyLinphoneVideoSize_Check(PyObject *p); +MSVideoSize PyLinphoneVideoSize_AsMSVideoSize(PyObject *obj); +PyObject * PyLinphoneVideoSize_FromMSVideoSize(MSVideoSize vs); diff --git a/tools/python/apixml2python/handwritten.mustache b/tools/python/apixml2python/handwritten_definitions.mustache similarity index 61% rename from tools/python/apixml2python/handwritten.mustache rename to tools/python/apixml2python/handwritten_definitions.mustache index df58453dc..f6697a606 100644 --- a/tools/python/apixml2python/handwritten.mustache +++ b/tools/python/apixml2python/handwritten_definitions.mustache @@ -14,7 +14,7 @@ static void pylinphone_log(const char *level, int indent, const char *fmt, va_li PyGILState_STATE gstate; gstate = PyGILState_Ensure(); - linphone_module = PyImport_ImportModule("linphone"); + linphone_module = PyImport_ImportModule("linphone.linphone"); if ((linphone_module != NULL) && PyObject_HasAttrString(linphone_module, "__log_handler")) { PyObject *log_handler = PyObject_GetAttrString(linphone_module, "__log_handler"); if ((log_handler != NULL) && PyCallable_Check(log_handler)) { @@ -71,7 +71,7 @@ static void pylinphone_module_log_handler(OrtpLogLevel lev, const char *fmt, va_ const char *level; gstate = PyGILState_Ensure(); - linphone_module = PyImport_ImportModule("linphone"); + linphone_module = PyImport_ImportModule("linphone.linphone"); 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"); @@ -97,7 +97,7 @@ static void pylinphone_init_logging(void) { static PyObject * pylinphone_module_method_set_log_handler(PyObject *self, PyObject *args) { - PyObject *linphone_module = PyImport_ImportModule("linphone"); + PyObject *linphone_module = PyImport_ImportModule("linphone.linphone"); PyObject *callback; if (!PyArg_ParseTuple(args, "O", &callback)) { return NULL; @@ -193,3 +193,113 @@ static PyObject * pylinphone_Core_class_method_new_with_config(PyObject *cls, Py Py_DECREF(self); return pyret; } + + + +static void pylinphone_VideoSize_dealloc(PyObject *self) { + pylinphone_trace(1, "[PYLINPHONE] >>> %s(%p)", __FUNCTION__, self); + self->ob_type->tp_free(self); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s", __FUNCTION__); +} + +static PyObject * pylinphone_VideoSize_new(PyTypeObject *type, PyObject *args, PyObject *kw) { + pylinphone_VideoSizeObject *self = (pylinphone_VideoSizeObject *)type->tp_alloc(type, 0); + pylinphone_trace(1, "[PYLINPHONE] >>> %s()", __FUNCTION__); + pylinphone_trace(-1, "[PYLINPHONE] <<< %s -> %p", __FUNCTION__, self); + return (PyObject *)self; +} + +static int pylinphone_VideoSize_init(PyObject *self, PyObject *args, PyObject *kwds) { + pylinphone_VideoSizeObject *vso = (pylinphone_VideoSizeObject *)self; + int width; + int height; + if (!PyArg_ParseTuple(args, "ii", &width, &height)) { + return -1; + } + vso->vs.width = width; + vso->vs.height = height; + return 0; +} + +static PyMemberDef pylinphone_VideoSize_members[] = { + { "width", T_INT, offsetof(pylinphone_VideoSizeObject, vs) + offsetof(MSVideoSize, width), 0, "The width of the video" }, + { "height", T_INT, offsetof(pylinphone_VideoSizeObject, vs) + offsetof(MSVideoSize, height), 0, "The height of the video" }, + { NULL } /* Sentinel */ +}; + +static PyTypeObject pylinphone_VideoSizeType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "linphone.VideoSize", /* tp_name */ + sizeof(pylinphone_VideoSizeObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + pylinphone_VideoSize_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 */ + "Object representing the size of a video: its width and its height in pixels.", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + pylinphone_VideoSize_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + pylinphone_VideoSize_init, /* tp_init */ + 0, /* tp_alloc */ + pylinphone_VideoSize_new, /* tp_new */ + 0, /* tp_free */ +}; + +int PyLinphoneVideoSize_Check(PyObject *p) { + return PyObject_IsInstance(p, (PyObject *)&pylinphone_VideoSizeType); +} + +MSVideoSize PyLinphoneVideoSize_AsMSVideoSize(PyObject *obj) { + return ((pylinphone_VideoSizeObject *)obj)->vs; +} + +PyObject * PyLinphoneVideoSize_FromMSVideoSize(MSVideoSize vs) { + PyObject *linphone_module; + PyObject *pyret = NULL; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); + linphone_module = PyImport_ImportModule("linphone.linphone"); + if (linphone_module != NULL) { + PyObject *cls = PyObject_GetAttrString(linphone_module, "VideoSize"); + if (cls != NULL) { + pyret = PyEval_CallObject(cls, Py_BuildValue("ii", vs.width, vs.height)); + if (pyret == NULL) { + PyErr_Print(); + } + Py_DECREF(cls); + } + Py_DECREF(linphone_module); + } + PyGILState_Release(gstate); + + if (pyret == NULL) { + Py_RETURN_NONE; + } + return pyret; +} diff --git a/tools/python/apixml2python/linphone.py b/tools/python/apixml2python/linphone.py index 90b054ba0..4a73cb820 100644 --- a/tools/python/apixml2python/linphone.py +++ b/tools/python/apixml2python/linphone.py @@ -45,8 +45,11 @@ class ArgumentType: self.type_str = None self.check_func = None self.convert_func = None + self.convert_from_func = None self.fmt_str = 'O' self.cfmt_str = '%p' + self.use_native_pointer = False + self.cast_convert_func_result = True self.__compute() def __compute(self): @@ -132,6 +135,14 @@ class ArgumentType: self.convert_func = 'PyInt_AsLong' self.fmt_str = 'i' self.cfmt_str = '%d' + elif self.basic_type == 'MSVideoSize': + self.type_str = 'linphone.VideoSize' + self.check_func = 'PyLinphoneVideoSize_Check' + self.convert_func = 'PyLinphoneVideoSize_AsMSVideoSize' + self.convert_from_func = 'PyLinphoneVideoSize_FromMSVideoSize' + self.fmt_str = 'O' + self.cfmt_str = '%p' + self.cast_convert_func_result = False else: if strip_leading_linphone(self.basic_type) in self.linphone_module.enum_names: self.type_str = 'int' @@ -139,6 +150,8 @@ class ArgumentType: self.convert_func = 'PyInt_AsLong' self.fmt_str = 'i' self.cfmt_str = '%d' + elif '*' in splitted_type: + self.use_native_pointer = True class MethodDefinition: @@ -177,7 +190,7 @@ class MethodDefinition: arg_complete_type = xml_method_arg.get('completetype') argument_type = ArgumentType(arg_type, arg_complete_type, self.linphone_module) self.parse_tuple_format += argument_type.fmt_str - if argument_type.fmt_str == 'O': + if argument_type.use_native_pointer: body += "\tPyObject * " + arg_name + ";\n" body += "\t" + arg_complete_type + " " + arg_name + "_native_ptr;\n" elif strip_leading_linphone(arg_complete_type) in self.linphone_module.enum_names: @@ -194,7 +207,7 @@ class MethodDefinition: parse_tuple_code = '' if len(self.arg_names) > 0: parse_tuple_code = \ -""" if (!PyArg_ParseTuple(args, "{fmt}", {args})) {{ +"""if (!PyArg_ParseTuple(args, "{fmt}", {args})) {{ return NULL; }} """.format(fmt=self.parse_tuple_format, args=', '.join(map(lambda a: '&' + a, self.arg_names))) @@ -252,27 +265,35 @@ class MethodDefinition: return_from_user_data_code = '' new_from_native_pointer_code = '' ref_native_pointer_code = '' + convert_from_code = '' build_value_code = '' result_variable = '' if self.return_complete_type != 'void': if self.build_value_format == 'O': stripped_return_type = strip_leading_linphone(self.return_type) return_type_class = self.find_class_definition(self.return_type) - if return_type_class['class_has_user_data']: - get_user_data_function = return_type_class['class_c_function_prefix'] + "get_user_data" - return_from_user_data_code = \ -""" if ((cresult != NULL) && ({func}(cresult) != NULL)) {{ + if return_type_class is not None: + if return_type_class['class_has_user_data']: + get_user_data_function = return_type_class['class_c_function_prefix'] + "get_user_data" + return_from_user_data_code = \ +"""if ((cresult != NULL) && ({func}(cresult) != NULL)) {{ return (PyObject *){func}(cresult); }} """.format(func=get_user_data_function) - new_from_native_pointer_code = "\tpyresult = pylinphone_{return_type}_new_from_native_ptr(&pylinphone_{return_type}Type, cresult);\n".format(return_type=stripped_return_type) - if self.self_arg is not None and return_type_class['class_refcountable']: - ref_function = return_type_class['class_c_function_prefix'] + "ref" - ref_native_pointer_code = \ -""" if (cresult != NULL) {{ + new_from_native_pointer_code = "pyresult = pylinphone_{return_type}_new_from_native_ptr(&pylinphone_{return_type}Type, cresult);\n".format(return_type=stripped_return_type) + if self.self_arg is not None and return_type_class['class_refcountable']: + ref_function = return_type_class['class_c_function_prefix'] + "ref" + ref_native_pointer_code = \ +"""if (cresult != NULL) {{ {func}(({cast_type})cresult); }} """.format(func=ref_function, cast_type=self.remove_const_from_complete_type(self.return_complete_type)) + else: + return_argument_type = ArgumentType(self.return_type, self.return_complete_type, self.linphone_module) + if return_argument_type.convert_from_func is not None: + convert_from_code = \ +"""pyresult = {convert_func}(cresult); +""".format(convert_func=return_argument_type.convert_from_func) result_variable = 'pyresult' else: result_variable = 'cresult' @@ -284,11 +305,13 @@ class MethodDefinition: {return_from_user_data_code} {new_from_native_pointer_code} {ref_native_pointer_code} + {convert_from_code} {build_value_code} """.format(c_function_call_code=c_function_call_code, return_from_user_data_code=return_from_user_data_code, new_from_native_pointer_code=new_from_native_pointer_code, ref_native_pointer_code=ref_native_pointer_code, + convert_from_code=convert_from_code, build_value_code=build_value_code) return body @@ -316,7 +339,7 @@ class MethodDefinition: if return_int: return_value = "-1" return \ -""" native_ptr = pylinphone_{class_name}_get_native_ptr(self); +"""native_ptr = pylinphone_{class_name}_get_native_ptr(self); if (native_ptr == NULL) {{ PyErr_SetString(PyExc_TypeError, "Invalid linphone.{class_name} instance"); return {return_value}; @@ -353,48 +376,6 @@ class MethodDefinition: splitted_type.remove('const') return ' '.join(splitted_type) - def ctype_to_str_format(self, name, basic_type, complete_type, with_native_ptr=True): - splitted_type = complete_type.split(' ') - if basic_type == 'char': - if '*' in splitted_type: - return ('\\"%s\\"', [name]) - elif 'unsigned' in splitted_type: - return ('%08x', [name]) - elif basic_type == 'int': - # TODO: - return ('%d', [name]) - elif basic_type == 'int8_t': - return ('%d', [name]) - elif basic_type == 'uint8_t': - return ('%u', [name]) - elif basic_type == 'int16_t': - return ('%d', [name]) - elif basic_type == 'uint16_t': - return ('%u', [name]) - elif basic_type == 'int32_t': - return ('%d', [name]) - elif basic_type == 'uint32_t': - return ('%u', [name]) - elif basic_type == 'int64_t': - return ('%ld', [name]) - elif basic_type == 'uint64_t': - return ('%lu', [name]) - elif basic_type == 'size_t': - return ('%lu', [name]) - elif basic_type == 'float': - return ('%f', [name]) - elif basic_type == 'double': - return ('%f', [name]) - elif basic_type == 'bool_t': - return ('%d', [name]) - else: - if strip_leading_linphone(basic_type) in self.linphone_module.enum_names: - return ('%d', [name]) - elif with_native_ptr: - return ('%p [%p]', [name, name + "_native_ptr"]) - else: - return ('%p', [name]) - def find_class_definition(self, basic_type): basic_type = strip_leading_linphone(basic_type) for c in self.linphone_module.classes: @@ -544,10 +525,13 @@ class SetterMethodDefinition(MethodDefinition): if self.first_argument_type.convert_func is None: attribute_conversion_code = "{arg_name} = value;\n".format(arg_name="_" + self.first_arg_name) else: - attribute_conversion_code = "{arg_name} = ({arg_type}){convertfunc}(value);\n".format( - arg_name="_" + self.first_arg_name, arg_type=self.first_arg_complete_type, convertfunc=self.first_argument_type.convert_func) + cast_code = '' + if self.first_argument_type.cast_convert_func_result: + cast_code = "({arg_type})".format(arg_type=self.first_arg_complete_type) + attribute_conversion_code = "{arg_name} = {cast_code}{convertfunc}(value);\n".format( + arg_name="_" + self.first_arg_name, cast_code=cast_code, convertfunc=self.first_argument_type.convert_func) attribute_native_ptr_check_code = '' - if self.first_argument_type.fmt_str == 'O': + if self.first_argument_type.use_native_pointer: attribute_native_ptr_check_code = \ """{arg_name}_native_ptr = pylinphone_{arg_class}_get_native_ptr({arg_name}); if ({arg_name}_native_ptr == NULL) {{ @@ -572,7 +556,7 @@ class SetterMethodDefinition(MethodDefinition): def format_c_function_call(self): use_native_ptr = '' - if self.first_argument_type.fmt_str == 'O': + if self.first_argument_type.use_native_pointer: use_native_ptr = '_native_ptr' return \ """ {method_name}(native_ptr, {arg_name}{use_native_ptr}); diff --git a/tools/python/apixml2python/linphone_module.mustache b/tools/python/apixml2python/linphone_module.mustache index 4a8888ff3..9c1b197f6 100644 --- a/tools/python/apixml2python/linphone_module.mustache +++ b/tools/python/apixml2python/linphone_module.mustache @@ -17,6 +17,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include +#include #include #include #include @@ -37,6 +38,10 @@ static void pylinphone_dispatch_messages(void); static PYLINPHONE_INLINE void pylinphone_trace(int indent, const char *fmt, ...); +{{> handwritten_declarations}} + + + {{#classes}} static PyTypeObject pylinphone_{{class_name}}Type; {{/classes}} @@ -186,7 +191,7 @@ static PyTypeObject pylinphone_{{class_name}}Type = { {{/classes}} -{{> handwritten}} +{{> handwritten_definitions}} static PyMethodDef pylinphone_ModuleMethods[] = { @@ -236,6 +241,9 @@ PyMODINIT_FUNC initlinphone(void) { if (PyType_Ready(&pylinphone_{{class_name}}Type) < 0) return; {{/classes}} + /* Hand-written classes. */ + if (PyType_Ready(&pylinphone_VideoSizeType) < 0) return; + m = Py_InitModule3("linphone", pylinphone_ModuleMethods, "Python module giving access to the Linphone library."); if (m == NULL) return; @@ -252,4 +260,8 @@ PyMODINIT_FUNC initlinphone(void) { Py_INCREF(&pylinphone_{{class_name}}Type); PyModule_AddObject(m, "{{class_name}}", (PyObject *)&pylinphone_{{class_name}}Type); {{/classes}} + + /* Hand-written classes. */ + Py_INCREF(&pylinphone_VideoSizeType); + PyModule_AddObject(m, "VideoSize", (PyObject *)&pylinphone_VideoSizeType); }