Commit 89565386 authored by Ghislain MARY's avatar Ghislain MARY

Working file transfer in Python.

- Add the LinphoneBuffer object so that file transfer callbacks do not pass out parameters
- Use the LinphoneBuffer object in the file transfer callbacks
- Implement the file_transfer_send callback in the Python file transfer test
parent 1b61ea21
......@@ -40,6 +40,7 @@ LOCAL_SRC_FILES := \
bellesip_sal/sal_op_publish.c \
bellesip_sal/sal_op_registration.c \
bellesip_sal/sal_sdp.c \
buffer.c \
callbacks.c \
call_log.c \
call_params.c \
......
......@@ -110,6 +110,7 @@
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_publish.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_op_registration.c" />
<ClCompile Include="..\..\coreapi\bellesip_sal\sal_sdp.c" />
<ClCompile Include="..\..\coreapi\buffer.c" />
<ClCompile Include="..\..\coreapi\call_log.c" />
<ClCompile Include="..\..\coreapi\call_params.c" />
<ClCompile Include="..\..\coreapi\callbacks.c" />
......@@ -145,6 +146,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\coreapi\bellesip_sal\sal_impl.h" />
<ClInclude Include="..\..\coreapi\buffer.h" />
<ClInclude Include="..\..\coreapi\content.h" />
<ClInclude Include="..\..\coreapi\enum.h" />
<ClInclude Include="..\..\coreapi\event.h" />
......
......@@ -42,6 +42,7 @@ set(SOURCE_FILES
bellesip_sal/sal_op_publish.c
bellesip_sal/sal_op_registration.c
bellesip_sal/sal_sdp.c
buffer.c
callbacks.c
call_log.c
call_params.c
......@@ -153,6 +154,7 @@ install(TARGETS linphone
set(HEADER_FILES
buffer.h
call_log.h
call_params.h
content.h
......
......@@ -25,6 +25,7 @@ CLEANFILES=$(GITVERSION_FILE)
linphone_includedir=$(includedir)/linphone
linphone_include_HEADERS=\
buffer.h \
call_log.h \
call_params.h \
content.h \
......@@ -44,6 +45,7 @@ lib_LTLIBRARIES=liblinphone.la
liblinphone_la_SOURCES=\
address.c \
authentication.c \
buffer.c \
callbacks.c \
call_log.c \
call_params.c \
......
/*
linphone
Copyright (C) 2010-2014 Belledonne Communications SARL
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 "linphonecore.h"
#include "private.h"
static void linphone_buffer_destroy(LinphoneBuffer *buffer) {
if (buffer->content) belle_sip_free(buffer->content);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneBuffer);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneBuffer, belle_sip_object_t,
(belle_sip_object_destroy_t)linphone_buffer_destroy,
NULL, // clone
NULL, // marshal
TRUE
);
LinphoneBuffer * linphone_buffer_new(void) {
LinphoneBuffer *buffer = belle_sip_object_new(LinphoneBuffer);
belle_sip_object_ref(buffer);
return buffer;
}
LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size) {
LinphoneBuffer *buffer = linphone_buffer_new();
linphone_buffer_set_content(buffer, data, size);
return buffer;
}
LinphoneBuffer * linphone_buffer_new_from_string(const char *data) {
LinphoneBuffer *buffer = linphone_buffer_new();
linphone_buffer_set_string_content(buffer, data);
return buffer;
}
LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer) {
belle_sip_object_ref(buffer);
return buffer;
}
void linphone_buffer_unref(LinphoneBuffer *buffer) {
belle_sip_object_unref(buffer);
}
void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer) {
return buffer->user_data;
}
void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud) {
buffer->user_data = ud;
}
const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer) {
return buffer->content;
}
void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size) {
buffer->size = size;
if (buffer->content) belle_sip_free(buffer->content);
buffer->content = belle_sip_malloc(size);
memcpy(buffer->content, content, size);
}
const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer) {
return (const char *)buffer->content;
}
void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content) {
buffer->size = strlen(content);
if (buffer->content) belle_sip_free(buffer->content);
buffer->content = (uint8_t *)belle_sip_strdup(content);
}
size_t linphone_buffer_get_size(const LinphoneBuffer *buffer) {
return buffer->size;
}
void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size) {
buffer->size = size;
}
bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer) {
return (buffer->size == 0) ? TRUE : FALSE;
}
/*
buffer.h
Copyright (C) 2010-2014 Belledonne Communications SARL
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.
*/
#ifndef LINPHONE_BUFFER_H_
#define LINPHONE_BUFFER_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup misc
* @{
*/
/**
* The LinphoneContent object representing a data buffer.
**/
typedef struct _LinphoneBuffer LinphoneBuffer;
/**
* Create a new empty LinphoneBuffer object.
* @return A new LinphoneBuffer object.
*/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new(void);
/**
* Create a new LinphoneBuffer object from existing data.
* @param[in] data The initial data to store in the LinphoneBuffer.
* @param[in] size The size of the initial data to stroe in the LinphoneBuffer.
* @return A new LinphoneBuffer object.
*/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_data(const uint8_t *data, size_t size);
/**
* Create a new LinphoneBuffer object from a string.
* @param[in] data The initial string content of the LinphoneBuffer.
* @return A new LinphoneBuffer object.
*/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_new_from_string(const char *data);
/**
* Acquire a reference to the buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The same LinphoneBuffer object.
**/
LINPHONE_PUBLIC LinphoneBuffer * linphone_buffer_ref(LinphoneBuffer *buffer);
/**
* Release reference to the buffer.
* @param[in] buffer LinphoneBuffer object.
**/
LINPHONE_PUBLIC void linphone_buffer_unref(LinphoneBuffer *buffer);
/**
* Retrieve the user pointer associated with the buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The user pointer associated with the buffer.
**/
LINPHONE_PUBLIC void *linphone_buffer_get_user_data(const LinphoneBuffer *buffer);
/**
* Assign a user pointer to the buffer.
* @param[in] buffer LinphoneBuffer object.
* @param[in] ud The user pointer to associate with the buffer.
**/
LINPHONE_PUBLIC void linphone_buffer_set_user_data(LinphoneBuffer *buffer, void *ud);
/**
* Get the content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The content of the data buffer.
*/
LINPHONE_PUBLIC const uint8_t * linphone_buffer_get_content(const LinphoneBuffer *buffer);
/**
* Set the content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @param[in] content The content of the data buffer.
* @param[in] size The size of the content of the data buffer.
*/
LINPHONE_PUBLIC void linphone_buffer_set_content(LinphoneBuffer *buffer, const uint8_t *content, size_t size);
/**
* Get the string content of the data buffer.
* @param[in] buffer LinphoneBuffer object
* @return The string content of the data buffer.
*/
LINPHONE_PUBLIC const char * linphone_buffer_get_string_content(const LinphoneBuffer *buffer);
/**
* Set the string content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @param[in] content The string content of the data buffer.
*/
LINPHONE_PUBLIC void linphone_buffer_set_string_content(LinphoneBuffer *buffer, const char *content);
/**
* Get the size of the content of the data buffer.
* @param[in] buffer LinphoneBuffer object.
* @return The size of the content of the data buffer.
*/
LINPHONE_PUBLIC size_t linphone_buffer_get_size(const LinphoneBuffer *buffer);
/**
* Set the size of the content of the data buffer.
* @param[in] buffer LinphoneBuffer object
* @param[in] size The size of the content of the data buffer.
*/
LINPHONE_PUBLIC void linphone_buffer_set_size(LinphoneBuffer *buffer, size_t size);
/**
* Tell whether the LinphoneBuffer is empty.
* @param[in] buffer LinphoneBuffer object
* @return A boolean value telling whether the LinphoneBuffer is empty or not.
*/
LINPHONE_PUBLIC bool_t linphone_buffer_is_empty(const LinphoneBuffer *buffer);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* LINPHONE_CONTENT_H_ */
......@@ -246,7 +246,13 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_
if (offset<linphone_content_get_size(chatMsg->file_transfer_information)){
/* get data from call back */
if (linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)) {
linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, buf, size);
LinphoneBuffer *lb = linphone_chat_message_cbs_get_file_transfer_send(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, offset, *size);
if (lb == NULL) *size = 0;
else {
*size = linphone_buffer_get_size(lb);
memcpy(buffer, linphone_buffer_get_content(lb), *size);
linphone_buffer_unref(lb);
}
} else {
/* Legacy */
linphone_core_notify_file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size);
......@@ -1205,7 +1211,9 @@ static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t
return;
}
if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) {
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
LinphoneBuffer *lb = linphone_buffer_new_from_data(buffer, size);
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb);
linphone_buffer_unref(lb);
} else {
/* Legacy: call back given by application level */
linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size);
......@@ -1279,7 +1287,9 @@ static void linphone_chat_process_response_from_get_file(void *data, const belle
LinphoneCore *lc = chatMsg->chat_room->lc;
/* file downloaded succesfully, call again the callback with size at zero */
if (linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)) {
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, NULL, 0);
LinphoneBuffer *lb = linphone_buffer_new();
linphone_chat_message_cbs_get_file_transfer_recv(chatMsg->callbacks)(chatMsg, chatMsg->file_transfer_information, lb);
linphone_buffer_unref(lb);
} else {
linphone_core_notify_file_transfer_recv(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0);
}
......
......@@ -366,12 +366,14 @@ LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
#ifdef IN_LINPHONE
#include "buffer.h"
#include "call_log.h"
#include "call_params.h"
#include "content.h"
#include "event.h"
#include "linphonefriend.h"
#else
#include "linphone/buffer.h"
#include "linphone/call_log.h"
#include "linphone/call_params.h"
#include "linphone/content.h"
......@@ -1350,30 +1352,24 @@ typedef void (*LinphoneChatMessageCbsMsgStateChangedCb)(LinphoneChatMessage* msg
/**
* File transfer receive callback prototype. This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file.
*
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
* @param buff pointer to the received data
* @param size number of bytes to be read from buff. 0 means end of file.
*
* @param buffer #LinphoneBuffer holding the received data. Empty buffer means end of file.
*/
typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size);
typedef void (*LinphoneChatMessageCbsFileTransferRecvCb)(LinphoneChatMessage *message, const LinphoneContent* content, const LinphoneBuffer *buffer);
/**
* File transfer send callback prototype. This function is called by the core upon an outgoing File transfer is started. This function is called until size is set to 0.
* <br> a #LinphoneContent with a size equal zero
*
* File transfer send callback prototype. This function is called by the core when an outgoing file transfer is started. This function is called until size is set to 0.
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent outgoing content
* @param buff pointer to the buffer where data chunk shall be written by the app
* @param size as input value, it represents the number of bytes expected by the framework. As output value, it means the number of bytes wrote by the application in the buffer. 0 means end of file.
*
* @param offset the offset in the file from where to get the data to be sent
* @param size the number of bytes expected by the framework
* @return A LinphoneBuffer object holding the data written by the application. An empty buffer means end of file.
*/
typedef void (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size);
typedef LinphoneBuffer * (*LinphoneChatMessageCbsFileTransferSendCb)(LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t size);
/**
* File transfer progress indication callback prototype.
*
* @param message #LinphoneChatMessage message from which the body is received.
* @param content #LinphoneContent incoming content information
* @param offset The number of bytes sent/received since the beginning of the transfer.
......
......@@ -936,6 +936,14 @@ struct _LinphoneContent {
BELLE_SIP_DECLARE_VPTR(LinphoneContent);
struct _LinphoneBuffer {
belle_sip_object_t base;
void *user_data;
uint8_t *content; /**< A pointer to the buffer content */
size_t size; /**< The size of the buffer content */
};
BELLE_SIP_DECLARE_VPTR(LinphoneBuffer);
/*****************************************************************************
......@@ -1012,6 +1020,7 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc);
*/
BELLE_SIP_DECLARE_TYPES_BEGIN(linphone,10000)
BELLE_SIP_TYPE_ID(LinphoneBuffer),
BELLE_SIP_TYPE_ID(LinphoneContactProvider),
BELLE_SIP_TYPE_ID(LinphoneContactSearch),
BELLE_SIP_TYPE_ID(LinphoneCall),
......
......@@ -433,9 +433,16 @@ class Project:
if pos == -1:
return None
returntype = definition[0:pos].strip()
if returntype != "void":
return None
returnarg = CArgument(returntype, enums = self.enums, structs = self.__structs)
returndesc = node.find("./detaileddescription/para/simplesect[@kind='return']")
if returndesc is not None:
if returnarg.ctype == 'MSList':
n = returndesc.find('.//mslist')
if n is not None:
returnarg.containedType = n.text
returnarg.description = self.__cleanDescription(returndesc)
elif returnarg.completeType != 'void':
missingDocWarning += "\tReturn value is not documented\n"
definition = definition[pos + 2 :]
pos = string.find(definition, "(")
definition = definition[pos + 1 : -1]
......
......@@ -38,6 +38,9 @@ blacklisted_events = [
'LinphoneCoreFileTransferSendCb' # missing LinphoneContent
]
blacklisted_functions = [
'linphone_buffer_new_from_data',
'linphone_buffer_get_content',
'linphone_buffer_set_content',
'linphone_call_log_get_local_stats', # missing rtp_stats_t
'linphone_call_log_get_remote_stats', # missing rtp_stats_t
'linphone_call_params_get_privacy', # missing LinphonePrivacyMask
......
......@@ -238,24 +238,7 @@ class MethodDefinition:
self.method_type = 'instancemethod'
def format_local_variables_definition(self):
body = ''
if self.xml_method_return is not None:
self.return_type = self.xml_method_return.get('type')
self.return_complete_type = self.xml_method_return.get('completetype')
self.return_contained_type = self.xml_method_return.get('containedtype')
if is_callback(self.return_complete_type):
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
elif self.return_complete_type != 'void':
body += "\t" + self.return_complete_type + " cresult;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
if self.build_value_format == 'O':
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
body += "\tconst char *pyret_fmt;\n"
body = self.format_local_return_variables_definition()
if self.self_arg is not None:
body += "\t" + self.self_arg.get('completetype') + "native_ptr;\n"
for xml_method_arg in self.xml_method_args:
......@@ -473,6 +456,27 @@ class MethodDefinition:
body = body[1:] # Remove leading '\t'
return body
def format_local_return_variables_definition(self):
body = ''
if self.xml_method_return is not None:
self.return_type = self.xml_method_return.get('type')
self.return_complete_type = self.xml_method_return.get('completetype')
self.return_contained_type = self.xml_method_return.get('containedtype')
if is_callback(self.return_complete_type):
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
elif self.return_complete_type != 'void':
body += "\t" + self.return_complete_type + " cresult;\n"
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
self.build_value_format = argument_type.fmt_str
if self.build_value_format == 'O':
body += "\tPyObject * pyresult;\n"
body += "\tPyObject * pyret;\n"
body += "\tconst char *pyret_fmt;\n"
return body
def parse_method_node(self):
if self.method_node is not None:
self.xml_method_return = self.method_node.find('./return')
......@@ -778,6 +782,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
nocallbacks_class_name = class_name
if class_name.endswith('Cbs'):
nocallbacks_class_name = class_name[:-3]
returnvars = self.format_local_return_variables_definition()
common = \
""" pylinphone_{class_name}Object *pyself = (pylinphone_{class_name}Object *){function_prefix}get_user_data(self);
PyObject *func;
......@@ -796,7 +801,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
argument_type = ArgumentType(arg_type, arg_complete_type, arg_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O':
specific += "\tPyObject * py" + arg_name + " = NULL;\n"
return "{common}\n{specific}".format(common=common, specific=specific)
return "{returnvars}\n{common}\n{specific}".format(returnvars=returnvars, common=common, specific=specific)
def format_arguments_parsing(self):
if self.class_['event_class'] == 'Core':
......@@ -832,6 +837,7 @@ class EventCallbackMethodDefinition(MethodDefinition):
def format_c_function_call(self):
create_python_objects_code = ''
convert_python_result_code = ''
fmt = 'O'
args = ['pyself']
for xml_method_arg in self.xml_method_args:
......@@ -852,22 +858,52 @@ class EventCallbackMethodDefinition(MethodDefinition):
type_class = self.find_class_definition(arg_type)
create_python_objects_code += "\t\tpy{name} = pylinphone_{arg_type}_from_native_ptr(&pylinphone_{arg_type}Type, {name});\n".format(name=arg_name, arg_type=strip_leading_linphone(arg_type))
args=', '.join(args)
if self.return_complete_type != 'void':
argument_type = ArgumentType(self.return_type, self.return_complete_type, self.return_contained_type, self.linphone_module)
if argument_type.fmt_str == 'O':
convert_python_result_code = \
""" if ((pyresult != Py_None) && !PyObject_IsInstance(pyresult, (PyObject *)&pylinphone_{class_name}Type)) {{
PyErr_SetString(PyExc_TypeError, "The return value must be a linphone.{class_name} instance.");
return NULL;
}}
if ((cresult = pylinphone_{class_name}_get_native_ptr(pyresult)) == NULL) {{
return NULL;
}}
""".format(class_name=strip_leading_linphone(self.return_type))
else:
convert_python_result_code = "\t\tcresult = {convertfunc}(pyresult);\n".format(convertfunc=argument_type.convert_func)
return \
""" if ((func != NULL) && PyCallable_Check(func)) {{
{create_python_objects_code}
args = Py_BuildValue("{fmt}", {args});
if (PyEval_CallObject(func, args) == NULL) {{
pyresult = PyEval_CallObject(func, args);
if (pyresult == NULL) {{
PyErr_Print();
}}
Py_DECREF(args);
{convert_python_result_code}
}}
""".format(fmt=fmt, args=args, create_python_objects_code=create_python_objects_code)
""".format(fmt=fmt, args=args, create_python_objects_code=create_python_objects_code, convert_python_result_code=convert_python_result_code)
def format_return_trace(self):
return "\tpylinphone_trace(-1, \"[PYLINPHONE] <<< %s\", __FUNCTION__);\n"
def format_return_result(self):
return '\tPyGILState_Release(pygil_state);'
s = '\tPyGILState_Release(pygil_state);'
if self.return_complete_type != 'void':
s += '\n\treturn cresult;'
return s
def format_local_return_variables_definition(self):
body = "\tPyObject * pyresult;"
if self.xml_method_return is not None:
self.return_type = self.xml_method_return.get('type')
self.return_complete_type = self.xml_method_return.get('completetype')
self.return_contained_type = self.xml_method_return.get('containedtype')
if self.return_complete_type != 'void':
body += "\n\t" + self.return_complete_type + " cresult;"
return body
def format(self):
body = MethodDefinition.format(self)
......@@ -882,10 +918,10 @@ class EventCallbackMethodDefinition(MethodDefinition):
arg_complete_type = xml_method_arg.get('completetype')
arguments.append(arg_complete_type + ' ' + arg_name)
definition = \
"""static void pylinphone_{class_name}_callback_{event_name}({arguments}) {{
"""static {returntype} pylinphone_{class_name}_callback_{event_name}({arguments}) {{
{body}
}}
""".format(class_name=class_name, event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body)
""".format(returntype=self.return_complete_type, class_name=class_name, event_name=self.class_['event_name'], arguments=', '.join(arguments), body=body)
return definition
......
......@@ -3,11 +3,17 @@ from copy import deepcopy
import linphone
from linphonetester import *
import os
import os.path
import time
class TestMessage:
@classmethod
def teardown_class(cls):
if os.path.exists('receive_file.dump'):
os.remove('receive_file.dump')
@classmethod