From 3e754fb44ba032f812430589568a50186253e09e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 14 May 2014 17:49:59 +0200 Subject: [PATCH 001/201] add a third cb dedicated to progress --- .cproject | 77 +++++++------ coreapi/help/Makefile.am | 5 +- coreapi/help/filetransfer.c | 210 ++++++++++++++++++++++++++++++++++++ coreapi/linphonecore.h | 74 ++++++++++++- 4 files changed, 322 insertions(+), 44 deletions(-) create mode 100644 coreapi/help/filetransfer.c diff --git a/.cproject b/.cproject index 07ef2412f..0d1eed0ed 100644 --- a/.cproject +++ b/.cproject @@ -60,47 +60,6 @@ - - - - make - all - true - true - true - - - make - CFLAGS="-g" - install - true - true - true - - - make - CFLAGS="-g" - install - true - true - true - - - make - all - true - true - true - - - make - all - true - true - true - - - @@ -209,4 +168,40 @@ + + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + all + true + true + true + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + + true + true + true + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + all + true + true + true + + + make + -j4 CFLAGS="-g -Wall -Werror -Qunused-arguments" CXXFLAGS="-g" + all + true + true + true + + + diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 9d3c2475a..454757094 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -46,7 +46,7 @@ clean-local: if ENABLE_TUTORIALS -noinst_PROGRAMS=helloworld registration buddy_status chatroom notify +noinst_PROGRAMS=helloworld registration buddy_status chatroom notify filetransfer helloworld_SOURCES=helloworld.c LINPHONE_TUTOS=$(helloworld_SOURCES) @@ -76,6 +76,9 @@ LINPHONE_TUTOS+=$(notify_SOURCES) notify_LDADD=$(helloworld_LDADD) +filetransfer_SOURCES=filetransfer.c +LINPHONE_TUTOS+=$(filetransfer_SOURCES) + AM_CFLAGS=\ -I$(top_srcdir)/coreapi \ $(STRICT_OPTIONS) \ diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c new file mode 100644 index 000000000..84e8c1f79 --- /dev/null +++ b/coreapi/help/filetransfer.c @@ -0,0 +1,210 @@ + +/* +linphone +Copyright (C) 2010 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. +*/ + +/** + * @defgroup chatroom_tuto Chat room and messaging + * @ingroup tutorials + *This program is a _very_ simple usage example of liblinphone, + *desmonstrating how to send/receive SIP MESSAGE from a sip uri identity passed from the command line. + *
Argument must be like sip:jehan@sip.linphone.org . + *
+ *ex chatroom sip:jehan@sip.linphone.org + *
+ *@include chatroom.c + + * + */ + +#ifdef IN_LINPHONE +#include "linphonecore.h" +#else +#include "linphone/linphonecore.h" +#endif + +#include + +static bool_t running=TRUE; + +static void stop(int signum){ + running=FALSE; +} +/** + * function invoked to report file transfer progress. + * */ +static void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t progress) { + const LinphoneAddress* from_address = linphone_chat_message_get_from(message); + const LinphoneAddress* to_address = linphone_chat_message_get_to(message); + char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); + printf(" File transfer [%i&] %s of type [%s/%s] %s [%s] \n", (int)(content->size/progress)*100 + ,(linphone_chat_message_is_outgoing(message)?"sent":"received") + , content->type + , content->subtype + ,(linphone_chat_message_is_outgoing(message)?"to":"from") + , address); + free(address); +} +/** + * function invoked when a file transfer is received. + * */ +static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){ + const LinphoneAddress* from_address = linphone_chat_message_get_from(message); + char *from = linphone_address_as_string(from_address); + int file=-1; + printf(" File transfer receive [%i] bytes of type [%s/%s] from [%s] \n" , (int)size + , content->type + , content->subtype + , from); + if (!linphone_chat_message_get_user_data(message)) { + /*first chunk, creating file*/ + file = open("receive_file.dump",O_WRONLY); + linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/ + } else { + /*next chunk*/ + file = (int)linphone_chat_message_get_user_data(message); + } + + /*store content on a file*/ + write(file,buff,size); + + if (size==0) { + printf("File transfert completed"); + close(file); + } /*else wait for next chunk*/ + + free(from); +} + +char big_file [128000]; +/* + * function call when is file transfer is initiated. file content should be feed into object LinphoneContent + * */ +static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){ + const LinphoneAddress* to_address = linphone_chat_message_get_to(message); + char *to = linphone_address_as_string(to_address); + int offset=-1; + /*content->size can be feed*/ + + if (!linphone_chat_message_get_user_data(message)) { + /*first chunk*/ + offset=0; + } else { + /*subsequent chunk*/ + offset = (int)linphone_chat_message_get_user_data(message); + } + *size = MIN(*size,sizeof(big_file)-offset); /*updating content->size with minimun between remaining data and requested size*/ + + if (*size==0) { + /*end of file*/ + return; + } + memcpy(buff,big_file+offset,*size); + + printf(" File transfer sending [%i] bytes of type [%s/%s] from [%s] \n" , (int)*size + , content->type + , content->subtype + , to); + /*store offset for next chunk*/ + linphone_chat_message_set_user_data(message,(void*)(offset+*size)); + + free(to); + +} +/* + * Call back to get delivery status of a message + * */ +static void linphone_file_transfer_state_changed(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { + const LinphoneAddress* to_address = linphone_chat_message_get_to(msg); + char *to = linphone_address_as_string(to_address); + printf("File transfer sent to [%s] delivery status is [%s] \n" , to + , linphone_chat_message_state_to_string(state)); + free(to); +} + +LinphoneCore *lc; +int main(int argc, char *argv[]){ + LinphoneCoreVTable vtable={0}; + + char* dest_friend=NULL; + int i; + const char* big_file_content="big file"; + /*seting dummy file content to something*/ + for (i=0;i1){ + dest_friend=argv[1]; + } + signal(SIGINT,stop); +//#define DEBUG +#ifdef DEBUG + linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/ +#endif + /* + Fill the LinphoneCoreVTable with application callbacks. + All are optional. Here we only use the file_transfer_received callback + in order to get notifications about incoming file receive, file_transfer_send to feed file to be transfered + and file_transfer_progress_indication to print progress. + */ + vtable.file_transfer_received=file_transfer_received; + vtable.file_transfer_send=file_transfer_send; + vtable.file_transfer_progress_indication=file_transfer_progress_indication; + + + /* + Instantiate a LinphoneCore object given the LinphoneCoreVTable + */ + lc=linphone_core_new(&vtable,NULL,NULL,NULL); + + /** + * Globally configure an http file transfer server. + */ + linphone_core_set_file_transfer_server(lc,"http://sharing.linphone.org/upload.php"); + + + /*Next step is to create a chat root*/ + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,dest_friend); + + LinphoneContent content; + memset(&content,0,sizeof(content)); + content.type="text"; + content.subtype="plain"; + content.size=sizeof(big_file); /*total size to be transfered*/ + + /*now create a chat message with custom content*/ + LinphoneChatMessage* chat_message = linphone_chat_room_create_file_transfer_message(chat_room,&content); + + /*initiating file transfer*/ + /**/ + linphone_chat_room_send_message2(chat_room, chat_message,linphone_file_transfer_state_changed,NULL); + + /* main loop for receiving incoming messages and doing background linphone core work: */ + while(running){ + linphone_core_iterate(lc); + ms_usleep(50000); + } + + printf("Shutting down...\n"); + linphone_chat_room_destroy(chat_room); + linphone_core_destroy(lc); + printf("Exited\n"); + return 0; +} + diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fc02cbb23..d57e77278 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -133,8 +133,9 @@ typedef struct belle_sip_dict LinphoneDictionary; struct _LinphoneContent{ char *type; /** a #LinphoneContent with a size equal zero + * + * @param lc #LinphoneCore object + * @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. + * + */ +typedef void (*LinphoneCoreFileTransferSendCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size); + +/** + * File transfer progress indication callback prototype. + * + * @param lc #LinphoneCore object + * @param message #LinphoneChatMessage message from which the body is received. + * @param content #LinphoneContent incoming content information + * @param progress number of bytes sent/received from the begening of the transfer. + * + */ +typedef void (*LinphoneCoreFileTransferProgressIndicationCb)(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t progress); + /** * Is composing notification callback prototype. * @@ -1333,6 +1392,9 @@ typedef struct _LinphoneCoreVTable{ DisplayUrlCb display_url; /**< @deprecated */ ShowInterfaceCb show; /**< @deprecated Notifies the application that it should show up*/ LinphoneCoreTextMessageReceivedCb text_received; /** @deprecated, use #message_received instead
A text message has been received */ + LinphoneCoreFileTransferRecvCb file_transfer_received; /** Callback to store file received attached to a #LinphoneChatMessage */ + LinphoneCoreFileTransferSendCb file_transfer_send; /** Callback to collect file chunk to be sent for a #LinphoneChatMessage */ + LinphoneCoreFileTransferProgressIndicationCb file_transfer_progress_indication; /**Callback to indicate file transfer progress*/ } LinphoneCoreVTable; /** @@ -2452,6 +2514,14 @@ typedef enum _LinphoneToneID LinphoneToneID; LINPHONE_PUBLIC void linphone_core_set_call_error_tone(LinphoneCore *lc, LinphoneReason reason, const char *audiofile); LINPHONE_PUBLIC void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *audiofile); + +/** + * Globaly set an http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml. This value can also be set for a dedicated account using #linphone_proxy_config_set_file_transfer_server + * @param #LinphoneCore to be modified + * @param const char* url of the file server like https://file.linphone.org/upload.php + * */ +LINPHONE_PUBLIC void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url); + #ifdef __cplusplus } #endif From f0d7040fbf1cc8d9cf6c441937966b5c8bc8d3d0 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 20 May 2014 10:24:05 +0200 Subject: [PATCH 002/201] unit tests for transient messages --- tester/message_tester.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tester/message_tester.c b/tester/message_tester.c index 8568492d4..6aa884616 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -234,12 +234,19 @@ static void text_message_with_external_body(void) { LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); linphone_chat_message_set_external_body_url(message,message_external_body_url="http://www.linphone.org"); linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + + /* check transient message list: the message should be in it, and should be the only one */ + CU_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 1); + CU_ASSERT_EQUAL(ms_list_nth_data(chat_room->transient_messages,0), message); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + CU_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 0); + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } @@ -254,10 +261,18 @@ static void text_message_with_send_error(void) { sal_set_send_error(marie->lc->sal, -1); linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,marie->lc); + /* check transient message list: the message should be in it, and should be the only one */ + CU_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 1); + CU_ASSERT_EQUAL(ms_list_nth_data(chat_room->transient_messages,0), message); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); /*CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageInProgress,1);*/ CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageReceived,0); + /* the message should have been discarded from transient list after an error */ + CU_ASSERT_EQUAL(ms_list_size(chat_room->transient_messages), 0); + sal_set_send_error(marie->lc->sal, 0); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); From 20c646bc4a8fce78727ac049fcfdeb90bab1b070 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 20 May 2014 10:49:34 +0200 Subject: [PATCH 003/201] Allow multiple calls to linphone_core_message_storage_init --- coreapi/message_storage.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 434b7e484..8eff460dd 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -87,7 +87,7 @@ static void create_chat_message(char **argv, void *data){ static int callback_all(void *data, int argc, char **argv, char **colName){ LinphoneCore* lc = (LinphoneCore*) data; char* address = argv[0]; - linphone_core_create_chat_room(lc, address); + linphone_core_get_or_create_chat_room(lc, address); return 0; } @@ -378,6 +378,9 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ int ret; const char *errmsg; sqlite3 *db; + + linphone_core_message_storage_close(lc); + ret=sqlite3_open(lc->chat_db_file,&db); if(ret != SQLITE_OK) { errmsg=sqlite3_errmsg(db); From 0dce1b41dbbbe6e3e236cfc8251637b3e89ac2ed Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Tue, 20 May 2014 11:16:38 +0200 Subject: [PATCH 004/201] Don't use printf --- coreapi/message_storage.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 8eff460dd..7b15c15a0 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -321,7 +321,7 @@ static int migrate_messages(void* data,int argc, char** argv, char** column_name sqlite3_free(buf); } } else { - printf("Cannot parse time %s from id %s", argv[1], argv[0]); + ms_warning("Cannot parse time %s from id %s\n", argv[1], argv[0]); } return 0; } @@ -332,10 +332,10 @@ static void linphone_migrate_timestamps(sqlite3* db){ ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1'", migrate_messages, db, &errmsg); if( ret != SQLITE_OK ){ - printf("Error migrating outgoing messages: %s.\n", errmsg); + ms_warning("Error migrating outgoing messages: %s.\n", errmsg); sqlite3_free(errmsg); } else { - printf("Migrated message timestamps to UTC\n"); + ms_message("Migrated message timestamps to UTC\n"); } } From a5e9eff708a8ef767c8417280cd5de21e75a7d8b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 20 May 2014 14:01:21 +0200 Subject: [PATCH 005/201] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 77022250a..ad376cf21 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 77022250a04459648101c3b4152d83158bbe0e63 +Subproject commit ad376cf215143507c1f8e297084e210939e7f31b diff --git a/oRTP b/oRTP index 519fabfed..d8b09cdb5 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 519fabfed1b38c9cde977d4c7a8a7c2bb642e0cb +Subproject commit d8b09cdb524ba1c0eaaeefdca79d5d6daebc19f8 From 93de3b194641cd902492a1ea0656a3ccaa5a660d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 20 May 2014 16:21:39 +0200 Subject: [PATCH 006/201] Update oRTP submodule. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index d8b09cdb5..73317c9bf 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit d8b09cdb524ba1c0eaaeefdca79d5d6daebc19f8 +Subproject commit 73317c9bf59700b44f85008f6e254476bbe756eb From bb6d660594e745c7a2f409b362697e5a5def80d0 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 20 May 2014 18:38:46 +0200 Subject: [PATCH 007/201] rework proxy config management edit()/done() method to only send unregister message when really needed --- coreapi/linphonecore.c | 2 +- coreapi/private.h | 9 +++ coreapi/proxy.c | 112 +++++++++++++++++++++++---- include/sal/sal.h | 3 + tester/register_tester.c | 162 ++++++++++++++++++++++++++++++++++++--- tester/setup_tester.c | 62 ++++++++++++++- 6 files changed, 321 insertions(+), 29 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a77d550ae..157ce6acf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5664,7 +5664,7 @@ void sip_config_uninit(LinphoneCore *lc) if (lc->network_reachable) { for(elem=config->proxies;elem!=NULL;elem=ms_list_next(elem)){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)(elem->data); - linphone_proxy_config_edit(cfg); /* to unregister */ + _linphone_proxy_config_unregister(cfg); /* to unregister without changing the stored flag enable_register */ } ms_message("Unregistration started."); diff --git a/coreapi/private.h b/coreapi/private.h index e3a97b8e5..ae1e109bd 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -393,6 +393,9 @@ LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); static const int linphone_proxy_config_magic=0x7979; +bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); +bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); +void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj); /*chat*/ void linphone_chat_message_destroy(LinphoneChatMessage* msg); @@ -428,6 +431,12 @@ struct _LinphoneProxyConfig void* user_data; time_t deletion_date; LinphonePrivacyMask privacy; + /*use to check if server config has changed between edit() and done()*/ + LinphoneAddress *saved_proxy; + LinphoneAddress *saved_identity; + LinphoneAddress *saved_route; + /*---*/ + }; struct _LinphoneAuthInfo diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 7827dcb82..a71ea868a 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -26,6 +26,60 @@ Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org) #include +/*store current config related to server location*/ +static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* obj) { + if (obj->saved_identity) linphone_address_destroy(obj->saved_identity); + if (obj->reg_identity) + obj->saved_identity = linphone_address_new(obj->reg_identity); + else + obj->saved_identity = NULL; + + if (obj->saved_proxy) linphone_address_destroy(obj->saved_proxy); + if (obj->reg_proxy) + obj->saved_proxy = linphone_address_new(obj->reg_proxy); + else + obj->saved_proxy = NULL; + + if (obj->saved_route) linphone_address_destroy(obj->saved_route); + if (obj->reg_route) + obj->saved_route = linphone_address_new(obj->reg_route); + else + obj->saved_route = NULL; +} + +bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b) { + if (a == NULL && b == NULL) + return TRUE; + else if (!a || !b) + return FALSE; + + if (linphone_address_weak_equal(a,b)) { + /*also check both transport and uri */ + if (!(linphone_address_is_secure(a) ^ linphone_address_is_secure(b))) { + return linphone_address_get_transport(a) == linphone_address_get_transport(b); + } else + return FALSE; /*secure flag not equals*/ + } else + return FALSE; /*either username, domain or port ar not equals*/ + +} + +bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj) { + LinphoneAddress *current_identity=obj->reg_identity?linphone_address_new(obj->reg_identity):NULL; + LinphoneAddress *current_proxy=obj->reg_proxy?linphone_address_new(obj->reg_proxy):NULL; + LinphoneAddress *current_route=obj->reg_route?linphone_address_new(obj->reg_route):NULL; + + if (!linphone_proxy_config_address_equal(obj->saved_identity,current_identity)) + return TRUE; + + if (!linphone_proxy_config_address_equal(obj->saved_proxy,current_proxy)) + return TRUE; + + if (!linphone_proxy_config_address_equal(obj->saved_route,current_route)) + return TRUE; + + return FALSE; +} void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ MSList *elem; @@ -106,6 +160,9 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->publish_op) sal_op_release(obj->publish_op); if (obj->contact_params) ms_free(obj->contact_params); if (obj->contact_uri_params) ms_free(obj->contact_uri_params); + if (obj->saved_proxy!=NULL) linphone_address_destroy(obj->saved_proxy); + if (obj->saved_identity!=NULL) ms_free(obj->saved_identity); + if (obj->saved_route!=NULL) ms_free(obj->saved_route); ms_free(obj); } @@ -265,21 +322,16 @@ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ **/ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ if (obj->publish && obj->publish_op){ - /*unpublish*/ - sal_publish_presence(obj->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL); - sal_op_release(obj->publish_op); - obj->publish_op=NULL; - } - if (obj->reg_sendregister){ - /* unregister */ - if (obj->state == LinphoneRegistrationOk - || obj->state == LinphoneRegistrationProgress) { - sal_unregister(obj->op); - } else { - /*stop refresher*/ - if (obj->op) sal_op_stop_refreshing(obj->op); - } + /*unpublish*/ + sal_publish_presence(obj->publish_op,NULL,NULL,0,(SalPresenceModel *)NULL); + sal_op_release(obj->publish_op); + obj->publish_op=NULL; } + /*store current config related to server location*/ + linphone_proxy_config_store_server_config(obj); + + /*stop refresher in any case*/ + if (obj->op) sal_op_stop_refreshing(obj->op); } void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc){ @@ -336,6 +388,14 @@ LinphoneAddress *guess_contact_for_register(LinphoneProxyConfig *obj){ return ret; } +/** + * unregister without moving the register_enable flag + */ +void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj) { + if (obj->state == LinphoneRegistrationOk) { + sal_unregister(obj->op); + } +} static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ if (obj->reg_sendregister){ @@ -360,8 +420,14 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ } ms_free(proxy_string); } else { - /*stop refresher, just in case*/ - if (obj->op) sal_op_stop_refreshing(obj->op); + /* unregister if registered*/ + if (obj->state == LinphoneRegistrationProgress) { + linphone_proxy_config_set_state(obj,LinphoneRegistrationCleared,"Registration cleared"); + } + _linphone_proxy_config_unregister(obj); + + + } } @@ -843,7 +909,19 @@ int linphone_proxy_config_normalize_number(LinphoneProxyConfig *proxy, const cha **/ int linphone_proxy_config_done(LinphoneProxyConfig *obj) { - if (!linphone_proxy_config_check(obj->lc,obj)) return -1; + if (!linphone_proxy_config_check(obj->lc,obj)) + return -1; + + /*check if server address as changed*/ + if (linphone_proxy_config_is_server_config_changed(obj)) { + /* server config has changed, need to unregister from previous first*/ + if (obj->op) { + _linphone_proxy_config_unregister(obj); + sal_op_set_user_pointer(obj->op,NULL); /*we don't want to receive status for this un register*/ + sal_op_unref(obj->op); /*but we keep refresher to handle authentication if needed*/ + obj->op=NULL; + } + } obj->commit=TRUE; linphone_proxy_config_write_all_to_config_file(obj->lc); return 0; diff --git a/include/sal/sal.h b/include/sal/sal.h index 2d7e4eec8..55c5ebf20 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -551,6 +551,9 @@ void sal_op_set_to_address(SalOp *op, const SalAddress *to); SalOp *sal_op_ref(SalOp* h); void sal_op_stop_refreshing(SalOp *op); void sal_op_release(SalOp *h); +/*same as release, but does not stop refresher if any*/ +void* sal_op_unref(SalOp* op); + void sal_op_authenticate(SalOp *h, const SalAuthInfo *info); void sal_op_cancel_authentication(SalOp *h); void sal_op_set_user_pointer(SalOp *h, void *up); diff --git a/tester/register_tester.c b/tester/register_tester.c index 0798bd61f..15584fc6f 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -119,7 +119,8 @@ static void register_with_refresh_base_3(LinphoneCore* lc linphone_core_add_proxy_config(lc,proxy_cfg); linphone_core_set_default_proxy(lc,proxy_cfg); - while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) && retry++ <310) { + while (counters->number_of_LinphoneRegistrationOk<1+(refresh!=0) + && retry++ <(110 /*only wait 11 s if final state is progress*/+(expected_final_state==LinphoneRegistrationProgress?0:200))) { linphone_core_iterate(lc); if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { if (!linphone_core_get_auth_info_list(lc)) { @@ -197,6 +198,52 @@ static void simple_register(){ linphone_core_manager_destroy(lcm); } +static void simple_unregister(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + register_with_refresh_base(lcm->lc,FALSE,NULL,NULL); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + + linphone_proxy_config_edit(proxy_config); + reset_counters(counters); /*clear stats*/ + + /*nothing is supposed to arrive until done*/ + CU_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + linphone_proxy_config_enable_register(proxy_config,FALSE); + linphone_proxy_config_done(proxy_config); + CU_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1)); + linphone_core_manager_destroy(lcm); +} + +static void change_expires(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + register_with_refresh_base(lcm->lc,FALSE,NULL,NULL); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + + linphone_proxy_config_edit(proxy_config); + reset_counters(counters); /*clear stats*/ + + /*nothing is supposed to arrive until done*/ + CU_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + + linphone_proxy_config_set_expires(proxy_config,3); + + linphone_proxy_config_done(proxy_config); + CU_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,1)); + /*wait 2s without receive refresh*/ + CU_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,2,2000)); + /* now, it should be ok*/ + CU_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,2)); + + + linphone_core_manager_destroy(lcm); +} + /*take care of min expires configuration from server*/ static void simple_register_with_refresh() { LinphoneCoreManager* lcm = create_lcm(); @@ -467,6 +514,101 @@ static void transport_change(){ linphone_core_manager_destroy(mgr); } +static void proxy_transport_change(){ + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + LinphoneAddress* addr; + char* addr_as_string; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base(lcm->lc,FALSE,auth_domain,NULL); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + reset_counters(counters); /*clear stats*/ + linphone_proxy_config_edit(proxy_config); + + CU_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + addr = linphone_address_new(linphone_proxy_config_get_addr(proxy_config)); + + if (LinphoneTransportTcp == linphone_address_get_transport(addr)) { + linphone_address_set_transport(addr,LinphoneTransportUdp); + } else { + linphone_address_set_transport(addr,LinphoneTransportTcp); + } + linphone_proxy_config_set_server_addr(proxy_config,addr_as_string=linphone_address_as_string(addr)); + + linphone_proxy_config_done(proxy_config); + + CU_ASSERT(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,1)); + /*as we change p[roxy server destination, we should'nt be notified about the clear*/ + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + ms_free(addr_as_string); + linphone_address_destroy(addr); + linphone_core_manager_destroy(lcm); + +} +static void proxy_transport_change_with_wrong_port() { + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + char route[256]; + LCSipTransports transport= {LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM}; + sprintf(route,"sip:%s",test_route); + + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base_3(lcm->lc, FALSE, auth_domain, "sip2.linphone.org:5987", 0,transport,LinphoneRegistrationProgress); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + linphone_proxy_config_edit(proxy_config); + + CU_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + linphone_proxy_config_set_server_addr(proxy_config,route); + linphone_proxy_config_done(proxy_config); + + CU_ASSERT(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationOk,1)); + /*as we change proxy server destination, we should'nt be notified about the clear*/ + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationCleared,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); + + linphone_core_manager_destroy(lcm); + +} + +static void proxy_transport_change_with_wrong_port_givin_up() { + LinphoneCoreManager* lcm = create_lcm(); + stats* counters = &lcm->stat; + LinphoneProxyConfig* proxy_config; + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + char route[256]; + LCSipTransports transport= {LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM,LC_SIP_TRANSPORT_RANDOM}; + sprintf(route,"sip:%s",test_route); + + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + + register_with_refresh_base_3(lcm->lc, FALSE, auth_domain, "sip2.linphone.org:5987", 0,transport,LinphoneRegistrationProgress); + + linphone_core_get_default_proxy(lcm->lc,&proxy_config); + linphone_proxy_config_edit(proxy_config); + + CU_ASSERT_FALSE(wait_for_until(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1,3000)); + linphone_proxy_config_enableregister(proxy_config,FALSE); + linphone_proxy_config_done(proxy_config); + + CU_ASSERT(wait_for(lcm->lc,lcm->lc,&counters->number_of_LinphoneRegistrationCleared,1)); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationOk,0); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationProgress,1); + CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0); + + linphone_core_manager_destroy(lcm); + +} + static void io_recv_error(){ LinphoneCoreManager *mgr; LinphoneCore* lc; @@ -567,22 +709,17 @@ static void io_recv_error_without_active_register(){ for (proxys=ms_list_copy(linphone_core_get_proxy_config_list(lc));proxys!=NULL;proxys=proxys->next) { LinphoneProxyConfig* proxy_cfg=(LinphoneProxyConfig*)proxys->data; linphone_proxy_config_edit(proxy_cfg); + linphone_proxy_config_enableregister(proxy_cfg,FALSE); + linphone_proxy_config_done(proxy_cfg); } ms_list_free(proxys); /*wait for unregistrations*/ CU_ASSERT_TRUE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationCleared,register_ok /*because 1 udp*/)); - for (proxys=ms_list_copy(linphone_core_get_proxy_config_list(lc));proxys!=NULL;proxys=proxys->next) { - LinphoneProxyConfig* proxy_cfg=(LinphoneProxyConfig*)proxys->data; - linphone_proxy_config_enable_register(proxy_cfg,FALSE); - linphone_proxy_config_done(proxy_cfg); - } - ms_list_free(proxys); - sal_set_recv_error(lc->sal, 0); /*nothing should happen because no active registration*/ - CU_ASSERT_FALSE(wait_for(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/)); + CU_ASSERT_FALSE(wait_for_until(lc,lc,&counters->number_of_LinphoneRegistrationProgress,2*(register_ok-number_of_udp_proxy) /*because 1 udp*/,3000)); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) @@ -669,6 +806,7 @@ static void tls_wildcard_register(){ test_t register_tests[] = { { "Simple register", simple_register }, + { "Simple register unregister", simple_unregister }, { "TCP register", simple_tcp_register }, { "TCP register compatibility mode", simple_tcp_register_compatibility_mode }, { "TLS register", simple_tls_register }, @@ -688,7 +826,11 @@ test_t register_tests[] = { { "Authenticated register with refresh", simple_auth_register_with_refresh }, { "Register with refresh and send error", register_with_refresh_with_send_error }, { "Multi account", multiple_proxy }, - { "Transport change", transport_change }, + { "Transport changes", transport_change }, + { "Proxy transport changes", proxy_transport_change}, + { "Proxy transport changes with wrong address at first", proxy_transport_change_with_wrong_port}, + { "Proxy transport changes with wrong address, giving up",proxy_transport_change_with_wrong_port_givin_up}, + { "Change expires", change_expires}, { "Network state change", network_state_change }, { "Io recv error", io_recv_error }, { "Io recv error with recovery", io_recv_error_retry_immediatly}, diff --git a/tester/setup_tester.c b/tester/setup_tester.c index dc30e058e..2ef643b86 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -21,7 +21,7 @@ #include "linphonecore.h" #include "liblinphone_tester.h" #include "lpconfig.h" - +#include "private.h" static void core_init_test(void) { LinphoneCoreVTable v_table; @@ -104,10 +104,70 @@ static void linphone_lpconfig_from_buffer(){ lp_config_destroy(conf); } +void linphone_proxy_config_address_equal_test() { + LinphoneAddress *a = linphone_address_new("sip:toto@titi"); + LinphoneAddress *b = linphone_address_new("sips:toto@titi"); + LinphoneAddress *c = linphone_address_new("sip:toto@titi;transport=tcp"); + LinphoneAddress *d = linphone_address_new("sip:toto@titu"); + LinphoneAddress *e = linphone_address_new("sip:toto@titi;transport=udp"); + CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,NULL)); + CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,b)); + CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,c)); + CU_ASSERT_FALSE(linphone_proxy_config_address_equal(a,d)); + CU_ASSERT_TRUE(linphone_proxy_config_address_equal(a,e)); + CU_ASSERT_TRUE(linphone_proxy_config_address_equal(NULL,NULL)); + + linphone_address_destroy(a); + linphone_address_destroy(b); + linphone_address_destroy(c); + linphone_address_destroy(d); +} + +void linphone_proxy_config_is_server_config_changed_test() { + LinphoneProxyConfig* proxy_config = linphone_proxy_config_new(); + + linphone_proxy_config_set_identity(proxy_config,"sip:toto@titi"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_identity(proxy_config,"sips:toto@titi"); + CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_server_addr(proxy_config,"sip:toto.com"); + CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + + linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org:4444"); + CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + + linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org;transport=tcp"); + CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); + + linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org;param=blue"); + CU_ASSERT_FALSE(linphone_proxy_config_is_server_config_changed(proxy_config)); + + + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_set_contact_parameters(proxy_config,"blabla=blue"); + CU_ASSERT_FALSE(linphone_proxy_config_is_server_config_changed(proxy_config)); + + linphone_proxy_config_edit(proxy_config); + linphone_proxy_config_enable_register(proxy_config,TRUE); + CU_ASSERT_FALSE(linphone_proxy_config_is_server_config_changed(proxy_config)); + + linphone_proxy_config_destroy(proxy_config); +} test_t setup_tests[] = { { "Linphone Address", linphone_address_test }, + { "Linphone proxy config address equal (internal api)", linphone_proxy_config_address_equal_test}, + { "Linphone proxy config server address change (internal api)", linphone_proxy_config_is_server_config_changed_test}, { "Linphone core init/uninit", core_init_test }, { "Linphone random transport port",core_sip_transport_test}, { "Linphone interpret url", linphone_interpret_url_test }, From cc5570cae5726e7b0fab31a651cc8a1dc9e90839 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 21 May 2014 10:17:43 +0200 Subject: [PATCH 008/201] proxy route parameter should not be used to check if proxy server address has changed --- coreapi/private.h | 1 - coreapi/proxy.c | 11 ----------- tester/setup_tester.c | 12 ++++++------ 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index ae1e109bd..08db6a40d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -434,7 +434,6 @@ struct _LinphoneProxyConfig /*use to check if server config has changed between edit() and done()*/ LinphoneAddress *saved_proxy; LinphoneAddress *saved_identity; - LinphoneAddress *saved_route; /*---*/ }; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a71ea868a..d7b99aeb2 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -39,12 +39,6 @@ static void linphone_proxy_config_store_server_config(LinphoneProxyConfig* obj) obj->saved_proxy = linphone_address_new(obj->reg_proxy); else obj->saved_proxy = NULL; - - if (obj->saved_route) linphone_address_destroy(obj->saved_route); - if (obj->reg_route) - obj->saved_route = linphone_address_new(obj->reg_route); - else - obj->saved_route = NULL; } bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b) { @@ -67,7 +61,6 @@ bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const Linph bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj) { LinphoneAddress *current_identity=obj->reg_identity?linphone_address_new(obj->reg_identity):NULL; LinphoneAddress *current_proxy=obj->reg_proxy?linphone_address_new(obj->reg_proxy):NULL; - LinphoneAddress *current_route=obj->reg_route?linphone_address_new(obj->reg_route):NULL; if (!linphone_proxy_config_address_equal(obj->saved_identity,current_identity)) return TRUE; @@ -75,9 +68,6 @@ bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* if (!linphone_proxy_config_address_equal(obj->saved_proxy,current_proxy)) return TRUE; - if (!linphone_proxy_config_address_equal(obj->saved_route,current_route)) - return TRUE; - return FALSE; } @@ -162,7 +152,6 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->contact_uri_params) ms_free(obj->contact_uri_params); if (obj->saved_proxy!=NULL) linphone_address_destroy(obj->saved_proxy); if (obj->saved_identity!=NULL) ms_free(obj->saved_identity); - if (obj->saved_route!=NULL) ms_free(obj->saved_route); ms_free(obj); } diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 2ef643b86..760cdf6bd 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -137,19 +137,19 @@ void linphone_proxy_config_is_server_config_changed_test() { linphone_proxy_config_set_server_addr(proxy_config,"sip:toto.com"); CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); - linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); linphone_proxy_config_edit(proxy_config); - linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org:4444"); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org:4444"); CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); - linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); linphone_proxy_config_edit(proxy_config); - linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org;transport=tcp"); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org;transport=tcp"); CU_ASSERT_TRUE(linphone_proxy_config_is_server_config_changed(proxy_config)); - linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org"); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org"); linphone_proxy_config_edit(proxy_config); - linphone_proxy_config_set_route(proxy_config,"sip:sip.linphone.org;param=blue"); + linphone_proxy_config_set_server_addr(proxy_config,"sip:sip.linphone.org;param=blue"); CU_ASSERT_FALSE(linphone_proxy_config_is_server_config_changed(proxy_config)); From fbc8f77e3ab217adc9826afec8b7b50ed2db0884 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 21 May 2014 13:10:34 +0200 Subject: [PATCH 009/201] allow crypto lines to be configured from linphonerc, and improve code handling SRTP crypto lines --- coreapi/bellesip_sal/sal_impl.c | 1 + coreapi/bellesip_sal/sal_sdp.c | 82 ++++++++++++--------------------- coreapi/linphonecall.c | 41 +++++++++++++---- coreapi/linphonecore.c | 1 + coreapi/misc.c | 49 ++++++++++++++++++++ coreapi/offeranswer.c | 5 +- coreapi/private.h | 2 + include/sal/sal.h | 2 +- mediastreamer2 | 2 +- oRTP | 2 +- 10 files changed, 118 insertions(+), 69 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index a35d85822..0212c8a39 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -999,3 +999,4 @@ void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) { belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); belle_sip_main_loop_remove_source(ml, timer); } + diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 50e3504a5..23d0d8be4 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -146,36 +146,15 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session if ( stream->proto == SalProtoRtpSavp ) { /* add crypto lines */ for ( j=0; jcrypto[j].algo ) { - case MS_AES_128_SHA1_80: - enc_name="AES_CM_128_HMAC_SHA1_80"; - break; - case MS_AES_128_SHA1_32: - enc_name="AES_CM_128_HMAC_SHA1_32"; - break; - case MS_AES_256_SHA1_32: - enc_name="AES_CM_256_HMAC_SHA1_32"; - break; - case MS_AES_256_SHA1_80: - enc_name="AES_CM_256_HMAC_SHA1_32"; - break; - case MS_AES_128_NO_AUTH: - ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" ); - break; - case MS_NO_CIPHER_SHA1_80: - ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" ); - break; - default: - j = SAL_CRYPTO_ALGO_MAX; - /* no break */ - } - if (enc_name){ - snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", - stream->crypto[j].tag, enc_name, stream->crypto[j].master_key ); - belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); - } + MSCryptoSuiteNameParams desc; + if (ms_crypto_suite_to_name_params(stream->crypto[j].algo,&desc)==0){ + if (desc.params) + snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s %s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key,desc.params); + else + snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key ); + + belle_sdp_media_description_add_attribute( media_desc,belle_sdp_attribute_create ("crypto", buffer)); + }else break; } } switch ( stream->dir ) { @@ -330,7 +309,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { belle_sip_list_t *attribute_it; belle_sdp_attribute_t *attribute; - char tmp[256], tmp2[256]; + char tmp[256], tmp2[256], parameters[256]={0}; int valid_count = 0; int nb; @@ -341,42 +320,39 @@ static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *med attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data ); if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) { - nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s", + nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s %256s", &stream->crypto[valid_count].tag, tmp, - tmp2 ); - ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", - stream->crypto[valid_count].tag, - tmp, - tmp2 ); - if ( nb == 3 ) { - if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ){ - stream->crypto[valid_count].algo = MS_AES_128_SHA1_80; - }else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ){ - stream->crypto[valid_count].algo = MS_AES_128_SHA1_32; - }else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_32",tmp ) == 0 ){ - stream->crypto[valid_count].algo = MS_AES_256_SHA1_32; - }else if ( keywordcmp ( "AES_CM_256_HMAC_SHA1_80",tmp ) == 0 ){ - stream->crypto[valid_count].algo = MS_AES_256_SHA1_80; - }else { + tmp2, parameters ); + + if ( nb >= 3 ) { + MSCryptoSuite cs; + MSCryptoSuiteNameParams np; + + np.name=tmp; + np.params=parameters[0]!='\0' ? parameters : NULL; + cs=ms_crypto_suite_build_from_name_params(&np); + if (cs==MS_CRYPTO_SUITE_INVALID){ ms_warning ( "Failed to parse crypto-algo: '%s'", tmp ); stream->crypto[valid_count].algo = 0; - } - if ( stream->crypto[valid_count].algo ) { - strncpy ( stream->crypto[valid_count].master_key, tmp2, 41 ); - stream->crypto[valid_count].master_key[40] = '\0'; + }else{ + char *sep; + strncpy ( stream->crypto[valid_count].master_key, tmp2, sizeof(stream->crypto[valid_count].master_key)-1 ); + sep=strchr(stream->crypto[valid_count].master_key,'|'); + if (sep) *sep='\0'; + stream->crypto[valid_count].algo = cs; ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", stream->crypto[valid_count].tag, tmp, stream->crypto[valid_count].master_key ); valid_count++; } - } else { + }else{ ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb ); } } } - ms_message ( "Found: %d valid crypto lines", valid_count ); + ms_message("Found: %d valid crypto lines", valid_count ); } static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 27ce04a3a..b91bf71c2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -232,9 +232,35 @@ static void update_media_description_from_stun(SalMediaDescription *md, const St } } +static int setup_encryption_key(SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, unsigned int tag){ + int keylen=0; + crypto->tag=tag; + crypto->algo=suite; + switch(suite){ + case MS_AES_128_SHA1_80: + case MS_AES_128_SHA1_32: + case MS_AES_128_NO_AUTH: + case MS_NO_CIPHER_SHA1_80: /*not sure for this one*/ + keylen=30; + break; + case MS_AES_256_SHA1_80: + case MS_AES_256_SHA1_32: + keylen=46; + break; + case MS_CRYPTO_SUITE_INVALID: + break; + } + if (keylen==0 || !generate_b64_crypto_key(30, crypto->master_key, SAL_SRTP_KEY_SIZE)){ + ms_error("Could not generate SRTP key."); + crypto->algo = 0; + return -1; + } + return 0; +} + static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ LinphoneCore *lc=call->core; - int i; + int i,j; SalMediaDescription *old_md=call->localdesc; bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1); @@ -247,15 +273,10 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ memcpy(&md->streams[i].crypto[j],&old_md->streams[i].crypto[j],sizeof(SalSrtpCryptoAlgo)); } }else{ - md->streams[i].crypto[0].tag = 1; - md->streams[i].crypto[0].algo = MS_AES_128_SHA1_80; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[0].master_key, SAL_SRTP_KEY_SIZE)) - md->streams[i].crypto[0].algo = 0; - md->streams[i].crypto[1].tag = 2; - md->streams[i].crypto[1].algo = MS_AES_128_SHA1_32; - if (!generate_b64_crypto_key(30, md->streams[i].crypto[1].master_key, SAL_SRTP_KEY_SIZE)) - md->streams[i].crypto[1].algo = 0; - md->streams[i].crypto[2].algo = 0; + const MSCryptoSuite *suites=linphone_core_get_srtp_crypto_suites(lc); + for(j=0;suites!=NULL && suites[j]!=MS_CRYPTO_SUITE_INVALID && jstreams[i].crypto[j],suites[j],j+1); + } } } } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 157ce6acf..a9e472388 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5738,6 +5738,7 @@ void rtp_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout); lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled); lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled); + ms_free(config->srtp_suites); } static void sound_config_uninit(LinphoneCore *lc) diff --git a/coreapi/misc.c b/coreapi/misc.c index 56383fa58..c27147107 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1471,3 +1471,52 @@ void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, const char *aud _linphone_core_set_tone(lc, LinphoneReasonNone, id, audiofile); } +const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){ + const char *config=lp_config_get_string(lc->config,"sip","srtp_crypto_suites","AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_32"); + char *tmp=ms_strdup(config); + char *sep; + char *pos; + char *nextpos; + char *params; + int found=0; + MSCryptoSuite *result=NULL; + pos=tmp; + do{ + sep=strchr(pos,','); + if (!sep) { + sep=pos+strlen(pos); + nextpos=NULL; + }else { + *sep='\0'; + nextpos=sep+1; + } + while(*pos==' ') ++pos; /*strip leading spaces*/ + params=strchr(pos,' '); /*look for params that arrive after crypto suite name*/ + if (params){ + while(*params==' ') ++params; /*strip parameters leading space*/ + } + if (sep-pos>0){ + MSCryptoSuiteNameParams np; + MSCryptoSuite suite; + np.name=pos; + np.params=params; + suite=ms_crypto_suite_build_from_name_params(&np); + if (suite!=MS_CRYPTO_SUITE_INVALID){ + result=ms_realloc(result,found+1+1); + result[found]=suite; + result[found+1]=MS_CRYPTO_SUITE_INVALID; + found++; + ms_message("Configured srtp crypto suite: %s %s",np.name,np.params ? np.params : ""); + } + } + pos=nextpos; + }while(pos); + ms_free(tmp); + if (lc->rtp_conf.srtp_suites){ + ms_free(lc->rtp_conf.srtp_suites); + lc->rtp_conf.srtp_suites=NULL; + } + lc->rtp_conf.srtp_suites=result; + return result; +} + diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index db2a28b76..fd99f421c 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -156,17 +156,16 @@ static bool_t match_crypto_algo(const SalSrtpCryptoAlgo* local, const SalSrtpCry result->algo = remote[i].algo; /* We're answering an SDP offer. Supply our master key, associated with the remote supplied tag */ if (use_local_key) { - strncpy(result->master_key, local[j].master_key, 41); + strncpy(result->master_key, local[j].master_key, sizeof(result->master_key) ); result->tag = remote[i].tag; *choosen_local_tag = local[j].tag; } /* We received an answer to our SDP crypto proposal. Copy matching algo remote master key to result, and memorize local tag */ else { - strncpy(result->master_key, remote[i].master_key, 41); + strncpy(result->master_key, remote[i].master_key, sizeof(result->master_key)); result->tag = local[j].tag; *choosen_local_tag = local[j].tag; } - result->master_key[40] = '\0'; return TRUE; } } diff --git a/coreapi/private.h b/coreapi/private.h index 08db6a40d..d43f6454f 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -519,6 +519,7 @@ typedef struct rtp_config int video_jitt_comp; /*jitter compensation*/ int nortp_timeout; int disable_upnp; + MSCryptoSuite *srtp_suites; bool_t rtp_no_xmit_on_audio_mute; /* stop rtp xmit when audio muted */ bool_t audio_adaptive_jitt_comp_enabled; @@ -886,6 +887,7 @@ static inline const LinphoneErrorInfo *linphone_error_info_from_sal_op(const Sal return (const LinphoneErrorInfo*)sal_op_get_error_info(op); } +const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc); /** Belle Sip-based objects need unique ids */ diff --git a/include/sal/sal.h b/include/sal/sal.h index 55c5ebf20..fbeaf2e14 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -166,7 +166,7 @@ typedef struct SalIceRemoteCandidate { #define SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN 256 /*sufficient for 256bit keys encoded in base 64*/ -#define SAL_SRTP_KEY_SIZE 64 +#define SAL_SRTP_KEY_SIZE 128 typedef struct SalSrtpCryptoAlgo { unsigned int tag; diff --git a/mediastreamer2 b/mediastreamer2 index ad376cf21..b6ad773d4 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ad376cf215143507c1f8e297084e210939e7f31b +Subproject commit b6ad773d4896b36fd707b6fc4f743b6b7df7325a diff --git a/oRTP b/oRTP index 73317c9bf..e4f28d143 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 73317c9bf59700b44f85008f6e254476bbe756eb +Subproject commit e4f28d1434b8f18061fb6a45a80649c4bc13cf9a From da54b475d78f0fbb56dd4cba94fc2a9782613362 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 21 May 2014 15:43:58 +0200 Subject: [PATCH 010/201] improve management of comments in linphonerc parser --- coreapi/lpconfig.c | 102 ++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 34 deletions(-) diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index 0ac692cde..9dcce9f4d 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -49,6 +49,7 @@ typedef struct _LpItem{ char *key; char *value; + int is_comment; } LpItem; typedef struct _LpSectionParam{ @@ -78,6 +79,13 @@ LpItem * lp_item_new(const char *key, const char *value){ return item; } +LpItem * lp_comment_new(const char *comment){ + LpItem *item=lp_new0(LpItem,1); + item->value=ortp_strdup(comment); + item->is_comment=TRUE; + return item; +} + LpSectionParam *lp_section_param_new(const char *key, const char *value){ LpSectionParam *param = lp_new0(LpSectionParam, 1); param->key = ortp_strdup(key); @@ -93,7 +101,7 @@ LpSection *lp_section_new(const char *name){ void lp_item_destroy(void *pitem){ LpItem *item=(LpItem*)pitem; - ortp_free(item->key); + if (item->key) ortp_free(item->key); ortp_free(item->value); free(item); } @@ -138,6 +146,14 @@ static bool_t is_first_char(const char *start, const char *pos){ return TRUE; } +static int is_a_comment(const char *str){ + while (*str==' '){ + str++; + } + if (*str=='#') return 1; + return 0; +} + LpSection *lp_config_find_section(const LpConfig *lpconfig, const char *name){ LpSection *sec; MSList *elem; @@ -170,7 +186,7 @@ LpItem *lp_section_find_item(const LpSection *sec, const char *name){ /*printf("Looking for item %s\n",name);*/ for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){ item=(LpItem*)elem->data; - if (strcmp(item->key,name)==0) { + if (!item->is_comment && strcmp(item->key,name)==0) { /*printf("Item %s found\n",name);*/ return item; } @@ -182,9 +198,10 @@ static LpSection* lp_config_parse_line(LpConfig* lpconfig, const char* line, LpS LpSectionParam *params = NULL; char *pos1,*pos2; int nbs; - static char secname[MAX_LEN]; - static char key[MAX_LEN]; - static char value[MAX_LEN]; + int size=strlen(line)+1; + char *secname=ms_malloc(size); + char *key=ms_malloc(size); + char *value=ms_malloc(size); LpItem *item; pos1=strchr(line,'['); @@ -230,43 +247,53 @@ static LpSection* lp_config_parse_line(LpConfig* lpconfig, const char* line, LpS } } }else { - pos1=strchr(line,'='); - if (pos1!=NULL){ - key[0]='\0'; + if (is_a_comment(line)){ + if (cur){ + LpItem *comment=lp_comment_new(line); + lp_section_add_item(cur,comment); + } + }else{ + pos1=strchr(line,'='); + if (pos1!=NULL){ + key[0]='\0'; - *pos1='\0'; - if (sscanf(line,"%s",key)>0){ + *pos1='\0'; + if (sscanf(line,"%s",key)>0){ - pos1++; - pos2=strchr(pos1,'\r'); - if (pos2==NULL) - pos2=strchr(pos1,'\n'); - if (pos2==NULL) pos2=pos1+strlen(pos1); - else { - *pos2='\0'; /*replace the '\n' */ - } - /* remove ending white spaces */ - for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0'; + pos1++; + pos2=strchr(pos1,'\r'); + if (pos2==NULL) + pos2=strchr(pos1,'\n'); + if (pos2==NULL) pos2=pos1+strlen(pos1); + else { + *pos2='\0'; /*replace the '\n' */ + } + /* remove ending white spaces */ + for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0'; - if (pos2-pos1>=0){ - /* found a pair key,value */ + if (pos2-pos1>=0){ + /* found a pair key,value */ - if (cur!=NULL){ - item=lp_section_find_item(cur,key); - if (item==NULL){ - lp_section_add_item(cur,lp_item_new(key,pos1)); + if (cur!=NULL){ + item=lp_section_find_item(cur,key); + if (item==NULL){ + lp_section_add_item(cur,lp_item_new(key,pos1)); + }else{ + ortp_free(item->value); + item->value=ortp_strdup(pos1); + } + /*ms_message("Found %s=%s",key,pos1);*/ }else{ - ortp_free(item->value); - item->value=ortp_strdup(pos1); + ms_warning("found key,item but no sections"); } - /*ms_message("Found %s=%s",key,pos1);*/ - }else{ - ms_warning("found key,item but no sections"); } } } } } + ms_free(key); + ms_free(value); + ms_free(secname); return cur; } @@ -425,13 +452,16 @@ bool_t lp_config_get_range(const LpConfig *lpconfig, const char *section, const } } + int lp_config_get_int(const LpConfig *lpconfig,const char *section, const char *key, int default_value){ const char *str=lp_config_get_string(lpconfig,section,key,NULL); if (str!=NULL) { int ret=0; + if (strstr(str,"0x")==str){ sscanf(str,"%x",&ret); - }else ret=atoi(str); + }else + sscanf(str,"%i",&ret); return ret; } else return default_value; @@ -510,7 +540,10 @@ void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key } void lp_item_write(LpItem *item, FILE *file){ - fprintf(file,"%s=%s\n",item->key,item->value); + if (item->is_comment) + fprintf(file,"%s",item->value); + else + fprintf(file,"%s=%s\n",item->key,item->value); } void lp_section_param_write(LpSectionParam *param, FILE *file){ @@ -566,7 +599,8 @@ void lp_config_for_each_entry(const LpConfig *lpconfig, const char *section, voi if (sec!=NULL){ for (elem=sec->items;elem!=NULL;elem=ms_list_next(elem)){ item=(LpItem*)elem->data; - callback(item->key, ctx); + if (!item->is_comment) + callback(item->key, ctx); } } } From e93ac6bf319e761563f8c8864b1c3269b4ef4430 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 21 May 2014 15:59:25 +0200 Subject: [PATCH 011/201] add test for Simple conference with ICE --- tester/call_tester.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index d20cf1fd6..60c9b8d6b 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1221,10 +1221,8 @@ static void call_waiting_indication_with_privacy(void) { call_waiting_indication_with_param(TRUE); } -static void simple_conference(void) { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); +static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManager* pauline, LinphoneCoreManager* laure) { + stats initial_marie_stat; stats initial_pauline_stat; stats initial_laure_stat; @@ -1266,6 +1264,16 @@ static void simple_conference(void) { CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) + if (linphone_core_get_firewall_policy(marie->lc) == LinphonePolicyUseIce) { + if (linphone_core_get_firewall_policy(pauline->lc) == LinphonePolicyUseIce) { + check_ice(marie,pauline,LinphoneIceStateHostConnection); + } + if (linphone_core_get_firewall_policy(laure->lc) == LinphonePolicyUseIce) { + check_ice(marie,laure,LinphoneIceStateHostConnection); + } + } + + linphone_core_terminate_conference(marie->lc); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); @@ -1273,10 +1281,35 @@ static void simple_conference(void) { CU_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,2000)); + + ms_list_free(lcs); +} +static void simple_conference(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + simple_conference_base(marie,pauline,laure); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(laure); +} + +static void simple_conference_with_ice(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + linphone_core_set_firewall_policy(laure->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(laure->lc,"stun.linphone.org"); + + simple_conference_base(marie,pauline,laure); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(laure); - ms_list_free(lcs); } static void srtp_call() { @@ -2173,6 +2206,7 @@ test_t call_tests[] = { { "Call waiting indication", call_waiting_indication }, { "Call waiting indication with privacy", call_waiting_indication_with_privacy }, { "Simple conference", simple_conference }, + { "Simple conference with ICE",simple_conference_with_ice}, { "Simple call transfer", simple_call_transfer }, { "Unattended call transfer", unattended_call_transfer }, { "Unattended call transfer with error", unattended_call_transfer_with_error }, From 78e59e5bec2fb8c44811118e4181776a8c9cf566 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 21 May 2014 16:03:52 +0200 Subject: [PATCH 012/201] suppress warnings --- coreapi/message_storage.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 7b15c15a0..5a66393f4 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -321,7 +321,7 @@ static int migrate_messages(void* data,int argc, char** argv, char** column_name sqlite3_free(buf); } } else { - ms_warning("Cannot parse time %s from id %s\n", argv[1], argv[0]); + ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]); } return 0; } @@ -335,7 +335,7 @@ static void linphone_migrate_timestamps(sqlite3* db){ ms_warning("Error migrating outgoing messages: %s.\n", errmsg); sqlite3_free(errmsg); } else { - ms_message("Migrated message timestamps to UTC\n"); + ms_message("Migrated message timestamps to UTC"); } } @@ -346,7 +346,7 @@ void linphone_update_table(sqlite3* db) { // for image url storage ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); if(ret != SQLITE_OK) { - ms_warning("Table already up to date: %s.\n", errmsg); + ms_message("Table already up to date: %s.", errmsg); sqlite3_free(errmsg); } else { ms_debug("Table updated successfully for URL."); @@ -355,14 +355,13 @@ void linphone_update_table(sqlite3* db) { // for UTC timestamp storage ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg); if( ret != SQLITE_OK ){ - ms_warning("Table already up to date: %s.\n", errmsg); + ms_message("Table already up to date: %s.", errmsg); sqlite3_free(errmsg); } else { ms_debug("Table updated successfully for UTC."); + // migrate from old text-based timestamps to unix time-based timestamps + linphone_migrate_timestamps(db); } - - // migrate from old text-based timestamps to unix time-based timestamps - linphone_migrate_timestamps(db); } void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { From 5f9076251368c733bcd7befcc0bbd4011c2e4d42 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 21 May 2014 16:25:32 +0200 Subject: [PATCH 013/201] fix crash with conference and ICE --- coreapi/conference.c | 3 ++- tester/call_tester.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/coreapi/conference.c b/coreapi/conference.c index 9e6dc7730..7bee313dd 100644 --- a/coreapi/conference.c +++ b/coreapi/conference.c @@ -200,7 +200,8 @@ int linphone_core_add_to_conference(LinphoneCore *lc, LinphoneCall *call){ params->has_video=FALSE; if (call->audiostream || call->videostream){ - linphone_call_stop_media_streams (call); /*free the audio & video local resources*/ + linphone_call_stop_media_streams(call); /*free the audio & video local resources*/ + linphone_call_init_media_streams(call); } if (call==lc->current_call){ lc->current_call=NULL; diff --git a/tester/call_tester.c b/tester/call_tester.c index 60c9b8d6b..852bc4d68 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1264,6 +1264,8 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag CU_ASSERT_TRUE(linphone_core_is_in_conference(marie->lc)); CU_ASSERT_EQUAL(linphone_core_get_conference_size(marie->lc),3) + /* + * FIXME: check_ice cannot work as it is today because there is no current call for the party that hosts the conference if (linphone_core_get_firewall_policy(marie->lc) == LinphonePolicyUseIce) { if (linphone_core_get_firewall_policy(pauline->lc) == LinphonePolicyUseIce) { check_ice(marie,pauline,LinphoneIceStateHostConnection); @@ -1272,7 +1274,7 @@ static void simple_conference_base(LinphoneCoreManager* marie, LinphoneCoreManag check_ice(marie,laure,LinphoneIceStateHostConnection); } } - + */ linphone_core_terminate_conference(marie->lc); From d9a4b6e15e97dc59ec13fa24840111b4d909a522 Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Wed, 21 May 2014 16:27:24 +0200 Subject: [PATCH 014/201] propertybox: only expose simple display filter in video out setting Do not expose 'decode and display' type filter. --- gtk/propertybox.c | 55 ++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 598e2f384..81d3db345 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -25,8 +25,8 @@ void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const c const char **p=devices; int i=0,active=-1; GtkTreeModel *model; - - + + if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ /*case where combo box is created with no model*/ GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); @@ -40,7 +40,7 @@ void linphone_gtk_fill_combo_box(GtkWidget *combo, const char **devices, const c unless we fill it with a dummy text. This dummy text needs to be removed first*/ } - + for(;*p!=NULL;++p){ if ( cap==CAP_IGNORE || (cap==CAP_CAPTURE && linphone_core_sound_device_can_capture(linphone_gtk_get_core(),*p)) @@ -836,9 +836,9 @@ static void linphone_gtk_proxy_closed(GtkWidget *w){ static void fill_transport_combo_box(GtkWidget *combo, LinphoneTransportType choice, gboolean is_sensitive){ GtkTreeModel *model; GtkTreeIter iter; - + if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo),"combo-updating"))) return; - + if ((model=gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))==NULL){ /*case where combo box is created with no model*/ GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); @@ -882,9 +882,9 @@ void linphone_gtk_proxy_transport_changed(GtkWidget *combo){ const char *addr=gtk_entry_get_text(GTK_ENTRY(proxy)); LinphoneAddress *laddr; LinphoneTransportType new_transport=(LinphoneTransportType)index; - + if (index==-1) return; - + g_object_set_data(G_OBJECT(w),"combo-updating",GINT_TO_POINTER(1)); laddr=linphone_address_new(addr); if (laddr){ @@ -941,7 +941,7 @@ void linphone_gtk_proxy_ok(GtkButton *button){ int index=gtk_combo_box_get_active(GTK_COMBO_BOX(linphone_gtk_get_widget(w,"transport"))); LinphoneTransportType tport=(LinphoneTransportType)index; gboolean was_editing=TRUE; - + if (!cfg){ was_editing=FALSE; cfg=linphone_proxy_config_new(); @@ -978,7 +978,7 @@ void linphone_gtk_proxy_ok(GtkButton *button){ linphone_proxy_config_enable_register(cfg, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")))); - + /* check if tls was asked but is not enabled in transport configuration*/ if (tport==LinphoneTransportTls){ LCSipTransports tports; @@ -988,7 +988,7 @@ void linphone_gtk_proxy_ok(GtkButton *button){ } linphone_core_set_sip_transports(lc,&tports); } - + if (was_editing){ if (linphone_proxy_config_done(cfg)==-1) return; @@ -1203,15 +1203,15 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){ GtkListStore *store; GtkTreeIter iter; GtkCellRenderer *renderer=gtk_cell_renderer_text_new(); - + model=GTK_TREE_MODEL((store=gtk_list_store_new(1,G_TYPE_STRING))); gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",0,NULL); - + gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,_("None"),-1); - + if (linphone_core_media_encryption_supported(lc,LinphoneMediaEncryptionSRTP)){ gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,_("SRTP"),-1); @@ -1293,19 +1293,26 @@ void linphone_gtk_fill_video_renderers(GtkWidget *pb){ GtkTreeModel *model=GTK_TREE_MODEL(store=gtk_list_store_new(2,G_TYPE_STRING,G_TYPE_STRING)); if (current_renderer==NULL) current_renderer=video_stream_get_default_video_renderer(); - + gtk_combo_box_set_model(GTK_COMBO_BOX(combo),model); gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo)); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),renderer,TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo),renderer,"text",1,NULL); - - for(i=0,elem=l;elem!=NULL && i<4 ;elem=elem->next,++i){ + + for(i=0,elem=l;elem!=NULL && i<4 ;elem=elem->next){ MSFilterDesc *desc=(MSFilterDesc *)elem->data; GtkTreeIter iter; + + /* do not offer the user to select combo 'decoding/rendering' filter */ + if (desc->enc_fmt != NULL) + continue; + gtk_list_store_append(store,&iter); gtk_list_store_set(store,&iter,0,desc->name,1,desc->text,-1); if (current_renderer && strcmp(current_renderer,desc->name)==0) active=i; + + i++; } ms_list_free(l); if (active!=-1) gtk_combo_box_set_active(GTK_COMBO_BOX(combo),active); @@ -1386,7 +1393,7 @@ void linphone_gtk_show_parameters(void){ tr.udp_port); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"sip_tcp_port")), tr.tcp_port); - + linphone_core_get_audio_port_range(lc, &min_port, &max_port); gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port); @@ -1404,7 +1411,7 @@ void linphone_gtk_show_parameters(void){ } linphone_gtk_show_media_encryption(pb); - + tmp=linphone_core_get_nat_address(lc); if (tmp) gtk_entry_set_text(GTK_ENTRY(linphone_gtk_get_widget(pb,"nat_address")),tmp); tmp=linphone_core_get_stun_server(lc); @@ -1548,9 +1555,9 @@ void linphone_gtk_edit_tunnel(GtkButton *button){ const MSList *configs; const char *host = NULL; int port=0; - + if (!tunnel) return; - + configs = linphone_tunnel_get_servers(tunnel); if(configs != NULL) { LinphoneTunnelConfig *ltc = (LinphoneTunnelConfig *)configs->data; @@ -1598,7 +1605,7 @@ void linphone_gtk_tunnel_ok(GtkButton *button){ gint http_port = (gint)gtk_spin_button_get_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"http_port"))); const char *username=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"username"))); const char *password=gtk_entry_get_text(GTK_ENTRY(linphone_gtk_get_widget(w,"password"))); - + if (tunnel==NULL) return; if (host && *host=='\0') host=NULL; if (http_port==0) http_port=8080; @@ -1608,7 +1615,7 @@ void linphone_gtk_tunnel_ok(GtkButton *button){ linphone_tunnel_add_server(tunnel, config); linphone_tunnel_enable(tunnel,enabled); linphone_tunnel_set_http_proxy(tunnel,http_host,http_port,username,password); - + gtk_widget_destroy(w); } @@ -1621,7 +1628,7 @@ static void show_dscp(GtkWidget *entry, int val){ char tmp[20]; snprintf(tmp,sizeof(tmp),"0x%x",val); gtk_entry_set_text(GTK_ENTRY(entry),tmp); - + } static int read_dscp(GtkWidget *entry){ @@ -1660,7 +1667,7 @@ void linphone_gtk_dscp_edit_response(GtkWidget *dialog, guint response_id){ read_dscp(linphone_gtk_get_widget(dialog,"audio_dscp"))); linphone_core_set_video_dscp(lc, read_dscp(linphone_gtk_get_widget(dialog,"video_dscp"))); - + break; default: break; From e15cc87d5ba153d34c037dafa1c926e0ef47126c Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 21 May 2014 17:29:15 +0200 Subject: [PATCH 015/201] Set RTCP information before starting the streams. --- coreapi/linphonecall.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b91bf71c2..d077b6de2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1981,6 +1981,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna } } configure_rtp_session_for_rtcp_xr(lc, call, SalAudio); + audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); audio_stream_start_full( call->audiostream, call->audio_profile, @@ -2007,7 +2008,6 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna if (send_ringbacktone){ setup_ring_player(lc,call); } - audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); if (call->params.in_conference){ /*transform the graph to connect it to the conference filter */ @@ -2105,12 +2105,12 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna video_stream_set_direction (call->videostream, dir); ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); video_stream_set_device_rotation(call->videostream, lc->device_rotation); + video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); video_stream_start(call->videostream, call->video_profile, rtp_addr, vstream->rtp_port, rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0, used_pt, linphone_core_get_video_jittcomp(lc), cam); - video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool); } }else ms_warning("No video stream accepted."); }else{ From 617522f78fa60e615576e8ff6fa67719a9894865 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 22 May 2014 09:54:01 +0200 Subject: [PATCH 016/201] Fix warning with linphone.png when starting linphone. --- gtk/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index 2fd3fd897..d49fba466 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -2269,6 +2269,9 @@ int main(int argc, char *argv[]){ } } #endif + add_pixmap_directory("pixmaps"); + add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); + /* Now, look for the factory configuration file, we do it this late since we want to have had time to change directory and to parse the options, in case we needed to access the working directory */ @@ -2283,9 +2286,6 @@ int main(int argc, char *argv[]){ pbuf=create_pixbuf(icon_path); if (pbuf!=NULL) gtk_window_set_default_icon(pbuf); - add_pixmap_directory("pixmaps"); - add_pixmap_directory(PACKAGE_DATA_DIR "/pixmaps/linphone"); - #ifdef HAVE_GTK_OSX GtkosxApplication *theMacApp = gtkosx_application_get(); g_signal_connect(G_OBJECT(theMacApp),"NSApplicationDidBecomeActive",(GCallback)linphone_gtk_show_main_window,NULL); From fa44718513de0dfb22626d7d3841ad04fdd67dd0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 22 May 2014 10:05:26 +0200 Subject: [PATCH 017/201] Fix icon in notifications. --- gtk/main.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index d49fba466..c1a52cda4 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1313,12 +1313,16 @@ static bool_t notify_actions_supported() { return accepts_actions; } -static NotifyNotification* build_notification(const char *title, const char *body){ - return notify_notification_new(title,body,linphone_gtk_get_ui_config("icon",LINPHONE_ICON) +static NotifyNotification* build_notification(const char *title, const char *body) { + const char *icon_path = linphone_gtk_get_ui_config("icon", LINPHONE_ICON); + GdkPixbuf *pbuf = create_pixbuf(icon_path); + NotifyNotification *n = notify_notification_new(title, body, NULL #ifdef HAVE_NOTIFY1 - ,NULL + ,NULL #endif ); + notify_notification_set_icon_from_pixbuf(n, pbuf); + return n; } static void show_notification(NotifyNotification* n){ From 76a5f51e35a14778da2fc5ab9b0ce49186099e7e Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 22 May 2014 13:41:46 +0200 Subject: [PATCH 018/201] Use storage id for storing the message state, instead of filtering by message and time. This was historically used because notifications of the new message state would supposedly be made with a new instance of the same message, so without a correct storage_id. I verified that this is not the case anymore. --- coreapi/message_storage.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 5a66393f4..b45b1afb1 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -156,12 +156,9 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ void linphone_chat_message_store_state(LinphoneChatMessage *msg){ LinphoneCore *lc=msg->chat_room->lc; if (lc->db){ - char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE message = %Q AND utc = %i;", - msg->state,msg->message,msg->time); - linphone_sql_request(lc->db,buf); + char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE id = %i;",msg->state,msg->storage_id); + linphone_sql_request(lc->db,buf); sqlite3_free(buf); - - } if( msg->state == LinphoneChatMessageStateDelivered From 43e42a55f54da89e09d02811f9fcdf21cd4b9f14 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 22 May 2014 14:40:42 +0200 Subject: [PATCH 019/201] Better fix: just in case, don't use the storage id and use a better search condition. --- coreapi/message_storage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index b45b1afb1..3676b5685 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -156,7 +156,8 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ void linphone_chat_message_store_state(LinphoneChatMessage *msg){ LinphoneCore *lc=msg->chat_room->lc; if (lc->db){ - char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE id = %i;",msg->state,msg->storage_id); + char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (message = %Q OR url = %Q) AND utc = %i;", + msg->state,msg->message,msg->external_body_url,msg->time); linphone_sql_request(lc->db,buf); sqlite3_free(buf); } From d6e43a065b07296d7f20d4608e5031015fb30d91 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 22 May 2014 16:55:03 +0200 Subject: [PATCH 020/201] remove GPLv3 notice from zRTP message in configure.ac --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index b3c66dc98..2cf308b87 100644 --- a/configure.ac +++ b/configure.ac @@ -924,7 +924,7 @@ printf "* %-30s %s\n" "Account assistant" $build_wizard printf "* %-30s %s\n" "Console interface" $console_ui printf "* %-30s %s\n" "Tools" $build_tools printf "* %-30s %s\n" "Message storage" $enable_msg_storage -printf "* %-30s %s\n" "zRTP encryption (GPLv3)" $zrtp +printf "* %-30s %s\n" "zRTP encryption" $zrtp printf "* %-30s %s\n" "uPnP support" $build_upnp printf "* %-30s %s\n" "LDAP support" $enable_ldap From 23e9ed4a34d559e24e20abe1bee056077b5e677f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 22 May 2014 19:07:11 +0200 Subject: [PATCH 021/201] update ms2 for conference bugfix --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b6ad773d4..a99d6b0dc 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b6ad773d4896b36fd707b6fc4f743b6b7df7325a +Subproject commit a99d6b0dc3f631a69e0aa46107213c5ebe45c1e3 From 063f0a4c19fab6dbf3f64854e8521ef6ff304e0a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 23 May 2014 11:44:35 +0200 Subject: [PATCH 022/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index a99d6b0dc..ce59013ae 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a99d6b0dc3f631a69e0aa46107213c5ebe45c1e3 +Subproject commit ce59013ae65791bd9fecf18462477c94ab24655a From 3c770cac9a1253d1a8aaa4c57a6f2a6a917d539f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 26 May 2014 10:10:02 +0200 Subject: [PATCH 023/201] Remove call to RTCP interval functions that no longer exist. --- coreapi/linphonecall.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d077b6de2..04023c386 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1880,15 +1880,6 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca session = call->videostream->ms.sessions.rtp_session; } rtp_session_configure_rtcp_xr(session, ¤tconfig); - if (currentconfig.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) { - rtp_session_set_rtcp_xr_rcvr_rtt_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_rcvr_rtt_interval_duration", 5000)); - } - if (currentconfig.stat_summary_enabled == TRUE) { - rtp_session_set_rtcp_xr_stat_summary_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_stat_summary_interval_duration", 5000)); - } - if (currentconfig.voip_metrics_enabled == TRUE) { - rtp_session_set_rtcp_xr_voip_metrics_interval(session, lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_interval_duration", 5000)); - } } static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){ From 0ddfbbb5745e0dc86ccfe5a35fb3b4cbb421c368 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 26 May 2014 10:10:49 +0200 Subject: [PATCH 024/201] Update oRTP and ms2 submodules for AVPF work. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index ce59013ae..4da992ba5 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ce59013ae65791bd9fecf18462477c94ab24655a +Subproject commit 4da992ba5695d51e84c832c20934c8c5bb73b3af diff --git a/oRTP b/oRTP index e4f28d143..902fd26d9 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit e4f28d1434b8f18061fb6a45a80649c4bc13cf9a +Subproject commit 902fd26d9c81665d48bea43e7771b3dc79f9e819 From 7b8a7a32ae15f965820bea51ed2b9e4af55907ad Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 26 May 2014 14:18:00 +0200 Subject: [PATCH 025/201] update ms2 and ortp for audio mixer bugfi --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 4da992ba5..4d6563b75 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4da992ba5695d51e84c832c20934c8c5bb73b3af +Subproject commit 4d6563b753e16e60fd5ece9bfa79c3be516ceaab diff --git a/oRTP b/oRTP index 902fd26d9..2f3ce6970 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 902fd26d9c81665d48bea43e7771b3dc79f9e819 +Subproject commit 2f3ce697093694165a31f024a3141cd89a95bc42 From 550af5a8c75fa0485918911f70ae1ce686395737 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 26 May 2014 22:10:05 +0200 Subject: [PATCH 026/201] fix linphone_proxy_config_edit() calls unbalanced with linphone_proxy_config_done() calls. This caused regressions, like for example linphone_core_clear_proxy_config() not sending any unREGISTER. --- coreapi/TunnelManager.cc | 110 ++------------------------------------- coreapi/proxy.c | 4 +- 2 files changed, 8 insertions(+), 106 deletions(-) diff --git a/coreapi/TunnelManager.cc b/coreapi/TunnelManager.cc index efac8fbb0..2bc8cd3e0 100644 --- a/coreapi/TunnelManager.cc +++ b/coreapi/TunnelManager.cc @@ -30,82 +30,6 @@ using namespace belledonnecomm; using namespace ::std; -#ifndef USE_BELLESIP - -Mutex TunnelManager::sMutex; - -int TunnelManager::eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata){ - TunnelManager* lTunnelMgr=(TunnelManager*)userdata; - - sMutex.lock(); - if (lTunnelMgr->mSipSocket==NULL){ - sMutex.unlock(); - return len; - } - lTunnelMgr->mSipSocket->sendto(buf,len,to,tolen); - sMutex.unlock(); - //ignore the error in all cases, retransmissions might be successful. - return len; -} - -int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen,void* userdata){ - TunnelManager* lTunnelMgr=(TunnelManager*)userdata; - int err; - sMutex.lock(); - if (lTunnelMgr->mSipSocket==NULL){ - sMutex.unlock(); - return 0;//let ignore the error - } - err=lTunnelMgr->mSipSocket->recvfrom(buf,len,from,*fromlen); - sMutex.unlock(); - return err; -} - -int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){ - struct timeval begin,cur; - TunnelManager* lTunnelMgr=(TunnelManager*)userdata; - if (s1 && tv!=0 && tv->tv_sec){ - /*this is the select from udp.c, the one that is interesting to us*/ - NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket(); - NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd(); - - FD_ZERO(s1); - gettimeofday(&begin,NULL); - do{ - struct timeval abit; - - abit.tv_sec=0; - abit.tv_usec=20000; - sMutex.lock(); - if (lTunnelMgr->mSipSocket!=NULL){ - if (lTunnelMgr->mSipSocket->hasData()) { - sMutex.unlock(); - /* we make exosip believe that it has udp data to read*/ - FD_SET(udp_fd,s1); - return 1; - } - } - sMutex.unlock(); - gettimeofday(&cur,NULL); - if (cur.tv_sec-begin.tv_sec>tv->tv_sec) { - FD_SET(controlfd,s1); - FD_SET(udp_fd,s1); - return 0; - } - FD_ZERO(s1); - FD_SET(controlfd,s1); - if (select(max_fds,s1,s2,s3,&abit)==1) { - return 1; - } - }while(1); - - }else{ - /*select called from other places, only the control fd is present */ - return select(max_fds,s1,s2,s3,tv); - } -} -#endif - void TunnelManager::addServer(const char *ip, int port,unsigned int udpMirrorPort,unsigned int delay) { if (ip == NULL) { @@ -186,10 +110,6 @@ void TunnelManager::start() { mTunnelClient->setHttpProxy(mHttpProxyHost.c_str(), mHttpProxyPort, mHttpUserName.c_str(), mHttpPasswd.c_str()); } mTunnelClient->start(); - -#ifndef USE_BELLESIP - if (mSipSocket == NULL) mSipSocket =mTunnelClient->createSocket(5060); -#endif } bool TunnelManager::isStarted() { @@ -217,9 +137,6 @@ int TunnelManager::customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flag TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mCore(lc) -#ifndef USE_BELLESIP -,mSipSocket(NULL) -#endif ,mCallback(NULL) ,mEnabled(false) ,mTunnelClient(NULL) @@ -227,12 +144,6 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController() ,mReady(false) ,mHttpProxyPort(0){ -#ifndef USE_BELLESIP - mExosipTransport.data=this; - mExosipTransport.recvfrom=eXosipRecvfrom; - mExosipTransport.sendto=eXosipSendto; - mExosipTransport.select=eXosipSelect; -#endif linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this); mTransportFactories.audio_rtcp_func=sCreateRtpTransport; mTransportFactories.audio_rtcp_func_data=this; @@ -249,17 +160,7 @@ TunnelManager::~TunnelManager(){ } void TunnelManager::stopClient(){ -#ifdef USE_BELLESIP sal_disable_tunnel(mCore->sal); -#else - eXosip_transport_hook_register(NULL); - if (mSipSocket != NULL){ - sMutex.lock(); - mTunnelClient->closeSocket(mSipSocket); - mSipSocket = NULL; - sMutex.unlock(); - } -#endif if (mTunnelClient){ delete mTunnelClient; mTunnelClient=NULL; @@ -279,16 +180,11 @@ void TunnelManager::processTunnelEvent(const Event &ev){ //register if (lProxy) { - linphone_proxy_config_done(lProxy); + linphone_proxy_config_refresh_register(lProxy); } mReady=true; }else if (mEnabled && !mTunnelClient->isReady()){ /* we got disconnected from the tunnel */ - if (lProxy && linphone_proxy_config_is_registered(lProxy)) { - /*forces de-registration so that we register again when the tunnel is up*/ - linphone_proxy_config_edit(lProxy); - linphone_core_iterate(mCore); - } mReady=false; } } @@ -299,6 +195,8 @@ void TunnelManager::waitUnRegistration(){ if (lProxy && linphone_proxy_config_get_state(lProxy)==LinphoneRegistrationOk) { int i=0; linphone_proxy_config_edit(lProxy); + linphone_proxy_config_enable_register(lProxy,FALSE); + linphone_proxy_config_done(lProxy); //make sure unregister is sent and authenticated do{ linphone_core_iterate(mCore); @@ -348,6 +246,8 @@ void TunnelManager::enable(bool isEnable) { LinphoneProxyConfig* lProxy; linphone_core_get_default_proxy(mCore, &lProxy); if (lProxy) { + linphone_proxy_config_edit(lProxy); + linphone_proxy_config_enable_register(lProxy,TRUE); linphone_proxy_config_done(lProxy); } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index d7b99aeb2..ea021639a 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1081,8 +1081,10 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf lc->sip_conf.deleted_proxies=ms_list_append(lc->sip_conf.deleted_proxies,cfg); cfg->deletion_date=ms_time(NULL); if (cfg->state==LinphoneRegistrationOk){ - /* this will unREGISTER */ + /* unREGISTER */ linphone_proxy_config_edit(cfg); + linphone_proxy_config_enable_register(cfg,FALSE); + linphone_proxy_config_done(cfg); } if (lc->default_proxy==cfg){ lc->default_proxy=NULL; From d8e6070066f810151755ae088374abe4a3ff8a20 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 27 May 2014 10:34:03 +0200 Subject: [PATCH 027/201] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 4d6563b75..6ce0bcea9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4d6563b753e16e60fd5ece9bfa79c3be516ceaab +Subproject commit 6ce0bcea96b6e91c856e9a9dbab5b7bf8720ba9f From dbbea2a41c2926494be46ee2f85acdaa9fb36550 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 28 May 2014 11:34:59 +0200 Subject: [PATCH 028/201] add debug message to indicate duration of sqlite request --- coreapi/message_storage.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 3676b5685..ee9b0efb0 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -242,6 +242,7 @@ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ MSList *ret; char *buf; char *peer; + uint64_t begin,end; if (lc->db==NULL) return NULL; peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); @@ -250,7 +251,10 @@ MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC LIMIT %i ;",peer,nb_message); else buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC;",peer); + begin=ortp_get_cur_time_ms(); linphone_sql_request_message(lc->db,buf,cr); + end=ortp_get_cur_time_ms(); + ms_message("linphone_chat_room_get_history(): completed in %i ms",(int)(end-begin)); sqlite3_free(buf); ret=cr->messages_hist; cr->messages_hist=NULL; @@ -327,13 +331,15 @@ static int migrate_messages(void* data,int argc, char** argv, char** column_name static void linphone_migrate_timestamps(sqlite3* db){ int ret; char* errmsg = NULL; + uint64_t begin=ortp_get_cur_time_ms(); ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1'", migrate_messages, db, &errmsg); if( ret != SQLITE_OK ){ ms_warning("Error migrating outgoing messages: %s.\n", errmsg); sqlite3_free(errmsg); } else { - ms_message("Migrated message timestamps to UTC"); + uint64_t end=ortp_get_cur_time_ms(); + ms_message("Migrated message timestamps to UTC in %i ms",(int)(end-begin)); } } From 1a89e8a1746d2bae7524756029937ff42dac2229 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 28 May 2014 14:26:14 +0200 Subject: [PATCH 029/201] Use a transaction for message migration. On 10000 messages, we have a 20x speedup. --- coreapi/message_storage.c | 896 +++++++++++++++++++------------------- 1 file changed, 450 insertions(+), 446 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index ee9b0efb0..8a04d1ad2 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -1,446 +1,450 @@ -/* -message_storage.c -Copyright (C) 2012 Belledonne Communications, Grenoble, France - -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 "private.h" -#include "linphonecore.h" - -#ifdef WIN32 - -static inline char *my_ctime_r(const time_t *t, char *buf){ - strcpy(buf,ctime(t)); - return buf; -} - -#else -#define my_ctime_r ctime_r -#endif - -#ifdef MSG_STORAGE_ENABLED - -#include "sqlite3.h" - -static inline LinphoneChatMessage* get_transient_message(LinphoneChatRoom* cr, unsigned int storage_id){ - MSList* transients = cr->transient_messages; - LinphoneChatMessage* chat; - while( transients ){ - chat = (LinphoneChatMessage*)transients->data; - if(chat->storage_id == storage_id){ - return linphone_chat_message_ref(chat); - } - transients = transients->next; - } - return NULL; -} - -static void create_chat_message(char **argv, void *data){ - LinphoneChatRoom *cr = (LinphoneChatRoom *)data; - LinphoneAddress *from; - - unsigned int storage_id = atoi(argv[0]); - - // check if the message exists in the transient list, in which case we should return that one. - LinphoneChatMessage* new_message = get_transient_message(cr, storage_id); - if( new_message == NULL ){ - new_message = linphone_chat_room_create_message(cr, argv[4]); - - if(atoi(argv[3])==LinphoneChatMessageIncoming){ - new_message->dir=LinphoneChatMessageIncoming; - from=linphone_address_new(argv[2]); - } else { - new_message->dir=LinphoneChatMessageOutgoing; - from=linphone_address_new(argv[1]); - } - linphone_chat_message_set_from(new_message,from); - linphone_address_destroy(from); - - if( argv[9] != NULL ){ - new_message->time = (time_t)atol(argv[9]); - } else { - new_message->time = time(NULL); - } - - new_message->is_read=atoi(argv[6]); - new_message->state=atoi(argv[7]); - new_message->storage_id=storage_id; - new_message->external_body_url=argv[8]?ms_strdup(argv[8]):NULL; - } - cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); -} - -// Called when fetching all conversations from database -static int callback_all(void *data, int argc, char **argv, char **colName){ - LinphoneCore* lc = (LinphoneCore*) data; - char* address = argv[0]; - linphone_core_get_or_create_chat_room(lc, address); - return 0; -} - -static int callback(void *data, int argc, char **argv, char **colName){ - create_chat_message(argv,data); - return 0; -} - -void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,stmt,callback,cr,&errmsg); - if(ret != SQLITE_OK) { - ms_error("Error in creation: %s.\n", errmsg); - sqlite3_free(errmsg); - } -} - -void linphone_sql_request(sqlite3* db,const char *stmt){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg); - sqlite3_free(errmsg); - } -} - -// Process the request to fetch all chat contacts -void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg); - if(ret != SQLITE_OK) { - ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.\n", errmsg); - sqlite3_free(errmsg); - } -} - -unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ - LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); - int id=0; - - if (lc->db){ - char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); - char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); - char *buf=sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%i);", - local_contact, - peer, - msg->dir, - msg->message, - "-1", /* use UTC field now */ - msg->is_read, - msg->state, - msg->external_body_url, - msg->time); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - ms_free(local_contact); - ms_free(peer); - id = (unsigned int) sqlite3_last_insert_rowid (lc->db); - } - return id; -} - -void linphone_chat_message_store_state(LinphoneChatMessage *msg){ - LinphoneCore *lc=msg->chat_room->lc; - if (lc->db){ - char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (message = %Q OR url = %Q) AND utc = %i;", - msg->state,msg->message,msg->external_body_url,msg->time); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - } - - if( msg->state == LinphoneChatMessageStateDelivered - || msg->state == LinphoneChatMessageStateNotDelivered ){ - // message is not transient anymore, we can remove it from our transient list: - msg->chat_room->transient_messages = ms_list_remove(msg->chat_room->transient_messages, msg); - linphone_chat_message_unref(msg); - } -} - -void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - int read=1; - - if (lc->db==NULL) return ; - - char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); - char *buf=sqlite3_mprintf("UPDATE history SET read=%i WHERE remoteContact = %Q;", - read,peer); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - ms_free(peer); -} - -void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - - if (lc->db==NULL) return ; - - char *buf=sqlite3_mprintf("UPDATE history SET url=%Q WHERE id=%i;",msg->external_body_url,msg->storage_id); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); -} - -int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - int numrows=0; - - if (lc->db==NULL) return 0; - - char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); - char *buf=sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q AND read = 0;",peer); - sqlite3_stmt *selectStatement; - int returnValue = sqlite3_prepare_v2(lc->db,buf,-1,&selectStatement,NULL); - if (returnValue == SQLITE_OK){ - if(sqlite3_step(selectStatement) == SQLITE_ROW){ - numrows= sqlite3_column_int(selectStatement, 0); - } - } - sqlite3_finalize(selectStatement); - sqlite3_free(buf); - ms_free(peer); - return numrows; -} - -void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { - LinphoneCore *lc=cr->lc; - - if (lc->db==NULL) return ; - - char *buf=sqlite3_mprintf("DELETE FROM history WHERE id = %i;", msg->storage_id); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); -} - -void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ - LinphoneCore *lc=cr->lc; - - if (lc->db==NULL) return ; - - char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); - char *buf=sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;",peer); - linphone_sql_request(lc->db,buf); - sqlite3_free(buf); - ms_free(peer); -} - -MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ - LinphoneCore *lc=linphone_chat_room_get_lc(cr); - MSList *ret; - char *buf; - char *peer; - uint64_t begin,end; - - if (lc->db==NULL) return NULL; - peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); - cr->messages_hist = NULL; - if (nb_message > 0) - buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC LIMIT %i ;",peer,nb_message); - else - buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC;",peer); - begin=ortp_get_cur_time_ms(); - linphone_sql_request_message(lc->db,buf,cr); - end=ortp_get_cur_time_ms(); - ms_message("linphone_chat_room_get_history(): completed in %i ms",(int)(end-begin)); - sqlite3_free(buf); - ret=cr->messages_hist; - cr->messages_hist=NULL; - ms_free(peer); - return ret; -} - -void linphone_close_storage(sqlite3* db){ - sqlite3_close(db); -} - -void linphone_create_table(sqlite3* db){ - char* errmsg=NULL; - int ret; - ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history (" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "localContact TEXT NOT NULL," - "remoteContact TEXT NOT NULL," - "direction INTEGER," - "message TEXT," - "time TEXT NOT NULL," - "read INTEGER," - "status INTEGER" - ");", - 0,0,&errmsg); - if(ret != SQLITE_OK) { - ms_error("Error in creation: %s.\n", errmsg); - sqlite3_free(errmsg); - } -} - - -static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; -static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; -static time_t parse_time_from_db( const char* time ){ - /* messages used to be stored in the DB by using string-based time */ - struct tm ret={0}; - char tmp1[80]={0}; - char tmp2[80]={0}; - int i,j; - time_t parsed = 0; - - if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday, - &ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){ - ret.tm_year-=1900; - for(i=0;i<7;i++) { - if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; - } - for(j=0;j<12;j++) { - if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; - } - ret.tm_isdst=-1; - parsed = mktime(&ret); - } - return parsed; -} - - -static int migrate_messages(void* data,int argc, char** argv, char** column_names) { - time_t new_time = parse_time_from_db(argv[1]); - if( new_time ){ - /* replace 'time' by -1 and set 'utc' to the timestamp */ - char *buf = sqlite3_mprintf("UPDATE history SET utc=%i,time='-1' WHERE id=%i", new_time, atoi(argv[0])); - if( buf) { - linphone_sql_request((sqlite3*)data, buf); - sqlite3_free(buf); - } - } else { - ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]); - } - return 0; -} - -static void linphone_migrate_timestamps(sqlite3* db){ - int ret; - char* errmsg = NULL; - uint64_t begin=ortp_get_cur_time_ms(); - - ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1'", migrate_messages, db, &errmsg); - if( ret != SQLITE_OK ){ - ms_warning("Error migrating outgoing messages: %s.\n", errmsg); - sqlite3_free(errmsg); - } else { - uint64_t end=ortp_get_cur_time_ms(); - ms_message("Migrated message timestamps to UTC in %i ms",(int)(end-begin)); - } -} - -void linphone_update_table(sqlite3* db) { - char* errmsg=NULL; - int ret; - - // for image url storage - ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); - if(ret != SQLITE_OK) { - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table updated successfully for URL."); - } - - // for UTC timestamp storage - ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg); - if( ret != SQLITE_OK ){ - ms_message("Table already up to date: %s.", errmsg); - sqlite3_free(errmsg); - } else { - ms_debug("Table updated successfully for UTC."); - // migrate from old text-based timestamps to unix time-based timestamps - linphone_migrate_timestamps(db); - } -} - -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { - char *buf; - - if (lc->db==NULL) return; - buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;"); - linphone_sql_request_all(lc->db,buf,lc); - sqlite3_free(buf); -} - -void linphone_core_message_storage_init(LinphoneCore *lc){ - int ret; - const char *errmsg; - sqlite3 *db; - - linphone_core_message_storage_close(lc); - - ret=sqlite3_open(lc->chat_db_file,&db); - if(ret != SQLITE_OK) { - errmsg=sqlite3_errmsg(db); - ms_error("Error in the opening: %s.\n", errmsg); - sqlite3_close(db); - } - linphone_create_table(db); - linphone_update_table(db); - lc->db=db; - - // Create a chatroom for each contact in the chat history - linphone_message_storage_init_chat_rooms(lc); -} - -void linphone_core_message_storage_close(LinphoneCore *lc){ - if (lc->db){ - sqlite3_close(lc->db); - lc->db=NULL; - } -} - -#else - -unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ - return 0; -} - -void linphone_chat_message_store_state(LinphoneChatMessage *cr){ -} - -void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ -} - -MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ - return NULL; -} - -void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { -} - -void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ -} - -void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { -} - -void linphone_core_message_storage_init(LinphoneCore *lc){ -} - -void linphone_core_message_storage_close(LinphoneCore *lc){ -} - -void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { -} - -int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ - return 0; -} - -#endif +/* +message_storage.c +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +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 "private.h" +#include "linphonecore.h" + +#ifdef WIN32 + +static inline char *my_ctime_r(const time_t *t, char *buf){ + strcpy(buf,ctime(t)); + return buf; +} + +#else +#define my_ctime_r ctime_r +#endif + +#ifdef MSG_STORAGE_ENABLED + +#include "sqlite3.h" + +static inline LinphoneChatMessage* get_transient_message(LinphoneChatRoom* cr, unsigned int storage_id){ + MSList* transients = cr->transient_messages; + LinphoneChatMessage* chat; + while( transients ){ + chat = (LinphoneChatMessage*)transients->data; + if(chat->storage_id == storage_id){ + return linphone_chat_message_ref(chat); + } + transients = transients->next; + } + return NULL; +} + +static void create_chat_message(char **argv, void *data){ + LinphoneChatRoom *cr = (LinphoneChatRoom *)data; + LinphoneAddress *from; + + unsigned int storage_id = atoi(argv[0]); + + // check if the message exists in the transient list, in which case we should return that one. + LinphoneChatMessage* new_message = get_transient_message(cr, storage_id); + if( new_message == NULL ){ + new_message = linphone_chat_room_create_message(cr, argv[4]); + + if(atoi(argv[3])==LinphoneChatMessageIncoming){ + new_message->dir=LinphoneChatMessageIncoming; + from=linphone_address_new(argv[2]); + } else { + new_message->dir=LinphoneChatMessageOutgoing; + from=linphone_address_new(argv[1]); + } + linphone_chat_message_set_from(new_message,from); + linphone_address_destroy(from); + + if( argv[9] != NULL ){ + new_message->time = (time_t)atol(argv[9]); + } else { + new_message->time = time(NULL); + } + + new_message->is_read=atoi(argv[6]); + new_message->state=atoi(argv[7]); + new_message->storage_id=storage_id; + new_message->external_body_url=argv[8]?ms_strdup(argv[8]):NULL; + } + cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); +} + +// Called when fetching all conversations from database +static int callback_all(void *data, int argc, char **argv, char **colName){ + LinphoneCore* lc = (LinphoneCore*) data; + char* address = argv[0]; + linphone_core_get_or_create_chat_room(lc, address); + return 0; +} + +static int callback(void *data, int argc, char **argv, char **colName){ + create_chat_message(argv,data); + return 0; +} + +void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom *cr){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,callback,cr,&errmsg); + if(ret != SQLITE_OK) { + ms_error("Error in creation: %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + +void linphone_sql_request(sqlite3* db,const char *stmt){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + +// Process the request to fetch all chat contacts +void linphone_sql_request_all(sqlite3* db,const char *stmt, LinphoneCore* lc){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,stmt,callback_all,lc,&errmsg); + if(ret != SQLITE_OK) { + ms_error("linphone_sql_request_all: error sqlite3_exec(): %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + +unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ + LinphoneCore *lc=linphone_chat_room_get_lc(msg->chat_room); + int id=0; + + if (lc->db){ + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); + char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); + char *buf=sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%i);", + local_contact, + peer, + msg->dir, + msg->message, + "-1", /* use UTC field now */ + msg->is_read, + msg->state, + msg->external_body_url, + msg->time); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + ms_free(local_contact); + ms_free(peer); + id = (unsigned int) sqlite3_last_insert_rowid (lc->db); + } + return id; +} + +void linphone_chat_message_store_state(LinphoneChatMessage *msg){ + LinphoneCore *lc=msg->chat_room->lc; + if (lc->db){ + char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (message = %Q OR url = %Q) AND utc = %i;", + msg->state,msg->message,msg->external_body_url,msg->time); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + } + + if( msg->state == LinphoneChatMessageStateDelivered + || msg->state == LinphoneChatMessageStateNotDelivered ){ + // message is not transient anymore, we can remove it from our transient list: + msg->chat_room->transient_messages = ms_list_remove(msg->chat_room->transient_messages, msg); + linphone_chat_message_unref(msg); + } +} + +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + int read=1; + + if (lc->db==NULL) return ; + + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + char *buf=sqlite3_mprintf("UPDATE history SET read=%i WHERE remoteContact = %Q;", + read,peer); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + ms_free(peer); +} + +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + + if (lc->db==NULL) return ; + + char *buf=sqlite3_mprintf("UPDATE history SET url=%Q WHERE id=%i;",msg->external_body_url,msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); +} + +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + int numrows=0; + + if (lc->db==NULL) return 0; + + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + char *buf=sqlite3_mprintf("SELECT count(*) FROM history WHERE remoteContact = %Q AND read = 0;",peer); + sqlite3_stmt *selectStatement; + int returnValue = sqlite3_prepare_v2(lc->db,buf,-1,&selectStatement,NULL); + if (returnValue == SQLITE_OK){ + if(sqlite3_step(selectStatement) == SQLITE_ROW){ + numrows= sqlite3_column_int(selectStatement, 0); + } + } + sqlite3_finalize(selectStatement); + sqlite3_free(buf); + ms_free(peer); + return numrows; +} + +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + LinphoneCore *lc=cr->lc; + + if (lc->db==NULL) return ; + + char *buf=sqlite3_mprintf("DELETE FROM history WHERE id = %i;", msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); +} + +void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ + LinphoneCore *lc=cr->lc; + + if (lc->db==NULL) return ; + + char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + char *buf=sqlite3_mprintf("DELETE FROM history WHERE remoteContact = %Q;",peer); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + ms_free(peer); +} + +MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ + LinphoneCore *lc=linphone_chat_room_get_lc(cr); + MSList *ret; + char *buf; + char *peer; + uint64_t begin,end; + + if (lc->db==NULL) return NULL; + peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(cr)); + cr->messages_hist = NULL; + if (nb_message > 0) + buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC LIMIT %i ;",peer,nb_message); + else + buf=sqlite3_mprintf("SELECT * FROM history WHERE remoteContact = %Q ORDER BY id DESC;",peer); + begin=ortp_get_cur_time_ms(); + linphone_sql_request_message(lc->db,buf,cr); + end=ortp_get_cur_time_ms(); + ms_message("linphone_chat_room_get_history(): completed in %i ms",(int)(end-begin)); + sqlite3_free(buf); + ret=cr->messages_hist; + cr->messages_hist=NULL; + ms_free(peer); + return ret; +} + +void linphone_close_storage(sqlite3* db){ + sqlite3_close(db); +} + +void linphone_create_table(sqlite3* db){ + char* errmsg=NULL; + int ret; + ret=sqlite3_exec(db,"CREATE TABLE IF NOT EXISTS history (" + "id INTEGER PRIMARY KEY AUTOINCREMENT," + "localContact TEXT NOT NULL," + "remoteContact TEXT NOT NULL," + "direction INTEGER," + "message TEXT," + "time TEXT NOT NULL," + "read INTEGER," + "status INTEGER" + ");", + 0,0,&errmsg); + if(ret != SQLITE_OK) { + ms_error("Error in creation: %s.\n", errmsg); + sqlite3_free(errmsg); + } +} + + +static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; +static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; +static time_t parse_time_from_db( const char* time ){ + /* messages used to be stored in the DB by using string-based time */ + struct tm ret={0}; + char tmp1[80]={0}; + char tmp2[80]={0}; + int i,j; + time_t parsed = 0; + + if( sscanf(time,"%3c %3c%d%d:%d:%d %d",tmp1,tmp2,&ret.tm_mday, + &ret.tm_hour,&ret.tm_min,&ret.tm_sec,&ret.tm_year) == 7 ){ + ret.tm_year-=1900; + for(i=0;i<7;i++) { + if(strcmp(tmp1,days[i])==0) ret.tm_wday=i; + } + for(j=0;j<12;j++) { + if(strcmp(tmp2,months[j])==0) ret.tm_mon=j; + } + ret.tm_isdst=-1; + parsed = mktime(&ret); + } + return parsed; +} + + +static int migrate_messages(void* data,int argc, char** argv, char** column_names) { + time_t new_time = parse_time_from_db(argv[1]); + if( new_time ){ + /* replace 'time' by -1 and set 'utc' to the timestamp */ + char *buf = sqlite3_mprintf("UPDATE history SET utc=%i,time='-1' WHERE id=%i", new_time, atoi(argv[0])); + if( buf) { + linphone_sql_request((sqlite3*)data, buf); + sqlite3_free(buf); + } + } else { + ms_warning("Cannot parse time %s from id %s", argv[1], argv[0]); + } + return 0; +} + +static void linphone_migrate_timestamps(sqlite3* db){ + int ret; + char* errmsg = NULL; + uint64_t begin=ortp_get_cur_time_ms(); + + linphone_sql_request(db,"BEGIN TRANSACTION"); + + ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1'", migrate_messages, db, &errmsg); + if( ret != SQLITE_OK ){ + ms_warning("Error migrating outgoing messages: %s.\n", errmsg); + sqlite3_free(errmsg); + linphone_sql_request(db, "ROLLBACK"); + } else { + linphone_sql_request(db, "COMMIT"); + uint64_t end=ortp_get_cur_time_ms(); + ms_message("Migrated message timestamps to UTC in %i ms",(int)(end-begin)); + } +} + +void linphone_update_table(sqlite3* db) { + char* errmsg=NULL; + int ret; + + // for image url storage + ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN url TEXT;",NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_message("Table already up to date: %s.", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table updated successfully for URL."); + } + + // for UTC timestamp storage + ret = sqlite3_exec(db, "ALTER TABLE history ADD COLUMN utc INTEGER;", NULL,NULL,&errmsg); + if( ret != SQLITE_OK ){ + ms_message("Table already up to date: %s.", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table updated successfully for UTC."); + // migrate from old text-based timestamps to unix time-based timestamps + linphone_migrate_timestamps(db); + } +} + +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { + char *buf; + + if (lc->db==NULL) return; + buf=sqlite3_mprintf("SELECT remoteContact FROM history GROUP BY remoteContact;"); + linphone_sql_request_all(lc->db,buf,lc); + sqlite3_free(buf); +} + +void linphone_core_message_storage_init(LinphoneCore *lc){ + int ret; + const char *errmsg; + sqlite3 *db; + + linphone_core_message_storage_close(lc); + + ret=sqlite3_open(lc->chat_db_file,&db); + if(ret != SQLITE_OK) { + errmsg=sqlite3_errmsg(db); + ms_error("Error in the opening: %s.\n", errmsg); + sqlite3_close(db); + } + linphone_create_table(db); + linphone_update_table(db); + lc->db=db; + + // Create a chatroom for each contact in the chat history + linphone_message_storage_init_chat_rooms(lc); +} + +void linphone_core_message_storage_close(LinphoneCore *lc){ + if (lc->db){ + sqlite3_close(lc->db); + lc->db=NULL; + } +} + +#else + +unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ + return 0; +} + +void linphone_chat_message_store_state(LinphoneChatMessage *cr){ +} + +void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ +} + +MSList *linphone_chat_room_get_history(LinphoneChatRoom *cr,int nb_message){ + return NULL; +} + +void linphone_chat_room_delete_message(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + +void linphone_chat_room_delete_history(LinphoneChatRoom *cr){ +} + +void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { +} + +void linphone_core_message_storage_init(LinphoneCore *lc){ +} + +void linphone_core_message_storage_close(LinphoneCore *lc){ +} + +void linphone_chat_room_update_url(LinphoneChatRoom *cr, LinphoneChatMessage *msg) { +} + +int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr){ + return 0; +} + +#endif From b56095f59ffc345f087a935ae5d24cbefca1b014 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 28 May 2014 14:53:30 +0200 Subject: [PATCH 030/201] Add API to debug sqlite timings, and a test to profile the message migration --- coreapi/message_storage.c | 39 ++++++++---- coreapi/private.h | 2 + tester/Makefile.am | 2 +- tester/message_tester.c | 121 +++++++++++++++++++++++++++++++++----- tester/messages.db | Bin 0 -> 1821696 bytes 5 files changed, 135 insertions(+), 29 deletions(-) create mode 100644 tester/messages.db diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 8a04d1ad2..86887c7b7 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -20,17 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include "linphonecore.h" -#ifdef WIN32 - -static inline char *my_ctime_r(const time_t *t, char *buf){ - strcpy(buf,ctime(t)); - return buf; -} - -#else -#define my_ctime_r ctime_r -#endif - #ifdef MSG_STORAGE_ENABLED #include "sqlite3.h" @@ -157,8 +146,8 @@ void linphone_chat_message_store_state(LinphoneChatMessage *msg){ LinphoneCore *lc=msg->chat_room->lc; if (lc->db){ char *buf=sqlite3_mprintf("UPDATE history SET status=%i WHERE (message = %Q OR url = %Q) AND utc = %i;", - msg->state,msg->message,msg->external_body_url,msg->time); - linphone_sql_request(lc->db,buf); + msg->state,msg->message,msg->external_body_url,msg->time); + linphone_sql_request(lc->db,buf); sqlite3_free(buf); } @@ -381,6 +370,27 @@ void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { sqlite3_free(buf); } +static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){ + ms_warning("SQL statement '%s' took %" PRId64 " microseconds", statement, duration / 1000 ); +} + +static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){ + if( debug ){ + sqlite3_profile(db, _linphone_message_storage_profile, NULL ); + } else { + sqlite3_profile(db, NULL, NULL ); + } +} + +void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug){ + + lc->debug_storage = debug; + + if( lc->db ){ + linphone_message_storage_activate_debug(lc->db, debug); + } +} + void linphone_core_message_storage_init(LinphoneCore *lc){ int ret; const char *errmsg; @@ -394,6 +404,9 @@ void linphone_core_message_storage_init(LinphoneCore *lc){ ms_error("Error in the opening: %s.\n", errmsg); sqlite3_close(db); } + + linphone_message_storage_activate_debug(db, lc->debug_storage); + linphone_create_table(db); linphone_update_table(db); lc->db=db; diff --git a/coreapi/private.h b/coreapi/private.h index d43f6454f..a2fb3d9c2 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -701,6 +701,7 @@ struct _LinphoneCore char *chat_db_file; #ifdef MSG_STORAGE_ENABLED sqlite3 *db; + bool_t debug_storage; #endif #ifdef BUILD_UPNP UpnpContext *upnp; @@ -815,6 +816,7 @@ void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); void linphone_chat_message_store_state(LinphoneChatMessage *msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); +void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug); void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID id); bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc); diff --git a/tester/Makefile.am b/tester/Makefile.am index 1cda152c7..46ffb12cd 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -26,7 +26,7 @@ liblinphonetester_la_LDFLAGS= -no-undefined liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS) AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/coreapi -AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) +AM_CFLAGS = $(STRICT_OPTIONS) -DIN_LINPHONE $(ORTP_CFLAGS) $(MEDIASTREAMER_CFLAGS) $(CUNIT_CFLAGS) $(BELLESIP_CFLAGS) $(LIBXML2_CFLAGS) $(SQLITE3_CFLAGS) if !BUILD_IOS diff --git a/tester/message_tester.c b/tester/message_tester.c index 6aa884616..b5b8934e4 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -1,19 +1,19 @@ /* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 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 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. + 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, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -23,6 +23,11 @@ #include "private.h" #include "liblinphone_tester.h" +#ifdef MSG_STORAGE_ENABLED +#include +#endif + + static char* message_external_body_url; void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { @@ -97,7 +102,7 @@ static void text_message(void) { static void text_message_within_dialog(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - + lp_config_set_int(pauline->lc->config,"sip","chat_use_call_dialogs",1); char* to = linphone_address_as_string(marie->identity); @@ -105,7 +110,7 @@ static void text_message_within_dialog(void) { ms_free(to); CU_ASSERT_TRUE(call(marie,pauline)); - + linphone_chat_room_send_message(chat_room,"Bla bla bla bla"); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); @@ -287,7 +292,7 @@ static void text_message_denied(void) { /*pauline doesn't want to be disturbed*/ linphone_core_disable_chat(pauline->lc,LinphoneReasonDoNotDisturb); - + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,marie->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageNotDelivered,1)); @@ -385,6 +390,89 @@ static void is_composing_notification(void) { linphone_core_manager_destroy(pauline); } +#ifdef MSG_STORAGE_ENABLED + +/* + * Copy file "from" to file "to". + * Destination file is truncated if existing. + * Return 1 on success, 0 on error (printing an error). + */ +static int +message_tester_copy_file(const char *from, const char *to) +{ + char message[256]; + FILE *in, *out; + char buf[256]; + size_t n; + + /* Open "from" file for reading */ + in=fopen(from, "r"); + if ( in == NULL ) + { + snprintf(message, 255, "Can't open %s for reading: %s\n", + from, strerror(errno)); + fprintf(stderr, "%s", message); + return 0; + } + + /* Open "to" file for writing (will truncate existing files) */ + out=fopen(to, "w"); + if ( out == NULL ) + { + snprintf(message, 255, "Can't open %s for writing: %s\n", + to, strerror(errno)); + fprintf(stderr, "%s", message); + fclose(in); + return 0; + } + + /* Copy data from "in" to "out" */ + while ( (n=fread(buf, 1, sizeof buf, in)) > 0 ) + { + if ( ! fwrite(buf, 1, n, out) ) + { + fclose(in); + fclose(out); + return 0; + } + } + + fclose(in); + fclose(out); + + return 1; +} + +static int check_no_strange_time(void* data,int argc, char** argv,char** cNames) { + CU_ASSERT_EQUAL(argc, 0); + return 0; +} + +static void message_storage_migration() { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + char src_db[256]; + char tmp_db[256]; + snprintf(src_db,sizeof(src_db), "%s/messages.db", liblinphone_tester_file_prefix); + snprintf(tmp_db,sizeof(tmp_db), "%s/tmp.db", liblinphone_tester_file_prefix); + + CU_ASSERT_EQUAL_FATAL(message_tester_copy_file(src_db, tmp_db), 1); + + // enable to test the performances of the migration step + //linphone_core_message_storage_set_debug(marie->lc, TRUE); + + // the messages.db has 10000 dummy messages with the very first DB scheme. + // This will test the migration procedure + linphone_core_set_chat_database_path(marie->lc, "tmp.db"); + + MSList* chatrooms = linphone_core_get_chat_rooms(marie->lc); + CU_ASSERT(ms_list_size(chatrooms) > 0); + + // check that all messages have been migrated to the UTC time storage + CU_ASSERT(sqlite3_exec(marie->lc->db, "SELECT * FROM history WHERE time != '-1';", check_no_strange_time, NULL, NULL) == SQLITE_OK ); +} + +#endif + test_t message_tests[] = { { "Text message", text_message }, { "Text message within call's dialog", text_message_within_dialog}, @@ -398,6 +486,9 @@ test_t message_tests[] = { { "Info message", info_message }, { "Info message with body", info_message_with_body }, { "IsComposing notification", is_composing_notification } +#ifdef MSG_STORAGE_ENABLED + ,{ "Database migration", message_storage_migration } +#endif }; test_suite_t message_test_suite = { diff --git a/tester/messages.db b/tester/messages.db new file mode 100644 index 0000000000000000000000000000000000000000..072aed397b2422206d0e6d819e2860e4aade95af GIT binary patch literal 1821696 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

phC$omyu@ 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 )RqK2x+&84!uxdp$d7yC*T> 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

#dVUP#}2+T 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

0T|$9-GD=%ih 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ʕoSv}LxJe5Rm7~}K>^RXj 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

;IwtAM5|6{@)uHG%jjf-ngQ1P2;-8 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 literal 0 HcmV?d00001 From 3b23045e0a01a0849a8f5bc06372ba4f9b010ae1 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 28 May 2014 15:42:12 +0200 Subject: [PATCH 031/201] Fix tmp path in message tester --- tester/message_tester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/message_tester.c b/tester/message_tester.c index b5b8934e4..09872e565 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -462,7 +462,7 @@ static void message_storage_migration() { // the messages.db has 10000 dummy messages with the very first DB scheme. // This will test the migration procedure - linphone_core_set_chat_database_path(marie->lc, "tmp.db"); + linphone_core_set_chat_database_path(marie->lc, tmp_db); MSList* chatrooms = linphone_core_get_chat_rooms(marie->lc); CU_ASSERT(ms_list_size(chatrooms) > 0); From 1293b195bd60bf23619ce86e97807c1c70f84c3e Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 28 May 2014 17:06:58 +0200 Subject: [PATCH 032/201] Add API to change the file prefix programatically in linphone tester --- tester/liblinphone_tester.h | 17 +++++++++-------- tester/tester.c | 13 +++++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 5e5767bab..152dd6dd3 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -1,11 +1,11 @@ /* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 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 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 @@ -67,6 +67,7 @@ extern int liblinphone_tester_test_index(const char *suite_name, const char *tes extern void liblinphone_tester_init(void); extern void liblinphone_tester_uninit(void); extern int liblinphone_tester_run_tests(const char *suite_name, const char *test_name); +extern void liblinphone_tester_set_fileprefix(const char* file_prefix); #ifdef __cplusplus }; @@ -177,7 +178,7 @@ typedef struct _stats { int number_of_LinphonePublishExpiring; int number_of_LinphonePublishError; int number_of_LinphonePublishCleared; - + int number_of_LinphoneConfiguringSkipped; int number_of_LinphoneConfiguringFailed; int number_of_LinphoneConfiguringSuccessful; @@ -230,7 +231,7 @@ const char *liblinphone_tester_get_notify_content(void); void liblinphone_tester_chat_message_state_change(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud); void liblinphone_tester_check_rtcp(LinphoneCoreManager* caller, LinphoneCoreManager* callee); void liblinphone_tester_clock_start(MSTimeSpec *start); -bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms); +bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms); #endif /* LIBLINPHONE_TESTER_H_ */ diff --git a/tester/tester.c b/tester/tester.c index 3623073e4..3e09be635 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -80,8 +80,8 @@ LinphoneAddress * create_linphone_address(const char * domain) { static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { stats* counters; ms_message("Auth info requested for user id [%s] at realm [%s]\n" - ,username - ,realm); + ,username + ,realm); counters = get_stats(lc); counters->number_of_auth_info_requested++; } @@ -147,7 +147,7 @@ bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) { bool_t wait_for_list(MSList* lcs,int* counter,int value,int timeout_ms) { MSList* iterator; MSTimeSpec start; - + liblinphone_tester_clock_start(&start); while ((counter==NULL || *counternext) { @@ -164,7 +164,7 @@ static void set_codec_enable(LinphoneCore* lc,const char* type,int rate,bool_t e MSList* codecs_it; PayloadType* pt; for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) { - linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); + linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0); } if((pt = linphone_core_find_payload_type(lc,type,rate,1))) { linphone_core_enable_payload_type(lc,pt, enable); @@ -322,6 +322,11 @@ const char * liblinphone_tester_test_name(const char *suite_name, int test_index return test_suite[suite_index]->tests[test_index].name; } +void liblinphone_tester_set_fileprefix(const char* file_prefix){ + liblinphone_tester_file_prefix = file_prefix; +} + + void liblinphone_tester_init(void) { add_test_suite(&setup_test_suite); add_test_suite(®ister_test_suite); From c10b5f652b4da61957f61729a7eb45bfa6ac459f Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 29 May 2014 00:10:49 +0200 Subject: [PATCH 033/201] File transfer implemented following RCS5.1 recommendation - memory leaks to be fixed --- coreapi/bellesip_sal/sal_op_message.c | 17 +- coreapi/chat.c | 326 +++++++++++++++++++++++++- coreapi/help/Makefile.am | 2 + coreapi/help/filetransfer.c | 69 ++++-- coreapi/linphonecore.c | 12 + coreapi/linphonecore.h | 3 + coreapi/private.h | 3 + include/sal/sal.h | 1 + mediastreamer2 | 2 +- oRTP | 2 +- 10 files changed, 405 insertions(+), 32 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_message.c b/coreapi/bellesip_sal/sal_op_message.c index 2f161c2a6..3324cefb7 100644 --- a/coreapi/bellesip_sal/sal_op_message.c +++ b/coreapi/bellesip_sal/sal_op_message.c @@ -55,6 +55,11 @@ static void process_response_event(void *op_base, const belle_sip_response_event op->base.root->callbacks.text_delivery_update(op,status); } +static bool_t is_rcs_filetransfer(belle_sip_header_content_type_t* content_type) { + return strcmp("application",belle_sip_header_content_type_get_type(content_type))==0 + && strcmp("vnd.gsma.rcs-ft-http+xml",belle_sip_header_content_type_get_subtype(content_type))==0; +} + static bool_t is_plain_text(belle_sip_header_content_type_t* content_type) { return strcmp("text",belle_sip_header_content_type_get_type(content_type))==0 && strcmp("plain",belle_sip_header_content_type_get_subtype(content_type))==0; @@ -69,7 +74,7 @@ static bool_t is_im_iscomposing(belle_sip_header_content_type_t* content_type) { } static void add_message_accept(belle_sip_message_t *msg){ - belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml")); + belle_sip_message_add_header(msg,belle_sip_header_create("Accept","text/plain, message/external-body, application/im-iscomposing+xml, application/vnd.gsma.rcs-ft-http+xml")); } void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *event){ @@ -85,11 +90,13 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve char* from; bool_t plain_text=FALSE; bool_t external_body=FALSE; + bool_t rcs_filetransfer=FALSE; from_header=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_from_t); content_type=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_content_type_t); if (content_type && ((plain_text=is_plain_text(content_type)) - || (external_body=is_external_body(content_type)))) { + || (external_body=is_external_body(content_type)) + || (rcs_filetransfer=is_rcs_filetransfer(content_type)))) { SalMessage salmsg; char message_id[256]={0}; @@ -104,8 +111,12 @@ void sal_process_incoming_message(SalOp *op,const belle_sip_request_event_t *eve ,belle_sip_header_call_id_get_call_id(call_id) ,belle_sip_header_cseq_get_seq_number(cseq)); salmsg.from=from; - salmsg.text=plain_text?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; + salmsg.text=(plain_text||rcs_filetransfer)?belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)):NULL; salmsg.url=NULL; + salmsg.content_type = NULL; + if (rcs_filetransfer) { /* if we have a rcs file transfer, set the type, message body (stored in salmsg.text) contains all needed information to retrieve the file */ + salmsg.content_type = "application/vnd.gsma.rcs-ft-http+xml"; + } if (external_body && belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")) { size_t url_length=strlen(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")); salmsg.url = ms_strdup(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type),"URL")+1); /* skip first "*/ diff --git a/coreapi/chat.c b/coreapi/chat.c index fb2a34159..02638a64c 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -25,6 +25,7 @@ #include "linphonecore.h" #include "private.h" #include "lpconfig.h" +#include "belle-sip/belle-sip.h" #include @@ -32,6 +33,135 @@ #define COMPOSING_DEFAULT_REFRESH_TIMEOUT 60 #define COMPOSING_DEFAULT_REMOTE_REFRESH_TIMEOUT 120 + +static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg); +#define MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449" +#define MULTIPART_HEADER_1 "--" MULTIPART_BOUNDARY "\r\n" \ + "Content-Disposition: form-data; name=\"File\"; filename=\"" +#define MULTIPART_HEADER_2 "\"\r\n" \ + "Content-Type: " +#define MULTIPART_HEADER_3 "\r\n\r\n" +#define MULTIPART_END "\r\n--" MULTIPART_BOUNDARY "--\r\n" +const char *multipart_boundary=MULTIPART_BOUNDARY; + +static size_t linphone_chat_message_compute_multipart_header_size(const char *filename, const char *content_type) { + return strlen(MULTIPART_HEADER_1)+strlen(filename)+strlen(MULTIPART_HEADER_2)+strlen(content_type)+strlen(MULTIPART_HEADER_3); +} +static void process_io_error(void *data, const belle_sip_io_error_event_t *event){ + printf("We have a response io error!\n"); +} +static void process_auth_requested(void *data, belle_sip_auth_event_t *event){ + printf("We have a auth requested!\n"); +} + +/** + * Callback called during upload or download of a file from server + * It is just forwarding the call and some parameters to the vtable defined callback + */ +static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total){ + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + /* call back given by application level */ + if (lc->vtable.file_transfer_progress_indication != NULL) { + lc->vtable.file_transfer_progress_indication(lc, chatMsg, chatMsg->file_transfer_information, (size_t)(((double)offset/(double)total)*100.0)); + } + return; +} + +/** + * Callback called when posting a file to server (following rcs5.1 recommendation) + * + * @param bh the body handler + * @param msg the belle sip message + * @param data the user data associated to the handler, contains the linphoneChatMessage we're working on + * @param offset current position in the input buffer + * @param buffer the ouput buffer we to copy the data to be uploaded + * @param size size in byte of the data requested, as output it will contain the effective copied size + * + */ +static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, void *buffer, size_t *size){ + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + + char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype); + size_t end_of_file=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size; + + if (offset==0){ + int partlen=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type); + memcpy(buffer,MULTIPART_HEADER_1,strlen(MULTIPART_HEADER_1)); + buffer += strlen(MULTIPART_HEADER_1); + memcpy(buffer,chatMsg->file_transfer_information->name,strlen(chatMsg->file_transfer_information->name)); + buffer += strlen(chatMsg->file_transfer_information->name); + memcpy(buffer,MULTIPART_HEADER_2,strlen(MULTIPART_HEADER_2)); + buffer += strlen(MULTIPART_HEADER_2); + memcpy(buffer,content_type,strlen(content_type)); + buffer += strlen(content_type); + memcpy(buffer,MULTIPART_HEADER_3,strlen(MULTIPART_HEADER_3)); + + *size=partlen; + }else if (offsetvtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + }else{ + *size=strlen(MULTIPART_END); + strncpy(buffer,MULTIPART_END,*size); + } + belle_sip_free(content_type); + return BELLE_SIP_CONTINUE; +} + +/** + * Callback function called when we have a response from server during a file upload to server (rcs5.1 recommandation) + * Note: The first post is empty and the server shall reply a 204 (No content) message, this will trigger a new post request to the server + * to upoad the file. The server response to this second post is processed by this same function + * + * @param data the user define pointer associated with the request, it contains the linphoneChatMessage we're trying to send + * @param event the response from server + */ +static void linphone_chat_message_process_response_from_post_file(void *data, const belle_http_response_event_t *event){ + LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + + /* check the answer code */ + if (event->response){ + int code=belle_http_response_get_status_code(event->response); + if (code == 204) { /* this is the reply to the first post to the server - an empty message */ + /* start uploading the file */ + belle_http_request_listener_callbacks_t cbs={0}; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + belle_http_request_t *req; + char *content_type=belle_sip_strdup_printf("%s/%s", msg->file_transfer_information->type, msg->file_transfer_information->subtype); + belle_sip_user_body_handler_t *bh=belle_sip_user_body_handler_new(msg->file_transfer_information->size+linphone_chat_message_compute_multipart_header_size(msg->file_transfer_information->name, content_type)+strlen(MULTIPART_END), linphone_chat_message_file_transfer_on_progress, NULL, linphone_chat_message_file_transfer_on_send_body, msg); + belle_sip_free(content_type); + content_type=belle_sip_strdup_printf("multipart/form-data; boundary=%s",multipart_boundary); + + uri=belle_generic_uri_parse(msg->chat_room->lc->file_transfer_server); + + req=belle_http_request_create("POST", + uri, + belle_sip_header_create("User-Agent","belle-sip/" PACKAGE_VERSION), + belle_sip_header_create("Content-type",content_type), + NULL); + belle_sip_free(content_type); + belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req),BELLE_SIP_BODY_HANDLER(bh)); + cbs.process_response=linphone_chat_message_process_response_from_post_file; + cbs.process_io_error=process_io_error; + cbs.process_auth_requested=process_auth_requested; + l=belle_http_request_listener_create_from_callbacks(&cbs,msg); + belle_http_provider_send_request(msg->chat_room->lc->http_provider,req,l); + } + if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */ + const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); + msg->message = ms_strdup(body); + msg->file_transfer_information = NULL; + msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); + _linphone_chat_room_send_message(msg->chat_room, msg); + } + } + +} + + static void _linphone_chat_message_destroy(LinphoneChatMessage* msg); BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneChatMessage); @@ -178,6 +308,30 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM const char *identity=NULL; time_t t=time(NULL); + /* Check if we shall upload a file to a server */ + if (msg->file_transfer_information != NULL) { + /* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ + belle_http_request_listener_callbacks_t cbs={0}; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + belle_http_request_t *req; + + uri=belle_generic_uri_parse(cr->lc->file_transfer_server); + + req=belle_http_request_create("POST", + uri, + NULL, + NULL, + NULL); + cbs.process_response=linphone_chat_message_process_response_from_post_file; + cbs.process_io_error=process_io_error; + cbs.process_auth_requested=process_auth_requested; + l=belle_http_request_listener_create_from_callbacks(&cbs,msg); /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */ + belle_http_provider_send_request(cr->lc->http_provider,req,l); + + return; + } + if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",0)){ if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){ if (call->state==LinphoneCallConnected || @@ -207,7 +361,11 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM sal_message_send(op,identity,cr->peer,content_type, NULL); ms_free(content_type); } else { - sal_text_send(op, identity, cr->peer,msg->message); + if (msg->content_type == NULL) { + sal_text_send(op, identity, cr->peer,msg->message); + } else { + sal_message_send(op, identity, cr->peer, msg->content_type, msg->message); + } } msg->dir=LinphoneChatMessageOutgoing; msg->from=linphone_address_new(identity); @@ -280,7 +438,65 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag /* create a new chat room */ cr=linphone_core_create_chat_room(lc,cleanfrom); } - msg = linphone_chat_room_create_message(cr, sal_msg->text); + if (sal_msg->content_type != NULL) { /* content_type field is, for now, used only for rcs file transfer bu twe shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */ + msg = linphone_chat_room_create_message(cr, NULL); /* create a message with empty body */ + msg->content_type = ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */ + msg->file_transfer_information = (LinphoneContent *)malloc(sizeof(LinphoneContent)); + memset(msg->file_transfer_information, 0, sizeof(*(msg->file_transfer_information))); + + xmlChar *file_url = NULL; + /* parse the message body to get all informations from it */ + xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text); + + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + if (cur != NULL) { + cur = cur->xmlChildrenNode; + while (cur!=NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-info")) { /* we found a file info node, check it has a type="file" attribute */ + xmlChar *typeAttribute = xmlGetProp(cur, (const xmlChar *)"type"); + if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ + cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ + while (cur!=NULL) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { + xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + msg->file_transfer_information->size = strtol((const char*)fileSizeString, NULL, 10); + xmlFree(fileSizeString); + } + + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { + msg->file_transfer_information->name = (char *)xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { + xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); + int contentTypeIndex = 0; + while (contentType[contentTypeIndex]!='/' && contentType[contentTypeIndex]!='\0') { + contentTypeIndex++; + } + msg->file_transfer_information->type = strndup((char *)contentType, contentTypeIndex); + msg->file_transfer_information->subtype = strdup(((char *)contentType+contentTypeIndex+1)); + xmlFree(contentType); + } + if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { + file_url = xmlGetProp(cur, (const xmlChar *)"url"); + } + + cur=cur->next; + } + xmlFree(typeAttribute); + break; + } + xmlFree(typeAttribute); + } + cur = cur->next; + } + } + xmlFreeDoc(xmlMessageBody); + + linphone_chat_message_set_external_body_url(msg, (const char *)file_url); + xmlFree(file_url); + } else { /* message is not rcs file transfer, create it with provided sal_msg->text as ->message */ + msg = linphone_chat_room_create_message(cr, sal_msg->text); + } linphone_chat_message_set_from(msg, cr->peer_url); { @@ -299,6 +515,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag if (sal_msg->url) { linphone_chat_message_set_external_body_url(msg, sal_msg->url); } + linphone_address_destroy(addr); msg->storage_id=linphone_chat_message_store(msg); linphone_chat_room_message_received(cr,lc,msg); @@ -426,6 +643,7 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con msg->chat_room=(LinphoneChatRoom*)cr; msg->message=message?ms_strdup(message):NULL; msg->is_read=TRUE; + msg->content_type = NULL; /* this property is used only when transfering file */ return msg; } @@ -452,6 +670,7 @@ LinphoneChatMessage* linphone_chat_room_create_message_2( msg->time=time; msg->state=state; msg->is_read=is_read; + msg->content_type = NULL; /* this property is used only when transfering file */ if (is_incoming) { msg->dir=LinphoneChatMessageIncoming; linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr)); @@ -668,6 +887,87 @@ void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,co message->external_body_url=url?ms_strdup(url):NULL; } +/** + * Get the file_transfer_information (used by call backs to recover informations during a rcs file transfer) + * + * @param message #LinphoneChatMessage + * @return a pointer to the LinphoneContent structure or NULL if not present. + */ +const LinphoneContent *linphone_chat_message_get_file_transfer_information(const LinphoneChatMessage*message) { + return message->file_transfer_information; +} + +static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const void *buffer, size_t size){ + //printf("Receive %ld bytes\n\n%s\n\n", size, (char *)buffer); + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + /* call back given by application level */ + if (lc->vtable.file_transfer_received != NULL) { + lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + } + return; + + /* feed the callback with the received data */ + + +} + +static void linphone_chat_process_response_headers_from_get_file(void *data, const belle_http_response_event_t *event){ + if (event->response){ + /*we are receiving a response, set a specific body handler to acquire the response. + * if not done, belle-sip will create a memory body handler, the default*/ + LinphoneChatMessage *message=belle_sip_object_data_get(BELLE_SIP_OBJECT(event->request),"message"); + belle_sip_message_set_body_handler( + (belle_sip_message_t*)event->response, + (belle_sip_body_handler_t*)belle_sip_user_body_handler_new(message->file_transfer_information->size, linphone_chat_message_file_transfer_on_progress,on_recv_body,NULL,message) + ); + } +} + +static void linphone_chat_process_response_from_get_file(void *data, const belle_http_response_event_t *event){ + //LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + + /* check the answer code */ + if (event->response){ + int code=belle_http_response_get_status_code(event->response); + if (code==200) { + LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; + LinphoneCore *lc = chatMsg->chat_room->lc; + /* file downloaded succesfully, call again the callback with size at zero */ + if (lc->vtable.file_transfer_received != NULL) { + lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, NULL, 0); + } + } + } +} + +/** + * Start the download of the file from remote server + * + * @param message #LinphoneChatMessage + */ +void linphone_chat_message_start_file_download(const LinphoneChatMessage *message) { + belle_http_request_listener_callbacks_t cbs={0}; + belle_http_request_listener_t *l; + belle_generic_uri_t *uri; + belle_http_request_t *req; + const char *url=message->external_body_url; + + uri=belle_generic_uri_parse(url); + + req=belle_http_request_create("GET", + uri, + belle_sip_header_create("User-Agent","belle-sip/" PACKAGE_VERSION), + NULL); + + cbs.process_response_headers=linphone_chat_process_response_headers_from_get_file; + cbs.process_response=linphone_chat_process_response_from_get_file; + cbs.process_io_error=process_io_error; + cbs.process_auth_requested=process_auth_requested; + l=belle_http_request_listener_create_from_callbacks(&cbs, (void *)message); + belle_sip_object_data_set(BELLE_SIP_OBJECT(req),"message",(void *)message,NULL); + belle_http_provider_send_request(message->chat_room->lc->http_provider,req,l); +} /** * Set origin of the message *@param message #LinphoneChatMessage obj @@ -834,6 +1134,7 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) { if (msg->from) linphone_address_destroy(msg->from); if (msg->to) linphone_address_destroy(msg->to); if (msg->custom_headers) sal_custom_header_free(msg->custom_headers); + if (msg->content_type) ms_free(msg->content_type); } @@ -868,6 +1169,27 @@ LinphoneReason linphone_chat_message_get_reason(LinphoneChatMessage* msg) { return linphone_error_info_get_reason(linphone_chat_message_get_error_info(msg)); } + + +/** + * Create a message attached to a dedicated chat room with a particular content. Use #linphone_chat_room_send_message2 to initiate the transfer + * @param cr the chat room. + * @param a #LinphoneContent initial content. #LinphoneCoreVTable.file_transfer_send is invoked later to notify file transfer progress and collect next chunk of the message if #LinphoneContent.data is NULL. + * @return a new #LinphoneChatMessage + */ + +LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneChatRoom *cr, LinphoneContent* initial_content) { + LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage); + msg->chat_room=(LinphoneChatRoom*)cr; + msg->message = NULL; + msg->file_transfer_information = initial_content; + msg->dir=LinphoneChatMessageOutgoing; + linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); + linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(cr->lc))); + msg->content_type=NULL; /* this will be set to application/vnd.gsma.rcs-ft-http+xml when we will transfer the xml reply from server to the peers */ + + return msg; +} /** * @} */ diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 454757094..84822e51c 100644 --- a/coreapi/help/Makefile.am +++ b/coreapi/help/Makefile.am @@ -79,6 +79,8 @@ notify_LDADD=$(helloworld_LDADD) filetransfer_SOURCES=filetransfer.c LINPHONE_TUTOS+=$(filetransfer_SOURCES) +filetransfer_LDADD=$(helloworld_LDADD) + AM_CFLAGS=\ -I$(top_srcdir)/coreapi \ $(STRICT_OPTIONS) \ diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c index 84e8c1f79..b45019c43 100644 --- a/coreapi/help/filetransfer.c +++ b/coreapi/help/filetransfer.c @@ -52,7 +52,7 @@ static void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMess const LinphoneAddress* from_address = linphone_chat_message_get_from(message); const LinphoneAddress* to_address = linphone_chat_message_get_to(message); char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); - printf(" File transfer [%i&] %s of type [%s/%s] %s [%s] \n", (int)(content->size/progress)*100 + printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)progress ,(linphone_chat_message_is_outgoing(message)?"sent":"received") , content->type , content->subtype @@ -73,31 +73,32 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag , from); if (!linphone_chat_message_get_user_data(message)) { /*first chunk, creating file*/ - file = open("receive_file.dump",O_WRONLY); + file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/ } else { /*next chunk*/ - file = (int)linphone_chat_message_get_user_data(message); + file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); } - /*store content on a file*/ - write(file,buff,size); - if (size==0) { - printf("File transfert completed"); + printf("File transfert completed\n"); close(file); - } /*else wait for next chunk*/ + running=FALSE; + } else { /* store content on a file*/ + write(file,buff,size); + } + free(from); } char big_file [128000]; /* - * function call when is file transfer is initiated. file content should be feed into object LinphoneContent + * function called when the file transfer is initiated. file content should be feed into object LinphoneContent * */ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){ - const LinphoneAddress* to_address = linphone_chat_message_get_to(message); - char *to = linphone_address_as_string(to_address); + //const LinphoneAddress* to_address = linphone_chat_message_get_to(message); + //char *to = linphone_address_as_string(to_address); int offset=-1; /*content->size can be feed*/ @@ -106,7 +107,7 @@ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, offset=0; } else { /*subsequent chunk*/ - offset = (int)linphone_chat_message_get_user_data(message); + offset = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); } *size = MIN(*size,sizeof(big_file)-offset); /*updating content->size with minimun between remaining data and requested size*/ @@ -119,11 +120,22 @@ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, printf(" File transfer sending [%i] bytes of type [%s/%s] from [%s] \n" , (int)*size , content->type , content->subtype - , to); + , "pipo"); /*store offset for next chunk*/ linphone_chat_message_set_user_data(message,(void*)(offset+*size)); - free(to); + //free(to); + +} + +/* + * Call back called when a message is received + */ +static void message_received(LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatMessage *msg) { + const LinphoneContent *file_transfer_info = linphone_chat_message_get_file_transfer_information(msg); + printf ("Do you really want to download %s (size %ld)?[Y/n]\nOk, let's go\n", file_transfer_info->name, file_transfer_info->size); + + linphone_chat_message_start_file_download(msg); } /* @@ -137,21 +149,21 @@ static void linphone_file_transfer_state_changed(LinphoneChatMessage* msg,Linpho free(to); } + LinphoneCore *lc; int main(int argc, char *argv[]){ LinphoneCoreVTable vtable={0}; - char* dest_friend=NULL; + const char* dest_friend=NULL; int i; const char* big_file_content="big file"; /*seting dummy file content to something*/ - for (i=0;i1){ - dest_friend=argv[1]; - } signal(SIGINT,stop); //#define DEBUG #ifdef DEBUG @@ -166,20 +178,24 @@ int main(int argc, char *argv[]){ vtable.file_transfer_received=file_transfer_received; vtable.file_transfer_send=file_transfer_send; vtable.file_transfer_progress_indication=file_transfer_progress_indication; + vtable.message_received=message_received; /* Instantiate a LinphoneCore object given the LinphoneCoreVTable */ lc=linphone_core_new(&vtable,NULL,NULL,NULL); + dest_friend = linphone_core_get_primary_contact(lc); + printf("Send message to me : %s\n", dest_friend); /** * Globally configure an http file transfer server. */ - linphone_core_set_file_transfer_server(lc,"http://sharing.linphone.org/upload.php"); + linphone_core_set_file_transfer_server(lc,"http://npasc.al/lft.php"); + //linphone_core_set_file_transfer_server(lc,"https://www.linphone.org:444/upload.php"); - /*Next step is to create a chat root*/ + /*Next step is to create a chat room*/ LinphoneChatRoom* chat_room = linphone_core_create_chat_room(lc,dest_friend); LinphoneContent content; @@ -187,13 +203,16 @@ int main(int argc, char *argv[]){ content.type="text"; content.subtype="plain"; content.size=sizeof(big_file); /*total size to be transfered*/ + content.name = "bigfile.txt"; /*now create a chat message with custom content*/ LinphoneChatMessage* chat_message = linphone_chat_room_create_file_transfer_message(chat_room,&content); + if (chat_message == NULL) { + printf("returned message is null\n"); + } /*initiating file transfer*/ - /**/ - linphone_chat_room_send_message2(chat_room, chat_message,linphone_file_transfer_state_changed,NULL); + linphone_chat_room_send_message2(chat_room, chat_message, linphone_file_transfer_state_changed, NULL); /* main loop for receiving incoming messages and doing background linphone core work: */ while(running){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a77d550ae..b1b77f0fb 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1392,6 +1392,8 @@ static void linphone_core_init(LinphoneCore * lc, const LinphoneCoreVTable *vtab lc->http_verify_policy = belle_tls_verify_policy_new(); belle_http_provider_set_tls_verify_policy(lc->http_provider,lc->http_verify_policy); + lc->file_transfer_server = NULL; + certificates_config_read(lc); remote_provisioning_uri = linphone_core_get_provisioning_uri(lc); @@ -5891,6 +5893,8 @@ static void linphone_core_uninit(LinphoneCore *lc) lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids); // Free struct variable + ms_free(lc->file_transfer_server); + if(lc->zrtp_secrets_cache != NULL) { ms_free(lc->zrtp_secrets_cache); } @@ -6536,3 +6540,11 @@ bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc) { return lc->sip_conf.sdp_200_ack!=0; } +/** + * Globaly set an http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml. This value can also be set for a dedicated account using #linphone_proxy_config_set_file_transfer_server + * @param #LinphoneCore to be modified + * @param const char* url of the file server like https://file.linphone.org/upload.php + **/ +void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url) { + core->file_transfer_server=ms_strdup(server_url); +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d57e77278..1c8f83992 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -137,6 +137,7 @@ struct _LinphoneContent{ size_t size; /** Date: Thu, 29 May 2014 12:31:22 +0200 Subject: [PATCH 034/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 6ce0bcea9..f47343572 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 6ce0bcea96b6e91c856e9a9dbab5b7bf8720ba9f +Subproject commit f47343572409561009e38a241ef3fde113d596d7 From 1a2e24b14aa4af35739d2cd9b797089de3aa91fa Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 29 May 2014 14:54:09 +0200 Subject: [PATCH 035/201] update mediastreamer2 to fix big regression with vp8 and h264 fix printf formatter to be compatible with visual studio --- coreapi/message_storage.c | 2 +- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 86887c7b7..1975edb23 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -371,7 +371,7 @@ void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { } static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){ - ms_warning("SQL statement '%s' took %" PRId64 " microseconds", statement, duration / 1000 ); + ms_warning("SQL statement '%s' took %llu microseconds", statement, (unsigned long long)duration / 1000LL ); } static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){ diff --git a/mediastreamer2 b/mediastreamer2 index f47343572..5db89bd64 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f47343572409561009e38a241ef3fde113d596d7 +Subproject commit 5db89bd644eb5a692c4b570e06a199943ff6cb26 diff --git a/oRTP b/oRTP index 2f3ce6970..a6c420eed 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 2f3ce697093694165a31f024a3141cd89a95bc42 +Subproject commit a6c420eedd03c677f5560c3b37bf2b5684c6b0f9 From 00fa127aecc7579a397730700eccf3c057d8f9b9 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 30 May 2014 08:41:32 +0200 Subject: [PATCH 036/201] fix format specifier again --- coreapi/message_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 1975edb23..81d076fc5 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -371,7 +371,7 @@ void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { } static void _linphone_message_storage_profile(void*data,const char*statement, sqlite3_uint64 duration){ - ms_warning("SQL statement '%s' took %llu microseconds", statement, (unsigned long long)duration / 1000LL ); + ms_warning("SQL statement '%s' took %" PRIu64 " microseconds", statement, (uint64_t)(duration / 1000LL) ); } static void linphone_message_storage_activate_debug(sqlite3* db, bool_t debug){ From 8c2e4d9e807f699ca70362bfbc08a73fee17a306 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 30 May 2014 12:06:26 +0200 Subject: [PATCH 037/201] increment sdp session id when making a response to pause/resume request don't accept linphone_core_update_call() outside of StreamsRunning state. --- coreapi/callbacks.c | 4 ++++ coreapi/linphonecall.c | 5 +++++ coreapi/linphonecore.c | 19 +++++++++++-------- coreapi/private.h | 1 + 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 94d7f17d2..cc981d9a6 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -460,6 +460,8 @@ static void call_accept_update(LinphoneCore *lc, LinphoneCall *call){ } static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ + /*when we are resumed, increment session id, because sdp is changed (a=recvonly disapears)*/ + linphone_call_increment_local_media_description(call); call_accept_update(lc,call); if(lc->vtable.display_status) lc->vtable.display_status(lc,_("We have been resumed.")); @@ -467,6 +469,8 @@ static void call_resumed(LinphoneCore *lc, LinphoneCall *call){ } static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){ + /*when we are resumed, increment session id, because sdp is changed (a=recvonly appears)*/ + linphone_call_increment_local_media_description(call); call_accept_update(lc,call); /* we are being paused */ if(lc->vtable.display_status) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 04023c386..3f473ce53 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -306,6 +306,11 @@ static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) { } } +void linphone_call_increment_local_media_description(LinphoneCall *call){ + SalMediaDescription *md=call->localdesc; + md->session_ver++; +} + void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ MSList *l; PayloadType *pt; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index a9e472388..95431b1f9 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3153,23 +3153,28 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho #ifdef VIDEO_ENABLED bool_t has_video = FALSE; #endif + + if (call->state!=LinphoneCallStreamsRunning){ + ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state)); + return -1; + } + if (params!=NULL){ linphone_call_set_state(call,LinphoneCallUpdating,"Updating call"); -#ifdef VIDEO_ENABLED +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) has_video = call->params.has_video; // Video removing if((call->videostream != NULL) && !params->has_video) { -#ifdef BUILD_UPNP if(call->upnp_session != NULL) { if (linphone_core_update_upnp(lc, call)<0) { /* uPnP port mappings failed, proceed with the call anyway. */ linphone_call_delete_upnp_session(call); } } -#endif //BUILD_UPNP + } -#endif /* VIDEO_ENABLED */ +#endif /* defined(VIDEO_ENABLED) && defined(BUILD_UPNP) */ _linphone_call_params_copy(&call->params,params); err=linphone_call_prepare_ice(call,FALSE); @@ -3178,10 +3183,9 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho return 0; } -#ifdef VIDEO_ENABLED +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) // Video adding if (!has_video && call->params.has_video) { -#ifdef BUILD_UPNP if(call->upnp_session != NULL) { ms_message("Defer call update to add uPnP port mappings"); video_stream_prepare_video(call->videostream); @@ -3192,9 +3196,8 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho return err; } } -#endif //BUILD_UPNP } -#endif //VIDEO_ENABLED +#endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP) err = linphone_core_start_update_call(lc, call); }else{ #ifdef VIDEO_ENABLED diff --git a/coreapi/private.h b/coreapi/private.h index a2fb3d9c2..5ebccdf35 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -742,6 +742,7 @@ int linphone_core_get_calls_nb(const LinphoneCore *lc); void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call); +void linphone_call_increment_local_media_description(LinphoneCall *call); void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md); bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, const PayloadType *pt, int bandwidth_limit); From 7a85da0ff0070a3b7ff9b61a366d7d7a784407de Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 30 May 2014 16:32:16 +0200 Subject: [PATCH 038/201] fix local ref overflow in JNI, due to too many logs during linphone_core_new(). --- coreapi/linphonecore_jni.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index f6478c5fe..4b04cb387 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -121,7 +121,13 @@ static void linphone_android_ortp_log_handler(OrtpLogLevel lev, const char *fmt, } if (handler_obj){ JNIEnv *env=ms_get_jni_env(); - env->CallVoidMethod(handler_obj,loghandler_id,env->NewStringUTF(LogDomain),(jint)lev,env->NewStringUTF(levname),env->NewStringUTF(str),NULL); + jstring jdomain=env->NewStringUTF(LogDomain); + jstring jlevname=env->NewStringUTF(levname); + jstring jstr=env->NewStringUTF(str); + env->CallVoidMethod(handler_obj,loghandler_id,jdomain,(jint)lev,jlevname,jstr,NULL); + if (jdomain) env->DeleteLocalRef(jdomain); + if (jlevname) env->DeleteLocalRef(jlevname); + if (jstr) env->DeleteLocalRef(jstr); }else linphone_android_log_handler(prio, str); } From 92b20e62feaa5ac039a21efc4d1a7be74a768d67 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sat, 31 May 2014 11:29:53 +0200 Subject: [PATCH 039/201] fix warning --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 95431b1f9..7cbb5b955 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3150,7 +3150,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ **/ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ int err=0; -#ifdef VIDEO_ENABLED +#if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) bool_t has_video = FALSE; #endif From 509b105bb64dcdbc99073639575a3e55670aa9ae Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 2 Jun 2014 06:58:19 +0200 Subject: [PATCH 040/201] File transfer: fix memory leak --- coreapi/chat.c | 12 +++++++++++- coreapi/help/filetransfer.c | 3 +++ coreapi/info.c | 4 +++- coreapi/private.h | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 02638a64c..ecb8d395b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -153,6 +153,8 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co if (code == 200 ) { /* file has been uplaoded correctly, get server reply and send it */ const char *body = belle_sip_message_get_body((belle_sip_message_t *)event->response); msg->message = ms_strdup(body); + linphone_content_uninit(msg->file_transfer_information); + ms_free(msg->file_transfer_information); msg->file_transfer_information = NULL; msg->content_type = ms_strdup("application/vnd.gsma.rcs-ft-http+xml"); _linphone_chat_room_send_message(msg->chat_room, msg); @@ -644,6 +646,7 @@ LinphoneChatMessage* linphone_chat_room_create_message(LinphoneChatRoom *cr, con msg->message=message?ms_strdup(message):NULL; msg->is_read=TRUE; msg->content_type = NULL; /* this property is used only when transfering file */ + msg->file_transfer_information = NULL; /* this property is used only when transfering file */ return msg; } @@ -671,6 +674,7 @@ LinphoneChatMessage* linphone_chat_room_create_message_2( msg->state=state; msg->is_read=is_read; msg->content_type = NULL; /* this property is used only when transfering file */ + msg->file_transfer_information = NULL; /* this property is used only when transfering file */ if (is_incoming) { msg->dir=LinphoneChatMessageIncoming; linphone_chat_message_set_from(msg, linphone_chat_room_get_peer_address(cr)); @@ -1135,6 +1139,10 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) { if (msg->to) linphone_address_destroy(msg->to); if (msg->custom_headers) sal_custom_header_free(msg->custom_headers); if (msg->content_type) ms_free(msg->content_type); + if (msg->file_transfer_information) { + linphone_content_uninit(msg->file_transfer_information); + ms_free(msg->file_transfer_information); + } } @@ -1182,7 +1190,9 @@ LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneCha LinphoneChatMessage* msg = belle_sip_object_new(LinphoneChatMessage); msg->chat_room=(LinphoneChatRoom*)cr; msg->message = NULL; - msg->file_transfer_information = initial_content; + msg->file_transfer_information = (LinphoneContent *)malloc(sizeof(LinphoneContent)); + memset(msg->file_transfer_information, 0, sizeof(LinphoneContent)); + linphone_content_copy(msg->file_transfer_information, initial_content); msg->dir=LinphoneChatMessageOutgoing; linphone_chat_message_set_to(msg, linphone_chat_room_get_peer_address(cr)); linphone_chat_message_set_from(msg, linphone_address_new(linphone_core_get_identity(cr->lc))); diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c index b45019c43..c297edaf2 100644 --- a/coreapi/help/filetransfer.c +++ b/coreapi/help/filetransfer.c @@ -82,6 +82,8 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag if (size==0) { printf("File transfert completed\n"); + linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); + linphone_chat_message_destroy(message); close(file); running=FALSE; } else { /* store content on a file*/ @@ -220,6 +222,7 @@ int main(int argc, char *argv[]){ ms_usleep(50000); } + printf("Shutting down...\n"); linphone_chat_room_destroy(chat_room); linphone_core_destroy(lc); diff --git a/coreapi/info.c b/coreapi/info.c index ff7ff3c93..2bf2b85ad 100644 --- a/coreapi/info.c +++ b/coreapi/info.c @@ -42,10 +42,11 @@ struct _LinphoneInfoMessage{ ptr->field=ms_strdup(val); \ } -static void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){ +void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref){ SET_STRING(obj,type,ref->type); SET_STRING(obj,subtype,ref->subtype); SET_STRING(obj,encoding,ref->encoding); + SET_STRING(obj,name,ref->name); if (obj->data) { ms_free(obj->data); obj->data=NULL; @@ -63,6 +64,7 @@ void linphone_content_uninit(LinphoneContent * obj){ if (obj->subtype) ms_free(obj->subtype); if (obj->data) ms_free(obj->data); if (obj->encoding) ms_free(obj->encoding); + if (obj->name) ms_free(obj->name); } LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref){ diff --git a/coreapi/private.h b/coreapi/private.h index bcf683c9e..581bd6bb9 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -818,6 +818,7 @@ void linphone_call_create_op(LinphoneCall *call); int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer); void linphone_core_notify_info_message(LinphoneCore* lc,SalOp *op, const SalBody *body); void linphone_content_uninit(LinphoneContent * obj); +void linphone_content_copy(LinphoneContent *obj, const LinphoneContent *ref); LinphoneContent *linphone_content_copy_from_sal_body(LinphoneContent *obj, const SalBody *ref); SalBody *sal_body_from_content(SalBody *body, const LinphoneContent *lc); SalReason linphone_reason_to_sal(LinphoneReason reason); From 2110281d2e8208453e353895ca7634731450ed62 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 28 May 2014 11:18:35 +0200 Subject: [PATCH 041/201] Handle AVPF and SAVPF profiles. --- coreapi/bellesip_sal/sal_op_call.c | 2 +- coreapi/bellesip_sal/sal_sdp.c | 18 +++--- coreapi/callbacks.c | 40 +++++++------ coreapi/linphonecall.c | 90 +++++++++++++----------------- coreapi/linphonecore.c | 2 +- coreapi/misc.c | 7 +++ coreapi/offeranswer.c | 9 +-- coreapi/private.h | 3 + coreapi/sal.c | 35 ++++++++++++ include/sal/sal.h | 6 ++ 10 files changed, 132 insertions(+), 80 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 9a2474b37..2a433b7f6 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -70,7 +70,7 @@ static void sdp_process(SalOp *h){ strcpy(h->result->streams[i].rtcp_addr,h->base.remote_media->streams[i].rtcp_addr); h->result->streams[i].rtcp_port=h->base.remote_media->streams[i].rtcp_port; - if (h->result->streams[i].proto == SalProtoRtpSavp) { + if ((h->result->streams[i].proto == SalProtoRtpSavpf) || (h->result->streams[i].proto == SalProtoRtpSavp)) { h->result->streams[i].crypto[0] = h->base.remote_media->streams[i].crypto[0]; } } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 23d0d8be4..0cf94bed3 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -143,7 +143,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session if ( stream->bandwidth>0 ) belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); - if ( stream->proto == SalProtoRtpSavp ) { + if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) { /* add crypto lines */ for ( j=0; jproto=SalProtoOther; if ( proto ) { - if ( strcasecmp ( proto,"RTP/AVP" ) ==0 ) - stream->proto=SalProtoRtpAvp; - else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) { - stream->proto=SalProtoRtpSavp; - }else{ + if (strcasecmp(proto, "RTP/AVP") == 0) { + stream->proto = SalProtoRtpAvp; + } else if (strcasecmp(proto, "RTP/SAVP") == 0) { + stream->proto = SalProtoRtpSavp; + } else if (strcasecmp(proto, "RTP/AVPF") == 0) { + stream->proto = SalProtoRtpAvpf; + } else if (strcasecmp(proto, "RTP/SAVPF") == 0) { + stream->proto = SalProtoRtpSavpf; + } else { strncpy(stream->proto_other,proto,sizeof(stream->proto_other)-1); } } @@ -532,7 +536,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, } /* Read crypto lines if any */ - if ( stream->proto == SalProtoRtpSavp ) { + if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) { sdp_parse_media_crypto_parameters(media_desc, stream); } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cc981d9a6..64f17f411 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -670,24 +670,32 @@ static void call_failure(SalOp *op){ break; case SalReasonUnsupportedContent: /*params.media_encryption == LinphoneMediaEncryptionSRTP && - !linphone_core_is_media_encryption_mandatory(lc)) { + ms_message("Outgoing call [%p] failed with SRTP and/or AVPF enabled", call); + if ((call->state == LinphoneCallOutgoingInit) + || (call->state == LinphoneCallOutgoingProgress) + || (call->state == LinphoneCallOutgoingRinging) /* Push notification case */ + || (call->state == LinphoneCallOutgoingEarlyMedia)) { int i; - ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call); - if (call->state==LinphoneCallOutgoingInit - || call->state==LinphoneCallOutgoingProgress - || call->state==LinphoneCallOutgoingRinging /*push case*/ - || call->state==LinphoneCallOutgoingEarlyMedia){ - ms_message("Retrying call [%p] with AVP",call); - /* clear SRTP local params */ - call->params.media_encryption = LinphoneMediaEncryptionNone; - for(i=0; ilocaldesc->n_active_streams; i++) { - call->localdesc->streams[i].proto = SalProtoRtpAvp; - memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); + for (i = 0; i < call->localdesc->n_active_streams; i++) { + if (call->params.media_encryption == LinphoneMediaEncryptionSRTP) { + if (call->params.avpf_enabled == TRUE) { + if (i == 0) ms_message("Retrying call [%p] with SAVP", call); + call->params.avpf_enabled = FALSE; + linphone_core_restart_invite(lc, call); + return; + } else if (!linphone_core_is_media_encryption_mandatory(lc)) { + if (i == 0) ms_message("Retrying call [%p] with AVP", call); + call->params.media_encryption = LinphoneMediaEncryptionNone; + memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto)); + linphone_core_restart_invite(lc, call); + return; + } + } else if (call->params.avpf_enabled == TRUE) { + if (i == 0) ms_message("Retrying call [%p] with AVP", call); + call->params.avpf_enabled = FALSE; + linphone_core_restart_invite(lc, call); + return; } - linphone_core_restart_invite(lc, call); - return; } } msg=_("Incompatible media parameters."); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 3f473ce53..1a962ef3e 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -265,8 +265,8 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1); for(i=0; in_active_streams; i++) { - if (md->streams[i].proto == SalProtoRtpSavp) { - if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){ + if (is_encryption_active(&md->streams[i]) == TRUE) { + if (keep_srtp_keys && old_md && is_encryption_active(&old_md->streams[i]) == TRUE){ int j; ms_message("Keeping same crypto keys."); for(j=0;jsession_ver++; } +static SalMediaProto get_proto_from_call_params(LinphoneCallParams *params) { + if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf; + if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp; + if (params->avpf_enabled) return SalProtoRtpAvpf; + return SalProtoRtpAvp; +} + void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){ MSList *l; PayloadType *pt; @@ -349,8 +356,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1); md->streams[0].rtp_port=call->media_ports[0].rtp_port; md->streams[0].rtcp_port=call->media_ports[0].rtcp_port; - md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ? - SalProtoRtpSavp : SalProtoRtpAvp; + md->streams[0].proto=get_proto_from_call_params(&call->params); md->streams[0].type=SalAudio; if (call->params.down_ptime) md->streams[0].ptime=call->params.down_ptime; @@ -961,10 +967,6 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ return &call->current_params; } -static bool_t is_video_active(const SalStreamDescription *sd){ - return sd->rtp_port!=0 && sd->dir!=SalStreamInactive; -} - /** * Returns call parameters proposed by remote. * @@ -976,19 +978,20 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ memset(cp,0,sizeof(*cp)); if (call->op){ SalMediaDescription *md=sal_call_get_remote_media_description(call->op); - if (md){ - SalStreamDescription *asd,*vsd,*secure_asd,*secure_vsd; + if (md) { + SalStreamDescription *sd; + unsigned int i; + unsigned int nb_audio_streams = sal_media_description_nb_active_streams_of_type(md, SalAudio); + unsigned int nb_video_streams = sal_media_description_nb_active_streams_of_type(md, SalVideo); - asd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalAudio); - vsd=sal_media_description_find_stream(md,SalProtoRtpAvp,SalVideo); - secure_asd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalAudio); - secure_vsd=sal_media_description_find_stream(md,SalProtoRtpSavp,SalVideo); - if (secure_vsd){ - cp->has_video=is_video_active(secure_vsd); - if (secure_asd || asd==NULL) - cp->media_encryption=LinphoneMediaEncryptionSRTP; - }else if (vsd){ - cp->has_video=is_video_active(vsd); + for (i = 0; i < nb_video_streams; i++) { + sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); + if (is_video_active(sd) == TRUE) cp->has_video = TRUE; + if (is_encryption_active(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + } + for (i = 0; i < nb_audio_streams; i++) { + sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); + if (is_encryption_active(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; } if (!cp->has_video){ if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){ @@ -1861,12 +1864,10 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca const SalStreamDescription *localstream; const SalStreamDescription *remotestream; - localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, type); - if (!localstream) localstream = sal_media_description_find_stream(call->localdesc, SalProtoRtpAvp, type); + localstream = sal_media_description_find_best_stream(call->localdesc, type); if (!localstream) return; localconfig = &localstream->rtcp_xr; - remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpSavp, type); - if (!remotestream) remotestream = sal_media_description_find_stream(sal_call_get_remote_media_description(call->op), SalProtoRtpAvp, type); + remotestream = sal_media_description_find_best_stream(sal_call_get_remote_media_description(call->op), type); if (!remotestream) return; remoteconfig = &remotestream->rtcp_xr; @@ -1902,14 +1903,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna int crypto_idx; snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); - /* look for savp stream first */ - stream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpSavp,SalAudio); - /* no savp audio stream, use avp */ - if (!stream) - stream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalAudio); + stream = sal_media_description_find_best_stream(call->resultdesc, SalAudio); if (stream && stream->dir!=SalStreamInactive && stream->rtp_port!=0){ playcard=lc->sound_conf.lsd_card ? lc->sound_conf.lsd_card : lc->sound_conf.play_sndcard; @@ -1965,8 +1960,8 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna call->current_params.record_file=ms_strdup(call->params.record_file); } /* valid local tags are > 0 */ - if (stream->proto == SalProtoRtpSavp) { - local_st_desc=sal_media_description_find_stream(call->localdesc,SalProtoRtpSavp,SalAudio); + if (is_encryption_active(stream) == TRUE) { + local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio); crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); if (crypto_idx >= 0) { @@ -2020,17 +2015,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna #ifdef VIDEO_ENABLED LinphoneCore *lc=call->core; int used_pt=-1; - - /* look for savp stream first */ - const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpSavp,SalVideo); char rtcp_tool[128]={0}; - snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); + const SalStreamDescription *vstream; - /* no savp audio stream, use avp */ - if (!vstream) - vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); + snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); /* shutdown preview */ if (lc->previewstream!=NULL) { @@ -2038,6 +2026,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna lc->previewstream=NULL; } + vstream = sal_media_description_find_best_stream(call->resultdesc, SalVideo); if (vstream!=NULL && vstream->dir!=SalStreamInactive && vstream->rtp_port!=0) { const char *rtp_addr=vstream->rtp_addr[0]!='\0' ? vstream->rtp_addr : call->resultdesc->addr; const char *rtcp_addr=vstream->rtcp_addr[0]!='\0' ? vstream->rtcp_addr : call->resultdesc->addr; @@ -2088,7 +2077,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna cam=get_nowebcam_device(); } if (!is_inactive){ - if (vstream->proto == SalProtoRtpSavp) { + if (is_encryption_active(vstream) == TRUE) { int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); if (crypto_idx >= 0) { media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key); @@ -2121,8 +2110,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut char *cname; bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); #ifdef VIDEO_ENABLED - const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, - SalProtoRtpAvp,SalVideo); + const SalStreamDescription *vstream=sal_media_description_find_best_stream(call->resultdesc,SalVideo); #endif call->current_params.audio_codec = NULL; @@ -2209,17 +2197,17 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript SalStreamDescription *new_stream; const SalStreamDescription *local_st_desc; - local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio); - old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalAudio); - new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio); + local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalAudio); + old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalAudio); + new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalAudio); if (call->audiostream && local_st_desc && old_stream && new_stream && update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->audiostream->ms)){ } #ifdef VIDEO_ENABLED - local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo); - old_stream = sal_media_description_find_stream(old_md, SalProtoRtpSavp, SalVideo); - new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo); + local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalVideo); + old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalVideo); + new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalVideo); if (call->videostream && local_st_desc && old_stream && new_stream && update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->videostream->ms)){ } diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7cbb5b955..15f7945cf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2972,7 +2972,7 @@ bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){ for(i=0;in_active_streams;i++){ const SalStreamDescription *sd=&md->streams[i]; - if (sd->proto!=SalProtoRtpSavp){ + if (is_encryption_active(sd) != TRUE){ return FALSE; } } diff --git a/coreapi/misc.c b/coreapi/misc.c index c27147107..f8fae4210 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1520,3 +1520,10 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){ return result; } +bool_t is_video_active(const SalStreamDescription *sd) { + return (sd->rtp_port != 0) && (sd->dir != SalStreamInactive); +} + +bool_t is_encryption_active(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoRtpSavpf) || (sd->proto == SalProtoRtpSavp)); +} diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index fd99f421c..be8998168 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -233,7 +233,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, }else{ result->rtp_port=0; } - if (result->proto == SalProtoRtpSavp) { + if (is_encryption_active(result) == TRUE) { /* verify crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) @@ -259,7 +259,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, }else{ result->rtp_port=0; } - if (result->proto == SalProtoRtpSavp) { + if (is_encryption_active(result) == TRUE) { /* select crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE)) @@ -323,10 +323,11 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c return TRUE; } -/*in answering mode, we consider that if we are able to make SAVP, then we can do AVP as well*/ +/*in answering mode, we consider that if we are able to make AVPF/SAVP/SAVPF, then we can do AVP as well*/ static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote){ if (local==remote) return TRUE; - if (remote==SalProtoRtpAvp && local==SalProtoRtpSavp) return TRUE; + if ((remote==SalProtoRtpAvp) && ((local==SalProtoRtpSavp) || (local==SalProtoRtpAvpf) || (local==SalProtoRtpSavpf))) + return TRUE; return FALSE; } diff --git a/coreapi/private.h b/coreapi/private.h index 5ebccdf35..dc9a02e80 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -95,6 +95,7 @@ struct _LinphoneCallParams{ char *session_name; SalCustomHeader *custom_headers; bool_t has_video; + bool_t avpf_enabled; /* RTCP feedback messages are enabled */ bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/ bool_t in_conference; /*in conference mode */ bool_t low_bandwidth; @@ -389,6 +390,8 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LinphoneCall * is_a_linphone_call(void *user_pointer); LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); +bool_t is_video_active(const SalStreamDescription *sd); +bool_t is_encryption_active(const SalStreamDescription *sd); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); diff --git a/coreapi/sal.c b/coreapi/sal.c index cb94d675c..74d087139 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -91,6 +91,39 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, return NULL; } +unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type) { + unsigned int i; + unsigned int nb = 0; + for (i = 0; i < md->n_active_streams; ++i) { + if (md->streams[i].type == type) nb++; + } + return nb; +} + +SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx) { + unsigned int i; + for (i = 0; i < md->n_active_streams; ++i) { + if (md->streams[i].type == type) { + if (idx-- == 0) return &md->streams[i]; + } + } + return NULL; +} + +SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type) { + SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); + return desc; +} + +SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type) { + SalStreamDescription *desc = sal_media_description_find_stream(md, SalProtoRtpSavpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpSavp, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvpf, type); + if (desc == NULL) desc = sal_media_description_find_stream(md, SalProtoRtpAvp, type); + return desc; +} + bool_t sal_media_description_empty(const SalMediaDescription *md){ if (md->n_active_streams > 0) return FALSE; return TRUE; @@ -515,6 +548,8 @@ const char* sal_media_proto_to_string(SalMediaProto type) { switch (type) { case SalProtoRtpAvp:return "RTP/AVP"; case SalProtoRtpSavp:return "RTP/SAVP"; + case SalProtoRtpAvpf:return "RTP/AVPF"; + case SalProtoRtpSavpf:return "RTP/SAVPF"; default: return "unknown"; } } diff --git a/include/sal/sal.h b/include/sal/sal.h index fbeaf2e14..d5712c09d 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -123,6 +123,8 @@ const char* sal_stream_type_to_string(SalStreamType type); typedef enum{ SalProtoRtpAvp, SalProtoRtpSavp, + SalProtoRtpAvpf, + SalProtoRtpSavpf, SalProtoOther }SalMediaProto; const char* sal_media_proto_to_string(SalMediaProto type); @@ -251,6 +253,10 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir); SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); +unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type); +SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx); +SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type); +SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type); void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir); From 1a5f37eabaf498eae98a76a08991cd1258c7fabd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 28 May 2014 12:14:18 +0200 Subject: [PATCH 042/201] Allow activation of AVPF for a call based on the proxy configuration. --- coreapi/linphonecall.c | 1 + coreapi/linphonecore.c | 10 ++++++++-- coreapi/linphonecore.h | 21 +++++++++++++++++++++ coreapi/private.h | 5 ++++- coreapi/proxy.c | 18 ++++++++++++++++++ include/sal/sal.h | 1 + 6 files changed, 53 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 1a962ef3e..84168419c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -340,6 +340,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); md->n_total_streams=(call->biggestdesc ? call->biggestdesc->n_total_streams : 1); + md->avpf_rr_interval = call->params.avpf_rr_interval; strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 15f7945cf..65b18e6e8 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2825,6 +2825,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const char *real_url=NULL; LinphoneCall *call; bool_t defer = FALSE; + LinphoneCallParams *cp = linphone_call_params_copy(params); linphone_core_preempt_sound_resources(lc); @@ -2837,20 +2838,24 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const real_url=linphone_address_as_string(addr); proxy=linphone_core_lookup_known_proxy(lc,addr); - if (proxy!=NULL) + if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); + cp->avpf_enabled = proxy->avpf_enabled; + cp->avpf_rr_interval = proxy->avpf_rr_interval; + } /* if no proxy or no identity defined for this proxy, default to primary contact*/ if (from==NULL) from=linphone_core_get_primary_contact(lc); parsed_url2=linphone_address_new(from); - call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params,proxy); + call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy); if(linphone_core_add_call(lc,call)!= 0) { ms_warning("we had a problem in adding the call into the invite ... weird"); linphone_call_unref(call); + linphone_call_params_destroy(cp); return NULL; } @@ -2895,6 +2900,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (defer==FALSE) linphone_core_start_invite(lc,call,NULL); if (real_url!=NULL) ms_free(real_url); + linphone_call_params_destroy(cp); return call; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index fc02cbb23..b9a199519 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -929,6 +929,27 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *para * */ LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const LinphoneProxyConfig *params); +/** + * Indicates whether AVPF/SAVPF must be used for calls using this proxy config. + * @param[in] cfg #LinphoneProxyConfig object + * @param[in] enable True to enable AVPF/SAVF, false to disable it. + */ +LINPHONE_PUBLIC void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable); + +/** + * Set the interval between regular RTCP reports when using AVPF/SAVPF. + * @param[in] cfg #LinphoneProxyConfig object + * @param[in] interval The interval in seconds (between 0 and 5 seconds). + */ +LINPHONE_PUBLIC void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval); + +/** + * Get the interval between regular RTCP reports when using AVPF/SAVPF. + * @param[in] cfg #LinphoneProxyConfig object + * @return The interval in seconds. + */ +LINPHONE_PUBLIC uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cfg); + /** * @} **/ diff --git a/coreapi/private.h b/coreapi/private.h index dc9a02e80..589297849 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -100,6 +100,7 @@ struct _LinphoneCallParams{ bool_t in_conference; /*in conference mode */ bool_t low_bandwidth; LinphonePrivacyMask privacy; + uint8_t avpf_rr_interval; }; struct _LinphoneCallLog{ @@ -430,7 +431,9 @@ struct _LinphoneProxyConfig bool_t dial_escape_plus; bool_t send_publish; bool_t send_statistics; - bool_t pad[3]; + bool_t avpf_enabled; + bool_t pad; + uint8_t avpf_rr_interval; void* user_data; time_t deletion_date; LinphonePrivacyMask privacy; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ea021639a..278fd9be6 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1183,6 +1183,8 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC lp_config_set_int(config,key,"reg_expires",obj->expires); lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister); lp_config_set_int(config,key,"publish",obj->publish); + lp_config_set_int(config, key, "avpf", obj->avpf_enabled); + lp_config_set_int(config, key, "avpf_rr_interval", obj->avpf_rr_interval); lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus); lp_config_set_int(config,key,"send_statistics",obj->send_statistics); lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix); @@ -1229,6 +1231,9 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0)); + linphone_proxy_config_enable_avpf(cfg, lp_config_get_int(config, key, "avpf", 0)); + linphone_proxy_config_set_avpf_rr_interval(cfg, lp_config_get_int(config, key, "avpf_rr_interval", 0)); + linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0))); linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL))); @@ -1541,3 +1546,16 @@ int linphone_proxy_config_get_publish_expires(const LinphoneProxyConfig *obj) { } } + +void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable) { + cfg->avpf_enabled = enable; +} + +void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval) { + if (interval > 5) interval = 5; + cfg->avpf_rr_interval = interval; +} + +uint8_t linphone_proxy_config_get_avpf_rr_interval(const LinphoneProxyConfig *cfg) { + return cfg->avpf_rr_interval; +} diff --git a/include/sal/sal.h b/include/sal/sal.h index d5712c09d..b2ce51e22 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -221,6 +221,7 @@ typedef struct SalMediaDescription{ unsigned int session_ver; unsigned int session_id; SalStreamDir dir; + uint8_t avpf_rr_interval; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; OrtpRtcpXrConfiguration rtcp_xr; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; From 0a40048d4b355cd82dab532ea9c84d14ffb03a73 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 28 May 2014 14:00:52 +0200 Subject: [PATCH 043/201] Add rtcp-fb attributes in the SDP. --- coreapi/bellesip_sal/sal_sdp.c | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 0cf94bed3..31341fd21 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -68,6 +68,40 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer)); } +static void add_rtcp_fb_nack_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) { + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, id); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_NACK); + belle_sdp_rtcp_fb_attribute_set_param(attribute, param); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); +} + +static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream, int nb_avpf_pt) { + MSList *pt_it; + PayloadType *pt; + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, -1); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT); + belle_sdp_rtcp_fb_attribute_set_trr_int(attribute, md->avpf_rr_interval); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); + if ((stream->type == SalVideo) && (nb_avpf_pt > 0)) { + if (nb_avpf_pt == ms_list_size(stream->payloads)) { + add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_PLI); + add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_SLI); + add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_RPSI); + } else { + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *) pt_it->data; + if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); + } + } + } + } +} + static belle_sdp_attribute_t * create_rtcp_xr_attribute(const OrtpRtcpXrConfiguration *config) { belle_sdp_rtcp_xr_attribute_t *attribute = belle_sdp_rtcp_xr_attribute_new(); if (config->rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) { @@ -100,6 +134,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session int rtp_port; int rtcp_port; bool_t different_rtp_and_rtcp_addr; + int nb_avpf_pt = 0; rtp_addr=stream->rtp_addr; rtcp_addr=stream->rtcp_addr; @@ -114,6 +149,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session if (stream->payloads) { for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { pt= ( PayloadType* ) pt_it->data; + if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) nb_avpf_pt++; mime_param= belle_sdp_mime_parameter_create ( pt->mime_type , payload_type_get_number ( pt ) , pt->clock_rate @@ -201,6 +237,10 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session } } + if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) { + add_rtcp_fb_attributes(media_desc, md, stream, nb_avpf_pt); + } + if (stream->rtcp_xr.enabled == TRUE) { char sastr[1024] = {0}; char mastr[1024] = {0}; From cc4095de90237d527de2af48bca910b3df6ec4f9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 28 May 2014 14:01:07 +0200 Subject: [PATCH 044/201] Do not unset the PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED flag anymore. --- coreapi/linphonecall.c | 1 - 1 file changed, 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 84168419c..63ea19a16 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -197,7 +197,6 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw if (max_sample_rate) *max_sample_rate=0; for(it=codecs;it!=NULL;it=it->next){ PayloadType *pt=(PayloadType*)it->data; - payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); /* Disable AVPF for the moment. */ if (pt->flags & PAYLOAD_TYPE_ENABLED){ if (bandwidth_limit>0 && !linphone_core_is_payload_type_usable_for_bandwidth(lc,pt,bandwidth_limit)){ ms_message("Codec %s/%i eliminated because of audio bandwidth constraint of %i kbit/s", From ad64b94401f02d2d9fc308430391c05ce9948d9d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 30 May 2014 14:25:51 +0200 Subject: [PATCH 045/201] Parse rtcp-fb attributes contained in SDP. --- coreapi/bellesip_sal/sal_sdp.c | 136 ++++++++++++++++++++++++++++----- coreapi/linphonecore.c | 5 +- coreapi/linphonecore.h | 7 ++ coreapi/offeranswer.c | 8 +- coreapi/proxy.c | 4 + 5 files changed, 134 insertions(+), 26 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 31341fd21..628fc6974 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -76,28 +76,34 @@ static void add_rtcp_fb_nack_attribute(belle_sdp_media_description_t *media_desc belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); } -static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream, int nb_avpf_pt) { +static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream) { MSList *pt_it; PayloadType *pt; + PayloadTypeAvpfParams avpf_params; belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, -1); belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT); belle_sdp_rtcp_fb_attribute_set_trr_int(attribute, md->avpf_rr_interval); belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); - if ((stream->type == SalVideo) && (nb_avpf_pt > 0)) { - if (nb_avpf_pt == ms_list_size(stream->payloads)) { - add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_PLI); - add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_SLI); - add_rtcp_fb_nack_attribute(media_desc, -1, BELLE_SDP_RTCP_FB_RPSI); - } else { - for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { - pt = (PayloadType *) pt_it->data; - if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); - add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); - } - } + + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + + /* AVPF/SAVPF profile is used so enable AVPF for all paylad types. */ + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params = payload_type_get_avpf_params(pt); + avpf_params.trr_interval = md->avpf_rr_interval; + + /* Add rtcp-fb attributes according to the AVPF features of the payload types. */ + if (avpf_params.features & PAYLOAD_TYPE_AVPF_PLI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_PLI); + } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_SLI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_SLI); + } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_RPSI) { + add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); } } } @@ -134,13 +140,12 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session int rtp_port; int rtcp_port; bool_t different_rtp_and_rtcp_addr; - int nb_avpf_pt = 0; - + rtp_addr=stream->rtp_addr; rtcp_addr=stream->rtcp_addr; rtp_port=stream->rtp_port; rtcp_port=stream->rtcp_port; - + media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream) ,stream->rtp_port ,1 @@ -149,7 +154,6 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session if (stream->payloads) { for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { pt= ( PayloadType* ) pt_it->data; - if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) nb_avpf_pt++; mime_param= belle_sdp_mime_parameter_create ( pt->mime_type , payload_type_get_number ( pt ) , pt->clock_rate @@ -175,7 +179,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session }else inet6=FALSE; belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr)); } - + if ( stream->bandwidth>0 ) belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); @@ -238,7 +242,7 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session } if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) { - add_rtcp_fb_attributes(media_desc, md, stream, nb_avpf_pt); + add_rtcp_fb_attributes(media_desc, md, stream); } if (stream->rtcp_xr.enabled == TRUE) { @@ -324,9 +328,11 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { PayloadType *pt; + PayloadTypeAvpfParams avpf_params; belle_sip_list_t* mime_param_it=NULL; belle_sdp_mime_parameter_t* mime_param; belle_sip_list_t* mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc ); + memset(&avpf_params, 0, sizeof(avpf_params)); for ( mime_param_it=mime_params ; mime_param_it!=NULL ; mime_param_it=mime_param_it->next ) { @@ -338,6 +344,7 @@ static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, S pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) ); pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param ); payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) ); + payload_type_set_avpf_params(pt, avpf_params); stream->payloads=ms_list_append ( stream->payloads,pt ); stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param ); ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, @@ -441,6 +448,87 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_ } } +static void enable_avpf_for_stream(SalStreamDescription *stream) { + MSList *pt_it; + PayloadType *pt; + PayloadTypeAvpfParams avpf_params; + + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + avpf_params = payload_type_get_avpf_params(pt); + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; + avpf_params.trr_interval = 0; + payload_type_set_avpf_params(pt, avpf_params); + } +} + +static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb_attribute, PayloadType *pt) { + PayloadTypeAvpfParams avpf_params = payload_type_get_avpf_params(pt); + switch (belle_sdp_rtcp_fb_attribute_get_type(fb_attribute)) { + case BELLE_SDP_RTCP_FB_NACK: + switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) { + case BELLE_SDP_RTCP_FB_PLI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_PLI; + break; + case BELLE_SDP_RTCP_FB_SLI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_SLI; + break; + case BELLE_SDP_RTCP_FB_RPSI: + avpf_params.features |= PAYLOAD_TYPE_AVPF_RPSI; + break; + default: + break; + } + break; + case BELLE_SDP_RTCP_FB_TRR_INT: + avpf_params.trr_interval = (unsigned char)belle_sdp_rtcp_fb_attribute_get_trr_int(fb_attribute); + break; + case BELLE_SDP_RTCP_FB_ACK: + default: + break; + } + payload_type_set_avpf_params(pt, avpf_params); +} + +static void sdp_parse_rtcp_fb_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *it; + belle_sdp_attribute_t *attribute; + belle_sdp_rtcp_fb_attribute_t *fb_attribute; + MSList *pt_it; + PayloadType *pt; + int8_t pt_num; + + /* Handle rtcp-fb attributes that concern all payload types. */ + for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) { + attribute = BELLE_SDP_ATTRIBUTE(it->data); + if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) { + fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute); + if (belle_sdp_rtcp_fb_attribute_get_id(fb_attribute) == -1) { + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + apply_rtcp_fb_attribute_to_payload(fb_attribute, pt); + } + } + } + } + + /* Handle rtcp-fb attributes that are specefic to a payload type. */ + for (it = belle_sdp_media_description_get_attributes(media_desc); it != NULL; it = it->next) { + attribute = BELLE_SDP_ATTRIBUTE(it->data); + if (keywordcmp("rtcp-fb", belle_sdp_attribute_get_name(attribute)) == 0) { + fb_attribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute); + pt_num = belle_sdp_rtcp_fb_attribute_get_id(fb_attribute); + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + if (payload_type_get_number(pt) == (int)pt_num) { + apply_rtcp_fb_attribute_to_payload(fb_attribute, pt); + } + } + } + } +} + static void sal_init_rtcp_xr_description(OrtpRtcpXrConfiguration *config) { config->enabled = FALSE; config->rcvr_rtt_mode = OrtpRtcpXrRcvrRttNone; @@ -583,6 +671,12 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, /* Get ICE candidate attributes if any */ sdp_parse_media_ice_parameters(media_desc, stream); + /* Get RTCP-FB attributes if any */ + if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) { + enable_avpf_for_stream(stream); + sdp_parse_rtcp_fb_parameters(media_desc, stream); + } + /* Get RTCP-XR attributes if any */ stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 65b18e6e8..d593a1dbd 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2840,8 +2840,8 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); - cp->avpf_enabled = proxy->avpf_enabled; - cp->avpf_rr_interval = proxy->avpf_rr_interval; + cp->avpf_enabled = linphone_proxy_config_is_avpf_enabled(proxy); + cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy); } /* if no proxy or no identity defined for this proxy, default to primary contact*/ @@ -6438,6 +6438,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->media_encryption=linphone_core_get_media_encryption(lc); params->in_conference=FALSE; params->privacy=LinphonePrivacyDefault; + params->avpf_enabled=TRUE; } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b9a199519..b21ebc7ca 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -936,6 +936,13 @@ LINPHONE_PUBLIC LinphonePrivacyMask linphone_proxy_config_get_privacy(const Linp */ LINPHONE_PUBLIC void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable); +/** + * Indicates whether AVPF/SAVPF is being used for calls using this proxy config. + * @param[in] cfg #LinphoneProxyConfig object + * @return True if AVPF/SAVPF is enabled, false otherwise. + */ +LINPHONE_PUBLIC bool_t linphone_proxy_config_is_avpf_enabled(LinphoneProxyConfig *cfg); + /** * Set the interval between regular RTCP reports when using AVPF/SAVPF. * @param[in] cfg #LinphoneProxyConfig object diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index be8998168..7b38aaed7 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -324,9 +324,11 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c } /*in answering mode, we consider that if we are able to make AVPF/SAVP/SAVPF, then we can do AVP as well*/ -static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote){ - if (local==remote) return TRUE; - if ((remote==SalProtoRtpAvp) && ((local==SalProtoRtpSavp) || (local==SalProtoRtpAvpf) || (local==SalProtoRtpSavpf))) +static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) { + if (local == remote) return TRUE; + if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) + return TRUE; + if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpAvpf) || (local == SalProtoRtpSavpf))) return TRUE; return FALSE; } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 278fd9be6..c85cc33dd 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1551,6 +1551,10 @@ void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable) cfg->avpf_enabled = enable; } +bool_t linphone_proxy_config_is_avpf_enabled(LinphoneProxyConfig *cfg) { + return cfg->avpf_enabled; +} + void linphone_proxy_config_set_avpf_rr_interval(LinphoneProxyConfig *cfg, uint8_t interval) { if (interval > 5) interval = 5; cfg->avpf_rr_interval = interval; From c82463afc1320a9b9046166afd97a2e6a46c0680 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 30 May 2014 14:50:19 +0200 Subject: [PATCH 046/201] Handle offer/answer of rtcp-fb parameters. --- coreapi/offeranswer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 7b38aaed7..2d89edcf7 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -99,6 +99,10 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t if (p2->send_fmtp) payload_type_set_send_fmtp(newp,p2->send_fmtp); newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND; + if (p2->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { + newp->flags |= PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED; + newp->avpf = payload_type_get_avpf_params(p2); + } res=ms_list_append(res,newp); /* we should use the remote numbering even when parsing a response */ payload_type_set_number(newp,remote_number); From 0cd71d6548000a88253b85097d19529ff914d604 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 30 May 2014 16:43:15 +0200 Subject: [PATCH 047/201] Fix issue with rtcp-fb attributes in SDP of response. --- coreapi/bellesip_sal/sal_sdp.c | 41 ++++++++++++++++++++++++++++------ coreapi/linphonecall.c | 27 +++++++++++++++++++++- include/sal/sal.h | 1 - 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 628fc6974..158460377 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -68,6 +68,31 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer)); } +static bool_t is_rtcp_fb_trr_int_the_same_for_all_payloads(const SalStreamDescription *stream, uint8_t *trr_int) { + MSList *pt_it; + bool_t first = TRUE; + for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { + PayloadType *pt = (PayloadType *)pt_it->data; + if (payload_type_get_flags(pt) & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { + if (first == TRUE) { + *trr_int = payload_type_get_avpf_params(pt).trr_interval; + first = FALSE; + } else if (payload_type_get_avpf_params(pt).trr_interval != *trr_int) { + return FALSE; + } + } + } + return TRUE; +} + +static void add_rtcp_fb_trr_int_attribute(belle_sdp_media_description_t *media_desc, int8_t id, uint8_t trr_int) { + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, id); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT); + belle_sdp_rtcp_fb_attribute_set_trr_int(attribute, trr_int); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); +} + static void add_rtcp_fb_nack_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) { belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); belle_sdp_rtcp_fb_attribute_set_id(attribute, id); @@ -80,12 +105,13 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co MSList *pt_it; PayloadType *pt; PayloadTypeAvpfParams avpf_params; - belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + bool_t general_trr_int; + uint8_t trr_int = 0; - belle_sdp_rtcp_fb_attribute_set_id(attribute, -1); - belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT); - belle_sdp_rtcp_fb_attribute_set_trr_int(attribute, md->avpf_rr_interval); - belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); + general_trr_int = is_rtcp_fb_trr_int_the_same_for_all_payloads(stream, &trr_int); + if (general_trr_int == TRUE) { + add_rtcp_fb_trr_int_attribute(media_desc, -1, trr_int); + } for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { pt = (PayloadType *)pt_it->data; @@ -93,7 +119,6 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co /* AVPF/SAVPF profile is used so enable AVPF for all paylad types. */ payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); avpf_params = payload_type_get_avpf_params(pt); - avpf_params.trr_interval = md->avpf_rr_interval; /* Add rtcp-fb attributes according to the AVPF features of the payload types. */ if (avpf_params.features & PAYLOAD_TYPE_AVPF_PLI) { @@ -457,7 +482,9 @@ static void enable_avpf_for_stream(SalStreamDescription *stream) { pt = (PayloadType *)pt_it->data; avpf_params = payload_type_get_avpf_params(pt); payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); - avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; + if (stream->type == SalVideo) { + avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; + } avpf_params.trr_interval = 0; payload_type_set_avpf_params(pt, avpf_params); } diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 63ea19a16..25be65fe4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -281,6 +281,31 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ } } +static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) { + MSList *pt_it; + PayloadType *pt; + PayloadTypeAvpfParams avpf_params; + int i; + + for (i = 0; i < md->n_active_streams; i++) { + for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) { + pt = (PayloadType *)pt_it->data; + if (call->params.avpf_enabled == TRUE) { + payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + avpf_params = payload_type_get_avpf_params(pt); + avpf_params.trr_interval = call->params.avpf_rr_interval; + if (md->streams[i].type == SalVideo) { + avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; + } + } else { + payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); + memset(&avpf_params, 0, sizeof(avpf_params)); + } + payload_type_set_avpf_params(pt, avpf_params); + } + } +} + static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) { LinphoneCore *lc = call->core; int i; @@ -339,7 +364,6 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); md->n_total_streams=(call->biggestdesc ? call->biggestdesc->n_total_streams : 1); - md->avpf_rr_interval = call->params.avpf_rr_interval; strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); @@ -392,6 +416,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * } setup_encryption_keys(call,md); + setup_rtcp_fb(call, md); setup_rtcp_xr(call, md); update_media_description_from_stun(md,&call->ac,&call->vc); diff --git a/include/sal/sal.h b/include/sal/sal.h index b2ce51e22..d5712c09d 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -221,7 +221,6 @@ typedef struct SalMediaDescription{ unsigned int session_ver; unsigned int session_id; SalStreamDir dir; - uint8_t avpf_rr_interval; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; OrtpRtcpXrConfiguration rtcp_xr; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; From d025d8bce0473ce8c52cc6edbe5b3f2b044d29c0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 2 Jun 2014 10:46:21 +0200 Subject: [PATCH 048/201] Remove useless traces. --- coreapi/linphonecall.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 25be65fe4..2bf68fc99 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1462,7 +1462,6 @@ static void rendercb(void *data, const MSPicture *local, const MSPicture *remote #ifdef VIDEO_ENABLED static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const unsigned int event_id, const void *args){ LinphoneCall* call = (LinphoneCall*) user_pointer; - ms_warning("In linphonecall.c: video_stream_event_cb"); switch (event_id) { case MS_VIDEO_DECODER_DECODING_ERRORS: ms_warning("Case is MS_VIDEO_DECODER_DECODING_ERRORS"); @@ -1476,6 +1475,11 @@ static void video_stream_event_cb(void *user_pointer, const MSFilter *f, const u if (call->nextVideoFrameDecoded._func != NULL) call->nextVideoFrameDecoded._func(call, call->nextVideoFrameDecoded._user_data); break; + case MS_VIDEO_DECODER_SEND_PLI: + case MS_VIDEO_DECODER_SEND_SLI: + case MS_VIDEO_DECODER_SEND_RPSI: + /* Handled internally by mediastreamer2. */ + break; default: ms_warning("Unhandled event %i", event_id); break; From 450489e25e1d1c59b4202b68aee77890011604c9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 2 Jun 2014 11:04:08 +0200 Subject: [PATCH 049/201] Update oRTP and ms2 submodules for changes on AVPF. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 5db89bd64..60b83538c 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5db89bd644eb5a692c4b570e06a199943ff6cb26 +Subproject commit 60b83538cd75a57703fd5267d40adc1b556f3245 diff --git a/oRTP b/oRTP index a6c420eed..8c0d0ec22 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit a6c420eedd03c677f5560c3b37bf2b5684c6b0f9 +Subproject commit 8c0d0ec22ad4cac478584da6663be1409b1f9ec1 From a29a93cd765e405472e2344a337ae57a08375aac Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 2 Jun 2014 14:05:30 +0200 Subject: [PATCH 050/201] Add an API to set and retrieve chat messages "app data". This allows clients to store resilient data for each messages --- coreapi/chat.c | 32 +++++++++++++++++++++++ coreapi/linphonecore.h | 8 +++--- coreapi/message_storage.c | 53 +++++++++++++++++++++++++++++++++------ coreapi/private.h | 2 ++ 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index fb2a34159..2ea196b47 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -668,6 +668,36 @@ void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,co message->external_body_url=url?ms_strdup(url):NULL; } + +/** + * Linphone message has an app-specific field that can store a text. The application might want + * to use it for keeping data over restarts, like thumbnail image path. + * @param message #LinphoneChatMessage + * @return the application-specific data or NULL if none has been stored. + */ +const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message){ + return message->appdata; +} + +/** + * Linphone message has an app-specific field that can store a text. The application might want + * to use it for keeping data over restarts, like thumbnail image path. + * + * Invoking this function will attempt to update the message storage to reflect the changeif it is + * enabled. + * + * @param message #LinphoneChatMessage + * @param data the data to store into the message + */ +void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data){ + if( message->appdata ){ + ms_free(message->appdata); + } + message->appdata = data? ms_strdup(data) : NULL; + linphone_chat_message_store_appdata(message); +} + + /** * Set origin of the message *@param message #LinphoneChatMessage obj @@ -805,6 +835,7 @@ LinphoneChatMessage* linphone_chat_message_clone(const LinphoneChatMessage* msg) };*/ LinphoneChatMessage* new_message = linphone_chat_room_create_message(msg->chat_room,msg->message); if (msg->external_body_url) new_message->external_body_url=ms_strdup(msg->external_body_url); + if (msg->appdata) new_message->appdata = ms_strdup(msg->appdata); new_message->cb=msg->cb; new_message->cb_ud=msg->cb_ud; new_message->message_userdata=msg->message_userdata; @@ -831,6 +862,7 @@ static void _linphone_chat_message_destroy(LinphoneChatMessage* msg) { if (msg->op) sal_op_release(msg->op); if (msg->message) ms_free(msg->message); if (msg->external_body_url) ms_free(msg->external_body_url); + if (msg->appdata) ms_free(msg->appdata); if (msg->from) linphone_address_destroy(msg->from); if (msg->to) linphone_address_destroy(msg->to); if (msg->custom_headers) sal_custom_header_free(msg->custom_headers); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b21ebc7ca..c2d565695 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1130,7 +1130,9 @@ LINPHONE_PUBLIC void linphone_chat_message_set_to(LinphoneChatMessage* message, LINPHONE_PUBLIC const LinphoneAddress* linphone_chat_message_get_to(const LinphoneChatMessage* message); LINPHONE_PUBLIC const char* linphone_chat_message_get_external_body_url(const LinphoneChatMessage* message); LINPHONE_PUBLIC void linphone_chat_message_set_external_body_url(LinphoneChatMessage* message,const char* url); -LINPHONE_PUBLIC const char * linphone_chat_message_get_text(const LinphoneChatMessage* message); +LINPHONE_PUBLIC const char* linphone_chat_message_get_appdata(const LinphoneChatMessage* message); +LINPHONE_PUBLIC void linphone_chat_message_set_appdata(LinphoneChatMessage* message, const char* data); +LINPHONE_PUBLIC const char* linphone_chat_message_get_text(const LinphoneChatMessage* message); LINPHONE_PUBLIC time_t linphone_chat_message_get_time(const LinphoneChatMessage* message); LINPHONE_PUBLIC void* linphone_chat_message_get_user_data(const LinphoneChatMessage* message); LINPHONE_PUBLIC void linphone_chat_message_set_user_data(LinphoneChatMessage* message,void*); @@ -1622,7 +1624,7 @@ LINPHONE_PUBLIC bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const * @param[in] lc the #LinphoneCore object * @param[in] pt the #PayloadType to modify. * @param[in] bitrate the IP bitrate in kbit/s. - * @ingroup media_parameters + * @ingroup media_parameters **/ LINPHONE_PUBLIC void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, PayloadType *pt, int bitrate); @@ -1631,7 +1633,7 @@ LINPHONE_PUBLIC void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, Pa * @param[in] lc the #LinphoneCore object * @param[in] pt the #PayloadType to modify. * @return bitrate the IP bitrate in kbit/s, or -1 if an error occured. - * @ingroup media_parameters + * @ingroup media_parameters **/ LINPHONE_PUBLIC int linphone_core_get_payload_type_bitrate(LinphoneCore *lc, const PayloadType *pt); diff --git a/coreapi/message_storage.c b/coreapi/message_storage.c index 81d076fc5..7caf4536b 100644 --- a/coreapi/message_storage.c +++ b/coreapi/message_storage.c @@ -37,6 +37,20 @@ static inline LinphoneChatMessage* get_transient_message(LinphoneChatRoom* cr, u return NULL; } + +/* DB layout: + * | 0 | storage_id + * | 1 | localContact + * | 2 | remoteContact + * | 3 | direction flag + * | 4 | message + * | 5 | time (unused now, used to be string-based timestamp) + * | 6 | read flag + * | 7 | status + * | 8 | external body url + * | 9 | utc timestamp + * | 10 | app data text + */ static void create_chat_message(char **argv, void *data){ LinphoneChatRoom *cr = (LinphoneChatRoom *)data; LinphoneAddress *from; @@ -67,7 +81,8 @@ static void create_chat_message(char **argv, void *data){ new_message->is_read=atoi(argv[6]); new_message->state=atoi(argv[7]); new_message->storage_id=storage_id; - new_message->external_body_url=argv[8]?ms_strdup(argv[8]):NULL; + new_message->external_body_url= argv[8] ? ms_strdup(argv[8]) : NULL; + new_message->appdata = argv[10]? ms_strdup(argv[10]) : NULL; } cr->messages_hist=ms_list_prepend(cr->messages_hist,new_message); } @@ -95,7 +110,7 @@ void linphone_sql_request_message(sqlite3 *db,const char *stmt,LinphoneChatRoom } } -void linphone_sql_request(sqlite3* db,const char *stmt){ +int linphone_sql_request(sqlite3* db,const char *stmt){ char* errmsg=NULL; int ret; ret=sqlite3_exec(db,stmt,NULL,NULL,&errmsg); @@ -103,6 +118,7 @@ void linphone_sql_request(sqlite3* db,const char *stmt){ ms_error("linphone_sql_request: error sqlite3_exec(): %s.\n", errmsg); sqlite3_free(errmsg); } + return ret; } // Process the request to fetch all chat contacts @@ -123,7 +139,7 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ if (lc->db){ char *peer=linphone_address_as_string_uri_only(linphone_chat_room_get_peer_address(msg->chat_room)); char *local_contact=linphone_address_as_string_uri_only(linphone_chat_message_get_local_address(msg)); - char *buf=sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%i);", + char *buf=sqlite3_mprintf("INSERT INTO history VALUES(NULL,%Q,%Q,%i,%Q,%Q,%i,%i,%Q,%i,%Q);", local_contact, peer, msg->dir, @@ -132,7 +148,8 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *msg){ msg->is_read, msg->state, msg->external_body_url, - msg->time); + msg->time, + msg->appdata); linphone_sql_request(lc->db,buf); sqlite3_free(buf); ms_free(local_contact); @@ -159,6 +176,16 @@ void linphone_chat_message_store_state(LinphoneChatMessage *msg){ } } +void linphone_chat_message_store_appdata(LinphoneChatMessage* msg){ + LinphoneCore *lc=msg->chat_room->lc; + if (lc->db){ + char *buf=sqlite3_mprintf("UPDATE history SET appdata=%Q WHERE id=%i;", + msg->appdata,msg->storage_id); + linphone_sql_request(lc->db,buf); + sqlite3_free(buf); + } +} + void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ LinphoneCore *lc=linphone_chat_room_get_lc(cr); int read=1; @@ -302,11 +329,11 @@ static time_t parse_time_from_db( const char* time ){ } -static int migrate_messages(void* data,int argc, char** argv, char** column_names) { +static int migrate_messages_timestamp(void* data,int argc, char** argv, char** column_names) { time_t new_time = parse_time_from_db(argv[1]); if( new_time ){ /* replace 'time' by -1 and set 'utc' to the timestamp */ - char *buf = sqlite3_mprintf("UPDATE history SET utc=%i,time='-1' WHERE id=%i", new_time, atoi(argv[0])); + char *buf = sqlite3_mprintf("UPDATE history SET utc=%i,time='-1' WHERE id=%i;", new_time, atoi(argv[0])); if( buf) { linphone_sql_request((sqlite3*)data, buf); sqlite3_free(buf); @@ -324,7 +351,7 @@ static void linphone_migrate_timestamps(sqlite3* db){ linphone_sql_request(db,"BEGIN TRANSACTION"); - ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1'", migrate_messages, db, &errmsg); + ret = sqlite3_exec(db,"SELECT id,time,direction FROM history WHERE time != '-1';", migrate_messages_timestamp, db, &errmsg); if( ret != SQLITE_OK ){ ms_warning("Error migrating outgoing messages: %s.\n", errmsg); sqlite3_free(errmsg); @@ -359,6 +386,15 @@ void linphone_update_table(sqlite3* db) { // migrate from old text-based timestamps to unix time-based timestamps linphone_migrate_timestamps(db); } + + // new field for app-specific storage + ret=sqlite3_exec(db,"ALTER TABLE history ADD COLUMN appdata TEXT;",NULL,NULL,&errmsg); + if(ret != SQLITE_OK) { + ms_message("Table already up to date: %s.", errmsg); + sqlite3_free(errmsg); + } else { + ms_debug("Table updated successfully for app-specific data."); + } } void linphone_message_storage_init_chat_rooms(LinphoneCore *lc) { @@ -431,6 +467,9 @@ unsigned int linphone_chat_message_store(LinphoneChatMessage *cr){ void linphone_chat_message_store_state(LinphoneChatMessage *cr){ } +void linphone_chat_message_store_appdata(LinphoneChatMessage *msg){ +} + void linphone_chat_room_mark_as_read(LinphoneChatRoom *cr){ } diff --git a/coreapi/private.h b/coreapi/private.h index 589297849..ac93f41b9 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -144,6 +144,7 @@ struct _LinphoneChatMessage { LinphoneChatMessageStateChangedCb cb; void* cb_ud; void* message_userdata; + char* appdata; char* external_body_url; LinphoneAddress *from; LinphoneAddress *to; @@ -821,6 +822,7 @@ sqlite3 * linphone_message_storage_init(); void linphone_message_storage_init_chat_rooms(LinphoneCore *lc); #endif void linphone_chat_message_store_state(LinphoneChatMessage *msg); +void linphone_chat_message_store_appdata(LinphoneChatMessage* msg); void linphone_core_message_storage_init(LinphoneCore *lc); void linphone_core_message_storage_close(LinphoneCore *lc); void linphone_core_message_storage_set_debug(LinphoneCore *lc, bool_t debug); From 038bebdcc9e9ee55987de849c51ae816ca9d4290 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 2 Jun 2014 14:15:49 +0200 Subject: [PATCH 051/201] Add a writable prefix variable for the tester. This will allow mobile unit tests to pass the message storage tests --- tester/liblinphone_tester.h | 2 ++ tester/message_tester.c | 2 +- tester/tester.c | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 152dd6dd3..de781c469 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -46,6 +46,7 @@ extern "C" { #endif extern const char *liblinphone_tester_file_prefix; +extern const char *liblinphone_tester_writable_dir_prefix; extern test_suite_t setup_test_suite; extern test_suite_t register_test_suite; extern test_suite_t call_test_suite; @@ -68,6 +69,7 @@ extern void liblinphone_tester_init(void); extern void liblinphone_tester_uninit(void); extern int liblinphone_tester_run_tests(const char *suite_name, const char *test_name); extern void liblinphone_tester_set_fileprefix(const char* file_prefix); +extern void liblinphone_tester_set_writable_dir_prefix(const char* writable_dir_prefix); #ifdef __cplusplus }; diff --git a/tester/message_tester.c b/tester/message_tester.c index 09872e565..37c79bbfe 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -453,7 +453,7 @@ static void message_storage_migration() { char src_db[256]; char tmp_db[256]; snprintf(src_db,sizeof(src_db), "%s/messages.db", liblinphone_tester_file_prefix); - snprintf(tmp_db,sizeof(tmp_db), "%s/tmp.db", liblinphone_tester_file_prefix); + snprintf(tmp_db,sizeof(tmp_db), "%s/tmp.db", liblinphone_tester_writable_dir_prefix); CU_ASSERT_EQUAL_FATAL(message_tester_copy_file(src_db, tmp_db), 1); diff --git a/tester/tester.c b/tester/tester.c index 3e09be635..da8552ab5 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -49,6 +49,9 @@ const char *liblinphone_tester_file_prefix="./app/native/assets/"; const char *liblinphone_tester_file_prefix="."; #endif +/* TODO: have the same "static" for QNX and windows as above? */ +const char *liblinphone_tester_writable_dir_prefix = "."; + const char *userhostsfile = "tester_hosts"; void liblinphone_tester_clock_start(MSTimeSpec *start){ @@ -326,6 +329,10 @@ void liblinphone_tester_set_fileprefix(const char* file_prefix){ liblinphone_tester_file_prefix = file_prefix; } +void liblinphone_tester_set_writable_dir_prefix(const char* writable_dir_prefix){ + liblinphone_tester_writable_dir_prefix = writable_dir_prefix; +} + void liblinphone_tester_init(void) { add_test_suite(&setup_test_suite); From 9a782d2d0c4113539e3e3c267c8f33106fc73e85 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 2 Jun 2014 17:20:46 +0200 Subject: [PATCH 052/201] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 60b83538c..e8e16ee35 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 60b83538cd75a57703fd5267d40adc1b556f3245 +Subproject commit e8e16ee358ee103ba06fa5d1c99417b612504fe7 diff --git a/oRTP b/oRTP index 8c0d0ec22..eed961c93 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 8c0d0ec22ad4cac478584da6663be1409b1f9ec1 +Subproject commit eed961c934164b41af6d85cf0f40e22c14e97f2c From a5af301c136d25ab72b2100a10d16b9b0acef694 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 2 Jun 2014 17:33:22 +0200 Subject: [PATCH 053/201] fix memory leaks --- coreapi/bellesip_sal/sal_op_call.c | 3 +++ coreapi/linphonecall.c | 40 ++++++++++++++++++------------ coreapi/linphonecore.c | 9 +++++++ coreapi/proxy.c | 28 ++++++++++++--------- 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 2a433b7f6..e2e731510 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -154,6 +154,9 @@ static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { SalReason reason; if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { if (sdp){ + if (op->base.remote_media){ + sal_media_description_unref(op->base.remote_media); + } op->base.remote_media=sal_media_description_new(); sdp_to_media_description(sdp,op->base.remote_media); if (op->base.local_media) sdp_process(op); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2bf68fc99..6861454d1 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -37,6 +37,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mseventqueue.h" #include "mediastreamer2/mssndcard.h" +static void linphone_call_stats_uninit(LinphoneCallStats *stats); + #ifdef VIDEO_ENABLED static MSWebCam *get_nowebcam_device(){ return ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),"StaticImage: Static picture"); @@ -743,7 +745,8 @@ static void linphone_call_set_terminated(LinphoneCall *call){ linphone_call_delete_upnp_session(call); linphone_call_delete_ice_session(call); linphone_core_update_allocated_audio_bandwidth(lc); - + linphone_call_stats_uninit(&call->stats[0]); + linphone_call_stats_uninit(&call->stats[1]); call->owns_call_log=FALSE; linphone_call_log_completed(call); @@ -2697,20 +2700,14 @@ static void report_bandwidth(LinphoneCall *call, MediaStream *as, MediaStream *v } static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ - char temp[256]; + char temp[256]={0}; char *from=NULL; - if(call) - from = linphone_call_get_remote_address_as_string(call); - if (from) - { - snprintf(temp,sizeof(temp),"Remote end %s seems to have disconnected, the call is going to be closed.",from); - ms_free(from); - } - else - { - snprintf(temp,sizeof(temp),"Remote end seems to have disconnected, the call is going to be closed."); - } - ms_message("On call [%p] %s",call,temp); + + from = linphone_call_get_remote_address_as_string(call); + snprintf(temp,sizeof(temp)-1,"Remote end %s seems to have disconnected, the call is going to be closed.",from ? from : ""); + if (from) ms_free(from); + + ms_message("On call [%p]: %s",call,temp); if (lc->vtable.display_warning!=NULL) lc->vtable.display_warning(lc,temp); linphone_core_terminate_call(lc,call); @@ -2818,6 +2815,17 @@ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEve } } +void linphone_call_stats_uninit(LinphoneCallStats *stats){ + if (stats->received_rtcp) { + freemsg(stats->received_rtcp); + stats->received_rtcp=NULL; + } + if (stats->sent_rtcp){ + freemsg(stats->sent_rtcp); + stats->sent_rtcp=NULL; + } +} + void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){ LinphoneCallStats *stats=&call->stats[stream_index]; LinphoneCore *lc=call->core; @@ -2952,8 +2960,8 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat if (state != call->transfer_state) { LinphoneCore* lc = call->core; ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call - ,linphone_call_state_to_string(call->transfer_state) - ,linphone_call_state_to_string(state)); + ,linphone_call_state_to_string(call->transfer_state) + ,linphone_call_state_to_string(state)); call->transfer_state = state; if (lc->vtable.transfer_state_changed) lc->vtable.transfer_state_changed(lc, call, state); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d593a1dbd..609b0bf2a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5890,6 +5890,15 @@ static void linphone_core_uninit(LinphoneCore *lc) } #endif //BUILD_UPNP + if (lc->chatrooms){ + MSList *cr=ms_list_copy(lc->chatrooms); + MSList *elem; + for(elem=cr;elem!=NULL;elem=elem->next){ + linphone_chat_room_destroy((LinphoneChatRoom*)elem->data); + } + ms_list_free(cr); + } + if (lp_config_needs_commit(lc->config)) lp_config_sync(lc->config); lp_config_destroy(lc->config); lc->config = NULL; /* Mark the config as NULL to block further calls */ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index c85cc33dd..50ede392b 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -49,10 +49,7 @@ bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const Linph if (linphone_address_weak_equal(a,b)) { /*also check both transport and uri */ - if (!(linphone_address_is_secure(a) ^ linphone_address_is_secure(b))) { - return linphone_address_get_transport(a) == linphone_address_get_transport(b); - } else - return FALSE; /*secure flag not equals*/ + return linphone_address_is_secure(a) == linphone_address_is_secure(b) && linphone_address_get_transport(a) == linphone_address_get_transport(b); } else return FALSE; /*either username, domain or port ar not equals*/ @@ -61,14 +58,21 @@ bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const Linph bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj) { LinphoneAddress *current_identity=obj->reg_identity?linphone_address_new(obj->reg_identity):NULL; LinphoneAddress *current_proxy=obj->reg_proxy?linphone_address_new(obj->reg_proxy):NULL; + bool_t result=FALSE; + + if (!linphone_proxy_config_address_equal(obj->saved_identity,current_identity)){ + result=TRUE; + goto end; + } + if (!linphone_proxy_config_address_equal(obj->saved_proxy,current_proxy)){ + result=TRUE; + goto end; + } - if (!linphone_proxy_config_address_equal(obj->saved_identity,current_identity)) - return TRUE; - - if (!linphone_proxy_config_address_equal(obj->saved_proxy,current_proxy)) - return TRUE; - - return FALSE; + end: + if (current_identity) linphone_address_destroy(current_identity); + if (current_proxy) linphone_address_destroy(current_proxy); + return result; } void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){ @@ -151,7 +155,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->contact_params) ms_free(obj->contact_params); if (obj->contact_uri_params) ms_free(obj->contact_uri_params); if (obj->saved_proxy!=NULL) linphone_address_destroy(obj->saved_proxy); - if (obj->saved_identity!=NULL) ms_free(obj->saved_identity); + if (obj->saved_identity!=NULL) linphone_address_destroy(obj->saved_identity); ms_free(obj); } From ba5c902bba08be1eec58f2f55ef44efdaa50aa75 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 2 Jun 2014 15:09:08 +0200 Subject: [PATCH 054/201] add option sip_update to linphonerc to disable SIP UPDATE --- coreapi/bellesip_sal/sal_impl.c | 4 ++++ coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_call.c | 18 ++++++++++++------ coreapi/linphonecore.c | 1 + include/sal/sal.h | 3 +++ 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 0212c8a39..c5040be3a 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -451,6 +451,7 @@ Sal * sal_init(){ sal->tls_verify=TRUE; sal->tls_verify_cn=TRUE; sal->refresher_retry_after=60000; /*default value in ms*/ + sal->enable_sip_update=TRUE; return sal; } @@ -999,4 +1000,7 @@ void sal_cancel_timer(Sal *sal, belle_sip_source_t *timer) { belle_sip_main_loop_t *ml = belle_sip_stack_get_main_loop(sal->stack); belle_sip_main_loop_remove_source(ml, timer); } +void sal_enable_sip_update_method(Sal *ctx,bool_t value) { + ctx->enable_sip_update=value; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index b6e18d76a..a20150de2 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -48,6 +48,7 @@ struct Sal{ bool_t auto_contacts; bool_t enable_test_features; bool_t no_initial_route; + bool_t enable_sip_update; /*true by default*/ }; typedef enum SalOpState { diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index e2e731510..59473474f 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -564,6 +564,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } else if (strcmp("MESSAGE",method)==0){ sal_process_incoming_message(op,event); } else if (strcmp("UPDATE",method)==0) { + + /*FIXME jehan: It might be better to silently accept UPDATE which do not modify either the number or the nature of streams*/ + /*rfc 3311 * 5.2 Receiving an UPDATE * ... @@ -571,8 +574,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t * the request with a 504 response. */ resp=sal_op_create_response_from_request(op,req,504); - belle_sip_message_add_header( BELLE_SIP_MESSAGE(resp) - ,belle_sip_header_create( "Warning", "Cannot change the session parameters without prompting the user")); + belle_sip_response_set_reason_phrase(resp,"Cannot change the session parameters without prompting the user"); + /*belle_sip_message_add_header( BELLE_SIP_MESSAGE(resp) + ,belle_sip_header_create( "Warning", "Cannot change the session parameters without prompting the user"));*/ belle_sip_server_transaction_send_response(server_transaction,resp); return; }else{ @@ -610,14 +614,16 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ return 0; } -static belle_sip_header_allow_t *create_allow(){ +static belle_sip_header_allow_t *create_allow(bool_t enable_update){ belle_sip_header_allow_t* header_allow; - header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO, UPDATE"); + char allow [256]; + snprintf(allow,sizeof(allow),"INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO%s",(enable_update?", UPDATE":"")); + header_allow = belle_sip_header_allow_create(allow); return header_allow; } static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { - belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow())); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(create_allow(op->base.root->enable_sip_update))); if (op->base.root->session_expires!=0){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200")); @@ -745,7 +751,7 @@ int sal_call_accept(SalOp*h){ ms_error("Fail to build answer for call"); return -1; } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow())); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_HEADER(create_allow(h->base.root->enable_sip_update))); if (h->base.root->session_expires!=0){ if (h->supports_session_timers) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(response),belle_sip_header_create("Supported", "timer")); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 609b0bf2a..582633783 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -754,6 +754,7 @@ static void sip_config_read(LinphoneCore *lc) linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0)); sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0)); + sal_enable_sip_update_method(lc->sal,lp_config_get_int(lc->config,"sip","sip_update",1)); } static void rtp_config_read(LinphoneCore *lc) diff --git a/include/sal/sal.h b/include/sal/sal.h index d5712c09d..5ec012795 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -519,6 +519,9 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value); void sal_use_tcp_tls_keepalive(Sal *ctx, bool_t enabled); int sal_enable_tunnel(Sal *ctx, void *tunnelclient); void sal_disable_tunnel(Sal *ctx); +/*Default value is true*/ +void sal_enable_sip_update_method(Sal *ctx,bool_t value); + /** * returns keepalive period in ms * 0 desactiaved From 419cac616c5e8b28117da576109fa91222b9ab5f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Jun 2014 12:22:03 +0200 Subject: [PATCH 055/201] Fix memory leak in presence model. --- coreapi/presence.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/coreapi/presence.c b/coreapi/presence.c index fa4b97014..df9271844 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -278,6 +278,7 @@ LinphonePresenceBasicStatus linphone_presence_model_get_basic_status(const Linph int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, LinphonePresenceBasicStatus basic_status) { LinphonePresenceService *service; + int err = 0; if (model == NULL) return -1; @@ -285,8 +286,9 @@ int linphone_presence_model_set_basic_status(LinphonePresenceModel *model, Linph service = linphone_presence_service_new(NULL, basic_status, NULL); if (service == NULL) return -1; - if (linphone_presence_model_add_service(model, service) < 0) return -1; - return 0; + err = linphone_presence_model_add_service(model, service); + linphone_presence_service_unref(service); + return err; } static void presence_service_find_newer_timestamp(LinphonePresenceService *service, time_t *timestamp) { @@ -363,6 +365,7 @@ LinphonePresenceActivity * linphone_presence_model_get_activity(const LinphonePr int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphonePresenceActivityType acttype, const char *description) { LinphonePresenceBasicStatus basic_status = LinphonePresenceBasicStatusOpen; LinphonePresenceActivity *activity; + int err = 0; if (model == NULL) return -1; @@ -383,8 +386,9 @@ int linphone_presence_model_set_activity(LinphonePresenceModel *model, LinphoneP linphone_presence_model_clear_activities(model); activity = linphone_presence_activity_new(acttype, description); if (activity == NULL) return -1; - return linphone_presence_model_add_activity(model, activity); - + err = linphone_presence_model_add_activity(model, activity); + linphone_presence_activity_unref(activity); + return err; } unsigned int linphone_presence_model_get_nb_activities(const LinphonePresenceModel *model) { From 19e8cea754496ad6c86e901e8e431b63d58f7cf4 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Jun 2014 14:43:05 +0200 Subject: [PATCH 056/201] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index e8e16ee35..d2d96d8d9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e8e16ee358ee103ba06fa5d1c99417b612504fe7 +Subproject commit d2d96d8d9c499477c903ac42cb0b77de3dfd56e3 diff --git a/oRTP b/oRTP index eed961c93..aa1ab4e8c 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit eed961c934164b41af6d85cf0f40e22c14e97f2c +Subproject commit aa1ab4e8cd367e51c9706bfe4947a744efe06412 From f11f588729ad8e885bc5aecc2513a5326ccfbb58 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Jun 2014 14:47:55 +0200 Subject: [PATCH 057/201] Add JNI wrapper for AVPF parameters of the proxy config. --- coreapi/linphonecore_jni.cc | 12 ++++++++++++ .../org/linphone/core/LinphoneProxyConfig.java | 18 ++++++++++++++++++ .../linphone/core/LinphoneProxyConfigImpl.java | 18 ++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 4b04cb387..e1f2da371 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2944,6 +2944,18 @@ extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getPrivacy(JNIEnv return linphone_proxy_config_get_privacy((LinphoneProxyConfig *) ptr); } +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_enableAvpf(JNIEnv *env, jobject thiz, jlong ptr, jboolean enable) { + linphone_proxy_config_enable_avpf((LinphoneProxyConfig *)ptr, (bool)enable); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setAvpfRRInterval(JNIEnv *env, jobject thiz, jlong ptr, jint interval) { + linphone_proxy_config_set_avpf_rr_interval((LinphoneProxyConfig *)ptr, (uint8_t)interval); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_getAvpfRRInterval(JNIEnv *env, jobject thiz, jlong ptr) { + return (jint)linphone_proxy_config_get_avpf_rr_interval((LinphoneProxyConfig *)ptr); +} + extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv* env,jobject thiz,jlong ptr) { return (jint)linphone_call_get_duration((LinphoneCall *) ptr); } diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index 0ff1900a3..b695e08f7 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -163,6 +163,24 @@ public interface LinphoneProxyConfig { */ int getPrivacy(); + /** + * Indicates whether AVPF/SAVPF must be used for calls using this proxy config. + * @param enable True to enable AVPF/SAVF, false to disable it. + */ + void enableAvpf(boolean enable); + + /** + * Set the interval between regular RTCP reports when using AVPF/SAVPF. + * @param interval The interval in seconds (between 0 and 5 seconds). + */ + void setAvpfRRInterval(int interval); + + /** + * Get the interval between regular RTCP reports when using AVPF/SAVPF. + * @return The interval in seconds. + */ + int getAvpfRRInterval(); + /** * Set optional contact parameters that will be added to the contact information sent in the registration. diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index a78819075..53db2a526 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -198,6 +198,24 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { return getPrivacy(nativePtr); } + private native void enableAvpf(long nativePtr, boolean enable); + @Override + public void enableAvpf(boolean enable) { + enableAvpf(nativePtr, enable); + } + + private native void setAvpfRRInterval(long nativePtr, int interval); + @Override + public void setAvpfRRInterval(int interval) { + setAvpfRRInterval(nativePtr, interval); + } + + private native int getAvpfRRInterval(long nativePtr); + @Override + public int getAvpfRRInterval() { + return getAvpfRRInterval(nativePtr); + } + private native String getContactParameters(long ptr); @Override public String getContactParameters() { From 2498e3164a59283db6f2125b0a33b885d4c6a2f7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Jun 2014 15:05:37 +0200 Subject: [PATCH 058/201] Initialize avpf parameters of proxy config with default values if available. --- coreapi/proxy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 50ede392b..25696691d 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -112,6 +112,8 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob obj->send_statistics = lc ? lp_config_get_default_int(lc->config, "proxy", "send_statistics", 0) : 0; obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL; obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL; + obj->avpf_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf", 0) : 0; + obj->avpf_rr_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf_rr_interval", 5) : 5; obj->publish_expires=-1; } @@ -1236,7 +1238,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0)); linphone_proxy_config_enable_avpf(cfg, lp_config_get_int(config, key, "avpf", 0)); - linphone_proxy_config_set_avpf_rr_interval(cfg, lp_config_get_int(config, key, "avpf_rr_interval", 0)); + linphone_proxy_config_set_avpf_rr_interval(cfg, lp_config_get_int(config, key, "avpf_rr_interval", 5)); linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0))); linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL))); From 706d9c3ed233509dc7f8e2756fa63e160eb6f0b2 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 3 Jun 2014 17:34:03 +0200 Subject: [PATCH 059/201] fix bug enabling avpf accidentally --- coreapi/linphonecore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 582633783..d858839c7 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6448,7 +6448,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->media_encryption=linphone_core_get_media_encryption(lc); params->in_conference=FALSE; params->privacy=LinphonePrivacyDefault; - params->avpf_enabled=TRUE; + params->avpf_enabled=FALSE; } void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { From ba0a032433d36c72adc8f664e8d9c1bc7ae1c94f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 3 Jun 2014 17:41:44 +0200 Subject: [PATCH 060/201] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index d2d96d8d9..f813759ed 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d2d96d8d9c499477c903ac42cb0b77de3dfd56e3 +Subproject commit f813759edf71ec3d7b1388ae772522df81d1d628 diff --git a/oRTP b/oRTP index aa1ab4e8c..ae0fec375 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit aa1ab4e8cd367e51c9706bfe4947a744efe06412 +Subproject commit ae0fec37506f4cc5de7dfc8ca84321b7ae311bbe From dafdbb34446c7b3c8bfd2a259f5acf12051a3273 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Jun 2014 11:59:50 +0200 Subject: [PATCH 061/201] Correctly handle negotiation of RTP profiles (APV/APVF/SAVP/SAVPF). --- coreapi/linphonecall.c | 18 ++++++++++++------ coreapi/linphonecore.c | 24 +++++++++--------------- coreapi/misc.c | 26 ++++++++++++++++++++++++-- coreapi/offeranswer.c | 10 ++++------ coreapi/private.h | 6 ++++-- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 6861454d1..d80a76920 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -266,8 +266,8 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1); for(i=0; in_active_streams; i++) { - if (is_encryption_active(&md->streams[i]) == TRUE) { - if (keep_srtp_keys && old_md && is_encryption_active(&old_md->streams[i]) == TRUE){ + if (stream_description_has_srtp(&md->streams[i]) == TRUE) { + if (keep_srtp_keys && old_md && stream_description_has_srtp(&old_md->streams[i]) == TRUE){ int j; ms_message("Keeping same crypto keys."); for(j=0;jparams.has_video &= linphone_core_media_description_contains_video_stream(md); + + /* Handle AVPF and SRTP. */ + call->params.avpf_enabled = media_description_has_avpf(md); + if ((media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { + call->params.media_encryption = LinphoneMediaEncryptionSRTP; + } } fpol=linphone_core_get_firewall_policy(call->core); /*create the ice session now if ICE is required*/ @@ -1015,11 +1021,11 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ for (i = 0; i < nb_video_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); if (is_video_active(sd) == TRUE) cp->has_video = TRUE; - if (is_encryption_active(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + if (stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; } for (i = 0; i < nb_audio_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); - if (is_encryption_active(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + if (stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; } if (!cp->has_video){ if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){ @@ -1992,7 +1998,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna call->current_params.record_file=ms_strdup(call->params.record_file); } /* valid local tags are > 0 */ - if (is_encryption_active(stream) == TRUE) { + if (stream_description_has_srtp(stream) == TRUE) { local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio); crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); @@ -2109,7 +2115,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna cam=get_nowebcam_device(); } if (!is_inactive){ - if (is_encryption_active(vstream) == TRUE) { + if (stream_description_has_srtp(vstream) == TRUE) { int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); if (crypto_idx >= 0) { media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index d858839c7..f51453475 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2973,21 +2973,8 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } -bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md){ - int i; - if (md->n_active_streams==0) return FALSE; - - for(i=0;in_active_streams;i++){ - const SalStreamDescription *sd=&md->streams[i]; - if (is_encryption_active(sd) != TRUE){ - return FALSE; - } - } - return TRUE; -} - bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ - return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !linphone_core_media_description_has_srtp(md); + return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !media_description_has_srtp(md); } void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ @@ -3432,7 +3419,14 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, _linphone_call_params_copy(&call->params,params); // There might not be a md if the INVITE was lacking an SDP // In this case we use the parameters as is. - if (md) call->params.has_video &= linphone_core_media_description_contains_video_stream(md); + if (md) { + call->params.has_video &= linphone_core_media_description_contains_video_stream(md); + /* Handle AVPF and SRTP. */ + call->params.avpf_enabled = media_description_has_avpf(md); + if ((media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { + call->params.media_encryption = LinphoneMediaEncryptionSRTP; + } + } linphone_call_make_local_media_description(lc,call); sal_call_set_local_media_description(call->op,call->localdesc); sal_op_set_sent_custom_header(call->op,params->custom_headers); diff --git a/coreapi/misc.c b/coreapi/misc.c index f8fae4210..57ebaa32e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1524,6 +1524,28 @@ bool_t is_video_active(const SalStreamDescription *sd) { return (sd->rtp_port != 0) && (sd->dir != SalStreamInactive); } -bool_t is_encryption_active(const SalStreamDescription *sd) { - return ((sd->proto == SalProtoRtpSavpf) || (sd->proto == SalProtoRtpSavp)); +bool_t stream_description_has_avpf(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf)); +} + +bool_t stream_description_has_srtp(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoRtpSavp) || (sd->proto == SalProtoRtpSavpf)); +} + +bool_t media_description_has_avpf(const SalMediaDescription *md) { + int i; + if (md->n_active_streams == 0) return FALSE; + for (i = 0; i < md->n_active_streams; i++) { + if (stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; +} + +bool_t media_description_has_srtp(const SalMediaDescription *md) { + int i; + if (md->n_active_streams == 0) return FALSE; + for (i = 0; i < md->n_active_streams; i++) { + if (stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 2d89edcf7..aef918b92 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -237,7 +237,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, }else{ result->rtp_port=0; } - if (is_encryption_active(result) == TRUE) { + if (stream_description_has_srtp(result) == TRUE) { /* verify crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) @@ -263,7 +263,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, }else{ result->rtp_port=0; } - if (is_encryption_active(result) == TRUE) { + if (stream_description_has_srtp(result) == TRUE) { /* select crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE)) @@ -330,10 +330,8 @@ static bool_t local_stream_not_already_used(const SalMediaDescription *result, c /*in answering mode, we consider that if we are able to make AVPF/SAVP/SAVPF, then we can do AVP as well*/ static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) { if (local == remote) return TRUE; - if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) - return TRUE; - if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpAvpf) || (local == SalProtoRtpSavpf))) - return TRUE; + if ((remote == SalProtoRtpAvp) && ((local == SalProtoRtpSavp) || (local == SalProtoRtpSavpf))) return TRUE; + if ((remote == SalProtoRtpAvpf) && (local == SalProtoRtpSavpf)) return TRUE; return FALSE; } diff --git a/coreapi/private.h b/coreapi/private.h index ac93f41b9..8de760b85 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -337,7 +337,6 @@ void linphone_call_stats_fill(LinphoneCallStats *stats, MediaStream *ms, OrtpEve void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session); void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md); bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md); -bool_t linphone_core_media_description_has_srtp(const SalMediaDescription *md); void linphone_core_send_initial_subscribes(LinphoneCore *lc); void linphone_core_write_friends_config(LinphoneCore* lc); @@ -393,7 +392,10 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LinphoneCall * is_a_linphone_call(void *user_pointer); LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); bool_t is_video_active(const SalStreamDescription *sd); -bool_t is_encryption_active(const SalStreamDescription *sd); +bool_t stream_description_has_avpf(const SalStreamDescription *sd); +bool_t stream_description_has_srtp(const SalStreamDescription *sd); +bool_t media_description_has_avpf(const SalMediaDescription *md); +bool_t media_description_has_srtp(const SalMediaDescription *md); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); From 85df75c1193e5867b1debd5a5e2465b12b979da1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Jun 2014 14:48:40 +0200 Subject: [PATCH 062/201] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f813759ed..916b6465a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f813759edf71ec3d7b1388ae772522df81d1d628 +Subproject commit 916b6465a2f46883cb2ad17ccc7b8fc210f1a942 From 10c9de93cadcf466dc46101104f77bbdc9273ec3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 4 Jun 2014 15:15:46 +0200 Subject: [PATCH 063/201] implement early media forking at client side --- coreapi/bellesip_sal/sal_op_call.c | 28 ++++++---- coreapi/bellesip_sal/sal_op_impl.c | 32 +++++++----- coreapi/callbacks.c | 64 ++++++++++++++++++++++- mediastreamer2 | 2 +- oRTP | 2 +- tester/call_tester.c | 84 +++++++++++++++++++++++++++++- tester/rcfiles/marie_early_rc | 4 +- 7 files changed, 187 insertions(+), 29 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 59473474f..f8d35e15c 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -152,11 +152,12 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat static void handle_sdp_from_response(SalOp* op,belle_sip_response_t* response) { belle_sdp_session_description_t* sdp; SalReason reason; + if (op->base.remote_media){ + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=NULL; + } if (extract_sdp(BELLE_SIP_MESSAGE(response),&sdp,&reason)==0) { if (sdp){ - if (op->base.remote_media){ - sal_media_description_unref(op->base.remote_media); - } op->base.remote_media=sal_media_description_new(); sdp_to_media_description(sdp,op->base.remote_media); if (op->base.local_media) sdp_process(op); @@ -177,6 +178,7 @@ static int vfu_retry (void *user_data, unsigned int events) { sal_op_unref(op); return BELLE_SIP_STOP; } + static void call_process_response(void *op_base, const belle_sip_response_event_t *event){ SalOp* op = (SalOp*)op_base; belle_sip_request_t* ack; @@ -186,17 +188,17 @@ static void call_process_response(void *op_base, const belle_sip_response_event_ belle_sip_response_t* response=belle_sip_response_event_get_response(event); int code = belle_sip_response_get_status_code(response); belle_sip_header_content_type_t *header_content_type=NULL; - + belle_sip_dialog_t *dialog=belle_sip_response_event_get_dialog(event); if (!client_transaction) { ms_warning("Discarding stateless response [%i] on op [%p]",code,op); return; } req=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); - set_or_update_dialog(op,belle_sip_response_event_get_dialog(event)); - dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; + set_or_update_dialog(op,dialog); + dialog_state=dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL; - ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,op->dialog,belle_sip_dialog_state_to_string(dialog_state)); + ms_message("Op [%p] receiving call response [%i], dialog is [%p] in state [%s]",op,code,dialog,belle_sip_dialog_state_to_string(dialog_state)); switch(dialog_state) { case BELLE_SIP_DIALOG_NULL: @@ -218,14 +220,18 @@ static void call_process_response(void *op_base, const belle_sip_response_event_ if (op->dialog==NULL) call_set_released(op); } } - } else if (code >= 180 && code<300) { - handle_sdp_from_response(op,response); - op->base.root->callbacks.call_ringing(op); + } else if (code >= 180 && code<200) { + belle_sip_response_t *prev_response=belle_sip_object_data_get(BELLE_SIP_OBJECT(dialog),"early_response"); + if (!prev_response || code>belle_sip_response_get_status_code(prev_response)){ + handle_sdp_from_response(op,response); + op->base.root->callbacks.call_ringing(op); + } + belle_sip_object_data_set(BELLE_SIP_OBJECT(dialog),"early_response",belle_sip_object_ref(response),belle_sip_object_unref); } else if (code>=300){ call_set_error(op,response); if (op->dialog==NULL) call_set_released(op); } - } else if ( code >=200 + } else if (code >=200 && code<300 && strcmp("UPDATE",belle_sip_request_get_method(req))==0) { handle_sdp_from_response(op,response); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index a364ce324..e2678dde0 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -560,20 +560,28 @@ const SalErrorInfo *sal_op_get_error_info(const SalOp *op){ return &op->error_info; } +static void unlink_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){ + belle_sip_dialog_set_application_data(dialog,NULL); + sal_op_unref(op); + belle_sip_object_unref(dialog); +} + +static belle_sip_dialog_t *link_op_with_dialog(SalOp *op, belle_sip_dialog_t* dialog){ + belle_sip_dialog_set_application_data(dialog,sal_op_ref(op)); + belle_sip_object_ref(dialog); + return dialog; +} + void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { - /*check if dialog has changed*/ - if (dialog && dialog != op->dialog) { - ms_message("Dialog set from [%p] to [%p] for op [%p]",op->dialog,dialog,op); - /*fixme, shouldn't we cancel previous dialog*/ - if (op->dialog) { - belle_sip_dialog_set_application_data(op->dialog,NULL); - belle_sip_object_unref(op->dialog); - sal_op_unref(op); + if (dialog==NULL) return; + ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]",op,op->dialog,dialog); + if (dialog && op->dialog!=dialog){ + if (op->dialog){ + /*FIXME: shouldn't we delete unconfirmed dialogs ?*/ + unlink_op_with_dialog(op,op->dialog); + op->dialog=NULL; } - op->dialog=dialog; - belle_sip_dialog_set_application_data(op->dialog,op); - sal_op_ref(op); - belle_sip_object_ref(op->dialog); + op->dialog=link_op_with_dialog(op,dialog); } } /*return reffed op*/ diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 64f17f411..9b427506b 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -72,6 +72,32 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c #endif } +static void _clear_early_media_destinations(LinphoneCall *call, MediaStream *ms){ + RtpSession *session=ms->sessions.rtp_session; + rtp_session_clear_aux_remote_addr(session); + if (!call->ice_session) rtp_session_set_symmetric_rtp(session,TRUE);/*restore symmetric rtp if ICE is not used*/ +} + +static void clear_early_media_destinations(LinphoneCall *call){ + if (call->audiostream){ + _clear_early_media_destinations(call,(MediaStream*)call->audiostream); + } + if (call->videostream){ + _clear_early_media_destinations(call,(MediaStream*)call->videostream); + } +} + +static void prepare_early_media_forking(LinphoneCall *call){ + /*we need to disable symmetric rtp otherwise our outgoing streams will be switching permanently between the multiple destinations*/ + if (call->audiostream){ + rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session,FALSE); + } + if (call->videostream){ + rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,FALSE); + } + +} + void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ SalMediaDescription *oldmd=call->resultdesc; bool_t all_muted=FALSE; @@ -98,6 +124,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia call->expect_media_in_ack=FALSE; call->resultdesc=new_md; if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){ + clear_early_media_destinations(call); /* we already started media: check if we really need to restart it*/ if (oldmd){ int md_changed = media_parameters_changed(call, oldmd, new_md); @@ -146,6 +173,9 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if ((call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingEarlyMedia) && !call->params.real_early_media){ all_muted=TRUE; } + if (call->params.real_early_media && call->state==LinphoneCallOutgoingEarlyMedia){ + prepare_early_media_forking(call); + } linphone_call_start_media_streams(call,all_muted,send_ringbacktone); if (call->state==LinphoneCallPausing && call->paused_by_app && ms_list_size(lc->calls)==1){ linphone_core_play_named_tone(lc,LinphoneToneCallOnHold); @@ -276,6 +306,38 @@ static void call_received(SalOp *h){ linphone_core_notify_incoming_call(lc,call); } +static void try_early_media_forking(LinphoneCall *call, SalMediaDescription *md){ + SalMediaDescription *cur_md=call->resultdesc; + int i; + SalStreamDescription *ref_stream,*new_stream; + ms_message("Early media response received from another branch, checking if media can be forked to this new destination."); + + for (i=0;in_active_streams;++i){ + ref_stream=&cur_md->streams[i]; + new_stream=&md->streams[i]; + if (ref_stream->type==new_stream->type && ref_stream->payloads && new_stream->payloads){ + PayloadType *refpt, *newpt; + refpt=(PayloadType*)ref_stream->payloads->data; + newpt=(PayloadType*)new_stream->payloads->data; + if (strcmp(refpt->mime_type,newpt->mime_type)==0 && refpt->clock_rate==newpt->clock_rate + && payload_type_get_number(refpt)==payload_type_get_number(newpt)){ + MediaStream *ms=NULL; + if (ref_stream->type==SalAudio){ + ms=(MediaStream*)call->audiostream; + }else if (ref_stream->type==SalVideo){ + ms=(MediaStream*)call->videostream; + } + if (ms){ + RtpSession *session=ms->sessions.rtp_session; + const char *rtp_addr=new_stream->rtp_addr[0]!='\0' ? new_stream->rtp_addr : md->addr; + const char *rtcp_addr=new_stream->rtcp_addr[0]!='\0' ? new_stream->rtcp_addr : md->addr; + rtp_session_add_aux_remote_addr_full(session,rtp_addr,new_stream->rtp_port,rtcp_addr,new_stream->rtcp_port); + } + } + } + } +} + static void call_ringing(SalOp *h){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(h)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(h); @@ -309,7 +371,7 @@ static void call_ringing(SalOp *h){ /*accept early media */ if (call->audiostream && audio_stream_started(call->audiostream)){ /*streams already started */ - ms_message("Early media already started."); + try_early_media_forking(call,md); return; } if (lc->vtable.show) lc->vtable.show(lc); diff --git a/mediastreamer2 b/mediastreamer2 index 916b6465a..e0ff32eeb 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 916b6465a2f46883cb2ad17ccc7b8fc210f1a942 +Subproject commit e0ff32eebb29671e855cb3cfe9c0ea46929419b4 diff --git a/oRTP b/oRTP index ae0fec375..a9ffd72d7 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit ae0fec37506f4cc5de7dfc8ca84321b7ae311bbe +Subproject commit a9ffd72d73d459e531fad094d18eb18f67870aba diff --git a/tester/call_tester.c b/tester/call_tester.c index 852bc4d68..a59313626 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1200,7 +1200,8 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { if (pauline_called_by_laure && enable_caller_privacy ) CU_ASSERT_EQUAL(linphone_call_params_get_privacy(linphone_call_get_current_params(pauline_called_by_laure)),LinphonePrivacyId); - + /*wait a bit for ACK to be sent*/ + wait_for_list(lcs,NULL,0,1000); linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); @@ -2162,6 +2163,86 @@ static void statistics_sent_at_call_termination() { } #ifdef VIDEO_ENABLED +/*this is call forking with early media managed at client side (not by flexisip server)*/ +static void multiple_early_media(void) { + LinphoneCoreManager* marie1 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* marie2 = linphone_core_manager_new("marie_early_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("pauline_tcp_rc"); + MSList *lcs=NULL; + LinphoneCallParams *params=linphone_core_create_default_call_parameters(pauline->lc); + LinphoneVideoPolicy pol; + LinphoneCall *marie1_call; + LinphoneCall *marie2_call; + LinphoneCall *pauline_call; + int dummy=0; + char ringbackpath[256]; + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); + + pol.automatically_accept=1; + pol.automatically_initiate=1; + + linphone_core_enable_video(pauline->lc,TRUE,TRUE); + + linphone_core_enable_video(marie1->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie1->lc,&pol); + /*use playfile for marie1 to avoid locking on capture card*/ + linphone_core_use_files(marie1->lc,TRUE); + linphone_core_set_play_file(marie1->lc,ringbackpath); + + linphone_core_enable_video(marie2->lc,TRUE,TRUE); + linphone_core_set_video_policy(marie2->lc,&pol); + linphone_core_set_audio_port_range(marie2->lc,40200,40300); + linphone_core_set_video_port_range(marie2->lc,40400,40500); + /*use playfile for marie2 to avoid locking on capture card*/ + linphone_core_use_files(marie2->lc,TRUE); + linphone_core_set_play_file(marie2->lc,ringbackpath); + + + lcs=ms_list_append(lcs,marie1->lc); + lcs=ms_list_append(lcs,marie2->lc); + lcs=ms_list_append(lcs,pauline->lc); + + linphone_call_params_enable_early_media_sending(params,TRUE); + linphone_call_params_enable_video(params,TRUE); + + linphone_core_invite_address_with_params(pauline->lc,marie1->identity,params); + linphone_call_params_destroy(params); + + CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,3000)); + + pauline_call=linphone_core_get_current_call(pauline->lc); + marie1_call=linphone_core_get_current_call(marie1->lc); + marie2_call=linphone_core_get_current_call(marie2->lc); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,6000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70); + + linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,3000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000)); + + /*marie2 should get her call terminated*/ + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); + + /*wait a bit that streams are established*/ + wait_for_list(lcs,&dummy,1,1000); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); + CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); + + ms_list_free(lcs); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + linphone_core_manager_destroy(pauline); +} #endif test_t call_tests[] = { @@ -2196,6 +2277,7 @@ test_t call_tests[] = { { "Call with video added", call_with_video_added }, { "Call with video added (random ports)", call_with_video_added_random_ports }, { "Call with video declined",call_with_declined_video}, + { "Call with multiple early media", multiple_early_media }, #endif { "SRTP ice call", srtp_ice_call }, { "ZRTP ice call", zrtp_ice_call }, diff --git a/tester/rcfiles/marie_early_rc b/tester/rcfiles/marie_early_rc index 844959eae..079a81879 100644 --- a/tester/rcfiles/marie_early_rc +++ b/tester/rcfiles/marie_early_rc @@ -30,8 +30,8 @@ subscribe=0 [rtp] -audio_rtp_port=8070 -video_rtp_port=8072 +audio_rtp_port=18070 +video_rtp_port=19072 [video] display=0 From 31d767f9e393b48956d4c3283c7a219321bb97d3 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 4 Jun 2014 15:17:48 +0200 Subject: [PATCH 064/201] fix compilation error --- coreapi/bellesip_sal/sal_sdp.c | 2 +- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 2 +- coreapi/proxy.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 158460377..650235399 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -581,7 +581,7 @@ static void sdp_parse_rtcp_xr_parameters(const belle_sdp_attribute_t *attribute, } config->stat_summary_enabled = (belle_sdp_rtcp_xr_attribute_has_stat_summary(xr_attr) != 0); if (config->stat_summary_enabled) { - belle_sip_list_t *stat_summary_flag_it; + const belle_sip_list_t *stat_summary_flag_it; for (stat_summary_flag_it = belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(xr_attr); stat_summary_flag_it != NULL; stat_summary_flag_it = stat_summary_flag_it->next ) { const char *flag = (const char *)stat_summary_flag_it->data; if (flag != NULL) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f51453475..468481b42 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2841,7 +2841,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); - cp->avpf_enabled = linphone_proxy_config_is_avpf_enabled(proxy); + cp->avpf_enabled = linphone_proxy_config_avpf_enabled(proxy); cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c2d565695..b7e297e0a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -941,7 +941,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, * @param[in] cfg #LinphoneProxyConfig object * @return True if AVPF/SAVPF is enabled, false otherwise. */ -LINPHONE_PUBLIC bool_t linphone_proxy_config_is_avpf_enabled(LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC bool_t linphone_proxy_config_avpf_enabled(LinphoneProxyConfig *cfg); /** * Set the interval between regular RTCP reports when using AVPF/SAVPF. diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 25696691d..dde023bc4 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1557,7 +1557,7 @@ void linphone_proxy_config_enable_avpf(LinphoneProxyConfig *cfg, bool_t enable) cfg->avpf_enabled = enable; } -bool_t linphone_proxy_config_is_avpf_enabled(LinphoneProxyConfig *cfg) { +bool_t linphone_proxy_config_avpf_enabled(LinphoneProxyConfig *cfg) { return cfg->avpf_enabled; } From 7c3924053be8b5a0b636224c62b37000b45c2543 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 4 Jun 2014 15:41:15 +0200 Subject: [PATCH 065/201] fix API naming --- java/common/org/linphone/core/LinphoneProxyConfig.java | 4 ++++ java/impl/org/linphone/core/LinphoneProxyConfigImpl.java | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index b695e08f7..5c2b8f1e6 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -181,6 +181,10 @@ public interface LinphoneProxyConfig { */ int getAvpfRRInterval(); + /** + * Whether AVPF is used for calls through this proxy. + */ + void avpfEnabled(); /** * Set optional contact parameters that will be added to the contact information sent in the registration. diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java index 53db2a526..aface8e36 100644 --- a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java +++ b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java @@ -203,6 +203,12 @@ class LinphoneProxyConfigImpl implements LinphoneProxyConfig { public void enableAvpf(boolean enable) { enableAvpf(nativePtr, enable); } + + private native boolean avpfEnabled(long nativePtr); + @Override + public boolean avpfEnabled() { + return avpfEnabled(nativePtr); + } private native void setAvpfRRInterval(long nativePtr, int interval); @Override From 22f6228c961a0621bff573e242cd5674a638cebe Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 4 Jun 2014 16:31:29 +0200 Subject: [PATCH 066/201] fix android build --- coreapi/linphonecore_jni.cc | 4 ++++ java/common/org/linphone/core/LinphoneProxyConfig.java | 3 ++- mediastreamer2 | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index e1f2da371..a24d2c589 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2948,6 +2948,10 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_enableAvpf linphone_proxy_config_enable_avpf((LinphoneProxyConfig *)ptr, (bool)enable); } +JNIEXPORT jboolean JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_avpfEnabled(JNIEnv *env, jobject thiz, jlong ptr) { + return linphone_proxy_config_avpf_enabled((LinphoneProxyConfig *)ptr); +} + JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setAvpfRRInterval(JNIEnv *env, jobject thiz, jlong ptr, jint interval) { linphone_proxy_config_set_avpf_rr_interval((LinphoneProxyConfig *)ptr, (uint8_t)interval); } diff --git a/java/common/org/linphone/core/LinphoneProxyConfig.java b/java/common/org/linphone/core/LinphoneProxyConfig.java index 5c2b8f1e6..ded4f9457 100644 --- a/java/common/org/linphone/core/LinphoneProxyConfig.java +++ b/java/common/org/linphone/core/LinphoneProxyConfig.java @@ -183,8 +183,9 @@ public interface LinphoneProxyConfig { /** * Whether AVPF is used for calls through this proxy. + * @return */ - void avpfEnabled(); + boolean avpfEnabled(); /** * Set optional contact parameters that will be added to the contact information sent in the registration. diff --git a/mediastreamer2 b/mediastreamer2 index e0ff32eeb..9c3d93635 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e0ff32eebb29671e855cb3cfe9c0ea46929419b4 +Subproject commit 9c3d936356fe4d4c8a1fa8ca57a47598ece44f81 From 16c47f7b01ccda9517daa7ea0daf41687faa5d3c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 4 Jun 2014 16:40:10 +0200 Subject: [PATCH 067/201] fix linphone_core_update_call() --- coreapi/linphonecore.c | 8 +++++++- tester/register_tester.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 468481b42..6c79d7c71 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3148,7 +3148,13 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho bool_t has_video = FALSE; #endif - if (call->state!=LinphoneCallStreamsRunning){ + switch(call->state){ + case LinphoneCallIncomingEarlyMedia: + case LinphoneCallIncomingReceived: + case LinphoneCallStreamsRunning: + /*these states are allowed for linphone_core_update_call()*/ + break; + default: ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state)); return -1; } diff --git a/tester/register_tester.c b/tester/register_tester.c index 15584fc6f..2e7d330ff 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -681,7 +681,7 @@ static void io_recv_error_late_recovery(){ CU_ASSERT_TRUE(wait_for(lc,NULL,&counters->number_of_LinphoneRegistrationProgress,(register_ok-number_of_udp_proxy)+register_ok /*because 1 udp*/)); CU_ASSERT_EQUAL(counters->number_of_LinphoneRegistrationFailed,0) - CU_ASSERT_TRUE(wait_for_list(lcs=ms_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationFailed,(register_ok-number_of_udp_proxy),sal_get_refresher_retry_after(lc->sal)+1000)); + CU_ASSERT_TRUE(wait_for_list(lcs=ms_list_append(NULL,lc),&counters->number_of_LinphoneRegistrationFailed,(register_ok-number_of_udp_proxy),sal_get_refresher_retry_after(lc->sal)+3000)); sal_set_recv_error(lc->sal, 1); /*reset*/ sal_set_send_error(lc->sal, 0); From e4f764eb5e4a1b87627f971f9426f63ed2fca1d6 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 4 Jun 2014 12:01:36 +0200 Subject: [PATCH 068/201] display error message when invalid argument is given to liblinphone_tester --- tester/liblinphone_tester.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index f47a556b9..7b5043680 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -203,6 +203,7 @@ int main (int argc, char *argv[]) } return 0; } else { + fprintf(stderr, "Unknown option \"%s\"\n", argv[i]); \ helper(argv[0]); return -1; } From e10667c4aed1b49e9e43abf6b490603331069472 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 4 Jun 2014 12:02:43 +0200 Subject: [PATCH 069/201] do not write empty sections in PUBLISH report for quality reporting --- coreapi/quality_reporting.c | 194 ++++++++++++++++++++---------------- coreapi/quality_reporting.h | 3 +- 2 files changed, 109 insertions(+), 88 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 7da31f3d1..370ab97a7 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -30,13 +30,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST - ****************************************************************************/ -/*For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). + *************************************************************************** +For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). moslq == moscq video: what happens if doing stop/resume? one time value: average? worst value? -rlq value: need algo to compute it*/ -/*************************************************************************** +rlq value: need algo to compute it + + - The Session report when session terminates, media change (codec change or a session fork), session terminates due to no media packets being received + - The Interval report SHOULD be used for periodic or interval reporting + *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -73,13 +76,13 @@ static void append_to_buffer_valist(char **buff, size_t *buff_size, size_t *offs /*if we are out of memory, we add some size to buffer*/ if (ret == BELLE_SIP_BUFFER_OVERFLOW) { /*some compilers complain that size_t cannot be formatted as unsigned long, hence forcing cast*/ - ms_warning("Buffer was too small to contain the whole report - doubling its size from %lu to %lu", - (unsigned long)*buff_size, (unsigned long)2 * *buff_size); + ms_warning("Buffer was too small to contain the whole report - increasing its size from %lu to %lu", + (unsigned long)*buff_size, (unsigned long)*buff_size + 2048); *buff_size += 2048; *buff = (char *) ms_realloc(*buff, *buff_size); *offset = prevoffset; - /*recall myself since we did not write all things into the buffer but + /*recall itself since we did not write all things into the buffer but only a part of it*/ append_to_buffer_valist(buff, buff_size, offset, fmt, args); } @@ -98,38 +101,46 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con #define APPEND_IF(buffer, size, offset, fmt, arg, cond) if (cond) append_to_buffer(buffer, size, offset, fmt, arg) #define IF_NUM_IN_RANGE(num, inf, sup, statement) if (inf <= num && num <= sup) statement -static bool_t are_metrics_filled(const reporting_content_metrics_t rm) { - IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, return TRUE); - IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, return TRUE); - IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, return TRUE); - IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, return TRUE); +#define METRICS_PACKET_LOSS 1 << 0 +#define METRICS_QUALITY_ESTIMATES 1 << 1 +#define METRICS_SESSION_DESCRIPTION 1 << 2 +#define METRICS_JITTER_BUFFER 1 << 3 +#define METRICS_DELAY 1 << 4 +#define METRICS_SIGNAL 1 << 5 +static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { + uint8_t ret = 0; + + IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, ret&=METRICS_PACKET_LOSS); + IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, ret&=METRICS_PACKET_LOSS); /*since these are same values than local ones, do not check them*/ - /*if (rm.session_description.payload_type != -1) return TRUE;*/ - /*if (rm.session_description.payload_desc != NULL) return TRUE;*/ - /*if (rm.session_description.sample_rate != -1) return TRUE;*/ - if (rm.session_description.frame_duration != -1) return TRUE; - /*if (rm.session_description.fmtp != NULL) return TRUE;*/ - if (rm.session_description.packet_loss_concealment != -1) return TRUE; + /*if (rm.session_description.payload_type != -1) ret&=METRICS_SESSION_DESCRIPTION;*/ + /*if (rm.session_description.payload_desc != NULL) ret&=METRICS_SESSION_DESCRIPTION;*/ + /*if (rm.session_description.sample_rate != -1) ret&=METRICS_SESSION_DESCRIPTION;*/ + /*if (rm.session_description.fmtp != NULL) ret&=METRICS_SESSION_DESCRIPTION;*/ + if (rm.session_description.frame_duration != -1) ret&=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.packet_loss_concealment != -1) ret&=METRICS_SESSION_DESCRIPTION; - IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, return TRUE); - IF_NUM_IN_RANGE(rm.jitter_buffer.nominal, 0, 65535, return TRUE); - IF_NUM_IN_RANGE(rm.jitter_buffer.max, 0, 65535, return TRUE); - IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, ret&=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.nominal, 0, 65535, ret&=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.max, 0, 65535, ret&=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret&=METRICS_JITTER_BUFFER); - IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, return TRUE); - IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, return TRUE); - IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, return TRUE); - IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, return TRUE); - IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, return TRUE); + IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, ret&=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret&=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret&=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret&=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret&=METRICS_DELAY); - if (rm.signal.level != 127) return TRUE; - if (rm.signal.noise_level != 127) return TRUE; + if (rm.signal.level != 127) ret&=METRICS_SIGNAL; + if (rm.signal.noise_level != 127) ret&=METRICS_SIGNAL; - IF_NUM_IN_RANGE(rm.quality_estimates.rlq, 1, 120, return TRUE); - IF_NUM_IN_RANGE(rm.quality_estimates.rcq, 1, 120, return TRUE); + IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, ret&=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, ret&=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.rlq, 1, 120, ret&=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.rcq, 1, 120, ret&=METRICS_QUALITY_ESTIMATES); - return FALSE; + return ret; } static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) { @@ -140,6 +151,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off /*char * gap_loss_density_str = NULL;*/ char * moslq_str = NULL; char * moscq_str = NULL; + uint8_t available_metrics = are_metrics_filled(rm); if (rm.timestamps.start > 0) timestamps_start_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.start); @@ -156,63 +168,74 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off APPEND_IF_NOT_NULL_STR(buffer, size, offset, " START=%s", timestamps_start_str); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " STOP=%s", timestamps_stop_str); - append_to_buffer(buffer, size, offset, "\r\nSessionDesc:"); - APPEND_IF(buffer, size, offset, " PT=%d", rm.session_description.payload_type, rm.session_description.payload_type != -1); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc); - APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1); - APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1); - /*append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets);*/ - /*append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec);*/ - /*append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec);*/ - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp); - APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state);*/ + if ((available_metrics & METRICS_SESSION_DESCRIPTION) != 0){ + append_to_buffer(buffer, size, offset, "\r\nSessionDesc:"); + APPEND_IF(buffer, size, offset, " PT=%d", rm.session_description.payload_type, rm.session_description.payload_type != -1); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc); + APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1); + APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1); + /*append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets);*/ + /*append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec);*/ + /*append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec);*/ + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp); + APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1); + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state);*/ + } - append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3); - /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15);*/ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); + if ((available_metrics & METRICS_JITTER_BUFFER) != 0){ + append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3); + /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15);*/ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); - append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); + append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); + } - /*append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:");*/ - /* append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density);*/ - /* append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration);*/ - /* APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str);*/ - /* append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration);*/ - /* append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold);*/ + /*append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:");*/ + /* append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density);*/ + /* append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration);*/ + /* APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str);*/ + /* append_to_buffer(buffer, size, offset, " GD=%d", rm.burst_gap_loss.gap_duration);*/ + /* append_to_buffer(buffer, size, offset, " GMIN=%d", rm.burst_gap_loss.min_gap_threshold);*/ - append_to_buffer(buffer, size, offset, "\r\nDelay:"); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay, 0, 65535); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); - /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535);*/ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535); + if ((available_metrics & METRICS_DELAY) != 0){ + append_to_buffer(buffer, size, offset, "\r\nDelay:"); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); + /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535);*/ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535); + } - append_to_buffer(buffer, size, offset, "\r\nSignal:"); - APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127); - APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127); - /*append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss);*/ + if ((available_metrics & METRICS_SIGNAL) != 0){ + append_to_buffer(buffer, size, offset, "\r\nSignal:"); + APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127); + APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127); + /*append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss);*/ + } + + if ((available_metrics & METRICS_QUALITY_ESTIMATES) != 0){ + append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq, 1, 120); + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg);*/ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq, 1, 120); + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg);*/ + /*append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri);*/ + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg);*/ + /*append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro);*/ + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg);*/ + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str); + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg);*/ + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str); + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg);*/ + /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg);*/ + } - append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq, 1, 120); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg);*/ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq, 1, 120); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg);*/ - /*append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri);*/ - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg);*/ - /*append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro);*/ - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg);*/ - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg);*/ - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg);*/ - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg);*/ append_to_buffer(buffer, size, offset, "\r\n"); ms_free(timestamps_start_str); @@ -261,7 +284,7 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); - if (are_metrics_filled(report->remote_metrics)) { + if (are_metrics_filled(report->remote_metrics)!=0) { append_to_buffer(&buffer, &size, &offset, "RemoteMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->remote_metrics); } @@ -329,9 +352,6 @@ static bool_t reporting_enabled(const LinphoneCall * call) { } void linphone_reporting_update_ip(LinphoneCall * call) { - /*This function can be called in two different cases: - - 1) at start when call is starting, remote ip/port info might be the proxy ones to which callee is registered - - 2) later, if we found a direct route between caller and callee with ICE/Stun, ip/port are updated for the direct route access*/ if (! reporting_enabled(call)) return; diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index c182a4210..651daeace 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -135,8 +135,9 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type); /** * Fill IP information about a given call. This function must be called each - * time state is 'LinphoneCallStreamsRunning' since IP might be updated (if we + * time call state is 'LinphoneCallStreamsRunning' since IP might be updated (if we * found a direct route between caller and callee for example). + * When call is starting, remote IP/port might be the proxy ones to which callee is registered * @param call #LinphoneCall object to consider * */ From 1946ccaaef1518af985f3505a8c4d3c94ea3e368 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 4 Jun 2014 16:40:26 +0200 Subject: [PATCH 070/201] Quality reporting: compute average values for instaneous parameters and added custom extension for qos analyzer to get its input/output on each RTCP packet received --- coreapi/linphonecall.c | 18 ++-- coreapi/quality_reporting.c | 199 +++++++++++++++++++++++------------- coreapi/quality_reporting.h | 26 +++-- mediastreamer2 | 2 +- 4 files changed, 156 insertions(+), 89 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d80a76920..c6087580c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -871,7 +871,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const if (cstate==LinphoneCallEnd){ if (call->log->status == LinphoneCallSuccess) - linphone_reporting_publish(call); + linphone_reporting_publish_on_call_term(call); } if (cstate==LinphoneCallReleased){ @@ -1778,7 +1778,7 @@ static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, const LinphoneCallParams *params=&call->params; bool_t will_use_video=linphone_core_media_description_contains_video_stream(md); bool_t forced=FALSE; - + if (desc->bandwidth>0) remote_bw=desc->bandwidth; else if (md->bandwidth>0) { /*case where b=AS is given globally, not per stream*/ @@ -1790,7 +1790,7 @@ static int get_ideal_audio_bw(LinphoneCall *call, const SalMediaDescription *md, }else upload_bw=total_upload_bw; upload_bw=get_min_bandwidth(upload_bw,remote_bw); if (!will_use_video || forced) return upload_bw; - + if (bandwidth_is_greater(upload_bw,512)){ upload_bw=100; }else if (bandwidth_is_greater(upload_bw,256)){ @@ -1823,13 +1823,13 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m LinphoneCore *lc=call->core; int up_ptime=0; const LinphoneCallParams *params=&call->params; - + *used_pt=-1; if (desc->type==SalAudio) bw=get_ideal_audio_bw(call,md,desc); else if (desc->type==SalVideo) bw=get_video_bw(call,md,desc); - + for(elem=desc->payloads;elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; int number; @@ -2293,7 +2293,7 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){ void linphone_call_stop_audio_stream(LinphoneCall *call) { if (call->audiostream!=NULL) { - linphone_reporting_update(call, LINPHONE_CALL_STATS_AUDIO); + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]); rtp_session_unregister_event_queue(call->audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); ortp_ev_queue_flush(call->audiostream_app_evq); @@ -2322,7 +2322,7 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) { void linphone_call_stop_video_stream(LinphoneCall *call) { #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ - linphone_reporting_update(call, LINPHONE_CALL_STATS_VIDEO); + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO); media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]); rtp_session_unregister_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); @@ -2712,7 +2712,7 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){ from = linphone_call_get_remote_address_as_string(call); snprintf(temp,sizeof(temp)-1,"Remote end %s seems to have disconnected, the call is going to be closed.",from ? from : ""); if (from) ms_free(from); - + ms_message("On call [%p]: %s",call,temp); if (lc->vtable.display_warning!=NULL) lc->vtable.display_warning(lc,temp); @@ -2836,7 +2836,7 @@ void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){ LinphoneCallStats *stats=&call->stats[stream_index]; LinphoneCore *lc=call->core; if (stats->updated){ - linphone_reporting_call_stats_updated(call, stream_index); + linphone_reporting_on_rtcp_received(call, stream_index); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, stats); stats->updated = 0; diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 370ab97a7..50c283cf0 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -34,11 +34,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). moslq == moscq video: what happens if doing stop/resume? -one time value: average? worst value? rlq value: need algo to compute it - The Session report when session terminates, media change (codec change or a session fork), session terminates due to no media packets being received - The Interval report SHOULD be used for periodic or interval reporting + + -> avg values + -> interval report + -> custom metrics *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -95,6 +98,19 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con va_end(args); } +static void reset_avg_metrics(reporting_session_report_t * rm){ + int i; + reporting_content_metrics_t * metrics[2] = {&rm->local_metrics, &rm->remote_metrics}; + + for (i = 0; i < 2; i++) { + metrics[i]->rtcp_xr_count = 0; + metrics[i]->jitter_buffer.nominal = 0; + metrics[i]->jitter_buffer.max = 0; + + metrics[i]->delay.round_trip_delay = 0; + metrics[i]->delay.symm_one_way_delay = 0; + } +} #define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) #define APPEND_IF_NUM_IN_RANGE(buffer, size, offset, fmt, arg, inf, sup) if (inf <= arg && arg <= sup) append_to_buffer(buffer, size, offset, fmt, arg) @@ -107,38 +123,45 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con #define METRICS_JITTER_BUFFER 1 << 3 #define METRICS_DELAY 1 << 4 #define METRICS_SIGNAL 1 << 5 +#define METRICS_ADAPTIVE_ALGORITHM 1 << 6 + static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { uint8_t ret = 0; - IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, ret&=METRICS_PACKET_LOSS); - IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, ret&=METRICS_PACKET_LOSS); + IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, ret|=METRICS_PACKET_LOSS); + IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, ret|=METRICS_PACKET_LOSS); /*since these are same values than local ones, do not check them*/ - /*if (rm.session_description.payload_type != -1) ret&=METRICS_SESSION_DESCRIPTION;*/ - /*if (rm.session_description.payload_desc != NULL) ret&=METRICS_SESSION_DESCRIPTION;*/ - /*if (rm.session_description.sample_rate != -1) ret&=METRICS_SESSION_DESCRIPTION;*/ - /*if (rm.session_description.fmtp != NULL) ret&=METRICS_SESSION_DESCRIPTION;*/ - if (rm.session_description.frame_duration != -1) ret&=METRICS_SESSION_DESCRIPTION; - if (rm.session_description.packet_loss_concealment != -1) ret&=METRICS_SESSION_DESCRIPTION; + /*if (rm.session_description.payload_type != -1) ret|=METRICS_SESSION_DESCRIPTION;*/ + /*if (rm.session_description.payload_desc != NULL) ret|=METRICS_SESSION_DESCRIPTION;*/ + /*if (rm.session_description.sample_rate != -1) ret|=METRICS_SESSION_DESCRIPTION;*/ + /*if (rm.session_description.fmtp != NULL) ret|=METRICS_SESSION_DESCRIPTION;*/ + if (rm.session_description.frame_duration != -1) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.packet_loss_concealment != -1) ret|=METRICS_SESSION_DESCRIPTION; - IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, ret&=METRICS_JITTER_BUFFER); - IF_NUM_IN_RANGE(rm.jitter_buffer.nominal, 0, 65535, ret&=METRICS_JITTER_BUFFER); - IF_NUM_IN_RANGE(rm.jitter_buffer.max, 0, 65535, ret&=METRICS_JITTER_BUFFER); - IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret&=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, ret|=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret|=METRICS_JITTER_BUFFER); - IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, ret&=METRICS_DELAY); - IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret&=METRICS_DELAY); - IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret&=METRICS_DELAY); - IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret&=METRICS_DELAY); - IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret&=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret|=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret|=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret|=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret|=METRICS_DELAY); - if (rm.signal.level != 127) ret&=METRICS_SIGNAL; - if (rm.signal.noise_level != 127) ret&=METRICS_SIGNAL; + if (rm.signal.level != 127) ret|=METRICS_SIGNAL; + if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; - IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, ret&=METRICS_QUALITY_ESTIMATES); - IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, ret&=METRICS_QUALITY_ESTIMATES); - IF_NUM_IN_RANGE(rm.quality_estimates.rlq, 1, 120, ret&=METRICS_QUALITY_ESTIMATES); - IF_NUM_IN_RANGE(rm.quality_estimates.rcq, 1, 120, ret&=METRICS_QUALITY_ESTIMATES); + if (rm.adaptive_algorithm.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; + if (rm.adaptive_algorithm.output!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; + + if (rm.rtcp_xr_count>0){ + IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); + IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, ret|=METRICS_DELAY); + IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.rlq/rm.rtcp_xr_count, 1, 120, ret|=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.rcq/rm.rtcp_xr_count, 1, 120, ret|=METRICS_QUALITY_ESTIMATES); + } return ret; } @@ -158,12 +181,6 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off if (rm.timestamps.stop > 0) timestamps_stop_str = linphone_timestamp_to_rfc3339_string(rm.timestamps.stop); - IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256)); - IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate / 256)); - /*IF_NUM_IN_RANGE(rm.burst_gap_loss.gap_loss_density, 0, 10, gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density));*/ - IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq)); - IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq)); - append_to_buffer(buffer, size, offset, "Timestamps:"); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " START=%s", timestamps_start_str); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " STOP=%s", timestamps_stop_str); @@ -186,16 +203,22 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3); /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15);*/ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal, 0, 65535); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max, 0, 65535); + if (rm.rtcp_xr_count){ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535); + } APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBX=%d", rm.jitter_buffer.abs_max, 0, 65535); append_to_buffer(buffer, size, offset, "\r\nPacketLoss:"); + IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, network_packet_loss_rate_str = float_to_one_decimal_string(rm.packet_loss.network_packet_loss_rate / 256)); + IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, jitter_buffer_discard_rate_str = float_to_one_decimal_string(rm.packet_loss.jitter_buffer_discard_rate / 256)); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " NLR=%s", network_packet_loss_rate_str); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " JDR=%s", jitter_buffer_discard_rate_str); } /*append_to_buffer(buffer, size, offset, "\r\nBurstGapLoss:");*/ + /*IF_NUM_IN_RANGE(rm.burst_gap_loss.gap_loss_density, 0, 10, gap_loss_density_str = float_to_one_decimal_string(rm.burst_gap_loss.gap_loss_density));*/ /* append_to_buffer(buffer, size, offset, " BLD=%d", rm.burst_gap_loss.burst_loss_density);*/ /* append_to_buffer(buffer, size, offset, " BD=%d", rm.burst_gap_loss.burst_duration);*/ /* APPEND_IF_NOT_NULL_STR(buffer, size, offset, " GLD=%s", gap_loss_density_str);*/ @@ -204,7 +227,9 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off if ((available_metrics & METRICS_DELAY) != 0){ append_to_buffer(buffer, size, offset, "\r\nDelay:"); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay, 0, 65535); + if (rm.rtcp_xr_count){ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay/rm.rtcp_xr_count, 0, 65535); + } APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535);*/ APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535); @@ -219,11 +244,15 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off /*append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss);*/ } + /*if quality estimates metrics are available, rtcp_xr_count should be always not null*/ if ((available_metrics & METRICS_QUALITY_ESTIMATES) != 0){ + IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq)); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq)); + append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq, 1, 120); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq/rm.rtcp_xr_count, 1, 120); /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg);*/ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq, 1, 120); + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq/rm.rtcp_xr_count, 1, 120); /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg);*/ /*append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri);*/ /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg);*/ @@ -236,6 +265,12 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg);*/ } + if ((available_metrics & METRICS_ADAPTIVE_ALGORITHM) != 0){ + append_to_buffer(buffer, size, offset, "\r\nAdaptiveAlg:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.adaptive_algorithm.input); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT=%s", rm.adaptive_algorithm.output); + } + append_to_buffer(buffer, size, offset, "\r\n"); ms_free(timestamps_start_str); @@ -247,7 +282,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off ms_free(moscq_str); } -static void reporting_publish(const LinphoneCall* call, const reporting_session_report_t * report) { +static void send_report(const LinphoneCall* call, reporting_session_report_t * report) { LinphoneContent content = {0}; LinphoneAddress *addr; int expires = -1; @@ -264,6 +299,12 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ return; } + addr = linphone_address_new(call->dest_proxy->statistics_collector); + if (addr == NULL) { + ms_warning("Asked to submit reporting statistics but no collector address found"); + return; + } + buffer = (char *) ms_malloc(size); content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); @@ -291,17 +332,12 @@ static void reporting_publish(const LinphoneCall* call, const reporting_session_ APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); content.data = buffer; - content.size = strlen((char*)content.data); + content.size = strlen(buffer); + linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); + linphone_address_destroy(addr); - addr = linphone_address_new(call->dest_proxy->statistics_collector); - if (addr != NULL) { - linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); - linphone_address_destroy(addr); - } else { - ms_warning("Asked to submit reporting statistics but no collector address found"); - } - + reset_avg_metrics(report); linphone_content_uninit(&content); } @@ -321,7 +357,7 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc return NULL; } -static void reporting_update_ip(LinphoneCall * call, int stats_type) { +static void update_ip(LinphoneCall * call, int stats_type) { SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; if (call->log->reports[stats_type] != NULL) { const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); @@ -347,29 +383,39 @@ static void reporting_update_ip(LinphoneCall * call, int stats_type) { } } -static bool_t reporting_enabled(const LinphoneCall * call) { +static bool_t is_reporting_enabled(const LinphoneCall * call) { return (call->dest_proxy != NULL && linphone_proxy_config_send_statistics_enabled(call->dest_proxy)); } +static void qos_analyser_on_action_suggested(void *user_data, const char * input, const char * output){ + reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; + char * newstr = NULL; + newstr = ms_strdup_printf("%s%s;", metrics->adaptive_algorithm.input?metrics->adaptive_algorithm.input:"", input); + STR_REASSIGN(metrics->adaptive_algorithm.input, newstr) + + newstr = ms_strdup_printf("%s%s;", metrics->adaptive_algorithm.output?metrics->adaptive_algorithm.output:"", output); + STR_REASSIGN(metrics->adaptive_algorithm.output, newstr) +} + void linphone_reporting_update_ip(LinphoneCall * call) { - if (! reporting_enabled(call)) + if (! is_reporting_enabled(call)) return; - reporting_update_ip(call, LINPHONE_CALL_STATS_AUDIO); + update_ip(call, LINPHONE_CALL_STATS_AUDIO); if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { - reporting_update_ip(call, LINPHONE_CALL_STATS_VIDEO); + update_ip(call, LINPHONE_CALL_STATS_VIDEO); } } -void linphone_reporting_update(LinphoneCall * call, int stats_type) { +void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { reporting_session_report_t * report = call->log->reports[stats_type]; MediaStream * stream = NULL; const PayloadType * local_payload = NULL; const PayloadType * remote_payload = NULL; const LinphoneCallParams * current_params = linphone_call_get_current_params(call); - if (! reporting_enabled(call)) + if (! is_reporting_enabled(call)) return; STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); @@ -430,14 +476,14 @@ void linphone_reporting_update(LinphoneCall * call, int stats_type) { } } -void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { +void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->log->reports[stats_type]; reporting_content_metrics_t * metrics = NULL; LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; - if (! reporting_enabled(call)) + if (! is_reporting_enabled(call)) return; if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { @@ -451,24 +497,33 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { block = stats.sent_rtcp; } } + + ms_qos_analyser_set_on_action_suggested( + ms_bitrate_controller_get_qos_analyser(call->audiostream->ms.rc), + qos_analyser_on_action_suggested, + &report->local_metrics); + if (block != NULL) { switch (rtcp_XR_get_block_type(block)) { case RTCP_XR_VOIP_METRICS: { - uint8_t config; + uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block); - metrics->quality_estimates.rcq = rtcp_XR_voip_metrics_get_r_factor(block); - metrics->quality_estimates.moslq = rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; - metrics->quality_estimates.moscq = rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + metrics->rtcp_xr_count++; - metrics->jitter_buffer.nominal = rtcp_XR_voip_metrics_get_jb_nominal(block); - metrics->jitter_buffer.max = rtcp_XR_voip_metrics_get_jb_maximum(block); + metrics->quality_estimates.rcq += rtcp_XR_voip_metrics_get_r_factor(block); + metrics->quality_estimates.moslq += rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; + metrics->quality_estimates.moscq += rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + + metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block); + metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block); metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block); + metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block); metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block); - config = rtcp_XR_voip_metrics_get_rx_config(block); metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; - metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; + + metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block); break; } default: { break; @@ -477,26 +532,28 @@ void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type) { } } -void linphone_reporting_publish(LinphoneCall* call) { - if (! reporting_enabled(call)) +void linphone_reporting_publish_on_call_term(LinphoneCall* call) { + if (! is_reporting_enabled(call)) return; if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { - reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]); + send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]); } if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { - reporting_publish(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO]); + send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO]); } } reporting_session_report_t * linphone_reporting_new() { int i; reporting_session_report_t * rm = ms_new0(reporting_session_report_t,1); - reporting_content_metrics_t * metrics[2] = {&rm->local_metrics, &rm->remote_metrics}; + + memset(rm, 0, sizeof(reporting_session_report_t)); + for (i = 0; i < 2; i++) { metrics[i]->session_description.payload_type = -1; metrics[i]->session_description.sample_rate = -1; @@ -509,20 +566,18 @@ reporting_session_report_t * linphone_reporting_new() { metrics[i]->jitter_buffer.adaptive = -1; /*metrics[i]->jitter_buffer.rate = -1;*/ - metrics[i]->jitter_buffer.nominal = -1; - metrics[i]->jitter_buffer.max = -1; metrics[i]->jitter_buffer.abs_max = -1; - metrics[i]->delay.round_trip_delay = -1; metrics[i]->delay.end_system_delay = -1; /*metrics[i]->delay.one_way_delay = -1;*/ - metrics[i]->delay.symm_one_way_delay = -1; metrics[i]->delay.interarrival_jitter = -1; metrics[i]->delay.mean_abs_jitter = -1; metrics[i]->signal.level = 127; metrics[i]->signal.noise_level = 127; } + + reset_avg_metrics(rm); return rm; } @@ -542,6 +597,8 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp); if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc); + if (report->local_metrics.adaptive_algorithm.input != NULL) ms_free(report->local_metrics.adaptive_algorithm.input); + if (report->local_metrics.adaptive_algorithm.output != NULL) ms_free(report->local_metrics.adaptive_algorithm.output); ms_free(report); } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 651daeace..44704c32a 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -28,7 +28,7 @@ extern "C"{ /** - * Linphone quality report sub object storing address related information (ip / port / MAC). + * Linphone quality report sub object storing address related information (IP/port/MAC). */ typedef struct reporting_addr { char * ip; @@ -60,15 +60,15 @@ typedef struct reporting_content_metrics { // jitter buffet - optional struct { int adaptive; // constant - int nominal; // no may vary during the call <- average? worst score? - int max; // no may vary during the call <- average? + int nominal; // average + int max; // average int abs_max; // constant } jitter_buffer; // packet loss - optional struct { - float network_packet_loss_rate; - float jitter_buffer_discard_rate; + float network_packet_loss_rate; // average + float jitter_buffer_discard_rate; // average } packet_loss; // delay - optional @@ -93,6 +93,16 @@ typedef struct reporting_content_metrics { float moslq; // no - vary or avg - voip metrics - in [0..4.9] float moscq; // no - vary or avg - voip metrics - in [0..4.9] } quality_estimates; + + // adaptive algorithm - custom extension + struct { + char* input; + char* output; + } adaptive_algorithm; + + // for internal processing + uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5) + } reporting_content_metrics_t; @@ -131,7 +141,7 @@ void linphone_reporting_destroy(reporting_session_report_t * report); * @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO) * */ -void linphone_reporting_update(LinphoneCall * call, int stats_type); +void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type); /** * Fill IP information about a given call. This function must be called each @@ -148,7 +158,7 @@ void linphone_reporting_update_ip(LinphoneCall * call); * @param call #LinphoneCall object to consider * */ -void linphone_reporting_publish(LinphoneCall* call); +void linphone_reporting_publish_on_call_term(LinphoneCall* call); /** * Update publish report data with fresh RTCP stats, if needed. @@ -156,7 +166,7 @@ void linphone_reporting_publish(LinphoneCall* call); * @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO) * */ -void linphone_reporting_call_stats_updated(LinphoneCall *call, int stats_type); +void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type); #ifdef __cplusplus } diff --git a/mediastreamer2 b/mediastreamer2 index 9c3d93635..8ea457fa6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9c3d936356fe4d4c8a1fa8ca57a47598ece44f81 +Subproject commit 8ea457fa65e32c3c943e0bedea6fbdbdc18f7156 From 52d8d8c59af7877ce1e1f6a95628aac9b5030fc8 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 4 Jun 2014 18:10:21 +0200 Subject: [PATCH 071/201] Show RTP profile in call statistics dialog. --- coreapi/linphonecall.c | 6 +- coreapi/linphonecore.h | 7 ++ gtk/call_statistics.ui | 227 ++++++++++++++++++++--------------------- gtk/incall_view.c | 7 +- 4 files changed, 128 insertions(+), 119 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c6087580c..aa1786891 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -337,7 +337,7 @@ void linphone_call_increment_local_media_description(LinphoneCall *call){ md->session_ver++; } -static SalMediaProto get_proto_from_call_params(LinphoneCallParams *params) { +static SalMediaProto get_proto_from_call_params(const LinphoneCallParams *params) { if ((params->media_encryption == LinphoneMediaEncryptionSRTP) && params->avpf_enabled) return SalProtoRtpSavpf; if (params->media_encryption == LinphoneMediaEncryptionSRTP) return SalProtoRtpSavp; if (params->avpf_enabled) return SalProtoRtpAvpf; @@ -1280,6 +1280,10 @@ MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParam return cp->recv_vsize; } +const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp) { + return sal_media_proto_to_string(get_proto_from_call_params(cp)); +} + /** * @ingroup call_control * Use to know if this call has been configured in low bandwidth mode. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b7e297e0a..60813272c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -429,6 +429,13 @@ LINPHONE_PUBLIC MSVideoSize linphone_call_params_get_sent_video_size(const Linph */ LINPHONE_PUBLIC MSVideoSize linphone_call_params_get_received_video_size(const LinphoneCallParams *cp); +/** + * Gets the RTP profile being used. + * @param[in] cp #LinphoneCallParams object + * @returns The RTP profile. + */ +LINPHONE_PUBLIC const char * linphone_call_params_get_rtp_profile(const LinphoneCallParams *cp); + /* * Note for developers: this enum must be kept synchronized with the SalPrivacy enum declared in sal.h diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui index 2412d9793..d53c93a1f 100644 --- a/gtk/call_statistics.ui +++ b/gtk/call_statistics.ui @@ -1,115 +1,67 @@ - + - False 5 Call statistics dialog - + True - False 2 - - - True - False - end - - - - - - gtk-close - True - True - True - False - True - - - False - False - 1 - - - - - False - True - end - 0 - - True - False 0 none True - False 12 True - False - 9 + 10 2 True True - False Audio codec - + 1 + 2 + True - False Video codec - 1 - 2 - + 2 + 3 + True - False Audio IP bandwidth usage - 2 - 3 - + 3 + 4 + True - False - - - 1 - 2 - - - - - True - False 1 @@ -119,9 +71,8 @@ - + True - False 1 @@ -130,22 +81,53 @@ 3 + + + True + + + 1 + 2 + 3 + 4 + + True - False Audio Media connectivity - 4 - 5 - + 5 + 6 + True - False + + + 1 + 2 + 5 + 6 + + + + + True + Video IP bandwidth usage + + + 4 + 5 + + + + + + True 1 @@ -154,120 +136,106 @@ 5 - - - True - False - Video IP bandwidth usage - - - 3 - 4 - - - - - - True - False - - - 1 - 2 - 3 - 4 - - True - False Video Media connectivity - 5 - 6 + 6 + 7 True - False 1 2 - 5 - 6 + 6 + 7 True - False Round trip time - 6 - 7 + 7 + 8 True - False 1 2 - 6 - 7 + 7 + 8 True - False Video resolution received - 7 - 8 + 8 + 9 True - False 1 2 - 7 - 8 + 8 + 9 True - False Video resolution sent - 8 - 9 + 9 + 10 True - False 1 2 - 8 - 9 + 9 + 10 + + + + + True + RTP profile + + + + + + + + True + + + 1 + 2 @@ -277,7 +245,6 @@ True - False <b>Call statistics and information</b> True @@ -289,6 +256,34 @@ 1 + + + True + end + + + + + + gtk-close + True + True + True + True + + + False + False + 1 + + + + + False + end + 0 + + diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 8ab6309f6..382e27746 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -258,9 +258,12 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ gboolean has_video=linphone_call_params_video_enabled(linphone_call_get_current_params(call)); MSVideoSize size_received = linphone_call_params_get_received_video_size(linphone_call_get_current_params(call)); MSVideoSize size_sent = linphone_call_params_get_sent_video_size(linphone_call_get_current_params(call)); - gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"), + const char *rtp_profile = linphone_call_params_get_rtp_profile(linphone_call_get_current_params(call)); + gchar *tmp = g_strdup_printf("%s", rtp_profile); + gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"rtp_profile")),tmp); + g_free(tmp); + tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"), as->download_bandwidth,as->upload_bandwidth); - gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp); g_free(tmp); if (has_video){ From fb61e1cf03d07e651bb82a23a61ada68f2680c87 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Jun 2014 10:48:24 +0200 Subject: [PATCH 072/201] Fix AVPF status in the call current params. --- coreapi/linphonecall.c | 56 ++++++++++++++++++++++++++++++++++++------ mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index aa1786891..af4ab7b57 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -96,27 +96,63 @@ bool_t linphone_call_get_authentication_token_verified(LinphoneCall *call){ return call->auth_token_verified; } -static bool_t linphone_call_are_all_streams_encrypted(LinphoneCall *call) { +static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) { int number_of_encrypted_stream = 0; int number_of_active_stream = 0; if (call) { if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { number_of_active_stream++; - if(media_stream_is_secured((MediaStream *)call->audiostream)) + if(media_stream_secured((MediaStream *)call->audiostream)) number_of_encrypted_stream++; } if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { number_of_active_stream++; - if (media_stream_is_secured((MediaStream *)call->videostream)) + if (media_stream_secured((MediaStream *)call->videostream)) number_of_encrypted_stream++; } } return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream; } +static bool_t linphone_call_all_streams_avpf_enabled(const LinphoneCall *call) { + int nb_active_streams = 0; + int nb_avpf_enabled_streams = 0; + if (call) { + if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { + nb_active_streams++; + if (media_stream_avpf_enabled((MediaStream *)call->audiostream)) + nb_avpf_enabled_streams++; + } + if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + nb_active_streams++; + if (media_stream_avpf_enabled((MediaStream *)call->videostream)) + nb_avpf_enabled_streams++; + } + } + return ((nb_active_streams > 0) && (nb_active_streams == nb_avpf_enabled_streams)); +} + +static uint8_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) { + uint8_t rr_interval = 0; + uint8_t stream_rr_interval; + if (call) { + if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { + stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->audiostream); + if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval; + } + if (call->videostream && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->videostream); + if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval; + } + } else { + rr_interval = 5; + } + return rr_interval; +} + static void propagate_encryption_changed(LinphoneCall *call){ LinphoneCore *lc=call->core; - if (!linphone_call_are_all_streams_encrypted(call)) { + if (!linphone_call_all_streams_encrypted(call)) { ms_message("Some streams are not encrypted"); call->current_params.media_encryption=LinphoneMediaEncryptionNone; if (lc->vtable.call_encryption_changed) @@ -988,7 +1024,7 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ } #endif - if (linphone_call_are_all_streams_encrypted(call)) { + if (linphone_call_all_streams_encrypted(call)) { if (linphone_call_get_authentication_token(call)) { call->current_params.media_encryption=LinphoneMediaEncryptionZRTP; } else { @@ -997,6 +1033,12 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ } else { call->current_params.media_encryption=LinphoneMediaEncryptionNone; } + call->current_params.avpf_enabled = linphone_call_all_streams_avpf_enabled(call); + if (call->current_params.avpf_enabled == TRUE) { + call->current_params.avpf_rr_interval = linphone_call_get_avpf_rr_interval(call); + } else { + call->current_params.avpf_rr_interval = 0; + } return &call->current_params; } @@ -2189,14 +2231,14 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut params.zid_file=lc->zrtp_secrets_cache; audio_stream_enable_zrtp(call->audiostream,¶ms); #if VIDEO_ENABLED - if (media_stream_is_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { + if (media_stream_secured((MediaStream *)call->audiostream) && media_stream_get_state((MediaStream *)call->videostream) == MSStreamStarted) { /*audio stream is already encrypted and video stream is active*/ memset(¶ms,0,sizeof(OrtpZrtpParams)); video_stream_enable_zrtp(call->videostream,call->audiostream,¶ms); } #endif }else{ - call->current_params.media_encryption=linphone_call_are_all_streams_encrypted(call) ? + call->current_params.media_encryption=linphone_call_all_streams_encrypted(call) ? LinphoneMediaEncryptionSRTP : LinphoneMediaEncryptionNone; } diff --git a/mediastreamer2 b/mediastreamer2 index 8ea457fa6..406505ddd 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8ea457fa65e32c3c943e0bedea6fbdbdc18f7156 +Subproject commit 406505dddac08300d937dd5f0f1fd3e701267287 diff --git a/oRTP b/oRTP index a9ffd72d7..30e4d5b1a 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit a9ffd72d73d459e531fad094d18eb18f67870aba +Subproject commit 30e4d5b1abf41c7d96825a3ca194eb47b5a45c1b From 3bf28e79af7946fca345207ae32bce1c4f10f5b2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Jun 2014 10:53:36 +0200 Subject: [PATCH 073/201] Do not include rtcp-xr and rtcp-fb attributes for inactive medias in the SDP. --- coreapi/bellesip_sal/sal_sdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 650235399..268fbc480 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -266,11 +266,11 @@ static void stream_description_to_sdp ( belle_sdp_session_description_t *session } } - if ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf)) { + if ((rtp_port != 0) && ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf))) { add_rtcp_fb_attributes(media_desc, md, stream); } - if (stream->rtcp_xr.enabled == TRUE) { + if ((rtp_port != 0) && (stream->rtcp_xr.enabled == TRUE)) { char sastr[1024] = {0}; char mastr[1024] = {0}; size_t saoff = 0; From 2aed7112775507350ff8c12df93ab8b1f7a42fb3 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 5 Jun 2014 14:15:16 +0200 Subject: [PATCH 074/201] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 406505ddd..f7eab3265 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 406505dddac08300d937dd5f0f1fd3e701267287 +Subproject commit f7eab3265577feb885dba012d34a10f1b9be072b diff --git a/oRTP b/oRTP index 30e4d5b1a..ec4c194c6 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 30e4d5b1abf41c7d96825a3ca194eb47b5a45c1b +Subproject commit ec4c194c62a9657f075d07dc2495f98914ee0b8b From f9c01ebdb429e9bb79601a6b53bf24f89a3b5b85 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 5 Jun 2014 15:59:49 +0200 Subject: [PATCH 075/201] fix ICE status not updated at callee side in case of video mline rejected. add new tests. --- coreapi/bellesip_sal/sal_impl.c | 2 + coreapi/linphonecall.c | 4 +- coreapi/linphonecore.c | 1 + coreapi/misc.c | 31 ++++++------- coreapi/quality_reporting.c | 15 ++++--- tester/call_tester.c | 80 ++++++++++++++++++++++++++++++--- 6 files changed, 104 insertions(+), 29 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c5040be3a..6896496f7 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -423,6 +423,8 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) { Sal * sal_init(){ belle_sip_listener_callbacks_t listener_callbacks; Sal * sal=ms_new0(Sal,1); + + /*belle_sip_object_enable_marshal_check(TRUE);*/ sal->auto_contacts=TRUE; /*first create the stack, which initializes the belle-sip object's pool for this thread*/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index af4ab7b57..a1172229c 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -718,7 +718,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->current_params.privacy=(LinphonePrivacyMask)sal_op_get_privacy(call->op); /*set video support */ md=sal_call_get_remote_media_description(op); - call->params.has_video = !!lc->video_policy.automatically_accept; + call->params.has_video = lc->video_policy.automatically_accept; if (md) { // It is licit to receive an INVITE without SDP // In this case WE chose the media parameters according to policy. @@ -1582,7 +1582,7 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ if (incoming_offer){ remote=sal_call_get_remote_media_description(call->op); - has_video=linphone_core_media_description_contains_video_stream(remote); + has_video=call->params.has_video && linphone_core_media_description_contains_video_stream(remote); }else has_video=call->params.has_video; _linphone_call_prepare_ice_for_stream(call,0,TRUE); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6c79d7c71..0183979a5 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3433,6 +3433,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, call->params.media_encryption = LinphoneMediaEncryptionSRTP; } } + linphone_call_prepare_ice(call,TRUE); linphone_call_make_local_media_description(lc,call); sal_call_set_local_media_description(call->op,call->localdesc); sal_op_set_sent_custom_header(call->op,params->custom_headers); diff --git a/coreapi/misc.c b/coreapi/misc.c index 57ebaa32e..2a86db03a 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -803,6 +803,13 @@ static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescri if ((*addr)[0] == '\0') *addr = md->addr; } +static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed){ + if (call->audiostream && call->audiostream->ms.ice_check_list==removed) + call->audiostream->ms.ice_check_list=NULL; + if (call->videostream && call->videostream->ms.ice_check_list==removed) + call->videostream->ms.ice_check_list=NULL; +} + void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) { bool_t ice_restarted = FALSE; @@ -853,6 +860,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, for (i = 0; i < md->n_total_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); + /* if ((cl == NULL) && (i < md->n_active_streams)) { cl = ice_check_list_new(); ice_session_add_check_list(call->ice_session, cl); @@ -867,16 +875,13 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, break; } } + */ + if (cl==NULL) continue; if (stream->ice_mismatch == TRUE) { ice_check_list_set_state(cl, ICL_Failed); } else if (stream->rtp_port == 0) { ice_session_remove_check_list(call->ice_session, cl); -#ifdef VIDEO_ENABLED - if (stream->type==SalVideo && call->videostream){ - video_stream_stop(call->videostream); - call->videostream=NULL; - } -#endif + clear_ice_check_list(call,cl); } else { if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd); @@ -916,10 +921,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) { IceCheckList *removed=ice_session_check_list(call->ice_session, i - 1); ice_session_remove_check_list(call->ice_session, removed); - if (call->audiostream && call->audiostream->ms.ice_check_list==removed) - call->audiostream->ms.ice_check_list=NULL; - if (call->videostream && call->videostream->ms.ice_check_list==removed) - call->videostream->ms.ice_check_list=NULL; + clear_ice_check_list(call,removed); } ice_session_check_mismatch(call->ice_session); } else { @@ -932,12 +934,11 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } } -bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md) -{ +bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){ int i; - for (i = 0; i < md->n_active_streams; i++) { - if (md->streams[i].type == SalVideo) + for (i = 0; i < md->n_total_streams; i++) { + if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0) return TRUE; } return FALSE; @@ -1502,7 +1503,7 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){ np.params=params; suite=ms_crypto_suite_build_from_name_params(&np); if (suite!=MS_CRYPTO_SUITE_INVALID){ - result=ms_realloc(result,found+1+1); + result=ms_realloc(result,(found+2)*sizeof(MSCryptoSuite)); result[found]=suite; result[found+1]=MS_CRYPTO_SUITE_INVALID; found++; diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 50c283cf0..164653e18 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -479,7 +479,7 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->log->reports[stats_type]; reporting_content_metrics_t * metrics = NULL; - + MSQosAnalyser *analyser=NULL; LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; @@ -497,11 +497,14 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { block = stats.sent_rtcp; } } - - ms_qos_analyser_set_on_action_suggested( - ms_bitrate_controller_get_qos_analyser(call->audiostream->ms.rc), - qos_analyser_on_action_suggested, - &report->local_metrics); + if (call->audiostream->ms.rc){ + analyser=ms_bitrate_controller_get_qos_analyser(call->audiostream->ms.rc); + if (analyser){ + ms_qos_analyser_set_on_action_suggested(analyser, + qos_analyser_on_action_suggested, + &report->local_metrics); + } + } if (block != NULL) { switch (rtcp_XR_get_block_type(block)) { diff --git a/tester/call_tester.c b/tester/call_tester.c index a59313626..23c92ef52 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -552,20 +552,23 @@ static void call_with_no_sdp(void) { static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee, LinphoneIceState state) { LinphoneCall *c1,*c2; - bool_t success=FALSE; + bool_t audio_success=FALSE; + bool_t video_success=FALSE; int i; + bool_t video_enabled; c1=linphone_core_get_current_call(caller->lc); c2=linphone_core_get_current_call(callee->lc); CU_ASSERT_PTR_NOT_NULL(c1); CU_ASSERT_PTR_NOT_NULL(c2); - + CU_ASSERT_EQUAL(linphone_call_params_video_enabled(linphone_call_get_current_params(c1)),linphone_call_params_video_enabled(linphone_call_get_current_params(c2))); + video_enabled=linphone_call_params_video_enabled(linphone_call_get_current_params(c1)); for (i=0;i<200;i++){ if ((c1 != NULL) && (c2 != NULL)) { - if (linphone_call_get_audio_stats(c1)->ice_state==LinphoneIceStateHostConnection && - linphone_call_get_audio_stats(c2)->ice_state==LinphoneIceStateHostConnection ){ - success=TRUE; + if (linphone_call_get_audio_stats(c1)->ice_state==state && + linphone_call_get_audio_stats(c2)->ice_state==state ){ + audio_success=TRUE; break; } linphone_core_iterate(caller->lc); @@ -573,6 +576,21 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee } ms_usleep(50000); } + + if (video_enabled){ + for (i=0;i<200;i++){ + if ((c1 != NULL) && (c2 != NULL)) { + if (linphone_call_get_video_stats(c1)->ice_state==state && + linphone_call_get_video_stats(c2)->ice_state==state ){ + video_success=TRUE; + break; + } + linphone_core_iterate(caller->lc); + linphone_core_iterate(callee->lc); + } + ms_usleep(50000); + } + } /*make sure encryption mode are preserved*/ if (c1) { @@ -584,7 +602,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee CU_ASSERT_EQUAL(linphone_call_params_get_media_encryption(call_param),linphone_core_get_media_encryption(callee->lc)); } - return success; + return video_enabled ? audio_success && video_success : audio_success; } static void _call_with_ice_base(LinphoneCoreManager* pauline,LinphoneCoreManager* marie, bool_t caller_with_ice, bool_t callee_with_ice, bool_t random_ports) { @@ -982,6 +1000,54 @@ static void video_call_no_sdp(void) { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + +static void call_with_ice_video_to_novideo(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneVideoPolicy vpol={0}; + vpol.automatically_initiate=TRUE; + linphone_core_set_video_policy(pauline->lc,&vpol); + vpol.automatically_initiate=FALSE; + linphone_core_set_video_policy(marie->lc,&vpol); + _call_with_ice_base(pauline,marie,TRUE,TRUE,TRUE); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void call_with_ice_video_added(void) { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneVideoPolicy vpol={0}; + linphone_core_set_video_policy(pauline->lc,&vpol); + linphone_core_set_video_policy(marie->lc,&vpol); + + linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc,"stun.linphone.org"); + + + linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); + + + if (1){ + linphone_core_set_audio_port(marie->lc,-1); + linphone_core_set_video_port(marie->lc,-1); + linphone_core_set_audio_port(pauline->lc,-1); + linphone_core_set_video_port(pauline->lc,-1); + } + + CU_ASSERT_TRUE(call(pauline,marie)); + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + /*wait for ICE reINVITEs to complete*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2) + && + wait_for(pauline->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(add_video(pauline,marie)); + CU_ASSERT_TRUE(check_ice(pauline,marie,LinphoneIceStateHostConnection)); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + #endif /*VIDEO_ENABLED*/ static void _call_with_media_relay(bool_t random_ports) { @@ -2278,6 +2344,8 @@ test_t call_tests[] = { { "Call with video added (random ports)", call_with_video_added_random_ports }, { "Call with video declined",call_with_declined_video}, { "Call with multiple early media", multiple_early_media }, + { "Call with ICE from video to non-video", call_with_ice_video_to_novideo}, + { "Call with ICE and video added", call_with_ice_video_added }, #endif { "SRTP ice call", srtp_ice_call }, { "ZRTP ice call", zrtp_ice_call }, From 22e2cb518f80b71922579a4c378dcaf2bc3518b8 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 5 Jun 2014 11:01:50 +0200 Subject: [PATCH 076/201] Quality reporting: rename parameters send_statistics to quality_reporting_enabled and statistics_collector to quality_repotring_collector --- coreapi/linphonecore.h | 8 ++--- coreapi/private.h | 4 +-- coreapi/proxy.c | 42 +++++++++++++-------------- coreapi/quality_reporting.c | 4 +-- tester/call_tester.c | 58 ++++++++++++++++++------------------- tester/rcfiles/marie_rc | 4 +-- 6 files changed, 60 insertions(+), 60 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 60813272c..372caeb70 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -840,10 +840,10 @@ LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig * * @param val if true, quality statistics publish will be stored and sent to the collector * */ -LINPHONE_PUBLIC void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val); -LINPHONE_PUBLIC bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg); -LINPHONE_PUBLIC void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector); -LINPHONE_PUBLIC const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val); +LINPHONE_PUBLIC bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector); +LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *obj); /** * Get the registration state of the given proxy config. diff --git a/coreapi/private.h b/coreapi/private.h index 8de760b85..ed9e78878 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -415,7 +415,7 @@ struct _LinphoneProxyConfig char *reg_proxy; char *reg_identity; char *reg_route; - char *statistics_collector; + char *quality_reporting_collector; char *realm; char *contact_params; char *contact_uri_params; @@ -433,7 +433,7 @@ struct _LinphoneProxyConfig bool_t publish; bool_t dial_escape_plus; bool_t send_publish; - bool_t send_statistics; + bool_t quality_reporting_enabled; bool_t avpf_enabled; bool_t pad; uint8_t avpf_rr_interval; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index dde023bc4..a72e3523a 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -59,7 +59,7 @@ bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* LinphoneAddress *current_identity=obj->reg_identity?linphone_address_new(obj->reg_identity):NULL; LinphoneAddress *current_proxy=obj->reg_proxy?linphone_address_new(obj->reg_proxy):NULL; bool_t result=FALSE; - + if (!linphone_proxy_config_address_equal(obj->saved_identity,current_identity)){ result=TRUE; goto end; @@ -94,7 +94,7 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob const char *identity = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_identity", NULL) : NULL; const char *proxy = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_proxy", NULL) : NULL; const char *route = lc ? lp_config_get_default_string(lc->config, "proxy", "reg_route", NULL) : NULL; - const char *statistics_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "statistics_collector", NULL) : NULL; + const char *quality_reporting_collector = lc ? lp_config_get_default_string(lc->config, "proxy", "quality_reporting_collector", NULL) : NULL; const char *contact_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_parameters", NULL) : NULL; const char *contact_uri_params = lc ? lp_config_get_default_string(lc->config, "proxy", "contact_uri_parameters", NULL) : NULL; @@ -108,8 +108,8 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob obj->reg_identity = identity ? ms_strdup(identity) : NULL; obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL; obj->reg_route = route ? ms_strdup(route) : NULL; - obj->statistics_collector = statistics_collector ? ms_strdup(statistics_collector) : NULL; - obj->send_statistics = lc ? lp_config_get_default_int(lc->config, "proxy", "send_statistics", 0) : 0; + obj->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL; + obj->quality_reporting_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0; obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL; obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL; obj->avpf_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf", 0) : 0; @@ -147,7 +147,7 @@ void linphone_proxy_config_destroy(LinphoneProxyConfig *obj){ if (obj->reg_proxy!=NULL) ms_free(obj->reg_proxy); if (obj->reg_identity!=NULL) ms_free(obj->reg_identity); if (obj->reg_route!=NULL) ms_free(obj->reg_route); - if (obj->statistics_collector!=NULL) ms_free(obj->statistics_collector); + if (obj->quality_reporting_collector!=NULL) ms_free(obj->quality_reporting_collector); if (obj->ssctx!=NULL) sip_setup_context_free(obj->ssctx); if (obj->realm!=NULL) ms_free(obj->realm); if (obj->type!=NULL) ms_free(obj->type); @@ -480,16 +480,16 @@ bool_t linphone_proxy_config_get_dial_escape_plus(const LinphoneProxyConfig *cfg return cfg->dial_escape_plus; } -void linphone_proxy_config_enable_statistics(LinphoneProxyConfig *cfg, bool_t val){ - cfg->send_statistics = val; +void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val){ + cfg->quality_reporting_enabled = val; } -bool_t linphone_proxy_config_send_statistics_enabled(LinphoneProxyConfig *cfg){ +bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg){ // ensure that collector address is set too! - return cfg->send_statistics && cfg->statistics_collector != NULL; + return cfg->quality_reporting_enabled && cfg->quality_reporting_collector != NULL; } -void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, const char *collector){ +void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector){ if (collector!=NULL && strlen(collector)>0){ LinphoneAddress *addr=linphone_address_new(collector); if (!addr || linphone_address_get_username(addr)==NULL){ @@ -497,16 +497,16 @@ void linphone_proxy_config_set_statistics_collector(LinphoneProxyConfig *cfg, co if (addr) linphone_address_destroy(addr); } else { - if (cfg->statistics_collector != NULL) - ms_free(cfg->statistics_collector); - cfg->statistics_collector = ms_strdup(collector); + if (cfg->quality_reporting_collector != NULL) + ms_free(cfg->quality_reporting_collector); + cfg->quality_reporting_collector = ms_strdup(collector); linphone_address_destroy(addr); } } } -const char *linphone_proxy_config_get_statistics_collector(const LinphoneProxyConfig *cfg){ - return cfg->statistics_collector; +const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg){ + return cfg->quality_reporting_collector; } @@ -1174,8 +1174,8 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC if (obj->reg_route!=NULL){ lp_config_set_string(config,key,"reg_route",obj->reg_route); } - if (obj->statistics_collector!=NULL){ - lp_config_set_string(config,key,"statistics_collector",obj->statistics_collector); + if (obj->quality_reporting_collector!=NULL){ + lp_config_set_string(config,key,"quality_reporting_collector",obj->quality_reporting_collector); } if (obj->reg_identity!=NULL){ lp_config_set_string(config,key,"reg_identity",obj->reg_identity); @@ -1192,7 +1192,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC lp_config_set_int(config, key, "avpf", obj->avpf_enabled); lp_config_set_int(config, key, "avpf_rr_interval", obj->avpf_rr_interval); lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus); - lp_config_set_int(config,key,"send_statistics",obj->send_statistics); + lp_config_set_int(config,key,"quality_reporting_enabled",obj->quality_reporting_enabled); lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix); lp_config_set_int(config,key,"privacy",obj->privacy); } @@ -1224,9 +1224,9 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config tmp=lp_config_get_string(config,key,"reg_route",NULL); if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); - tmp=lp_config_get_string(config,key,"statistics_collector",NULL); - if (tmp!=NULL) linphone_proxy_config_set_statistics_collector(cfg,tmp); - linphone_proxy_config_enable_statistics(cfg,lp_config_get_int(config,key,"send_statistics",0)); + tmp=lp_config_get_string(config,key,"quality_reporting_collector",NULL); + if (tmp!=NULL) linphone_proxy_config_set_quality_reporting_collector(cfg,tmp); + linphone_proxy_config_enable_quality_reporting(cfg,lp_config_get_int(config,key,"quality_reporting_enabled",0)); linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 164653e18..c9c5e7fd7 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -299,7 +299,7 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r return; } - addr = linphone_address_new(call->dest_proxy->statistics_collector); + addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy)); if (addr == NULL) { ms_warning("Asked to submit reporting statistics but no collector address found"); return; @@ -384,7 +384,7 @@ static void update_ip(LinphoneCall * call, int stats_type) { } static bool_t is_reporting_enabled(const LinphoneCall * call) { - return (call->dest_proxy != NULL && linphone_proxy_config_send_statistics_enabled(call->dest_proxy)); + return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); } static void qos_analyser_on_action_suggested(void *user_data, const char * input, const char * output){ diff --git a/tester/call_tester.c b/tester/call_tester.c index 23c92ef52..f1b94bbd2 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -259,17 +259,17 @@ static void call_with_specified_codec_bitrate(void) { ms_warning("opus codec not supported, test skipped."); goto end; } - + disable_all_codecs_except_one(marie->lc,"opus"); disable_all_codecs_except_one(pauline->lc,"opus"); - + linphone_core_set_payload_type_bitrate(marie->lc, linphone_core_find_payload_type(marie->lc,"opus",48000,-1), 50); linphone_core_set_payload_type_bitrate(pauline->lc, linphone_core_find_payload_type(pauline->lc,"opus",48000,-1), 24); - + CU_ASSERT_TRUE((call_ok=call(pauline,marie))); if (!call_ok) goto end; liblinphone_tester_check_rtcp(marie,pauline); @@ -663,9 +663,9 @@ static void call_with_ice_no_sdp(void){ linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce); linphone_core_set_stun_server(pauline->lc,"stun.linphone.org"); - + call(pauline,marie); - + liblinphone_tester_check_rtcp(marie,pauline); linphone_core_manager_destroy(marie); @@ -2136,7 +2136,7 @@ static void call_rejected_without_403_because_wrong_credentials_no_auth_req_cb() call_rejected_because_wrong_credentials_with_params("tester-no-403",FALSE); } -void create_call_for_statistics_tests( +void create_call_for_quality_reporting_tests( LinphoneCoreManager* marie, LinphoneCoreManager* pauline, LinphoneCall** call_marie, @@ -2148,20 +2148,20 @@ void create_call_for_statistics_tests( CU_ASSERT_PTR_NOT_NULL(*call_pauline); } -static void statistics_not_used_without_config() { +static void quality_reporting_not_used_without_config() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_marie = NULL; LinphoneCall* call_pauline = NULL; - create_call_for_statistics_tests(marie, pauline, &call_marie, &call_pauline); + create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); // marie has stats collection enabled since pauline has not - CU_ASSERT_TRUE(linphone_proxy_config_send_statistics_enabled(call_marie->dest_proxy)); - CU_ASSERT_FALSE(linphone_proxy_config_send_statistics_enabled(call_pauline->dest_proxy)); + CU_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(call_marie->dest_proxy)); + CU_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(call_pauline->dest_proxy)); CU_ASSERT_EQUAL(strcmp("sip:collector@sip.example.org", - linphone_proxy_config_get_statistics_collector(call_marie->dest_proxy)), 0); + linphone_proxy_config_get_quality_reporting_collector(call_marie->dest_proxy)), 0); // this field should be already filled CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->info.local_addr.ip); @@ -2173,7 +2173,7 @@ static void statistics_not_used_without_config() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -static void statistics_not_sent_if_call_not_started() { +static void quality_reporting_not_sent_if_call_not_started() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCallLog* out_call_log; @@ -2201,14 +2201,14 @@ static void statistics_not_sent_if_call_not_started() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } -static void statistics_sent_at_call_termination() { +static void quality_reporting_at_call_termination() { // int return_code = -1; LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_marie = NULL; LinphoneCall* call_pauline = NULL; - create_call_for_statistics_tests(marie, pauline, &call_marie, &call_pauline); + create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); linphone_core_terminate_all_calls(marie->lc); CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); @@ -2243,12 +2243,12 @@ static void multiple_early_media(void) { int dummy=0; char ringbackpath[256]; snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); - + pol.automatically_accept=1; pol.automatically_initiate=1; - + linphone_core_enable_video(pauline->lc,TRUE,TRUE); - + linphone_core_enable_video(marie1->lc,TRUE,TRUE); linphone_core_set_video_policy(marie1->lc,&pol); /*use playfile for marie1 to avoid locking on capture card*/ @@ -2262,44 +2262,44 @@ static void multiple_early_media(void) { /*use playfile for marie2 to avoid locking on capture card*/ linphone_core_use_files(marie2->lc,TRUE); linphone_core_set_play_file(marie2->lc,ringbackpath); - - + + lcs=ms_list_append(lcs,marie1->lc); lcs=ms_list_append(lcs,marie2->lc); lcs=ms_list_append(lcs,pauline->lc); linphone_call_params_enable_early_media_sending(params,TRUE); linphone_call_params_enable_video(params,TRUE); - + linphone_core_invite_address_with_params(pauline->lc,marie1->identity,params); linphone_call_params_destroy(params); CU_ASSERT_TRUE(wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallIncomingEarlyMedia,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallOutgoingEarlyMedia,1,3000)); - + pauline_call=linphone_core_get_current_call(pauline->lc); marie1_call=linphone_core_get_current_call(marie1->lc); marie2_call=linphone_core_get_current_call(marie2->lc); - + /*wait a bit that streams are established*/ wait_for_list(lcs,&dummy,1,6000); CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>70); CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>70); CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie2_call)->download_bandwidth>70); - + linphone_core_accept_call(marie1->lc,linphone_core_get_current_call(marie1->lc)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallStreamsRunning,1,3000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallStreamsRunning,1,3000)); - + /*marie2 should get her call terminated*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallEnd,1,1000)); - + /*wait a bit that streams are established*/ wait_for_list(lcs,&dummy,1,1000); CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); - + linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); @@ -2374,9 +2374,9 @@ test_t call_tests[] = { { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, { "Call redirected by callee", call_redirect}, - { "Call statistics not used if no config", statistics_not_used_without_config}, - { "Call statistics not sent if call did not start", statistics_not_sent_if_call_not_started}, - { "Call statistics sent if call ended normally", statistics_sent_at_call_termination}, + { "Call quality reporting not used if no config", quality_reporting_not_used_without_config}, + { "Call quality reporting not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, + { "Call quality reporting sent if call ended normally", quality_reporting_at_call_termination}, { "Call with specified codec bitrate", call_with_specified_codec_bitrate} }; diff --git a/tester/rcfiles/marie_rc b/tester/rcfiles/marie_rc index e5cd7a3b5..f4f9aa793 100644 --- a/tester/rcfiles/marie_rc +++ b/tester/rcfiles/marie_rc @@ -22,8 +22,8 @@ reg_expires=3600 reg_sendregister=1 publish=0 dial_escape_plus=0 -statistics_collector=sip:collector@sip.example.org -send_statistics=1 +quality_reporting_collector=sip:collector@sip.example.org +quality_reporting_enabled=1 [friend_0] url="Paupoche" From ce7a644616b694f9a612bb04e85b0e1537b01ed6 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 5 Jun 2014 11:57:51 +0200 Subject: [PATCH 077/201] Quality reporting: add possibility to send interval reports to a given spacing interval during a call --- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.h | 52 ++++++++++++++++++++++++++++++++----- coreapi/private.h | 1 + coreapi/proxy.c | 23 +++++++++++----- coreapi/quality_reporting.c | 43 +++++++++++++++++++++++++----- coreapi/quality_reporting.h | 15 +++++++++-- 6 files changed, 114 insertions(+), 22 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a1172229c..2c6c188b4 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -907,7 +907,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const if (cstate==LinphoneCallEnd){ if (call->log->status == LinphoneCallSuccess) - linphone_reporting_publish_on_call_term(call); + linphone_reporting_publish_session_report(call); } if (cstate==LinphoneCallReleased){ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 372caeb70..c3ebf9aaf 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -834,16 +834,54 @@ LINPHONE_PUBLIC int linphone_proxy_config_get_publish_expires(const LinphoneProx LINPHONE_PUBLIC void linphone_proxy_config_set_dial_escape_plus(LinphoneProxyConfig *cfg, bool_t val); LINPHONE_PUBLIC void linphone_proxy_config_set_dial_prefix(LinphoneProxyConfig *cfg, const char *prefix); -/** - * Indicates either or not, quality statistics during call should be stored and sent to a collector at termination. - * @param cfg #LinphoneProxyConfig object - * @param val if true, quality statistics publish will be stored and sent to the collector - * + /** + * Indicates whether quality statistics during call should be stored and sent to a collector according to RFC 6035. + * @param[in] cfg #LinphoneProxyConfig object + * @param[in] enable True to sotre quality statistics and sent them to the collector, false to disable it. + */ +LINPHONE_PUBLIC void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t enable); + +/** + * Indicates whether quality statistics during call should be stored and sent to a collector according to RFC 6035. + * @param[in] cfg #LinphoneProxyConfig object + * @return True if quality repotring is enabled, false otherwise. */ -LINPHONE_PUBLIC void linphone_proxy_config_enable_quality_reporting(LinphoneProxyConfig *cfg, bool_t val); LINPHONE_PUBLIC bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg); + + /** + * Set the SIP address of the collector end-point when using quality reporting. This SIP address + * should be used on server-side to process packets directly then discard packets. Collector address + * should be a non existing account and should not received any packets. + * @param[in] cfg #LinphoneProxyConfig object + * @param[in] collector SIP address of the collector end-point. + */ LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector); -LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *obj); + + /** + * Get the SIP address of the collector end-point when using quality reporting. This SIP address + * should be used on server-side to process packets directly then discard packets. Collector address + * should be a non existing account and should not received any packets. + * @param[in] cfg #LinphoneProxyConfig object + * @return The SIP address of the collector end-point. + */ +LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collector(const LinphoneProxyConfig *cfg); + +/** + * Set the interval between 2 interval reports sending when using quality reporting. If call exceed interval size, an + * interval report will be sent to the collector. On call termination, a session report will be sent + * for the remaining period. + * @param[in] cfg #LinphoneProxyConfig object + * @param[in] interval The interval in seconds. + */ +void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval); + +/** + * Get the interval between interval reports when using quality reporting. + * @param[in] cfg #LinphoneProxyConfig object + * @return The interval in seconds. + */ + +int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg); /** * Get the registration state of the given proxy config. diff --git a/coreapi/private.h b/coreapi/private.h index ed9e78878..5270f5440 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -437,6 +437,7 @@ struct _LinphoneProxyConfig bool_t avpf_enabled; bool_t pad; uint8_t avpf_rr_interval; + uint8_t quality_reporting_interval; void* user_data; time_t deletion_date; LinphonePrivacyMask privacy; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a72e3523a..cedb97b29 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -108,8 +108,9 @@ static void linphone_proxy_config_init(LinphoneCore* lc, LinphoneProxyConfig *ob obj->reg_identity = identity ? ms_strdup(identity) : NULL; obj->reg_proxy = proxy ? ms_strdup(proxy) : NULL; obj->reg_route = route ? ms_strdup(route) : NULL; - obj->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL; obj->quality_reporting_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_enabled", 0) : 0; + obj->quality_reporting_collector = quality_reporting_collector ? ms_strdup(quality_reporting_collector) : NULL; + obj->quality_reporting_interval = lc ? lp_config_get_default_int(lc->config, "proxy", "quality_reporting_interval", 0) : 0; obj->contact_params = contact_params ? ms_strdup(contact_params) : NULL; obj->contact_uri_params = contact_uri_params ? ms_strdup(contact_uri_params) : NULL; obj->avpf_enabled = lc ? lp_config_get_default_int(lc->config, "proxy", "avpf", 0) : 0; @@ -489,6 +490,14 @@ bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg) return cfg->quality_reporting_enabled && cfg->quality_reporting_collector != NULL; } +void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval) { + cfg->quality_reporting_interval = interval; +} + +int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) { + return cfg->quality_reporting_interval; +} + void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig *cfg, const char *collector){ if (collector!=NULL && strlen(collector)>0){ LinphoneAddress *addr=linphone_address_new(collector); @@ -1174,9 +1183,6 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC if (obj->reg_route!=NULL){ lp_config_set_string(config,key,"reg_route",obj->reg_route); } - if (obj->quality_reporting_collector!=NULL){ - lp_config_set_string(config,key,"quality_reporting_collector",obj->quality_reporting_collector); - } if (obj->reg_identity!=NULL){ lp_config_set_string(config,key,"reg_identity",obj->reg_identity); } @@ -1186,13 +1192,17 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC if (obj->contact_uri_params!=NULL){ lp_config_set_string(config,key,"contact_uri_parameters",obj->contact_uri_params); } + if (obj->quality_reporting_collector!=NULL){ + lp_config_set_string(config,key,"quality_reporting_collector",obj->quality_reporting_collector); + } + lp_config_set_int(config,key,"quality_reporting_enabled",obj->quality_reporting_enabled); + lp_config_set_int(config,key,"quality_reporting_interval",obj->quality_reporting_interval); lp_config_set_int(config,key,"reg_expires",obj->expires); lp_config_set_int(config,key,"reg_sendregister",obj->reg_sendregister); lp_config_set_int(config,key,"publish",obj->publish); lp_config_set_int(config, key, "avpf", obj->avpf_enabled); lp_config_set_int(config, key, "avpf_rr_interval", obj->avpf_rr_interval); lp_config_set_int(config,key,"dial_escape_plus",obj->dial_escape_plus); - lp_config_set_int(config,key,"quality_reporting_enabled",obj->quality_reporting_enabled); lp_config_set_string(config,key,"dial_prefix",obj->dial_prefix); lp_config_set_int(config,key,"privacy",obj->privacy); } @@ -1224,9 +1234,10 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config tmp=lp_config_get_string(config,key,"reg_route",NULL); if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); + linphone_proxy_config_enable_quality_reporting(cfg,lp_config_get_int(config,key,"quality_reporting_enabled",0)); tmp=lp_config_get_string(config,key,"quality_reporting_collector",NULL); if (tmp!=NULL) linphone_proxy_config_set_quality_reporting_collector(cfg,tmp); - linphone_proxy_config_enable_quality_reporting(cfg,lp_config_get_int(config,key,"quality_reporting_enabled",0)); + linphone_proxy_config_set_quality_reporting_interval(cfg, lp_config_get_int(config, key, "quality_reporting_interval", 5)); linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index c9c5e7fd7..4d8a68b23 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -33,8 +33,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *************************************************************************** For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). moslq == moscq +valgrind video: what happens if doing stop/resume? rlq value: need algo to compute it +3.4 overload avoidance? - The Session report when session terminates, media change (codec change or a session fork), session terminates due to no media packets being received - The Interval report SHOULD be used for periodic or interval reporting @@ -282,7 +284,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off ms_free(moscq_str); } -static void send_report(const LinphoneCall* call, reporting_session_report_t * report) { +static void send_report(const LinphoneCall* call, reporting_session_report_t * report, const char * report_event) { LinphoneContent content = {0}; LinphoneAddress *addr; int expires = -1; @@ -295,7 +297,15 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0 || report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) { ms_warning("The call was hang up too early (duration: %d sec) and IP could " - "not be retrieved so dropping this report", linphone_call_get_duration(call)); + "not be retrieved so dropping this report" + , linphone_call_get_duration(call)); + return; + } + + /*do not send report if the previous one was sent less than 30seconds ago*/ + if (ms_time(NULL) - report->last_report_date < 30){ + ms_warning("Already sent a report %ld sec ago. Cancel sending this report" + , ms_time(NULL) - report->last_report_date); return; } @@ -309,7 +319,7 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r content.type = ms_strdup("application"); content.subtype = ms_strdup("vq-rtcpxr"); - append_to_buffer(&buffer, &size, &offset, "VQSessionReport: CallTerm\r\n"); + append_to_buffer(&buffer, &size, &offset, "%s\r\n", report_event); append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", report->info.call_id); append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_id); append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id); @@ -339,6 +349,8 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r reset_avg_metrics(report); linphone_content_uninit(&content); + + report->last_report_date = ms_time(NULL); } static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) { @@ -533,20 +545,39 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { } } } + + /* check if we should send an interval report */ + if (ms_time(NULL) - report->last_report_date > linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy)){ + linphone_reporting_publish_interval_report(call); + } } -void linphone_reporting_publish_on_call_term(LinphoneCall* call) { +void linphone_reporting_publish_session_report(LinphoneCall* call) { + if (! is_reporting_enabled(call)) + return; + + if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { + send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO], "VQSessionReport: CallTerm"); + } + + if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL + && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { + send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport: CallTerm"); + } +} + +void linphone_reporting_publish_interval_report(LinphoneCall* call) { if (! is_reporting_enabled(call)) return; if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { - send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO]); + send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO], "VQIntervalReport"); } if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { - send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO]); + send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO], "VQIntervalReport"); } } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 44704c32a..00fb07215 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -129,6 +129,9 @@ typedef struct reporting_session_report { reporting_content_metrics_t remote_metrics; // optional char * dialog_id; // optional + + // for internal processing + time_t last_report_date; } reporting_session_report_t; reporting_session_report_t * linphone_reporting_new(); @@ -154,11 +157,19 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type); void linphone_reporting_update_ip(LinphoneCall * call); /** - * Publish the report on the call end. + * Publish a session report. This function should be called when session terminates, + * media change (codec change or session fork), session terminates due to no media packets being received. * @param call #LinphoneCall object to consider * */ -void linphone_reporting_publish_on_call_term(LinphoneCall* call); +void linphone_reporting_publish_session_report(LinphoneCall* call); + +/** + * Publish an interval report. This function should be used for periodic interval + * @param call #LinphoneCall object to consider + * + */ +void linphone_reporting_publish_interval_report(LinphoneCall* call); /** * Update publish report data with fresh RTCP stats, if needed. From 25186cc0ae03b72c202f75d31033ca89a69366c2 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 5 Jun 2014 15:25:05 +0200 Subject: [PATCH 078/201] Quality reporting: disabled interval report per default and add minimal value when set (120 seconds minimum) --- coreapi/linphonecore.h | 6 +++--- coreapi/proxy.c | 4 ++-- coreapi/quality_reporting.c | 20 +++++++------------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index c3ebf9aaf..b70e90600 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -869,16 +869,16 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collecto /** * Set the interval between 2 interval reports sending when using quality reporting. If call exceed interval size, an * interval report will be sent to the collector. On call termination, a session report will be sent - * for the remaining period. + * for the remaining period. Value must be 0 (disabled) or greater than 120sec to avoid overloading. * @param[in] cfg #LinphoneProxyConfig object - * @param[in] interval The interval in seconds. + * @param[in] interval The interval in seconds, 0 means interval reports are disabled. */ void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval); /** * Get the interval between interval reports when using quality reporting. * @param[in] cfg #LinphoneProxyConfig object - * @return The interval in seconds. + * @return The interval in seconds, 0 means interval reports are disabled. */ int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index cedb97b29..8faaa95cf 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -491,7 +491,7 @@ bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg) } void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval) { - cfg->quality_reporting_interval = interval; + cfg->quality_reporting_interval = interval ? MAX(interval, 120) : 0; } int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) { @@ -1237,7 +1237,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config linphone_proxy_config_enable_quality_reporting(cfg,lp_config_get_int(config,key,"quality_reporting_enabled",0)); tmp=lp_config_get_string(config,key,"quality_reporting_collector",NULL); if (tmp!=NULL) linphone_proxy_config_set_quality_reporting_collector(cfg,tmp); - linphone_proxy_config_set_quality_reporting_interval(cfg, lp_config_get_int(config, key, "quality_reporting_interval", 5)); + linphone_proxy_config_set_quality_reporting_interval(cfg, lp_config_get_int(config, key, "quality_reporting_interval", 0)); linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 4d8a68b23..251f82b38 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -100,9 +100,9 @@ static void append_to_buffer(char **buff, size_t *buff_size, size_t *offset, con va_end(args); } -static void reset_avg_metrics(reporting_session_report_t * rm){ +static void reset_avg_metrics(reporting_session_report_t * report){ int i; - reporting_content_metrics_t * metrics[2] = {&rm->local_metrics, &rm->remote_metrics}; + reporting_content_metrics_t * metrics[2] = {&report->local_metrics, &report->remote_metrics}; for (i = 0; i < 2; i++) { metrics[i]->rtcp_xr_count = 0; @@ -110,8 +110,10 @@ static void reset_avg_metrics(reporting_session_report_t * rm){ metrics[i]->jitter_buffer.max = 0; metrics[i]->delay.round_trip_delay = 0; + metrics[i]->delay.symm_one_way_delay = 0; } + report->last_report_date = ms_time(NULL); } #define APPEND_IF_NOT_NULL_STR(buffer, size, offset, fmt, arg) if (arg != NULL) append_to_buffer(buffer, size, offset, fmt, arg) @@ -302,13 +304,6 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r return; } - /*do not send report if the previous one was sent less than 30seconds ago*/ - if (ms_time(NULL) - report->last_report_date < 30){ - ms_warning("Already sent a report %ld sec ago. Cancel sending this report" - , ms_time(NULL) - report->last_report_date); - return; - } - addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy)); if (addr == NULL) { ms_warning("Asked to submit reporting statistics but no collector address found"); @@ -349,8 +344,6 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r reset_avg_metrics(report); linphone_content_uninit(&content); - - report->last_report_date = ms_time(NULL); } static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) { @@ -495,6 +488,8 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; + int report_interval = linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy); + if (! is_reporting_enabled(call)) return; @@ -547,7 +542,7 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { } /* check if we should send an interval report */ - if (ms_time(NULL) - report->last_report_date > linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy)){ + if (report_interval>0 && ms_time(NULL)-report->last_report_date>report_interval){ linphone_reporting_publish_interval_report(call); } } @@ -570,7 +565,6 @@ void linphone_reporting_publish_interval_report(LinphoneCall* call) { if (! is_reporting_enabled(call)) return; - if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO], "VQIntervalReport"); } From ff6cbfc0f37c3eae1acb7d65c1e4da6625e23b84 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 5 Jun 2014 16:56:54 +0200 Subject: [PATCH 079/201] Display available tests if the given one is not existing --- tester/liblinphone_tester.c | 8 +++----- tester/liblinphone_tester.h | 1 + tester/tester.c | 8 ++++++++ 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 7b5043680..c5d017566 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -197,10 +197,7 @@ int main (int argc, char *argv[]) } else if (strcmp(argv[i],"--list-tests")==0){ CHECK_ARG("--list-tests", ++i, argc); suite_name = argv[i]; - for(j=0;j Date: Thu, 5 Jun 2014 16:59:21 +0200 Subject: [PATCH 080/201] fill media information when sending interval report too and added unit test for it (quality_reporting_interval_report) --- coreapi/linphonecore.h | 2 +- coreapi/proxy.c | 6 ++++-- coreapi/quality_reporting.c | 30 +++++++++++++++++------------- coreapi/quality_reporting.h | 8 +++++--- tester/call_tester.c | 29 +++++++++++++++++++++++++---- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index b70e90600..bb35fc98c 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -869,7 +869,7 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collecto /** * Set the interval between 2 interval reports sending when using quality reporting. If call exceed interval size, an * interval report will be sent to the collector. On call termination, a session report will be sent - * for the remaining period. Value must be 0 (disabled) or greater than 120sec to avoid overloading. + * for the remaining period. Value must be 0 (disabled) or positive. * @param[in] cfg #LinphoneProxyConfig object * @param[in] interval The interval in seconds, 0 means interval reports are disabled. */ diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 8faaa95cf..3772bc744 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -491,7 +491,7 @@ bool_t linphone_proxy_config_quality_reporting_enabled(LinphoneProxyConfig *cfg) } void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval) { - cfg->quality_reporting_interval = interval ? MAX(interval, 120) : 0; + cfg->quality_reporting_interval = interval; } int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg) { @@ -1216,6 +1216,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config const char *proxy; LinphoneProxyConfig *cfg; char key[50]; + int interval; sprintf(key,"proxy_%i",index); @@ -1237,7 +1238,8 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config linphone_proxy_config_enable_quality_reporting(cfg,lp_config_get_int(config,key,"quality_reporting_enabled",0)); tmp=lp_config_get_string(config,key,"quality_reporting_collector",NULL); if (tmp!=NULL) linphone_proxy_config_set_quality_reporting_collector(cfg,tmp); - linphone_proxy_config_set_quality_reporting_interval(cfg, lp_config_get_int(config, key, "quality_reporting_interval", 0)); + interval=lp_config_get_int(config, key, "quality_reporting_interval", 0); + linphone_proxy_config_set_quality_reporting_interval(cfg, interval? MAX(interval, 120) : 0); linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 251f82b38..81241efd1 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -35,6 +35,8 @@ For codecs that are able to change sample rates, the lowest and highest sample r moslq == moscq valgrind video: what happens if doing stop/resume? +one single report <- merge audio/video? +unit test interval report rlq value: need algo to compute it 3.4 overload avoidance? @@ -111,7 +113,7 @@ static void reset_avg_metrics(reporting_session_report_t * report){ metrics[i]->delay.round_trip_delay = 0; - metrics[i]->delay.symm_one_way_delay = 0; + /*metrics[i]->delay.symm_one_way_delay = 0;*/ } report->last_report_date = ms_time(NULL); } @@ -147,15 +149,15 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret|=METRICS_JITTER_BUFFER); IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret|=METRICS_DELAY); - IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret|=METRICS_DELAY); + /*IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret|=METRICS_DELAY);*/ IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret|=METRICS_DELAY); IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret|=METRICS_DELAY); if (rm.signal.level != 127) ret|=METRICS_SIGNAL; if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; - if (rm.adaptive_algorithm.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; - if (rm.adaptive_algorithm.output!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; + if (rm.qos_analyzer.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; + if (rm.qos_analyzer.output!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.rtcp_xr_count>0){ IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); @@ -236,7 +238,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off } APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535);*/ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535); + /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535);*/ APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535); } @@ -271,8 +273,8 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off if ((available_metrics & METRICS_ADAPTIVE_ALGORITHM) != 0){ append_to_buffer(buffer, size, offset, "\r\nAdaptiveAlg:"); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.adaptive_algorithm.input); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT=%s", rm.adaptive_algorithm.output); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.qos_analyzer.input); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT=%s", rm.qos_analyzer.output); } append_to_buffer(buffer, size, offset, "\r\n"); @@ -395,11 +397,11 @@ static bool_t is_reporting_enabled(const LinphoneCall * call) { static void qos_analyser_on_action_suggested(void *user_data, const char * input, const char * output){ reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; char * newstr = NULL; - newstr = ms_strdup_printf("%s%s;", metrics->adaptive_algorithm.input?metrics->adaptive_algorithm.input:"", input); - STR_REASSIGN(metrics->adaptive_algorithm.input, newstr) + newstr = ms_strdup_printf("%s%s;", metrics->qos_analyzer.input?metrics->qos_analyzer.input:"", input); + STR_REASSIGN(metrics->qos_analyzer.input, newstr) - newstr = ms_strdup_printf("%s%s;", metrics->adaptive_algorithm.output?metrics->adaptive_algorithm.output:"", output); - STR_REASSIGN(metrics->adaptive_algorithm.output, newstr) + newstr = ms_strdup_printf("%s%s;", metrics->qos_analyzer.output?metrics->qos_analyzer.output:"", output); + STR_REASSIGN(metrics->qos_analyzer.output, newstr) } void linphone_reporting_update_ip(LinphoneCall * call) { @@ -566,11 +568,13 @@ void linphone_reporting_publish_interval_report(LinphoneCall* call) { return; if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO], "VQIntervalReport"); } if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO); send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO], "VQIntervalReport"); } } @@ -625,8 +629,8 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp); if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc); - if (report->local_metrics.adaptive_algorithm.input != NULL) ms_free(report->local_metrics.adaptive_algorithm.input); - if (report->local_metrics.adaptive_algorithm.output != NULL) ms_free(report->local_metrics.adaptive_algorithm.output); + if (report->local_metrics.qos_analyzer.input != NULL) ms_free(report->local_metrics.qos_analyzer.input); + if (report->local_metrics.qos_analyzer.output != NULL) ms_free(report->local_metrics.qos_analyzer.output); ms_free(report); } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 00fb07215..2dc888a89 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -75,7 +75,7 @@ typedef struct reporting_content_metrics { struct { int round_trip_delay; // no - vary int end_system_delay; // no - not implemented yet - int symm_one_way_delay; // no - vary (depends on round_trip_delay) + not implemented (depends on end_system_delay) + int symm_one_way_delay; // no - not implemented (depends on end_system_delay) int interarrival_jitter; // no - not implemented yet int mean_abs_jitter; // to check } delay; @@ -94,11 +94,13 @@ typedef struct reporting_content_metrics { float moscq; // no - vary or avg - voip metrics - in [0..4.9] } quality_estimates; - // adaptive algorithm - custom extension + // Quality of Service analyzer - custom extension + /* This should allow us to analysis bad network conditions and quality adaptation + on server side*/ struct { char* input; char* output; - } adaptive_algorithm; + } qos_analyzer; // for internal processing uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5) diff --git a/tester/call_tester.c b/tester/call_tester.c index f1b94bbd2..7e2617ca3 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2202,7 +2202,6 @@ static void quality_reporting_not_sent_if_call_not_started() { linphone_core_manager_destroy(pauline); } static void quality_reporting_at_call_termination() { - // int return_code = -1; LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_marie = NULL; @@ -2228,6 +2227,27 @@ static void quality_reporting_at_call_termination() { linphone_core_manager_destroy(pauline); } +static void quality_reporting_interval_report() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 3); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc)); + + // PUBLISH submission to the collector should be ok + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,3,15000)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,3,15000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + #ifdef VIDEO_ENABLED /*this is call forking with early media managed at client side (not by flexisip server)*/ static void multiple_early_media(void) { @@ -2374,9 +2394,10 @@ test_t call_tests[] = { { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, { "Call redirected by callee", call_redirect}, - { "Call quality reporting not used if no config", quality_reporting_not_used_without_config}, - { "Call quality reporting not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, - { "Call quality reporting sent if call ended normally", quality_reporting_at_call_termination}, + { "Quality reporting not used if no config", quality_reporting_not_used_without_config}, + { "Quality reporting session report not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, + { "Quality reporting session report sent if call ended normally", quality_reporting_at_call_termination}, + { "Quality reporting interval report if interval is configured", quality_reporting_interval_report}, { "Call with specified codec bitrate", call_with_specified_codec_bitrate} }; From 4094aec87ab5a5915dc7d985d7670d360709eff2 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 5 Jun 2014 17:38:15 +0200 Subject: [PATCH 081/201] removed minor warnings generated by doxygen due to outdated functions prototype --- coreapi/chat.c | 2 +- coreapi/event.h | 9 ++++----- coreapi/linphone_tunnel.h | 12 ++++++------ coreapi/linphonecall.c | 2 +- coreapi/linphonecore.c | 8 +++++--- coreapi/linphonecore.h | 8 ++++---- coreapi/linphonepresence.h | 2 +- coreapi/proxy.c | 2 +- coreapi/quality_reporting.c | 1 - 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 2ea196b47..c20cfef9e 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -247,7 +247,7 @@ void linphone_chat_room_message_received(LinphoneChatRoom *cr, LinphoneCore *lc, /** * Retrieve an existing chat room whose peer is the supplied address, if exists. * @param lc the linphone core - * @param add a linphone address. + * @param addr a linphone address. * @returns the matching chatroom, or NULL if no such chatroom exists. **/ LinphoneChatRoom *linphone_core_get_chat_room(LinphoneCore *lc, const LinphoneAddress *addr){ diff --git a/coreapi/event.h b/coreapi/event.h index 2b0e2bf0d..4b3e26bd9 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -97,12 +97,12 @@ typedef void (*LinphoneCoreNotifyReceivedCb)(LinphoneCore *lc, LinphoneEvent *le /** * Callback prototype for notifying the application about changes of subscription states, including arrival of new subscriptions. -**/ +**/ typedef void (*LinphoneCoreSubscriptionStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state); /** * Callback prototype for notifying the application about changes of publish states. -**/ +**/ typedef void (*LinphoneCorePublishStateChangedCb)(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state); /** @@ -125,7 +125,6 @@ LINPHONE_PUBLIC LinphoneEvent *linphone_core_subscribe(LinphoneCore *lc, const L * @param resource the destination resource * @param event the event name * @param expires the whished duration of the subscription - * @param body an optional body, may be NULL. * @return a LinphoneEvent holding the context of the created subcription. **/ LINPHONE_PUBLIC LinphoneEvent *linphone_core_create_subscribe(LinphoneCore *lc, const LinphoneAddress *resource, const char *event, int expires); @@ -258,7 +257,7 @@ LINPHONE_PUBLIC const char *linphone_event_get_custom_header(LinphoneEvent *ev, /** * Terminate an incoming or outgoing subscription that was previously acccepted, or a previous publication. * This function does not unref the object. The core will unref() if it does not need this object anymore. - * + * * For subscribed event, when the subscription is terminated normally or because of an error, the core will unref. * For published events, no unref is performed. This is because it is allowed to re-publish an expired publish, as well as retry it in case of error. **/ @@ -270,7 +269,7 @@ LINPHONE_PUBLIC void linphone_event_terminate(LinphoneEvent *lev); * By default LinphoneEvents created by the core are owned by the core only. * An application that wishes to retain a reference to it must call linphone_event_ref(). * When this reference is no longer needed, linphone_event_unref() must be called. - * + * **/ LINPHONE_PUBLIC LinphoneEvent *linphone_event_ref(LinphoneEvent *lev); diff --git a/coreapi/linphone_tunnel.h b/coreapi/linphone_tunnel.h index cff8fc532..9b33e32f8 100644 --- a/coreapi/linphone_tunnel.h +++ b/coreapi/linphone_tunnel.h @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + #ifndef LINPHONETUNNEL_H #define LINPHONETUNNEL_H @@ -86,7 +86,7 @@ LINPHONE_PUBLIC void linphone_tunnel_config_set_port(LinphoneTunnelConfig *tunne LINPHONE_PUBLIC int linphone_tunnel_config_get_port(const LinphoneTunnelConfig *tunnel); /** - * Set the remote port on the tunnel server side used to test udp reachability. + * Set the remote port on the tunnel server side used to test udp reachability. * * @param tunnel configuration object * @param remote_udp_mirror_port remote port on the tunnel server side used to test udp reachability, set to -1 to disable the feature @@ -110,7 +110,7 @@ LINPHONE_PUBLIC void linphone_tunnel_config_set_delay(LinphoneTunnelConfig *tunn /** * Get the udp packet round trip delay in ms for a tunnel configuration. - * + * * @param tunnel configuration object */ LINPHONE_PUBLIC int linphone_tunnel_config_get_delay(const LinphoneTunnelConfig *tunnel); @@ -132,7 +132,7 @@ LINPHONE_PUBLIC void linphone_tunnel_add_server(LinphoneTunnel *tunnel, Linphone /** * Remove tunnel server configuration - * + * * @param tunnel object * @param tunnel_config object */ @@ -208,7 +208,7 @@ LINPHONE_PUBLIC bool_t linphone_tunnel_auto_detect_enabled(LinphoneTunnel *tunne * @param host Http proxy host. * @param port http proxy port. * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. - * @param password optional http proxy password. Use NULL if not needed. + * @param passwd optional http proxy password. Use NULL if not needed. **/ LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd); @@ -218,7 +218,7 @@ LINPHONE_PUBLIC void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, cons * @param host Http proxy host. * @param port http proxy port. * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed. - * @param password optional http proxy password. Use NULL if not needed. + * @param passwd optional http proxy password. Use NULL if not needed. **/ LINPHONE_PUBLIC void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2c6c188b4..7fa8b5fc5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1447,7 +1447,7 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam * Set requested level of privacy for the call. * \xmlonly javascript \endxmlonly * @param params the call parameters to be modified - * @param LinphonePrivacy to configure privacy + * @param privacy LinphonePrivacy to configure privacy * */ void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) { params->privacy=privacy; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0183979a5..5c4e51ddf 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2037,6 +2037,7 @@ int linphone_core_get_sip_transports(LinphoneCore *lc, LCSipTransports *tr){ * A zero value means that the transport is not activated. * If LC_SIP_TRANSPORT_RANDOM was passed to linphone_core_set_sip_transports(), the random port choosed by the system is returned. * @ingroup network_parameters + * @param lc the LinphoneCore * @param tr a LCSipTransports structure. **/ void linphone_core_get_sip_transports_used(LinphoneCore *lc, LCSipTransports *tr){ @@ -2914,7 +2915,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const * * It is possible to follow the progress of the transfer provided that transferee sends notification about it. * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. - * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected. **/ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char *url) { @@ -3147,7 +3148,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho #if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) bool_t has_video = FALSE; #endif - + switch(call->state){ case LinphoneCallIncomingEarlyMedia: case LinphoneCallIncomingReceived: @@ -3158,7 +3159,7 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho ms_error("linphone_core_update_call() is not allowed in [%s] state",linphone_call_state_to_string(call->state)); return -1; } - + if (params!=NULL){ linphone_call_set_state(call,LinphoneCallUpdating,"Updating call"); #if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) @@ -5614,6 +5615,7 @@ void linphone_core_set_rtp_transport_factories(LinphoneCore* lc, LinphoneRtpTran /** * Retrieve RTP statistics regarding current call. + * @param lc the LinphoneCore * @param local RTP statistics computed locally. * @param remote RTP statistics computed by far end (obtained via RTCP feedback). * diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index bb35fc98c..debf48461 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -819,7 +819,7 @@ LINPHONE_PUBLIC void linphone_proxy_config_enable_publish(LinphoneProxyConfig *o /** * Set the publish expiration time in second. * @param obj proxy config - * @param exires in second + * @param expires in second * */ LINPHONE_PUBLIC void linphone_proxy_config_set_publish_expires(LinphoneProxyConfig *obj, int expires); @@ -964,7 +964,7 @@ LINPHONE_PUBLIC void * linphone_proxy_config_get_user_data(LinphoneProxyConfig * /** * Set default privacy policy for all calls routed through this proxy. * @param params to be modified - * @param LinphonePrivacy to configure privacy + * @param privacy LinphonePrivacy to configure privacy * */ LINPHONE_PUBLIC void linphone_proxy_config_set_privacy(LinphoneProxyConfig *params, LinphonePrivacyMask privacy); /** @@ -1581,7 +1581,7 @@ LINPHONE_PUBLIC int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneC /** * @ingroup media_parameters * Get default call parameters reflecting current linphone core configuration - * @param LinphoneCore object + * @param lc LinphoneCore object * @return LinphoneCallParams */ LINPHONE_PUBLIC LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc); @@ -2023,7 +2023,7 @@ LINPHONE_PUBLIC void linphone_core_mute_mic(LinphoneCore *lc, bool_t muted); /** * Get mic state. - * @deprecated Use #linphone_core_is_mic_enabled instead + * @deprecated Use #linphone_core_mic_enabled instead **/ LINPHONE_PUBLIC bool_t linphone_core_is_mic_muted(LinphoneCore *lc); diff --git a/coreapi/linphonepresence.h b/coreapi/linphonepresence.h index 851ccf63e..780ae22b6 100644 --- a/coreapi/linphonepresence.h +++ b/coreapi/linphonepresence.h @@ -426,7 +426,7 @@ LINPHONE_PUBLIC int linphone_presence_model_clear_persons(LinphonePresenceModel * * The created presence service has the basic status 'closed'. */ -LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus, const char *contact); +LINPHONE_PUBLIC LinphonePresenceService * linphone_presence_service_new(const char *id, LinphonePresenceBasicStatus basic_status, const char *contact); /** * Gets the id of a presence service. diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 3772bc744..6b23eebdd 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1029,7 +1029,7 @@ void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, cons /** * Set optional contact parameters that will be added to the contact information sent in the registration, inside the URI. * @param obj the proxy config object - * @param contact_params a string contaning the additional parameters in text form, like "myparam=something;myparam2=something_else" + * @param contact_uri_params a string containing the additional parameters in text form, like "myparam=something;myparam2=something_else" * * The main use case for this function is provide the proxy additional information regarding the user agent, like for example unique identifier or apple push id. * As an example, the contact address in the SIP register sent will look like . diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 81241efd1..4d1108077 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -36,7 +36,6 @@ moslq == moscq valgrind video: what happens if doing stop/resume? one single report <- merge audio/video? -unit test interval report rlq value: need algo to compute it 3.4 overload avoidance? From 728e76cdfb0cbfe4a5efbf933188bb170a1a591d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 5 Jun 2014 17:50:17 +0200 Subject: [PATCH 082/201] redisplay failed test at the end of all tests --- mediastreamer2 | 2 +- tester/tester.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index f7eab3265..3dbbb2367 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f7eab3265577feb885dba012d34a10f1b9be072b +Subproject commit 3dbbb23674085d116c4b43063f3cf082b08565ae diff --git a/tester/tester.c b/tester/tester.c index 1cc4acebc..dd17c9190 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -403,6 +403,13 @@ int liblinphone_tester_run_tests(const char *suite_name, const char *test_name) } ret=CU_get_number_of_tests_failed()!=0; + + /* Redisplay list of failed tests on end */ + if (CU_get_number_of_failure_records()){ + CU_basic_show_failures(CU_get_failure_list()); + printf("\n"); + } + CU_cleanup_registry(); return ret; } From fe2e927642fb60086d6f5ca52ca8746d0bc1f5e8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 5 Jun 2014 20:52:05 +0200 Subject: [PATCH 083/201] fix memleak --- tester/call_tester.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tester/call_tester.c b/tester/call_tester.c index 7e2617ca3..bede109ed 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -967,6 +967,9 @@ static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* ma CU_ASSERT_TRUE(call_with_params(pauline,marie,caller_params,callee_params)); marie_call=linphone_core_get_current_call(marie->lc); pauline_call=linphone_core_get_current_call(pauline->lc); + + linphone_call_params_destroy(caller_params); + linphone_call_params_destroy(callee_params); if (marie_call && pauline_call ) { CU_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(marie_call))); From 2f8244d39b12297f86fddd314fb302450ba067a8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 6 Jun 2014 10:07:25 +0200 Subject: [PATCH 084/201] memory leak hunting --- coreapi/bellesip_sal/sal_impl.c | 5 ++--- coreapi/bellesip_sal/sal_op_call.c | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 6896496f7..92017616d 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -342,7 +342,6 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even break; case 401: case 407: - /*belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),NULL);*//*remove op from trans*/ if (op->state == SalOpStateTerminating && strcmp("BYE",belle_sip_request_get_method(request))!=0) { /*only bye are completed*/ belle_sip_message("Op is in state terminating, nothing else to do "); @@ -396,7 +395,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans if(client_transaction) trans=BELLE_SIP_TRANSACTION(client_transaction); else - trans=BELLE_SIP_TRANSACTION(server_transaction); + trans=BELLE_SIP_TRANSACTION(server_transaction); op = (SalOp*)belle_sip_transaction_get_application_data(trans); if (op && op->callbacks && op->callbacks->process_transaction_terminated) { @@ -404,7 +403,7 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } else { ms_message("Unhandled transaction terminated [%p]",trans); } - if (op && client_transaction) sal_op_unref(op); /*because every client transaction ref op*/ + if (op) sal_op_unref(op); /*because every transaction ref op*/ } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f8d35e15c..4d61feca9 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -427,8 +427,7 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t if (strcmp("ACK",method)!=0){ /*ACK does'nt create srv transaction*/ server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); belle_sip_object_ref(server_transaction); - belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),op); - sal_op_ref(op); + belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(server_transaction),sal_op_ref(op)); } if (strcmp("INVITE",method)==0) { From fbb56c4c710c7736bcfb2599063a37dd6d36941e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 6 Jun 2014 11:24:05 +0200 Subject: [PATCH 085/201] update submodules --- coreapi/quality_reporting.c | 14 +++++++------- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 4d1108077..102f38c9e 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -393,7 +393,7 @@ static bool_t is_reporting_enabled(const LinphoneCall * call) { return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); } -static void qos_analyser_on_action_suggested(void *user_data, const char * input, const char * output){ +static void qos_analyzer_on_action_suggested(void *user_data, const char * input, const char * output){ reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; char * newstr = NULL; newstr = ms_strdup_printf("%s%s;", metrics->qos_analyzer.input?metrics->qos_analyzer.input:"", input); @@ -485,7 +485,7 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->log->reports[stats_type]; reporting_content_metrics_t * metrics = NULL; - MSQosAnalyser *analyser=NULL; + MSQosAnalyzer *analyzer=NULL; LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; @@ -505,11 +505,11 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { block = stats.sent_rtcp; } } - if (call->audiostream->ms.rc){ - analyser=ms_bitrate_controller_get_qos_analyser(call->audiostream->ms.rc); - if (analyser){ - ms_qos_analyser_set_on_action_suggested(analyser, - qos_analyser_on_action_suggested, + if (call->audiostream->ms.use_rc&&call->audiostream->ms.rc){ + analyzer=ms_bitrate_controller_get_qos_analyzer(call->audiostream->ms.rc); + if (analyzer){ + ms_qos_analyzer_set_on_action_suggested(analyzer, + qos_analyzer_on_action_suggested, &report->local_metrics); } } diff --git a/mediastreamer2 b/mediastreamer2 index 3dbbb2367..c3529c41b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3dbbb23674085d116c4b43063f3cf082b08565ae +Subproject commit c3529c41b46ae5e099566462b3fb7f055441ddfb diff --git a/oRTP b/oRTP index ec4c194c6..c889f49b6 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit ec4c194c62a9657f075d07dc2495f98914ee0b8b +Subproject commit c889f49b6c6367b2c3ccb44fa74a70e73dd1b575 From 721d35d5f02f208a818d1acc24a79fef3999b166 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 6 Jun 2014 15:24:54 +0200 Subject: [PATCH 086/201] Update oRTP submodule. --- oRTP | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oRTP b/oRTP index c889f49b6..f0fa4ba94 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit c889f49b6c6367b2c3ccb44fa74a70e73dd1b575 +Subproject commit f0fa4ba94d2b5b44d5348701177c0cf8931bdc93 From 17f113d30f11fdc9c0ef0854777bfc1176797946 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 6 Jun 2014 15:25:15 +0200 Subject: [PATCH 087/201] Add configuration of AVPF in the proxy config GTK dialog. --- gtk/propertybox.c | 10 +++++++++ gtk/sip_account.ui | 54 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 81d3db345..23211fa3b 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -922,6 +922,10 @@ void linphone_gtk_show_proxy_config(GtkWidget *pb, LinphoneProxyConfig *cfg){ linphone_proxy_config_register_enabled(cfg)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"publish")), linphone_proxy_config_publish_enabled(cfg)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf")), + linphone_proxy_config_avpf_enabled(cfg)); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval")), + linphone_proxy_config_get_avpf_rr_interval(cfg)); } g_object_set_data(G_OBJECT(w),"config",(gpointer)cfg); g_object_set_data(G_OBJECT(w),"parameters",(gpointer)pb); @@ -978,6 +982,12 @@ void linphone_gtk_proxy_ok(GtkButton *button){ linphone_proxy_config_enable_register(cfg, gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"register")))); + linphone_proxy_config_enable_avpf(cfg, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(w,"avpf")))); + linphone_proxy_config_set_avpf_rr_interval(cfg, + (int)gtk_spin_button_get_value( + GTK_SPIN_BUTTON(linphone_gtk_get_widget(w,"avpf_rr_interval")))); /* check if tls was asked but is not enabled in transport configuration*/ if (tport==LinphoneTransportTls){ diff --git a/gtk/sip_account.ui b/gtk/sip_account.ui index d0a93d5dc..6d03932d1 100644 --- a/gtk/sip_account.ui +++ b/gtk/sip_account.ui @@ -8,6 +8,13 @@ 1 10 + + 5 + 1 + 5 + 1 + 1 + False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -235,6 +242,37 @@ 6 + + + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + AVPF regular RTCP interval (sec): + right + + + 6 + 7 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + False + True + True + adjustment2 + + + 1 + 2 + 6 + 7 + + True @@ -311,6 +349,22 @@ 2 + + + Enable AVPF + True + True + False + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + False + True + + + False + True + 3 + + From 33794b1a1453c3ad848a5aa6c3df76c5155127e8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 6 Jun 2014 15:58:47 +0200 Subject: [PATCH 088/201] update mediastreamer2 and ortp (loss rate estimator) --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index c3529c41b..4b156f31e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c3529c41b46ae5e099566462b3fb7f055441ddfb +Subproject commit 4b156f31e41eab5ac34dd0cefffa9ff40eeefc0c diff --git a/oRTP b/oRTP index f0fa4ba94..9d85ca0e1 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit f0fa4ba94d2b5b44d5348701177c0cf8931bdc93 +Subproject commit 9d85ca0e1a117a2fbfb02de8df3b19bd5eb5db81 From 134a4cd91489858598570a6ee1331c6ee5863297 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 6 Jun 2014 14:52:05 +0200 Subject: [PATCH 089/201] fix invalid memory access and add warning about memory leak in quality reporting --- coreapi/quality_reporting.c | 24 ++++++++++++------------ tester/call_tester.c | 10 ++++++---- tester/liblinphone_tester.c | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 102f38c9e..e0f21d377 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,20 +31,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST *************************************************************************** -For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). -moslq == moscq -valgrind -video: what happens if doing stop/resume? -one single report <- merge audio/video? -rlq value: need algo to compute it -3.4 overload avoidance? + For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). + moslq == moscq + rlq value: need algo to compute it - - The Session report when session terminates, media change (codec change or a session fork), session terminates due to no media packets being received - - The Interval report SHOULD be used for periodic or interval reporting + 3.4 overload avoidance? + a. Send only one report at the end of each call. (audio | video?) + b. Use interval reports only on "problem" calls that are being closely monitored. - -> avg values - -> interval report - -> custom metrics + + - The Session report when + codec change + session fork + video enable/disable <-- what happens if doing stop/resume? *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -340,6 +339,7 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r content.data = buffer; content.size = strlen(buffer); + /*(WIP) Memory leak: PUBLISH message is never freed (issue 1283)*/ linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); linphone_address_destroy(addr); diff --git a/tester/call_tester.c b/tester/call_tester.c index bede109ed..0548c7c1e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -576,7 +576,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee } ms_usleep(50000); } - + if (video_enabled){ for (i=0;i<200;i++){ if ((c1 != NULL) && (c2 != NULL)) { @@ -967,7 +967,7 @@ static void video_call_base(LinphoneCoreManager* pauline,LinphoneCoreManager* ma CU_ASSERT_TRUE(call_with_params(pauline,marie,caller_params,callee_params)); marie_call=linphone_core_get_current_call(marie->lc); pauline_call=linphone_core_get_current_call(pauline->lc); - + linphone_call_params_destroy(caller_params); linphone_call_params_destroy(callee_params); @@ -2213,14 +2213,16 @@ static void quality_reporting_at_call_termination() { create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); linphone_core_terminate_all_calls(marie->lc); + + // now dialog id should be filled + CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->dialog_id); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); CU_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); CU_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc)); CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc)); - // now dialog id should be filled - CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->dialog_id); // PUBLISH submission to the collector should be ok CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index c5d017566..825e16727 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -119,7 +119,7 @@ static void liblinphone_tester_qnx_log_handler(OrtpLogLevel lev, const char *fmt void helper(const char *name) { - fprintf(stderr,"%s \t--help\n" + fprintf(stderr,"%s --help\n" "\t\t\t--verbose\n" "\t\t\t--silent\n" "\t\t\t--list-suites\n" From 13ecaf7a91fddd49d5f556a1c479fd2861b7f663 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 6 Jun 2014 16:45:46 +0200 Subject: [PATCH 090/201] Quality reporting: fix RTCP-XR packets processing --- coreapi/quality_reporting.c | 57 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index e0f21d377..25ef43059 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -32,18 +32,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * TODO / REMINDER LIST *************************************************************************** For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). - moslq == moscq + rlq value: need algo to compute it 3.4 overload avoidance? a. Send only one report at the end of each call. (audio | video?) b. Use interval reports only on "problem" calls that are being closely monitored. + move "on_action_suggested" stuff in init - The Session report when codec change session fork video enable/disable <-- what happens if doing stop/resume? + + + if BYE and continue received packet drop them *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -250,8 +254,8 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off /*if quality estimates metrics are available, rtcp_xr_count should be always not null*/ if ((available_metrics & METRICS_QUALITY_ESTIMATES) != 0){ - IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq)); - IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq)); + IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq/rm.rtcp_xr_count)); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq/rm.rtcp_xr_count)); append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq/rm.rtcp_xr_count, 1, 120); @@ -496,15 +500,12 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { metrics = &report->remote_metrics; - if (rtcp_is_XR(stats.received_rtcp) == TRUE) { - block = stats.received_rtcp; - } + block = stats.received_rtcp; } else if (stats.updated == LINPHONE_CALL_STATS_SENT_RTCP_UPDATE) { metrics = &report->local_metrics; - if (rtcp_is_XR(stats.sent_rtcp) == TRUE) { - block = stats.sent_rtcp; - } + block = stats.sent_rtcp; } + /*should not be done there*/ if (call->audiostream->ms.use_rc&&call->audiostream->ms.rc){ analyzer=ms_bitrate_controller_get_qos_analyzer(call->audiostream->ms.rc); if (analyzer){ @@ -514,33 +515,29 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { } } - if (block != NULL) { - switch (rtcp_XR_get_block_type(block)) { - case RTCP_XR_VOIP_METRICS: { - uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block); + do{ + if (rtcp_is_XR(block) && (rtcp_XR_get_block_type(block) == RTCP_XR_VOIP_METRICS)){ - metrics->rtcp_xr_count++; + uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block); - metrics->quality_estimates.rcq += rtcp_XR_voip_metrics_get_r_factor(block); - metrics->quality_estimates.moslq += rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; - metrics->quality_estimates.moscq += rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + metrics->rtcp_xr_count++; - metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block); - metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block); - metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block); - metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; - metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block); - metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block); + metrics->quality_estimates.rcq += rtcp_XR_voip_metrics_get_r_factor(block); + metrics->quality_estimates.moslq += rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; + metrics->quality_estimates.moscq += rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; - metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; + metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block); + metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block); + metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block); + metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; + metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block); + metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block); - metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block); - break; - } default: { - break; - } + metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; + + metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block); } - } + }while(rtcp_next_packet(block)); /* check if we should send an interval report */ if (report_interval>0 && ms_time(NULL)-report->last_report_date>report_interval){ From 94da3680bedf037d81bceff3536071e79b1c18ee Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 6 Jun 2014 17:02:06 +0200 Subject: [PATCH 091/201] Quality reporting: factorizing some functions --- coreapi/quality_reporting.c | 73 ++++++++++++++++--------------------- tester/call_tester.c | 4 +- 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 25ef43059..79557dc37 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -174,6 +174,20 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { return ret; } +static bool_t quality_reporting_enabled(const LinphoneCall * call) { + return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); +} + +static bool_t media_report_enabled(LinphoneCall * call, int stats_type){ + if (! quality_reporting_enabled(call)) + return FALSE; + + if (stats_type == LINPHONE_CALL_STATS_VIDEO && !linphone_call_params_video_enabled(linphone_call_get_current_params(call))) + return FALSE; + + return (call->log->reports[stats_type] != NULL); +} + static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) { char * timestamps_start_str = NULL; char * timestamps_stop_str = NULL; @@ -360,16 +374,14 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc } } } - if (smd == NULL || count == smd->n_total_streams) { - ms_warning("Could not find the associated stream of type %d", sal_stream_type); - } + ms_warning("Could not find the associated stream of type %d", sal_stream_type); return NULL; } static void update_ip(LinphoneCall * call, int stats_type) { SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; - if (call->log->reports[stats_type] != NULL) { + if (media_report_enabled(call,stats_type)) { const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type); @@ -393,10 +405,6 @@ static void update_ip(LinphoneCall * call, int stats_type) { } } -static bool_t is_reporting_enabled(const LinphoneCall * call) { - return (call->dest_proxy != NULL && linphone_proxy_config_quality_reporting_enabled(call->dest_proxy)); -} - static void qos_analyzer_on_action_suggested(void *user_data, const char * input, const char * output){ reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; char * newstr = NULL; @@ -408,24 +416,18 @@ static void qos_analyzer_on_action_suggested(void *user_data, const char * input } void linphone_reporting_update_ip(LinphoneCall * call) { - if (! is_reporting_enabled(call)) - return; - update_ip(call, LINPHONE_CALL_STATS_AUDIO); - - if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { - update_ip(call, LINPHONE_CALL_STATS_VIDEO); - } + update_ip(call, LINPHONE_CALL_STATS_VIDEO); } void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { - reporting_session_report_t * report = call->log->reports[stats_type]; MediaStream * stream = NULL; const PayloadType * local_payload = NULL; const PayloadType * remote_payload = NULL; const LinphoneCallParams * current_params = linphone_call_get_current_params(call); + reporting_session_report_t * report = call->log->reports[stats_type]; - if (! is_reporting_enabled(call)) + if (!media_report_enabled(call, stats_type)) return; STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); @@ -495,7 +497,7 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { int report_interval = linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy); - if (! is_reporting_enabled(call)) + if (! media_report_enabled(call,stats_type)) return; if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { @@ -545,34 +547,21 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { } } +static void publish_report(LinphoneCall *call, const char *event_type){ + int i; + for (i = 0; i < 2; i++){ + if (media_report_enabled(call, i)){ + linphone_reporting_update_media_info(call, i); + send_report(call, call->log->reports[i], event_type); + } + } +} void linphone_reporting_publish_session_report(LinphoneCall* call) { - if (! is_reporting_enabled(call)) - return; - - if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { - send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO], "VQSessionReport: CallTerm"); - } - - if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL - && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { - send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport: CallTerm"); - } + publish_report(call, "VQSessionReport: CallTerm"); } void linphone_reporting_publish_interval_report(LinphoneCall* call) { - if (! is_reporting_enabled(call)) - return; - - if (call->log->reports[LINPHONE_CALL_STATS_AUDIO] != NULL) { - linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); - send_report(call, call->log->reports[LINPHONE_CALL_STATS_AUDIO], "VQIntervalReport"); - } - - if (call->log->reports[LINPHONE_CALL_STATS_VIDEO] != NULL - && linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { - linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO); - send_report(call, call->log->reports[LINPHONE_CALL_STATS_VIDEO], "VQIntervalReport"); - } + publish_report(call, "VQIntervalReport"); } reporting_session_report_t * linphone_reporting_new() { diff --git a/tester/call_tester.c b/tester/call_tester.c index 0548c7c1e..b5feb834e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2245,8 +2245,8 @@ static void quality_reporting_interval_report() { CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc)); // PUBLISH submission to the collector should be ok - CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,3,15000)); - CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,3,15000)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,3,25000)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,3,25000)); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); From e98ad8e4a630b1e48b7851a64a2db3f85fad8c0d Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Sun, 8 Jun 2014 23:27:03 +0200 Subject: [PATCH 092/201] Add test for file transfer to liblinphone tester --- tester/liblinphone_tester.h | 3 + tester/message_tester.c | 116 +++++++++++++++++++++++++++++++++++- tester/tester.c | 3 + 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 5e5767bab..e7c77066b 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -208,6 +208,9 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, void notify_presence_received(LinphoneCore *lc, LinphoneFriend * lf); void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message); void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage* message); +void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size); +void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size); +void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t progress); void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room); void info_message_received(LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg); void new_subscription_requested(LinphoneCore *lc, LinphoneFriend *lf, const char *url); diff --git a/tester/message_tester.c b/tester/message_tester.c index 8568492d4..e7b78d00b 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -35,18 +35,90 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess stats* counters; const char *text=linphone_chat_message_get_text(message); const char *external_body_url=linphone_chat_message_get_external_body_url(message); + const LinphoneContent *file_transfer_info=linphone_chat_message_get_file_transfer_information(message); + ms_message("Message from [%s] is [%s] , external URL [%s]",from?from:"" ,text?text:"" ,external_body_url?external_body_url:""); ms_free(from); counters = get_stats(lc); counters->number_of_LinphoneMessageReceived++; - if (linphone_chat_message_get_external_body_url(message)) { + if (file_transfer_info) { /* if we have a file transfer in RCS mode, start the download */ + linphone_chat_message_start_file_download(message); + } else if (linphone_chat_message_get_external_body_url(message)) { counters->number_of_LinphoneMessageExtBodyReceived++; CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); } } +/** + * function invoked when a file transfer is received. + * */ +void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){ + int file=-1; + if (!linphone_chat_message_get_user_data(message)) { + /*first chunk, creating file*/ + file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); + linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/ + } else { + /*next chunk*/ + file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + } + + if (size==0) { + linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); + linphone_chat_message_destroy(message); + stats* counters = get_stats(lc); + counters->number_of_LinphoneMessageExtBodyReceived++; + close(file); + } else { /* store content on a file*/ + write(file,buff,size); + } +} + +static char big_file [128000]; /* a buffer to simulate a big file for the file transfer message test */ + +/* + * function called when the file transfer is initiated. file content should be feed into object LinphoneContent + * */ +void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){ + int offset=-1; + + if (!linphone_chat_message_get_user_data(message)) { + /*first chunk*/ + offset=0; + } else { + /*subsequent chunk*/ + offset = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + } + *size = MIN(*size,sizeof(big_file)-offset); /*updating content->size with minimun between remaining data and requested size*/ + + if (*size==0) { + /*end of file*/ + return; + } + memcpy(buff,big_file+offset,*size); + + /*store offset for next chunk*/ + linphone_chat_message_set_user_data(message,(void*)(offset+*size)); +} + +/** + * function invoked to report file transfer progress. + * */ +void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t progress) { + const LinphoneAddress* from_address = linphone_chat_message_get_from(message); + const LinphoneAddress* to_address = linphone_chat_message_get_to(message); + char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); + printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)progress + ,(linphone_chat_message_is_outgoing(message)?"sent":"received") + , content->type + , content->subtype + ,(linphone_chat_message_is_outgoing(message)?"to":"from") + , address); + free(address); +} + void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { stats *counters = get_stats(lc); if (room->remote_is_composing == LinphoneIsComposingActive) { @@ -244,6 +316,47 @@ static void text_message_with_external_body(void) { linphone_core_manager_destroy(pauline); } +static void file_transfer_message(void) { + int i; + /* setting dummy file content to something */ + + const char* big_file_content="big file"; + for (i=0;ilc,"http://npasc.al/lft.php"); + + /* create a chatroom on pauline's side */ + char* to = linphone_address_as_string(marie->identity); + LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + + /* create a file transfer message */ + LinphoneContent content; + memset(&content,0,sizeof(content)); + content.type="text"; + content.subtype="plain"; + content.size=sizeof(big_file); /*total size to be transfered*/ + content.name = "bigfile.txt"; + LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,1); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void text_message_with_send_error(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -379,6 +492,7 @@ test_t message_tests[] = { { "Text message with ack", text_message_with_ack }, { "Text message with send error", text_message_with_send_error }, { "Text message with external body", text_message_with_external_body }, + { "File transfer message", file_transfer_message }, { "Text message denied", text_message_denied }, { "Info message", info_message }, { "Info message with body", info_message_with_body }, diff --git a/tester/tester.c b/tester/tester.c index 3623073e4..3794d707f 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -196,6 +196,9 @@ LinphoneCoreManager* linphone_core_manager_new2(const char* rc_file, int check_f mgr->v_table.call_state_changed=call_state_changed; mgr->v_table.text_received=text_message_received; mgr->v_table.message_received=message_received; + mgr->v_table.file_transfer_received=file_transfer_received; + mgr->v_table.file_transfer_send=file_transfer_send; + mgr->v_table.file_transfer_progress_indication=file_transfer_progress_indication; mgr->v_table.is_composing_received=is_composing_received; mgr->v_table.new_subscription_requested=new_subscription_requested; mgr->v_table.notify_presence_received=notify_presence_received; From 44aa4a821b8e2dac8b77aed3900d9d51505439d7 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 9 Jun 2014 11:02:13 +0200 Subject: [PATCH 093/201] Hide wizard button in preferences if Linphone has been build without wizard support. --- gtk/propertybox.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gtk/propertybox.c b/gtk/propertybox.c index 23211fa3b..7ed960c46 100644 --- a/gtk/propertybox.c +++ b/gtk/propertybox.c @@ -1483,6 +1483,8 @@ void linphone_gtk_show_parameters(void){ } #ifdef BUILD_WIZARD gtk_widget_show(linphone_gtk_get_widget(pb,"wizard")); +#else + gtk_widget_hide(linphone_gtk_get_widget(pb,"wizard")); #endif linphone_gtk_show_sip_accounts(pb); /* CODECS CONFIG */ From c913816dee591ea7d8feff14b2f95e016bd5f88a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Jun 2014 11:04:41 +0200 Subject: [PATCH 094/201] java synchronize LinphoneEvent and LinphoneChatRoom APIs with LinphoneCore --- coreapi/chat.c | 8 ++ coreapi/linphonecore.h | 1 + coreapi/linphonecore_jni.cc | 15 ++++ .../org/linphone/core/LinphoneChatRoom.java | 5 ++ .../org/linphone/core/LinphoneEvent.java | 6 ++ .../linphone/core/LinphoneChatRoomImpl.java | 5 ++ .../org/linphone/core/LinphoneCoreImpl.java | 12 +-- .../org/linphone/core/LinphoneEventImpl.java | 84 ++++++++++++------- 8 files changed, 99 insertions(+), 37 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index c20cfef9e..9e2ce9a69 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -387,11 +387,19 @@ bool_t linphone_chat_room_is_remote_composing(const LinphoneChatRoom *cr) { /** * Returns back pointer to LinphoneCore object. + * @deprecated use linphone_chat_room_get_core() **/ LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr){ return cr->lc; } +/** + * Returns back pointer to LinphoneCore object. +**/ +LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr){ + return cr->lc; +} + /** * Assign a user pointer to the chat room. **/ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index debf48461..c35776c1d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1158,6 +1158,7 @@ LINPHONE_PUBLIC bool_t linphone_chat_room_is_remote_composing(const LinphoneChat LINPHONE_PUBLIC int linphone_chat_room_get_unread_messages_count(LinphoneChatRoom *cr); LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); +LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr); LINPHONE_PUBLIC void linphone_chat_room_set_user_data(LinphoneChatRoom *cr, void * ud); LINPHONE_PUBLIC void * linphone_chat_room_get_user_data(LinphoneChatRoom *cr); LINPHONE_PUBLIC MSList* linphone_core_get_chat_rooms(LinphoneCore *lc); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index a24d2c589..919c813a9 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2630,6 +2630,15 @@ static void chat_room_impl_callback(LinphoneChatMessage* msg, LinphoneChatMessag linphone_chat_message_set_user_data(msg,NULL); } } + +extern "C" jobject Java_org_linphone_core_LinphoneChatRoomImpl_getCore(JNIEnv* env + ,jobject thiz + ,jlong chatroom_ptr){ + LinphoneCore *lc=linphone_chat_room_get_core((LinphoneChatRoom*)chatroom_ptr); + LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data(lc); + return lcd->core; +} + extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* env ,jobject thiz ,jlong chatroom_ptr @@ -3669,6 +3678,12 @@ JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCoreFactoryImpl__1setLogHa } } +JNIEXPORT jobject JNICALL Java_org_linphone_core_LinphoneEventImpl_getCore(JNIEnv *env, jobject jobj, jlong evptr){ + LinphoneCore *lc=linphone_event_get_core((LinphoneEvent*)evptr); + LinphoneCoreData *lcd=(LinphoneCoreData*)linphone_core_get_user_data(lc); + return lcd->core; +} + /* * Class: org_linphone_core_LinphoneEventImpl * Method: getEventName diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index e84538269..c1e635c0a 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -114,4 +114,9 @@ public interface LinphoneChatRoom { * @return LinphoneChatMessage object */ LinphoneChatMessage createLinphoneChatMessage(String message, String url, State state, long timestamp, boolean isRead, boolean isIncoming); + /** + * Returns a back pointer to the core managing the chat room. + * @return the LinphoneCore + */ + LinphoneCore getCore(); } diff --git a/java/common/org/linphone/core/LinphoneEvent.java b/java/common/org/linphone/core/LinphoneEvent.java index dcdfcfc48..cca9a3f2d 100644 --- a/java/common/org/linphone/core/LinphoneEvent.java +++ b/java/common/org/linphone/core/LinphoneEvent.java @@ -100,4 +100,10 @@ public interface LinphoneEvent { * @param body the new data to be published */ void sendPublish(LinphoneContent body); + + /** + * Get a back pointer to the LinphoneCore object managing this LinphoneEvent. + * @return + */ + LinphoneCore getCore(); } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 7901272c9..003cdd076 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -119,4 +119,9 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { return new LinphoneChatMessageImpl(createLinphoneChatMessage2( nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); } + private native Object getCore(long nativePtr); + @Override + public LinphoneCore getCore() { + return (LinphoneCore)getCore(nativePtr); + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 8cd5fe79e..bf43810a3 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -610,13 +610,13 @@ class LinphoneCoreImpl implements LinphoneCore { public synchronized void enableEchoLimiter(boolean val) { enableEchoLimiter(nativePtr,val); } - public void setVideoDevice(int id) { + public synchronized void setVideoDevice(int id) { Log.i("Setting camera id :", id); if (setVideoDevice(nativePtr, id) != 0) { Log.e("Failed to set video device to id:", id); } } - public int getVideoDevice() { + public synchronized int getVideoDevice() { return getVideoDevice(nativePtr); } @@ -847,7 +847,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void tunnelSetHttpProxy(long nativePtr, String proxy_host, int port, String username, String password); @Override - public void tunnelSetHttpProxy(String proxy_host, int port, + public synchronized void tunnelSetHttpProxy(String proxy_host, int port, String username, String password) { tunnelSetHttpProxy(nativePtr, proxy_host, port, username, password); } @@ -1185,17 +1185,17 @@ class LinphoneCoreImpl implements LinphoneCore { } @Override - public void stopRinging() { + public synchronized void stopRinging() { stopRinging(nativePtr); } private native void setPayloadTypeBitrate(long coreptr, long payload_ptr, int bitrate); @Override - public void setPayloadTypeBitrate(PayloadType pt, int bitrate) { + public synchronized void setPayloadTypeBitrate(PayloadType pt, int bitrate) { setPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr, bitrate); } private native int getPayloadTypeBitrate(long coreptr, long payload_ptr); @Override - public int getPayloadTypeBitrate(PayloadType pt) { + public synchronized int getPayloadTypeBitrate(PayloadType pt) { return getPayloadTypeBitrate(nativePtr, ((PayloadTypeImpl)pt).nativePtr); } diff --git a/java/impl/org/linphone/core/LinphoneEventImpl.java b/java/impl/org/linphone/core/LinphoneEventImpl.java index 2b4c1a71b..ca9c2151c 100644 --- a/java/impl/org/linphone/core/LinphoneEventImpl.java +++ b/java/impl/org/linphone/core/LinphoneEventImpl.java @@ -11,71 +11,83 @@ public class LinphoneEventImpl implements LinphoneEvent { private native String getEventName(long nativeptr); @Override - public String getEventName() { + public synchronized String getEventName() { return getEventName(mNativePtr); } private native int acceptSubscription(long nativeptr); @Override - public void acceptSubscription() { - acceptSubscription(mNativePtr); + public synchronized void acceptSubscription() { + synchronized(getCore()){ + acceptSubscription(mNativePtr); + } } private native int denySubscription(long nativeptr, int reason); @Override - public void denySubscription(Reason reason) { - denySubscription(mNativePtr,reason.mValue); + public synchronized void denySubscription(Reason reason) { + synchronized(getCore()){ + denySubscription(mNativePtr,reason.mValue); + } } private native int notify(long nativeptr, String type, String subtype, byte data[], String encoding); @Override - public void notify(LinphoneContent content) { - notify(mNativePtr,content.getType(),content.getSubtype(),content.getData(),content.getEncoding()); + public synchronized void notify(LinphoneContent content) { + synchronized(getCore()){ + notify(mNativePtr,content.getType(),content.getSubtype(),content.getData(),content.getEncoding()); + } } private native int updateSubscribe(long nativePtr, String type, String subtype, byte data[], String encoding); @Override - public void updateSubscribe(LinphoneContent content) { - updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); + public synchronized void updateSubscribe(LinphoneContent content) { + synchronized(getCore()){ + updateSubscribe(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); + } } private native int updatePublish(long nativePtr, String type, String subtype, byte data[], String encoding); @Override - public void updatePublish(LinphoneContent content) { - updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); + public synchronized void updatePublish(LinphoneContent content) { + synchronized(getCore()){ + updatePublish(mNativePtr,content.getType(), content.getSubtype(),content.getData(),content.getEncoding()); + } } private native int terminate(long nativePtr); @Override - public void terminate() { - terminate(mNativePtr); + public synchronized void terminate() { + synchronized(getCore()){ + terminate(mNativePtr); + } } private native int getReason(long nativePtr); @Override - public Reason getReason() { + public synchronized Reason getReason() { return Reason.fromInt(getReason(mNativePtr)); } @Override - public void setUserContext(Object obj) { + public synchronized void setUserContext(Object obj) { mUserContext=obj; } @Override - public Object getUserContext() { + public synchronized Object getUserContext() { return mUserContext; } private native int getSubscriptionDir(long nativeptr); @Override - public SubscriptionDir getSubscriptionDir() { + public synchronized SubscriptionDir getSubscriptionDir() { return SubscriptionDir.fromInt(getSubscriptionDir(mNativePtr)); } private native int getSubscriptionState(long nativeptr); @Override - public SubscriptionState getSubscriptionState() { + public synchronized SubscriptionState getSubscriptionState() { try { return SubscriptionState.fromInt(getSubscriptionState(mNativePtr)); } catch (LinphoneCoreException e) { @@ -91,37 +103,47 @@ public class LinphoneEventImpl implements LinphoneEvent { private native void addCustomHeader(long ptr, String name, String value); @Override - public void addCustomHeader(String name, String value) { + public synchronized void addCustomHeader(String name, String value) { addCustomHeader(mNativePtr, name, value); } private native String getCustomHeader(long ptr, String name); @Override - public String getCustomHeader(String name) { + public synchronized String getCustomHeader(String name) { return getCustomHeader(mNativePtr, name); } private native void sendSubscribe(long ptr, String type, String subtype, byte data [], String encoding); @Override - public void sendSubscribe(LinphoneContent body) { - if (body != null) - sendSubscribe(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); - else - sendSubscribe(mNativePtr, null, null, null, null); + public synchronized void sendSubscribe(LinphoneContent body) { + synchronized(getCore()){ + if (body != null) + sendSubscribe(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); + else + sendSubscribe(mNativePtr, null, null, null, null); + } } private native void sendPublish(long ptr, String type, String subtype, byte data [], String encoding); @Override - public void sendPublish(LinphoneContent body) { - if (body != null) - sendPublish(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); - else - sendPublish(mNativePtr, null, null, null, null); + public synchronized void sendPublish(LinphoneContent body) { + synchronized(getCore()){ + if (body != null) + sendPublish(mNativePtr, body.getType(), body.getSubtype(), body.getData(), body.getEncoding()); + else + sendPublish(mNativePtr, null, null, null, null); + } } private native long getErrorInfo(long nativePtr); @Override - public ErrorInfo getErrorInfo() { + public synchronized ErrorInfo getErrorInfo() { return new ErrorInfoImpl(getErrorInfo(mNativePtr)); } + private native Object getCore(long nativePtr); + @Override + public synchronized LinphoneCore getCore() { + return (LinphoneCore)getCore(mNativePtr); + } + } From 7d3031dd2304de7e95654ad1a9b0deb77ea66678 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Jun 2014 11:52:53 +0200 Subject: [PATCH 095/201] synchronisation in chatroom (lost in previous commit) --- .../linphone/core/LinphoneChatRoomImpl.java | 124 +++++++++++------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 003cdd076..8aa9c258d 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -44,84 +44,110 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { nativePtr = aNativePtr; } - public LinphoneAddress getPeerAddress() { + public synchronized LinphoneAddress getPeerAddress() { return new LinphoneAddressImpl(getPeerAddress(nativePtr),LinphoneAddressImpl.WrapMode.FromConst); } - public void sendMessage(String message) { - sendMessage(nativePtr,message); - } - - @Override - public void sendMessage(LinphoneChatMessage message, StateListener listener) { - sendMessage2(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr(), listener); - } - - @Override - public LinphoneChatMessage createLinphoneChatMessage(String message) { - return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message)); - } - - public LinphoneChatMessage[] getHistory() { - return getHistory(0); - } - - public LinphoneChatMessage[] getHistory(int limit) { - long[] typesPtr = getHistory(nativePtr, limit); - if (typesPtr == null) return null; - - LinphoneChatMessage[] messages = new LinphoneChatMessage[typesPtr.length]; - for (int i=0; i < messages.length; i++) { - messages[i] = new LinphoneChatMessageImpl(typesPtr[i]); + public synchronized void sendMessage(String message) { + synchronized(getCore()){ + sendMessage(nativePtr,message); } - - return messages; } - public void destroy() { + @Override + public synchronized void sendMessage(LinphoneChatMessage message, StateListener listener) { + synchronized(getCore()){ + sendMessage2(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr(), listener); + } + } + + @Override + public synchronized LinphoneChatMessage createLinphoneChatMessage(String message) { + synchronized(getCore()){ + return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message)); + } + } + + public synchronized LinphoneChatMessage[] getHistory() { + synchronized(getCore()){ + return getHistory(0); + } + } + + public synchronized LinphoneChatMessage[] getHistory(int limit) { + synchronized(getCore()){ + long[] typesPtr = getHistory(nativePtr, limit); + if (typesPtr == null) return null; + + LinphoneChatMessage[] messages = new LinphoneChatMessage[typesPtr.length]; + for (int i=0; i < messages.length; i++) { + messages[i] = new LinphoneChatMessageImpl(typesPtr[i]); + } + + return messages; + } + } + + public synchronized void destroy() { destroy(nativePtr); } - public int getUnreadMessagesCount() { - return getUnreadMessagesCount(nativePtr); + public synchronized int getUnreadMessagesCount() { + synchronized(getCore()){ + return getUnreadMessagesCount(nativePtr); + } } - public void deleteHistory() { - deleteHistory(nativePtr); + public synchronized void deleteHistory() { + synchronized(getCore()){ + deleteHistory(nativePtr); + } } - public void compose() { - compose(nativePtr); + public synchronized void compose() { + synchronized(getCore()){ + compose(nativePtr); + } } - public boolean isRemoteComposing() { - return isRemoteComposing(nativePtr); + public synchronized boolean isRemoteComposing() { + synchronized(getCore()){ + return isRemoteComposing(nativePtr); + } } - public void markAsRead() { - markAsRead(nativePtr); + public synchronized void markAsRead() { + synchronized(getCore()){ + markAsRead(nativePtr); + } } - public void deleteMessage(LinphoneChatMessage message) { - if (message != null) - deleteMessage(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr()); + public synchronized void deleteMessage(LinphoneChatMessage message) { + synchronized(getCore()){ + if (message != null) + deleteMessage(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr()); + } } - public void updateUrl(LinphoneChatMessage message) { - if (message != null) - updateUrl(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr()); + public synchronized void updateUrl(LinphoneChatMessage message) { + synchronized(getCore()){ + if (message != null) + updateUrl(nativePtr, ((LinphoneChatMessageImpl)message).getNativePtr()); + } } @Override - public LinphoneChatMessage createLinphoneChatMessage(String message, + public synchronized LinphoneChatMessage createLinphoneChatMessage(String message, String url, State state, long timestamp, boolean isRead, boolean isIncoming) { - return new LinphoneChatMessageImpl(createLinphoneChatMessage2( - nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); + synchronized(getCore()){ + return new LinphoneChatMessageImpl(createLinphoneChatMessage2( + nativePtr, message, url, state.value(), timestamp / 1000, isRead, isIncoming)); + } } private native Object getCore(long nativePtr); @Override - public LinphoneCore getCore() { + public synchronized LinphoneCore getCore() { return (LinphoneCore)getCore(nativePtr); } } From ba970baa9569a03aed531d4a53c035eb22219c45 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 9 Jun 2014 10:19:54 +0200 Subject: [PATCH 096/201] Quality reporting: split adaptive algorithm values and captions --- coreapi/quality_reporting.c | 21 +++++++++++++++------ coreapi/quality_reporting.h | 2 ++ mediastreamer2 | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 79557dc37..2fd4229c3 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -158,7 +158,9 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { if (rm.signal.level != 127) ret|=METRICS_SIGNAL; if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; + if (rm.qos_analyzer.input_leg!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.qos_analyzer.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; + if (rm.qos_analyzer.output_leg!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.qos_analyzer.output!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.rtcp_xr_count>0){ @@ -289,7 +291,9 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off if ((available_metrics & METRICS_ADAPTIVE_ALGORITHM) != 0){ append_to_buffer(buffer, size, offset, "\r\nAdaptiveAlg:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN_LEG=%s", rm.qos_analyzer.input_leg); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.qos_analyzer.input); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT_LEG=%s", rm.qos_analyzer.output_leg); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT=%s", rm.qos_analyzer.output); } @@ -405,14 +409,17 @@ static void update_ip(LinphoneCall * call, int stats_type) { } } -static void qos_analyzer_on_action_suggested(void *user_data, const char * input, const char * output){ +static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** data){ reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; - char * newstr = NULL; - newstr = ms_strdup_printf("%s%s;", metrics->qos_analyzer.input?metrics->qos_analyzer.input:"", input); - STR_REASSIGN(metrics->qos_analyzer.input, newstr) + char * appendbuf; - newstr = ms_strdup_printf("%s%s;", metrics->qos_analyzer.output?metrics->qos_analyzer.output:"", output); - STR_REASSIGN(metrics->qos_analyzer.output, newstr) + STR_REASSIGN(metrics->qos_analyzer.input_leg, ms_strdup(data[0])); + appendbuf=ms_strdup_printf("%s%s;", metrics->qos_analyzer.input?metrics->qos_analyzer.input:"", data[1]); + STR_REASSIGN(metrics->qos_analyzer.input,appendbuf); + + STR_REASSIGN(metrics->qos_analyzer.output_leg, ms_strdup(data[2])); + appendbuf=ms_strdup_printf("%s%s;", metrics->qos_analyzer.output?metrics->qos_analyzer.output:"", data[3]); + STR_REASSIGN(metrics->qos_analyzer.output, appendbuf); } void linphone_reporting_update_ip(LinphoneCall * call) { @@ -614,7 +621,9 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp); if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc); + if (report->local_metrics.qos_analyzer.input_leg != NULL) ms_free(report->local_metrics.qos_analyzer.input_leg); if (report->local_metrics.qos_analyzer.input != NULL) ms_free(report->local_metrics.qos_analyzer.input); + if (report->local_metrics.qos_analyzer.output_leg != NULL) ms_free(report->local_metrics.qos_analyzer.output_leg); if (report->local_metrics.qos_analyzer.output != NULL) ms_free(report->local_metrics.qos_analyzer.output); ms_free(report); diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 2dc888a89..c909baecc 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -98,7 +98,9 @@ typedef struct reporting_content_metrics { /* This should allow us to analysis bad network conditions and quality adaptation on server side*/ struct { + char* input_leg; char* input; + char* output_leg; char* output; } qos_analyzer; diff --git a/mediastreamer2 b/mediastreamer2 index 4b156f31e..0aee9ceea 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 4b156f31e41eab5ac34dd0cefffa9ff40eeefc0c +Subproject commit 0aee9ceeaa0f766c8d0e15ee2bcb82e06c7c541d From 94ce7ad1bf5e578007e56c9dd265077e8a421f4a Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 9 Jun 2014 12:48:44 +0200 Subject: [PATCH 097/201] File transfer move server to https:linphone.org --- coreapi/help/filetransfer.c | 43 +++++++++++-------------------------- tester/message_tester.c | 21 +++++++++--------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c index c297edaf2..9bbbcddeb 100644 --- a/coreapi/help/filetransfer.c +++ b/coreapi/help/filetransfer.c @@ -64,13 +64,7 @@ static void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMess * function invoked when a file transfer is received. * */ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){ - const LinphoneAddress* from_address = linphone_chat_message_get_from(message); - char *from = linphone_address_as_string(from_address); int file=-1; - printf(" File transfer receive [%i] bytes of type [%s/%s] from [%s] \n" , (int)size - , content->type - , content->subtype - , from); if (!linphone_chat_message_get_user_data(message)) { /*first chunk, creating file*/ file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); @@ -78,20 +72,18 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag } else { /*next chunk*/ file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + + if (size==0) { + + printf("File transfert completed\n"); + linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); + linphone_chat_message_destroy(message); + close(file); + running=FALSE; + } else { /* store content on a file*/ + write(file,buff,size); + } } - - if (size==0) { - printf("File transfert completed\n"); - linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); - linphone_chat_message_destroy(message); - close(file); - running=FALSE; - } else { /* store content on a file*/ - write(file,buff,size); - } - - - free(from); } char big_file [128000]; @@ -99,10 +91,7 @@ char big_file [128000]; * function called when the file transfer is initiated. file content should be feed into object LinphoneContent * */ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){ - //const LinphoneAddress* to_address = linphone_chat_message_get_to(message); - //char *to = linphone_address_as_string(to_address); int offset=-1; - /*content->size can be feed*/ if (!linphone_chat_message_get_user_data(message)) { /*first chunk*/ @@ -119,15 +108,9 @@ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, } memcpy(buff,big_file+offset,*size); - printf(" File transfer sending [%i] bytes of type [%s/%s] from [%s] \n" , (int)*size - , content->type - , content->subtype - , "pipo"); /*store offset for next chunk*/ linphone_chat_message_set_user_data(message,(void*)(offset+*size)); - //free(to); - } /* @@ -193,8 +176,8 @@ int main(int argc, char *argv[]){ /** * Globally configure an http file transfer server. */ - linphone_core_set_file_transfer_server(lc,"http://npasc.al/lft.php"); - //linphone_core_set_file_transfer_server(lc,"https://www.linphone.org:444/upload.php"); + //linphone_core_set_file_transfer_server(lc,"http://npasc.al/lft.php"); + linphone_core_set_file_transfer_server(lc,"https://www.linphone.org:444/lft.php"); /*Next step is to create a chat room*/ diff --git a/tester/message_tester.c b/tester/message_tester.c index e7b78d00b..a0b9721be 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -63,16 +63,16 @@ void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, cons } else { /*next chunk*/ file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); - } - if (size==0) { - linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); - linphone_chat_message_destroy(message); - stats* counters = get_stats(lc); - counters->number_of_LinphoneMessageExtBodyReceived++; - close(file); - } else { /* store content on a file*/ - write(file,buff,size); + if (size==0) { /* tranfer complerte */ + linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); + linphone_chat_message_destroy(message); + stats* counters = get_stats(lc); + counters->number_of_LinphoneMessageExtBodyReceived++; + close(file); + } else { /* store content on a file*/ + write(file,buff,size); + } } } @@ -319,7 +319,6 @@ static void text_message_with_external_body(void) { static void file_transfer_message(void) { int i; /* setting dummy file content to something */ - const char* big_file_content="big file"; for (i=0;ilc,"http://npasc.al/lft.php"); + linphone_core_set_file_transfer_server(pauline->lc,"https://www.linphone.org:444/lft.php"); /* create a chatroom on pauline's side */ char* to = linphone_address_as_string(marie->identity); From ae0ca2f31427dfa55367aed421a7648ff6a4ce63 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Jun 2014 13:46:54 +0200 Subject: [PATCH 098/201] Update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 0aee9ceea..a56c48867 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 0aee9ceeaa0f766c8d0e15ee2bcb82e06c7c541d +Subproject commit a56c48867ebcf5ae29edfad98070ce717978ab3b From 35cd2665b787dd9f5400d94ae9267a6430c4f5af Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Jun 2014 14:06:13 +0200 Subject: [PATCH 099/201] enhance multiple early media forking test to check that dialogs are ok --- coreapi/bellesip_sal/sal_op_call_transfer.c | 6 +++--- tester/call_tester.c | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 796966acd..5958c8745 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -122,9 +122,9 @@ int sal_call_set_referer(SalOp *h, SalOp *refered_call){ SalOp *sal_call_get_replaces(SalOp *op){ if (op && op->replaces){ belle_sip_dialog_t* dialog=belle_sip_provider_find_dialog(op->base.root->prov - ,belle_sip_header_replaces_get_call_id(op->replaces) - ,belle_sip_header_replaces_get_from_tag(op->replaces) - ,belle_sip_header_replaces_get_to_tag(op->replaces)); + ,belle_sip_header_replaces_get_call_id(op->replaces) + ,belle_sip_header_replaces_get_from_tag(op->replaces) + ,belle_sip_header_replaces_get_to_tag(op->replaces)); if (dialog) { return (SalOp*)belle_sip_dialog_get_application_data(dialog); diff --git a/tester/call_tester.c b/tester/call_tester.c index b5feb834e..7418cbba0 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2265,6 +2265,7 @@ static void multiple_early_media(void) { LinphoneCall *marie1_call; LinphoneCall *marie2_call; LinphoneCall *pauline_call; + LinphoneInfoMessage *info; int dummy=0; char ringbackpath[256]; snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); @@ -2325,9 +2326,14 @@ static void multiple_early_media(void) { CU_ASSERT_TRUE(linphone_call_get_audio_stats(pauline_call)->download_bandwidth>71); CU_ASSERT_TRUE(linphone_call_get_audio_stats(marie1_call)->download_bandwidth>71); + /*send an INFO in reverse side to check that dialogs are properly established*/ + info=linphone_core_create_info_message(marie1->lc); + linphone_call_send_info_message(marie1_call,info); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_inforeceived,1,2000)); + linphone_core_terminate_all_calls(pauline->lc); - CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,1000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,1000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,2000)); ms_list_free(lcs); linphone_core_manager_destroy(marie1); From 9fd237ec5f2f47a1da104891e0815b755f73b3e3 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 9 Jun 2014 14:08:04 +0200 Subject: [PATCH 100/201] MS2:avoid using functions: av_frame_alloc(), av_frame_unref() and av_frame_free() until libavcodec version 55.45.101 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index a56c48867..c41b1f952 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a56c48867ebcf5ae29edfad98070ce717978ab3b +Subproject commit c41b1f95201c74809fdf35bca0d5a81a3de4c21f From 1c1165ff658b6d77c36177171a5e13a2ca72874d Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Mon, 9 Jun 2014 15:29:30 +0200 Subject: [PATCH 101/201] Fix user agent in chat --- coreapi/chat.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 4bd4fe68c..7aa596566 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -85,7 +85,7 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_ char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype); size_t end_of_file=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size; - + if (offset==0){ int partlen=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type); memcpy(buffer,MULTIPART_HEADER_1,strlen(MULTIPART_HEADER_1)); @@ -132,16 +132,19 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co belle_http_request_t *req; char *content_type=belle_sip_strdup_printf("%s/%s", msg->file_transfer_information->type, msg->file_transfer_information->subtype); belle_sip_user_body_handler_t *bh=belle_sip_user_body_handler_new(msg->file_transfer_information->size+linphone_chat_message_compute_multipart_header_size(msg->file_transfer_information->name, content_type)+strlen(MULTIPART_END), linphone_chat_message_file_transfer_on_progress, NULL, linphone_chat_message_file_transfer_on_send_body, msg); + char* ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); + belle_sip_free(content_type); content_type=belle_sip_strdup_printf("multipart/form-data; boundary=%s",multipart_boundary); - + uri=belle_generic_uri_parse(msg->chat_room->lc->file_transfer_server); - + req=belle_http_request_create("POST", - uri, - belle_sip_header_create("User-Agent","belle-sip/" PACKAGE_VERSION), - belle_sip_header_create("Content-type",content_type), - NULL); + uri, + belle_sip_header_create("User-Agent",ua), + belle_sip_header_create("Content-type",content_type), + NULL); + ms_free(ua); belle_sip_free(content_type); belle_sip_message_set_body_handler(BELLE_SIP_MESSAGE(req),BELLE_SIP_BODY_HANDLER(bh)); cbs.process_response=linphone_chat_message_process_response_from_post_file; @@ -160,7 +163,7 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co _linphone_chat_room_send_message(msg->chat_room, msg); } } - + } @@ -317,9 +320,9 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM belle_http_request_listener_t *l; belle_generic_uri_t *uri; belle_http_request_t *req; - + uri=belle_generic_uri_parse(cr->lc->file_transfer_server); - + req=belle_http_request_create("POST", uri, NULL, @@ -445,11 +448,11 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag msg->content_type = ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */ msg->file_transfer_information = (LinphoneContent *)malloc(sizeof(LinphoneContent)); memset(msg->file_transfer_information, 0, sizeof(*(msg->file_transfer_information))); - + xmlChar *file_url = NULL; /* parse the message body to get all informations from it */ xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text); - + xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); if (cur != NULL) { cur = cur->xmlChildrenNode; @@ -459,16 +462,16 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag if(!xmlStrcmp(typeAttribute, (const xmlChar *)"file")) { /* this is the node we are looking for */ cur = cur->xmlChildrenNode; /* now loop on the content of the file-info node */ while (cur!=NULL) { - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-size")) { xmlChar *fileSizeString = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); msg->file_transfer_information->size = strtol((const char*)fileSizeString, NULL, 10); xmlFree(fileSizeString); } - if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"file-name")) { msg->file_transfer_information->name = (char *)xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); } - if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"content-type")) { xmlChar *contentType = xmlNodeListGetString(xmlMessageBody, cur->xmlChildrenNode, 1); int contentTypeIndex = 0; while (contentType[contentTypeIndex]!='/' && contentType[contentTypeIndex]!='\0') { @@ -478,7 +481,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag msg->file_transfer_information->subtype = strdup(((char *)contentType+contentTypeIndex+1)); xmlFree(contentType); } - if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { + if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { file_url = xmlGetProp(cur, (const xmlChar *)"url"); } @@ -996,12 +999,16 @@ void linphone_chat_message_start_file_download(const LinphoneChatMessage *messag const char *url=message->external_body_url; uri=belle_generic_uri_parse(url); - + + char* ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); + req=belle_http_request_create("GET", uri, - belle_sip_header_create("User-Agent","belle-sip/" PACKAGE_VERSION), + belle_sip_header_create("User-Agent",ua), NULL); + ms_free(ua); + cbs.process_response_headers=linphone_chat_process_response_headers_from_get_file; cbs.process_response=linphone_chat_process_response_from_get_file; cbs.process_io_error=process_io_error; From 649a5a5fe8d14bc751c409ba53d9a7e8c72b916b Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 9 Jun 2014 22:13:40 +0200 Subject: [PATCH 102/201] fix memory leaks --- coreapi/bellesip_sal/sal_impl.c | 4 ++-- coreapi/bellesip_sal/sal_op_call.c | 11 +++-------- coreapi/bellesip_sal/sal_op_impl.c | 14 +++++++++++--- coreapi/help/filetransfer.c | 6 ++++-- mediastreamer2 | 2 +- tester/call_tester.c | 8 +++++++- tester/message_tester.c | 4 +++- 7 files changed, 31 insertions(+), 18 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 92017616d..224bd73ee 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -375,8 +375,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even ms_error("Unhandled event response [%p]",event); } } - } + static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); @@ -386,6 +386,7 @@ static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *eve ms_error("Unhandled event timeout [%p]",event); } } + static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { belle_sip_client_transaction_t* client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event); belle_sip_server_transaction_t* server_transaction = belle_sip_transaction_terminated_event_get_server_transaction(event); @@ -404,7 +405,6 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans ms_message("Unhandled transaction terminated [%p]",trans); } if (op) sal_op_unref(op); /*because every transaction ref op*/ - } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 4d61feca9..76b7069b3 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -27,16 +27,11 @@ static void call_set_released(SalOp* op){ op->state=SalOpStateTerminated; op->base.root->callbacks.call_released(op); op->call_released=TRUE; + /*be aware that the following line may destroy the op*/ + set_or_update_dialog(op,NULL); } } -/*used when the SalOp was ref'd by the dialog, in which case we rely only on the dialog terminated notification*/ -static void call_set_released_and_unref(SalOp* op) { - call_set_released(op); - sal_op_unref(op); -} - - static void call_set_error(SalOp* op,belle_sip_response_t* response){ sal_op_set_error_info_from_response(op,response); op->base.root->callbacks.call_failure(op); @@ -142,7 +137,7 @@ static void process_dialog_terminated(void *ctx, const belle_sip_dialog_terminat break; } belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(op->base.root->stack) - ,(belle_sip_callback_t) call_set_released_and_unref + ,(belle_sip_callback_t) call_set_released , op); } else { ms_error("dialog unknown for op "); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index e2678dde0..1a49cd65c 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -573,16 +573,17 @@ static belle_sip_dialog_t *link_op_with_dialog(SalOp *op, belle_sip_dialog_t* di } void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { - if (dialog==NULL) return; ms_message("op [%p] : set_or_update_dialog() current=[%p] new=[%p]",op,op->dialog,dialog); - if (dialog && op->dialog!=dialog){ + sal_op_ref(op); + if (op->dialog!=dialog){ if (op->dialog){ /*FIXME: shouldn't we delete unconfirmed dialogs ?*/ unlink_op_with_dialog(op,op->dialog); op->dialog=NULL; } - op->dialog=link_op_with_dialog(op,dialog); + if (dialog) op->dialog=link_op_with_dialog(op,dialog); } + sal_op_unref(op); } /*return reffed op*/ SalOp* sal_op_ref(SalOp* op) { @@ -607,6 +608,13 @@ int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int exp belle_sip_object_unref(op->refresher); } if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) { + /*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified + * that it is terminated anymore.*/ + sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*/ + /* Note that the refresher will replace our data with belle_sip_transaction_set_application_data(). + Something in the design is not very good here, it makes things complicated to the belle-sip user. + Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transaction + notify the user as a normal transaction*/ belle_sip_refresher_set_listener(op->refresher,listener,op); belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after); belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher); diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c index 9bbbcddeb..ece07d6c2 100644 --- a/coreapi/help/filetransfer.c +++ b/coreapi/help/filetransfer.c @@ -62,7 +62,7 @@ static void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMess } /** * function invoked when a file transfer is received. - * */ + **/ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){ int file=-1; if (!linphone_chat_message_get_user_data(message)) { @@ -81,7 +81,9 @@ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *messag close(file); running=FALSE; } else { /* store content on a file*/ - write(file,buff,size); + if (write(file,buff,size)==-1){ + ms_warning("file_transfer_received() write failed: %s",strerror(errno)); + } } } } diff --git a/mediastreamer2 b/mediastreamer2 index c41b1f952..8b80c5023 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c41b1f95201c74809fdf35bca0d5a81a3de4c21f +Subproject commit 8b80c5023cabeb400826104b5641a9a6917ab4cf diff --git a/tester/call_tester.c b/tester/call_tester.c index 7418cbba0..40fbf37b8 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -239,13 +239,19 @@ bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr){ return call_with_params(caller_mgr,callee_mgr,NULL,NULL); } +static void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){ + linphone_core_terminate_all_calls(m1->lc); + CU_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m1->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(m1->lc,m2->lc,&m2->stat.number_of_LinphoneCallEnd,1)); +} + static void simple_call(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); CU_ASSERT_TRUE(call(pauline,marie)); liblinphone_tester_check_rtcp(marie,pauline); - + end_call(marie,pauline); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } diff --git a/tester/message_tester.c b/tester/message_tester.c index ec3cc8a36..151505c59 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -76,7 +76,9 @@ void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, cons counters->number_of_LinphoneMessageExtBodyReceived++; close(file); } else { /* store content on a file*/ - write(file,buff,size); + if (write(file,buff,size)==-1){ + ms_error("file_transfer_received(): write() failed: %s",strerror(errno)); + } } } } From 306a2647cf6a21df1eb07dd36738a1a386651f08 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 10 Jun 2014 08:41:01 +0200 Subject: [PATCH 103/201] fix mingw compilation issue --- coreapi/chat.c | 4 ++-- mediastreamer2 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 7aa596566..babd3e82c 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -477,8 +477,8 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag while (contentType[contentTypeIndex]!='/' && contentType[contentTypeIndex]!='\0') { contentTypeIndex++; } - msg->file_transfer_information->type = strndup((char *)contentType, contentTypeIndex); - msg->file_transfer_information->subtype = strdup(((char *)contentType+contentTypeIndex+1)); + msg->file_transfer_information->type = ms_strdup((char *)contentType, contentTypeIndex); + msg->file_transfer_information->subtype = ms_strdup(((char *)contentType+contentTypeIndex+1)); xmlFree(contentType); } if (!xmlStrcmp(cur->name, (const xmlChar *)"data")) { diff --git a/mediastreamer2 b/mediastreamer2 index 8b80c5023..ff45699c7 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8b80c5023cabeb400826104b5641a9a6917ab4cf +Subproject commit ff45699c79c09eb2f57aa07d8e63c20e66e35073 From 0b46ef520cc2eb65d4587d8687a4b3233b8990ec Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 10 Jun 2014 10:26:32 +0200 Subject: [PATCH 104/201] fix compilation issue --- coreapi/chat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index babd3e82c..245abccc3 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -477,7 +477,7 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag while (contentType[contentTypeIndex]!='/' && contentType[contentTypeIndex]!='\0') { contentTypeIndex++; } - msg->file_transfer_information->type = ms_strdup((char *)contentType, contentTypeIndex); + msg->file_transfer_information->type = ms_strndup((char *)contentType, contentTypeIndex); msg->file_transfer_information->subtype = ms_strdup(((char *)contentType+contentTypeIndex+1)); xmlFree(contentType); } From 6f95bbc5d246851be1b0049d0520efe6124c439e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Jun 2014 13:25:39 +0200 Subject: [PATCH 105/201] Fix bug 0001279: Wrong usage of n_active_streams in the media descriptions. Inactive streams are now allowed between active streams in the SDP. --- coreapi/bellesip_sal/sal_op_call.c | 4 +- coreapi/bellesip_sal/sal_sdp.c | 16 +++----- coreapi/callbacks.c | 11 ++++-- coreapi/linphonecall.c | 48 +++++++++++++---------- coreapi/linphonecore.c | 6 +-- coreapi/misc.c | 52 ++++++------------------- coreapi/offeranswer.c | 20 +++++----- coreapi/private.h | 5 --- coreapi/quality_reporting.c | 2 +- coreapi/sal.c | 62 ++++++++++++++++++++++++++---- coreapi/upnp.c | 5 ++- include/sal/sal.h | 9 ++++- mediastreamer2 | 2 +- 13 files changed, 132 insertions(+), 110 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 76b7069b3..f2363af83 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -57,7 +57,7 @@ static void sdp_process(SalOp *h){ strcpy(h->result->addr,h->base.remote_media->addr); h->result->bandwidth=h->base.remote_media->bandwidth; - for(i=0;iresult->n_active_streams;++i){ + for(i=0;iresult);++i){ strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); h->result->streams[i].ptime=h->base.remote_media->streams[i].ptime; h->result->streams[i].bandwidth=h->base.remote_media->streams[i].bandwidth; @@ -368,7 +368,7 @@ static int extract_sdp(belle_sip_message_t* message,belle_sdp_session_descriptio } static int is_media_description_acceptable(SalMediaDescription *md){ - if (md->n_total_streams==0){ + if (md->nb_streams==0){ ms_warning("Media description does not define any stream."); return FALSE; } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 268fbc480..90f38af19 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -344,7 +344,7 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr belle_sdp_session_description_add_attribute(session_desc, create_rtcp_xr_attribute(&desc->rtcp_xr)); } - for ( i=0; in_total_streams; i++ ) { + for ( i=0; inb_streams; i++ ) { stream_description_to_sdp(session_desc, desc, &desc->streams[i]); } return session_desc; @@ -616,7 +616,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, const char* value; const char *mtype,*proto; - stream=&md->streams[md->n_total_streams]; + stream=&md->streams[md->nb_streams]; media=belle_sdp_media_description_get_media ( media_desc ); memset ( stream,0,sizeof ( *stream ) ); @@ -642,9 +642,6 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, stream->rtp_port=belle_sdp_media_get_media_port ( media ); - if ( stream->rtp_port > 0 ) - md->n_active_streams++; - mtype = belle_sdp_media_get_media_type ( media ); if ( strcasecmp ( "audio", mtype ) == 0 ) { stream->type=SalAudio; @@ -708,7 +705,7 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, stream->rtcp_xr = md->rtcp_xr; // Use session parameters if no stream parameters are defined sdp_parse_media_rtcp_xr_parameters(media_desc, &stream->rtcp_xr); - md->n_total_streams++; + md->nb_streams++; return stream; } @@ -720,8 +717,7 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S belle_sdp_session_name_t *sname; const char* value; - desc->n_active_streams = 0; - desc->n_total_streams = 0; + desc->nb_streams = 0; desc->dir = SalStreamSendRecv; if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { @@ -762,8 +758,8 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) ; media_desc_it!=NULL ; media_desc_it=media_desc_it->next ) { - if (desc->n_total_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){ - ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->n_total_streams); + if (desc->nb_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){ + ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->nb_streams); break; } media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 9b427506b..16b2b9d92 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -47,7 +47,8 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c char *rtp_addr, *rtcp_addr; int i; - for (i = 0; i < new_md->n_active_streams; i++) { + for (i = 0; i < new_md->nb_streams; i++) { + if (!sal_stream_description_active(&new_md->streams[i])) continue; if (new_md->streams[i].type == SalAudio) { new_audiodesc = &new_md->streams[i]; } else if (new_md->streams[i].type == SalVideo) { @@ -108,7 +109,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia ms_error("linphone_core_update_streams() called with null media description"); return; } - if (call->biggestdesc==NULL || new_md->n_total_streams>call->biggestdesc->n_total_streams){ + if (call->biggestdesc==NULL || new_md->nb_streams>call->biggestdesc->nb_streams){ /*we have been offered and now are ready to proceed, or we added a new stream*/ /*store the media description to remember the mapping of calls*/ if (call->biggestdesc){ @@ -312,7 +313,8 @@ static void try_early_media_forking(LinphoneCall *call, SalMediaDescription *md) SalStreamDescription *ref_stream,*new_stream; ms_message("Early media response received from another branch, checking if media can be forked to this new destination."); - for (i=0;in_active_streams;++i){ + for (i=0;inb_streams;++i){ + if (!sal_stream_description_active(&cur_md->streams[i])) continue; ref_stream=&cur_md->streams[i]; new_stream=&md->streams[i]; if (ref_stream->type==new_stream->type && ref_stream->payloads && new_stream->payloads){ @@ -738,7 +740,8 @@ static void call_failure(SalOp *op){ || (call->state == LinphoneCallOutgoingRinging) /* Push notification case */ || (call->state == LinphoneCallOutgoingEarlyMedia)) { int i; - for (i = 0; i < call->localdesc->n_active_streams; i++) { + for (i = 0; i < call->localdesc->nb_streams; i++) { + if (!sal_stream_description_active(&call->localdesc->streams[i])) continue; if (call->params.media_encryption == LinphoneMediaEncryptionSRTP) { if (call->params.avpf_enabled == TRUE) { if (i == 0) ms_message("Retrying call [%p] with SAVP", call); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 7fa8b5fc5..d856a4383 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -254,11 +254,12 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){ int i; - for (i = 0; i < md->n_active_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; if ((md->streams[i].type == SalAudio) && (ac->port != 0)) { strcpy(md->streams[0].rtp_addr,ac->addr); md->streams[0].rtp_port=ac->port; - if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){ + if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || sal_media_description_get_nb_active_streams(md)==1){ strcpy(md->addr,ac->addr); } } @@ -301,9 +302,10 @@ static void setup_encryption_keys(LinphoneCall *call, SalMediaDescription *md){ SalMediaDescription *old_md=call->localdesc; bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",1); - for(i=0; in_active_streams; i++) { - if (stream_description_has_srtp(&md->streams[i]) == TRUE) { - if (keep_srtp_keys && old_md && stream_description_has_srtp(&old_md->streams[i]) == TRUE){ + for(i=0; inb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_srtp(&md->streams[i]) == TRUE) { + if (keep_srtp_keys && old_md && sal_stream_description_has_srtp(&old_md->streams[i]) == TRUE){ int j; ms_message("Keeping same crypto keys."); for(j=0;jn_active_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; for (pt_it = md->streams[i].payloads; pt_it != NULL; pt_it = pt_it->next) { pt = (PayloadType *)pt_it->data; if (call->params.avpf_enabled == TRUE) { @@ -363,7 +366,8 @@ static void setup_rtcp_xr(LinphoneCall *call, SalMediaDescription *md) { } md->rtcp_xr.voip_metrics_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_xr_voip_metrics_enabled", 0); } - for (i = 0; i < md->n_active_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; memcpy(&md->streams[i].rtcp_xr, &md->rtcp_xr, sizeof(md->streams[i].rtcp_xr)); } } @@ -385,6 +389,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * PayloadType *pt; SalMediaDescription *old_md=call->localdesc; int i; + int nb_active_streams = 0; const char *me; SalMediaDescription *md=sal_media_description_new(); LinphoneAddress *addr; @@ -401,7 +406,7 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff)); md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff)); - md->n_total_streams=(call->biggestdesc ? call->biggestdesc->n_total_streams : 1); + md->nb_streams=(call->biggestdesc ? call->biggestdesc->nb_streams : 1); strncpy(md->addr,local_ip,sizeof(md->addr)); strncpy(md->username,linphone_address_get_username(addr),sizeof(md->username)); @@ -412,7 +417,6 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * else md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ - md->n_active_streams=1; strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr)); strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr)); strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1); @@ -428,9 +432,9 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event")); l=ms_list_append(l,pt); md->streams[0].payloads=l; + nb_active_streams++; if (call->params.has_video){ - md->n_active_streams++; strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1); md->streams[1].rtp_port=call->media_ports[1].rtp_port; md->streams[1].rtcp_port=call->media_ports[1].rtcp_port; @@ -438,12 +442,14 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * md->streams[1].type=SalVideo; l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1); md->streams[1].payloads=l; + nb_active_streams++; } - if (md->n_total_streams < md->n_active_streams) - md->n_total_streams = md->n_active_streams; + + if (md->nb_streams < nb_active_streams) + md->nb_streams = nb_active_streams; /* Deactivate inactive streams. */ - for (i = md->n_active_streams; i < md->n_total_streams; i++) { + for (i = nb_active_streams; i < md->nb_streams; i++) { md->streams[i].rtp_port = 0; md->streams[i].rtcp_port = 0; md->streams[i].proto = call->biggestdesc->streams[i].proto; @@ -725,8 +731,8 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro call->params.has_video &= linphone_core_media_description_contains_video_stream(md); /* Handle AVPF and SRTP. */ - call->params.avpf_enabled = media_description_has_avpf(md); - if ((media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { + call->params.avpf_enabled = sal_media_description_has_avpf(md); + if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { call->params.media_encryption = LinphoneMediaEncryptionSRTP; } } @@ -1062,12 +1068,12 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ for (i = 0; i < nb_video_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); - if (is_video_active(sd) == TRUE) cp->has_video = TRUE; - if (stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + if (sal_stream_description_active(sd) == TRUE) cp->has_video = TRUE; + if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; } for (i = 0; i < nb_audio_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); - if (stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; + if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; } if (!cp->has_video){ if (md->bandwidth>0 && md->bandwidth<=linphone_core_get_edge_bw(call->core)){ @@ -1565,7 +1571,7 @@ static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream cl=ice_session_check_list(call->ice_session, stream_index); if (cl == NULL && create_checklist) { cl=ice_check_list_new(); - ice_session_add_check_list(call->ice_session, cl); + ice_session_add_check_list(call->ice_session, cl, stream_index); ms_message("Created new ICE check list for stream [%i]",stream_index); } if (cl){ @@ -2044,7 +2050,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna call->current_params.record_file=ms_strdup(call->params.record_file); } /* valid local tags are > 0 */ - if (stream_description_has_srtp(stream) == TRUE) { + if (sal_stream_description_has_srtp(stream) == TRUE) { local_st_desc=sal_media_description_find_stream(call->localdesc,stream->proto,SalAudio); crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, stream->crypto_local_tag); @@ -2161,7 +2167,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna cam=get_nowebcam_device(); } if (!is_inactive){ - if (stream_description_has_srtp(vstream) == TRUE) { + if (sal_stream_description_has_srtp(vstream) == TRUE) { int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, vstream->crypto_local_tag); if (crypto_idx >= 0) { media_stream_set_srtp_recv_key(&call->videostream->ms,vstream->crypto[0].algo,vstream->crypto[0].master_key); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 360a69725..afa7a7265 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2977,7 +2977,7 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ } bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ - return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !media_description_has_srtp(md); + return linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP && !sal_media_description_has_srtp(md); } void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ @@ -3431,8 +3431,8 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, if (md) { call->params.has_video &= linphone_core_media_description_contains_video_stream(md); /* Handle AVPF and SRTP. */ - call->params.avpf_enabled = media_description_has_avpf(md); - if ((media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { + call->params.avpf_enabled = sal_media_description_has_avpf(md); + if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { call->params.media_encryption = LinphoneMediaEncryptionSRTP; } } diff --git a/coreapi/misc.c b/coreapi/misc.c index 2a86db03a..43b3a3139 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -711,11 +711,11 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription * } strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd)); strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag)); - for (i = 0; i < desc->n_active_streams; i++) { + for (i = 0; i < desc->nb_streams; i++) { SalStreamDescription *stream = &desc->streams[i]; IceCheckList *cl = ice_session_check_list(session, i); nb_candidates = 0; - if (cl == NULL) continue; + if (!sal_stream_description_active(stream) || (cl == NULL)) continue; if (ice_check_list_state(cl) == ICL_Completed) { stream->ice_completed = TRUE; result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port); @@ -822,7 +822,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, ice_session_restart(call->ice_session); ice_restarted = TRUE; } else { - for (i = 0; i < md->n_total_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { @@ -841,7 +841,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd); } - for (i = 0; i < md->n_total_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { @@ -857,7 +857,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } /* Create ICE check lists if needed and parse ICE attributes. */ - for (i = 0; i < md->n_total_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); /* @@ -918,10 +918,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, } } } - for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) { - IceCheckList *removed=ice_session_check_list(call->ice_session, i - 1); - ice_session_remove_check_list(call->ice_session, removed); - clear_ice_check_list(call,removed); + for (i = 0; i < md->nb_streams; i++) { + IceCheckList * cl = ice_session_check_list(call->ice_session, i); + if (!sal_stream_description_active(&md->streams[i]) && (cl != NULL)) { + ice_session_remove_check_list_from_idx(call->ice_session, i); + clear_ice_check_list(call, cl); + } } ice_session_check_mismatch(call->ice_session); } else { @@ -937,7 +939,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md){ int i; - for (i = 0; i < md->n_total_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0) return TRUE; } @@ -1520,33 +1522,3 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){ lc->rtp_conf.srtp_suites=result; return result; } - -bool_t is_video_active(const SalStreamDescription *sd) { - return (sd->rtp_port != 0) && (sd->dir != SalStreamInactive); -} - -bool_t stream_description_has_avpf(const SalStreamDescription *sd) { - return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf)); -} - -bool_t stream_description_has_srtp(const SalStreamDescription *sd) { - return ((sd->proto == SalProtoRtpSavp) || (sd->proto == SalProtoRtpSavpf)); -} - -bool_t media_description_has_avpf(const SalMediaDescription *md) { - int i; - if (md->n_active_streams == 0) return FALSE; - for (i = 0; i < md->n_active_streams; i++) { - if (stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE; - } - return TRUE; -} - -bool_t media_description_has_srtp(const SalMediaDescription *md) { - int i; - if (md->n_active_streams == 0) return FALSE; - for (i = 0; i < md->n_active_streams; i++) { - if (stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE; - } - return TRUE; -} diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index aef918b92..779e7ae65 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -237,7 +237,7 @@ static void initiate_outgoing(const SalStreamDescription *local_offer, }else{ result->rtp_port=0; } - if (stream_description_has_srtp(result) == TRUE) { + if (sal_stream_description_has_srtp(result) == TRUE) { /* verify crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_offer->crypto, remote_answer->crypto, &result->crypto[0], &result->crypto_local_tag, FALSE)) @@ -263,7 +263,7 @@ static void initiate_incoming(const SalStreamDescription *local_cap, }else{ result->rtp_port=0; } - if (stream_description_has_srtp(result) == TRUE) { + if (sal_stream_description_has_srtp(result) == TRUE) { /* select crypto algo */ memset(result->crypto, 0, sizeof(result->crypto)); if (!match_crypto_algo(local_cap->crypto, remote_offer->crypto, &result->crypto[0], &result->crypto_local_tag, TRUE)) @@ -289,7 +289,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, int i,j; const SalStreamDescription *ls,*rs; - for(i=0,j=0;in_total_streams;++i){ + for(i=0,j=0;inb_streams;++i){ ms_message("Processing for stream %i",i); ls=&local_offer->streams[i]; rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); @@ -303,8 +303,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, } else ms_warning("No matching stream for %i",i); } - result->n_active_streams=j; - result->n_total_streams=local_offer->n_total_streams; + result->nb_streams=local_offer->nb_streams; result->bandwidth=remote_answer->bandwidth; strcpy(result->addr,remote_answer->addr); memcpy(&result->rtcp_xr, &local_offer->rtcp_xr, sizeof(result->rtcp_xr)); @@ -317,7 +316,7 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, static bool_t local_stream_not_already_used(const SalMediaDescription *result, const SalStreamDescription *stream){ int i; - for(i=0;in_total_streams;++i){ + for(i=0;inb_streams;++i){ const SalStreamDescription *ss=&result->streams[i]; if (strcmp(ss->name,stream->name)==0){ ms_message("video stream already used in answer"); @@ -337,8 +336,9 @@ static bool_t proto_compatible(SalMediaProto local, SalMediaProto remote) { static const SalStreamDescription *find_local_matching_stream(const SalMediaDescription *result, const SalMediaDescription *local_capabilities, const SalStreamDescription *remote_stream){ int i; - for(i=0;in_active_streams;++i){ + for(i=0;inb_streams;++i){ const SalStreamDescription *ss=&local_capabilities->streams[i]; + if (!sal_stream_description_active(ss)) continue; if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto) && local_stream_not_already_used(result,ss)) return ss; } @@ -356,15 +356,13 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities int i; const SalStreamDescription *ls=NULL,*rs; - result->n_active_streams=0; - for(i=0;in_total_streams;++i){ + for(i=0;inb_streams;++i){ rs=&remote_offer->streams[i]; if (rs->proto!=SalProtoOther){ ls=find_local_matching_stream(result,local_capabilities,rs); }else ms_warning("Unknown protocol for mline %i, declining",i); if (ls){ initiate_incoming(ls,rs,&result->streams[i],one_matching_codec); - if (result->streams[i].rtp_port!=0) result->n_active_streams++; // Handle media RTCP XR attribute memset(&result->streams[i].rtcp_xr, 0, sizeof(result->streams[i].rtcp_xr)); @@ -393,7 +391,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities } } } - result->n_total_streams=i; + result->nb_streams=i; strcpy(result->username, local_capabilities->username); strcpy(result->addr,local_capabilities->addr); result->bandwidth=local_capabilities->bandwidth; diff --git a/coreapi/private.h b/coreapi/private.h index b0ddd3047..2b6f8308d 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -393,11 +393,6 @@ bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); LinphoneCall * is_a_linphone_call(void *user_pointer); LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); -bool_t is_video_active(const SalStreamDescription *sd); -bool_t stream_description_has_avpf(const SalStreamDescription *sd); -bool_t stream_description_has_srtp(const SalStreamDescription *sd); -bool_t media_description_has_avpf(const SalMediaDescription *md); -bool_t media_description_has_srtp(const SalMediaDescription *md); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 2fd4229c3..06e42fb43 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -372,7 +372,7 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) { int count; if (smd != NULL) { - for (count = 0; count < smd->n_total_streams; ++count) { + for (count = 0; count < smd->nb_streams; ++count) { if (smd->streams[count].type == sal_stream_type) { return &smd->streams[count]; } diff --git a/coreapi/sal.c b/coreapi/sal.c index 74d087139..24da751b6 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -84,8 +84,9 @@ void sal_media_description_unref(SalMediaDescription *md){ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ int i; - for(i=0;in_active_streams;++i){ + for(i=0;inb_streams;++i){ SalStreamDescription *ss=&md->streams[i]; + if (!sal_stream_description_active(ss)) continue; if (ss->proto==proto && ss->type==type) return ss; } return NULL; @@ -94,7 +95,8 @@ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription *md, SalStreamType type) { unsigned int i; unsigned int nb = 0; - for (i = 0; i < md->n_active_streams; ++i) { + for (i = 0; i < md->nb_streams; ++i) { + if (!sal_stream_description_active(&md->streams[i])) continue; if (md->streams[i].type == type) nb++; } return nb; @@ -102,7 +104,8 @@ unsigned int sal_media_description_nb_active_streams_of_type(SalMediaDescription SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaDescription *md, SalStreamType type, unsigned int idx) { unsigned int i; - for (i = 0; i < md->n_active_streams; ++i) { + for (i = 0; i < md->nb_streams; ++i) { + if (!sal_stream_description_active(&md->streams[i])) continue; if (md->streams[i].type == type) { if (idx-- == 0) return &md->streams[i]; } @@ -125,18 +128,28 @@ SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescriptio } bool_t sal_media_description_empty(const SalMediaDescription *md){ - if (md->n_active_streams > 0) return FALSE; + if (sal_media_description_get_nb_active_streams(md) > 0) return FALSE; return TRUE; } void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){ int i; - for(i=0;in_active_streams;++i){ + for(i=0;inb_streams;++i){ SalStreamDescription *ss=&md->streams[i]; + if (!sal_stream_description_active(ss)) continue; ss->dir=stream_dir; } } +int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) { + int i; + int nb = 0; + for (i = 0; i < md->nb_streams; i++) { + if (sal_stream_description_active(&md->streams[i])) nb++; + } + return nb; +} + static bool_t is_null_address(const char *addr){ return strcmp(addr,"0.0.0.0")==0 || strcmp(addr,"::0")==0; @@ -147,8 +160,9 @@ static bool_t has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ int i; /* we are looking for at least one stream with requested direction, inactive streams are ignored*/ - for(i=0;in_active_streams;++i){ + for(i=0;inb_streams;++i){ const SalStreamDescription *ss=&md->streams[i]; + if (!sal_stream_description_active(ss)) continue; if (ss->dir==stream_dir) return TRUE; /*compatibility check for phones that only used the null address and no attributes */ if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))) @@ -175,6 +189,38 @@ bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir return FALSE; } +bool_t sal_stream_description_active(const SalStreamDescription *sd) { + return (sd->rtp_port > 0); +} + +bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoRtpAvpf) || (sd->proto == SalProtoRtpSavpf)); +} + +bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd) { + return ((sd->proto == SalProtoRtpSavp) || (sd->proto == SalProtoRtpSavpf)); +} + +bool_t sal_media_description_has_avpf(const SalMediaDescription *md) { + int i; + if (md->nb_streams == 0) return FALSE; + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; +} + +bool_t sal_media_description_has_srtp(const SalMediaDescription *md) { + int i; + if (md->nb_streams == 0) return FALSE; + for (i = 0; i < md->nb_streams; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (sal_stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE; + } + return TRUE; +} + /* static bool_t fmtp_equals(const char *p1, const char *p2){ if (p1 && p2 && strcmp(p1,p2)==0) return TRUE; @@ -261,9 +307,9 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD int i; if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; - if (md1->n_total_streams != md2->n_total_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - for(i = 0; i < md1->n_total_streams; ++i){ + for(i = 0; i < md1->nb_streams; ++i){ result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } return result; diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 7feaaa30c..5fcbbe065 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -731,7 +731,7 @@ int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, int i; const SalStreamDescription *stream; - for (i = 0; i < md->n_total_streams; i++) { + for (i = 0; i < md->nb_streams; i++) { stream = &md->streams[i]; if(stream->type == SalAudio) { audio = TRUE; @@ -1058,8 +1058,9 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription * SalStreamDescription *stream; UpnpStream *upnpStream; - for (i = 0; i < desc->n_active_streams; i++) { + for (i = 0; i < desc->nb_streams; i++) { stream = &desc->streams[i]; + if (!sal_stream_description_active(stream)) continue; upnpStream = NULL; if(stream->type == SalAudio) { upnpStream = session->audio; diff --git a/include/sal/sal.h b/include/sal/sal.h index d86dcc91e..e9719fc7b 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -215,8 +215,7 @@ typedef struct SalMediaDescription{ char name[64]; char addr[64]; char username[64]; - int n_active_streams; - int n_total_streams; + int nb_streams; int bandwidth; unsigned int session_ver; unsigned int session_id; @@ -259,6 +258,12 @@ SalStreamDescription * sal_media_description_get_active_stream_of_type(SalMediaD SalStreamDescription * sal_media_description_find_secure_stream_of_type(SalMediaDescription *md, SalStreamType type); SalStreamDescription * sal_media_description_find_best_stream(SalMediaDescription *md, SalStreamType type); void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir); +bool_t sal_stream_description_active(const SalStreamDescription *sd); +bool_t sal_stream_description_has_avpf(const SalStreamDescription *sd); +bool_t sal_stream_description_has_srtp(const SalStreamDescription *sd); +bool_t sal_media_description_has_avpf(const SalMediaDescription *md); +bool_t sal_media_description_has_srtp(const SalMediaDescription *md); +int sal_media_description_get_nb_active_streams(const SalMediaDescription *md); /*this structure must be at the first byte of the SalOp structure defined by implementors*/ diff --git a/mediastreamer2 b/mediastreamer2 index ff45699c7..7bf89d430 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ff45699c79c09eb2f57aa07d8e63c20e66e35073 +Subproject commit 7bf89d4302afb266bb359d7af8c16907ae8c327e From 2d3d752032a422977d8a363ae4ea08747f6c82b1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Jun 2014 14:42:08 +0200 Subject: [PATCH 106/201] Add unit test for video call with ICE with no matching audio codecs. --- tester/call_tester.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tester/call_tester.c b/tester/call_tester.c index 40fbf37b8..bab8e8666 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1057,6 +1057,32 @@ static void call_with_ice_video_added(void) { linphone_core_manager_destroy(pauline); } +static void video_call_with_ice_no_matching_audio_codecs(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); + LinphoneCall *out_call; + + linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMU", 8000, 1), FALSE); /* Disable PCMU */ + linphone_core_enable_payload_type(marie->lc, linphone_core_find_payload_type(marie->lc, "PCMA", 8000, 1), TRUE); /* Enable PCMA */ + linphone_core_set_firewall_policy(marie->lc, LinphonePolicyUseIce); + linphone_core_set_stun_server(marie->lc, "stun.linphone.org"); + linphone_core_set_firewall_policy(pauline->lc, LinphonePolicyUseIce); + linphone_core_set_stun_server(pauline->lc, "stun.linphone.org"); + + out_call = linphone_core_invite(marie->lc, "pauline"); + linphone_call_ref(out_call); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallOutgoingInit, 1)); + + /* flexisip will retain the 488 until the "urgent reply" timeout arrives. */ + CU_ASSERT_TRUE(wait_for_until(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallError, 1, 6000)); + CU_ASSERT_EQUAL(linphone_call_get_reason(out_call), LinphoneReasonNotAcceptable); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallIncomingReceived, 0); + + linphone_call_unref(out_call); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + #endif /*VIDEO_ENABLED*/ static void _call_with_media_relay(bool_t random_ports) { @@ -2383,6 +2409,7 @@ test_t call_tests[] = { { "Call with multiple early media", multiple_early_media }, { "Call with ICE from video to non-video", call_with_ice_video_to_novideo}, { "Call with ICE and video added", call_with_ice_video_added }, + { "Video call with ICE no matching audio codecs", video_call_with_ice_no_matching_audio_codecs }, #endif { "SRTP ice call", srtp_ice_call }, { "ZRTP ice call", zrtp_ice_call }, From 99594853e8e4949e3ef0676c3ce6672aff430682 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 10 Jun 2014 15:03:46 +0200 Subject: [PATCH 107/201] Add local IP address in video stream when making the local media description. --- coreapi/linphonecall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d856a4383..31f5b9c07 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -435,7 +435,9 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall * nb_active_streams++; if (call->params.has_video){ - strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1); + strncpy(md->streams[1].rtp_addr,local_ip,sizeof(md->streams[1].rtp_addr)); + strncpy(md->streams[1].rtcp_addr,local_ip,sizeof(md->streams[1].rtcp_addr)); + strncpy(md->streams[1].name,"Video",sizeof(md->streams[1].name)-1); md->streams[1].rtp_port=call->media_ports[1].rtp_port; md->streams[1].rtcp_port=call->media_ports[1].rtcp_port; md->streams[1].proto=md->streams[0].proto; From e2a35a71a2b1057ca15a353c8cec7812c2be5883 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 9 Jun 2014 15:37:36 +0200 Subject: [PATCH 108/201] Quality reporting: send session reports when video is disabled --- coreapi/linphonecall.c | 10 +--- coreapi/linphonecore.c | 9 ++-- coreapi/private.h | 9 +++- coreapi/quality_reporting.c | 94 ++++++++++++++++++++++++++++--------- coreapi/quality_reporting.h | 16 +++++-- tester/call_tester.c | 8 ++-- 6 files changed, 102 insertions(+), 44 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 31f5b9c07..b3e4ea740 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -819,6 +819,7 @@ static void linphone_call_set_terminated(LinphoneCall *call){ void linphone_call_fix_call_parameters(LinphoneCall *call){ call->params.has_video=call->current_params.has_video; + if (call->params.media_encryption != LinphoneMediaEncryptionZRTP) /*in case of ZRTP call parameter are handle after zrtp negociation*/ call->params.media_encryption=call->current_params.media_encryption; } @@ -906,17 +907,10 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const call->media_start_time=time(NULL); } - if (cstate == LinphoneCallStreamsRunning) { - linphone_reporting_update_ip(call); - } - if (lc->vtable.call_state_changed) lc->vtable.call_state_changed(lc,call,cstate,message); - if (cstate==LinphoneCallEnd){ - if (call->log->status == LinphoneCallSuccess) - linphone_reporting_publish_session_report(call); - } + linphone_reporting_call_state_updated(call); if (cstate==LinphoneCallReleased){ if (call->op!=NULL) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index afa7a7265..e9c5585e3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -129,8 +129,8 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro cl->status=LinphoneCallAborted; /*default status*/ cl->quality=-1; - cl->reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new(); - cl->reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new(); + cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]=linphone_reporting_new(); + cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]=linphone_reporting_new(); return cl; } @@ -394,8 +394,8 @@ void linphone_call_log_destroy(LinphoneCallLog *cl){ if (cl->to!=NULL) linphone_address_destroy(cl->to); if (cl->refkey!=NULL) ms_free(cl->refkey); if (cl->call_id) ms_free(cl->call_id); - if (cl->reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_AUDIO]); - if (cl->reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reports[LINPHONE_CALL_STATS_VIDEO]); + if (cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_AUDIO]); + if (cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]!=NULL) linphone_reporting_destroy(cl->reporting.reports[LINPHONE_CALL_STATS_VIDEO]); ms_free(cl); } @@ -3257,7 +3257,6 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) linphone_core_update_streams (lc,call,md); linphone_call_fix_call_parameters(call); } - if (call->state != LinphoneCallOutgoingEarlyMedia) /*don't change the state in case of outgoing early (SIP UPDATE)*/ linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); return 0; diff --git a/coreapi/private.h b/coreapi/private.h index 2b6f8308d..aec83fa0e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -103,6 +103,11 @@ struct _LinphoneCallParams{ uint8_t avpf_rr_interval; }; +struct _LinphoneQualityReporting{ + reporting_session_report_t * reports[2]; /**Store information on audio and video media streams (RFC 6035) */ + bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/ +}; + struct _LinphoneCallLog{ struct _LinphoneCore *lc; LinphoneCallDir dir; /**< The direction of the call*/ @@ -119,10 +124,12 @@ struct _LinphoneCallLog{ time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */ char* call_id; /**unique id of a call*/ - reporting_session_report_t * reports[2]; /**log->reports[stats_type] != NULL); + return (call->log->reporting.reports[stats_type] != NULL); } static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * offset, const reporting_content_metrics_t rm) { @@ -308,28 +308,30 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off ms_free(moscq_str); } -static void send_report(const LinphoneCall* call, reporting_session_report_t * report, const char * report_event) { +static int send_report(const LinphoneCall* call, reporting_session_report_t * report, const char * report_event) { LinphoneContent content = {0}; LinphoneAddress *addr; int expires = -1; size_t offset = 0; size_t size = 2048; char * buffer; + int ret = 0; /*if the call was hung up too early, we might have invalid IPs information in that case, we abort the report since it's not useful data*/ if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0 || report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) { - ms_warning("The call was hang up too early (duration: %d sec) and IP could " + ms_warning("QualityReporting: Trying to submit a %s too early (call duration: %d sec) and IP could " "not be retrieved so dropping this report" + , report_event , linphone_call_get_duration(call)); - return; + return 1; } addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy)); if (addr == NULL) { - ms_warning("Asked to submit reporting statistics but no collector address found"); - return; + ms_warning("QualityReporting: Asked to submit reporting statistics but no collector address found"); + return 2; } buffer = (char *) ms_malloc(size); @@ -362,11 +364,14 @@ static void send_report(const LinphoneCall* call, reporting_session_report_t * r content.size = strlen(buffer); /*(WIP) Memory leak: PUBLISH message is never freed (issue 1283)*/ - linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content); + if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){ + ret=3; + } linphone_address_destroy(addr); reset_avg_metrics(report); linphone_content_uninit(&content); + return ret; } static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDescription * smd, SalStreamType sal_stream_type) { @@ -379,7 +384,7 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc } } - ms_warning("Could not find the associated stream of type %d", sal_stream_type); + ms_warning("QualityReporting: Could not find the associated stream of type %d", sal_stream_type); return NULL; } @@ -391,19 +396,19 @@ static void update_ip(LinphoneCall * call, int stats_type) { /*local info are always up-to-date and correct*/ if (local_desc != NULL) { - call->log->reports[stats_type]->info.local_addr.port = local_desc->rtp_port; - STR_REASSIGN(call->log->reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr)); + call->log->reporting.reports[stats_type]->info.local_addr.port = local_desc->rtp_port; + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr)); } if (remote_desc != NULL) { /*port is always stored in stream description struct*/ - call->log->reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port; + call->log->reporting.reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port; /*for IP it can be not set if we are using a direct route*/ if (remote_desc->rtp_addr != NULL && strlen(remote_desc->rtp_addr) > 0) { - STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); } else { - STR_REASSIGN(call->log->reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); } } } @@ -432,11 +437,12 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { const PayloadType * local_payload = NULL; const PayloadType * remote_payload = NULL; const LinphoneCallParams * current_params = linphone_call_get_current_params(call); - reporting_session_report_t * report = call->log->reports[stats_type]; + reporting_session_report_t * report = call->log->reporting.reports[stats_type]; if (!media_report_enabled(call, stats_type)) return; + STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); STR_REASSIGN(report->info.local_group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), linphone_core_get_user_agent_name(), report->info.call_id)); @@ -496,7 +502,7 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { } void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { - reporting_session_report_t * report = call->log->reports[stats_type]; + reporting_session_report_t * report = call->log->reporting.reports[stats_type]; reporting_content_metrics_t * metrics = NULL; MSQosAnalyzer *analyzer=NULL; LinphoneCallStats stats = call->stats[stats_type]; @@ -554,21 +560,31 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { } } -static void publish_report(LinphoneCall *call, const char *event_type){ +static int publish_report(LinphoneCall *call, const char *event_type){ + int ret = 0; int i; for (i = 0; i < 2; i++){ if (media_report_enabled(call, i)){ + int sndret; linphone_reporting_update_media_info(call, i); - send_report(call, call->log->reports[i], event_type); + sndret=send_report(call, call->log->reporting.reports[i], event_type); + if (sndret>0){ + ret += 10+(i+1)*sndret; + } + } else{ + ret += i+1; } } -} -void linphone_reporting_publish_session_report(LinphoneCall* call) { - publish_report(call, "VQSessionReport: CallTerm"); + return ret; } -void linphone_reporting_publish_interval_report(LinphoneCall* call) { - publish_report(call, "VQIntervalReport"); +int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term) { + char * session_type = call_term?"VQSessionReport: CallTerm":"VQSessionReport"; + return publish_report(call, session_type); +} + +int linphone_reporting_publish_interval_report(LinphoneCall* call) { + return publish_report(call, "VQIntervalReport"); } reporting_session_report_t * linphone_reporting_new() { @@ -628,3 +644,35 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { ms_free(report); } + +void linphone_reporting_call_state_updated(LinphoneCall *call){ + LinphoneCallState state=linphone_call_get_state(call); + bool_t enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); + switch (state){ + case LinphoneCallStreamsRunning: + if (enabled!=call->log->reporting.was_video_running){ + if (enabled){ + linphone_reporting_update_ip(call); + }else{ + ms_message("Send midterm report with status %d", + send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport") + ); + } + }else{ + linphone_reporting_update_ip(call); + } + + call->log->reporting.was_video_running=enabled; + break; + case LinphoneCallEnd: + if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){ + ms_message("Send report with status %d", + linphone_reporting_publish_session_report(call, TRUE) + ); + } + break; + default: + + break; + } +} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index c909baecc..29fb3c4d0 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -164,25 +164,35 @@ void linphone_reporting_update_ip(LinphoneCall * call); * Publish a session report. This function should be called when session terminates, * media change (codec change or session fork), session terminates due to no media packets being received. * @param call #LinphoneCall object to consider + * @param call_term whether the call has ended or is continuing * + * @return error code. 0 for success, positive value otherwise. */ -void linphone_reporting_publish_session_report(LinphoneCall* call); +int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_term); /** * Publish an interval report. This function should be used for periodic interval * @param call #LinphoneCall object to consider + * @return error code. 0 for success, positive value otherwise. * */ -void linphone_reporting_publish_interval_report(LinphoneCall* call); +int linphone_reporting_publish_interval_report(LinphoneCall* call); /** - * Update publish report data with fresh RTCP stats, if needed. + * Update publish reports with newly received RTCP-XR packets (if available). * @param call #LinphoneCall object to consider * @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO) * */ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type); +/** + * Update publish reports on call state change. + * @param call #LinphoneCall object to consider + * + */ +void linphone_reporting_call_state_updated(LinphoneCall *call); + #ifdef __cplusplus } #endif diff --git a/tester/call_tester.c b/tester/call_tester.c index bab8e8666..b8a66f82e 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2199,11 +2199,11 @@ static void quality_reporting_not_used_without_config() { linphone_proxy_config_get_quality_reporting_collector(call_marie->dest_proxy)), 0); // this field should be already filled - CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->info.local_addr.ip); - CU_ASSERT_PTR_NULL(call_pauline->log->reports[0]->info.local_addr.ip); + CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->info.local_addr.ip); + CU_ASSERT_PTR_NULL(call_pauline->log->reporting.reports[0]->info.local_addr.ip); // but not this one since it is updated at the end of call - CU_ASSERT_PTR_NULL(call_marie->log->reports[0]->dialog_id); + CU_ASSERT_PTR_NULL(call_marie->log->reporting.reports[0]->dialog_id); linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -2247,7 +2247,7 @@ static void quality_reporting_at_call_termination() { linphone_core_terminate_all_calls(marie->lc); // now dialog id should be filled - CU_ASSERT_PTR_NOT_NULL(call_marie->log->reports[0]->dialog_id); + CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->dialog_id); CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); CU_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); From 10d1411f876763f3c7f691abafef02c2535b522c Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 10 Jun 2014 15:50:41 +0200 Subject: [PATCH 109/201] Quality reporting: separate unit tests in a different file and fix mid term session report --- build/android/liblinphone_tester.mk | 11 +- coreapi/quality_reporting.c | 56 ++++---- mediastreamer2 | 2 +- tester/Makefile.am | 9 +- tester/call_tester.c | 120 +---------------- tester/liblinphone_tester.c | 22 +--- tester/liblinphone_tester.h | 6 + tester/quality_reporting_tester.c | 198 ++++++++++++++++++++++++++++ tester/tester.c | 30 ++++- 9 files changed, 270 insertions(+), 184 deletions(-) create mode 100644 tester/quality_reporting_tester.c diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index 8e5221e20..e9a2c8718 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -12,21 +12,22 @@ common_SRC_FILES := \ stun_tester.c \ flexisip_tester.c \ tester.c \ - remote_provisioning_tester.c - + remote_provisioning_tester.c \ + quality_reporting_tester.c + common_C_INCLUDES += \ $(LOCAL_PATH) \ $(LOCAL_PATH)/../include \ $(LOCAL_PATH)/../coreapi \ $(LOCAL_PATH)/../oRTP/include \ - $(LOCAL_PATH)/../mediastreamer2/include + $(LOCAL_PATH)/../mediastreamer2/include include $(CLEAR_VARS) -LOCAL_MODULE := liblinphone_tester +LOCAL_MODULE := liblinphone_tester LOCAL_MODULE_FILENAME := liblinphone_tester-$(TARGET_ARCH_ABI) -LOCAL_SRC_FILES += $(common_SRC_FILES) +LOCAL_SRC_FILES += $(common_SRC_FILES) LOCAL_C_INCLUDES = $(common_C_INCLUDES) LOCAL_CFLAGS = -DIN_LINPHONE LOCAL_LDLIBS := -llog diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 1cd9c9152..52c60f446 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -321,16 +321,19 @@ static int send_report(const LinphoneCall* call, reporting_session_report_t * re in that case, we abort the report since it's not useful data*/ if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0 || report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) { - ms_warning("QualityReporting: Trying to submit a %s too early (call duration: %d sec) and IP could " + ms_warning("QualityReporting[%p]: Trying to submit a %s too early (call duration: %d sec) but %s IP could " "not be retrieved so dropping this report" + , report , report_event - , linphone_call_get_duration(call)); + , linphone_call_get_duration(call) + , (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0) ? "local" : "remote"); return 1; } addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy)); if (addr == NULL) { - ms_warning("QualityReporting: Asked to submit reporting statistics but no collector address found"); + ms_warning("QualityReporting[%p]: Asked to submit reporting statistics but no collector address found" + , report); return 2; } @@ -383,33 +386,32 @@ static const SalStreamDescription * get_media_stream_for_desc(const SalMediaDesc } } } - - ms_warning("QualityReporting: Could not find the associated stream of type %d", sal_stream_type); return NULL; } static void update_ip(LinphoneCall * call, int stats_type) { SalStreamType sal_stream_type = (stats_type == LINPHONE_CALL_STATS_AUDIO) ? SalAudio : SalVideo; - if (media_report_enabled(call,stats_type)) { - const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); - const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type); + const SalStreamDescription * local_desc = get_media_stream_for_desc(call->localdesc, sal_stream_type); + const SalStreamDescription * remote_desc = get_media_stream_for_desc(sal_call_get_remote_media_description(call->op), sal_stream_type); - /*local info are always up-to-date and correct*/ - if (local_desc != NULL) { + if (local_desc != NULL) { + /*since this function might be called for video stream AFTER it has been uninitialized, local description might + be invalid. In any other case, IP/port should be always filled and valid*/ + if (local_desc->rtp_addr != NULL && strlen(local_desc->rtp_addr) > 0) { call->log->reporting.reports[stats_type]->info.local_addr.port = local_desc->rtp_port; STR_REASSIGN(call->log->reporting.reports[stats_type]->info.local_addr.ip, ms_strdup(local_desc->rtp_addr)); } + } - if (remote_desc != NULL) { - /*port is always stored in stream description struct*/ - call->log->reporting.reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port; + if (remote_desc != NULL) { + /*port is always stored in stream description struct*/ + call->log->reporting.reports[stats_type]->info.remote_addr.port = remote_desc->rtp_port; - /*for IP it can be not set if we are using a direct route*/ - if (remote_desc->rtp_addr != NULL && strlen(remote_desc->rtp_addr) > 0) { - STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); - } else { - STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); - } + /*for IP it can be not set if we are using a direct route*/ + if (remote_desc->rtp_addr != NULL && strlen(remote_desc->rtp_addr) > 0) { + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(remote_desc->rtp_addr)); + } else { + STR_REASSIGN(call->log->reporting.reports[stats_type]->info.remote_addr.ip, ms_strdup(sal_call_get_remote_media_description(call->op)->addr)); } } } @@ -650,18 +652,12 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ bool_t enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); switch (state){ case LinphoneCallStreamsRunning: - if (enabled!=call->log->reporting.was_video_running){ - if (enabled){ - linphone_reporting_update_ip(call); - }else{ - ms_message("Send midterm report with status %d", - send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport") - ); - } - }else{ - linphone_reporting_update_ip(call); + linphone_reporting_update_ip(call); + if (!enabled && call->log->reporting.was_video_running){ + ms_message("Send midterm report with status %d", + send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport") + ); } - call->log->reporting.was_video_running=enabled; break; case LinphoneCallEnd: diff --git a/mediastreamer2 b/mediastreamer2 index 7bf89d430..24427ed56 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7bf89d4302afb266bb359d7af8c16907ae8c327e +Subproject commit 24427ed565a93f523b44b43ed9b2d20f8cea5385 diff --git a/tester/Makefile.am b/tester/Makefile.am index 46ffb12cd..afa7f77a9 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -20,7 +20,8 @@ liblinphonetester_la_SOURCES = tester.c \ eventapi_tester.c \ flexisip_tester.c \ stun_tester.c \ - remote_provisioning_tester.c + remote_provisioning_tester.c \ + quality_reporting_tester.c liblinphonetester_la_LDFLAGS= -no-undefined liblinphonetester_la_LIBADD= ../coreapi/liblinphone.la $(CUNIT_LIBS) @@ -32,14 +33,14 @@ if !BUILD_IOS noinst_PROGRAMS = liblinphone_tester -liblinphone_tester_SOURCES = liblinphone_tester.c -liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la +liblinphone_tester_SOURCES = liblinphone_tester.c +liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la endif test: liblinphone_tester - ./liblinphone_tester --config $(abs_srcdir) + ./liblinphone_tester --config $(abs_srcdir) else !BUILD_CUNIT_TESTS diff --git a/tester/call_tester.c b/tester/call_tester.c index b8a66f82e..534065a7a 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2171,120 +2171,6 @@ static void call_rejected_without_403_because_wrong_credentials_no_auth_req_cb() call_rejected_because_wrong_credentials_with_params("tester-no-403",FALSE); } -void create_call_for_quality_reporting_tests( - LinphoneCoreManager* marie, - LinphoneCoreManager* pauline, - LinphoneCall** call_marie, - LinphoneCall** call_pauline) { - CU_ASSERT_TRUE(call(pauline,marie)); - *call_marie = linphone_core_get_current_call(marie->lc); - *call_pauline = linphone_core_get_current_call(pauline->lc); - CU_ASSERT_PTR_NOT_NULL(*call_marie); - CU_ASSERT_PTR_NOT_NULL(*call_pauline); -} - -static void quality_reporting_not_used_without_config() { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall* call_marie = NULL; - LinphoneCall* call_pauline = NULL; - - create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); - - // marie has stats collection enabled since pauline has not - CU_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(call_marie->dest_proxy)); - CU_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(call_pauline->dest_proxy)); - - CU_ASSERT_EQUAL(strcmp("sip:collector@sip.example.org", - linphone_proxy_config_get_quality_reporting_collector(call_marie->dest_proxy)), 0); - - // this field should be already filled - CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->info.local_addr.ip); - CU_ASSERT_PTR_NULL(call_pauline->log->reporting.reports[0]->info.local_addr.ip); - - // but not this one since it is updated at the end of call - CU_ASSERT_PTR_NULL(call_marie->log->reporting.reports[0]->dialog_id); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} -static void quality_reporting_not_sent_if_call_not_started() { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCallLog* out_call_log; - LinphoneCall* out_call; - - linphone_core_set_max_calls(pauline->lc,0); - out_call = linphone_core_invite(marie->lc,"pauline"); - linphone_call_ref(out_call); - - CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallError,1, 10000)); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); - - if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) { - CU_ASSERT_PTR_NOT_NULL(out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data)); - CU_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted); - } - linphone_call_unref(out_call); - - // wait a few time... - wait_for(marie->lc,NULL,NULL,0); - // since the callee was busy, there should be no publish to do - CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); - CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} -static void quality_reporting_at_call_termination() { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall* call_marie = NULL; - LinphoneCall* call_pauline = NULL; - - create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); - - linphone_core_terminate_all_calls(marie->lc); - - // now dialog id should be filled - CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->dialog_id); - - CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); - CU_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); - - CU_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc)); - CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc)); - - - // PUBLISH submission to the collector should be ok - CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); - CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - -static void quality_reporting_interval_report() { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall* call_marie = NULL; - LinphoneCall* call_pauline = NULL; - - create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); - linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 3); - - CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc)); - CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc)); - - // PUBLISH submission to the collector should be ok - CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,3,25000)); - CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,3,25000)); - - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); -} - - #ifdef VIDEO_ENABLED /*this is call forking with early media managed at client side (not by flexisip server)*/ static void multiple_early_media(void) { @@ -2362,7 +2248,7 @@ static void multiple_early_media(void) { info=linphone_core_create_info_message(marie1->lc); linphone_call_send_info_message(marie1_call,info); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_inforeceived,1,2000)); - + linphone_core_terminate_all_calls(pauline->lc); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallEnd,1,2000)); @@ -2438,10 +2324,6 @@ test_t call_tests[] = { { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, { "Call redirected by callee", call_redirect}, - { "Quality reporting not used if no config", quality_reporting_not_used_without_config}, - { "Quality reporting session report not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, - { "Quality reporting session report sent if call ended normally", quality_reporting_at_call_termination}, - { "Quality reporting interval report if interval is configured", quality_reporting_interval_report}, { "Call with specified codec bitrate", call_with_specified_codec_bitrate} }; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 825e16727..b11cbefaf 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -147,7 +147,7 @@ return -1; \ int main (int argc, char *argv[]) { - int i,j; + int i; int ret; const char *suite_name=NULL; const char *test_name=NULL; @@ -189,10 +189,7 @@ int main (int argc, char *argv[]) CHECK_ARG("--suite", ++i, argc); suite_name=argv[i]; } else if (strcmp(argv[i],"--list-suites")==0){ - for(j=0;j. +*/ + +#include +#include "CUnit/Basic.h" +#include "linphonecore.h" +#include "private.h" +#include "liblinphone_tester.h" + +void create_call_for_quality_reporting_tests( + LinphoneCoreManager* marie, + LinphoneCoreManager* pauline, + LinphoneCall** call_marie, + LinphoneCall** call_pauline) { + CU_ASSERT_TRUE(call(pauline,marie)); + *call_marie = linphone_core_get_current_call(marie->lc); + *call_pauline = linphone_core_get_current_call(pauline->lc); + CU_ASSERT_PTR_NOT_NULL(*call_marie); + CU_ASSERT_PTR_NOT_NULL(*call_pauline); +} + +static void quality_reporting_not_used_without_config() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + + // marie has stats collection enabled since pauline has not + CU_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(call_marie->dest_proxy)); + CU_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(call_pauline->dest_proxy)); + + CU_ASSERT_EQUAL(strcmp("sip:collector@sip.example.org", + linphone_proxy_config_get_quality_reporting_collector(call_marie->dest_proxy)), 0); + + // this field should be already filled + CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->info.local_addr.ip); + + // but not this one since it is updated at the end of call + CU_ASSERT_PTR_NULL(call_marie->log->reporting.reports[0]->dialog_id); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void quality_reporting_not_sent_if_call_not_started() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallLog* out_call_log; + LinphoneCall* out_call; + + linphone_core_set_max_calls(pauline->lc,0); + out_call = linphone_core_invite(marie->lc,"pauline"); + linphone_call_ref(out_call); + + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallError,1, 10000)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallError,1); + + if (ms_list_size(linphone_core_get_call_logs(marie->lc))>0) { + out_call_log=(LinphoneCallLog*)(linphone_core_get_call_logs(marie->lc)->data); + CU_ASSERT_PTR_NOT_NULL(out_call_log); + CU_ASSERT_EQUAL(linphone_call_log_get_status(out_call_log),LinphoneCallAborted); + } + linphone_call_unref(out_call); + + // wait a few time... + wait_for_until(marie->lc,NULL,NULL,0,1000); + + // since the callee was busy, there should be no publish to do + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} +static void quality_reporting_at_call_termination() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + + linphone_core_terminate_all_calls(marie->lc); + + // now dialog id should be filled + CU_ASSERT_PTR_NOT_NULL(call_marie->log->reporting.reports[0]->dialog_id); + + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallReleased,1, 10000)); + CU_ASSERT_TRUE(wait_for_until(pauline->lc,NULL,&pauline->stat.number_of_LinphoneCallReleased,1, 10000)); + + CU_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc)); + + + // PUBLISH submission to the collector should be ok + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); + CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void quality_reporting_interval_report() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 3); + + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(pauline->lc)); + + // PUBLISH submission to the collector should be ok + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,3,25000)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,3,25000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void quality_reporting_session_report_if_video_stopped() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + LinphoneCallParams* pauline_params; + LinphoneCallParams* marie_params; + + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, FALSE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, FALSE); + marie_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_video(marie_params,TRUE); + pauline_params=linphone_core_create_default_call_parameters(pauline->lc); + linphone_call_params_enable_video(pauline_params,TRUE); + CU_ASSERT_TRUE(call_with_params(pauline,marie,pauline_params,marie_params)); + call_marie=linphone_core_get_current_call(marie->lc); + call_pauline=linphone_core_get_current_call(pauline->lc); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); + + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,NULL,0,3000)); + CU_ASSERT_TRUE(linphone_call_params_video_enabled(linphone_call_get_current_params(call_pauline))); + + /*remove video*/ + linphone_call_params_enable_video(pauline_params,FALSE); + linphone_core_update_call(pauline->lc,call_pauline,pauline_params); + + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,1,5000)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,1,5000)); + + CU_ASSERT_FALSE(linphone_call_params_video_enabled(linphone_call_get_current_params(call_pauline))); + + linphone_core_terminate_all_calls(marie->lc); + + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,2,5000)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishOk,2,5000)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + +test_t quality_reporting_tests[] = { + { "Not used if no config", quality_reporting_not_used_without_config}, + { "Call term session report not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, + { "Call term session report sent if call ended normally", quality_reporting_at_call_termination}, + { "Interval report if interval is configured", quality_reporting_interval_report}, + { "Session report sent if video stopped during call", quality_reporting_session_report_if_video_stopped}, +}; + +test_suite_t quality_reporting_test_suite = { + "QualityReporting", + NULL, + NULL, + sizeof(quality_reporting_tests) / sizeof(quality_reporting_tests[0]), + quality_reporting_tests +}; diff --git a/tester/tester.c b/tester/tester.c index 1f1c8d725..268a0f302 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -291,6 +291,13 @@ int liblinphone_tester_test_suite_index(const char *suite_name) { return -1; } +void liblinphone_tester_list_suites() { + int j; + for(j=0;jpName); + return -2; + } else { + CU_ErrorCode err= CU_basic_run_test(suite, test); + if (err != CUE_SUCCESS) ms_error("CU_basic_run_test error %d", err); + } + } else { CU_basic_run_suite(suite); + } } else { #if HAVE_CU_CURSES From 0d5af07a7e14550a70a77a954e9f86eba9848f64 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Jun 2014 16:27:19 +0200 Subject: [PATCH 110/201] fix memory leaks --- coreapi/bellesip_sal/sal_impl.c | 8 +++++--- coreapi/bellesip_sal/sal_op_call.c | 1 + coreapi/bellesip_sal/sal_op_impl.c | 2 +- coreapi/callbacks.c | 6 +++++- coreapi/event.c | 20 ++++++++++++++++++-- tester/call_tester.c | 24 +++++++++++++++++------- tester/message_tester.c | 5 +++-- 7 files changed, 50 insertions(+), 16 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 224bd73ee..c4809ecc6 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -97,14 +97,13 @@ void sal_disable_logs() { void sal_add_pending_auth(Sal *sal, SalOp *op){ if (ms_list_find(sal->pending_auths,op)==NULL){ - sal->pending_auths=ms_list_append(sal->pending_auths,sal_op_ref(op)); + sal->pending_auths=ms_list_append(sal->pending_auths,op); } } void sal_remove_pending_auth(Sal *sal, SalOp *op){ if (ms_list_find(sal->pending_auths,op)){ sal->pending_auths=ms_list_remove(sal->pending_auths,op); - sal_op_unref(op); } } @@ -157,7 +156,10 @@ void sal_process_authentication(SalOp *op) { } } /*always store auth info, for case of wrong credential*/ - if (op->auth_info) sal_auth_info_delete(op->auth_info); + if (op->auth_info) { + sal_auth_info_delete(op->auth_info); + op->auth_info=NULL; + } if (auth_list){ auth_event=(belle_sip_auth_event_t*)(auth_list->data); op->auth_info=sal_auth_info_create(auth_event); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f2363af83..26bbdb038 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -167,6 +167,7 @@ static void cancelling_invite(SalOp* op ){ sal_op_send_request(op,cancel); op->state=SalOpStateTerminating; } + static int vfu_retry (void *user_data, unsigned int events) { SalOp *op=(SalOp *)user_data; sal_call_send_vfu_request(op); diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 1a49cd65c..649a4e240 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -44,8 +44,8 @@ void sal_op_release(SalOp *op){ void sal_op_release_impl(SalOp *op){ ms_message("Destroying op [%p] of type [%s]",op,sal_op_type_to_string(op->type)); if (op->pending_auth_transaction) belle_sip_object_unref(op->pending_auth_transaction); + sal_remove_pending_auth(op->base.root,op); if (op->auth_info) { - sal_remove_pending_auth(op->base.root,op); sal_auth_info_delete(op->auth_info); } if (op->sdp_answer) belle_sip_object_unref(op->sdp_answer); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 16b2b9d92..121291a00 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -817,7 +817,11 @@ static void call_released(SalOp *op){ LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op); if (call!=NULL){ linphone_call_set_state(call,LinphoneCallReleased,"Call released"); - }else ms_error("call_released() for already destroyed call ?"); + }else{ + /*we can arrive here when the core manages call at Sal level without creating a LinphoneCall object. Typicially: + * - when declining an incoming call with busy because maximum number of calls is reached. + */ + } } static void auth_failure(SalOp *op, SalAuthInfo* info) { diff --git a/coreapi/event.c b/coreapi/event.c index b1c7b110d..992d058ab 100644 --- a/coreapi/event.c +++ b/coreapi/event.c @@ -79,12 +79,15 @@ static LinphoneEvent *linphone_event_new_with_op_base(LinphoneCore *lc, SalOp *o lev->is_out_of_dialog_op=is_out_of_dialog; return lev; } + LinphoneEvent *linphone_event_new_with_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) { return linphone_event_new_with_op_base(lc,op,dir,name,FALSE); } + LinphoneEvent *linphone_event_new_with_out_of_dialog_op(LinphoneCore *lc, SalOp *op, LinphoneSubscriptionDir dir, const char *name) { return linphone_event_new_with_op_base(lc,op,dir,name,TRUE); } + void linphone_event_set_state(LinphoneEvent *lev, LinphoneSubscriptionState state){ LinphoneCore *lc=lev->lc; if (lev->subscription_state!=state){ @@ -107,9 +110,22 @@ void linphone_event_set_publish_state(LinphoneEvent *lev, LinphonePublishState s if (lc->vtable.publish_state_changed){ lc->vtable.publish_state_changed(lev->lc,lev,state); } - if (state==LinphonePublishCleared){ - linphone_event_unref(lev); + switch(state){ + case LinphonePublishCleared: + linphone_event_unref(lev); + break; + case LinphonePublishOk: + case LinphonePublishError: + if (lev->expires==-1) + linphone_event_unref(lev); + break; + case LinphonePublishNone: + case LinphonePublishProgress: + case LinphonePublishExpiring: + /*nothing special to do*/ + break; } + } } diff --git a/tester/call_tester.c b/tester/call_tester.c index 534065a7a..0c1b50392 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -246,14 +246,24 @@ static void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){ } static void simple_call(void) { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + belle_sip_object_enable_leak_detector(TRUE); + int begin=belle_sip_object_get_object_count(); + int leaked_objects; + { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - CU_ASSERT_TRUE(call(pauline,marie)); - liblinphone_tester_check_rtcp(marie,pauline); - end_call(marie,pauline); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); + CU_ASSERT_TRUE(call(pauline,marie)); + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + } + leaked_objects=belle_sip_object_get_object_count()-begin; + CU_ASSERT_TRUE(leaked_objects==0); + if (leaked_objects>0){ + belle_sip_object_dump_active_objects(); + } } static void call_with_specified_codec_bitrate(void) { diff --git a/tester/message_tester.c b/tester/message_tester.c index 151505c59..9e9132fa5 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -28,7 +28,7 @@ #endif -static char* message_external_body_url; +static char* message_external_body_url=NULL; void text_message_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from_address, const char *message) { stats* counters = get_stats(lc); @@ -52,7 +52,8 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess linphone_chat_message_start_file_download(message); } else if (linphone_chat_message_get_external_body_url(message)) { counters->number_of_LinphoneMessageExtBodyReceived++; - CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); + if (message_external_body_url) + CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); } } From 04d30ac2d68c9e9a633a35a122d4ae0a270fef86 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 10 Jun 2014 16:49:04 +0200 Subject: [PATCH 111/201] Quality reporting: initialize on_action_suggested in LinphoneCallConnected state --- .gitignore | 1 + coreapi/quality_reporting.c | 32 +++++++++++++++++--------------- oRTP | 2 +- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 2adb3b20b..de0a26fd7 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,4 @@ tester/liblinphone_tester tools/lp-gen-wrappers tools/lpc2xml_test tools/xml2lpc_test +coreapi/help/filetransfer diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 52c60f446..288bf7802 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -39,13 +39,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. a. Send only one report at the end of each call. (audio | video?) b. Use interval reports only on "problem" calls that are being closely monitored. - move "on_action_suggested" stuff in init - - The Session report when codec change session fork - video enable/disable <-- what happens if doing stop/resume? - if BYE and continue received packet drop them *************************************************************************** @@ -506,7 +502,6 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->log->reporting.reports[stats_type]; reporting_content_metrics_t * metrics = NULL; - MSQosAnalyzer *analyzer=NULL; LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; @@ -522,15 +517,6 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { metrics = &report->local_metrics; block = stats.sent_rtcp; } - /*should not be done there*/ - if (call->audiostream->ms.use_rc&&call->audiostream->ms.rc){ - analyzer=ms_bitrate_controller_get_qos_analyzer(call->audiostream->ms.rc); - if (analyzer){ - ms_qos_analyzer_set_on_action_suggested(analyzer, - qos_analyzer_on_action_suggested, - &report->local_metrics); - } - } do{ if (rtcp_is_XR(block) && (rtcp_XR_get_block_type(block) == RTCP_XR_VOIP_METRICS)){ @@ -651,6 +637,23 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ LinphoneCallState state=linphone_call_get_state(call); bool_t enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); switch (state){ + case LinphoneCallConnected:{ + int i; + MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; + MSQosAnalyzer *analyzer; + for (i=0;i<2;i++){ + if (streams[i]==NULL) + continue; + + analyzer=ms_bitrate_controller_get_qos_analyzer(streams[i]->rc); + if (analyzer){ + ms_qos_analyzer_set_on_action_suggested(analyzer, + qos_analyzer_on_action_suggested, + &call->log->reporting.reports[i]->local_metrics); + } + } + break; + } case LinphoneCallStreamsRunning: linphone_reporting_update_ip(call); if (!enabled && call->log->reporting.was_video_running){ @@ -668,7 +671,6 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ } break; default: - break; } } diff --git a/oRTP b/oRTP index 9d85ca0e1..c5bf1ca7a 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 9d85ca0e1a117a2fbfb02de8df3b19bd5eb5db81 +Subproject commit c5bf1ca7a3d27169b8853769426dceb0b15c90db From 509474e4a58345df4047f4bd1f8c9878324670df Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 10 Jun 2014 19:39:11 +0200 Subject: [PATCH 112/201] fix compilation warning --- tester/quality_reporting_tester.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index f098df204..3fccb6c83 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -139,7 +139,7 @@ static void quality_reporting_interval_report() { static void quality_reporting_session_report_if_video_stopped() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - LinphoneCall* call_marie = NULL; + /*LinphoneCall* call_marie = NULL;*/ LinphoneCall* call_pauline = NULL; LinphoneCallParams* pauline_params; LinphoneCallParams* marie_params; @@ -153,7 +153,7 @@ static void quality_reporting_session_report_if_video_stopped() { pauline_params=linphone_core_create_default_call_parameters(pauline->lc); linphone_call_params_enable_video(pauline_params,TRUE); CU_ASSERT_TRUE(call_with_params(pauline,marie,pauline_params,marie_params)); - call_marie=linphone_core_get_current_call(marie->lc); + /*call_marie=linphone_core_get_current_call(marie->lc);*/ call_pauline=linphone_core_get_current_call(pauline->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); From d17848d5b2e703434a149d0c1cc9099ef5c19f4d Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 11 Jun 2014 11:03:07 +0200 Subject: [PATCH 113/201] Quality reporting: fix crash when one or several streams have not adaptive algorithm enabled --- coreapi/quality_reporting.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 288bf7802..b59c3a36c 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -319,7 +319,7 @@ static int send_report(const LinphoneCall* call, reporting_session_report_t * re || report->info.remote_addr.ip == NULL || strlen(report->info.remote_addr.ip) == 0) { ms_warning("QualityReporting[%p]: Trying to submit a %s too early (call duration: %d sec) but %s IP could " "not be retrieved so dropping this report" - , report + , call , report_event , linphone_call_get_duration(call) , (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0) ? "local" : "remote"); @@ -329,7 +329,7 @@ static int send_report(const LinphoneCall* call, reporting_session_report_t * re addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy)); if (addr == NULL) { ms_warning("QualityReporting[%p]: Asked to submit reporting statistics but no collector address found" - , report); + , call); return 2; } @@ -642,7 +642,7 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; MSQosAnalyzer *analyzer; for (i=0;i<2;i++){ - if (streams[i]==NULL) + if (streams[i]==NULL||streams[i]->rc==NULL) continue; analyzer=ms_bitrate_controller_get_qos_analyzer(streams[i]->rc); @@ -657,7 +657,8 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ case LinphoneCallStreamsRunning: linphone_reporting_update_ip(call); if (!enabled && call->log->reporting.was_video_running){ - ms_message("Send midterm report with status %d", + ms_message("QualityReporting[%p]: Send midterm report with status %d", + call, send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport") ); } @@ -665,7 +666,8 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ break; case LinphoneCallEnd: if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){ - ms_message("Send report with status %d", + ms_message("QualityReporting[%p]: Send report with status %d", + call, linphone_reporting_publish_session_report(call, TRUE) ); } From dba8b0de5644daa5eb2083170df5a95c48e4980b Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 11 Jun 2014 14:36:47 +0200 Subject: [PATCH 114/201] Quality reporting: add decisions' timestamp in adaptive algorithm section and fix on_action_suggested callback setting --- coreapi/quality_reporting.c | 97 +++++++++++++++++-------------- coreapi/quality_reporting.h | 9 +-- mediastreamer2 | 2 +- tester/quality_reporting_tester.c | 2 - 4 files changed, 59 insertions(+), 51 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index b59c3a36c..5de9a33f5 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -42,8 +42,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - The Session report when codec change session fork - - if BYE and continue received packet drop them *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -154,6 +152,7 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { if (rm.signal.level != 127) ret|=METRICS_SIGNAL; if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; + if (rm.qos_analyzer.timestamp!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.qos_analyzer.input_leg!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.qos_analyzer.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; if (rm.qos_analyzer.output_leg!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; @@ -287,6 +286,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off if ((available_metrics & METRICS_ADAPTIVE_ALGORITHM) != 0){ append_to_buffer(buffer, size, offset, "\r\nAdaptiveAlg:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " TS=%s", rm.qos_analyzer.timestamp); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN_LEG=%s", rm.qos_analyzer.input_leg); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.qos_analyzer.input); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT_LEG=%s", rm.qos_analyzer.output_leg); @@ -416,6 +416,9 @@ static void qos_analyzer_on_action_suggested(void *user_data, int datac, const c reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; char * appendbuf; + appendbuf=ms_strdup_printf("%s%d;", metrics->qos_analyzer.timestamp?metrics->qos_analyzer.timestamp:"", ms_time(0)); + STR_REASSIGN(metrics->qos_analyzer.timestamp,appendbuf); + STR_REASSIGN(metrics->qos_analyzer.input_leg, ms_strdup(data[0])); appendbuf=ms_strdup_printf("%s%s;", metrics->qos_analyzer.input?metrics->qos_analyzer.input:"", data[1]); STR_REASSIGN(metrics->qos_analyzer.input,appendbuf); @@ -575,6 +578,53 @@ int linphone_reporting_publish_interval_report(LinphoneCall* call) { return publish_report(call, "VQIntervalReport"); } +void linphone_reporting_call_state_updated(LinphoneCall *call){ + LinphoneCallState state=linphone_call_get_state(call); + bool_t enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); + + switch (state){ + case LinphoneCallStreamsRunning:{ + int i; + MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; + MSQosAnalyzer *analyzer; + for (i=0;i<2;i++){ + if (streams[i]==NULL||streams[i]->rc==NULL){ + ms_message("QualityReporting[%p] Cannot set on_action_suggested" + " callback for %s stream because something is null", call, i?"video":"audio"); + continue; + } + + analyzer=ms_bitrate_controller_get_qos_analyzer(streams[i]->rc); + if (analyzer){ + ms_qos_analyzer_set_on_action_suggested(analyzer, + qos_analyzer_on_action_suggested, + &call->log->reporting.reports[i]->local_metrics); + } + } + linphone_reporting_update_ip(call); + if (!enabled && call->log->reporting.was_video_running){ + ms_message("QualityReporting[%p]: Send midterm report with status %d", + call, + send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport") + ); + } + call->log->reporting.was_video_running=enabled; + break; + } + case LinphoneCallEnd:{ + if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){ + ms_message("QualityReporting[%p]: Send end reports with status %d", + call, + linphone_reporting_publish_session_report(call, TRUE) + ); + } + break; + } + default:{ + break; + } + } +} reporting_session_report_t * linphone_reporting_new() { int i; reporting_session_report_t * rm = ms_new0(reporting_session_report_t,1); @@ -625,6 +675,7 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp); if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc); + if (report->local_metrics.qos_analyzer.timestamp != NULL) ms_free(report->local_metrics.qos_analyzer.timestamp); if (report->local_metrics.qos_analyzer.input_leg != NULL) ms_free(report->local_metrics.qos_analyzer.input_leg); if (report->local_metrics.qos_analyzer.input != NULL) ms_free(report->local_metrics.qos_analyzer.input); if (report->local_metrics.qos_analyzer.output_leg != NULL) ms_free(report->local_metrics.qos_analyzer.output_leg); @@ -633,46 +684,4 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { ms_free(report); } -void linphone_reporting_call_state_updated(LinphoneCall *call){ - LinphoneCallState state=linphone_call_get_state(call); - bool_t enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); - switch (state){ - case LinphoneCallConnected:{ - int i; - MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; - MSQosAnalyzer *analyzer; - for (i=0;i<2;i++){ - if (streams[i]==NULL||streams[i]->rc==NULL) - continue; - analyzer=ms_bitrate_controller_get_qos_analyzer(streams[i]->rc); - if (analyzer){ - ms_qos_analyzer_set_on_action_suggested(analyzer, - qos_analyzer_on_action_suggested, - &call->log->reporting.reports[i]->local_metrics); - } - } - break; - } - case LinphoneCallStreamsRunning: - linphone_reporting_update_ip(call); - if (!enabled && call->log->reporting.was_video_running){ - ms_message("QualityReporting[%p]: Send midterm report with status %d", - call, - send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport") - ); - } - call->log->reporting.was_video_running=enabled; - break; - case LinphoneCallEnd: - if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){ - ms_message("QualityReporting[%p]: Send report with status %d", - call, - linphone_reporting_publish_session_report(call, TRUE) - ); - } - break; - default: - break; - } -} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 29fb3c4d0..67a4eed8f 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -98,10 +98,11 @@ typedef struct reporting_content_metrics { /* This should allow us to analysis bad network conditions and quality adaptation on server side*/ struct { - char* input_leg; - char* input; - char* output_leg; - char* output; + char* timestamp; /*time of each decision in seconds*/ + char* input_leg; /*input parameters' name*/ + char* input; /*set of inputs for each decision, semicolon separated*/ + char* output_leg; /*output parameters' name*/ + char* output; /*set of outputs for each decision, semicolon separated*/ } qos_analyzer; // for internal processing diff --git a/mediastreamer2 b/mediastreamer2 index 24427ed56..8e0f6fb25 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 24427ed565a93f523b44b43ed9b2d20f8cea5385 +Subproject commit 8e0f6fb250ed655a136f72e44fbe92fc6c886ae7 diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 3fccb6c83..4bc8a75f4 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -139,7 +139,6 @@ static void quality_reporting_interval_report() { static void quality_reporting_session_report_if_video_stopped() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); - /*LinphoneCall* call_marie = NULL;*/ LinphoneCall* call_pauline = NULL; LinphoneCallParams* pauline_params; LinphoneCallParams* marie_params; @@ -153,7 +152,6 @@ static void quality_reporting_session_report_if_video_stopped() { pauline_params=linphone_core_create_default_call_parameters(pauline->lc); linphone_call_params_enable_video(pauline_params,TRUE); CU_ASSERT_TRUE(call_with_params(pauline,marie,pauline_params,marie_params)); - /*call_marie=linphone_core_get_current_call(marie->lc);*/ call_pauline=linphone_core_get_current_call(pauline->lc); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); From 009f3f83c7bd9b0a573c2945387631deddae23dd Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 11 Jun 2014 14:36:14 +0200 Subject: [PATCH 115/201] Add test for 2 calls --- tester/call_tester.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tester/call_tester.c b/tester/call_tester.c index 0c1b50392..2e01751fd 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -266,6 +266,46 @@ static void simple_call(void) { } } +static void multiple_answers_call() { + /* Scenario is this: pauline calls marie, which is registered 2 times. + Both linphones answer at the same time, and only one should get the + call running, the other should be terminated */ + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" ); + LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" ); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" ); + + LinphoneCall* call1, *call2; + + MSList* lcs = ms_list_append(NULL,pauline->lc); + lcs = ms_list_append(lcs,marie1->lc); + lcs = ms_list_append(lcs,marie2->lc); + + CU_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) ); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat->number_of_LinphoneCallIncomingReceived, 1, 2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat->number_of_LinphoneCallIncomingReceived, 1, 2000)); + + // marie 1 and 2 answer at the same time + call1 = linphone_core_get_current_call(marie1->lc); + call2 = linphone_core_get_current_call(marie2->lc); + + CU_ASSERT_PTR_NOT_NULL_FATAL(call1); + CU_ASSERT_PTR_NOT_NULL_FATAL(call2); + + CU_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0); + CU_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0); + + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat->number_of_LinphoneCallStreamsRunning, 1, 2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat->number_of_LinphoneCallStreamsRunning, 1, 2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat->number_of_LinphoneCallReleased, 1, 2000) ); + + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); + +} + static void call_with_specified_codec_bitrate(void) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -2279,6 +2319,7 @@ test_t call_tests[] = { { "Cancelled ringing call", cancelled_ringing_call }, { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, + { "Multiple answers to a call", multiple_answers_call }, { "Call with media relay", call_with_media_relay}, { "Call with media relay (random ports)", call_with_media_relay_random_ports}, { "Simple call compatibility mode", simple_call_compatibility_mode }, From d00c3c51113161903a7d4580385dd9f94760dd9c Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 11 Jun 2014 17:22:17 +0200 Subject: [PATCH 116/201] Add tests for multiple answers to a call, with both media relay and without --- tester/call_tester.c | 78 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 2e01751fd..16ba90716 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -266,10 +266,12 @@ static void simple_call(void) { } } +#if 0 /* TODO: activate test when the implementation is ready */ static void multiple_answers_call() { /* Scenario is this: pauline calls marie, which is registered 2 times. Both linphones answer at the same time, and only one should get the call running, the other should be terminated */ + char ringbackpath[256]; LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" ); LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" ); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" ); @@ -280,10 +282,19 @@ static void multiple_answers_call() { lcs = ms_list_append(lcs,marie1->lc); lcs = ms_list_append(lcs,marie2->lc); + linphone_core_use_files(pauline->lc, TRUE); + linphone_core_use_files(marie1->lc, TRUE); + linphone_core_use_files(marie2->lc, TRUE); + + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); + + CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + CU_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) ); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat->number_of_LinphoneCallIncomingReceived, 1, 2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat->number_of_LinphoneCallIncomingReceived, 1, 2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000)); // marie 1 and 2 answer at the same time call1 = linphone_core_get_current_call(marie1->lc); @@ -295,15 +306,69 @@ static void multiple_answers_call() { CU_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0); CU_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0); - CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat->number_of_LinphoneCallStreamsRunning, 1, 2000) ); - CU_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat->number_of_LinphoneCallStreamsRunning, 1, 2000) ); - CU_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat->number_of_LinphoneCallReleased, 1, 2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 2000) ); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie1); linphone_core_manager_destroy(marie2); +} +#endif + +static void multiple_answers_call_with_media_relay() { + /* Scenario is this: pauline calls marie, which is registered 2 times. + * Both linphones answer at the same time, and only one should get the + * call running, the other should be terminated */ + char ringbackpath[256]; + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" ); + LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" ); + LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" ); + + LinphoneCall* call1, *call2; + + MSList* lcs = ms_list_append(NULL,pauline->lc); + lcs = ms_list_append(lcs,marie1->lc); + lcs = ms_list_append(lcs,marie2->lc); + + linphone_core_use_files(pauline->lc, TRUE); + linphone_core_use_files(marie1->lc, TRUE); + linphone_core_use_files(marie2->lc, TRUE); + + linphone_core_set_user_agent(pauline->lc, "Natted Linphone", NULL); + linphone_core_set_user_agent(marie1->lc, "Natted Linphone", NULL); + linphone_core_set_user_agent(marie2->lc, "Natted Linphone", NULL); + + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); + + CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + + CU_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) ); + + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000)); + + // marie 1 and 2 answer at the same time + call1 = linphone_core_get_current_call(marie1->lc); + call2 = linphone_core_get_current_call(marie2->lc); + + CU_ASSERT_PTR_NOT_NULL_FATAL(call1); + CU_ASSERT_PTR_NOT_NULL_FATAL(call2); + + CU_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0); + CU_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0); + + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); + CU_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 2000) ); + + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie1); + linphone_core_manager_destroy(marie2); } static void call_with_specified_codec_bitrate(void) { @@ -2319,7 +2384,10 @@ test_t call_tests[] = { { "Cancelled ringing call", cancelled_ringing_call }, { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, +#if 0 /* not yet activated because not implemented */ { "Multiple answers to a call", multiple_answers_call }, +#endif + { "Multiple answers to a call with media relay", multiple_answers_call_with_media_relay }, { "Call with media relay", call_with_media_relay}, { "Call with media relay (random ports)", call_with_media_relay_random_ports}, { "Simple call compatibility mode", simple_call_compatibility_mode }, From 66ad59929f68f4271cf4fcac60b2eeda882e3010 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Wed, 11 Jun 2014 17:46:14 +0200 Subject: [PATCH 117/201] Update flexisip.conf with bye-orphan-dialogs option --- tester/flexisip.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 48f4a054b..c4b2a5894 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -432,6 +432,10 @@ sdp-port-range-max=65535 # Default value: 1 #h264-iframe-decim=1 +# Sends a ACK and BYE to 200 Ok for INVITEs not belonging to any established call. +bye-orphan-dialogs=true + + ## ## The purpose of the Transcoder module is to transparently transcode ## from one audio codec to another to make the communication possible From 8079748a02a7a238418474822c4d19d9b808ad27 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 11 Jun 2014 18:11:35 +0200 Subject: [PATCH 118/201] Add unit tests for call between different RTP profiles (AVP/AVPF/SAVP/SAVPF). --- tester/call_tester.c | 127 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/tester/call_tester.c b/tester/call_tester.c index 16ba90716..ceb9055e3 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2375,6 +2375,115 @@ static void multiple_early_media(void) { } #endif +static void profile_call(bool_t avpf1, bool_t srtp1, bool_t avpf2, bool_t srtp2, const char *expected_profile) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_rc"); + LinphoneProxyConfig *lpc; + const LinphoneCallParams *params; + + if (avpf1) { + linphone_core_get_default_proxy(marie->lc, &lpc); + linphone_proxy_config_enable_avpf(lpc, TRUE); + linphone_proxy_config_set_avpf_rr_interval(lpc, 3); + } + if (avpf2) { + linphone_core_get_default_proxy(pauline->lc, &lpc); + linphone_proxy_config_enable_avpf(lpc, TRUE); + linphone_proxy_config_set_avpf_rr_interval(lpc, 3); + } + if (srtp1) { + if (linphone_core_media_encryption_supported(marie->lc, LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(marie->lc, LinphoneMediaEncryptionSRTP); + } + } + if (srtp2) { + if (linphone_core_media_encryption_supported(pauline->lc, LinphoneMediaEncryptionSRTP)) { + linphone_core_set_media_encryption(pauline->lc, LinphoneMediaEncryptionSRTP); + } + } + + CU_ASSERT_TRUE(call(marie, pauline)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallStreamsRunning, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1)); + params = linphone_call_get_current_params(linphone_core_get_current_call(marie->lc)); + CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); + params = linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc)); + CU_ASSERT_STRING_EQUAL(linphone_call_params_get_rtp_profile(params), expected_profile); + + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); + CU_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallConnected, 1); + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallConnected, 1); + + linphone_core_manager_destroy(pauline); + linphone_core_manager_destroy(marie); +} + +static void avp_to_avp_call(void) { + profile_call(FALSE, FALSE, FALSE, FALSE, "RTP/AVP"); +} + +static void avp_to_avpf_call(void) { + profile_call(FALSE, FALSE, TRUE, FALSE, "RTP/AVP"); +} + +static void avp_to_savp_call(void) { + profile_call(FALSE, FALSE, FALSE, TRUE, "RTP/AVP"); +} + +static void avp_to_savpf_call(void) { + profile_call(FALSE, FALSE, TRUE, TRUE, "RTP/AVP"); +} + +static void avpf_to_avp_call(void) { + profile_call(TRUE, FALSE, FALSE, FALSE, "RTP/AVPF"); +} + +static void avpf_to_avpf_call(void) { + profile_call(TRUE, FALSE, TRUE, FALSE, "RTP/AVPF"); +} + +static void avpf_to_savp_call(void) { + profile_call(TRUE, FALSE, FALSE, TRUE, "RTP/AVPF"); +} + +static void avpf_to_savpf_call(void) { + profile_call(TRUE, FALSE, TRUE, TRUE, "RTP/AVPF"); +} + +static void savp_to_avp_call(void) { + profile_call(FALSE, TRUE, FALSE, FALSE, "RTP/SAVP"); +} + +static void savp_to_avpf_call(void) { + profile_call(FALSE, TRUE, TRUE, FALSE, "RTP/SAVP"); +} + +static void savp_to_savp_call(void) { + profile_call(FALSE, TRUE, FALSE, TRUE, "RTP/SAVP"); +} + +static void savp_to_savpf_call(void) { + profile_call(FALSE, TRUE, TRUE, TRUE, "RTP/SAVP"); +} + +static void savpf_to_avp_call(void) { + profile_call(TRUE, TRUE, FALSE, FALSE, "RTP/SAVPF"); +} + +static void savpf_to_avpf_call(void) { + profile_call(TRUE, TRUE, TRUE, FALSE, "RTP/SAVPF"); +} + +static void savpf_to_savp_call(void) { + profile_call(TRUE, TRUE, FALSE, TRUE, "RTP/SAVPF"); +} + +static void savpf_to_savpf_call(void) { + profile_call(TRUE, TRUE, TRUE, TRUE, "RTP/SAVPF"); +} + test_t call_tests[] = { { "Early declined call", early_declined_call }, { "Call declined", call_declined }, @@ -2443,7 +2552,23 @@ test_t call_tests[] = { { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, { "Call redirected by callee", call_redirect}, - { "Call with specified codec bitrate", call_with_specified_codec_bitrate} + { "Call with specified codec bitrate", call_with_specified_codec_bitrate}, + { "AVP to AVP call", avp_to_avp_call }, + { "AVP to AVPF call", avp_to_avpf_call }, + { "AVP to SAVP call", avp_to_savp_call }, + { "AVP to SAVPF call", avp_to_savpf_call }, + { "AVPF to AVP call", avpf_to_avp_call }, + { "AVPF to AVPF call", avpf_to_avpf_call }, + { "AVPF to SAVP call", avpf_to_savp_call }, + { "AVPF to SAVPF call", avpf_to_savpf_call }, + { "SAVP to AVP call", savp_to_avp_call }, + { "SAVP to AVPF call", savp_to_avpf_call }, + { "SAVP to SAVP call", savp_to_savp_call }, + { "SAVP to SAVPF call", savp_to_savpf_call }, + { "SAVPF to AVP call", savpf_to_avp_call }, + { "SAVPF to AVPF call", savpf_to_avpf_call }, + { "SAVPF to SAVP call", savpf_to_savp_call }, + { "SAVPF to SAVPF call", savpf_to_savpf_call } }; test_suite_t call_test_suite = { From e78765d33f93d8444a3be72674200ea67dbe0108 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 12 Jun 2014 08:26:51 +0200 Subject: [PATCH 119/201] fix compilation issue on mingw --- coreapi/help/filetransfer.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/coreapi/help/filetransfer.c b/coreapi/help/filetransfer.c index ece07d6c2..819330f57 100644 --- a/coreapi/help/filetransfer.c +++ b/coreapi/help/filetransfer.c @@ -64,24 +64,24 @@ static void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMess * function invoked when a file transfer is received. **/ static void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){ - int file=-1; + FILE* file=NULL; if (!linphone_chat_message_get_user_data(message)) { /*first chunk, creating file*/ - file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); - linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/ + file = fopen("receive_file.dump","wb"); + linphone_chat_message_set_user_data(message,(void*)file); /*store fd for next chunks*/ } else { /*next chunk*/ - file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + file = (FILE*)linphone_chat_message_get_user_data(message); if (size==0) { printf("File transfert completed\n"); linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); linphone_chat_message_destroy(message); - close(file); + fclose(file); running=FALSE; } else { /* store content on a file*/ - if (write(file,buff,size)==-1){ + if (fwrite(buff,size,1,file)==-1){ ms_warning("file_transfer_received() write failed: %s",strerror(errno)); } } @@ -120,7 +120,7 @@ static void file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, */ static void message_received(LinphoneCore *lc, LinphoneChatRoom *cr, LinphoneChatMessage *msg) { const LinphoneContent *file_transfer_info = linphone_chat_message_get_file_transfer_information(msg); - printf ("Do you really want to download %s (size %ld)?[Y/n]\nOk, let's go\n", file_transfer_info->name, file_transfer_info->size); + printf ("Do you really want to download %s (size %ld)?[Y/n]\nOk, let's go\n", file_transfer_info->name, (long int)file_transfer_info->size); linphone_chat_message_start_file_download(msg); From 5df2086f6f622b956d4e689f306fd1d2d62046d6 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 12 Jun 2014 08:33:36 +0200 Subject: [PATCH 120/201] update ms2 and ortp (compil fixes) --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 8e0f6fb25..b1baa287e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8e0f6fb250ed655a136f72e44fbe92fc6c886ae7 +Subproject commit b1baa287e0dc18881ebd81fb9938ff89d20fb6a1 diff --git a/oRTP b/oRTP index c5bf1ca7a..7cd4b3ab9 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit c5bf1ca7a3d27169b8853769426dceb0b15c90db +Subproject commit 7cd4b3ab9ea0d60b00d82dd39ccdf2f8aea3c51f From 03b2dade140ae4ac9168771bf73c1268740da2f0 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 11 Jun 2014 15:59:01 +0200 Subject: [PATCH 121/201] Quality reporting: do not send reports on low bandwidth connections --- coreapi/quality_reporting.c | 61 ++++++++++--------------------- coreapi/quality_reporting.h | 2 - tester/quality_reporting_tester.c | 23 +++++++++++- 3 files changed, 42 insertions(+), 44 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 5de9a33f5..d5b28ab17 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,17 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST *************************************************************************** - For codecs that are able to change sample rates, the lowest and highest sample rates MUST be reported (e.g., 8000;16000). - - rlq value: need algo to compute it - - 3.4 overload avoidance? - a. Send only one report at the end of each call. (audio | video?) - b. Use interval reports only on "problem" calls that are being closely monitored. - - - The Session report when - codec change - session fork + rtt SR recuperer *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -108,8 +98,6 @@ static void reset_avg_metrics(reporting_session_report_t * report){ metrics[i]->jitter_buffer.max = 0; metrics[i]->delay.round_trip_delay = 0; - - /*metrics[i]->delay.symm_one_way_delay = 0;*/ } report->last_report_date = ms_time(NULL); } @@ -164,8 +152,6 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, ret|=METRICS_DELAY); IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); - IF_NUM_IN_RANGE(rm.quality_estimates.rlq/rm.rtcp_xr_count, 1, 120, ret|=METRICS_QUALITY_ESTIMATES); - IF_NUM_IN_RANGE(rm.quality_estimates.rcq/rm.rtcp_xr_count, 1, 120, ret|=METRICS_QUALITY_ESTIMATES); } return ret; @@ -210,18 +196,13 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off APPEND_IF_NOT_NULL_STR(buffer, size, offset, " PD=%s", rm.session_description.payload_desc); APPEND_IF(buffer, size, offset, " SR=%d", rm.session_description.sample_rate, rm.session_description.sample_rate != -1); APPEND_IF(buffer, size, offset, " FD=%d", rm.session_description.frame_duration, rm.session_description.frame_duration != -1); - /*append_to_buffer(buffer, size, offset, " FO=%d", rm.session_description.frame_ocets);*/ - /*append_to_buffer(buffer, size, offset, " FPP=%d", rm.session_description.frames_per_sec);*/ - /*append_to_buffer(buffer, size, offset, " PPS=%d", rm.session_description.packets_per_sec);*/ APPEND_IF_NOT_NULL_STR(buffer, size, offset, " FMTP=\"%s\"", rm.session_description.fmtp); APPEND_IF(buffer, size, offset, " PLC=%d", rm.session_description.packet_loss_concealment, rm.session_description.packet_loss_concealment != -1); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " SSUP=%s", rm.session_description.silence_suppression_state);*/ } if ((available_metrics & METRICS_JITTER_BUFFER) != 0){ append_to_buffer(buffer, size, offset, "\r\nJitterBuffer:"); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBA=%d", rm.jitter_buffer.adaptive, 0, 3); - /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBR=%d", rm.jitter_buffer.rate, 0, 15);*/ if (rm.rtcp_xr_count){ APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBN=%d", rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " JBM=%d", rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535); @@ -250,8 +231,6 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay/rm.rtcp_xr_count, 0, 65535); } APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); - /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " OWD=%d", rm.delay.one_way_delay, 0, 65535);*/ - /*APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " SOWD=%d", rm.delay.symm_one_way_delay, 0, 65535);*/ APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " MAJ=%d", rm.delay.mean_abs_jitter, 0, 65535); } @@ -260,7 +239,6 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off append_to_buffer(buffer, size, offset, "\r\nSignal:"); APPEND_IF(buffer, size, offset, " SL=%d", rm.signal.level, rm.signal.level != 127); APPEND_IF(buffer, size, offset, " NL=%d", rm.signal.noise_level, rm.signal.noise_level != 127); - /*append_to_buffer(buffer, size, offset, " RERL=%d", rm.signal.residual_echo_return_loss);*/ } /*if quality estimates metrics are available, rtcp_xr_count should be always not null*/ @@ -269,19 +247,8 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq/rm.rtcp_xr_count)); append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RLQ=%d", rm.quality_estimates.rlq/rm.rtcp_xr_count, 1, 120); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RLQEstAlg=%s", rm.quality_estimates.rlqestalg);*/ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RCQ=%d", rm.quality_estimates.rcq/rm.rtcp_xr_count, 1, 120); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " RCQEstAlgo=%s", rm.quality_estimates.rcqestalg);*/ - /*append_to_buffer(buffer, size, offset, " EXTRI=%d", rm.quality_estimates.extri);*/ - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtRIEstAlg=%s", rm.quality_estimates.extriestalg);*/ - /*append_to_buffer(buffer, size, offset, " EXTRO=%d", rm.quality_estimates.extro);*/ - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " ExtROEstAlg=%s", rm.quality_estimates.extroutestalg);*/ APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQEstAlgo=%s", rm.quality_estimates.moslqestalg);*/ APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str); - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQEstAlgo=%s", rm.quality_estimates.moscqestalg);*/ - /*APPEND_IF_NOT_NULL_STR(buffer, size, offset, " QoEEstAlg=%s", rm.quality_estimates.qoestalg);*/ } if ((available_metrics & METRICS_ADAPTIVE_ALGORITHM) != 0){ @@ -304,7 +271,7 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off ms_free(moscq_str); } -static int send_report(const LinphoneCall* call, reporting_session_report_t * report, const char * report_event) { +static int send_report(LinphoneCall* call, reporting_session_report_t * report, const char * report_event) { LinphoneContent content = {0}; LinphoneAddress *addr; int expires = -1; @@ -313,6 +280,12 @@ static int send_report(const LinphoneCall* call, reporting_session_report_t * re char * buffer; int ret = 0; + /*if we are on a low bandwidth network, do not send reports to not overload it*/ + if (linphone_call_params_low_bandwidth_enabled(linphone_call_get_current_params(call))){ + ms_warning("QualityReporting[%p]: Avoid sending reports on low bandwidth network", call); + return 1; + } + /*if the call was hung up too early, we might have invalid IPs information in that case, we abort the report since it's not useful data*/ if (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0 @@ -323,14 +296,14 @@ static int send_report(const LinphoneCall* call, reporting_session_report_t * re , report_event , linphone_call_get_duration(call) , (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0) ? "local" : "remote"); - return 1; + return 2; } addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy)); if (addr == NULL) { ms_warning("QualityReporting[%p]: Asked to submit reporting statistics but no collector address found" , call); - return 2; + return 3; } buffer = (char *) ms_malloc(size); @@ -364,7 +337,7 @@ static int send_report(const LinphoneCall* call, reporting_session_report_t * re /*(WIP) Memory leak: PUBLISH message is never freed (issue 1283)*/ if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){ - ret=3; + ret=4; } linphone_address_destroy(addr); @@ -502,6 +475,11 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { } } +/* generate random float in interval ] 0.9 t ; 1.1 t [*/ +static float reporting_rand(float t){ + return t * (.2f * (rand() / (RAND_MAX * 1.0f)) + 0.9f); +} + void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->log->reporting.reports[stats_type]; reporting_content_metrics_t * metrics = NULL; @@ -528,7 +506,6 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { metrics->rtcp_xr_count++; - metrics->quality_estimates.rcq += rtcp_XR_voip_metrics_get_r_factor(block); metrics->quality_estimates.moslq += rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; metrics->quality_estimates.moscq += rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; @@ -545,8 +522,9 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { } }while(rtcp_next_packet(block)); - /* check if we should send an interval report */ - if (report_interval>0 && ms_time(NULL)-report->last_report_date>report_interval){ + /* check if we should send an interval report - use a random sending time to + dispatch reports and avoid sending them too close from each other */ + if (report_interval>0 && ms_time(NULL)-report->last_report_date>reporting_rand(report_interval)){ linphone_reporting_publish_interval_report(call); } } @@ -625,6 +603,7 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ } } } + reporting_session_report_t * linphone_reporting_new() { int i; reporting_session_report_t * rm = ms_new0(reporting_session_report_t,1); diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 67a4eed8f..c090c33da 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -88,8 +88,6 @@ typedef struct reporting_content_metrics { // quality estimates - optional struct { - int rlq; // linked to moslq - in [0..120] - int rcq; //voip metrics R factor - no - vary or avg in [0..120] float moslq; // no - vary or avg - voip metrics - in [0..4.9] float moscq; // no - vary or avg - voip metrics - in [0..4.9] } quality_estimates; diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 4bc8a75f4..1c174f810 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -58,6 +58,7 @@ static void quality_reporting_not_used_without_config() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + static void quality_reporting_not_sent_if_call_not_started() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -88,6 +89,26 @@ static void quality_reporting_not_sent_if_call_not_started() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + +static void quality_reporting_not_sent_if_low_bandwidth() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCallParams* marie_params; + + marie_params=linphone_core_create_default_call_parameters(marie->lc); + linphone_call_params_enable_low_bandwidth(marie_params,TRUE); + + CU_ASSERT_TRUE(call_with_params(marie,pauline,marie_params,NULL)); + + linphone_core_terminate_all_calls(marie->lc); + + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void quality_reporting_at_call_termination() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -178,10 +199,10 @@ static void quality_reporting_session_report_if_video_stopped() { linphone_core_manager_destroy(pauline); } - test_t quality_reporting_tests[] = { { "Not used if no config", quality_reporting_not_used_without_config}, { "Call term session report not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, + { "Call term session report not sent if low bandwidth", quality_reporting_not_sent_if_low_bandwidth}, { "Call term session report sent if call ended normally", quality_reporting_at_call_termination}, { "Interval report if interval is configured", quality_reporting_interval_report}, { "Session report sent if video stopped during call", quality_reporting_session_report_if_video_stopped}, From 888f870a82af32a92795d600d5974f5fe8fd70e6 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 11 Jun 2014 17:07:45 +0200 Subject: [PATCH 122/201] Quality reporting: compute RTT using RTCP SR reports too (in case RTCP XR voip metrics not available) - interspace randomly report sending and clean QoS analyzer data stats on report send --- coreapi/quality_reporting.c | 77 +++++++++++++++++++++++++++---------- coreapi/quality_reporting.h | 1 + 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index d5b28ab17..87bccf961 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,7 +31,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST *************************************************************************** - rtt SR recuperer +check: + - removed qos data + - rand interval +todo: + - move qos data at report's end? *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -93,6 +97,7 @@ static void reset_avg_metrics(reporting_session_report_t * report){ reporting_content_metrics_t * metrics[2] = {&report->local_metrics, &report->remote_metrics}; for (i = 0; i < 2; i++) { + metrics[i]->rtcp_sr_count = 0; metrics[i]->rtcp_xr_count = 0; metrics[i]->jitter_buffer.nominal = 0; metrics[i]->jitter_buffer.max = 0; @@ -149,10 +154,12 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { if (rm.rtcp_xr_count>0){ IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); IF_NUM_IN_RANGE(rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); - IF_NUM_IN_RANGE(rm.delay.round_trip_delay, 0, 65535, ret|=METRICS_DELAY); IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); } + if (rm.rtcp_sr_count+rm.rtcp_xr_count>0){ + IF_NUM_IN_RANGE(rm.delay.round_trip_delay/(rm.rtcp_sr_count+rm.rtcp_xr_count), 0, 65535, ret|=METRICS_DELAY); + } return ret; } @@ -227,8 +234,8 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off if ((available_metrics & METRICS_DELAY) != 0){ append_to_buffer(buffer, size, offset, "\r\nDelay:"); - if (rm.rtcp_xr_count){ - APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay/rm.rtcp_xr_count, 0, 65535); + if (rm.rtcp_xr_count+rm.rtcp_sr_count){ + APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " RTD=%d", rm.delay.round_trip_delay/(rm.rtcp_xr_count+rm.rtcp_sr_count), 0, 65535); } APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " ESD=%d", rm.delay.end_system_delay, 0, 65535); APPEND_IF_NUM_IN_RANGE(buffer, size, offset, " IAJ=%d", rm.delay.interarrival_jitter, 0, 65535); @@ -283,7 +290,8 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, /*if we are on a low bandwidth network, do not send reports to not overload it*/ if (linphone_call_params_low_bandwidth_enabled(linphone_call_get_current_params(call))){ ms_warning("QualityReporting[%p]: Avoid sending reports on low bandwidth network", call); - return 1; + ret = 1; + goto end; } /*if the call was hung up too early, we might have invalid IPs information @@ -296,14 +304,16 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, , report_event , linphone_call_get_duration(call) , (report->info.local_addr.ip == NULL || strlen(report->info.local_addr.ip) == 0) ? "local" : "remote"); - return 2; + ret = 2; + goto end; } addr = linphone_address_new(linphone_proxy_config_get_quality_reporting_collector(call->dest_proxy)); if (addr == NULL) { ms_warning("QualityReporting[%p]: Asked to submit reporting statistics but no collector address found" , call); - return 3; + ret = 3; + goto end; } buffer = (char *) ms_malloc(size); @@ -338,11 +348,27 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, /*(WIP) Memory leak: PUBLISH message is never freed (issue 1283)*/ if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){ ret=4; + } else { + reset_avg_metrics(report); + STR_REASSIGN(report->local_metrics.qos_analyzer.timestamp, NULL); + STR_REASSIGN(report->local_metrics.qos_analyzer.input_leg, NULL); + STR_REASSIGN(report->local_metrics.qos_analyzer.input, NULL); + STR_REASSIGN(report->local_metrics.qos_analyzer.output_leg, NULL); + STR_REASSIGN(report->local_metrics.qos_analyzer.output, NULL); } + linphone_address_destroy(addr); - reset_avg_metrics(report); linphone_content_uninit(&content); + + end: + ms_message("QualityReporting[%p]: Send '%s' for '%s' stream with status %d", + call, + report_event, + report->info.local_group, + ret + ); + return ret; } @@ -418,10 +444,16 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); - STR_REASSIGN(report->info.local_group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), - linphone_core_get_user_agent_name(), report->info.call_id)); - STR_REASSIGN(report->info.remote_group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), - linphone_call_get_remote_user_agent(call), report->info.call_id)); + STR_REASSIGN(report->info.local_group, ms_strdup_printf("linphone-%s-%s-%s", + (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), + linphone_core_get_user_agent_name(), + report->info.call_id) + ); + STR_REASSIGN(report->info.remote_group, ms_strdup_printf("linphone-%s-%s-%s", + (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), + linphone_call_get_remote_user_agent(call), + report->info.call_id) + ); if (call->dir == LinphoneCallIncoming) { STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->from)); @@ -519,13 +551,22 @@ void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block); + }else if (rtcp_is_SR(block)){ + MediaStream *ms=(stats_type==0 ? &call->audiostream->ms : &call->videostream->ms); + float rtt = rtp_session_get_round_trip_propagation(ms->sessions.rtp_session); + + if (rtt > 1e-6){ + metrics->rtcp_sr_count++; + metrics->delay.round_trip_delay += 1000*rtt; + } } }while(rtcp_next_packet(block)); /* check if we should send an interval report - use a random sending time to dispatch reports and avoid sending them too close from each other */ if (report_interval>0 && ms_time(NULL)-report->last_report_date>reporting_rand(report_interval)){ - linphone_reporting_publish_interval_report(call); + linphone_reporting_update_media_info(call, stats_type); + send_report(call, report, "VQIntervalReport"); } } @@ -581,20 +622,14 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ } linphone_reporting_update_ip(call); if (!enabled && call->log->reporting.was_video_running){ - ms_message("QualityReporting[%p]: Send midterm report with status %d", - call, - send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport") - ); + send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport"); } call->log->reporting.was_video_running=enabled; break; } case LinphoneCallEnd:{ if (call->log->status==LinphoneCallSuccess || call->log->status==LinphoneCallAborted){ - ms_message("QualityReporting[%p]: Send end reports with status %d", - call, - linphone_reporting_publish_session_report(call, TRUE) - ); + linphone_reporting_publish_session_report(call, TRUE); } break; } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index c090c33da..6111d4250 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -105,6 +105,7 @@ typedef struct reporting_content_metrics { // for internal processing uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5) + uint8_t rtcp_sr_count; // number of RTCP SR packets received since last report, used to compute RTT average values in case RTCP XR voip metrics is not enabled } reporting_content_metrics_t; From ff31a5270ffbb166d7333d0cc889b48086a64db4 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 12 Jun 2014 09:25:55 +0200 Subject: [PATCH 123/201] Quality reporting: avoid crash in rtcp processing function in case the config proxy is not available --- coreapi/linphonecall.c | 2 +- coreapi/quality_reporting.c | 15 +++++++-------- coreapi/quality_reporting.h | 4 ++-- mediastreamer2 | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index b3e4ea740..40c3e197b 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2884,7 +2884,7 @@ void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){ LinphoneCallStats *stats=&call->stats[stream_index]; LinphoneCore *lc=call->core; if (stats->updated){ - linphone_reporting_on_rtcp_received(call, stream_index); + linphone_reporting_on_rtcp_update(call, stream_index); if (lc->vtable.call_stats_updated) lc->vtable.call_stats_updated(lc, call, stats); stats->updated = 0; diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 87bccf961..62a6f071b 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -512,17 +512,18 @@ static float reporting_rand(float t){ return t * (.2f * (rand() / (RAND_MAX * 1.0f)) + 0.9f); } -void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type) { +void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type) { reporting_session_report_t * report = call->log->reporting.reports[stats_type]; reporting_content_metrics_t * metrics = NULL; LinphoneCallStats stats = call->stats[stats_type]; mblk_t *block = NULL; - - int report_interval = linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy); + int report_interval; if (! media_report_enabled(call,stats_type)) return; + report_interval = linphone_proxy_config_get_quality_reporting_interval(call->dest_proxy); + if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { metrics = &report->remote_metrics; block = stats.received_rtcp; @@ -599,10 +600,10 @@ int linphone_reporting_publish_interval_report(LinphoneCall* call) { void linphone_reporting_call_state_updated(LinphoneCall *call){ LinphoneCallState state=linphone_call_get_state(call); - bool_t enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); switch (state){ case LinphoneCallStreamsRunning:{ + bool_t video_enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); int i; MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; MSQosAnalyzer *analyzer; @@ -621,10 +622,10 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ } } linphone_reporting_update_ip(call); - if (!enabled && call->log->reporting.was_video_running){ + if (!video_enabled && call->log->reporting.was_video_running){ send_report(call, call->log->reporting.reports[LINPHONE_CALL_STATS_VIDEO], "VQSessionReport"); } - call->log->reporting.was_video_running=enabled; + call->log->reporting.was_video_running=video_enabled; break; } case LinphoneCallEnd:{ @@ -657,11 +658,9 @@ reporting_session_report_t * linphone_reporting_new() { metrics[i]->session_description.packet_loss_concealment = -1; metrics[i]->jitter_buffer.adaptive = -1; - /*metrics[i]->jitter_buffer.rate = -1;*/ metrics[i]->jitter_buffer.abs_max = -1; metrics[i]->delay.end_system_delay = -1; - /*metrics[i]->delay.one_way_delay = -1;*/ metrics[i]->delay.interarrival_jitter = -1; metrics[i]->delay.mean_abs_jitter = -1; diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 6111d4250..34faa4a9c 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -179,12 +179,12 @@ int linphone_reporting_publish_session_report(LinphoneCall* call, bool_t call_te int linphone_reporting_publish_interval_report(LinphoneCall* call); /** - * Update publish reports with newly received RTCP-XR packets (if available). + * Update publish reports with newly sent/received RTCP-XR packets (if available). * @param call #LinphoneCall object to consider * @param stats_type the media type (LINPHONE_CALL_STATS_AUDIO or LINPHONE_CALL_STATS_VIDEO) * */ -void linphone_reporting_on_rtcp_received(LinphoneCall *call, int stats_type); +void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type); /** * Update publish reports on call state change. diff --git a/mediastreamer2 b/mediastreamer2 index b1baa287e..7a627f30b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b1baa287e0dc18881ebd81fb9938ff89d20fb6a1 +Subproject commit 7a627f30b0462574290e03e99983327e6ea987dc From 7734a7c1da79275b8cd3f93b3e59f074b6fe89a0 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 12 Jun 2014 12:16:39 +0200 Subject: [PATCH 124/201] Add option to freeze or not on video decoding error. --- coreapi/linphonecall.c | 1 + mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 40c3e197b..2a98afef1 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2177,6 +2177,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation); video_stream_set_device_rotation(call->videostream, lc->device_rotation); video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); + video_stream_set_freeze_on_error(call->videostream, lp_config_get_int(lc->config, "video", "freeze_on_error", 0)); video_stream_start(call->videostream, call->video_profile, rtp_addr, vstream->rtp_port, rtcp_addr, diff --git a/mediastreamer2 b/mediastreamer2 index 7a627f30b..9c9d88041 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7a627f30b0462574290e03e99983327e6ea987dc +Subproject commit 9c9d88041cc8859c115a706f5cd7211434336531 From 52c3f0d52131e98260604624b3893ee771ac75b3 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 12 Jun 2014 12:06:16 +0200 Subject: [PATCH 125/201] Quality reporting: move qos_analyzer data at the end of the report and add its name to the report --- coreapi/quality_reporting.c | 74 +++++++++++++++++-------------------- coreapi/quality_reporting.h | 23 ++++++------ mediastreamer2 | 2 +- 3 files changed, 47 insertions(+), 52 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 62a6f071b..ac2e56930 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,11 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST *************************************************************************** -check: - - removed qos data - - rand interval -todo: - - move qos data at report's end? + - move qos data at report's end? <-- unit test recup publish body *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -145,12 +141,6 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { if (rm.signal.level != 127) ret|=METRICS_SIGNAL; if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; - if (rm.qos_analyzer.timestamp!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; - if (rm.qos_analyzer.input_leg!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; - if (rm.qos_analyzer.input!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; - if (rm.qos_analyzer.output_leg!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; - if (rm.qos_analyzer.output!=NULL) ret|=METRICS_ADAPTIVE_ALGORITHM; - if (rm.rtcp_xr_count>0){ IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); IF_NUM_IN_RANGE(rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); @@ -258,15 +248,6 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str); } - if ((available_metrics & METRICS_ADAPTIVE_ALGORITHM) != 0){ - append_to_buffer(buffer, size, offset, "\r\nAdaptiveAlg:"); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " TS=%s", rm.qos_analyzer.timestamp); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN_LEG=%s", rm.qos_analyzer.input_leg); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " IN=%s", rm.qos_analyzer.input); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT_LEG=%s", rm.qos_analyzer.output_leg); - APPEND_IF_NOT_NULL_STR(buffer, size, offset, " OUT=%s", rm.qos_analyzer.output); - } - append_to_buffer(buffer, size, offset, "\r\n"); ms_free(timestamps_start_str); @@ -342,6 +323,17 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, } APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "DialogID: %s\r\n", report->dialog_id); + if (report->qos_analyzer.timestamp!=NULL){ + append_to_buffer(&buffer, &size, &offset, "AdaptiveAlg:"); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " NAME=%s", report->qos_analyzer.name); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " TS=%s", report->qos_analyzer.timestamp); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN_LEG=%s", report->qos_analyzer.input_leg); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN=%s", report->qos_analyzer.input); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT_LEG=%s", report->qos_analyzer.output_leg); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT=%s", report->qos_analyzer.output); + append_to_buffer(&buffer, &size, &offset, "\r\n"); + } + content.data = buffer; content.size = strlen(buffer); @@ -350,11 +342,11 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, ret=4; } else { reset_avg_metrics(report); - STR_REASSIGN(report->local_metrics.qos_analyzer.timestamp, NULL); - STR_REASSIGN(report->local_metrics.qos_analyzer.input_leg, NULL); - STR_REASSIGN(report->local_metrics.qos_analyzer.input, NULL); - STR_REASSIGN(report->local_metrics.qos_analyzer.output_leg, NULL); - STR_REASSIGN(report->local_metrics.qos_analyzer.output, NULL); + STR_REASSIGN(report->qos_analyzer.timestamp, NULL); + STR_REASSIGN(report->qos_analyzer.input_leg, NULL); + STR_REASSIGN(report->qos_analyzer.input, NULL); + STR_REASSIGN(report->qos_analyzer.output_leg, NULL); + STR_REASSIGN(report->qos_analyzer.output, NULL); } linphone_address_destroy(addr); @@ -412,19 +404,19 @@ static void update_ip(LinphoneCall * call, int stats_type) { } static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** data){ - reporting_content_metrics_t *metrics = (reporting_content_metrics_t*) user_data; + reporting_session_report_t *report = (reporting_session_report_t*) user_data; char * appendbuf; - appendbuf=ms_strdup_printf("%s%d;", metrics->qos_analyzer.timestamp?metrics->qos_analyzer.timestamp:"", ms_time(0)); - STR_REASSIGN(metrics->qos_analyzer.timestamp,appendbuf); + appendbuf=ms_strdup_printf("%s%d;", report->qos_analyzer.timestamp?report->qos_analyzer.timestamp:"", ms_time(0)); + STR_REASSIGN(report->qos_analyzer.timestamp,appendbuf); - STR_REASSIGN(metrics->qos_analyzer.input_leg, ms_strdup(data[0])); - appendbuf=ms_strdup_printf("%s%s;", metrics->qos_analyzer.input?metrics->qos_analyzer.input:"", data[1]); - STR_REASSIGN(metrics->qos_analyzer.input,appendbuf); + STR_REASSIGN(report->qos_analyzer.input_leg, ms_strdup(data[0])); + appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.input?report->qos_analyzer.input:"", data[1]); + STR_REASSIGN(report->qos_analyzer.input,appendbuf); - STR_REASSIGN(metrics->qos_analyzer.output_leg, ms_strdup(data[2])); - appendbuf=ms_strdup_printf("%s%s;", metrics->qos_analyzer.output?metrics->qos_analyzer.output:"", data[3]); - STR_REASSIGN(metrics->qos_analyzer.output, appendbuf); + STR_REASSIGN(report->qos_analyzer.output_leg, ms_strdup(data[2])); + appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.output?report->qos_analyzer.output:"", data[3]); + STR_REASSIGN(report->qos_analyzer.output, appendbuf); } void linphone_reporting_update_ip(LinphoneCall * call) { @@ -616,9 +608,10 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ analyzer=ms_bitrate_controller_get_qos_analyzer(streams[i]->rc); if (analyzer){ + STR_REASSIGN(call->log->reporting.reports[i]->qos_analyzer.name, ms_strdup(ms_qos_analyzer_get_name(analyzer))); ms_qos_analyzer_set_on_action_suggested(analyzer, qos_analyzer_on_action_suggested, - &call->log->reporting.reports[i]->local_metrics); + call->log->reporting.reports[i]); } } linphone_reporting_update_ip(call); @@ -688,11 +681,12 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp); if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc); - if (report->local_metrics.qos_analyzer.timestamp != NULL) ms_free(report->local_metrics.qos_analyzer.timestamp); - if (report->local_metrics.qos_analyzer.input_leg != NULL) ms_free(report->local_metrics.qos_analyzer.input_leg); - if (report->local_metrics.qos_analyzer.input != NULL) ms_free(report->local_metrics.qos_analyzer.input); - if (report->local_metrics.qos_analyzer.output_leg != NULL) ms_free(report->local_metrics.qos_analyzer.output_leg); - if (report->local_metrics.qos_analyzer.output != NULL) ms_free(report->local_metrics.qos_analyzer.output); + if (report->qos_analyzer.name != NULL) ms_free(report->qos_analyzer.name); + if (report->qos_analyzer.timestamp != NULL) ms_free(report->qos_analyzer.timestamp); + if (report->qos_analyzer.input_leg != NULL) ms_free(report->qos_analyzer.input_leg); + if (report->qos_analyzer.input != NULL) ms_free(report->qos_analyzer.input); + if (report->qos_analyzer.output_leg != NULL) ms_free(report->qos_analyzer.output_leg); + if (report->qos_analyzer.output != NULL) ms_free(report->qos_analyzer.output); ms_free(report); } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 34faa4a9c..d3ec1013e 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -92,17 +92,6 @@ typedef struct reporting_content_metrics { float moscq; // no - vary or avg - voip metrics - in [0..4.9] } quality_estimates; - // Quality of Service analyzer - custom extension - /* This should allow us to analysis bad network conditions and quality adaptation - on server side*/ - struct { - char* timestamp; /*time of each decision in seconds*/ - char* input_leg; /*input parameters' name*/ - char* input; /*set of inputs for each decision, semicolon separated*/ - char* output_leg; /*output parameters' name*/ - char* output; /*set of outputs for each decision, semicolon separated*/ - } qos_analyzer; - // for internal processing uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5) uint8_t rtcp_sr_count; // number of RTCP SR packets received since last report, used to compute RTT average values in case RTCP XR voip metrics is not enabled @@ -134,6 +123,18 @@ typedef struct reporting_session_report { char * dialog_id; // optional + // Quality of Service analyzer - custom extension + /* This should allow us to analysis bad network conditions and quality adaptation + on server side*/ + struct { + char * name; /*type of the QoS analyzer used*/ + char* timestamp; /*time of each decision in seconds*/ + char* input_leg; /*input parameters' name*/ + char* input; /*set of inputs for each decision, semicolon separated*/ + char* output_leg; /*output parameters' name*/ + char* output; /*set of outputs for each decision, semicolon separated*/ + } qos_analyzer; + // for internal processing time_t last_report_date; } reporting_session_report_t; diff --git a/mediastreamer2 b/mediastreamer2 index 9c9d88041..b921f138a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 9c9d88041cc8859c115a706f5cd7211434336531 +Subproject commit b921f138aee3d6f9340d5a0646f98c121eb560e1 From 634ebdfde15a75a8844e5c07851f9f0c57a1eb8d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 12 Jun 2014 13:39:29 +0200 Subject: [PATCH 126/201] Fix some documentation generation warnings. --- coreapi/event.h | 6 +++--- coreapi/help/doxygen.dox | 8 ++++---- coreapi/linphonecore.c | 9 ++------- coreapi/linphonecore.h | 41 ++++++++++++++++++++-------------------- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/coreapi/event.h b/coreapi/event.h index 4b3e26bd9..0cf107fd7 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -37,9 +37,9 @@ typedef struct _LinphoneEvent LinphoneEvent; * Enum for subscription direction (incoming or outgoing). **/ enum _LinphoneSubscriptionDir{ - LinphoneSubscriptionIncoming, - LinphoneSubscriptionOutgoing, - LinphoneSubscriptionInvalidDir + LinphoneSubscriptionIncoming, /**< Incoming subscription. */ + LinphoneSubscriptionOutgoing, /**< Outgoing subscription. */ + LinphoneSubscriptionInvalidDir /**< Invalid subscription direction. */ }; /** diff --git a/coreapi/help/doxygen.dox b/coreapi/help/doxygen.dox index 656f25e09..8831758d6 100644 --- a/coreapi/help/doxygen.dox +++ b/coreapi/help/doxygen.dox @@ -61,7 +61,7 @@ *like \link linphone_proxy_config_set_server_addr() proxy address \endlink , \link linphone_proxy_config_set_identity() user id \endlink, \link linphone_proxy_config_expires() refresh period \endlink, and so on. *
A created proxy config using linphone_proxy_config_new(), once configured, must be added to #LinphoneCore using function linphone_core_add_proxy_config(). *
It is recommended to set a default \link #LinphoneProxyConfig proxy config \endlink using function linphone_core_set_default_proxy(). Once done, if \link #LinphoneProxyConfig a proxy config \endlink has been configured with attribute \link linphone_proxy_config_enable_register() enable register \endlink , next call to linphone_core_iterate() triggers a SIP register. - *
Registration status is reported by #LinphoneRegistrationStateCb. + *
Registration status is reported by LinphoneCoreRegistrationStateChangedCb. *
*
This pseudo code demonstrates basic registration operations: *
\code @@ -96,7 +96,7 @@ } \endcode *
Authentication: - *
Most of the time, registration requires \ref authentication "authentication" to succed. #LinphoneAuthInfo info must be either added to #LinphoneCore using function linphone_core_add_auth_info() before #LinphoneProxyConfig is added to Linphone core, or on demand from call back #AuthInfoRequested . + *
Most of the time, registration requires \ref authentication "authentication" to succeed. #LinphoneAuthInfo info must be either added to #LinphoneCore using function linphone_core_add_auth_info() before #LinphoneProxyConfig is added to Linphone core, or on demand from call back #LinphoneCoreAuthInfoRequestedCb. *
*
Unregistration: *
Unregistration or any changes to #LinphoneProxyConfig must be first started by a call to function linphone_proxy_config_edit() and validated by function linphone_proxy_config_done() @@ -203,7 +203,7 @@ void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddre * While initiating the second call, the first one is automatically paused. * Then, once the second call is established, the application has the possibility to merge the two calls to form a conference where each participant * (the local participant, the remote destination of the first call, the remote destination of the second call) can talk together. - * This must be done by adding the two calls to the conference using \link linphone_call_add_to_conference() \endlink + * This must be done by adding the two calls to the conference using \link linphone_core_add_to_conference() \endlink * * Once merged into a conference the LinphoneCall objects representing the calls that were established remain unchanged, except that * they are tagged as part of the conference (see \link linphone_call_is_in_conference() \endlink ). The calls in a conference are in the LinphoneCallStreamsRunning state. @@ -270,7 +270,7 @@ and register a keep-alive handler for periodically refreshing the registration. }]; \endcode
  • Incoming call notification while in background mode -
    Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCallStateCb. Here under a speudo code for this operation: +
    Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCoreCallStateChangedCb. Here under a speudo code for this operation: \code if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) { // Create a new notification diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e9c5585e3..452447232 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2377,7 +2377,7 @@ void linphone_core_iterate(LinphoneCore *lc){ * * @ingroup call_control * - * A sip address should look like DisplayName . + * A sip address should look like DisplayName \ . * Basically this function performs the following tasks * - if a phone number is entered, prepend country prefix of the default proxy * configuration, eventually escape the '+' by 00. @@ -2957,7 +2957,7 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * * It is possible to follow the progress of the transfer provided that transferee sends notification about it. * In this case, the transfer_state_changed callback of the #LinphoneCoreVTable is invoked to notify of the state of the new call at the other party. - * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallOutgoingConnected. + * The notified states are #LinphoneCallOutgoingInit , #LinphoneCallOutgoingProgress, #LinphoneCallOutgoingRinging and #LinphoneCallConnected. **/ int linphone_core_transfer_call_to_another(LinphoneCore *lc, LinphoneCall *call, LinphoneCall *dest){ int result = sal_call_refer_with_replaces (call->op,dest->op); @@ -6563,11 +6563,6 @@ bool_t linphone_core_sdp_200_ack_enabled(const LinphoneCore *lc) { return lc->sip_conf.sdp_200_ack!=0; } -/** - * Globaly set an http file transfer server to be used for content type application/vnd.gsma.rcs-ft-http+xml. This value can also be set for a dedicated account using #linphone_proxy_config_set_file_transfer_server - * @param #LinphoneCore to be modified - * @param const char* url of the file server like https://file.linphone.org/upload.php - **/ void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url) { core->file_transfer_server=ms_strdup(server_url); } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 2c02c801d..dd0ff311a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -133,9 +133,9 @@ typedef struct belle_sip_dict LinphoneDictionary; struct _LinphoneContent{ char *type; /** Date: Thu, 12 Jun 2014 17:12:08 +0200 Subject: [PATCH 127/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index b921f138a..67c7dc274 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b921f138aee3d6f9340d5a0646f98c121eb560e1 +Subproject commit 67c7dc27471f1bfa4388b6b8d956b1b095efc6a9 From 6783dc1d64d57481542f6fa8875f42a9b725371c Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 12 Jun 2014 17:21:20 +0200 Subject: [PATCH 128/201] replace obsolete tempnam method with mkstemp --- console/commands.c | 82 +++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/console/commands.c b/console/commands.c index 725ce8e4b..6fbedcc79 100644 --- a/console/commands.c +++ b/console/commands.c @@ -45,7 +45,7 @@ /*************************************************************************** * - * Forward declarations + * Forward declarations * ***************************************************************************/ @@ -190,19 +190,19 @@ static LPC_COMMAND commands[] = { "'conference add : join the call with id 'call id' into the audio conference." "'conference rm : remove the call with id 'call id' from the audio conference." }, - { "mute", lpc_cmd_mute_mic, + { "mute", lpc_cmd_mute_mic, "Mute microphone and suspend voice transmission."}, #ifdef VIDEO_ENABLED { "camera", lpc_cmd_camera, "Send camera output for current call.", "'camera on'\t: allow sending of local camera video to remote end.\n" "'camera off'\t: disable sending of local camera's video to remote end.\n"}, #endif - { "unmute", lpc_cmd_unmute_mic, + { "unmute", lpc_cmd_unmute_mic, "Unmute microphone and resume voice transmission."}, - { "playbackgain", lpc_cmd_playback_gain, + { "playbackgain", lpc_cmd_playback_gain, "Adjust playback gain."}, { "duration", lpc_cmd_duration, "Print duration in seconds of the last call.", NULL }, - + { "autoanswer", lpc_cmd_autoanswer, "Show/set auto-answer mode", "'autoanswer' \t: show current autoanswer mode\n" "'autoanswer enable'\t: enable autoanswer mode\n" @@ -291,7 +291,7 @@ static LPC_COMMAND advanced_commands[] = { { "nortp-on-audio-mute", lpc_cmd_rtp_no_xmit_on_audio_mute, "Set the rtp_no_xmit_on_audio_mute configuration parameter", " If set to 1 then rtp transmission will be muted when\n" - " audio is muted , otherwise rtp is always sent."}, + " audio is muted , otherwise rtp is always sent."}, #ifdef VIDEO_ENABLED { "vwindow", lpc_cmd_video_window, "Control video display window", "'vwindow show': shows video window\n" @@ -321,11 +321,11 @@ static LPC_COMMAND advanced_commands[] = { }, { "register", lpc_cmd_register, "Register in one line to a proxy" , "register "}, { "unregister", lpc_cmd_unregister, "Unregister from default proxy", NULL }, - { "status", lpc_cmd_status, "Print various status information", + { "status", lpc_cmd_status, "Print various status information", "'status register' \t: print status concerning registration\n" "'status autoanswer'\t: tell whether autoanswer mode is enabled\n" "'status hook' \t: print hook status\n" }, - { "ports", lpc_cmd_ports, "Network ports configuration", + { "ports", lpc_cmd_ports, "Network ports configuration", "'ports' \t: prints current used ports.\n" "'ports sip '\t: Sets the sip port.\n" }, { "param", lpc_cmd_param, "parameter set or read as normally given in .linphonerc", @@ -365,7 +365,7 @@ static LPC_COMMAND advanced_commands[] = { /*************************************************************************** * - * Public interface + * Public interface * ***************************************************************************/ @@ -476,7 +476,7 @@ linphonec_command_generator(const char *text, int state) /*************************************************************************** * - * Command handlers + * Command handlers * ***************************************************************************/ @@ -497,7 +497,7 @@ lpc_cmd_help(LinphoneCore *lc, char *arg) commands[i].help); i++; } - + linphonec_out("---------------------------\n"); linphonec_out("Type 'help ' for more details or\n"); linphonec_out(" 'help advanced' to list additional commands.\n"); @@ -515,13 +515,13 @@ lpc_cmd_help(LinphoneCore *lc, char *arg) advanced_commands[i].help); i++; } - + linphonec_out("---------------------------\n"); linphonec_out("Type 'help ' for more details.\n"); return 1; } - + cmd=lpc_find_command(arg); if ( !cmd ) { @@ -579,7 +579,7 @@ lpc_cmd_call(LinphoneCore *lc, char *args) return 1; } -static int +static int lpc_cmd_calls(LinphoneCore *lc, char *args){ const MSList *calls = linphone_core_get_calls(lc); if(calls) @@ -692,7 +692,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args) } return 1; } - + if(strcmp(args,"all")==0){ linphonec_out("We are going to stop all the calls.\n"); linphone_core_terminate_all_calls(lc); @@ -709,7 +709,7 @@ lpc_cmd_terminate(LinphoneCore *lc, char *args) return 1; } return 0; - + } static int @@ -852,7 +852,7 @@ lpc_cmd_firewall(LinphoneCore *lc, char *args) { linphone_core_set_firewall_policy(lc,LinphonePolicyNoFirewall); } - else if (strcmp(args,"upnp")==0) + else if (strcmp(args,"upnp")==0) { linphone_core_set_firewall_policy(lc,LinphonePolicyUseUpnp); } @@ -930,7 +930,7 @@ lpc_friend_name(char **args, char **name) *args = ++end; } else { *name = strsep(args, " "); - + if (NULL == *args) { /* Means there was no separator */ fprintf(stderr, "Either name or address is missing\n"); return 0; @@ -960,7 +960,7 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) args+=4; if ( ! *args ) return 0; friend_num = strtol(args, NULL, 10); -#ifndef _WIN32_WCE +#ifndef _WIN32_WCE if ( errno == ERANGE ) { linphonec_out("Invalid friend number\n"); return 0; @@ -978,11 +978,11 @@ lpc_cmd_friend(LinphoneCore *lc, char *args) if (!strncmp(args, "all", 3)) { friend_num = -1; - } + } else { friend_num = strtol(args, NULL, 10); -#ifndef _WIN32_WCE +#ifndef _WIN32_WCE if ( errno == ERANGE ) { linphonec_out("Invalid friend number\n"); return 0; @@ -1411,7 +1411,7 @@ static int lpc_cmd_pause(LinphoneCore *lc, char *args){ } static int lpc_cmd_resume(LinphoneCore *lc, char *args){ - + if(linphone_core_in_call(lc)) { linphonec_out("There is already a call in process pause or stop it first"); @@ -1450,7 +1450,7 @@ static int lpc_cmd_resume(LinphoneCore *lc, char *args){ } } return 0; - + } static int lpc_cmd_conference(LinphoneCore *lc, char *args){ @@ -1659,7 +1659,7 @@ linphonec_proxy_add(LinphoneCore *lc) } /* - * Final confirmation + * Final confirmation */ while (1) { @@ -1742,12 +1742,12 @@ linphonec_proxy_list(LinphoneCore *lc) const MSList *proxies; int n; int def=linphone_core_get_default_proxy(lc,NULL); - + proxies=linphone_core_get_proxy_config_list(lc); for(n=0;proxies!=NULL;proxies=ms_list_next(proxies),n++){ if (n==def) linphonec_out("****** Proxy %i - this is the default one - *******\n",n); - else + else linphonec_out("****** Proxy %i *******\n",n); linphonec_proxy_display((LinphoneProxyConfig*)proxies->data); } @@ -1789,7 +1789,7 @@ linphonec_friend_display(LinphoneFriend *fr) { LinphoneAddress *uri=linphone_address_clone(linphone_friend_get_address(fr)); char *str; - + linphonec_out("name: %s\n", linphone_address_get_display_name(uri)); linphone_address_set_display_name(uri,NULL); str=linphone_address_as_string(uri); @@ -1874,7 +1874,7 @@ linphonec_friend_delete(LinphoneCore *lc, int num) } } - if (-1 == num) + if (-1 == num) { unsigned int i; for (i = 0 ; i < n ; i++) @@ -1900,7 +1900,7 @@ static int lpc_cmd_register(LinphoneCore *lc, char *args){ char passwd[512]; LinphoneProxyConfig *cfg; const MSList *elem; - + if (!args) { /* it means that you want to register the default proxy */ @@ -1979,7 +1979,7 @@ static int lpc_cmd_duration(LinphoneCore *lc, char *args){ static int lpc_cmd_status(LinphoneCore *lc, char *args) { LinphoneProxyConfig *cfg; - + if ( ! args ) return 0; linphone_core_get_default_proxy(lc,&cfg); if (strstr(args,"register")) @@ -2042,7 +2042,7 @@ static int lpc_cmd_status(LinphoneCore *lc, char *args) default: break; } - + } else return 0; @@ -2101,19 +2101,19 @@ static int lpc_cmd_speak(LinphoneCore *lc, char *args){ char voice[64]; char *sentence; char cl[128]; - char *wavfile; + char wavfile[128]="/tmp/linphonec-espeak-XXXXXX"; int status; FILE *file; - + if (!args) return 0; memset(voice,0,sizeof(voice)); sscanf(args,"%63s",voice); sentence=args+strlen(voice); #ifdef __APPLE__ - wavfile=mktemp("/tmp/linphonec-espeak-XXXXXX"); + mktemp(wavfile); #else - wavfile=tempnam("/tmp/","linphonec-espeak-"); + mkstemp(wavfile); #endif snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile); @@ -2200,7 +2200,7 @@ static void linphonec_codec_list(int type, LinphoneCore *lc){ for(;node!=NULL;node=ms_list_next(node)){ pt=(PayloadType*)(node->data); - linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, + linphonec_out("%2d: %s (%d) %s\n", index, pt->mime_type, pt->clock_rate, linphone_core_payload_type_enabled(lc,pt) ? "enabled" : "disabled"); index++; } @@ -2274,7 +2274,7 @@ static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){ if (arg2 != 0) { n = sscanf(arg2, "%d %d %d", &delay, &tail_len, &frame_size); - if (n == 1) { + if (n == 1) { lp_config_set_int(config,"sound","ec_delay",delay); } else if (n == 2) { @@ -2292,11 +2292,11 @@ static int lpc_cmd_echocancellation(LinphoneCore *lc, char *args){ linphone_core_enable_echo_cancellation(lc,0); } else if (strcmp(arg1,"show")==0){ - linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n", + linphonec_out("echo cancellation is %s; delay %d, tail length %d, frame size %d\n", linphone_core_echo_cancellation_enabled(lc) ? "on" : "off", lp_config_get_int(config,"sound","ec_delay",0), lp_config_get_int(config,"sound","ec_tail_len",0), - lp_config_get_int(config,"sound","ec_framesize",0)); + lp_config_get_int(config,"sound","ec_framesize",0)); } else { return 0; @@ -2346,7 +2346,7 @@ static int lpc_cmd_rtp_no_xmit_on_audio_mute(LinphoneCore *lc, char *args) if(strstr(args,"1"))rtp_xmit_off=TRUE; if(linphone_core_get_current_call (lc)==NULL) linphone_core_set_rtp_no_xmit_on_audio_mute(lc,rtp_xmit_off); - else + else linphonec_out("nortp-on-audio-mute: call in progress - cannot change state\n"); } rtp_xmit_off=linphone_core_get_rtp_no_xmit_on_audio_mute(lc); @@ -2487,7 +2487,7 @@ static int lpc_cmd_states(LinphoneCore *lc, char *args){ static int lpc_cmd_camera(LinphoneCore *lc, char *args){ LinphoneCall *call=linphone_core_get_current_call(lc); bool_t activated=FALSE; - + if (linphone_core_video_enabled (lc)==FALSE){ linphonec_out("Video is disabled, re-run linphonec with -V option."); return 1; From bf47097f2530e170b98491f20a55e28cbb3c2172 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 13 Jun 2014 09:20:50 +0200 Subject: [PATCH 129/201] fix compilation issue on android (replace open by fopen) --- tester/message_tester.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tester/message_tester.c b/tester/message_tester.c index 9e9132fa5..407dc7509 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -61,23 +61,26 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess * function invoked when a file transfer is received. * */ void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size){ - int file=-1; + FILE* file=NULL; + char receive_file[256]; + snprintf(receive_file,sizeof(receive_file), "%s/receive_file.dump", liblinphone_tester_writable_dir_prefix); + if (!linphone_chat_message_get_user_data(message)) { /*first chunk, creating file*/ - file = open("receive_file.dump",O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR); - linphone_chat_message_set_user_data(message,(void*)(long)(0x00000000FFFFFFFF&file)); /*store fd for next chunks*/ + file = fopen("receive_file.dump","wb"); + linphone_chat_message_set_user_data(message,(void*)file); /*store fd for next chunks*/ } else { /*next chunk*/ - file = (int)((long)(linphone_chat_message_get_user_data(message))&0x00000000FFFFFFFF); + file = (FILE*)linphone_chat_message_get_user_data(message); if (size==0) { /* tranfer complerte */ linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); linphone_chat_message_destroy(message); stats* counters = get_stats(lc); counters->number_of_LinphoneMessageExtBodyReceived++; - close(file); + fclose(file); } else { /* store content on a file*/ - if (write(file,buff,size)==-1){ + if (fwrite(buff,size,1,file)==-1){ ms_error("file_transfer_received(): write() failed: %s",strerror(errno)); } } From 8d9145b9756bc5a218e191348916aa84da1edf91 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Jun 2014 10:35:57 +0200 Subject: [PATCH 130/201] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 67c7dc274..ebc30daf0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 67c7dc27471f1bfa4388b6b8d956b1b095efc6a9 +Subproject commit ebc30daf06e5b98eab43257fbf425aac291a7bba diff --git a/oRTP b/oRTP index 7cd4b3ab9..459dd69b8 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 7cd4b3ab9ea0d60b00d82dd39ccdf2f8aea3c51f +Subproject commit 459dd69b898f4d7e2eb74b7ccfa2e0e1093b2376 From 0b6492f7e5cf180b402257e80fec7e0e6c21c48e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 12 Jun 2014 13:50:26 +0200 Subject: [PATCH 131/201] remove outdated comment --- .gitignore | 1 + coreapi/quality_reporting.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index de0a26fd7..047ebb08c 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ tools/lp-gen-wrappers tools/lpc2xml_test tools/xml2lpc_test coreapi/help/filetransfer +tester/receive_file.dump diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index ac2e56930..7dc48e040 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -337,7 +337,6 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, content.data = buffer; content.size = strlen(buffer); - /*(WIP) Memory leak: PUBLISH message is never freed (issue 1283)*/ if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){ ret=4; } else { From dda79c7bc4fa1e5f462c8e2a7dd1f4619aa696b6 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 12 Jun 2014 15:07:22 +0200 Subject: [PATCH 132/201] Quality reporting: check it is enabled before processing call state changes --- coreapi/proxy.c | 10 ++++++---- coreapi/quality_reporting.c | 3 +++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 6b23eebdd..4f39247b6 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -502,13 +502,15 @@ void linphone_proxy_config_set_quality_reporting_collector(LinphoneProxyConfig * if (collector!=NULL && strlen(collector)>0){ LinphoneAddress *addr=linphone_address_new(collector); if (!addr || linphone_address_get_username(addr)==NULL){ - ms_warning("Invalid sip collector identity: %s",collector); - if (addr) - linphone_address_destroy(addr); + ms_error("Invalid SIP collector URI: %s. Quality reporting will be DISABLED.",collector); } else { - if (cfg->quality_reporting_collector != NULL) + if (cfg->quality_reporting_collector != NULL){ ms_free(cfg->quality_reporting_collector); + } cfg->quality_reporting_collector = ms_strdup(collector); + } + + if (addr){ linphone_address_destroy(addr); } } diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 7dc48e040..78e075809 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -592,6 +592,9 @@ int linphone_reporting_publish_interval_report(LinphoneCall* call) { void linphone_reporting_call_state_updated(LinphoneCall *call){ LinphoneCallState state=linphone_call_get_state(call); + if (! quality_reporting_enabled(call)){ + return; + } switch (state){ case LinphoneCallStreamsRunning:{ bool_t video_enabled=media_report_enabled(call, LINPHONE_CALL_STATS_VIDEO); From 929bc9744da09f5b90c178420028ad3b56699c09 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 12 Jun 2014 16:15:35 +0200 Subject: [PATCH 133/201] Quality reporting: add on_report_send callback to check reports content in unit tests --- coreapi/private.h | 2 +- coreapi/quality_reporting.c | 28 +++++---- coreapi/quality_reporting.h | 13 ++++ tester/quality_reporting_tester.c | 101 ++++++++++++++++++++++++++++-- tester/rcfiles/marie_rc_rtcp_xr | 55 ++++++++++++++++ tester/rcfiles/pauline_rc_rtcp_xr | 52 +++++++++++++++ 6 files changed, 233 insertions(+), 18 deletions(-) create mode 100644 tester/rcfiles/marie_rc_rtcp_xr create mode 100644 tester/rcfiles/pauline_rc_rtcp_xr diff --git a/coreapi/private.h b/coreapi/private.h index aec83fa0e..b59ccd906 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -106,6 +106,7 @@ struct _LinphoneCallParams{ struct _LinphoneQualityReporting{ reporting_session_report_t * reports[2]; /**Store information on audio and video media streams (RFC 6035) */ bool_t was_video_running; /*Keep video state since last check in order to detect its (de)activation*/ + LinphoneQualityReportingReportSendCb on_report_sent; }; struct _LinphoneCallLog{ @@ -860,7 +861,6 @@ LinphoneSubscriptionState linphone_subscription_state_from_sal(SalSubscribeStatu const LinphoneContent *linphone_content_from_sal_body(LinphoneContent *obj, const SalBody *ref); void linphone_core_invalidate_friend_subscriptions(LinphoneCore *lc); - /***************************************************************************** * REMOTE PROVISIONING FUNCTIONS * ****************************************************************************/ diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 78e075809..668e2785a 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST *************************************************************************** - - move qos data at report's end? <-- unit test recup publish body + bug ms_debug *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -122,19 +122,15 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { IF_NUM_IN_RANGE(rm.packet_loss.network_packet_loss_rate, 0, 255, ret|=METRICS_PACKET_LOSS); IF_NUM_IN_RANGE(rm.packet_loss.jitter_buffer_discard_rate, 0, 255, ret|=METRICS_PACKET_LOSS); - /*since these are same values than local ones, do not check them*/ - /*if (rm.session_description.payload_type != -1) ret|=METRICS_SESSION_DESCRIPTION;*/ - /*if (rm.session_description.payload_desc != NULL) ret|=METRICS_SESSION_DESCRIPTION;*/ - /*if (rm.session_description.sample_rate != -1) ret|=METRICS_SESSION_DESCRIPTION;*/ - /*if (rm.session_description.fmtp != NULL) ret|=METRICS_SESSION_DESCRIPTION;*/ - if (rm.session_description.frame_duration != -1) ret|=METRICS_SESSION_DESCRIPTION; - if (rm.session_description.packet_loss_concealment != -1) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.payload_type != -1) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.payload_desc != NULL) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.sample_rate != -1) ret|=METRICS_SESSION_DESCRIPTION; + if (rm.session_description.fmtp != NULL) ret|=METRICS_SESSION_DESCRIPTION; IF_NUM_IN_RANGE(rm.jitter_buffer.adaptive, 0, 3, ret|=METRICS_JITTER_BUFFER); IF_NUM_IN_RANGE(rm.jitter_buffer.abs_max, 0, 65535, ret|=METRICS_JITTER_BUFFER); IF_NUM_IN_RANGE(rm.delay.end_system_delay, 0, 65535, ret|=METRICS_DELAY); - /*IF_NUM_IN_RANGE(rm.delay.symm_one_way_delay, 0, 65535, ret|=METRICS_DELAY);*/ IF_NUM_IN_RANGE(rm.delay.interarrival_jitter, 0, 65535, ret|=METRICS_DELAY); IF_NUM_IN_RANGE(rm.delay.mean_abs_jitter, 0, 65535, ret|=METRICS_DELAY); @@ -337,6 +333,13 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, content.data = buffer; content.size = strlen(buffer); + if (call->log->reporting.on_report_sent != NULL){ + call->log->reporting.on_report_sent( + call, + (report==call->log->reporting.reports[0])?LINPHONE_CALL_STATS_AUDIO:LINPHONE_CALL_STATS_VIDEO, + &content); + } + if (! linphone_core_publish(call->core, addr, "vq-rtcpxr", expires, &content)){ ret=4; } else { @@ -485,9 +488,9 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { if (local_payload != NULL) { report->local_metrics.session_description.payload_type = local_payload->type; - STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type)); + if (local_payload->mime_type!=NULL) STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type)); report->local_metrics.session_description.sample_rate = local_payload->clock_rate; - STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp)); + if (local_payload->recv_fmtp!=NULL) STR_REASSIGN(report->local_metrics.session_description.fmtp, ms_strdup(local_payload->recv_fmtp)); } if (remote_payload != NULL) { @@ -694,3 +697,6 @@ void linphone_reporting_destroy(reporting_session_report_t * report) { } +void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb){ + call->log->reporting.on_report_sent = cb; +} diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index d3ec1013e..bffc39c69 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -139,6 +139,9 @@ typedef struct reporting_session_report { time_t last_report_date; } reporting_session_report_t; + +typedef void (*LinphoneQualityReportingReportSendCb)(const LinphoneCall *call, int stream_type, const LinphoneContent *content); + reporting_session_report_t * linphone_reporting_new(); void linphone_reporting_destroy(reporting_session_report_t * report); @@ -194,6 +197,16 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type); */ void linphone_reporting_call_state_updated(LinphoneCall *call); +/** + * Setter of the #LinphoneQualityReportingReportSendCb callback method which is + * notified each time a report will be submitted to the collector, if quality + * reporting is enabled + * @param call #LinphoneCall object to consider + * @param cb #LinphoneQualityReportingReportSendCb callback function to notify + * + */ +void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb); + #ifdef __cplusplus } #endif diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 1c174f810..59e05fc9e 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -22,6 +22,93 @@ #include "private.h" #include "liblinphone_tester.h" +/*avoid crash if x is NULL on libc versions <4.5.26 */ +#define __strstr(x, y) ((x==NULL)?NULL:strstr(x,y)) + +void on_report_send_mandatory(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ + const MediaStream * ms = ((stream_type == LINPHONE_CALL_STATS_AUDIO)?&call->audiostream->ms:&call->videostream->ms); + char * body = (char *)content->data; + char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); + reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + + CU_ASSERT_TRUE( + __strstr(body, "VQIntervalReport\r\n") == body || + __strstr(body, "VQSessionReport\r\n") == body || + __strstr(body, "VQSessionReport: CallTerm\r\n") == body + ); + + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "CallID:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalID:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteID:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "OrigID:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalGroup:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteGroup:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalAddr:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "IP=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PORT=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SSRC=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteAddr:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "IP=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PORT=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SSRC=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Timestamps:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "START=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "STOP=")); + + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SessionDesc:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PT=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PD=")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SR=")); + + /* We should have not reached RemoteMetrics section yet */ + CU_ASSERT_TRUE(!remote_metrics_start || body < remote_metrics_start); + + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "DialogID:")); + + if (report->remote_metrics.rtcp_sr_count&&ms->rc!=NULL){ + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "AdaptiveAlg:")); + } +} + +char * on_report_send_verify_metrics(const reporting_content_metrics_t *metrics, char * body){ + if (metrics->rtcp_xr_count){ + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "SessionDesc:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "JitterBuffer:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PacketLoss:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "QualityEst:")); + } + if (metrics->rtcp_sr_count){ + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Delay:")); + } + + return body; +} + +void on_report_send_with_rtcp_xr_local(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ + char * body = (char*)content->data; + char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); + reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + on_report_send_mandatory(call,stream_type,content); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "LocalMetrics:")); + CU_ASSERT_TRUE(!remote_metrics_start || on_report_send_verify_metrics(&report->local_metrics,body) < remote_metrics_start); +} +void on_report_send_with_rtcp_xr_remote(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ + char * body = (char*)content->data; + reporting_session_report_t * report = call->log->reporting.reports[stream_type]; + + on_report_send_mandatory(call,stream_type,content); + if (report->remote_metrics.rtcp_sr_count+report->remote_metrics.rtcp_xr_count>0){ + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "RemoteMetrics:")); + CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Timestamps:")); + on_report_send_verify_metrics(&report->remote_metrics,body); + } +} +void on_report_send_with_rtcp_xr_both(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ + on_report_send_with_rtcp_xr_local(call,stream_type,content); + on_report_send_with_rtcp_xr_remote(call,stream_type,content); +} + void create_call_for_quality_reporting_tests( LinphoneCoreManager* marie, LinphoneCoreManager* pauline, @@ -42,7 +129,7 @@ static void quality_reporting_not_used_without_config() { create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); - // marie has stats collection enabled since pauline has not + // marie has stats collection enabled but pauline has not CU_ASSERT_TRUE(linphone_proxy_config_quality_reporting_enabled(call_marie->dest_proxy)); CU_ASSERT_FALSE(linphone_proxy_config_quality_reporting_enabled(call_pauline->dest_proxy)); @@ -111,11 +198,12 @@ static void quality_reporting_not_sent_if_low_bandwidth() { static void quality_reporting_at_call_termination() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr"); LinphoneCall* call_marie = NULL; LinphoneCall* call_pauline = NULL; create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + linphone_reporting_set_on_report_send(call_marie, on_report_send_with_rtcp_xr_remote); linphone_core_terminate_all_calls(marie->lc); @@ -128,7 +216,6 @@ static void quality_reporting_at_call_termination() { CU_ASSERT_PTR_NULL(linphone_core_get_current_call(marie->lc)); CU_ASSERT_PTR_NULL(linphone_core_get_current_call(pauline->lc)); - // PUBLISH submission to the collector should be ok CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishProgress,1)); CU_ASSERT_TRUE(wait_for(marie->lc,NULL,&marie->stat.number_of_LinphonePublishOk,1)); @@ -138,12 +225,13 @@ static void quality_reporting_at_call_termination() { } static void quality_reporting_interval_report() { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc_rtcp_xr"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr"); LinphoneCall* call_marie = NULL; LinphoneCall* call_pauline = NULL; create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + linphone_reporting_set_on_report_send(call_marie, on_report_send_mandatory); linphone_proxy_config_set_quality_reporting_interval(call_marie->dest_proxy, 3); CU_ASSERT_PTR_NOT_NULL(linphone_core_get_current_call(marie->lc)); @@ -158,7 +246,7 @@ static void quality_reporting_interval_report() { } static void quality_reporting_session_report_if_video_stopped() { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc_rtcp_xr"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); LinphoneCall* call_pauline = NULL; LinphoneCallParams* pauline_params; @@ -174,6 +262,7 @@ static void quality_reporting_session_report_if_video_stopped() { linphone_call_params_enable_video(pauline_params,TRUE); CU_ASSERT_TRUE(call_with_params(pauline,marie,pauline_params,marie_params)); call_pauline=linphone_core_get_current_call(pauline->lc); + linphone_reporting_set_on_report_send(linphone_core_get_current_call(marie->lc), on_report_send_with_rtcp_xr_local); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishProgress,0); CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); diff --git a/tester/rcfiles/marie_rc_rtcp_xr b/tester/rcfiles/marie_rc_rtcp_xr new file mode 100644 index 000000000..93f8e5bd0 --- /dev/null +++ b/tester/rcfiles/marie_rc_rtcp_xr @@ -0,0 +1,55 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +sip_tls_port=-1 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +composing_idle_timeout=1 + +[auth_info_0] +username=marie +userid=marie +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 +quality_reporting_collector=sip:collector@sip.example.org +quality_reporting_enabled=1 + +[friend_0] +url="Paupoche" +pol=accept +subscribe=0 + + +[rtp] +audio_rtp_port=8070 +video_rtp_port=9072 +rtcp_xr_enabled=1 +rtcp_xr_rcvr_rtt_mode=all +rtcp_xr_rcvr_rtt_max_size=10000 +rtcp_xr_stat_summary_enabled=1 +rtcp_xr_voip_metrics_enabled=1 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG diff --git a/tester/rcfiles/pauline_rc_rtcp_xr b/tester/rcfiles/pauline_rc_rtcp_xr new file mode 100644 index 000000000..331f942ef --- /dev/null +++ b/tester/rcfiles/pauline_rc_rtcp_xr @@ -0,0 +1,52 @@ +[sip] +sip_port=-1 +sip_tcp_port=-1 +sip_tls_port=-1 +default_proxy=0 +ping_with_options=0 +register_only_when_network_is_up=0 +composing_idle_timeout=1 + +[auth_info_0] +username=pauline +userid=pauline +passwd=secret +realm=sip.example.org + + +[proxy_0] +reg_proxy=sip2.linphone.org;transport=tls +reg_route=sip2.linphone.org;transport=tls +reg_identity=sip:pauline@sip.example.org +reg_expires=3600 +reg_sendregister=1 +publish=0 +dial_escape_plus=0 + +#[friend_0] +#url="Mariette" +#pol=accept +#subscribe=0 + +[rtp] +audio_rtp_port=8090 +video_rtp_port=9092 +rtcp_xr_enabled=1 +rtcp_xr_rcvr_rtt_mode=all +rtcp_xr_rcvr_rtt_max_size=10000 +rtcp_xr_stat_summary_enabled=1 +rtcp_xr_voip_metrics_enabled=1 + +[video] +display=0 +capture=0 +show_local=0 +size=vga +enabled=0 +self_view=0 +automatically_initiate=0 +automatically_accept=0 +device=StaticImage: Static picture + +[sound] +echocancellation=0 #to not overload cpu in case of VG From 0021b21feb9f05d454725269c8372ab802e7d07e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 13 Jun 2014 12:56:43 +0200 Subject: [PATCH 134/201] fix bad handling of call transfer sipfrags and compilation warning --- console/commands.c | 6 +++++- coreapi/bellesip_sal/sal_op_call_transfer.c | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/console/commands.c b/console/commands.c index 6fbedcc79..c22c963b0 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2113,7 +2113,11 @@ static int lpc_cmd_speak(LinphoneCore *lc, char *args){ #ifdef __APPLE__ mktemp(wavfile); #else - mkstemp(wavfile); + if (mkstemp(wavfile)==-1){ + ms_error("Could not create temporary filename: %s", strerror(errno)); + linphonec_out("An error occured, please consult logs for details."); + return 1; + } #endif snprintf(cl,sizeof(cl),"espeak -v %s -s 100 -w %s --stdin",voice,wavfile); diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index 5958c8745..84e529091 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -208,7 +208,7 @@ void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event, bel belle_sip_free(refer_to_uri_str); } else { ms_warning("cannot do anything with the refer without destination\n"); - resp = sal_op_create_response_from_request(op,req,501); + resp = sal_op_create_response_from_request(op,req,400); belle_sip_server_transaction_send_response(server_transaction,resp); } @@ -233,9 +233,9 @@ void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *even if (sipfrag){ int code=belle_sip_response_get_status_code(sipfrag); SalReferStatus status=SalReferFailed; - if (code==100){ + if (code<200){ status=SalReferTrying; - }else if (code==200){ + }else if (code<300){ status=SalReferSuccess; }else if (code>=400){ status=SalReferFailed; From 7caaca64ff3e96d202ad9192a0e6dbf76f9deecc Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 13 Jun 2014 14:57:24 +0200 Subject: [PATCH 135/201] Use the iSAC codec and WebRTC echo canceller from the mswebrtc plugin on Android. --- build/android/Android.mk | 29 +++++++++++++++++++++++++---- coreapi/linphonecore_jni.cc | 8 ++++---- mediastreamer2 | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/build/android/Android.mk b/build/android/Android.mk index d815a11a9..438732952 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -160,10 +160,31 @@ LOCAL_CFLAGS += -DHAVE_SILK LOCAL_STATIC_LIBRARIES += libmssilk endif -ifeq ($(BUILD_WEBRTC_ISAC),1) -LOCAL_CFLAGS += -DHAVE_ISAC -LOCAL_STATIC_LIBRARIES += libwebrtc_isacfix_neon -LOCAL_STATIC_LIBRARIES += libwebrtc_spl libwebrtc_isacfix libmsisac +ifneq ($(BUILD_WEBRTC_AECM)$(BUILD_WEBRTC_ISAC),00) +LOCAL_CFLAGS += -DHAVE_WEBRTC +LOCAL_STATIC_LIBRARIES += libmswebrtc +endif +ifneq ($(BUILD_WEBRTC_AECM),0) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_aecm \ + libwebrtc_apm_utility \ + libwebrtc_spl \ + libwebrtc_system_wrappers +ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_aecm_neon \ + libwebrtc_spl_neon +endif +endif +ifneq ($(BUILD_WEBRTC_ISAC),0) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_isacfix \ + libwebrtc_spl +ifeq ($(TARGET_ARCH_ABI), armeabi-v7a) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_isacfix_neon \ + libwebrtc_spl_neon +endif endif ifeq ($(BUILD_G729),1) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 919c813a9..dd84cafba 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -52,8 +52,8 @@ extern "C" void libmssilk_init(); #ifdef HAVE_G729 extern "C" void libmsbcg729_init(); #endif -#ifdef HAVE_ISAC -extern "C" void libmsisac_init(); +#ifdef HAVE_WEBRTC +extern "C" void libmswebrtc_init(); #endif #endif /*ANDROID*/ @@ -787,8 +787,8 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv* #ifdef HAVE_G729 libmsbcg729_init(); #endif -#ifdef HAVE_ISAC - libmsisac_init(); +#ifdef HAVE_WEBRTC + libmswebrtc_init(); #endif jlong nativePtr = (jlong)linphone_core_new( &ldata->vTable diff --git a/mediastreamer2 b/mediastreamer2 index ebc30daf0..903d16fd9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit ebc30daf06e5b98eab43257fbf425aac291a7bba +Subproject commit 903d16fd95c070f8194221142aaa13c17be7d535 From b5bc7172e536a1262893ce6fddfb7a587358c20f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 13 Jun 2014 16:39:47 +0200 Subject: [PATCH 136/201] Quality reporting: SSRC are unsigned int, not int --- coreapi/quality_reporting.c | 6 +++--- mediastreamer2 | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 668e2785a..e69a7ace2 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /*************************************************************************** * TODO / REMINDER LIST *************************************************************************** - bug ms_debug + - negative cum loss without duplications? *************************************************************************** * END OF TODO / REMINDER LIST ****************************************************************************/ @@ -305,9 +305,9 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group); APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group); - append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); + append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); - append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%d\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); + append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); diff --git a/mediastreamer2 b/mediastreamer2 index 903d16fd9..50166e9ec 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 903d16fd95c070f8194221142aaa13c17be7d535 +Subproject commit 50166e9ec9d1ef326a924f797c6fa683b9d193d1 From 8dadd2a95725c14b7d62ae35cff92a28a4027592 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Jun 2014 11:33:10 +0200 Subject: [PATCH 137/201] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 50166e9ec..29d408d0d 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 50166e9ec9d1ef326a924f797c6fa683b9d193d1 +Subproject commit 29d408d0dd2822d5ce426452960df2295c046d27 From de947f440336815397ce43cd86d527556bea9c93 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Jun 2014 14:05:59 +0200 Subject: [PATCH 138/201] Include libxml/parser.h. --- coreapi/chat.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/chat.c b/coreapi/chat.c index 245abccc3..280c4353b 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -27,6 +27,7 @@ #include "lpconfig.h" #include "belle-sip/belle-sip.h" +#include #include #define COMPOSING_DEFAULT_IDLE_TIMEOUT 15 From d4f2c4a099303a91934b1806fa77a1a2a8ec086f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 16 Jun 2014 15:51:42 +0200 Subject: [PATCH 139/201] Quality reporting: fix unit test segfault in case of invalid mediastream pointer --- coreapi/quality_reporting.c | 8 -------- tester/quality_reporting_tester.c | 12 ++++++++---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index e69a7ace2..b3c071bba 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -28,14 +28,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include -/*************************************************************************** - * TODO / REMINDER LIST - *************************************************************************** - - negative cum loss without duplications? - *************************************************************************** - * END OF TODO / REMINDER LIST - ****************************************************************************/ - #define STR_REASSIGN(dest, src) {\ if (dest != NULL) \ ms_free(dest); \ diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 59e05fc9e..438f1ba46 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -26,11 +26,15 @@ #define __strstr(x, y) ((x==NULL)?NULL:strstr(x,y)) void on_report_send_mandatory(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ - const MediaStream * ms = ((stream_type == LINPHONE_CALL_STATS_AUDIO)?&call->audiostream->ms:&call->videostream->ms); char * body = (char *)content->data; char * remote_metrics_start = __strstr(body, "RemoteMetrics:"); reporting_session_report_t * report = call->log->reporting.reports[stream_type]; - + MediaStream * ms; + if (stream_type == LINPHONE_CALL_STATS_AUDIO){ + ms = (MediaStream*)call->audiostream; + }else{ + ms = (MediaStream*)call->videostream; + } CU_ASSERT_TRUE( __strstr(body, "VQIntervalReport\r\n") == body || __strstr(body, "VQSessionReport\r\n") == body || @@ -66,7 +70,7 @@ void on_report_send_mandatory(const LinphoneCall *call, int stream_type, const L CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "DialogID:")); - if (report->remote_metrics.rtcp_sr_count&&ms->rc!=NULL){ + if (report->remote_metrics.rtcp_sr_count&&ms!=NULL&&ms->rc!=NULL){ CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "AdaptiveAlg:")); } } @@ -78,7 +82,7 @@ char * on_report_send_verify_metrics(const reporting_content_metrics_t *metrics, CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "PacketLoss:")); CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "QualityEst:")); } - if (metrics->rtcp_sr_count){ + if (metrics->rtcp_sr_count+metrics->rtcp_xr_count>0){ CU_ASSERT_PTR_NOT_NULL(body=__strstr(body, "Delay:")); } From 62d5838097764d2de7d8001f60d3b3a136f0e016 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 16 Jun 2014 15:52:50 +0200 Subject: [PATCH 140/201] Fix link error when building statically. --- tester/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/Makefile.am b/tester/Makefile.am index afa7f77a9..348306bca 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -34,7 +34,7 @@ if !BUILD_IOS noinst_PROGRAMS = liblinphone_tester liblinphone_tester_SOURCES = liblinphone_tester.c -liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la +liblinphone_tester_LDADD = $(top_builddir)/coreapi/liblinphone.la liblinphonetester.la -lm endif From b18bb2653a27976f5be3254cd064a4fe9e1ca112 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 17 Jun 2014 11:32:27 +0200 Subject: [PATCH 141/201] Update oRTP and ms2 submodules. --- mediastreamer2 | 2 +- oRTP | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mediastreamer2 b/mediastreamer2 index 29d408d0d..df42f0d73 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 29d408d0dd2822d5ce426452960df2295c046d27 +Subproject commit df42f0d73d930079c43ef92808529a4716e72d99 diff --git a/oRTP b/oRTP index 459dd69b8..8d9a4ac29 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 459dd69b898f4d7e2eb74b7ccfa2e0e1093b2376 +Subproject commit 8d9a4ac29b80f6dbb16ef6ca9ed68727a0c7d759 From 26e13f37e7dbd4a609cefa935d985acfe3fef5c0 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 17 Jun 2014 16:12:38 +0200 Subject: [PATCH 142/201] Quality reporting: factorize local/remote variables in addr struct --- coreapi/quality_reporting.c | 42 ++++++++++++++++++------------------- coreapi/quality_reporting.h | 13 +++++------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index b3c071bba..dc36f7a25 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -291,16 +291,16 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, append_to_buffer(&buffer, &size, &offset, "%s\r\n", report_event); append_to_buffer(&buffer, &size, &offset, "CallID: %s\r\n", report->info.call_id); - append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_id); - append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_id); + append_to_buffer(&buffer, &size, &offset, "LocalID: %s\r\n", report->info.local_addr.id); + append_to_buffer(&buffer, &size, &offset, "RemoteID: %s\r\n", report->info.remote_addr.id); append_to_buffer(&buffer, &size, &offset, "OrigID: %s\r\n", report->info.orig_id); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_group); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_group); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalGroup: %s\r\n", report->info.local_addr.group); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteGroup: %s\r\n", report->info.remote_addr.group); append_to_buffer(&buffer, &size, &offset, "LocalAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.local_addr.ip, report->info.local_addr.port, report->info.local_addr.ssrc); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_mac_addr); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "LocalMAC: %s\r\n", report->info.local_addr.mac); append_to_buffer(&buffer, &size, &offset, "RemoteAddr: IP=%s PORT=%d SSRC=%u\r\n", report->info.remote_addr.ip, report->info.remote_addr.port, report->info.remote_addr.ssrc); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_mac_addr); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, "RemoteMAC: %s\r\n", report->info.remote_addr.mac); append_to_buffer(&buffer, &size, &offset, "LocalMetrics:\r\n"); append_metrics_to_buffer(&buffer, &size, &offset, report->local_metrics); @@ -351,7 +351,7 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, ms_message("QualityReporting[%p]: Send '%s' for '%s' stream with status %d", call, report_event, - report->info.local_group, + report->info.local_addr.group, ret ); @@ -430,25 +430,25 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); - STR_REASSIGN(report->info.local_group, ms_strdup_printf("linphone-%s-%s-%s", + STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), linphone_core_get_user_agent_name(), report->info.call_id) ); - STR_REASSIGN(report->info.remote_group, ms_strdup_printf("linphone-%s-%s-%s", + STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("linphone-%s-%s-%s", (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), linphone_call_get_remote_user_agent(call), report->info.call_id) ); if (call->dir == LinphoneCallIncoming) { - STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->from)); - STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->to)); - STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_id)); + STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->from)); + STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->to)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.remote_addr.id)); } else { - STR_REASSIGN(report->info.remote_id, linphone_address_as_string(call->log->to)); - STR_REASSIGN(report->info.local_id, linphone_address_as_string(call->log->from)); - STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_id)); + STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->to)); + STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->from)); + STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_addr.id)); } STR_REASSIGN(report->dialog_id, sal_op_get_dialog_id(call->op)); @@ -664,15 +664,15 @@ reporting_session_report_t * linphone_reporting_new() { void linphone_reporting_destroy(reporting_session_report_t * report) { if (report->info.call_id != NULL) ms_free(report->info.call_id); - if (report->info.local_id != NULL) ms_free(report->info.local_id); - if (report->info.remote_id != NULL) ms_free(report->info.remote_id); + if (report->info.local_addr.id != NULL) ms_free(report->info.local_addr.id); + if (report->info.remote_addr.id != NULL) ms_free(report->info.remote_addr.id); if (report->info.orig_id != NULL) ms_free(report->info.orig_id); if (report->info.local_addr.ip != NULL) ms_free(report->info.local_addr.ip); if (report->info.remote_addr.ip != NULL) ms_free(report->info.remote_addr.ip); - if (report->info.local_group != NULL) ms_free(report->info.local_group); - if (report->info.remote_group != NULL) ms_free(report->info.remote_group); - if (report->info.local_mac_addr != NULL) ms_free(report->info.local_mac_addr); - if (report->info.remote_mac_addr != NULL) ms_free(report->info.remote_mac_addr); + if (report->info.local_addr.group != NULL) ms_free(report->info.local_addr.group); + if (report->info.remote_addr.group != NULL) ms_free(report->info.remote_addr.group); + if (report->info.local_addr.mac != NULL) ms_free(report->info.local_addr.mac); + if (report->info.remote_addr.mac != NULL) ms_free(report->info.remote_addr.mac); if (report->dialog_id != NULL) ms_free(report->dialog_id); if (report->local_metrics.session_description.fmtp != NULL) ms_free(report->local_metrics.session_description.fmtp); if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index bffc39c69..3c387a903 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -28,12 +28,16 @@ extern "C"{ /** - * Linphone quality report sub object storing address related information (IP/port/MAC). + * Linphone quality report sub object storing address related information. */ typedef struct reporting_addr { + char * id; char * ip; int port; uint32_t ssrc; + + char * group; + char * mac; // optional } reporting_addr_t; /** @@ -106,16 +110,9 @@ typedef struct reporting_content_metrics { typedef struct reporting_session_report { struct { char * call_id; - char * local_id; - char * remote_id; char * orig_id; reporting_addr_t local_addr; reporting_addr_t remote_addr; - char * local_group; - char * remote_group; - - char * local_mac_addr; // optional - char * remote_mac_addr; // optional } info; reporting_content_metrics_t local_metrics; From 34cce12c239a468ef675a8f83c3e6bb5f49d72e8 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Wed, 18 Jun 2014 14:32:14 +0200 Subject: [PATCH 143/201] Quality reporting: quote adaptive algo data and add unit test for bad formatted reports --- coreapi/quality_reporting.c | 14 +++++++------- tester/quality_reporting_tester.c | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index dc36f7a25..e16dd8f81 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -313,12 +313,12 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, if (report->qos_analyzer.timestamp!=NULL){ append_to_buffer(&buffer, &size, &offset, "AdaptiveAlg:"); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " NAME=%s", report->qos_analyzer.name); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " TS=%s", report->qos_analyzer.timestamp); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN_LEG=%s", report->qos_analyzer.input_leg); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN=%s", report->qos_analyzer.input); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT_LEG=%s", report->qos_analyzer.output_leg); - APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT=%s", report->qos_analyzer.output); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " NAME=\"%s\"", report->qos_analyzer.name); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " TS=\"%s\"", report->qos_analyzer.timestamp); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN_LEG=\"%s\"", report->qos_analyzer.input_leg); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " IN=\"%s\"", report->qos_analyzer.input); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT_LEG=\"%s\"", report->qos_analyzer.output_leg); + APPEND_IF_NOT_NULL_STR(&buffer, &size, &offset, " OUT=\"%s\"", report->qos_analyzer.output); append_to_buffer(&buffer, &size, &offset, "\r\n"); } @@ -641,11 +641,11 @@ reporting_session_report_t * linphone_reporting_new() { metrics[i]->session_description.payload_type = -1; metrics[i]->session_description.sample_rate = -1; metrics[i]->session_description.frame_duration = -1; + metrics[i]->session_description.packet_loss_concealment = -1; metrics[i]->packet_loss.network_packet_loss_rate = -1; metrics[i]->packet_loss.jitter_buffer_discard_rate = -1; - metrics[i]->session_description.packet_loss_concealment = -1; metrics[i]->jitter_buffer.adaptive = -1; metrics[i]->jitter_buffer.abs_max = -1; diff --git a/tester/quality_reporting_tester.c b/tester/quality_reporting_tester.c index 438f1ba46..b6b449b91 100644 --- a/tester/quality_reporting_tester.c +++ b/tester/quality_reporting_tester.c @@ -200,6 +200,31 @@ static void quality_reporting_not_sent_if_low_bandwidth() { linphone_core_manager_destroy(pauline); } +void on_report_send_remove_fields(const LinphoneCall *call, int stream_type, const LinphoneContent *content){ + char *body = (char*)content->data; + /*corrupt start of the report*/ + strncpy(body, "corrupted report is corrupted", strlen("corrupted report is corrupted")); +} + +static void quality_reporting_invalid_report() { + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCall* call_marie = NULL; + LinphoneCall* call_pauline = NULL; + + create_call_for_quality_reporting_tests(marie, pauline, &call_marie, &call_pauline); + linphone_reporting_set_on_report_send(call_marie, on_report_send_remove_fields); + + linphone_core_terminate_all_calls(marie->lc); + + CU_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishProgress,1)); + CU_ASSERT_TRUE(wait_for_until(marie->lc,pauline->lc,&marie->stat.number_of_LinphonePublishError,1,3000)); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphonePublishOk,0); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void quality_reporting_at_call_termination() { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc_rtcp_xr"); @@ -296,6 +321,7 @@ test_t quality_reporting_tests[] = { { "Not used if no config", quality_reporting_not_used_without_config}, { "Call term session report not sent if call did not start", quality_reporting_not_sent_if_call_not_started}, { "Call term session report not sent if low bandwidth", quality_reporting_not_sent_if_low_bandwidth}, + { "Call term session report invalid if missing mandatory fields", quality_reporting_invalid_report}, { "Call term session report sent if call ended normally", quality_reporting_at_call_termination}, { "Interval report if interval is configured", quality_reporting_interval_report}, { "Session report sent if video stopped during call", quality_reporting_session_report_if_video_stopped}, From e8bd526f74b235d20bff1d4bf774a6a744c2746e Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 18 Jun 2014 15:46:51 +0200 Subject: [PATCH 144/201] Update ms2 submodule for speexec fix. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index df42f0d73..d09fd38aa 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit df42f0d73d930079c43ef92808529a4716e72d99 +Subproject commit d09fd38aa00d38a99eb9470c0f9e117027f4dc50 From 94105aaa1f5cfb43badc5b8fa5f520d1e87bb5ba Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Jun 2014 09:55:19 +0200 Subject: [PATCH 145/201] Handle AVPF RR interval in milliseconds + fix negotiation of rtcp-fb trr-int parameter. --- coreapi/bellesip_sal/sal_sdp.c | 9 ++++----- coreapi/linphonecall.c | 37 ++++++++++++++++++++++++---------- coreapi/linphonecore.c | 9 ++------- coreapi/offeranswer.c | 6 +++++- coreapi/private.h | 3 ++- mediastreamer2 | 2 +- oRTP | 2 +- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 90f38af19..5f71dba0e 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -68,7 +68,7 @@ static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const S if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer)); } -static bool_t is_rtcp_fb_trr_int_the_same_for_all_payloads(const SalStreamDescription *stream, uint8_t *trr_int) { +static bool_t is_rtcp_fb_trr_int_the_same_for_all_payloads(const SalStreamDescription *stream, uint16_t *trr_int) { MSList *pt_it; bool_t first = TRUE; for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { @@ -85,7 +85,7 @@ static bool_t is_rtcp_fb_trr_int_the_same_for_all_payloads(const SalStreamDescri return TRUE; } -static void add_rtcp_fb_trr_int_attribute(belle_sdp_media_description_t *media_desc, int8_t id, uint8_t trr_int) { +static void add_rtcp_fb_trr_int_attribute(belle_sdp_media_description_t *media_desc, int8_t id, uint16_t trr_int) { belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); belle_sdp_rtcp_fb_attribute_set_id(attribute, id); belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_TRR_INT); @@ -106,7 +106,7 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co PayloadType *pt; PayloadTypeAvpfParams avpf_params; bool_t general_trr_int; - uint8_t trr_int = 0; + uint16_t trr_int = 0; general_trr_int = is_rtcp_fb_trr_int_the_same_for_all_payloads(stream, &trr_int); if (general_trr_int == TRUE) { @@ -485,7 +485,6 @@ static void enable_avpf_for_stream(SalStreamDescription *stream) { if (stream->type == SalVideo) { avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; } - avpf_params.trr_interval = 0; payload_type_set_avpf_params(pt, avpf_params); } } @@ -509,7 +508,7 @@ static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb } break; case BELLE_SDP_RTCP_FB_TRR_INT: - avpf_params.trr_interval = (unsigned char)belle_sdp_rtcp_fb_attribute_get_trr_int(fb_attribute); + avpf_params.trr_interval = belle_sdp_rtcp_fb_attribute_get_trr_int(fb_attribute); break; case BELLE_SDP_RTCP_FB_ACK: default: diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 2a98afef1..218bf86fd 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -132,9 +132,9 @@ static bool_t linphone_call_all_streams_avpf_enabled(const LinphoneCall *call) { return ((nb_active_streams > 0) && (nb_active_streams == nb_avpf_enabled_streams)); } -static uint8_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) { - uint8_t rr_interval = 0; - uint8_t stream_rr_interval; +static uint16_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) { + uint16_t rr_interval = 0; + uint16_t stream_rr_interval; if (call) { if (call->audiostream && media_stream_get_state((MediaStream *)call->audiostream) == MSStreamStarted) { stream_rr_interval = media_stream_get_avpf_rr_interval((MediaStream *)call->audiostream); @@ -145,7 +145,7 @@ static uint8_t linphone_call_get_avpf_rr_interval(const LinphoneCall *call) { if (stream_rr_interval > rr_interval) rr_interval = stream_rr_interval; } } else { - rr_interval = 5; + rr_interval = 5000; } return rr_interval; } @@ -682,6 +682,26 @@ static void linphone_call_incoming_select_ip_version(LinphoneCall *call){ }else call->af=AF_INET; } +/** + * Fix call parameters on incoming call to eg. enable AVPF if the incoming call propose it and it is not enabled locally. + */ +void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md) { + call->params.has_video &= linphone_core_media_description_contains_video_stream(md); + + /* Handle AVPF and SRTP. */ + call->params.avpf_enabled = sal_media_description_has_avpf(md); + if (call->params.avpf_enabled == TRUE) { + if (call->dest_proxy != NULL) { + call->params.avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(call->dest_proxy) * 1000; + } else { + call->params.avpf_rr_interval = 5000; + } + } + if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { + call->params.media_encryption = LinphoneMediaEncryptionSRTP; + } +} + LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call=ms_new0(LinphoneCall,1); char *from_str; @@ -716,6 +736,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_core_get_local_ip(lc,call->af,call->localip); linphone_call_init_common(call, from, to); call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/ + call->dest_proxy = linphone_core_lookup_known_proxy(call->core, to); linphone_core_init_default_params(lc, &call->params); /* @@ -730,13 +751,7 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro if (md) { // It is licit to receive an INVITE without SDP // In this case WE chose the media parameters according to policy. - call->params.has_video &= linphone_core_media_description_contains_video_stream(md); - - /* Handle AVPF and SRTP. */ - call->params.avpf_enabled = sal_media_description_has_avpf(md); - if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { - call->params.media_encryption = LinphoneMediaEncryptionSRTP; - } + linphone_call_set_compatible_incoming_call_parameters(call, md); } fpol=linphone_core_get_firewall_policy(call->core); /*create the ice session now if ICE is required*/ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 452447232..9f4cfbd9c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2845,7 +2845,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const if (proxy!=NULL) { from=linphone_proxy_config_get_identity(proxy); cp->avpf_enabled = linphone_proxy_config_avpf_enabled(proxy); - cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy); + cp->avpf_rr_interval = linphone_proxy_config_get_avpf_rr_interval(proxy) * 1000; } /* if no proxy or no identity defined for this proxy, default to primary contact*/ @@ -3428,12 +3428,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, // There might not be a md if the INVITE was lacking an SDP // In this case we use the parameters as is. if (md) { - call->params.has_video &= linphone_core_media_description_contains_video_stream(md); - /* Handle AVPF and SRTP. */ - call->params.avpf_enabled = sal_media_description_has_avpf(md); - if ((sal_media_description_has_srtp(md) == TRUE) && (media_stream_srtp_supported() == TRUE)) { - call->params.media_encryption = LinphoneMediaEncryptionSRTP; - } + linphone_call_set_compatible_incoming_call_parameters(call, md); } linphone_call_prepare_ice(call,TRUE); linphone_call_make_local_media_description(lc,call); diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 779e7ae65..d7d2e6e84 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -101,7 +101,11 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND; if (p2->flags & PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED) { newp->flags |= PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED; - newp->avpf = payload_type_get_avpf_params(p2); + newp->avpf = payload_type_get_avpf_params(p2); /* Take remote AVPF features */ + /* Take bigger AVPF trr interval */ + if (p2->avpf.trr_interval < matched->avpf.trr_interval) { + newp->avpf.trr_interval = matched->avpf.trr_interval; + } } res=ms_list_append(res,newp); /* we should use the remote numbering even when parsing a response */ diff --git a/coreapi/private.h b/coreapi/private.h index b59ccd906..9cb1b45da 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -100,7 +100,7 @@ struct _LinphoneCallParams{ bool_t in_conference; /*in conference mode */ bool_t low_bandwidth; LinphonePrivacyMask privacy; - uint8_t avpf_rr_interval; + uint16_t avpf_rr_interval; }; struct _LinphoneQualityReporting{ @@ -255,6 +255,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op); void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const char *message); void linphone_call_set_contact_op(LinphoneCall* call); +void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, const SalMediaDescription *md); /* private: */ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *local, LinphoneAddress * remote); void linphone_call_log_completed(LinphoneCall *call); diff --git a/mediastreamer2 b/mediastreamer2 index d09fd38aa..e4ee08232 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d09fd38aa00d38a99eb9470c0f9e117027f4dc50 +Subproject commit e4ee08232c70023bf772b6499752bd682671b99c diff --git a/oRTP b/oRTP index 8d9a4ac29..e4a235076 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 8d9a4ac29b80f6dbb16ef6ca9ed68727a0c7d759 +Subproject commit e4a235076787acef6e97eb7a15b400f91fd4f481 From ae4298faaf531741fe29f03c448a0b0d3a429c6a Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 19 Jun 2014 11:59:49 +0200 Subject: [PATCH 146/201] video recorder in place --- coreapi/linphonecore.c | 2 +- coreapi/linphonecore.h | 8 ++++++++ coreapi/misc.c | 15 +++++++++++++++ coreapi/private.h | 1 + gtk/main.c | 18 ++++++++++++++---- mediastreamer2 | 2 +- 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 452447232..0befb3cd4 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -5930,7 +5930,7 @@ static void linphone_core_uninit(LinphoneCore *lc) linphone_presence_model_unref(lc->presence_model); } linphone_core_free_payload_types(lc); - + if (lc->supported_formats) ms_free(lc->supported_formats); linphone_core_message_storage_close(lc); ms_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index dd0ff311a..89fd4723a 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -2602,6 +2602,14 @@ LINPHONE_PUBLIC void linphone_core_set_tone(LinphoneCore *lc, LinphoneToneID id, * */ LINPHONE_PUBLIC void linphone_core_set_file_transfer_server(LinphoneCore *core, const char * server_url); +/** + * Returns a null terminated table of strings containing the file format extension supported for call recording. + * @param core the core + * @return the supported formats, typically 'wav' and 'mkv' + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const char ** linphone_core_get_supported_file_formats(LinphoneCore *core); + #ifdef __cplusplus } #endif diff --git a/coreapi/misc.c b/coreapi/misc.c index 43b3a3139..a058db102 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1522,3 +1522,18 @@ const MSCryptoSuite * linphone_core_get_srtp_crypto_suites(LinphoneCore *lc){ lc->rtp_conf.srtp_suites=result; return result; } + + + +const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){ + static const char *mkv="mkv"; + static const char *wav="wav"; + if (core->supported_formats==NULL){ + core->supported_formats=ms_malloc0(3*sizeof(char*)); + core->supported_formats[0]=wav; + if (ms_factory_lookup_filter_by_id(ms_factory_get_fallback(),MS_MKV_WRITER_ID)){ + core->supported_formats[1]=mkv; + } + } + return core->supported_formats; +} diff --git a/coreapi/private.h b/coreapi/private.h index b59ccd906..49e3fb72e 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -726,6 +726,7 @@ struct _LinphoneCore MSList *tones; LinphoneReason chat_deny_code; char *file_transfer_server; + const char **supported_formats; }; diff --git a/gtk/main.c b/gtk/main.c index c1a52cda4..c987b4f9e 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -983,6 +983,9 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_ char date[64]={0}; time_t curtime=time(NULL); struct tm loctime; + const char **fmts=linphone_core_get_supported_file_formats(linphone_gtk_get_core()); + int i; + const char *ext="wav"; #ifdef WIN32 loctime=*localtime(&curtime); @@ -991,19 +994,26 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_ #endif snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min); + for (i=0;fmts[i]!=NULL;++i){ + if (strcmp(fmts[i],"mkv")==0){ + ext="mkv"; + break; + } + } + if (address){ id=linphone_address_get_username(address); if (id==NULL) id=linphone_address_get_domain(address); } if (is_conference){ - snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav", + snprintf(filename,sizeof(filename)-1,"%s-conference-%s.%s", linphone_gtk_get_ui_config("title","Linphone"), - date); + date,ext); }else{ - snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav", + snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.%s", linphone_gtk_get_ui_config("title","Linphone"), date, - id); + id,ext); } if (!dir) { ms_message ("No directory for music, using [%s] instead",dir=getenv("HOME")); diff --git a/mediastreamer2 b/mediastreamer2 index df42f0d73..a7846bc24 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit df42f0d73d930079c43ef92808529a4716e72d99 +Subproject commit a7846bc24f3e5bb1cc89faf879f6d64638665585 From 0e3039d5072ae374590c3cb36c740550303dc462 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jun 2014 12:08:28 +0200 Subject: [PATCH 147/201] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e4ee08232..999768a69 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e4ee08232c70023bf772b6499752bd682671b99c +Subproject commit 999768a69bd0b6ead9de0930c6d6ebd4a020ffcf From 136d8379fe708a2cc9e7248556e5c3a296078c49 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jun 2014 15:31:16 +0200 Subject: [PATCH 148/201] Fix compilation for Windows Phone 8. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 33 ++++++++++------------- coreapi/chat.c | 18 +++++++------ coreapi/private.h | 10 +++---- mediastreamer2 | 2 +- oRTP | 2 +- 5 files changed, 31 insertions(+), 34 deletions(-) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj index bc1f56695..814314f15 100644 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ b/build/vsx/LibLinphone/LibLinphone.vcxproj @@ -66,7 +66,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) false Default @@ -90,7 +90,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) true true @@ -116,7 +116,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) false Default @@ -146,7 +146,7 @@ Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) true true @@ -204,11 +204,13 @@ + + @@ -222,40 +224,33 @@ + {4c225a82-800b-427b-ba7b-61686a9b347f} - - {027bad0e-9179-48c1-9733-7aa7e2c2ec70} - {9924ac72-f96c-4e56-94d9-2b025da43c6b} {072fad20-7007-4da2-b2e7-16ce2b219f67} - - {b16b81a9-bef2-44c9-b603-1065183ae844} - {36b528f9-fb79-4078-a16b-0a7442581bb7} {d22bd217-d0f8-4274-9b3a-f3f35f46482c} - - {ffc7b532-0502-4d88-ac98-9e89071cbc97} - false - true - false - true - false - {59500dd1-b192-4ddf-a402-8a8e3739e032} + + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} @@ -276,4 +271,4 @@ - + \ No newline at end of file diff --git a/coreapi/chat.c b/coreapi/chat.c index 280c4353b..39fe39a8c 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -80,7 +80,7 @@ static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handl * @param size size in byte of the data requested, as output it will contain the effective copied size * */ -static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, void *buffer, size_t *size){ +static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, char *buffer, size_t *size){ LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; @@ -445,16 +445,19 @@ void linphone_core_message_received(LinphoneCore *lc, SalOp *op, const SalMessag cr=linphone_core_create_chat_room(lc,cleanfrom); } if (sal_msg->content_type != NULL) { /* content_type field is, for now, used only for rcs file transfer bu twe shall strcmp it with "application/vnd.gsma.rcs-ft-http+xml" */ + xmlChar *file_url = NULL; + xmlDocPtr xmlMessageBody; + xmlNodePtr cur; + msg = linphone_chat_room_create_message(cr, NULL); /* create a message with empty body */ msg->content_type = ms_strdup(sal_msg->content_type); /* add the content_type "application/vnd.gsma.rcs-ft-http+xml" */ msg->file_transfer_information = (LinphoneContent *)malloc(sizeof(LinphoneContent)); memset(msg->file_transfer_information, 0, sizeof(*(msg->file_transfer_information))); - xmlChar *file_url = NULL; /* parse the message body to get all informations from it */ - xmlDocPtr xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text); + xmlMessageBody = xmlParseDoc((const xmlChar *)sal_msg->text); - xmlNodePtr cur = xmlDocGetRootElement(xmlMessageBody); + cur = xmlDocGetRootElement(xmlMessageBody); if (cur != NULL) { cur = cur->xmlChildrenNode; while (cur!=NULL) { @@ -943,7 +946,7 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const return message->file_transfer_information; } -static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const void *buffer, size_t size){ +static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const char *buffer, size_t size){ //printf("Receive %ld bytes\n\n%s\n\n", size, (char *)buffer); LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; @@ -962,7 +965,7 @@ static void linphone_chat_process_response_headers_from_get_file(void *data, con if (event->response){ /*we are receiving a response, set a specific body handler to acquire the response. * if not done, belle-sip will create a memory body handler, the default*/ - LinphoneChatMessage *message=belle_sip_object_data_get(BELLE_SIP_OBJECT(event->request),"message"); + LinphoneChatMessage *message=(LinphoneChatMessage *)belle_sip_object_data_get(BELLE_SIP_OBJECT(event->request),"message"); belle_sip_message_set_body_handler( (belle_sip_message_t*)event->response, (belle_sip_body_handler_t*)belle_sip_user_body_handler_new(message->file_transfer_information->size, linphone_chat_message_file_transfer_on_progress,on_recv_body,NULL,message) @@ -998,11 +1001,10 @@ void linphone_chat_message_start_file_download(const LinphoneChatMessage *messag belle_generic_uri_t *uri; belle_http_request_t *req; const char *url=message->external_body_url; + char* ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); uri=belle_generic_uri_parse(url); - char* ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); - req=belle_http_request_create("GET", uri, belle_sip_header_create("User-Agent",ua), diff --git a/coreapi/private.h b/coreapi/private.h index 9cb1b45da..5c174fb64 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -294,24 +294,24 @@ void linphone_core_get_local_ip(LinphoneCore *lc, int af, char *result); bool_t host_has_ipv6_network(); bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret); -static inline int get_min_bandwidth(int dbw, int ubw){ +static MS2_INLINE int get_min_bandwidth(int dbw, int ubw){ if (dbw<=0) return ubw; if (ubw<=0) return dbw; return MIN(dbw,ubw); } -static inline bool_t bandwidth_is_greater(int bw1, int bw2){ +static MS2_INLINE bool_t bandwidth_is_greater(int bw1, int bw2){ if (bw1<0) return TRUE; else if (bw2<0) return FALSE; else return bw1>=bw2; } -static inline int get_remaining_bandwidth_for_video(int total, int audio){ +static MS2_INLINE int get_remaining_bandwidth_for_video(int total, int audio){ if (total<=0) return 0; return total-audio-10; } -static inline void set_string(char **dest, const char *src){ +static MS2_INLINE void set_string(char **dest, const char *src){ if (*dest){ ms_free(*dest); *dest=NULL; @@ -903,7 +903,7 @@ xmlXPathObjectPtr linphone_get_xml_xpath_object_for_node_list(xmlparsing_context char * linphone_timestamp_to_rfc3339_string(time_t timestamp); -static inline const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){ +static MS2_INLINE const LinphoneErrorInfo *linphone_error_info_from_sal_op(const SalOp *op){ if (op==NULL) return (LinphoneErrorInfo*)sal_error_info_none(); return (const LinphoneErrorInfo*)sal_op_get_error_info(op); } diff --git a/mediastreamer2 b/mediastreamer2 index 999768a69..fdf4db8e0 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 999768a69bd0b6ead9de0930c6d6ebd4a020ffcf +Subproject commit fdf4db8e0c2a5aa9b7c054f22df6fdb31a21fa46 diff --git a/oRTP b/oRTP index e4a235076..d0e9c7c3d 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit e4a235076787acef6e97eb7a15b400f91fd4f481 +Subproject commit d0e9c7c3d961ac1a400bf2796b03ebefab77541d From 02914901f5d8aa646af21361528a60f22167c6d2 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 23 Jun 2014 18:18:13 +0200 Subject: [PATCH 149/201] Fix compilation on Linux. --- coreapi/chat.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 39fe39a8c..addc400fc 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -80,32 +80,33 @@ static void linphone_chat_message_file_transfer_on_progress(belle_sip_body_handl * @param size size in byte of the data requested, as output it will contain the effective copied size * */ -static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, char *buffer, size_t *size){ +static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, uint8_t *buffer, size_t *size){ LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; + char *buf = (char *)buffer; char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype); size_t end_of_file=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size; if (offset==0){ int partlen=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type); - memcpy(buffer,MULTIPART_HEADER_1,strlen(MULTIPART_HEADER_1)); - buffer += strlen(MULTIPART_HEADER_1); - memcpy(buffer,chatMsg->file_transfer_information->name,strlen(chatMsg->file_transfer_information->name)); - buffer += strlen(chatMsg->file_transfer_information->name); - memcpy(buffer,MULTIPART_HEADER_2,strlen(MULTIPART_HEADER_2)); - buffer += strlen(MULTIPART_HEADER_2); - memcpy(buffer,content_type,strlen(content_type)); - buffer += strlen(content_type); - memcpy(buffer,MULTIPART_HEADER_3,strlen(MULTIPART_HEADER_3)); + memcpy(buf,MULTIPART_HEADER_1,strlen(MULTIPART_HEADER_1)); + buf += strlen(MULTIPART_HEADER_1); + memcpy(buf,chatMsg->file_transfer_information->name,strlen(chatMsg->file_transfer_information->name)); + buf += strlen(chatMsg->file_transfer_information->name); + memcpy(buf,MULTIPART_HEADER_2,strlen(MULTIPART_HEADER_2)); + buf += strlen(MULTIPART_HEADER_2); + memcpy(buf,content_type,strlen(content_type)); + buf += strlen(content_type); + memcpy(buf,MULTIPART_HEADER_3,strlen(MULTIPART_HEADER_3)); *size=partlen; }else if (offsetvtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + lc->vtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size); }else{ *size=strlen(MULTIPART_END); - strncpy(buffer,MULTIPART_END,*size); + strncpy(buf,MULTIPART_END,*size); } belle_sip_free(content_type); return BELLE_SIP_CONTINUE; @@ -946,13 +947,13 @@ const LinphoneContent *linphone_chat_message_get_file_transfer_information(const return message->file_transfer_information; } -static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const char *buffer, size_t size){ +static void on_recv_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, const uint8_t *buffer, size_t size){ //printf("Receive %ld bytes\n\n%s\n\n", size, (char *)buffer); LinphoneChatMessage* chatMsg=(LinphoneChatMessage *)data; LinphoneCore *lc = chatMsg->chat_room->lc; /* call back given by application level */ if (lc->vtable.file_transfer_received != NULL) { - lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, buffer, size); + lc->vtable.file_transfer_received(lc, chatMsg, chatMsg->file_transfer_information, (char *)buffer, size); } return; From 85bf7d9a97cfd476cc6a38792002fbf75c4a1716 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 23 Jun 2014 18:52:53 +0200 Subject: [PATCH 150/201] fix possible use of freed object --- coreapi/bellesip_sal/sal_op_registration.c | 4 +++- mediastreamer2 | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_registration.c b/coreapi/bellesip_sal/sal_op_registration.c index 0f011d308..b51435a4f 100644 --- a/coreapi/bellesip_sal/sal_op_registration.c +++ b/coreapi/bellesip_sal/sal_op_registration.c @@ -56,13 +56,15 @@ static void register_refresher_listener (belle_sip_refresher_t* refresher chooses not to re-register, the UA SHOULD discard any stored service route for that address-of-record. */ sal_op_set_service_route(op,NULL); + sal_op_ref(op); /*take a ref while invoking the callback to make sure the operations done after are valid*/ op->base.root->callbacks.register_failure(op); - if (op->auth_info) { + if (op->state!=SalOpStateTerminated && op->auth_info) { /*add pending auth*/ sal_add_pending_auth(op->base.root,op); if (status_code==403 || status_code==401 || status_code==407 ) op->base.root->callbacks.auth_failure(op,op->auth_info); } + sal_op_unref(op); } } diff --git a/mediastreamer2 b/mediastreamer2 index fdf4db8e0..be7b962af 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit fdf4db8e0c2a5aa9b7c054f22df6fdb31a21fa46 +Subproject commit be7b962af74afcfbabe3d99bd0cea447c8fb8fae From bd779601b8add0510b4db98ba5198f52afad80c1 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 24 Jun 2014 10:50:52 +0200 Subject: [PATCH 151/201] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index be7b962af..8bb88345e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit be7b962af74afcfbabe3d99bd0cea447c8fb8fae +Subproject commit 8bb88345ec1788e9c4f6a1a732cddff4f4167d34 From 3e13527bb310c58d8187bf5450d2e7f0e6f37c7a Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 24 Jun 2014 10:51:10 +0200 Subject: [PATCH 152/201] Activate PLI, SLI and RPSI when receiving rtcp-fb nack attribute. --- coreapi/bellesip_sal/sal_sdp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 5f71dba0e..4bfed5cf1 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -494,6 +494,9 @@ static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb switch (belle_sdp_rtcp_fb_attribute_get_type(fb_attribute)) { case BELLE_SDP_RTCP_FB_NACK: switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) { + case BELLE_SDP_RTCP_FB_NONE: + avpf_params.features |= PAYLOAD_TYPE_AVPF_PLI | PAYLOAD_TYPE_AVPF_SLI | PAYLOAD_TYPE_AVPF_RPSI; + break; case BELLE_SDP_RTCP_FB_PLI: avpf_params.features |= PAYLOAD_TYPE_AVPF_PLI; break; From 960253d058f687a842a5cba818ffdaf586ac70af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Tue, 24 Jun 2014 13:22:10 +0200 Subject: [PATCH 153/201] Rename the MKV_WRITER filter into MKV_RECORDER --- coreapi/misc.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index a058db102..0cc6a3ac9 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1531,7 +1531,7 @@ const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){ if (core->supported_formats==NULL){ core->supported_formats=ms_malloc0(3*sizeof(char*)); core->supported_formats[0]=wav; - if (ms_factory_lookup_filter_by_id(ms_factory_get_fallback(),MS_MKV_WRITER_ID)){ + if (ms_factory_lookup_filter_by_id(ms_factory_get_fallback(),MS_MKV_RECORDER_ID)){ core->supported_formats[1]=mkv; } } diff --git a/mediastreamer2 b/mediastreamer2 index a7846bc24..c9c803253 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit a7846bc24f3e5bb1cc89faf879f6d64638665585 +Subproject commit c9c8032530fd21361cfbe03953fcb20d002dcad5 From 704e2cd0801473fd7219f903fbac34ca11f86b50 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 24 Jun 2014 13:58:49 +0200 Subject: [PATCH 154/201] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 8bb88345e..d4095e659 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8bb88345ec1788e9c4f6a1a732cddff4f4167d34 +Subproject commit d4095e65985501aa3b0b676602b62d2e5e63b5d8 From 2f6136009c0be20c8a75371e4397577d6b6ce2ed Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 24 Jun 2014 13:59:11 +0200 Subject: [PATCH 155/201] Handle "rtcp-fb ccm fir" attribute in SDP. --- coreapi/bellesip_sal/sal_sdp.c | 30 +++++++++++++++++++++--------- coreapi/linphonecall.c | 3 --- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 4bfed5cf1..fe952bb56 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -101,6 +101,14 @@ static void add_rtcp_fb_nack_attribute(belle_sdp_media_description_t *media_desc belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); } +static void add_rtcp_fb_ccm_attribute(belle_sdp_media_description_t *media_desc, int8_t id, belle_sdp_rtcp_fb_val_param_t param) { + belle_sdp_rtcp_fb_attribute_t *attribute = belle_sdp_rtcp_fb_attribute_new(); + belle_sdp_rtcp_fb_attribute_set_id(attribute, id); + belle_sdp_rtcp_fb_attribute_set_type(attribute, BELLE_SDP_RTCP_FB_CCM); + belle_sdp_rtcp_fb_attribute_set_param(attribute, param); + belle_sdp_media_description_add_attribute(media_desc, BELLE_SDP_ATTRIBUTE(attribute)); +} + static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, const SalMediaDescription *md, const SalStreamDescription *stream) { MSList *pt_it; PayloadType *pt; @@ -130,6 +138,9 @@ static void add_rtcp_fb_attributes(belle_sdp_media_description_t *media_desc, co if (avpf_params.features & PAYLOAD_TYPE_AVPF_RPSI) { add_rtcp_fb_nack_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_RPSI); } + if (avpf_params.features & PAYLOAD_TYPE_AVPF_FIR) { + add_rtcp_fb_ccm_attribute(media_desc, payload_type_get_number(pt), BELLE_SDP_RTCP_FB_FIR); + } } } @@ -475,17 +486,9 @@ static void sdp_parse_media_ice_parameters(belle_sdp_media_description_t *media_ static void enable_avpf_for_stream(SalStreamDescription *stream) { MSList *pt_it; - PayloadType *pt; - PayloadTypeAvpfParams avpf_params; - for (pt_it = stream->payloads; pt_it != NULL; pt_it = pt_it->next) { - pt = (PayloadType *)pt_it->data; - avpf_params = payload_type_get_avpf_params(pt); + PayloadType *pt = (PayloadType *)pt_it->data; payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); - if (stream->type == SalVideo) { - avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; - } - payload_type_set_avpf_params(pt, avpf_params); } } @@ -513,6 +516,15 @@ static void apply_rtcp_fb_attribute_to_payload(belle_sdp_rtcp_fb_attribute_t *fb case BELLE_SDP_RTCP_FB_TRR_INT: avpf_params.trr_interval = belle_sdp_rtcp_fb_attribute_get_trr_int(fb_attribute); break; + case BELLE_SDP_RTCP_FB_CCM: + switch (belle_sdp_rtcp_fb_attribute_get_param(fb_attribute)) { + case BELLE_SDP_RTCP_FB_FIR: + avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; + break; + default: + break; + } + break; case BELLE_SDP_RTCP_FB_ACK: default: break; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 218bf86fd..4e4babcbc 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -335,9 +335,6 @@ static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) { payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); avpf_params = payload_type_get_avpf_params(pt); avpf_params.trr_interval = call->params.avpf_rr_interval; - if (md->streams[i].type == SalVideo) { - avpf_params.features |= PAYLOAD_TYPE_AVPF_FIR; - } } else { payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED); memset(&avpf_params, 0, sizeof(avpf_params)); From 5cf381b667d77a52381155a5b64dfa0a2c75da2b Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 24 Jun 2014 09:43:32 +0200 Subject: [PATCH 156/201] add linphone_core_get_user_agent to retrieve local user agent --- coreapi/bellesip_sal/sal_impl.c | 14 ++++-- coreapi/linphonecore.c | 9 ++++ coreapi/linphonecore.h | 7 +++ coreapi/quality_reporting.c | 76 ++++++++++++++++++++------------- coreapi/quality_reporting.h | 45 ++++++++++--------- include/sal/sal.h | 1 + 6 files changed, 97 insertions(+), 55 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index c4809ecc6..daf746c79 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -424,21 +424,21 @@ static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) { Sal * sal_init(){ belle_sip_listener_callbacks_t listener_callbacks; Sal * sal=ms_new0(Sal,1); - + /*belle_sip_object_enable_marshal_check(TRUE);*/ sal->auto_contacts=TRUE; - + /*first create the stack, which initializes the belle-sip object's pool for this thread*/ belle_sip_set_log_handler(_belle_sip_log); sal->stack = belle_sip_stack_new(NULL); - + sal->user_agent=belle_sip_header_user_agent_new(); #if defined(PACKAGE_NAME) && defined(LINPHONE_VERSION) belle_sip_header_user_agent_add_product(sal->user_agent, PACKAGE_NAME "/" LINPHONE_VERSION); #endif sal_append_stack_string_to_user_agent(sal); belle_sip_object_ref(sal->user_agent); - + sal->prov = belle_sip_stack_create_provider(sal->stack,NULL); sal_nat_helper_enable(sal,TRUE); memset(&listener_callbacks,0,sizeof(listener_callbacks)); @@ -617,6 +617,12 @@ void sal_set_user_agent(Sal *ctx, const char *user_agent){ return ; } +const char* sal_get_user_agent(Sal *ctx){ + static char user_agent[255]; + belle_sip_header_user_agent_get_products_as_string(ctx->user_agent, user_agent, 254); + return user_agent; +} + void sal_append_stack_string_to_user_agent(Sal *ctx) { char stack_string[64]; snprintf(stack_string, sizeof(stack_string) - 1, "(belle-sip/%s)", belle_sip_version_to_string()); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 9f4cfbd9c..65db5a709 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1914,6 +1914,15 @@ void linphone_core_set_user_agent(LinphoneCore *lc, const char *name, const char apply_user_agent(lc); #endif } +const char *linphone_core_get_user_agent(LinphoneCore *lc){ +#if USE_BELLESIP + return sal_get_user_agent(lc->sal); +#else + static char ua_buffer[255] = {0}; + snprintf(ua_buffer, "%s/%s", _ua_name, _ua_version, 254); + return ua_buffer; +#endif +} const char *linphone_core_get_user_agent_name(void){ return _ua_name; diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index dd0ff311a..0cabc434f 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1542,7 +1542,14 @@ LINPHONE_PUBLIC void linphone_core_enable_logs(FILE *file); LINPHONE_PUBLIC void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc); LINPHONE_PUBLIC void linphone_core_disable_logs(void); LINPHONE_PUBLIC const char *linphone_core_get_version(void); +LINPHONE_PUBLIC const char *linphone_core_get_user_agent(LinphoneCore *lc); +/** + * @deprecated Use #linphone_core_get_user_agent instead. +**/ LINPHONE_PUBLIC const char *linphone_core_get_user_agent_name(void); +/** + * @deprecated Use #linphone_core_get_user_agent instead. +**/ LINPHONE_PUBLIC const char *linphone_core_get_user_agent_version(void); LINPHONE_PUBLIC LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index e16dd8f81..528ec5208 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -236,6 +236,11 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSCQ=%s", moscq_str); } + if (rm.user_agent!=NULL){ + append_to_buffer(buffer, size, offset, "\r\nLinphoneExt:"); + APPEND_IF_NOT_NULL_STR(buffer, size, offset, " UA=\"%s\"", rm.user_agent); + } + append_to_buffer(buffer, size, offset, "\r\n"); ms_free(timestamps_start_str); @@ -430,17 +435,27 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); - STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("linphone-%s-%s-%s", - (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), - linphone_core_get_user_agent_name(), - report->info.call_id) + STR_REASSIGN(report->dialog_id, sal_op_get_dialog_id(call->op)); + + STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(call->core))); + STR_REASSIGN(report->remote_metrics.user_agent, ms_strdup(linphone_call_get_remote_user_agent(call))); + + // RFC states: "LocalGroupID provides the identification for the purposes + // of aggregation for the local endpoint.". + STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("%s-%s-%s" + , report->dialog_id + , "local" + , report->local_metrics.user_agent + ) ); - STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("linphone-%s-%s-%s", - (stats_type == LINPHONE_CALL_STATS_AUDIO ? "audio" : "video"), - linphone_call_get_remote_user_agent(call), - report->info.call_id) + STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("%s-%s-%s" + , report->dialog_id + , "remote" + , report->remote_metrics.user_agent + ) ); + if (call->dir == LinphoneCallIncoming) { STR_REASSIGN(report->info.remote_addr.id, linphone_address_as_string(call->log->from)); STR_REASSIGN(report->info.local_addr.id, linphone_address_as_string(call->log->to)); @@ -451,7 +466,6 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { STR_REASSIGN(report->info.orig_id, ms_strdup(report->info.local_addr.id)); } - STR_REASSIGN(report->dialog_id, sal_op_get_dialog_id(call->op)); report->local_metrics.timestamps.start = call->log->start_date_time; report->local_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call); @@ -663,27 +677,29 @@ reporting_session_report_t * linphone_reporting_new() { } void linphone_reporting_destroy(reporting_session_report_t * report) { - if (report->info.call_id != NULL) ms_free(report->info.call_id); - if (report->info.local_addr.id != NULL) ms_free(report->info.local_addr.id); - if (report->info.remote_addr.id != NULL) ms_free(report->info.remote_addr.id); - if (report->info.orig_id != NULL) ms_free(report->info.orig_id); - if (report->info.local_addr.ip != NULL) ms_free(report->info.local_addr.ip); - if (report->info.remote_addr.ip != NULL) ms_free(report->info.remote_addr.ip); - if (report->info.local_addr.group != NULL) ms_free(report->info.local_addr.group); - if (report->info.remote_addr.group != NULL) ms_free(report->info.remote_addr.group); - if (report->info.local_addr.mac != NULL) ms_free(report->info.local_addr.mac); - if (report->info.remote_addr.mac != NULL) ms_free(report->info.remote_addr.mac); - if (report->dialog_id != NULL) ms_free(report->dialog_id); - if (report->local_metrics.session_description.fmtp != NULL) ms_free(report->local_metrics.session_description.fmtp); - if (report->local_metrics.session_description.payload_desc != NULL) ms_free(report->local_metrics.session_description.payload_desc); - if (report->remote_metrics.session_description.fmtp != NULL) ms_free(report->remote_metrics.session_description.fmtp); - if (report->remote_metrics.session_description.payload_desc != NULL) ms_free(report->remote_metrics.session_description.payload_desc); - if (report->qos_analyzer.name != NULL) ms_free(report->qos_analyzer.name); - if (report->qos_analyzer.timestamp != NULL) ms_free(report->qos_analyzer.timestamp); - if (report->qos_analyzer.input_leg != NULL) ms_free(report->qos_analyzer.input_leg); - if (report->qos_analyzer.input != NULL) ms_free(report->qos_analyzer.input); - if (report->qos_analyzer.output_leg != NULL) ms_free(report->qos_analyzer.output_leg); - if (report->qos_analyzer.output != NULL) ms_free(report->qos_analyzer.output); + STR_REASSIGN(report->info.call_id, NULL); + STR_REASSIGN(report->info.local_addr.id, NULL); + STR_REASSIGN(report->info.remote_addr.id, NULL); + STR_REASSIGN(report->info.orig_id, NULL); + STR_REASSIGN(report->info.local_addr.ip, NULL); + STR_REASSIGN(report->info.remote_addr.ip, NULL); + STR_REASSIGN(report->info.local_addr.group, NULL); + STR_REASSIGN(report->info.remote_addr.group, NULL); + STR_REASSIGN(report->info.local_addr.mac, NULL); + STR_REASSIGN(report->info.remote_addr.mac, NULL); + STR_REASSIGN(report->dialog_id, NULL); + STR_REASSIGN(report->local_metrics.session_description.fmtp, NULL); + STR_REASSIGN(report->local_metrics.session_description.payload_desc, NULL); + STR_REASSIGN(report->local_metrics.user_agent, NULL); + STR_REASSIGN(report->remote_metrics.session_description.fmtp, NULL); + STR_REASSIGN(report->remote_metrics.session_description.payload_desc, NULL); + STR_REASSIGN(report->remote_metrics.user_agent, NULL); + STR_REASSIGN(report->qos_analyzer.name, NULL); + STR_REASSIGN(report->qos_analyzer.timestamp, NULL); + STR_REASSIGN(report->qos_analyzer.input_leg, NULL); + STR_REASSIGN(report->qos_analyzer.input, NULL); + STR_REASSIGN(report->qos_analyzer.output_leg, NULL); + STR_REASSIGN(report->qos_analyzer.output, NULL); ms_free(report); } diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index 3c387a903..acc898924 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -54,48 +54,51 @@ typedef struct reporting_content_metrics { // session description - optional struct { int payload_type; - char * payload_desc; // mime type - int sample_rate; // clock rate - int frame_duration; // to check (ptime?) - audio only + char * payload_desc; + int sample_rate; + int frame_duration; char * fmtp; - int packet_loss_concealment; // in voip metrics - audio only + int packet_loss_concealment; } session_description; // jitter buffet - optional struct { - int adaptive; // constant - int nominal; // average - int max; // average - int abs_max; // constant + int adaptive; + int nominal; + int max; + int abs_max; } jitter_buffer; // packet loss - optional struct { - float network_packet_loss_rate; // average - float jitter_buffer_discard_rate; // average + float network_packet_loss_rate; + float jitter_buffer_discard_rate; } packet_loss; // delay - optional struct { - int round_trip_delay; // no - vary - int end_system_delay; // no - not implemented yet - int symm_one_way_delay; // no - not implemented (depends on end_system_delay) - int interarrival_jitter; // no - not implemented yet - int mean_abs_jitter; // to check + int round_trip_delay; + int end_system_delay; + int symm_one_way_delay; + int interarrival_jitter; + int mean_abs_jitter; } delay; // signal - optional struct { - int level; // no - vary - int noise_level; // no - vary + int level; + int noise_level; } signal; // quality estimates - optional struct { - float moslq; // no - vary or avg - voip metrics - in [0..4.9] - float moscq; // no - vary or avg - voip metrics - in [0..4.9] + float moslq; + float moscq; } quality_estimates; + // custom extension + char * user_agent; + // for internal processing uint8_t rtcp_xr_count; // number of RTCP XR packets received since last report, used to compute average of instantaneous parameters as stated in the RFC 6035 (4.5) uint8_t rtcp_sr_count; // number of RTCP SR packets received since last report, used to compute RTT average values in case RTCP XR voip metrics is not enabled @@ -127,9 +130,9 @@ typedef struct reporting_session_report { char * name; /*type of the QoS analyzer used*/ char* timestamp; /*time of each decision in seconds*/ char* input_leg; /*input parameters' name*/ - char* input; /*set of inputs for each decision, semicolon separated*/ + char* input; /*set of inputs for each semicolon separated decision*/ char* output_leg; /*output parameters' name*/ - char* output; /*set of outputs for each decision, semicolon separated*/ + char* output; /*set of outputs for each semicolon separated decision*/ } qos_analyzer; // for internal processing diff --git a/include/sal/sal.h b/include/sal/sal.h index e9719fc7b..642cfdd2a 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -519,6 +519,7 @@ void sal_set_dscp(Sal *ctx, int dscp); int sal_reset_transports(Sal *ctx); ortp_socket_t sal_get_socket(Sal *ctx); void sal_set_user_agent(Sal *ctx, const char *user_agent); +const char* sal_get_user_agent(Sal *ctx); void sal_append_stack_string_to_user_agent(Sal *ctx); /*keepalive period in ms*/ void sal_set_keepalive_period(Sal *ctx,unsigned int value); From d472ac0bef88f3405cd87e8b685ca04f74bf3d0a Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 24 Jun 2014 11:51:36 +0200 Subject: [PATCH 157/201] set linphonec as user-agent for linphonec --- console/linphonec.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/console/linphonec.c b/console/linphonec.c index ca7d6cafa..b8072e325 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -551,7 +551,7 @@ char *linphonec_readline(char *prompt){ should. Maybe should we only have this on when the option -V or -D is on? */ MSG msg; - + if (PeekMessage(&msg, NULL, 0, 0,1)) { TranslateMessage(&msg); DispatchMessage(&msg); @@ -648,7 +648,7 @@ main (int argc, char *argv[]) { linphonec_vtable.refer_received=linphonec_display_refer; linphonec_vtable.transfer_state_changed=linphonec_transfer_state_changed; linphonec_vtable.call_encryption_changed=linphonec_call_encryption_changed; - + if (! linphonec_init(argc, argv) ) exit(EXIT_FAILURE); linphonec_main_loop (linphonec); @@ -671,8 +671,8 @@ linphonec_init(int argc, char **argv) * Set initial values for global variables */ mylogfile = NULL; - - + + #ifndef _WIN32 snprintf(configfile_name, PATH_MAX, "%s/.linphonerc", getenv("HOME")); @@ -701,7 +701,6 @@ linphonec_init(int argc, char **argv) default: break; } - #ifdef ENABLE_NLS if (NULL == bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR)) perror ("bindtextdomain failed"); @@ -741,10 +740,12 @@ linphonec_init(int argc, char **argv) * Initialize linphone core */ linphonec=linphone_core_new (&linphonec_vtable, configfile_name, factory_configfile_name, NULL); + + linphone_core_set_user_agent(linphonec,"Linphonec", LINPHONE_VERSION); linphone_core_set_zrtp_secrets_file(linphonec,zrtpsecrets); linphone_core_enable_video_capture(linphonec, vcap_enabled); linphone_core_enable_video_display(linphonec, display_enabled); - if (display_enabled && window_id != 0) + if (display_enabled && window_id != 0) { printf ("Setting window_id: 0x%x\n", window_id); linphone_core_set_native_video_window_id(linphonec,window_id); @@ -782,7 +783,7 @@ linphonec_finish(int exit_status) { // Do not allow concurrent destroying to prevent glibc errors static bool_t terminating=FALSE; - if (terminating) return; + if (terminating) return; terminating=TRUE; linphonec_out("Terminating...\n"); @@ -829,9 +830,9 @@ linphonec_prompt_for_auth_final(LinphoneCore *lc) #endif if (reentrancy!=0) return 0; - + reentrancy++; - + LinphoneAuthInfo *pending_auth=auth_stack.elem[auth_stack.nitems-1]; snprintf(auth_prompt, 256, "Password for %s on %s: ", @@ -1159,7 +1160,6 @@ linphonec_main_loop (LinphoneCore * opm) add_history(iptr); } #endif - linphonec_parse_command_line(linphonec, iptr); linphonec_command_finished(); free(input); From ef7bf6a96bd974c0152c02465268b6e14cfd88f6 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 24 Jun 2014 12:20:38 +0200 Subject: [PATCH 158/201] QosAnalyser: change dialog_id and reset avg values --- coreapi/quality_reporting.c | 24 ++++++++++++++++-------- mediastreamer2 | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 528ec5208..f4ba1260f 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -90,6 +90,9 @@ static void reset_avg_metrics(reporting_session_report_t * report){ metrics[i]->jitter_buffer.nominal = 0; metrics[i]->jitter_buffer.max = 0; + metrics[i]->quality_estimates.moslq = 0; + metrics[i]->quality_estimates.moscq = 0; + metrics[i]->delay.round_trip_delay = 0; } report->last_report_date = ms_time(NULL); @@ -353,10 +356,9 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, linphone_content_uninit(&content); end: - ms_message("QualityReporting[%p]: Send '%s' for '%s' stream with status %d", + ms_message("QualityReporting[%p]: Send '%s' with status %d", call, report_event, - report->info.local_addr.group, ret ); @@ -429,13 +431,14 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { const PayloadType * remote_payload = NULL; const LinphoneCallParams * current_params = linphone_call_get_current_params(call); reporting_session_report_t * report = call->log->reporting.reports[stats_type]; + char * dialog_id; if (!media_report_enabled(call, stats_type)) return; + dialog_id = sal_op_get_dialog_id(call->op); STR_REASSIGN(report->info.call_id, ms_strdup(call->log->call_id)); - STR_REASSIGN(report->dialog_id, sal_op_get_dialog_id(call->op)); STR_REASSIGN(report->local_metrics.user_agent, ms_strdup(linphone_core_get_user_agent(call->core))); STR_REASSIGN(report->remote_metrics.user_agent, ms_strdup(linphone_call_get_remote_user_agent(call))); @@ -443,13 +446,13 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { // RFC states: "LocalGroupID provides the identification for the purposes // of aggregation for the local endpoint.". STR_REASSIGN(report->info.local_addr.group, ms_strdup_printf("%s-%s-%s" - , report->dialog_id + , dialog_id , "local" , report->local_metrics.user_agent ) ); STR_REASSIGN(report->info.remote_addr.group, ms_strdup_printf("%s-%s-%s" - , report->dialog_id + , dialog_id , "remote" , report->remote_metrics.user_agent ) @@ -492,6 +495,8 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); } + STR_REASSIGN(report->dialog_id, ms_strdup_printf("%s;%u", dialog_id, report->info.local_addr.ssrc)); + if (local_payload != NULL) { report->local_metrics.session_description.payload_type = local_payload->type; if (local_payload->mime_type!=NULL) STR_REASSIGN(report->local_metrics.session_description.payload_desc, ms_strdup(local_payload->mime_type)); @@ -505,6 +510,8 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { report->remote_metrics.session_description.sample_rate = remote_payload->clock_rate; STR_REASSIGN(report->remote_metrics.session_description.fmtp, ms_strdup(remote_payload->recv_fmtp)); } + + ms_free(dialog_id); } /* generate random float in interval ] 0.9 t ; 1.1 t [*/ @@ -531,7 +538,6 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type) { metrics = &report->local_metrics; block = stats.sent_rtcp; } - do{ if (rtcp_is_XR(block) && (rtcp_XR_get_block_type(block) == RTCP_XR_VOIP_METRICS)){ @@ -539,8 +545,10 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type) { metrics->rtcp_xr_count++; - metrics->quality_estimates.moslq += rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; - metrics->quality_estimates.moscq += rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(block)==127) ? + 127 : metrics->quality_estimates.moslq + rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; + metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(block)==127) ? + 127 : metrics->quality_estimates.moscq + rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block); metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block); diff --git a/mediastreamer2 b/mediastreamer2 index d4095e659..5fbe23460 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d4095e65985501aa3b0b676602b62d2e5e63b5d8 +Subproject commit 5fbe23460f99743eb0df9c479e0832cc41703988 From 6cb4ab91610f6c2900344582a682cdeb7454960e Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 24 Jun 2014 16:30:22 +0200 Subject: [PATCH 159/201] display error if invalid arguments are passed to linphone GTK before quitting --- gtk/main.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/gtk/main.c b/gtk/main.c index c1a52cda4..538bb11a2 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -418,9 +418,9 @@ GtkWidget *linphone_gtk_create_widget(const char *filename, const char *widget_n object_ids[1]=NULL; if (get_ui_file(filename,path,sizeof(path))==-1) return NULL; - + gtk_builder_set_translation_domain(builder,GETTEXT_PACKAGE); - + if (!gtk_builder_add_objects_from_file(builder,path,object_ids,&error)){ g_error("Couldn't load %s from builder file %s: %s", widget_name,path,error->message); g_error_free (error); @@ -983,14 +983,14 @@ gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_ char date[64]={0}; time_t curtime=time(NULL); struct tm loctime; - + #ifdef WIN32 loctime=*localtime(&curtime); #else localtime_r(&curtime,&loctime); #endif snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min); - + if (address){ id=linphone_address_get_username(address); if (id==NULL) id=linphone_address_get_domain(address); @@ -1015,7 +1015,7 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){ const char *entered=gtk_entry_get_text(GTK_ENTRY(uri_bar)); LinphoneCore *lc=linphone_gtk_get_core(); LinphoneAddress *addr=linphone_core_interpret_url(lc,entered); - + if (addr!=NULL){ LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc); gchar *record_file=linphone_gtk_get_record_path(addr,FALSE); @@ -1632,13 +1632,13 @@ static GtkWidget *create_icon_menu(){ } void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data){ - gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y); + gtk_window_get_position(GTK_WINDOW(mw), &main_window_x, &main_window_y); } static void handle_icon_click() { GtkWidget *mw=linphone_gtk_get_main_window(); if (!gtk_window_is_active((GtkWindow*)mw)) { - if(!gtk_widget_is_drawable(mw)){ + if(!gtk_widget_is_drawable(mw)){ //we only move if window was hidden. If it was simply behind the window stack, ie, drawable, we keep it as it was gtk_window_move (GTK_WINDOW(mw), main_window_x, main_window_y); } @@ -2180,6 +2180,7 @@ int main(int argc, char *argv[]){ const char *app_name="Linphone"; LpConfig *factory; const char *db_file; + GError *error=NULL; #if !GLIB_CHECK_VERSION(2, 31, 0) g_thread_init(NULL); @@ -2234,8 +2235,9 @@ int main(int argc, char *argv[]){ gdk_threads_enter(); if (!gtk_init_with_args(&argc,&argv,_("A free SIP video-phone"), - linphone_options,NULL,NULL)){ + linphone_options,NULL,&error)){ gdk_threads_leave(); + g_critical("%s", error->message); return -1; } if (config_file) free(config_file); @@ -2261,7 +2263,7 @@ int main(int argc, char *argv[]){ g_error("Could not change directory to %s : %s",workingdir,strerror(errno)); } } - + #if defined(__APPLE__) && defined(ENABLE_NLS) /*workaround for bundles. GTK is unable to find translations in the bundle (obscure bug again). So we help it:*/ @@ -2312,18 +2314,18 @@ core_start: linphone_gtk_create_log_window(); linphone_core_enable_logs_with_cb(linphone_gtk_log_handler); - + db_file=linphone_gtk_message_storage_get_db_file(NULL); linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file); - + /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/ gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core()); - + gtk_main(); linphone_gtk_quit(); - + if (restart){ quit_done=FALSE; restart=FALSE; From 779e0fc3821ece403b9dcb232f1b7bd789f605ba Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 24 Jun 2014 18:09:01 +0200 Subject: [PATCH 160/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 5fbe23460..2a8a13ab6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 5fbe23460f99743eb0df9c479e0832cc41703988 +Subproject commit 2a8a13ab6a83fe4b63778886b4b9ef844dd51e87 From 3e8f8fc41f5ea3e2b1b94614482df338f98f5982 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 25 Jun 2014 16:41:10 +0200 Subject: [PATCH 161/201] Clean Windows Phone 8 projects and solutions. --- build/vsx/LibLinphone/LibLinphone.vcxproj | 274 --------- .../LibLinphoneTester-wp8.sln | 522 ------------------ .../Assets/marie_early_rc | 45 -- .../LibLinphoneTester-wp8/Assets/marie_rc | 47 -- .../LibLinphoneTester-wp8/Assets/pauline_rc | 46 -- build/vsx/libxml2/libxml2/libxml2.vcxproj | 249 --------- build/wp8/LibLinphone.vcxproj | 183 ++++++ .../LibLinphoneTester-native.vcxproj} | 116 ++-- .../linphone-tester-native.cpp | 0 .../linphone-tester-native.h | 0 .../LibLinphoneTester-wp8/App.xaml | 0 .../LibLinphoneTester-wp8/App.xaml.cs | 0 .../Assets/AlignmentGrid.png | Bin .../Assets/ApplicationIcon.png | Bin .../Assets/Tiles/FlipCycleTileLarge.png | Bin .../Assets/Tiles/FlipCycleTileMedium.png | Bin .../Assets/Tiles/FlipCycleTileSmall.png | Bin .../Assets/Tiles/IconicTileMediumLarge.png | Bin .../Assets/Tiles/IconicTileSmall.png | Bin .../LibLinphoneTester-wp8/Assets/empty_rc | 0 .../LibLinphoneTester-wp8/Assets/laure_rc | 0 .../Assets/multi_account_lrc | 0 .../LibLinphoneTester-wp8/Assets/oldphone.wav | Bin .../LibLinphoneTester-wp8/Assets/ringback.wav | Bin .../LibLinphoneTester-wp8.csproj | 32 +- .../LibLinphoneTester-wp8.sln | 294 ++++++++++ .../LibLinphoneTester-wp8/LocalizedStrings.cs | 0 .../LibLinphoneTester-wp8/MainPage.xaml | 0 .../LibLinphoneTester-wp8/MainPage.xaml.cs | 0 .../Properties/AppManifest.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../Properties/WMAppManifest.xml | 0 .../Resources/AppResources.Designer.cs | 0 .../Resources/AppResources.resx | 0 .../LibLinphoneTester-wp8/TestCasePage.xaml | 0 .../TestCasePage.xaml.cs | 0 .../LibLinphoneTester-wp8/TestResultPage.xaml | 0 .../TestResultPage.xaml.cs | 0 .../LibLinphoneTester-wp8/log.html | 0 .../libxml2/install_headers.bat | 2 +- build/{vsx => wp8}/libxml2/libxml2.sln | 2 +- build/wp8/libxml2/libxml2.vcxproj | 159 ++++++ .../libxml2 => wp8}/libxml2/libxml2_port.h | 0 .../{vsx/libxml2 => wp8}/libxml2/xmlversion.h | 0 44 files changed, 695 insertions(+), 1276 deletions(-) delete mode 100644 build/vsx/LibLinphone/LibLinphone.vcxproj delete mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln delete mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc delete mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc delete mode 100644 build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc delete mode 100644 build/vsx/libxml2/libxml2/libxml2.vcxproj create mode 100644 build/wp8/LibLinphone.vcxproj rename build/{vsx/LibLinphoneTester/LibLinphoneTester.vcxproj => wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj} (51%) rename build/{vsx/LibLinphoneTester => wp8/LibLinphoneTester-native}/linphone-tester-native.cpp (100%) rename build/{vsx/LibLinphoneTester => wp8/LibLinphoneTester-native}/linphone-tester-native.h (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/App.xaml (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/App.xaml.cs (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/AlignmentGrid.png (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/ApplicationIcon.png (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/empty_rc (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/laure_rc (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/multi_account_lrc (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/oldphone.wav (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Assets/ringback.wav (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj (84%) create mode 100644 build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/LocalizedStrings.cs (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/MainPage.xaml (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/MainPage.xaml.cs (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Properties/AppManifest.xml (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Properties/WMAppManifest.xml (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/Resources/AppResources.resx (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/TestCasePage.xaml (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/TestCasePage.xaml.cs (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/TestResultPage.xaml (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/TestResultPage.xaml.cs (100%) rename build/{vsx/LibLinphoneTester-wp8 => wp8}/LibLinphoneTester-wp8/log.html (100%) rename build/{vsx/libxml2 => wp8}/libxml2/install_headers.bat (71%) rename build/{vsx => wp8}/libxml2/libxml2.sln (94%) create mode 100644 build/wp8/libxml2/libxml2.vcxproj rename build/{vsx/libxml2 => wp8}/libxml2/libxml2_port.h (100%) rename build/{vsx/libxml2 => wp8}/libxml2/xmlversion.h (100%) diff --git a/build/vsx/LibLinphone/LibLinphone.vcxproj b/build/vsx/LibLinphone/LibLinphone.vcxproj deleted file mode 100644 index 814314f15..000000000 --- a/build/vsx/LibLinphone/LibLinphone.vcxproj +++ /dev/null @@ -1,274 +0,0 @@ - - - - - Debug - Win32 - - - Debug - ARM - - - Release - Win32 - - - Release - ARM - - - - {08dd0d38-d9b5-4626-b60d-b4d76b571142} - LibLinphone - en-US - 11.0 - - - - DynamicLibrary - true - v110 - false - - - DynamicLibrary - true - v110_wp80 - false - - - DynamicLibrary - false - true - v110 - false - - - DynamicLibrary - false - true - v110_wp80 - false - - - - - - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ - - - false - - - - Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) - false - Default - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - - - Console - false - false - true - belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) - $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) - $(TargetDir)$(TargetName)_dll.lib - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;%(PreprocessorDefinitions) - true - true - Default - true - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - - - Console - false - false - false - belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) - $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) - $(TargetDir)$(TargetName)_dll.lib - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) - false - Default - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - false - false - SyncCThrow - - - Console - false - false - true - ws2_32.lib;%(AdditionalDependencies) - $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) - $(TargetDir)$(TargetName)_dll.lib - ole32.lib;%(IgnoreSpecificDefaultLibraries) - - - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - Level4 - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\linphone\oRTP\include;$(ProjectDir)..\..\..\..\linphone\mediastreamer2\include;$(ProjectDIr)..\..\..\..\tunnel\include;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) - __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) - true - true - Default - true - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - - - Console - false - false - false - belle-sip_dll.lib;mediastreamer2_dll.lib;ws2_32.lib;ortp_dll.lib;gsm_dll.lib;speex_dll.lib;speexdsp_dll.lib;%(AdditionalDependencies) - $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) - $(TargetDir)$(TargetName)_dll.lib - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {4c225a82-800b-427b-ba7b-61686a9b347f} - - - {9924ac72-f96c-4e56-94d9-2b025da43c6b} - - - {072fad20-7007-4da2-b2e7-16ce2b219f67} - - - {36b528f9-fb79-4078-a16b-0a7442581bb7} - - - {d22bd217-d0f8-4274-9b3a-f3f35f46482c} - - - {59500dd1-b192-4ddf-a402-8a8e3739e032} - - - {027bad0e-9179-48c1-9733-7aa7e2c2ec70} - - - {ffc7b532-0502-4d88-ac98-9e89071cbc97} - - - {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} - - - - - true - - - true - false - - - - - - - - - - \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln deleted file mode 100644 index cccf2645c..000000000 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ /dev/null @@ -1,522 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Express 2012 for Windows Phone -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "LibLinphoneTester-wp8\LibLinphoneTester-wp8.csproj", "{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}" - ProjectSection(ProjectDependencies) = postProject - {5E94A00B-B14A-4E42-8284-8CB0EF099534} = {5E94A00B-B14A-4E42-8284-8CB0EF099534} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphone", "..\LibLinphone\LibLinphone.vcxproj", "{08DD0D38-D9B5-4626-B60D-B4D76B571142}" - ProjectSection(ProjectDependencies) = postProject - {D22BD217-D0F8-4274-9B3A-F3F35F46482C} = {D22BD217-D0F8-4274-9B3A-F3F35F46482C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester", "..\LibLinphoneTester\LibLinphoneTester.vcxproj", "{5E94A00B-B14A-4E42-8284-8CB0EF099534}" - ProjectSection(ProjectDependencies) = postProject - {902DAF1D-EBF1-4D03-B598-143500A50AB4} = {902DAF1D-EBF1-4D03-B598-143500A50AB4} - {08DD0D38-D9B5-4626-B60D-B4D76B571142} = {08DD0D38-D9B5-4626-B60D-B4D76B571142} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\windows\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\..\mediastreamer2\build\vsx\mediastreamer2\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\..\..\oRTP\build\vsx\oRTP\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\vsx\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\windows\gsm\gsm\gsm.vcxproj", "{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\windows\speex\speex\speex.vcxproj", "{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\windows\speex\speexdsp\speexdsp.vcxproj", "{6BD78980-9C71-4341-8775-AD19E9EC7305}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\windows\cunit\cunit.vcxproj", "{902DAF1D-EBF1-4D03-B598-143500A50AB4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\mswasapi\mswasapi\mswasapi\mswasapi.vcxproj", "{D22BD217-D0F8-4274-9B3A-F3F35F46482C}" - ProjectSection(ProjectDependencies) = postProject - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} - {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcaecm", "..\..\..\..\webrtc\build\windows\webrtcaecm\webrtcaecm\webrtcaecm.vcxproj", "{1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\windows\libilbc-rfc3951\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\windows\msilbc\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}" - ProjectSection(ProjectDependencies) = postProject - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} - {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\windows\mssilk\mssilk\mssilk.vcxproj", "{36B528F9-FB79-4078-A16B-0A7442581BB7}" - ProjectSection(ProjectDependencies) = postProject - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} - {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\windows\msamr\msamr\msamr.vcxproj", "{9924AC72-F96C-4E56-94D9-2B025DA43C6B}" - ProjectSection(ProjectDependencies) = postProject - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} - {018A4428-535C-4566-9AE0-E93AFF0D3ED2} = {018A4428-535C-4566-9AE0-E93AFF0D3ED2} - {7AC65D2A-6981-4D17-856D-C37A522739D8} = {7AC65D2A-6981-4D17-856D-C37A522739D8} - {88191E75-2993-48D7-AA76-652F274EF0FE} = {88191E75-2993-48D7-AA76-652F274EF0FE} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vo-amrwbenc", "..\..\..\..\msamr\build\windows\msamr\vo-amrwbenc\vo-amrwbenc.vcxproj", "{018A4428-535C-4566-9AE0-E93AFF0D3ED2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\..\msamr\build\windows\msamr\opencore_amrnb\opencore_amrnb.vcxproj", "{88191E75-2993-48D7-AA76-652F274EF0FE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\windows\msamr\opencore_amrwb\opencore_amrwb.vcxproj", "{7AC65D2A-6981-4D17-856D-C37A522739D8}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\windows\polarssl\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\windows\tunnel\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "..\libxml2\libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|Win32 = Debug|Win32 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|Mixed Platforms = Release|Mixed Platforms - Release|Win32 = Release|Win32 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.Build.0 = Debug|Any CPU - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.ActiveCfg = Debug|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Build.0 = Debug|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Deploy.0 = Debug|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Mixed Platforms.Deploy.0 = Debug|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.ActiveCfg = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Build.0 = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Deploy.0 = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.ActiveCfg = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Build.0 = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Deploy.0 = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.ActiveCfg = Release|Any CPU - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.Build.0 = Release|Any CPU - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Any CPU.Deploy.0 = Release|Any CPU - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.ActiveCfg = Release|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Build.0 = Release|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Deploy.0 = Release|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.Build.0 = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Mixed Platforms.Deploy.0 = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.ActiveCfg = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Build.0 = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Deploy.0 = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.ActiveCfg = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Build.0 = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Deploy.0 = Release|x86 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.ActiveCfg = Debug|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.Build.0 = Debug|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.ActiveCfg = Debug|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.Build.0 = Debug|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.ActiveCfg = Debug|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.Build.0 = Debug|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Any CPU.ActiveCfg = Release|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.ActiveCfg = Release|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.Build.0 = Release|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Mixed Platforms.Build.0 = Release|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.ActiveCfg = Release|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.Build.0 = Release|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.ActiveCfg = Release|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.Build.0 = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.ActiveCfg = Debug|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.Build.0 = Debug|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.ActiveCfg = Debug|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.Build.0 = Debug|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.ActiveCfg = Debug|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.Build.0 = Debug|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Any CPU.ActiveCfg = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.ActiveCfg = Release|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.Build.0 = Release|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Mixed Platforms.Build.0 = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.ActiveCfg = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.Build.0 = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.ActiveCfg = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.Build.0 = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.ActiveCfg = Debug|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.Build.0 = Debug|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Any CPU.ActiveCfg = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Mixed Platforms.Build.0 = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.ActiveCfg = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.Build.0 = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.ActiveCfg = Debug|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.Build.0 = Debug|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.ActiveCfg = Debug|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.Build.0 = Debug|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Any CPU.ActiveCfg = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Mixed Platforms.Build.0 = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.ActiveCfg = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.Build.0 = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.ActiveCfg = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.Build.0 = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.ActiveCfg = Debug|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.Build.0 = Debug|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.Build.0 = Debug|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Any CPU.ActiveCfg = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.ActiveCfg = Release|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.Build.0 = Release|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Mixed Platforms.Build.0 = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.ActiveCfg = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.Build.0 = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.ActiveCfg = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.Build.0 = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.ActiveCfg = Debug|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.Build.0 = Debug|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Any CPU.ActiveCfg = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Mixed Platforms.Build.0 = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.ActiveCfg = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.Build.0 = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.ActiveCfg = Debug|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.Build.0 = Debug|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.ActiveCfg = Debug|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.Build.0 = Debug|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.ActiveCfg = Debug|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.Build.0 = Debug|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Any CPU.ActiveCfg = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.ActiveCfg = Release|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.Build.0 = Release|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Mixed Platforms.Build.0 = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.ActiveCfg = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.Build.0 = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.ActiveCfg = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.Build.0 = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.ActiveCfg = Debug|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.Build.0 = Debug|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.ActiveCfg = Debug|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.Build.0 = Debug|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.ActiveCfg = Debug|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.Build.0 = Debug|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Any CPU.ActiveCfg = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.ActiveCfg = Release|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.Build.0 = Release|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Mixed Platforms.Build.0 = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.ActiveCfg = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.Build.0 = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.ActiveCfg = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.Build.0 = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.ActiveCfg = Debug|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.Build.0 = Debug|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.ActiveCfg = Debug|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.Build.0 = Debug|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.ActiveCfg = Debug|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.Build.0 = Debug|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Any CPU.ActiveCfg = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.ActiveCfg = Release|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Mixed Platforms.Build.0 = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.ActiveCfg = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.Build.0 = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.ActiveCfg = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.Build.0 = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Mixed Platforms.ActiveCfg = Debug|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Mixed Platforms.Build.0 = Debug|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.ActiveCfg = Debug|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.Build.0 = Debug|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Any CPU.ActiveCfg = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Mixed Platforms.Build.0 = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.ActiveCfg = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.Build.0 = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.ActiveCfg = Debug|ARM - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.Build.0 = Debug|ARM - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.ActiveCfg = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.Build.0 = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.ActiveCfg = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.Build.0 = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Any CPU.ActiveCfg = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.ActiveCfg = Release|ARM - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Mixed Platforms.Build.0 = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.ActiveCfg = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.Build.0 = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|ARM.ActiveCfg = Debug|ARM - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|ARM.Build.0 = Debug|ARM - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Win32.ActiveCfg = Debug|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|Win32.Build.0 = Debug|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|x86.ActiveCfg = Debug|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Debug|x86.Build.0 = Debug|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Any CPU.ActiveCfg = Release|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|ARM.ActiveCfg = Release|ARM - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|ARM.Build.0 = Release|ARM - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Mixed Platforms.Build.0 = Release|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.ActiveCfg = Release|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|Win32.Build.0 = Release|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.ActiveCfg = Release|Win32 - {1C4E6DA0-B8C7-4A05-A58E-54A6ED07C8DF}.Release|x86.Build.0 = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.ActiveCfg = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.Build.0 = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.ActiveCfg = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.Build.0 = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Any CPU.ActiveCfg = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.ActiveCfg = Release|ARM - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.Build.0 = Release|ARM - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Mixed Platforms.Build.0 = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.ActiveCfg = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.Build.0 = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.ActiveCfg = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.Build.0 = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.ActiveCfg = Debug|ARM - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.Build.0 = Debug|ARM - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.ActiveCfg = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.Build.0 = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.ActiveCfg = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.Build.0 = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Any CPU.ActiveCfg = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.ActiveCfg = Release|ARM - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.Build.0 = Release|ARM - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Mixed Platforms.Build.0 = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.ActiveCfg = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.Build.0 = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.ActiveCfg = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.Build.0 = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.ActiveCfg = Debug|ARM - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.Build.0 = Debug|ARM - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.ActiveCfg = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.Build.0 = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.ActiveCfg = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.Build.0 = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Any CPU.ActiveCfg = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.ActiveCfg = Release|ARM - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.Build.0 = Release|ARM - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Mixed Platforms.Build.0 = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.ActiveCfg = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.Build.0 = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.ActiveCfg = Debug|ARM - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.Build.0 = Debug|ARM - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.ActiveCfg = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.Build.0 = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.ActiveCfg = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.Build.0 = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Any CPU.ActiveCfg = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.ActiveCfg = Release|ARM - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.Build.0 = Release|ARM - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Mixed Platforms.Build.0 = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.ActiveCfg = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.Build.0 = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.ActiveCfg = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.Build.0 = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.ActiveCfg = Debug|ARM - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.Build.0 = Debug|ARM - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.ActiveCfg = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.Build.0 = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.ActiveCfg = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.Build.0 = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Any CPU.ActiveCfg = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.ActiveCfg = Release|ARM - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.Build.0 = Release|ARM - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Mixed Platforms.Build.0 = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.ActiveCfg = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.Build.0 = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.ActiveCfg = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.Build.0 = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.ActiveCfg = Debug|ARM - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.Build.0 = Debug|ARM - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.ActiveCfg = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.Build.0 = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.ActiveCfg = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.Build.0 = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Any CPU.ActiveCfg = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.ActiveCfg = Release|ARM - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.Build.0 = Release|ARM - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Mixed Platforms.Build.0 = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.ActiveCfg = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.Build.0 = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.ActiveCfg = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.Build.0 = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.ActiveCfg = Debug|ARM - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.Build.0 = Debug|ARM - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.ActiveCfg = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.Build.0 = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.ActiveCfg = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.Build.0 = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Any CPU.ActiveCfg = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.ActiveCfg = Release|ARM - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.Build.0 = Release|ARM - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Mixed Platforms.Build.0 = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.ActiveCfg = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.Build.0 = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Any CPU.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Mixed Platforms.Build.0 = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.ActiveCfg = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.Build.0 = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Any CPU.ActiveCfg = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Mixed Platforms.Build.0 = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.ActiveCfg = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.Build.0 = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.ActiveCfg = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.Build.0 = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.ActiveCfg = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.Build.0 = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Any CPU.ActiveCfg = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Mixed Platforms.ActiveCfg = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Mixed Platforms.Build.0 = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.ActiveCfg = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.Build.0 = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.ActiveCfg = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc deleted file mode 100644 index 65934c3f3..000000000 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_early_rc +++ /dev/null @@ -1,45 +0,0 @@ -[sip] -sip_port=5082 -sip_tcp_port=5082 -sip_tls_port=5083 -default_proxy=0 -ping_with_options=0 -register_only_when_network_is_up=0 -incoming_calls_early_media=1 - -[auth_info_0] -username=marie -userid=marie -passwd=secret -realm="sip.example.org" - - -[proxy_0] -reg_proxy=sip.example.org;transport=tcp -reg_route=sip.example.org;transport=tcp;lr -reg_identity=sip:marie@sip.example.org -reg_expires=3600 -reg_sendregister=1 -publish=0 -dial_escape_plus=0 - -[friend_0] -url="Paupoche" -pol=accept -subscribe=0 - - -[rtp] -audio_rtp_port=8070 -video_rtp_port=8072 - -[video] -display=0 -capture=0 -show_local=0 -size=vga -enabled=0 -self_view=0 -automatically_initiate=0 -automatically_accept=0 -device=StaticImage: Static picture \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc deleted file mode 100644 index 56c96bc98..000000000 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/marie_rc +++ /dev/null @@ -1,47 +0,0 @@ -[sip] -sip_port=5082 -sip_tcp_port=5082 -sip_tls_port=5083 -default_proxy=0 -ping_with_options=0 -register_only_when_network_is_up=0 - -[auth_info_0] -username=marie -userid=marie -passwd=secret -realm="sip.example.org" - - -[proxy_0] -reg_proxy=sip.example.org;transport=tcp -reg_route=sip.example.org;transport=tcp;lr -reg_identity=sip:marie@sip.example.org -reg_expires=3600 -reg_sendregister=1 -publish=0 -dial_escape_plus=0 - -[friend_0] -url="Paupoche" -pol=accept -subscribe=0 - - -[rtp] -audio_rtp_port=8070 -video_rtp_port=8072 - -[video] -display=0 -capture=0 -show_local=0 -size=vga -enabled=0 -self_view=0 -automatically_initiate=0 -automatically_accept=0 -device=StaticImage: Static picture - -[sound] -echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc b/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc deleted file mode 100644 index 4ff876cf7..000000000 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/pauline_rc +++ /dev/null @@ -1,46 +0,0 @@ -[sip] -sip_port=5072 -sip_tcp_port=5072 -sip_tls_port=5073 -default_proxy=0 -ping_with_options=0 -register_only_when_network_is_up=0 - -[auth_info_0] -username=pauline -userid=pauline -passwd=secret -realm="sip.example.org" - - -[proxy_0] -reg_proxy=sip2.linphone.org;transport=tls -reg_route=sip2.linphone.org;transport=tls -reg_identity=sip:pauline@sip.example.org -reg_expires=3600 -reg_sendregister=1 -publish=0 -dial_escape_plus=0 - -#[friend_0] -#url="Mariette" -#pol=accept -#subscribe=0 - -[rtp] -audio_rtp_port=8090 -video_rtp_port=8092 - -[video] -display=0 -capture=0 -show_local=0 -size=vga -enabled=0 -self_view=0 -automatically_initiate=0 -automatically_accept=0 -device=StaticImage: Static picture - -[sound] -echocancellation=0 #to not overload cpu in case of VG \ No newline at end of file diff --git a/build/vsx/libxml2/libxml2/libxml2.vcxproj b/build/vsx/libxml2/libxml2/libxml2.vcxproj deleted file mode 100644 index fb873bf4e..000000000 --- a/build/vsx/libxml2/libxml2/libxml2.vcxproj +++ /dev/null @@ -1,249 +0,0 @@ - - - - - Debug - Win32 - - - Debug - ARM - - - Release - Win32 - - - Release - ARM - - - - {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} - libxml2 - en-US - 11.0 - - - - DynamicLibrary - true - v110 - false - - - DynamicLibrary - true - v110_wp80 - false - - - DynamicLibrary - false - true - v110 - false - - - DynamicLibrary - false - true - v110_wp80 - false - - - - - - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ - - - false - - - - Level4 - $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) - LIBXML_MODULES_ENABLED - false - Default - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - $(ProjectDir)libxml2_port.h - - - Console - false - false - true - $(TargetDir)$(TargetName)_dll.lib - Ws2_32.lib;%(AdditionalDependencies) - - - install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - Level4 - MaxSpeed - $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) - LIBXML_MODULES_ENABLED - true - true - Default - true - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - $(ProjectDir)libxml2_port.h - - - Console - false - false - false - $(TargetDir)$(TargetName)_dll.lib - Ws2_32.lib;%(AdditionalDependencies) - - - install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - Level4 - $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) - LIBXML_MODULES_ENABLED - false - Default - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - $(ProjectDir)libxml2_port.h - - - Console - false - false - true - $(TargetDir)$(TargetName)_dll.lib - Ws2_32.lib;%(AdditionalDependencies) - - - install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - Level4 - MaxSpeed - $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) - _WIN32;_WINDLL;_USRDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) - LIBXML_MODULES_ENABLED - true - true - Default - true - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - $(ProjectDir)libxml2_port.h - - - Console - false - false - false - $(TargetDir)$(TargetName)_dll.lib - Ws2_32.lib;%(AdditionalDependencies) - - - install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include - - - $(TargetDir)$(TargetName)_dll.lib;%(Outputs) - - - - - true - - - true - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/wp8/LibLinphone.vcxproj b/build/wp8/LibLinphone.vcxproj new file mode 100644 index 000000000..7f9a53ce0 --- /dev/null +++ b/build/wp8/LibLinphone.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {08dd0d38-d9b5-4626-b60d-b4d76b571142} + LibLinphone + en-US + 11.0 + + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + Level4 + $(ProjectDir)..\..\..\belle-sip\include;$(ProjectDir)..\..\oRTP\include;$(ProjectDir)..\..\mediastreamer2\include;$(ProjectDIr)..\..\..\tunnel\include;$(ProjectDir)..\..\coreapi;$(ProjectDir)..\..\include;$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) + __STDC_CONSTANT_MACROS;_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;_USRDLL;WINDOW_NATIVE;_TRUE_TIME;IN_LINPHONE;USE_BELLESIP;TUNNEL_ENABLED;VIDEO_ENABLED;LINPHONE_PACKAGE_NAME="linphone";LINPHONE_VERSION="Devel";LIBLINPHONE_EXPORTS;LINPHONE_PLUGINS_DIR="";UNICODE;_XKEYCHECK_H;%(PreprocessorDefinitions) + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + + + Console + false + false + belle-sip.lib;mediastreamer2.lib;ws2_32.lib;ortp.lib;gsm.lib;speex.lib;speexdsp.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).lib + + + $(TargetDir)$(TargetName)_dll.lib;%(Outputs) + + + + + _DEBUG;%(PreprocessorDefinitions) + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + MaxSpeed + true + true + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + false + + + + + + + + {4c225a82-800b-427b-ba7b-61686a9b347f} + + + {59500dd1-b192-4ddf-a402-8a8e3739e032} + + + {b9bd3213-b7c4-431e-a827-9a92682045af} + + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} + + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} + + + + + \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj similarity index 51% rename from build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj rename to build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj index 3b8e9bfc0..bf345cce1 100644 --- a/build/vsx/LibLinphoneTester/LibLinphoneTester.vcxproj +++ b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj @@ -26,26 +26,13 @@ true - + DynamicLibrary true v110_wp80 false - - DynamicLibrary - true - v110_wp80 - true - - - DynamicLibrary - false - true - v110_wp80 - false - - + DynamicLibrary false true @@ -60,66 +47,42 @@ false - - - _USRDLL;%(PreprocessorDefinitions) - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - - - Console - false - false - true - - - - - _USRDLL;NDEBUG;%(PreprocessorDefinitions) - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - - - Console - false - false - false - - - + Level4 - WIN32;_DEBUG;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions) - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\oRTP\include;$(ProjectDir)..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\wp8\cunit\$(Platform)\$(Configuration);$(SolutionDir)$(Platform)\$(Configuration)\include;%(AdditionalIncludeDirectories) + WIN32;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;IN_LINPHONE;%(PreprocessorDefinitions) Default NotUsing - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) false - Async + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) Console false - ole32.lib;%(IgnoreSpecificDefaultLibraries) true + ole32.lib;%(IgnoreSpecificDefaultLibraries) WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;ws2_32.lib;%(AdditionalDependencies) $(SolutionDir)$(Platform)\$(Configuration) - + - _USRDLL;NDEBUG;%(PreprocessorDefinitions) - NotUsing - false - $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) - $(ProjectDir)..\..\..\..\belle-sip\include;$(ProjectDir)..\..\..\..\oRTP\include;$(ProjectDir)..\..\..\..\mediastreamer2\include;$(ProjectDir)..\..\..\tester;$(ProjectDir)..\..\..\coreapi;$(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\cunit\build\windows\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) + _DEBUG;%(PreprocessorDefinitions) + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + MaxSpeed + true + true + true - Console - false - false false @@ -132,13 +95,18 @@ + + + + + - true + true @@ -146,21 +114,37 @@ - + + {4c225a82-800b-427b-ba7b-61686a9b347f} + + {902daf1d-ebf1-4d03-b598-143500a50ab4} - - {027bad0e-9179-48c1-9733-7aa7e2c2ec70} + + {9924ac72-f96c-4e56-94d9-2b025da43c6b} - + + {072fad20-7007-4da2-b2e7-16ce2b219f67} + + + {36b528f9-fb79-4078-a16b-0a7442581bb7} + + + {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + + {0565952a-ea62-46a2-8261-f5b4b490da42} + + + {b9bd3213-b7c4-431e-a827-9a92682045af} + + {ffc7b532-0502-4d88-ac98-9e89071cbc97} - + {08dd0d38-d9b5-4626-b60d-b4d76b571142} - - \ No newline at end of file diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.cpp b/build/wp8/LibLinphoneTester-native/linphone-tester-native.cpp similarity index 100% rename from build/vsx/LibLinphoneTester/linphone-tester-native.cpp rename to build/wp8/LibLinphoneTester-native/linphone-tester-native.cpp diff --git a/build/vsx/LibLinphoneTester/linphone-tester-native.h b/build/wp8/LibLinphoneTester-native/linphone-tester-native.h similarity index 100% rename from build/vsx/LibLinphoneTester/linphone-tester-native.h rename to build/wp8/LibLinphoneTester-native/linphone-tester-native.h diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml b/build/wp8/LibLinphoneTester-wp8/App.xaml similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml rename to build/wp8/LibLinphoneTester-wp8/App.xaml diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs b/build/wp8/LibLinphoneTester-wp8/App.xaml.cs similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/App.xaml.cs rename to build/wp8/LibLinphoneTester-wp8/App.xaml.cs diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png b/build/wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png rename to build/wp8/LibLinphoneTester-wp8/Assets/AlignmentGrid.png diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png b/build/wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png rename to build/wp8/LibLinphoneTester-wp8/Assets/ApplicationIcon.png diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png rename to build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileLarge.png diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png rename to build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileMedium.png diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png rename to build/wp8/LibLinphoneTester-wp8/Assets/Tiles/FlipCycleTileSmall.png diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png rename to build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileMediumLarge.png diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png b/build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png rename to build/wp8/LibLinphoneTester-wp8/Assets/Tiles/IconicTileSmall.png diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc b/build/wp8/LibLinphoneTester-wp8/Assets/empty_rc similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/empty_rc rename to build/wp8/LibLinphoneTester-wp8/Assets/empty_rc diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc b/build/wp8/LibLinphoneTester-wp8/Assets/laure_rc similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/laure_rc rename to build/wp8/LibLinphoneTester-wp8/Assets/laure_rc diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc b/build/wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc rename to build/wp8/LibLinphoneTester-wp8/Assets/multi_account_lrc diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav b/build/wp8/LibLinphoneTester-wp8/Assets/oldphone.wav similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/oldphone.wav rename to build/wp8/LibLinphoneTester-wp8/Assets/oldphone.wav diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav b/build/wp8/LibLinphoneTester-wp8/Assets/ringback.wav similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Assets/ringback.wav rename to build/wp8/LibLinphoneTester-wp8/Assets/ringback.wav diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj similarity index 84% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj rename to build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj index 6ab7c0d58..4a73fb3b2 100644 --- a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.csproj @@ -26,27 +26,6 @@ 11.0 true - - true - full - false - Bin\Debug - DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - pdbonly - true - Bin\Release - TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - true full @@ -171,12 +150,15 @@ - + + {0565952A-EA62-46A2-8261-F5B4B490DA42} + libmswp8vid + + {5E94A00B-B14A-4E42-8284-8CB0EF099534} - LibLinphoneTester + LibLinphoneTester-native - - Xcopy /I /Y $(ProjectDir)..\..\..\..\tester\*rc $(ProjectDir)Assets\ + Xcopy /I /Y $(ProjectDir)..\..\..\tester\rcfiles\*_rc $(ProjectDir)Assets\ \ No newline at end of file diff --git a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln new file mode 100644 index 000000000..a74c954d7 --- /dev/null +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -0,0 +1,294 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Phone +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "LibLinphoneTester-wp8.csproj", "{34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}" + ProjectSection(ProjectDependencies) = postProject + {5E94A00B-B14A-4E42-8284-8CB0EF099534} = {5E94A00B-B14A-4E42-8284-8CB0EF099534} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphone", "..\LibLinphone.vcxproj", "{08DD0D38-D9B5-4626-B60D-B4D76B571142}" + ProjectSection(ProjectDependencies) = postProject + {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {59500DD1-B192-4DDF-A402-8A8E3739E032} = {59500DD1-B192-4DDF-A402-8A8E3739E032} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester-native", "..\LibLinphoneTester-native\LibLinphoneTester-native.vcxproj", "{5E94A00B-B14A-4E42-8284-8CB0EF099534}" + ProjectSection(ProjectDependencies) = postProject + {D22BD217-D0F8-4274-9B3A-F3F35F46482C} = {D22BD217-D0F8-4274-9B3A-F3F35F46482C} + {902DAF1D-EBF1-4D03-B598-143500A50AB4} = {902DAF1D-EBF1-4D03-B598-143500A50AB4} + {072FAD20-7007-4DA2-B2E7-16CE2B219F67} = {072FAD20-7007-4DA2-B2E7-16CE2B219F67} + {0565952A-EA62-46A2-8261-F5B4B490DA42} = {0565952A-EA62-46A2-8261-F5B4B490DA42} + {08DD0D38-D9B5-4626-B60D-B4D76B571142} = {08DD0D38-D9B5-4626-B60D-B4D76B571142} + {9924AC72-F96C-4E56-94D9-2B025DA43C6B} = {9924AC72-F96C-4E56-94D9-2B025DA43C6B} + {36B528F9-FB79-4078-A16B-0A7442581BB7} = {36B528F9-FB79-4078-A16B-0A7442581BB7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\wp8\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\mediastreamer2\build\wp8\mediastreamer2\mediastreamer2.vcxproj", "{B9BD3213-B7C4-431E-A827-9A92682045AF}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\..\oRTP\build\wp8\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\wp8\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gsm", "..\..\..\..\gsm\build\wp8\gsm\gsm.vcxproj", "{746EA080-5BA9-42C5-9E52-EA421C3F3AFD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speex", "..\..\..\..\speex\build\wp8\speex\speex.vcxproj", "{D5EC8C11-C1D9-47E3-BB82-A93C300FD902}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "speexdsp", "..\..\..\..\speex\build\wp8\speex\speexdsp.vcxproj", "{6BD78980-9C71-4341-8775-AD19E9EC7305}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\wp8\cunit\cunit.vcxproj", "{902DAF1D-EBF1-4D03-B598-143500A50AB4}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\mswasapi\mswasapi\mswasapi.vcxproj", "{D22BD217-D0F8-4274-9B3A-F3F35F46482C}" + ProjectSection(ProjectDependencies) = postProject + {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\..\..\libilbc-rfc3951\build\wp8\libilbc-rfc3951\libilbc-rfc3951.vcxproj", "{8E216BF3-2DD8-4794-8E97-B1AED301ED4D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\wp8\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}" + ProjectSection(ProjectDependencies) = postProject + {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\wp8\mssilk\mssilk.vcxproj", "{36B528F9-FB79-4078-A16B-0A7442581BB7}" + ProjectSection(ProjectDependencies) = postProject + {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\wp8\msamr\msamr.vcxproj", "{9924AC72-F96C-4E56-94D9-2B025DA43C6B}" + ProjectSection(ProjectDependencies) = postProject + {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {018A4428-535C-4566-9AE0-E93AFF0D3ED2} = {018A4428-535C-4566-9AE0-E93AFF0D3ED2} + {7AC65D2A-6981-4D17-856D-C37A522739D8} = {7AC65D2A-6981-4D17-856D-C37A522739D8} + {88191E75-2993-48D7-AA76-652F274EF0FE} = {88191E75-2993-48D7-AA76-652F274EF0FE} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vo-amrwbenc", "..\..\..\..\msamr\build\wp8\msamr\vo-amrwbenc.vcxproj", "{018A4428-535C-4566-9AE0-E93AFF0D3ED2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrnb", "..\..\..\..\msamr\build\wp8\msamr\opencore_amrnb.vcxproj", "{88191E75-2993-48D7-AA76-652F274EF0FE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opencore_amrwb", "..\..\..\..\msamr\build\wp8\msamr\opencore_amrwb.vcxproj", "{7AC65D2A-6981-4D17-856D-C37A522739D8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\wp8\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\wp8\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "..\libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "srtp", "..\..\..\..\srtp\build\wp8\srtp\srtp.vcxproj", "{B4B96BC4-2B72-4964-98E4-7FD048A43363}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswp8vid", "..\..\..\..\mswp8vid\mswp8vid\mswp8vid.vcxproj", "{0565952A-EA62-46A2-8261-F5B4B490DA42}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.ActiveCfg = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Build.0 = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Deploy.0 = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.ActiveCfg = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Build.0 = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Deploy.0 = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.ActiveCfg = Release|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Build.0 = Release|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Deploy.0 = Release|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.ActiveCfg = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Build.0 = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Deploy.0 = Release|x86 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.ActiveCfg = Debug|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.Build.0 = Debug|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.ActiveCfg = Debug|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.Build.0 = Debug|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.ActiveCfg = Release|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.Build.0 = Release|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.ActiveCfg = Release|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.Build.0 = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.ActiveCfg = Debug|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.Build.0 = Debug|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.ActiveCfg = Debug|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.Build.0 = Debug|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.ActiveCfg = Release|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.Build.0 = Release|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.ActiveCfg = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.Build.0 = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32 + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|ARM.ActiveCfg = Debug|ARM + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|ARM.Build.0 = Debug|ARM + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|x86.ActiveCfg = Debug|Win32 + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|x86.Build.0 = Debug|Win32 + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|ARM.ActiveCfg = Release|ARM + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|ARM.Build.0 = Release|ARM + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|x86.ActiveCfg = Release|Win32 + {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|x86.Build.0 = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.Build.0 = Debug|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.ActiveCfg = Release|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.Build.0 = Release|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.ActiveCfg = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.Build.0 = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.ActiveCfg = Debug|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.Build.0 = Debug|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.ActiveCfg = Debug|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.Build.0 = Debug|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.ActiveCfg = Release|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.Build.0 = Release|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.ActiveCfg = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.Build.0 = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.ActiveCfg = Debug|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.Build.0 = Debug|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.ActiveCfg = Debug|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.Build.0 = Debug|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.ActiveCfg = Release|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.Build.0 = Release|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.ActiveCfg = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.Build.0 = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.ActiveCfg = Debug|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.Build.0 = Debug|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.ActiveCfg = Debug|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.Build.0 = Debug|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.ActiveCfg = Release|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.ActiveCfg = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.Build.0 = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.ActiveCfg = Debug|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.Build.0 = Debug|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.ActiveCfg = Debug|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.Build.0 = Debug|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.ActiveCfg = Release|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.ActiveCfg = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.Build.0 = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.ActiveCfg = Release|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.Build.0 = Release|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.ActiveCfg = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.Build.0 = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.ActiveCfg = Debug|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.Build.0 = Debug|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.ActiveCfg = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.Build.0 = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.ActiveCfg = Release|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.Build.0 = Release|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.ActiveCfg = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.Build.0 = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.ActiveCfg = Debug|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.Build.0 = Debug|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.ActiveCfg = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.Build.0 = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.ActiveCfg = Release|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.Build.0 = Release|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.ActiveCfg = Debug|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.Build.0 = Debug|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.ActiveCfg = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.Build.0 = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.ActiveCfg = Release|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.Build.0 = Release|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.ActiveCfg = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.Build.0 = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.ActiveCfg = Debug|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.Build.0 = Debug|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.ActiveCfg = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.Build.0 = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.ActiveCfg = Release|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.Build.0 = Release|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.ActiveCfg = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.Build.0 = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.ActiveCfg = Debug|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.Build.0 = Debug|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.ActiveCfg = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.Build.0 = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.ActiveCfg = Release|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.Build.0 = Release|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.ActiveCfg = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.Build.0 = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.ActiveCfg = Debug|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.Build.0 = Debug|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.ActiveCfg = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.Build.0 = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.ActiveCfg = Release|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.Build.0 = Release|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.ActiveCfg = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.Build.0 = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.ActiveCfg = Debug|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.Build.0 = Debug|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.ActiveCfg = Debug|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.Build.0 = Debug|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.ActiveCfg = Release|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.Build.0 = Release|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.ActiveCfg = Release|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.Build.0 = Release|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.ActiveCfg = Debug|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.Build.0 = Debug|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.ActiveCfg = Debug|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.Build.0 = Debug|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.ActiveCfg = Release|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.Build.0 = Release|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.ActiveCfg = Release|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs b/build/wp8/LibLinphoneTester-wp8/LocalizedStrings.cs similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/LocalizedStrings.cs rename to build/wp8/LibLinphoneTester-wp8/LocalizedStrings.cs diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml b/build/wp8/LibLinphoneTester-wp8/MainPage.xaml similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml rename to build/wp8/LibLinphoneTester-wp8/MainPage.xaml diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs b/build/wp8/LibLinphoneTester-wp8/MainPage.xaml.cs similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/MainPage.xaml.cs rename to build/wp8/LibLinphoneTester-wp8/MainPage.xaml.cs diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml b/build/wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml rename to build/wp8/LibLinphoneTester-wp8/Properties/AppManifest.xml diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs b/build/wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs rename to build/wp8/LibLinphoneTester-wp8/Properties/AssemblyInfo.cs diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml b/build/wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml rename to build/wp8/LibLinphoneTester-wp8/Properties/WMAppManifest.xml diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs b/build/wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs rename to build/wp8/LibLinphoneTester-wp8/Resources/AppResources.Designer.cs diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx b/build/wp8/LibLinphoneTester-wp8/Resources/AppResources.resx similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/Resources/AppResources.resx rename to build/wp8/LibLinphoneTester-wp8/Resources/AppResources.resx diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml b/build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml rename to build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs b/build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs rename to build/wp8/LibLinphoneTester-wp8/TestCasePage.xaml.cs diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml b/build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml rename to build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs b/build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs rename to build/wp8/LibLinphoneTester-wp8/TestResultPage.xaml.cs diff --git a/build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html b/build/wp8/LibLinphoneTester-wp8/log.html similarity index 100% rename from build/vsx/LibLinphoneTester-wp8/LibLinphoneTester-wp8/log.html rename to build/wp8/LibLinphoneTester-wp8/log.html diff --git a/build/vsx/libxml2/libxml2/install_headers.bat b/build/wp8/libxml2/install_headers.bat similarity index 71% rename from build/vsx/libxml2/libxml2/install_headers.bat rename to build/wp8/libxml2/install_headers.bat index 8e97127d8..d33f20c04 100644 --- a/build/vsx/libxml2/libxml2/install_headers.bat +++ b/build/wp8/libxml2/install_headers.bat @@ -1,5 +1,5 @@ SET curdir=%CD% -SET incdir=..\..\..\..\..\libxml2\include\libxml +SET incdir=..\..\..\..\libxml2\include\libxml SET installdir=%1\libxml Xcopy /I /Y %incdir%\*.h %installdir%\ diff --git a/build/vsx/libxml2/libxml2.sln b/build/wp8/libxml2/libxml2.sln similarity index 94% rename from build/vsx/libxml2/libxml2.sln rename to build/wp8/libxml2/libxml2.sln index 62fad2d3f..b10b61b6b 100644 --- a/build/vsx/libxml2/libxml2.sln +++ b/build/wp8/libxml2/libxml2.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Express 2012 for Windows Phone -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "libxml2\libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxml2", "libxml2.vcxproj", "{5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/build/wp8/libxml2/libxml2.vcxproj b/build/wp8/libxml2/libxml2.vcxproj new file mode 100644 index 000000000..0e1f21c63 --- /dev/null +++ b/build/wp8/libxml2/libxml2.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {5dfa07b4-0be9-46a9-ba32-fdf5a55c580b} + libxml2 + en-US + 11.0 + + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ + + + false + + + + Level4 + $(SolutionDir)$(Platform)\$(Configuration)\include;$(ProjectDir)..\..\..\..\libxml2\include;$(ProjectDir)..\..\..\..\libxml2\win32\VC10;%(AdditionalIncludeDirectories) + _WIN32;_WINDLL;_USRDLL;_CRT_SECURE_NO_WARNINGS;HAVE_WIN32_THREADS;HAVE_COMPILER_TLS;UNICODE;%(PreprocessorDefinitions) + LIBXML_MODULES_ENABLED + Default + NotUsing + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + $(ProjectDir)libxml2_port.h + + + Console + false + false + $(TargetDir)$(TargetName).lib + Ws2_32.lib;%(AdditionalDependencies) + + + install_headers.bat $(SolutionDir)$(Platform)\$(Configuration)\include + + + + + _DEBUG;%(PreprocessorDefinitions) + + + true + + + + + NDEBUG;%(PreprocessorDefinitions) + MaxSpeed + true + true + true + + + false + + + + + true + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build/vsx/libxml2/libxml2/libxml2_port.h b/build/wp8/libxml2/libxml2_port.h similarity index 100% rename from build/vsx/libxml2/libxml2/libxml2_port.h rename to build/wp8/libxml2/libxml2_port.h diff --git a/build/vsx/libxml2/libxml2/xmlversion.h b/build/wp8/libxml2/xmlversion.h similarity index 100% rename from build/vsx/libxml2/libxml2/xmlversion.h rename to build/wp8/libxml2/xmlversion.h From e41203a4c56e45b1263c62781296733f1b7cc1d9 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 25 Jun 2014 17:45:28 +0200 Subject: [PATCH 162/201] Fix compilation for Windows Phone 8. --- coreapi/event.h | 2 +- coreapi/linphonecore.h | 6 ++--- coreapi/private.h | 6 ++--- coreapi/quality_reporting.h | 2 +- include/sal/sal.h | 2 +- tester/call_tester.c | 32 +++++++++++++++------------ tester/eventapi_tester.c | 3 ++- tester/flexisip_tester.c | 3 ++- tester/message_tester.c | 34 +++++++++++++++++------------ tester/remote_provisioning_tester.c | 3 ++- 10 files changed, 53 insertions(+), 40 deletions(-) diff --git a/coreapi/event.h b/coreapi/event.h index 0cf107fd7..894f3e32a 100644 --- a/coreapi/event.h +++ b/coreapi/event.h @@ -210,7 +210,7 @@ LINPHONE_PUBLIC LinphoneReason linphone_event_get_reason(const LinphoneEvent *le /** * Get full details about an error occured. **/ -const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev); +LINPHONE_PUBLIC const LinphoneErrorInfo *linphone_event_get_error_info(const LinphoneEvent *lev); /** * Get subscription state. If the event object was not created by a subscription mechanism, #LinphoneSubscriptionNone is returned. diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 0cabc434f..05776a89d 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -875,7 +875,7 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_quality_reporting_collecto * @param[in] cfg #LinphoneProxyConfig object * @param[in] interval The interval in seconds, 0 means interval reports are disabled. */ -void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval); +LINPHONE_PUBLIC void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *cfg, uint8_t interval); /** * Get the interval between interval reports when using quality reporting. @@ -883,7 +883,7 @@ void linphone_proxy_config_set_quality_reporting_interval(LinphoneProxyConfig *c * @return The interval in seconds, 0 means interval reports are disabled. */ -int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg); +LINPHONE_PUBLIC int linphone_proxy_config_get_quality_reporting_interval(LinphoneProxyConfig *cfg); /** * Get the registration state of the given proxy config. @@ -2317,7 +2317,7 @@ LINPHONE_PUBLIC int linphone_core_get_camera_sensor_rotation(LinphoneCore *lc); void linphone_core_show_video(LinphoneCore *lc, bool_t show); /*play/record support: use files instead of soundcard*/ -void linphone_core_use_files(LinphoneCore *lc, bool_t yesno); +LINPHONE_PUBLIC void linphone_core_use_files(LinphoneCore *lc, bool_t yesno); LINPHONE_PUBLIC void linphone_core_set_play_file(LinphoneCore *lc, const char *file); LINPHONE_PUBLIC void linphone_core_set_record_file(LinphoneCore *lc, const char *file); diff --git a/coreapi/private.h b/coreapi/private.h index 5c174fb64..1b8a0d4ad 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -338,7 +338,7 @@ void linphone_subscription_closed(LinphoneCore *lc, SalOp *op); void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc); void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt, int maxbw); -int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); +LINPHONE_PUBLIC int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call); void linphone_core_resolve_stun_server(LinphoneCore *lc); const struct addrinfo *linphone_core_get_stun_server_addrinfo(LinphoneCore *lc); void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params); @@ -406,8 +406,8 @@ LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer); void linphone_core_queue_task(LinphoneCore *lc, belle_sip_source_func_t task_fun, void *data, const char *task_description); static const int linphone_proxy_config_magic=0x7979; -bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); -bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); +LINPHONE_PUBLIC bool_t linphone_proxy_config_address_equal(const LinphoneAddress *a, const LinphoneAddress *b); +LINPHONE_PUBLIC bool_t linphone_proxy_config_is_server_config_changed(const LinphoneProxyConfig* obj); void _linphone_proxy_config_unregister(LinphoneProxyConfig *obj); /*chat*/ diff --git a/coreapi/quality_reporting.h b/coreapi/quality_reporting.h index acc898924..319353fc0 100644 --- a/coreapi/quality_reporting.h +++ b/coreapi/quality_reporting.h @@ -205,7 +205,7 @@ void linphone_reporting_call_state_updated(LinphoneCall *call); * @param cb #LinphoneQualityReportingReportSendCb callback function to notify * */ -void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb); +LINPHONE_PUBLIC void linphone_reporting_set_on_report_send(LinphoneCall *call, LinphoneQualityReportingReportSendCb cb); #ifdef __cplusplus } diff --git a/include/sal/sal.h b/include/sal/sal.h index 642cfdd2a..5533182ed 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -545,7 +545,7 @@ void sal_verify_server_certificates(Sal *ctx, bool_t verify); void sal_verify_server_cn(Sal *ctx, bool_t verify); void sal_set_uuid(Sal*ctx, const char *uuid); int sal_create_uuid(Sal*ctx, char *uuid, size_t len); -void sal_enable_test_features(Sal*ctx, bool_t enabled); +LINPHONE_PUBLIC void sal_enable_test_features(Sal*ctx, bool_t enabled); void sal_use_no_initial_route(Sal *ctx, bool_t enabled); int sal_iterate(Sal *sal); diff --git a/tester/call_tester.c b/tester/call_tester.c index ceb9055e3..3e1a11ed6 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -246,19 +246,22 @@ static void end_call(LinphoneCoreManager *m1, LinphoneCoreManager *m2){ } static void simple_call(void) { - belle_sip_object_enable_leak_detector(TRUE); - int begin=belle_sip_object_get_object_count(); + int begin; int leaked_objects; - { - LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); - LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + LinphoneCoreManager* marie; + LinphoneCoreManager* pauline; + + belle_sip_object_enable_leak_detector(TRUE); + begin=belle_sip_object_get_object_count(); + + marie = linphone_core_manager_new( "marie_rc"); + pauline = linphone_core_manager_new( "pauline_rc"); + CU_ASSERT_TRUE(call(pauline,marie)); + liblinphone_tester_check_rtcp(marie,pauline); + end_call(marie,pauline); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); - CU_ASSERT_TRUE(call(pauline,marie)); - liblinphone_tester_check_rtcp(marie,pauline); - end_call(marie,pauline); - linphone_core_manager_destroy(marie); - linphone_core_manager_destroy(pauline); - } leaked_objects=belle_sip_object_get_object_count()-begin; CU_ASSERT_TRUE(leaked_objects==0); if (leaked_objects>0){ @@ -816,11 +819,11 @@ static void call_with_custom_headers(void) { *pauline_remote_contact, *marie_remote_contact, *marie_remote_contact_header; - + LinphoneAddress* marie_identity; char* tmp=linphone_address_as_string_uri_only(marie->identity); char tmp2[256]; snprintf(tmp2,sizeof(tmp2),"%s?uriHeader=myUriHeader",tmp); - LinphoneAddress* marie_identity=linphone_address_new(tmp2); + marie_identity=linphone_address_new(tmp2); ms_free(tmp); linphone_address_destroy(marie->identity); marie->identity=marie_identity; @@ -1358,6 +1361,7 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc"); char hellopath[256]; MSList *iterator; + MSList* lcs; LinphoneCall* pauline_called_by_marie; LinphoneCall* pauline_called_by_laure=NULL; LinphoneCallParams *laure_params=linphone_core_create_default_call_parameters(laure->lc); @@ -1366,7 +1370,7 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { if (enable_caller_privacy) linphone_call_params_set_privacy(marie_params,LinphonePrivacyId); - MSList* lcs=ms_list_append(NULL,marie->lc); + lcs=ms_list_append(NULL,marie->lc); lcs=ms_list_append(lcs,pauline->lc); lcs=ms_list_append(lcs,laure->lc); diff --git a/tester/eventapi_tester.c b/tester/eventapi_tester.c index e5c459489..1d4b07e59 100644 --- a/tester/eventapi_tester.c +++ b/tester/eventapi_tester.c @@ -38,9 +38,10 @@ const char *liblinphone_tester_get_notify_content(void){ } void linphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *eventname, const LinphoneContent *content){ + LinphoneCoreManager *mgr; CU_ASSERT_PTR_NOT_NULL_FATAL(content); CU_ASSERT_TRUE(strcmp(notify_content,(const char*)content->data)==0); - LinphoneCoreManager *mgr=get_manager(lc); + mgr=get_manager(lc); mgr->stat.number_of_NotifyReceived++; } diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 89c2dfe4b..a91811538 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -376,13 +376,14 @@ static void call_forking_declined_localy(void){ static void call_forking_with_push_notification_single(void){ char hellopath[256]; + MSList* lcs; LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL); linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL); - MSList* lcs=ms_list_append(NULL,pauline->lc); + lcs=ms_list_append(NULL,pauline->lc); lcs=ms_list_append(lcs,marie->lc); diff --git a/tester/message_tester.c b/tester/message_tester.c index 407dc7509..a9b35253a 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -74,9 +74,9 @@ void file_transfer_received(LinphoneCore *lc, LinphoneChatMessage *message, cons file = (FILE*)linphone_chat_message_get_user_data(message); if (size==0) { /* tranfer complerte */ + stats* counters = get_stats(lc); linphone_chat_room_destroy(linphone_chat_message_get_chat_room(message)); linphone_chat_message_destroy(message); - stats* counters = get_stats(lc); counters->number_of_LinphoneMessageExtBodyReceived++; fclose(file); } else { /* store content on a file*/ @@ -178,13 +178,15 @@ static void text_message(void) { } static void text_message_within_dialog(void) { + char* to; + LinphoneChatRoom* chat_room; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); lp_config_set_int(pauline->lc->config,"sip","chat_use_call_dialogs",1); - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); CU_ASSERT_TRUE(call(marie,pauline)); @@ -211,6 +213,8 @@ static void text_message_with_credential_from_auth_cb_auth_info_requested(Linpho static void text_message_with_credential_from_auth_cb(void) { + char* to; + LinphoneChatRoom* chat_room; LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); text_message_with_credential_from_auth_cb_auth_info=linphone_auth_info_clone((LinphoneAuthInfo*)(linphone_core_get_auth_info_list(marie->lc)->data)); @@ -219,8 +223,8 @@ static void text_message_with_credential_from_auth_cb(void) { linphone_core_clear_all_auth_info(marie->lc); marie->lc->vtable.auth_info_requested=text_message_with_credential_from_auth_cb_auth_info_requested; - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); ms_free(to); @@ -336,32 +340,34 @@ static void text_message_with_external_body(void) { static void file_transfer_message(void) { int i; - /* setting dummy file content to something */ - const char* big_file_content="big file"; + char* to; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneContent content; + const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); /* create a chatroom on pauline's side */ - char* to = linphone_address_as_string(marie->identity); - LinphoneChatRoom* chat_room = linphone_core_create_chat_room(pauline->lc,to); + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); /* create a file transfer message */ - LinphoneContent content; memset(&content,0,sizeof(content)); content.type="text"; content.subtype="plain"; content.size=sizeof(big_file); /*total size to be transfered*/ content.name = "bigfile.txt"; - LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + message = linphone_chat_room_create_file_transfer_message(chat_room, &content); linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index 365673ff6..d81df94d4 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -23,9 +23,10 @@ #include "liblinphone_tester.h" void linphone_configuration_status(LinphoneCore *lc, LinphoneConfiguringState status, const char *message) { + stats* counters; ms_message("Configuring state = %i with message %s", status, message?message:""); - stats* counters = get_stats(lc); + counters = get_stats(lc); if (status == LinphoneConfiguringSkipped) { counters->number_of_LinphoneConfiguringSkipped++; } else if (status == LinphoneConfiguringFailed) { From d6fc5e8a36a5bb11594bbb75d360a4fbf41cb9dc Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 23 Jun 2014 21:36:07 +0200 Subject: [PATCH 163/201] fix presence id generation --- coreapi/linphonecore.c | 2 +- coreapi/presence.c | 12 +++++++----- coreapi/private.h | 2 +- coreapi/proxy.c | 5 +++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 65db5a709..1a7c1d5e1 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -717,7 +717,7 @@ static void sip_config_read(LinphoneCore *lc) /* get proxies config */ for(i=0;; i++){ - LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i); + LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc,i); if (cfg!=NULL){ linphone_core_add_proxy_config(lc,cfg); }else{ diff --git a/coreapi/presence.c b/coreapi/presence.c index df9271844..183002b86 100644 --- a/coreapi/presence.c +++ b/coreapi/presence.c @@ -81,15 +81,17 @@ static const char *person_prefix = "/pidf:presence/dm:person"; /***************************************************************************** * PRIVATE FUNCTIONS * ****************************************************************************/ - -static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz"; +/*defined in http://www.w3.org/TR/REC-xml/*/ +static char presence_id_valid_characters[] = "0123456789abcdefghijklmnopqrstuvwxyz-."; +/*NameStartChar (NameChar)**/ +static char presence_id_valid_start_characters[] = ":_abcdefghijklmnopqrstuvwxyz"; static char * generate_presence_id(void) { char id[7]; int i; - - for (i = 0; i < 6; i++) { - id[i] = presence_id_valid_characters[random() % sizeof(presence_id_valid_characters)]; + id[0] = presence_id_valid_start_characters[random() % (sizeof(presence_id_valid_start_characters)-1)]; + for (i = 1; i < 6; i++) { + id[i] = presence_id_valid_characters[random() % (sizeof(presence_id_valid_characters)-1)]; } id[6] = '\0'; diff --git a/coreapi/private.h b/coreapi/private.h index 1b8a0d4ad..690498c98 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -360,7 +360,7 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L const char *linphone_core_find_best_identity(LinphoneCore *lc, const LinphoneAddress *to); int linphone_core_get_local_ip_for(int type, const char *dest, char *result); -LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(struct _LpConfig *config, int index); +LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore *lc, int index); void linphone_proxy_config_write_to_config_file(struct _LpConfig* config,LinphoneProxyConfig *obj, int index); int linphone_proxy_config_normalize_number(LinphoneProxyConfig *cfg, const char *username, char *result, size_t result_len); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 4f39247b6..201035606 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1211,7 +1211,7 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC -LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config, int index) +LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc, int index) { const char *tmp; const char *identity; @@ -1219,6 +1219,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config LinphoneProxyConfig *cfg; char key[50]; int interval; + LpConfig *config=lc->config; sprintf(key,"proxy_%i",index); @@ -1226,7 +1227,7 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config return NULL; } - cfg=linphone_proxy_config_new(); + cfg=linphone_core_create_proxy_config(lc); identity=lp_config_get_string(config,key,"reg_identity",NULL); proxy=lp_config_get_string(config,key,"reg_proxy",NULL); From f17e70838e469b2d72bf23defb67c4f9eee7bfe1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 25 Jun 2014 17:54:00 +0200 Subject: [PATCH 164/201] fix build issue --- coreapi/private.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/coreapi/private.h b/coreapi/private.h index 1aefc667e..4ae799c93 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -375,8 +375,6 @@ void linphone_call_init_video_stream(LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone); void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call); -void linphone_call_stop_audio_stream(LinphoneCall *call); -void linphone_call_stop_video_stream(LinphoneCall *call); void linphone_call_stop_media_streams(LinphoneCall *call); void linphone_call_delete_ice_session(LinphoneCall *call); void linphone_call_delete_upnp_session(LinphoneCall *call); From 17c77cbf5dd5fd9d66ca7c72671bb812d9e53dfd Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 25 Jun 2014 18:28:56 +0200 Subject: [PATCH 165/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 2a8a13ab6..30ed2c1ae 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 2a8a13ab6a83fe4b63778886b4b9ef844dd51e87 +Subproject commit 30ed2c1ae1e7b04eeee35de47ceaa10a0149b76a From 58530de9bb837320d12e8a8043091dace1e2613c Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Thu, 26 Jun 2014 00:45:53 +0200 Subject: [PATCH 166/201] File transfer : add test for I/O error --- coreapi/chat.c | 3 ++- tester/liblinphone_tester.h | 1 + tester/message_tester.c | 51 +++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index addc400fc..39e5f4c34 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -49,7 +49,8 @@ static size_t linphone_chat_message_compute_multipart_header_size(const char *fi return strlen(MULTIPART_HEADER_1)+strlen(filename)+strlen(MULTIPART_HEADER_2)+strlen(content_type)+strlen(MULTIPART_HEADER_3); } static void process_io_error(void *data, const belle_sip_io_error_event_t *event){ - printf("We have a response io error!\n"); + LinphoneChatMessage* msg=(LinphoneChatMessage *)data; + msg->cb(msg, LinphoneChatMessageStateNotDelivered, msg->chat_room->lc); } static void process_auth_requested(void *data, belle_sip_auth_event_t *event){ printf("We have a auth requested!\n"); diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 3d1cbc953..239e30e0b 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -131,6 +131,7 @@ typedef struct _stats { int number_of_LinphoneMessageNotDelivered; int number_of_LinphoneIsComposingActiveReceived; int number_of_LinphoneIsComposingIdleReceived; + int progress_of_LinphoneFileTransfer; int number_of_IframeDecoded; diff --git a/tester/message_tester.c b/tester/message_tester.c index a9b35253a..bb18b1931 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -127,6 +127,8 @@ void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *me , content->subtype ,(linphone_chat_message_is_outgoing(message)?"to":"from") , address); + stats* counters = get_stats(lc); + counters->progress_of_LinphoneFileTransfer = progress; free(address); } @@ -380,6 +382,54 @@ static void file_transfer_message(void) { linphone_core_manager_destroy(pauline); } +static void file_transfer_message_io_error(void) { + int i; + char* to; + LinphoneChatRoom* chat_room; + LinphoneChatMessage* message; + LinphoneContent content; + const char* big_file_content="big file"; /* setting dummy file content to something */ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + + /* setting dummy file content to something */ + for (i=0;ilc,"https://www.linphone.org:444/lft.php"); + + /* create a chatroom on pauline's side */ + to = linphone_address_as_string(marie->identity); + chat_room = linphone_core_create_chat_room(pauline->lc,to); + + /* create a file transfer message */ + memset(&content,0,sizeof(content)); + content.type="text"; + content.subtype="plain"; + content.size=sizeof(big_file); /*total size to be transfered*/ + content.name = "bigfile.txt"; + message = linphone_chat_room_create_file_transfer_message(chat_room, &content); + + linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); + + /*wait for file to be 25% uploaded and simultate a network error*/ + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.progress_of_LinphoneFileTransfer,25)); + sal_set_send_error(pauline->lc->sal, -1); + + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageNotDelivered,1)); + + CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageNotDelivered,1); + CU_ASSERT_EQUAL(marie->stat.number_of_LinphoneMessageExtBodyReceived,0); + + sal_set_send_error(pauline->lc->sal, 0); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void text_message_with_send_error(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); @@ -607,6 +657,7 @@ test_t message_tests[] = { { "Text message with send error", text_message_with_send_error }, { "Text message with external body", text_message_with_external_body }, { "File transfer message", file_transfer_message }, + { "File transfer message with io error", file_transfer_message_io_error }, { "Text message denied", text_message_denied }, { "Info message", info_message }, { "Info message with body", info_message_with_body }, From 397203140165e052292bf1e5b894f0d486538d2d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jun 2014 11:57:14 +0200 Subject: [PATCH 167/201] Add references to ms2 plugins in the Windows Phone 8 project. --- build/wp8/LibLinphone.vcxproj | 18 ++++++++++++++++++ mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/build/wp8/LibLinphone.vcxproj b/build/wp8/LibLinphone.vcxproj index 7f9a53ce0..6e2fb044d 100644 --- a/build/wp8/LibLinphone.vcxproj +++ b/build/wp8/LibLinphone.vcxproj @@ -162,9 +162,27 @@ + + {1db09afe-fc9b-472e-a746-0e33f8ef8883} + {4c225a82-800b-427b-ba7b-61686a9b347f} + + {9924ac72-f96c-4e56-94d9-2b025da43c6b} + + + {072fad20-7007-4da2-b2e7-16ce2b219f67} + + + {36b528f9-fb79-4078-a16b-0a7442581bb7} + + + {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + + {0565952a-ea62-46a2-8261-f5b4b490da42} + {59500dd1-b192-4ddf-a402-8a8e3739e032} diff --git a/mediastreamer2 b/mediastreamer2 index 30ed2c1ae..c3e51bb20 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 30ed2c1ae1e7b04eeee35de47ceaa10a0149b76a +Subproject commit c3e51bb20be5658a5883a5d056084ddfa9fe2ac1 diff --git a/oRTP b/oRTP index d0e9c7c3d..43a9185fe 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit d0e9c7c3d961ac1a400bf2796b03ebefab77541d +Subproject commit 43a9185fe6baab7a009f730f123f1de07555f5fe From f5c4e889b1ad794ce995c2b706f592a3428c6084 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jun 2014 12:14:58 +0200 Subject: [PATCH 168/201] Fix mediastreamer2 references in Windows Phone 8 projects. --- build/wp8/LibLinphone.vcxproj | 2 +- .../LibLinphoneTester-native.vcxproj | 2 +- .../LibLinphoneTester-wp8.sln | 28 +++++++++---------- mediastreamer2 | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/build/wp8/LibLinphone.vcxproj b/build/wp8/LibLinphone.vcxproj index 6e2fb044d..3ae118ae8 100644 --- a/build/wp8/LibLinphone.vcxproj +++ b/build/wp8/LibLinphone.vcxproj @@ -187,7 +187,7 @@ {59500dd1-b192-4ddf-a402-8a8e3739e032} - {b9bd3213-b7c4-431e-a827-9a92682045af} + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} {ffc7b532-0502-4d88-ac98-9e89071cbc97} diff --git a/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj index bf345cce1..10bb0241b 100644 --- a/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj +++ b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj @@ -136,7 +136,7 @@ {0565952a-ea62-46a2-8261-f5b4b490da42} - {b9bd3213-b7c4-431e-a827-9a92682045af} + {027bad0e-9179-48c1-9733-7aa7e2c2ec70} {ffc7b532-0502-4d88-ac98-9e89071cbc97} diff --git a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index a74c954d7..5768cb744 100644 --- a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -8,7 +8,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibLinphoneTester-wp8", "Li EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphone", "..\LibLinphone.vcxproj", "{08DD0D38-D9B5-4626-B60D-B4D76B571142}" ProjectSection(ProjectDependencies) = postProject - {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} {59500DD1-B192-4DDF-A402-8A8E3739E032} = {59500DD1-B192-4DDF-A402-8A8E3739E032} EndProjectSection EndProject @@ -25,7 +25,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester-native", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\wp8\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\mediastreamer2\build\wp8\mediastreamer2\mediastreamer2.vcxproj", "{B9BD3213-B7C4-431E-A827-9A92682045AF}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mediastreamer2", "..\..\..\mediastreamer2\build\wp8\mediastreamer2\mediastreamer2.vcxproj", "{027BAD0E-9179-48C1-9733-7AA7E2C2EC70}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "oRTP", "..\..\..\oRTP\build\wp8\oRTP\oRTP.vcxproj", "{FFC7B532-0502-4D88-AC98-9E89071CBC97}" EndProject @@ -41,7 +41,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswasapi", "..\..\..\..\mswasapi\mswasapi\mswasapi.vcxproj", "{D22BD217-D0F8-4274-9B3A-F3F35F46482C}" ProjectSection(ProjectDependencies) = postProject - {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} EndProjectSection EndProject @@ -49,19 +49,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libilbc-rfc3951", "..\..\.. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsilbc", "..\..\..\..\msilbc\build\wp8\msilbc\msilbc.vcxproj", "{072FAD20-7007-4DA2-B2E7-16CE2B219F67}" ProjectSection(ProjectDependencies) = postProject - {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmssilk", "..\..\..\..\mssilk\build\wp8\mssilk\mssilk.vcxproj", "{36B528F9-FB79-4078-A16B-0A7442581BB7}" ProjectSection(ProjectDependencies) = postProject - {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} {FFC7B532-0502-4D88-AC98-9E89071CBC97} = {FFC7B532-0502-4D88-AC98-9E89071CBC97} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsamr", "..\..\..\..\msamr\build\wp8\msamr\msamr.vcxproj", "{9924AC72-F96C-4E56-94D9-2B025DA43C6B}" ProjectSection(ProjectDependencies) = postProject - {B9BD3213-B7C4-431E-A827-9A92682045AF} = {B9BD3213-B7C4-431E-A827-9A92682045AF} + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} = {027BAD0E-9179-48C1-9733-7AA7E2C2EC70} {018A4428-535C-4566-9AE0-E93AFF0D3ED2} = {018A4428-535C-4566-9AE0-E93AFF0D3ED2} {7AC65D2A-6981-4D17-856D-C37A522739D8} = {7AC65D2A-6981-4D17-856D-C37A522739D8} {88191E75-2993-48D7-AA76-652F274EF0FE} = {88191E75-2993-48D7-AA76-652F274EF0FE} @@ -127,14 +127,14 @@ Global {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32 - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|ARM.ActiveCfg = Debug|ARM - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|ARM.Build.0 = Debug|ARM - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|x86.ActiveCfg = Debug|Win32 - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Debug|x86.Build.0 = Debug|Win32 - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|ARM.ActiveCfg = Release|ARM - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|ARM.Build.0 = Release|ARM - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|x86.ActiveCfg = Release|Win32 - {B9BD3213-B7C4-431E-A827-9A92682045AF}.Release|x86.Build.0 = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.ActiveCfg = Debug|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.Build.0 = Debug|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.ActiveCfg = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.Build.0 = Release|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32 diff --git a/mediastreamer2 b/mediastreamer2 index c3e51bb20..e3d68c9f9 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c3e51bb20be5658a5883a5d056084ddfa9fe2ac1 +Subproject commit e3d68c9f9a0104f6d1355894dd215bf398d09c32 From c230ea0b536ae54abba53858561e1b42fc09d543 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jun 2014 14:14:21 +0200 Subject: [PATCH 169/201] Update ms2 submodule. --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index e3d68c9f9..d53acb177 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit e3d68c9f9a0104f6d1355894dd215bf398d09c32 +Subproject commit d53acb177a5be59cbd7e277f6358d339670b2dd1 From 278f48022d490c86f2c5f1d34612c0f1369bb6cd Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jun 2014 14:21:28 +0200 Subject: [PATCH 170/201] Add mswebrtc to the liblinphone-tester project for Windows Phone 8. --- .../LibLinphoneTester-native.vcxproj | 6 + .../LibLinphoneTester-wp8.sln | 144 ++++++++++++++++++ tester/message_tester.c | 2 +- 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj index 10bb0241b..424044515 100644 --- a/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj +++ b/build/wp8/LibLinphoneTester-native/LibLinphoneTester-native.vcxproj @@ -114,6 +114,9 @@ + + {1db09afe-fc9b-472e-a746-0e33f8ef8883} + {4c225a82-800b-427b-ba7b-61686a9b347f} @@ -132,6 +135,9 @@ {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + {b16b81a9-bef2-44c9-b603-1065183ae844} + {0565952a-ea62-46a2-8261-f5b4b490da42} diff --git a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index 5768cb744..dc0ab0ae2 100644 --- a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -20,7 +20,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibLinphoneTester-native", {0565952A-EA62-46A2-8261-F5B4B490DA42} = {0565952A-EA62-46A2-8261-F5B4B490DA42} {08DD0D38-D9B5-4626-B60D-B4D76B571142} = {08DD0D38-D9B5-4626-B60D-B4D76B571142} {9924AC72-F96C-4E56-94D9-2B025DA43C6B} = {9924AC72-F96C-4E56-94D9-2B025DA43C6B} + {B16B81A9-BEF2-44C9-B603-1065183AE844} = {B16B81A9-BEF2-44C9-B603-1065183AE844} {36B528F9-FB79-4078-A16B-0A7442581BB7} = {36B528F9-FB79-4078-A16B-0A7442581BB7} + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883} = {1DB09AFE-FC9B-472E-A746-0E33F8EF8883} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\..\..\..\belle-sip\build\wp8\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" @@ -83,210 +85,352 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "srtp", "..\..\..\..\srtp\bu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswp8vid", "..\..\..\..\mswp8vid\mswp8vid\mswp8vid.vcxproj", "{0565952A-EA62-46A2-8261-F5B4B490DA42}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswebrtc", "..\..\..\..\mswebrtc\build\wp8\mswebrtc\mswebrtc.vcxproj", "{B16B81A9-BEF2-44C9-B603-1065183AE844}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcisac", "..\..\..\..\mswebrtc\webrtc\build\wp8\webrtcisac\webrtcisac.vcxproj", "{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsbcg729", "..\..\..\..\bcg729\build\wp8\bcg729\bcg729.vcxproj", "{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM + Debug|Win32 = Debug|Win32 Debug|x86 = Debug|x86 Release|ARM = Release|ARM + Release|Win32 = Release|Win32 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.ActiveCfg = Debug|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Build.0 = Debug|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Deploy.0 = Debug|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.ActiveCfg = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Build.0 = Debug|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Deploy.0 = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.ActiveCfg = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Build.0 = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Deploy.0 = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.ActiveCfg = Release|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Build.0 = Release|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Deploy.0 = Release|ARM + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.ActiveCfg = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Build.0 = Release|x86 + {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Deploy.0 = Release|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.ActiveCfg = Release|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Build.0 = Release|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Deploy.0 = Release|x86 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.ActiveCfg = Debug|ARM {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.Build.0 = Debug|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.ActiveCfg = Debug|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.Build.0 = Debug|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.ActiveCfg = Debug|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.Build.0 = Debug|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.ActiveCfg = Release|ARM {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.Build.0 = Release|ARM + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.ActiveCfg = Release|Win32 + {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.Build.0 = Release|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.ActiveCfg = Release|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.Build.0 = Release|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.ActiveCfg = Debug|ARM {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.Build.0 = Debug|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.ActiveCfg = Debug|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.Build.0 = Debug|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.ActiveCfg = Debug|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.Build.0 = Debug|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.ActiveCfg = Release|ARM {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.Build.0 = Release|ARM + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.ActiveCfg = Release|Win32 + {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.Build.0 = Release|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.ActiveCfg = Release|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.Build.0 = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.Build.0 = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.ActiveCfg = Release|Win32 + {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.Build.0 = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.ActiveCfg = Debug|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.Build.0 = Debug|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.ActiveCfg = Debug|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.Build.0 = Debug|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.ActiveCfg = Release|Win32 + {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.Build.0 = Release|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.ActiveCfg = Release|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.Build.0 = Release|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.ActiveCfg = Debug|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.Build.0 = Debug|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.Build.0 = Debug|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.ActiveCfg = Release|ARM {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.Build.0 = Release|ARM + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.ActiveCfg = Release|Win32 + {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.Build.0 = Release|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.ActiveCfg = Release|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.Build.0 = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.Build.0 = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.ActiveCfg = Release|Win32 + {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.Build.0 = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.ActiveCfg = Debug|ARM {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.Build.0 = Debug|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.ActiveCfg = Debug|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.Build.0 = Debug|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.ActiveCfg = Debug|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.Build.0 = Debug|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.ActiveCfg = Release|ARM {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.Build.0 = Release|ARM + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.ActiveCfg = Release|Win32 + {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.Build.0 = Release|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.ActiveCfg = Release|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.Build.0 = Release|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.ActiveCfg = Debug|ARM {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.Build.0 = Debug|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.ActiveCfg = Debug|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.Build.0 = Debug|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.ActiveCfg = Debug|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.Build.0 = Debug|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.ActiveCfg = Release|ARM {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.Build.0 = Release|ARM + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.ActiveCfg = Release|Win32 + {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.Build.0 = Release|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.ActiveCfg = Release|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.Build.0 = Release|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.ActiveCfg = Debug|ARM {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.Build.0 = Debug|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.ActiveCfg = Debug|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.Build.0 = Debug|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.ActiveCfg = Debug|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.Build.0 = Debug|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.ActiveCfg = Release|ARM {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.ActiveCfg = Release|Win32 + {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.Build.0 = Release|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.ActiveCfg = Release|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.Build.0 = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.ActiveCfg = Debug|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.Build.0 = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.ActiveCfg = Release|Win32 + {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.Build.0 = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.ActiveCfg = Debug|ARM {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.Build.0 = Debug|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.ActiveCfg = Debug|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.Build.0 = Debug|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.ActiveCfg = Debug|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.Build.0 = Debug|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.ActiveCfg = Release|ARM {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.ActiveCfg = Release|Win32 + {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.Build.0 = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.Build.0 = Debug|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.ActiveCfg = Debug|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.Build.0 = Debug|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.ActiveCfg = Release|ARM {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.Build.0 = Release|ARM + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.ActiveCfg = Release|Win32 + {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.Build.0 = Release|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.ActiveCfg = Release|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.Build.0 = Release|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.ActiveCfg = Debug|ARM {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.Build.0 = Debug|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.ActiveCfg = Debug|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.Build.0 = Debug|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.ActiveCfg = Debug|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.Build.0 = Debug|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.ActiveCfg = Release|ARM {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.Build.0 = Release|ARM + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.ActiveCfg = Release|Win32 + {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.Build.0 = Release|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.ActiveCfg = Release|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.Build.0 = Release|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.ActiveCfg = Debug|ARM {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.Build.0 = Debug|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.Build.0 = Debug|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.ActiveCfg = Debug|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.Build.0 = Debug|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.ActiveCfg = Release|ARM {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.Build.0 = Release|ARM + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.ActiveCfg = Release|Win32 + {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.Build.0 = Release|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.ActiveCfg = Debug|ARM {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.Build.0 = Debug|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.ActiveCfg = Debug|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.Build.0 = Debug|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.ActiveCfg = Debug|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.Build.0 = Debug|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.ActiveCfg = Release|ARM {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.Build.0 = Release|ARM + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.ActiveCfg = Release|Win32 + {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.Build.0 = Release|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.ActiveCfg = Release|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.Build.0 = Release|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.ActiveCfg = Debug|ARM {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.Build.0 = Debug|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.ActiveCfg = Debug|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.Build.0 = Debug|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.ActiveCfg = Debug|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.Build.0 = Debug|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.ActiveCfg = Release|ARM {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.Build.0 = Release|ARM + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.ActiveCfg = Release|Win32 + {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.Build.0 = Release|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.ActiveCfg = Release|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.Build.0 = Release|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.ActiveCfg = Debug|ARM {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.Build.0 = Debug|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.ActiveCfg = Debug|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.Build.0 = Debug|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.ActiveCfg = Debug|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.Build.0 = Debug|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.ActiveCfg = Release|ARM {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.Build.0 = Release|ARM + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.ActiveCfg = Release|Win32 + {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.Build.0 = Release|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.ActiveCfg = Release|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.Build.0 = Release|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.ActiveCfg = Debug|ARM {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.Build.0 = Debug|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.ActiveCfg = Debug|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.Build.0 = Debug|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.ActiveCfg = Debug|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.Build.0 = Debug|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.ActiveCfg = Release|ARM {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.Build.0 = Release|ARM + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.ActiveCfg = Release|Win32 + {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.Build.0 = Release|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32 + {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.ActiveCfg = Debug|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.Build.0 = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.ActiveCfg = Release|Win32 + {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.Build.0 = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.Build.0 = Debug|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.ActiveCfg = Debug|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.Build.0 = Debug|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.ActiveCfg = Release|Win32 + {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.Build.0 = Release|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.ActiveCfg = Release|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.ActiveCfg = Debug|ARM {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.Build.0 = Debug|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|Win32.ActiveCfg = Debug|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|Win32.Build.0 = Debug|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.ActiveCfg = Debug|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.Build.0 = Debug|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.ActiveCfg = Release|ARM {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.Build.0 = Release|ARM + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|Win32.ActiveCfg = Release|Win32 + {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|Win32.Build.0 = Release|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.ActiveCfg = Release|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.Build.0 = Release|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.ActiveCfg = Debug|ARM {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.Build.0 = Debug|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|Win32.ActiveCfg = Debug|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|Win32.Build.0 = Debug|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.ActiveCfg = Debug|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.Build.0 = Debug|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.ActiveCfg = Release|ARM {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.Build.0 = Release|ARM + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|Win32.ActiveCfg = Release|Win32 + {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|Win32.Build.0 = Release|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.ActiveCfg = Release|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.Build.0 = Release|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.ActiveCfg = Debug|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.Build.0 = Debug|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|Win32.ActiveCfg = Debug|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|Win32.Build.0 = Debug|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.ActiveCfg = Debug|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.Build.0 = Debug|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.ActiveCfg = Release|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.Build.0 = Release|ARM + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|Win32.ActiveCfg = Release|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|Win32.Build.0 = Release|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.ActiveCfg = Release|Win32 + {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.Build.0 = Release|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.ActiveCfg = Debug|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.Build.0 = Debug|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|Win32.ActiveCfg = Debug|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|Win32.Build.0 = Debug|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.ActiveCfg = Debug|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.Build.0 = Debug|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.ActiveCfg = Release|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.Build.0 = Release|ARM + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|Win32.ActiveCfg = Release|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|Win32.Build.0 = Release|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.ActiveCfg = Release|Win32 + {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.Build.0 = Release|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.ActiveCfg = Debug|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.Build.0 = Debug|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|Win32.ActiveCfg = Debug|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|Win32.Build.0 = Debug|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.ActiveCfg = Debug|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.Build.0 = Debug|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.ActiveCfg = Release|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.Build.0 = Release|ARM + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|Win32.ActiveCfg = Release|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|Win32.Build.0 = Release|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.ActiveCfg = Release|Win32 + {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tester/message_tester.c b/tester/message_tester.c index bb18b1931..85b5f2e00 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -121,13 +121,13 @@ void file_transfer_progress_indication(LinphoneCore *lc, LinphoneChatMessage *me const LinphoneAddress* from_address = linphone_chat_message_get_from(message); const LinphoneAddress* to_address = linphone_chat_message_get_to(message); char *address = linphone_chat_message_is_outgoing(message)?linphone_address_as_string(to_address):linphone_address_as_string(from_address); + stats* counters = get_stats(lc); printf(" File transfer [%d%%] %s of type [%s/%s] %s [%s] \n", (int)progress ,(linphone_chat_message_is_outgoing(message)?"sent":"received") , content->type , content->subtype ,(linphone_chat_message_is_outgoing(message)?"to":"from") , address); - stats* counters = get_stats(lc); counters->progress_of_LinphoneFileTransfer = progress; free(address); } From 5d7ef300435e125c2f846e2bec3ac06ae8bb3f63 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 26 Jun 2014 15:43:52 +0200 Subject: [PATCH 171/201] fix compilation problem on mingw --- tester/stun_tester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tester/stun_tester.c b/tester/stun_tester.c index d19650f06..99b1190ed 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -61,7 +61,7 @@ static void linphone_stun_test_encode() len = test_stun_encode(bigBuff, bigLen, TRUE); CU_ASSERT(len > 0); - ms_message("STUN message encoded in %zu bytes", len); + ms_message("STUN message encoded in %i bytes", (int)len); } From 5189503d3d39692b7f47485d23a58a51c977d59f Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 26 Jun 2014 15:48:13 +0200 Subject: [PATCH 172/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d53acb177..8009a7440 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d53acb177a5be59cbd7e277f6358d339670b2dd1 +Subproject commit 8009a7440d296621f2074642394effabe442b028 From 0441c7c3204060a2daa1dd6304162b721ddfc851 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Thu, 26 Jun 2014 16:16:32 +0200 Subject: [PATCH 173/201] Quality reporting: use moscq/moslq from quality indicator for local value --- coreapi/quality_reporting.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index f4ba1260f..73de2d922 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -132,11 +132,12 @@ static uint8_t are_metrics_filled(const reporting_content_metrics_t rm) { if (rm.signal.level != 127) ret|=METRICS_SIGNAL; if (rm.signal.noise_level != 127) ret|=METRICS_SIGNAL; + IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); + if (rm.rtcp_xr_count>0){ IF_NUM_IN_RANGE(rm.jitter_buffer.nominal/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); IF_NUM_IN_RANGE(rm.jitter_buffer.max/rm.rtcp_xr_count, 0, 65535, ret|=METRICS_JITTER_BUFFER); - IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); - IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, ret|=METRICS_QUALITY_ESTIMATES); } if (rm.rtcp_sr_count+rm.rtcp_xr_count>0){ IF_NUM_IN_RANGE(rm.delay.round_trip_delay/(rm.rtcp_sr_count+rm.rtcp_xr_count), 0, 65535, ret|=METRICS_DELAY); @@ -231,8 +232,8 @@ static void append_metrics_to_buffer(char ** buffer, size_t * size, size_t * off /*if quality estimates metrics are available, rtcp_xr_count should be always not null*/ if ((available_metrics & METRICS_QUALITY_ESTIMATES) != 0){ - IF_NUM_IN_RANGE(rm.quality_estimates.moslq/rm.rtcp_xr_count, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq/rm.rtcp_xr_count)); - IF_NUM_IN_RANGE(rm.quality_estimates.moscq/rm.rtcp_xr_count, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq/rm.rtcp_xr_count)); + IF_NUM_IN_RANGE(rm.quality_estimates.moslq, 1, 5, moslq_str = float_to_one_decimal_string(rm.quality_estimates.moslq)); + IF_NUM_IN_RANGE(rm.quality_estimates.moscq, 1, 5, moscq_str = float_to_one_decimal_string(rm.quality_estimates.moscq)); append_to_buffer(buffer, size, offset, "\r\nQualityEst:"); APPEND_IF_NOT_NULL_STR(buffer, size, offset, " MOSLQ=%s", moslq_str); @@ -477,6 +478,7 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { report->remote_metrics.timestamps.start = call->log->start_date_time; report->remote_metrics.timestamps.stop = call->log->start_date_time + linphone_call_get_duration(call); + /*yet we use the same payload config for local and remote, since this is the largest use case*/ if (stats_type == LINPHONE_CALL_STATS_AUDIO && call->audiostream != NULL) { stream = &call->audiostream->ms; @@ -493,6 +495,11 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { report->info.local_addr.ssrc = rtp_session_get_send_ssrc(session); report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); + + if (stream->qi != NULL){ + report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(stream->qi); + report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(stream->qi); + } } STR_REASSIGN(report->dialog_id, ms_strdup_printf("%s;%u", dialog_id, report->info.local_addr.ssrc)); @@ -545,10 +552,14 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, int stats_type) { metrics->rtcp_xr_count++; - metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(block)==127) ? - 127 : metrics->quality_estimates.moslq + rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; - metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(block)==127) ? - 127 : metrics->quality_estimates.moscq + rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + // for local mos rating, we'll use the quality indicator directly + // because rtcp XR might not be enabled + if (stats.updated == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE){ + metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(block)==127) ? + 127 : rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; + metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(block)==127) ? + 127 : rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + } metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block); metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block); From 93a0794c39af89b3f13c36d249b03e335ea9f3dc Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 26 Jun 2014 17:32:37 +0200 Subject: [PATCH 174/201] fix remote user-agent not set correctly in case of call forking --- coreapi/bellesip_sal/sal_impl.c | 5 ++--- mediastreamer2 | 2 +- oRTP | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index daf746c79..9693226dd 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -323,9 +323,8 @@ static void process_response_event(void *user_ctx, const belle_sip_response_even belle_sip_message("Op is terminated, nothing to do with this [%i]",response_code); return; } - if (!op->base.remote_ua) { - sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); - } + /*do it all the time, since we can receive provisional responses from a different instance than the final one*/ + sal_op_set_remote_ua(op,BELLE_SIP_MESSAGE(response)); if(remote_contact) { __sal_op_set_remote_contact(op, belle_sip_header_get_unparsed_value(BELLE_SIP_HEADER(remote_contact))); diff --git a/mediastreamer2 b/mediastreamer2 index 8009a7440..b0e768db7 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 8009a7440d296621f2074642394effabe442b028 +Subproject commit b0e768db74b5944de8ec606e2d70744dc124cb70 diff --git a/oRTP b/oRTP index 43a9185fe..9d03c3aa1 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 43a9185fe6baab7a009f730f123f1de07555f5fe +Subproject commit 9d03c3aa1643f1cfae32de4abf04dc84ff3ad175 From fd22b3631e23d24474cac5d6c1e31e4d1b62ba67 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jun 2014 17:56:40 +0200 Subject: [PATCH 175/201] Add reference to mswebrtc in the Windows Phone 8 project. --- build/wp8/LibLinphone.vcxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/wp8/LibLinphone.vcxproj b/build/wp8/LibLinphone.vcxproj index 3ae118ae8..ed1e7e847 100644 --- a/build/wp8/LibLinphone.vcxproj +++ b/build/wp8/LibLinphone.vcxproj @@ -180,6 +180,9 @@ {d22bd217-d0f8-4274-9b3a-f3f35f46482c} + + {b16b81a9-bef2-44c9-b603-1065183ae844} + {0565952a-ea62-46a2-8261-f5b4b490da42} From 2552449faca85c16a7799d2854e3f98af426287f Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 26 Jun 2014 18:08:51 +0200 Subject: [PATCH 176/201] Add opus on Windows Phone 8. --- .../LibLinphoneTester-wp8.sln | 122 ++---------------- mediastreamer2 | 2 +- 2 files changed, 11 insertions(+), 113 deletions(-) diff --git a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index dc0ab0ae2..3e8ba7bb3 100644 --- a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -91,346 +91,244 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcisac", "..\..\..\..\m EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsbcg729", "..\..\..\..\bcg729\build\wp8\bcg729\bcg729.vcxproj", "{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opus", "..\..\..\..\opus\build\wp8\opus\opus.vcxproj", "{D450EC75-DF02-48B0-A4FB-ACA79BD894AB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM - Debug|Win32 = Debug|Win32 Debug|x86 = Debug|x86 Release|ARM = Release|ARM - Release|Win32 = Release|Win32 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.ActiveCfg = Debug|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Build.0 = Debug|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|ARM.Deploy.0 = Debug|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.ActiveCfg = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Build.0 = Debug|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|Win32.Deploy.0 = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.ActiveCfg = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Build.0 = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Debug|x86.Deploy.0 = Debug|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.ActiveCfg = Release|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Build.0 = Release|ARM {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|ARM.Deploy.0 = Release|ARM - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.ActiveCfg = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Build.0 = Release|x86 - {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|Win32.Deploy.0 = Release|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.ActiveCfg = Release|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Build.0 = Release|x86 {34D6878F-6CAB-4AE3-9CCC-25E8D6734C90}.Release|x86.Deploy.0 = Release|x86 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.ActiveCfg = Debug|ARM {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|ARM.Build.0 = Debug|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.ActiveCfg = Debug|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|Win32.Build.0 = Debug|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.ActiveCfg = Debug|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Debug|x86.Build.0 = Debug|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.ActiveCfg = Release|ARM {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|ARM.Build.0 = Release|ARM - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.ActiveCfg = Release|Win32 - {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|Win32.Build.0 = Release|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.ActiveCfg = Release|Win32 {08DD0D38-D9B5-4626-B60D-B4D76B571142}.Release|x86.Build.0 = Release|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.ActiveCfg = Debug|ARM {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|ARM.Build.0 = Debug|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.ActiveCfg = Debug|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|Win32.Build.0 = Debug|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.ActiveCfg = Debug|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Debug|x86.Build.0 = Debug|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.ActiveCfg = Release|ARM {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|ARM.Build.0 = Release|ARM - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.ActiveCfg = Release|Win32 - {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|Win32.Build.0 = Release|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.ActiveCfg = Release|Win32 {5E94A00B-B14A-4E42-8284-8CB0EF099534}.Release|x86.Build.0 = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.ActiveCfg = Debug|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.Build.0 = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.ActiveCfg = Release|Win32 - {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.Build.0 = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.ActiveCfg = Debug|ARM {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|ARM.Build.0 = Debug|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.ActiveCfg = Debug|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|Win32.Build.0 = Debug|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.ActiveCfg = Debug|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Debug|x86.Build.0 = Debug|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.ActiveCfg = Release|ARM {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|ARM.Build.0 = Release|ARM - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.ActiveCfg = Release|Win32 - {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|Win32.Build.0 = Release|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.ActiveCfg = Release|Win32 {027BAD0E-9179-48C1-9733-7AA7E2C2EC70}.Release|x86.Build.0 = Release|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.ActiveCfg = Debug|ARM {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|ARM.Build.0 = Debug|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.ActiveCfg = Debug|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|Win32.Build.0 = Debug|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.ActiveCfg = Debug|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Debug|x86.Build.0 = Debug|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.ActiveCfg = Release|ARM {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|ARM.Build.0 = Release|ARM - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.ActiveCfg = Release|Win32 - {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|Win32.Build.0 = Release|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.ActiveCfg = Release|Win32 {FFC7B532-0502-4D88-AC98-9E89071CBC97}.Release|x86.Build.0 = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.ActiveCfg = Debug|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.Build.0 = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.ActiveCfg = Release|Win32 - {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.Build.0 = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.ActiveCfg = Debug|ARM {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|ARM.Build.0 = Debug|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.ActiveCfg = Debug|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|Win32.Build.0 = Debug|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.ActiveCfg = Debug|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Debug|x86.Build.0 = Debug|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.ActiveCfg = Release|ARM {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|ARM.Build.0 = Release|ARM - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.ActiveCfg = Release|Win32 - {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|Win32.Build.0 = Release|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.ActiveCfg = Release|Win32 {746EA080-5BA9-42C5-9E52-EA421C3F3AFD}.Release|x86.Build.0 = Release|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.ActiveCfg = Debug|ARM {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|ARM.Build.0 = Debug|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.ActiveCfg = Debug|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|Win32.Build.0 = Debug|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.ActiveCfg = Debug|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Debug|x86.Build.0 = Debug|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.ActiveCfg = Release|ARM {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|ARM.Build.0 = Release|ARM - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.ActiveCfg = Release|Win32 - {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|Win32.Build.0 = Release|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.ActiveCfg = Release|Win32 {D5EC8C11-C1D9-47E3-BB82-A93C300FD902}.Release|x86.Build.0 = Release|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.ActiveCfg = Debug|ARM {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|ARM.Build.0 = Debug|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.ActiveCfg = Debug|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|Win32.Build.0 = Debug|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.ActiveCfg = Debug|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Debug|x86.Build.0 = Debug|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.ActiveCfg = Release|ARM {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|ARM.Build.0 = Release|ARM - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.ActiveCfg = Release|Win32 - {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|Win32.Build.0 = Release|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.ActiveCfg = Release|Win32 {6BD78980-9C71-4341-8775-AD19E9EC7305}.Release|x86.Build.0 = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.ActiveCfg = Debug|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|Win32.Build.0 = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.ActiveCfg = Release|Win32 - {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|Win32.Build.0 = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.ActiveCfg = Debug|ARM {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|ARM.Build.0 = Debug|ARM - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.ActiveCfg = Debug|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|Win32.Build.0 = Debug|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.ActiveCfg = Debug|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Debug|x86.Build.0 = Debug|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.ActiveCfg = Release|ARM {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|ARM.Build.0 = Release|ARM - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.ActiveCfg = Release|Win32 - {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|Win32.Build.0 = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.ActiveCfg = Release|Win32 {D22BD217-D0F8-4274-9B3A-F3F35F46482C}.Release|x86.Build.0 = Release|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.ActiveCfg = Debug|ARM {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|ARM.Build.0 = Debug|ARM - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.ActiveCfg = Debug|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|Win32.Build.0 = Debug|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.ActiveCfg = Debug|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Debug|x86.Build.0 = Debug|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.ActiveCfg = Release|ARM {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|ARM.Build.0 = Release|ARM - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.ActiveCfg = Release|Win32 - {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|Win32.Build.0 = Release|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.ActiveCfg = Release|Win32 {8E216BF3-2DD8-4794-8E97-B1AED301ED4D}.Release|x86.Build.0 = Release|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.ActiveCfg = Debug|ARM {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|ARM.Build.0 = Debug|ARM - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.ActiveCfg = Debug|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|Win32.Build.0 = Debug|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.ActiveCfg = Debug|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Debug|x86.Build.0 = Debug|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.ActiveCfg = Release|ARM {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|ARM.Build.0 = Release|ARM - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.ActiveCfg = Release|Win32 - {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|Win32.Build.0 = Release|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.ActiveCfg = Release|Win32 {072FAD20-7007-4DA2-B2E7-16CE2B219F67}.Release|x86.Build.0 = Release|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.ActiveCfg = Debug|ARM {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|ARM.Build.0 = Debug|ARM - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.ActiveCfg = Debug|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|Win32.Build.0 = Debug|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.ActiveCfg = Debug|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Debug|x86.Build.0 = Debug|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.ActiveCfg = Release|ARM {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|ARM.Build.0 = Release|ARM - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.ActiveCfg = Release|Win32 - {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|Win32.Build.0 = Release|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.ActiveCfg = Release|Win32 {36B528F9-FB79-4078-A16B-0A7442581BB7}.Release|x86.Build.0 = Release|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.ActiveCfg = Debug|ARM {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|ARM.Build.0 = Debug|ARM - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.ActiveCfg = Debug|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|Win32.Build.0 = Debug|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.ActiveCfg = Debug|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Debug|x86.Build.0 = Debug|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.ActiveCfg = Release|ARM {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|ARM.Build.0 = Release|ARM - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.ActiveCfg = Release|Win32 - {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|Win32.Build.0 = Release|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.ActiveCfg = Release|Win32 {9924AC72-F96C-4E56-94D9-2B025DA43C6B}.Release|x86.Build.0 = Release|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.ActiveCfg = Debug|ARM {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|ARM.Build.0 = Debug|ARM - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.ActiveCfg = Debug|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|Win32.Build.0 = Debug|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.ActiveCfg = Debug|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Debug|x86.Build.0 = Debug|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.ActiveCfg = Release|ARM {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|ARM.Build.0 = Release|ARM - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.ActiveCfg = Release|Win32 - {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|Win32.Build.0 = Release|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.ActiveCfg = Release|Win32 {018A4428-535C-4566-9AE0-E93AFF0D3ED2}.Release|x86.Build.0 = Release|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.ActiveCfg = Debug|ARM {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|ARM.Build.0 = Debug|ARM - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.ActiveCfg = Debug|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|Win32.Build.0 = Debug|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.ActiveCfg = Debug|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Debug|x86.Build.0 = Debug|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.ActiveCfg = Release|ARM {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|ARM.Build.0 = Release|ARM - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.ActiveCfg = Release|Win32 - {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|Win32.Build.0 = Release|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.ActiveCfg = Release|Win32 {88191E75-2993-48D7-AA76-652F274EF0FE}.Release|x86.Build.0 = Release|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.ActiveCfg = Debug|ARM {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|ARM.Build.0 = Debug|ARM - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.ActiveCfg = Debug|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|Win32.Build.0 = Debug|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.ActiveCfg = Debug|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Debug|x86.Build.0 = Debug|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.ActiveCfg = Release|ARM {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|ARM.Build.0 = Release|ARM - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.ActiveCfg = Release|Win32 - {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|Win32.Build.0 = Release|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.ActiveCfg = Release|Win32 {7AC65D2A-6981-4D17-856D-C37A522739D8}.Release|x86.Build.0 = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32 - {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.ActiveCfg = Debug|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.Build.0 = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.ActiveCfg = Release|Win32 - {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.Build.0 = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.ActiveCfg = Debug|ARM {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|ARM.Build.0 = Debug|ARM - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.ActiveCfg = Debug|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|Win32.Build.0 = Debug|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.ActiveCfg = Debug|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Debug|x86.Build.0 = Debug|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.ActiveCfg = Release|ARM {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|ARM.Build.0 = Release|ARM - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.ActiveCfg = Release|Win32 - {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|Win32.Build.0 = Release|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.ActiveCfg = Release|Win32 {5DFA07B4-0BE9-46A9-BA32-FDF5A55C580B}.Release|x86.Build.0 = Release|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.ActiveCfg = Debug|ARM {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|ARM.Build.0 = Debug|ARM - {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|Win32.ActiveCfg = Debug|Win32 - {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|Win32.Build.0 = Debug|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.ActiveCfg = Debug|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Debug|x86.Build.0 = Debug|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.ActiveCfg = Release|ARM {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|ARM.Build.0 = Release|ARM - {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|Win32.ActiveCfg = Release|Win32 - {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|Win32.Build.0 = Release|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.ActiveCfg = Release|Win32 {B4B96BC4-2B72-4964-98E4-7FD048A43363}.Release|x86.Build.0 = Release|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.ActiveCfg = Debug|ARM {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|ARM.Build.0 = Debug|ARM - {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|Win32.ActiveCfg = Debug|Win32 - {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|Win32.Build.0 = Debug|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.ActiveCfg = Debug|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Debug|x86.Build.0 = Debug|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.ActiveCfg = Release|ARM {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|ARM.Build.0 = Release|ARM - {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|Win32.ActiveCfg = Release|Win32 - {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|Win32.Build.0 = Release|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.ActiveCfg = Release|Win32 {0565952A-EA62-46A2-8261-F5B4B490DA42}.Release|x86.Build.0 = Release|Win32 {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.ActiveCfg = Debug|ARM {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|ARM.Build.0 = Debug|ARM - {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|Win32.ActiveCfg = Debug|Win32 - {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|Win32.Build.0 = Debug|Win32 {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.ActiveCfg = Debug|Win32 {B16B81A9-BEF2-44C9-B603-1065183AE844}.Debug|x86.Build.0 = Debug|Win32 {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.ActiveCfg = Release|ARM {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|ARM.Build.0 = Release|ARM - {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|Win32.ActiveCfg = Release|Win32 - {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|Win32.Build.0 = Release|Win32 {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.ActiveCfg = Release|Win32 {B16B81A9-BEF2-44C9-B603-1065183AE844}.Release|x86.Build.0 = Release|Win32 {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.ActiveCfg = Debug|ARM {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|ARM.Build.0 = Debug|ARM - {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|Win32.ActiveCfg = Debug|Win32 - {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|Win32.Build.0 = Debug|Win32 {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.ActiveCfg = Debug|Win32 {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Debug|x86.Build.0 = Debug|Win32 {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.ActiveCfg = Release|ARM {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|ARM.Build.0 = Release|ARM - {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|Win32.ActiveCfg = Release|Win32 - {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|Win32.Build.0 = Release|Win32 {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.ActiveCfg = Release|Win32 {A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}.Release|x86.Build.0 = Release|Win32 {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.ActiveCfg = Debug|ARM {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|ARM.Build.0 = Debug|ARM - {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|Win32.ActiveCfg = Debug|Win32 - {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|Win32.Build.0 = Debug|Win32 {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.ActiveCfg = Debug|Win32 {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Debug|x86.Build.0 = Debug|Win32 {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.ActiveCfg = Release|ARM {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|ARM.Build.0 = Release|ARM - {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|Win32.ActiveCfg = Release|Win32 - {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|Win32.Build.0 = Release|Win32 {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.ActiveCfg = Release|Win32 {1DB09AFE-FC9B-472E-A746-0E33F8EF8883}.Release|x86.Build.0 = Release|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|ARM.ActiveCfg = Debug|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|ARM.Build.0 = Debug|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|x86.ActiveCfg = Debug|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Debug|x86.Build.0 = Debug|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|ARM.ActiveCfg = Release|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|ARM.Build.0 = Release|ARM + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|x86.ActiveCfg = Release|Win32 + {D450EC75-DF02-48B0-A4FB-ACA79BD894AB}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/mediastreamer2 b/mediastreamer2 index b0e768db7..bcb80cd10 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit b0e768db74b5944de8ec606e2d70744dc124cb70 +Subproject commit bcb80cd105e3fe4c96a66ab4b80b87a92dcb21c7 From cfe31b55b0310e16ec428d129015e962eb2d2dfa Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 27 Jun 2014 11:57:02 +0200 Subject: [PATCH 177/201] fix local moslq/moscq interval for quality reporting from (0..5) to (1..5) --- coreapi/quality_reporting.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 73de2d922..176cf02df 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -497,8 +497,10 @@ void linphone_reporting_update_media_info(LinphoneCall * call, int stats_type) { report->info.remote_addr.ssrc = rtp_session_get_recv_ssrc(session); if (stream->qi != NULL){ - report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(stream->qi); - report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(stream->qi); + report->local_metrics.quality_estimates.moslq = ms_quality_indicator_get_average_lq_rating(stream->qi) >= 0 ? + MAX(1, ms_quality_indicator_get_average_lq_rating(stream->qi)) : -1; + report->local_metrics.quality_estimates.moscq = ms_quality_indicator_get_average_rating(stream->qi) >= 0 ? + MAX(1, ms_quality_indicator_get_average_rating(stream->qi)) : -1; } } From 09478ccdc99bf4d85182a994cb34e21d48a1d116 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Fri, 27 Jun 2014 16:26:29 +0200 Subject: [PATCH 178/201] Quality report: add audio/video bitrate and upload/download rates on report too --- coreapi/quality_reporting.c | 55 +++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 176cf02df..f5dd852f4 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -405,19 +405,51 @@ static void update_ip(LinphoneCall * call, int stats_type) { } } -static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** data){ - reporting_session_report_t *report = (reporting_session_report_t*) user_data; +typedef struct on_action_suggested_struct{ + LinphoneCall *call; + int stats_type; +}on_action_suggested_struct_t; + +static void qos_analyzer_on_action_suggested(void *user_data, int datac, const char** datav){ + on_action_suggested_struct_t * oass = (on_action_suggested_struct_t *)user_data; + LinphoneCall *call = oass->call; + reporting_session_report_t *report = call->log->reporting.reports[oass->stats_type]; char * appendbuf; + int i; + int ptime = -1; + int bitrate[2] = {-1, -1}; + int up_bw[2] = {-1, -1}; + int down_bw[2] = {-1, -1}; + MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; + for (i=0;i<2;i++){ + if (streams[i]!=NULL){ + if (streams[i]->encoder!=NULL){ + if (ms_filter_has_method(streams[i]->encoder,MS_FILTER_GET_BITRATE)){ + ms_filter_call_method(streams[i]->encoder,MS_FILTER_GET_BITRATE,&bitrate[i]); + bitrate[i] /= 1000.f; + } + } + up_bw[i] = media_stream_get_up_bw(streams[i])/1000.f; + down_bw[i] = media_stream_get_down_bw(streams[i])/1000.f; + } + } + if (call->audiostream!=NULL){ + if (call->audiostream->ms.encoder!=NULL){ + if(ms_filter_has_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME)){ + ms_filter_call_method(call->audiostream->ms.encoder,MS_AUDIO_ENCODER_GET_PTIME,&ptime); + } + } + } appendbuf=ms_strdup_printf("%s%d;", report->qos_analyzer.timestamp?report->qos_analyzer.timestamp:"", ms_time(0)); STR_REASSIGN(report->qos_analyzer.timestamp,appendbuf); - STR_REASSIGN(report->qos_analyzer.input_leg, ms_strdup(data[0])); - appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.input?report->qos_analyzer.input:"", data[1]); + STR_REASSIGN(report->qos_analyzer.input_leg, ms_strdup_printf("%s aenc_ptime aenc_br a_dbw a_ubw venc_br v_dbw v_ubw", datav[0])); + appendbuf=ms_strdup_printf("%s%s %d %d %d %d %d %d %d;", report->qos_analyzer.input?report->qos_analyzer.input:"", datav[1], + ptime, bitrate[0], down_bw[0], up_bw[0], bitrate[1], down_bw[1], up_bw[1] ); STR_REASSIGN(report->qos_analyzer.input,appendbuf); - - STR_REASSIGN(report->qos_analyzer.output_leg, ms_strdup(data[2])); - appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.output?report->qos_analyzer.output:"", data[3]); + STR_REASSIGN(report->qos_analyzer.output_leg, ms_strdup(datav[2])); + appendbuf=ms_strdup_printf("%s%s;", report->qos_analyzer.output?report->qos_analyzer.output:"", datav[3]); STR_REASSIGN(report->qos_analyzer.output, appendbuf); } @@ -632,6 +664,7 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ MediaStream *streams[2] = {(MediaStream*) call->audiostream, (MediaStream *) call->videostream}; MSQosAnalyzer *analyzer; for (i=0;i<2;i++){ + if (streams[i]==NULL||streams[i]->rc==NULL){ ms_message("QualityReporting[%p] Cannot set on_action_suggested" " callback for %s stream because something is null", call, i?"video":"audio"); @@ -640,10 +673,16 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ analyzer=ms_bitrate_controller_get_qos_analyzer(streams[i]->rc); if (analyzer){ + on_action_suggested_struct_t * oass = ms_new0(on_action_suggested_struct_t, 1); + oass->call = call; + oass->stats_type = i; STR_REASSIGN(call->log->reporting.reports[i]->qos_analyzer.name, ms_strdup(ms_qos_analyzer_get_name(analyzer))); + + // /!\ only us use this callback so we can free user_data from here + ms_free(analyzer->on_action_suggested_user_pointer); ms_qos_analyzer_set_on_action_suggested(analyzer, qos_analyzer_on_action_suggested, - call->log->reporting.reports[i]); + oass); } } linphone_reporting_update_ip(call); From 7cd96d33badf38269ad348dc7915371691598dcf Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 27 Jun 2014 17:13:17 +0200 Subject: [PATCH 179/201] fix git version checking when not in a git tree add linphone_proxy_config_pause_register() make linphone_core_remove_proxy_config() really send unregister. --- coreapi/Makefile.am | 22 ++++++++++++++-------- coreapi/linphonecore.h | 1 + coreapi/proxy.c | 18 ++++++++++++++++-- mediastreamer2 | 2 +- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index e2db1d2c1..8a3b62daf 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -91,7 +91,7 @@ if HAVE_LD_OUTPUT_DEF liblinphone_la_LDFLAGS += -Wl,--output-def,liblinphone-$(LIBLINPHONE_SO_CURRENT).def defexecdir = $(libdir) defexec_DATA = liblinphone-$(LIBLINPHONE_SO_CURRENT).def -CLEANFILES = $(defexec_DATA) +CLEANFILES += $(defexec_DATA) liblinphone-$(LIBLINPHONE_SO_CURRENT).def: liblinphone.la @@ -156,15 +156,21 @@ AM_CFLAGS+= -DUSE_BELLESIP AM_CXXFLAGS=$(AM_CFLAGS) +#Make sure that we are in linphone's git tree by doing git log $(top_srcdir)/configure.ac. +#if it is something known to git, then that will be ok to check the git describe number and make sure it is consistent with +#the PACKAGE_VERSION given in configure.ac + make_gitversion_h: - if test "$(GITDESCRIBE)" != "" ; then \ - if test "$(GIT_TAG)" != "$(PACKAGE_VERSION)" ; then \ - echo "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \ - exit 1; \ + if test -d $(top_srcdir)/.git ; then \ + if test "$(GITDESCRIBE)" != "" ; then \ + if test "$(GIT_TAG)" != "$(PACKAGE_VERSION)" ; then \ + echo "*** PACKAGE_VERSION and git tag differ. Please put them identical."; \ + exit 1; \ + fi ; \ + $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \ + elif test "$(GITREVISION)" != "" ; then \ + $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \ fi ; \ - $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \ - elif test "$(GITREVISION)" != "" ; then \ - $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \ else \ $(ECHO) -n "" > $(GITVERSION_FILE_TMP) ; \ fi diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 05776a89d..825a41697 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -908,6 +908,7 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_addr(const LinphoneProxyCo LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj); +LINPHONE_PUBLIC void linphone_proxy_config_pause_register(LinphoneProxyConfig *obj); LINPHONE_PUBLIC const char *linphone_proxy_config_get_contact_parameters(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC void linphone_proxy_config_set_contact_parameters(LinphoneProxyConfig *obj, const char *contact_params); LINPHONE_PUBLIC void linphone_proxy_config_set_contact_uri_parameters(LinphoneProxyConfig *obj, const char *contact_uri_params); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 201035606..ad7234a7b 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -307,6 +307,19 @@ void linphone_proxy_config_set_expires(LinphoneProxyConfig *obj, int val){ void linphone_proxy_config_enable_publish(LinphoneProxyConfig *obj, bool_t val){ obj->publish=val; } + +/** + * Prevent a proxy config from refreshing its registration. + * This is useful to let registrations to expire naturally (or) when the application wants to keep control on when + * refreshes are sent. + * However, linphone_core_set_network_reachable(lc,TRUE) will always request the proxy configs to refresh their registrations. + * The refreshing operations can be resumed with linphone_proxy_config_refresh_register(). + * @param obj the proxy config +**/ +void linphone_proxy_config_pause_register(LinphoneProxyConfig *obj){ + if (obj->op) sal_op_stop_refreshing(obj->op); +} + /** * Starts editing a proxy configuration. * @@ -327,7 +340,7 @@ void linphone_proxy_config_edit(LinphoneProxyConfig *obj){ linphone_proxy_config_store_server_config(obj); /*stop refresher in any case*/ - if (obj->op) sal_op_stop_refreshing(obj->op); + linphone_proxy_config_pause_register(obj); } void linphone_proxy_config_apply(LinphoneProxyConfig *obj,LinphoneCore *lc){ @@ -1090,7 +1103,7 @@ int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){ /* check this proxy config is in the list before doing more*/ if (ms_list_find(lc->sip_conf.proxies,cfg)==NULL){ - ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig %p is not known by LinphoneCore (programming error?)",cfg); + ms_error("linphone_core_remove_proxy_config: LinphoneProxyConfig [%p] is not known by LinphoneCore (programming error?)",cfg); return; } lc->sip_conf.proxies=ms_list_remove(lc->sip_conf.proxies,cfg); @@ -1102,6 +1115,7 @@ void linphone_core_remove_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cf linphone_proxy_config_edit(cfg); linphone_proxy_config_enable_register(cfg,FALSE); linphone_proxy_config_done(cfg); + linphone_proxy_config_update(cfg); /*so that it has an effect*/ } if (lc->default_proxy==cfg){ lc->default_proxy=NULL; diff --git a/mediastreamer2 b/mediastreamer2 index bcb80cd10..71bce450a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit bcb80cd105e3fe4c96a66ab4b80b87a92dcb21c7 +Subproject commit 71bce450a360361039cfdf1967095bcd2a842af3 From 3d925e71632b87b17667060f8c52f31d0903b259 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Fri, 27 Jun 2014 17:57:52 +0200 Subject: [PATCH 180/201] webrtcisac has been renamed to webrtc. --- build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln | 2 +- coreapi/linphonecall.c | 2 +- mediastreamer2 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln index 3e8ba7bb3..cf0d4a086 100644 --- a/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln +++ b/build/wp8/LibLinphoneTester-wp8/LibLinphoneTester-wp8.sln @@ -87,7 +87,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswp8vid", "..\..\..\..\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmswebrtc", "..\..\..\..\mswebrtc\build\wp8\mswebrtc\mswebrtc.vcxproj", "{B16B81A9-BEF2-44C9-B603-1065183AE844}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtcisac", "..\..\..\..\mswebrtc\webrtc\build\wp8\webrtcisac\webrtcisac.vcxproj", "{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webrtc", "..\..\..\..\mswebrtc\webrtc\build\wp8\webrtc\webrtc.vcxproj", "{A5A719E5-FDD6-4DFD-AAF6-68C9534B5562}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmsbcg729", "..\..\..\..\bcg729\build\wp8\bcg729\bcg729.vcxproj", "{1DB09AFE-FC9B-472E-A746-0E33F8EF8883}" EndProject diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4e4babcbc..e5dfbed58 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -3099,7 +3099,7 @@ static LinphoneAddress *get_fixed_contact(LinphoneCore *lc, LinphoneCall *call , } else { ctt=linphone_core_get_primary_contact_parsed(lc); if (ctt!=NULL){ - /*otherwise use supllied localip*/ + /*otherwise use supplied localip*/ linphone_address_set_domain(ctt,localip); linphone_address_set_port(ctt,linphone_core_get_sip_port(lc)); ms_message("Contact has been fixed using local ip"/* to %s",ret*/); diff --git a/mediastreamer2 b/mediastreamer2 index 71bce450a..185eae373 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 71bce450a360361039cfdf1967095bcd2a842af3 +Subproject commit 185eae3737b6956667f022d68dadeca9eae2a706 From 191d7f5e91510ba26e25326fd20b2954012b8c35 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 27 Jun 2014 19:04:56 +0200 Subject: [PATCH 181/201] Fix linphone_core_lookup_known_proxy to search for registered proxy configs instead of just registrable. Unit test attached. --- coreapi/linphonecore.c | 13 +++-- tester/call_tester.c | 120 +++++++++++++++++++++++++++-------------- 2 files changed, 88 insertions(+), 45 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1a7c1d5e1..0b49be7cc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2570,6 +2570,7 @@ static MSList *make_routes_for_proxy(LinphoneProxyConfig *proxy, const LinphoneA LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const LinphoneAddress *uri){ const MSList *elem; LinphoneProxyConfig *found_cfg=NULL; + LinphoneProxyConfig *found_reg_cfg=NULL; LinphoneProxyConfig *found_noreg_cfg=NULL; LinphoneProxyConfig *default_cfg=lc->default_proxy; @@ -2582,21 +2583,25 @@ LinphoneProxyConfig * linphone_core_lookup_known_proxy(LinphoneCore *lc, const L } } - /*otherwise return first registering matching, otherwise first matching */ + /*otherwise return first registered, then first registering matching, otherwise first matching */ for (elem=linphone_core_get_proxy_config_list(lc);elem!=NULL;elem=elem->next){ LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data; const char *domain=linphone_proxy_config_get_domain(cfg); if (domain!=NULL && strcmp(domain,linphone_address_get_domain(uri))==0){ - if (linphone_proxy_config_register_enabled(cfg)) { + if (linphone_proxy_config_get_state(cfg) == LinphoneRegistrationOk ){ found_cfg=cfg; - goto end; + break; + } else if (!found_reg_cfg && linphone_proxy_config_register_enabled(cfg)) { + found_reg_cfg=cfg; } else if (!found_noreg_cfg){ found_noreg_cfg=cfg; } } } end: - if (!found_cfg && found_noreg_cfg) found_cfg = found_noreg_cfg; + if ( !found_cfg && found_reg_cfg) found_cfg = found_reg_cfg; + else if( !found_cfg && found_noreg_cfg ) found_cfg = found_noreg_cfg; + if (found_cfg && found_cfg!=default_cfg){ ms_debug("Overriding default proxy setting for this call/message/subscribe operation."); }else if (!found_cfg) found_cfg=default_cfg; /*when no matching proxy config is found, use the default proxy config*/ diff --git a/tester/call_tester.c b/tester/call_tester.c index 3e1a11ed6..7e3780279 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1,19 +1,19 @@ /* - liblinphone_tester - liblinphone test suite - Copyright (C) 2013 Belledonne Communications SARL + liblinphone_tester - liblinphone test suite + Copyright (C) 2013 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 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. + 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, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -269,51 +269,88 @@ static void simple_call(void) { } } +static void call_outbound_with_multiple_proxy() { + LinphoneCoreManager* pauline = linphone_core_manager_new2( "pauline_rc", FALSE); + LinphoneCoreManager* marie = linphone_core_manager_new2( "marie_rc", FALSE); + + LinphoneProxyConfig* lpc = NULL; + LinphoneProxyConfig* registered_lpc = linphone_proxy_config_new(); + + linphone_core_get_default_proxy(marie->lc, &lpc); + linphone_core_set_default_proxy(marie->lc,NULL); + + CU_ASSERT_FATAL(lpc != NULL); + CU_ASSERT_FATAL(registered_lpc != NULL); + + // create new LPC that will successfully register + linphone_proxy_config_set_identity(registered_lpc, linphone_proxy_config_get_identity(lpc)); + linphone_proxy_config_set_server_addr(registered_lpc, linphone_proxy_config_get_addr(lpc)); + linphone_proxy_config_set_route(registered_lpc, linphone_proxy_config_get_route(lpc)); + linphone_proxy_config_enable_register(registered_lpc, TRUE); + + linphone_core_add_proxy_config(marie->lc, registered_lpc); + + // set first LPC to unreacheable proxy addr + linphone_proxy_config_edit(lpc); + linphone_proxy_config_set_server_addr(lpc,"12.13.14.15:5223;transport=udp"); + linphone_proxy_config_set_route(lpc, "12.13.14.15:5223;transport=udp;lr"); + linphone_proxy_config_done(lpc); + + CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + + CU_ASSERT_TRUE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationProgress, 2, 200)); + CU_ASSERT_TRUE(wait_for_until(marie->lc, NULL, &marie->stat.number_of_LinphoneRegistrationOk, 1, 2000)); + + // calling marie should go through the second proxy config + CU_ASSERT_TRUE(call(marie, pauline)); + +} + #if 0 /* TODO: activate test when the implementation is ready */ static void multiple_answers_call() { /* Scenario is this: pauline calls marie, which is registered 2 times. - Both linphones answer at the same time, and only one should get the + Both linphones answer at the same time, and only one should get the call running, the other should be terminated */ char ringbackpath[256]; LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" ); LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" ); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" ); - + LinphoneCall* call1, *call2; - + MSList* lcs = ms_list_append(NULL,pauline->lc); lcs = ms_list_append(lcs,marie1->lc); lcs = ms_list_append(lcs,marie2->lc); - + linphone_core_use_files(pauline->lc, TRUE); linphone_core_use_files(marie1->lc, TRUE); linphone_core_use_files(marie2->lc, TRUE); - + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); - + CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); - + CU_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) ); CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000)); - + // marie 1 and 2 answer at the same time call1 = linphone_core_get_current_call(marie1->lc); call2 = linphone_core_get_current_call(marie2->lc); - + CU_ASSERT_PTR_NOT_NULL_FATAL(call1); CU_ASSERT_PTR_NOT_NULL_FATAL(call2); - + CU_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0); CU_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0); - + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); CU_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); CU_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 2000) ); - - + + linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie1); linphone_core_manager_destroy(marie2); @@ -321,54 +358,54 @@ static void multiple_answers_call() { #endif static void multiple_answers_call_with_media_relay() { - + /* Scenario is this: pauline calls marie, which is registered 2 times. - * Both linphones answer at the same time, and only one should get the + * Both linphones answer at the same time, and only one should get the * call running, the other should be terminated */ char ringbackpath[256]; LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc" ); LinphoneCoreManager* marie1 = linphone_core_manager_new( "marie_rc" ); LinphoneCoreManager* marie2 = linphone_core_manager_new( "marie_rc" ); - + LinphoneCall* call1, *call2; - + MSList* lcs = ms_list_append(NULL,pauline->lc); lcs = ms_list_append(lcs,marie1->lc); lcs = ms_list_append(lcs,marie2->lc); - + linphone_core_use_files(pauline->lc, TRUE); linphone_core_use_files(marie1->lc, TRUE); linphone_core_use_files(marie2->lc, TRUE); - + linphone_core_set_user_agent(pauline->lc, "Natted Linphone", NULL); linphone_core_set_user_agent(marie1->lc, "Natted Linphone", NULL); linphone_core_set_user_agent(marie2->lc, "Natted Linphone", NULL); - + snprintf(ringbackpath,sizeof(ringbackpath), "%s/sounds/hello8000.wav" /*use hello because rinback is too short*/, liblinphone_tester_file_prefix); - + CU_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000)); - + CU_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) ); - + CU_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000)); CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000)); - + // marie 1 and 2 answer at the same time call1 = linphone_core_get_current_call(marie1->lc); call2 = linphone_core_get_current_call(marie2->lc); - + CU_ASSERT_PTR_NOT_NULL_FATAL(call1); CU_ASSERT_PTR_NOT_NULL_FATAL(call2); - + CU_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0); CU_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0); - + CU_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); CU_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) ); CU_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 2000) ); - - + + linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(marie1); linphone_core_manager_destroy(marie2); @@ -2497,6 +2534,7 @@ test_t call_tests[] = { { "Cancelled ringing call", cancelled_ringing_call }, { "Call failed because of codecs", call_failed_because_of_codecs }, { "Simple call", simple_call }, + { "Outbound call with multiple proxy possible", call_outbound_with_multiple_proxy }, #if 0 /* not yet activated because not implemented */ { "Multiple answers to a call", multiple_answers_call }, #endif From 72269e28b787c903679b6eaaf0a364f416b45c8c Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 29 Jun 2014 13:11:58 +0200 Subject: [PATCH 182/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index 185eae373..c0547fb0b 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 185eae3737b6956667f022d68dadeca9eae2a706 +Subproject commit c0547fb0b6602cf9590a5dfb3f59742273ba692c From a18092880baef242a631ef249d8a21be11c79bf5 Mon Sep 17 00:00:00 2001 From: Johan Pascal Date: Mon, 30 Jun 2014 01:27:17 +0200 Subject: [PATCH 183/201] File transfer uses multipart body handler for uploading --- coreapi/chat.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 39e5f4c34..36f5beb89 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -37,16 +37,14 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatMessage* msg); #define MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449" -#define MULTIPART_HEADER_1 "--" MULTIPART_BOUNDARY "\r\n" \ - "Content-Disposition: form-data; name=\"File\"; filename=\"" -#define MULTIPART_HEADER_2 "\"\r\n" \ +#define FILEPART_HEADER_1 "Content-Disposition: form-data; name=\"File\"; filename=\"" +#define FILEPART_HEADER_2 "\"\r\n" \ "Content-Type: " -#define MULTIPART_HEADER_3 "\r\n\r\n" -#define MULTIPART_END "\r\n--" MULTIPART_BOUNDARY "--\r\n" +#define FILEPART_HEADER_3 "\r\n\r\n" const char *multipart_boundary=MULTIPART_BOUNDARY; -static size_t linphone_chat_message_compute_multipart_header_size(const char *filename, const char *content_type) { - return strlen(MULTIPART_HEADER_1)+strlen(filename)+strlen(MULTIPART_HEADER_2)+strlen(content_type)+strlen(MULTIPART_HEADER_3); +static size_t linphone_chat_message_compute_filepart_header_size(const char *filename, const char *content_type) { + return strlen(FILEPART_HEADER_1)+strlen(filename)+strlen(FILEPART_HEADER_2)+strlen(content_type)+strlen(FILEPART_HEADER_3); } static void process_io_error(void *data, const belle_sip_io_error_event_t *event){ LinphoneChatMessage* msg=(LinphoneChatMessage *)data; @@ -87,28 +85,26 @@ static int linphone_chat_message_file_transfer_on_send_body(belle_sip_user_body_ char *buf = (char *)buffer; char *content_type=belle_sip_strdup_printf("%s/%s", chatMsg->file_transfer_information->type, chatMsg->file_transfer_information->subtype); - size_t end_of_file=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size; + size_t end_of_file=linphone_chat_message_compute_filepart_header_size(chatMsg->file_transfer_information->name, content_type)+chatMsg->file_transfer_information->size; if (offset==0){ - int partlen=linphone_chat_message_compute_multipart_header_size(chatMsg->file_transfer_information->name, content_type); - memcpy(buf,MULTIPART_HEADER_1,strlen(MULTIPART_HEADER_1)); - buf += strlen(MULTIPART_HEADER_1); + int partlen=linphone_chat_message_compute_filepart_header_size(chatMsg->file_transfer_information->name, content_type); + memcpy(buf,FILEPART_HEADER_1,strlen(FILEPART_HEADER_1)); + buf += strlen(FILEPART_HEADER_1); memcpy(buf,chatMsg->file_transfer_information->name,strlen(chatMsg->file_transfer_information->name)); buf += strlen(chatMsg->file_transfer_information->name); - memcpy(buf,MULTIPART_HEADER_2,strlen(MULTIPART_HEADER_2)); - buf += strlen(MULTIPART_HEADER_2); + memcpy(buf,FILEPART_HEADER_2,strlen(FILEPART_HEADER_2)); + buf += strlen(FILEPART_HEADER_2); memcpy(buf,content_type,strlen(content_type)); buf += strlen(content_type); - memcpy(buf,MULTIPART_HEADER_3,strlen(MULTIPART_HEADER_3)); + memcpy(buf,FILEPART_HEADER_3,strlen(FILEPART_HEADER_3)); *size=partlen; }else if (offsetvtable.file_transfer_send(lc, chatMsg, chatMsg->file_transfer_information, buf, size); - }else{ - *size=strlen(MULTIPART_END); - strncpy(buf,MULTIPART_END,*size); } + belle_sip_free(content_type); return BELLE_SIP_CONTINUE; } @@ -134,7 +130,12 @@ static void linphone_chat_message_process_response_from_post_file(void *data, co belle_generic_uri_t *uri; belle_http_request_t *req; char *content_type=belle_sip_strdup_printf("%s/%s", msg->file_transfer_information->type, msg->file_transfer_information->subtype); - belle_sip_user_body_handler_t *bh=belle_sip_user_body_handler_new(msg->file_transfer_information->size+linphone_chat_message_compute_multipart_header_size(msg->file_transfer_information->name, content_type)+strlen(MULTIPART_END), linphone_chat_message_file_transfer_on_progress, NULL, linphone_chat_message_file_transfer_on_send_body, msg); + + /* create a user body handler to take care of the file */ + belle_sip_user_body_handler_t *first_part_bh=belle_sip_user_body_handler_new(msg->file_transfer_information->size+linphone_chat_message_compute_filepart_header_size(msg->file_transfer_information->name, content_type), NULL, NULL, linphone_chat_message_file_transfer_on_send_body, msg); + /* insert it in a multipart body handler which will manage the boundaries of multipart message */ + belle_sip_multipart_body_handler_t *bh=belle_sip_multipart_body_handler_new(linphone_chat_message_file_transfer_on_progress, msg, (belle_sip_body_handler_t *)first_part_bh); + char* ua = ms_strdup_printf("%s/%s", linphone_core_get_user_agent_name(), linphone_core_get_user_agent_version()); belle_sip_free(content_type); From 8a6fb40b5f728717cc3d48a483889787332b28a4 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 30 Jun 2014 09:37:41 +0200 Subject: [PATCH 184/201] update ms2 --- coreapi/quality_reporting.c | 2 -- mediastreamer2 | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index f5dd852f4..63944e55d 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -678,8 +678,6 @@ void linphone_reporting_call_state_updated(LinphoneCall *call){ oass->stats_type = i; STR_REASSIGN(call->log->reporting.reports[i]->qos_analyzer.name, ms_strdup(ms_qos_analyzer_get_name(analyzer))); - // /!\ only us use this callback so we can free user_data from here - ms_free(analyzer->on_action_suggested_user_pointer); ms_qos_analyzer_set_on_action_suggested(analyzer, qos_analyzer_on_action_suggested, oass); diff --git a/mediastreamer2 b/mediastreamer2 index c0547fb0b..d26e126d3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit c0547fb0b6602cf9590a5dfb3f59742273ba692c +Subproject commit d26e126d301e689cc1812de7d37a3cd40865a201 From 5394925707ef08359f5ee959426aeaca1ae05c14 Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Mon, 30 Jun 2014 10:09:19 +0200 Subject: [PATCH 185/201] fix some memory leaks in gtk --- gtk/incall_view.c | 28 +++++++++++++++------------- gtk/main.ui | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 382e27746..0450f374c 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -84,13 +84,13 @@ void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause){ GtkWidget *i=NULL; GtkWidget *l; gchar *text; - + if(pause){ i=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_SMALL_TOOLBAR); } else { i=create_pixmap ("startcall-small.png"); } - + text=g_strdup_printf(_("Call #%i"),call_index); l=gtk_label_new (text); gtk_box_pack_start (GTK_BOX(new_label),i,FALSE,FALSE,0); @@ -98,6 +98,7 @@ void linphone_gtk_call_update_tab_header(LinphoneCall *call,gboolean pause){ gtk_notebook_set_tab_label(notebook,w,new_label); gtk_widget_show_all(new_label); + g_free(text); } static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const char *image_name, gboolean is_stock){ @@ -181,7 +182,7 @@ static void conference_button_clicked(GtkWidget *button, gpointer call_ref){ gtk_widget_set_sensitive(button,FALSE); g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame",NULL); linphone_core_add_all_to_conference(linphone_gtk_get_core()); - + } void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value){ @@ -271,7 +272,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ gchar *size_s=g_strdup_printf(_("%ix%i"),size_sent.width,size_sent.height); gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_recv")),size_r); gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_size_sent")),size_s); - + tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),vs->download_bandwidth,vs->upload_bandwidth); g_free(size_r); g_free(size_s); @@ -286,7 +287,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ audio_media_connectivity = ice_state_to_string(as->ice_state); } gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_media_connectivity")),audio_media_connectivity); - + if (has_video){ if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) { video_media_connectivity = upnp_state_to_string(vs->upnp_state); @@ -295,7 +296,7 @@ static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){ } }else video_media_connectivity=NULL; gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_media_connectivity")),video_media_connectivity); - + if (as->round_trip_delay>0){ tmp=g_strdup_printf(_("%.3f seconds"),as->round_trip_delay); gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"round_trip_time")),tmp); @@ -467,7 +468,7 @@ void linphone_gtk_remove_in_call_view(LinphoneCall *call){ static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress *from){ const char *displayname=NULL; - const char *id; + char *id; char *uri_label; displayname=linphone_address_get_display_name(from); id=linphone_address_as_string_uri_only(from); @@ -479,6 +480,7 @@ static void display_peer_name_in_label(GtkWidget *label, const LinphoneAddress * uri_label=g_markup_printf_escaped("%s\n",id); gtk_label_set_markup(GTK_LABEL(label),uri_label); g_free(uri_label); + g_free(id); } void linphone_gtk_in_call_view_set_calling(LinphoneCall *call){ @@ -686,10 +688,10 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats"); display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); - + gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),in_conf ? _("In conference") : _("In call")); - + gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"conference_button"),!in_conf); gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"transfer_button"),!in_conf); @@ -698,7 +700,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ linphone_gtk_call_update_tab_header(call,FALSE); linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE); - + if (taskid==0){ taskid=g_timeout_add(250,(GSourceFunc)linphone_gtk_in_call_view_refresh,call); g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid)); @@ -772,7 +774,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE); linphone_gtk_enable_hold_button(call,FALSE,TRUE); - + if (taskid!=0) g_source_remove(taskid); g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call); if (in_conf) @@ -909,7 +911,7 @@ void linphone_gtk_record_call_toggled(GtkWidget *button){ return; } message=g_strdup_printf(_("Recording into\n%s %s"),filepath,active ? "" : _("(Paused)")); - + if (active){ if (call) linphone_call_start_recording(call); @@ -920,7 +922,7 @@ void linphone_gtk_record_call_toggled(GtkWidget *button){ linphone_call_stop_recording(call); else linphone_core_stop_conference_recording(lc); - + } gtk_label_set_markup(GTK_LABEL(label),message); g_free(message); diff --git a/gtk/main.ui b/gtk/main.ui index 44750d572..06909d6c6 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1772,7 +1772,7 @@ False model4 0 - + From 52d67ee288b48e0db1832951d9c7c8182bf2c973 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 30 Jun 2014 11:15:38 +0200 Subject: [PATCH 186/201] fix crash in ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d26e126d3..d9c06ebeb 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d26e126d301e689cc1812de7d37a3cd40865a201 +Subproject commit d9c06ebebb3a0a37736c83e9f40aead90326d1f6 From bcf7e96c24989e4eda894303109dddad730b9ab7 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 30 Jun 2014 16:35:23 +0200 Subject: [PATCH 187/201] make video recording working --- coreapi/linphonecall.c | 2 +- mediastreamer2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index a714f88b7..50452ef8e 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2237,8 +2237,8 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut } call->current_params.has_video=FALSE; if (call->videostream!=NULL) { - linphone_call_start_video_stream(call,cname,all_inputs_muted); if (call->audiostream) audio_stream_link_video(call->audiostream,call->videostream); + linphone_call_start_video_stream(call,cname,all_inputs_muted); } call->all_muted=all_inputs_muted; diff --git a/mediastreamer2 b/mediastreamer2 index 964c468de..15387edf6 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 964c468de35f6f864967ed23c0d9fc9f5d95b521 +Subproject commit 15387edf656f1ec185ecb22786f2361c6bcb0c86 From de18523576bf1bc69e781ab0ac7a27295e0f3dbd Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Mon, 30 Jun 2014 17:19:55 +0200 Subject: [PATCH 188/201] update ms2 --- mediastreamer2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mediastreamer2 b/mediastreamer2 index d9c06ebeb..f466a6e17 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit d9c06ebebb3a0a37736c83e9f40aead90326d1f6 +Subproject commit f466a6e17e4cb62d48d9ab27b2c231a29ca750dd From 8639b1f83dc359400216afdd8518c3fa367d7f7e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 30 Jun 2014 20:50:03 +0200 Subject: [PATCH 189/201] make sure default value are not reset when proxy config is read from file --- coreapi/linphonecore.h | 3 ++- coreapi/proxy.c | 56 +++++++++++++++++++----------------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 825a41697..d1b6d1212 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -904,7 +904,8 @@ LINPHONE_PUBLIC const char *linphone_proxy_config_get_domain(const LinphoneProxy LINPHONE_PUBLIC const char *linphone_proxy_config_get_route(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC const char *linphone_proxy_config_get_identity(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj); -LINPHONE_PUBLIC const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj); +LINPHONE_PUBLIC const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *obj); +#define linphone_proxy_config_get_addr linphone_proxy_config_get_server_addr LINPHONE_PUBLIC int linphone_proxy_config_get_expires(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC bool_t linphone_proxy_config_register_enabled(const LinphoneProxyConfig *obj); LINPHONE_PUBLIC void linphone_proxy_config_refresh_register(LinphoneProxyConfig *obj); diff --git a/coreapi/proxy.c b/coreapi/proxy.c index ad7234a7b..f96401d6c 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1005,7 +1005,7 @@ bool_t linphone_proxy_config_publish_enabled(const LinphoneProxyConfig *obj){ /** * Returns the proxy's SIP address. **/ -const char *linphone_proxy_config_get_addr(const LinphoneProxyConfig *obj){ +const char *linphone_proxy_config_get_server_addr(const LinphoneProxyConfig *obj){ return obj->reg_proxy; } @@ -1224,15 +1224,20 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC } +#define CONFIGURE_STRING_VALUE(obj,config,key,param,param_name) \ + linphone_proxy_config_set_##param(obj,lp_config_get_string(config,key,param_name,linphone_proxy_config_get_##param(obj))); + +#define CONFIGURE_BOOL_VALUE(obj,config,key,param,param_name) \ + linphone_proxy_config_enable_##param(obj,lp_config_get_int(config,key,param_name,linphone_proxy_config_##param##_enabled(obj))); + +#define CONFIGURE_INT_VALUE(obj,config,key,param,param_name) \ + linphone_proxy_config_set_##param(obj,lp_config_get_int(config,key,param_name,linphone_proxy_config_get_##param(obj))); LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc, int index) { const char *tmp; - const char *identity; - const char *proxy; LinphoneProxyConfig *cfg; char key[50]; - int interval; LpConfig *config=lc->config; sprintf(key,"proxy_%i",index); @@ -1243,42 +1248,31 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LinphoneCore* lc cfg=linphone_core_create_proxy_config(lc); - identity=lp_config_get_string(config,key,"reg_identity",NULL); - proxy=lp_config_get_string(config,key,"reg_proxy",NULL); + CONFIGURE_STRING_VALUE(cfg,config,key,identity,"reg_identity") + CONFIGURE_STRING_VALUE(cfg,config,key,server_addr,"reg_proxy") + CONFIGURE_STRING_VALUE(cfg,config,key,route,"reg_route") - linphone_proxy_config_set_identity(cfg,identity); - linphone_proxy_config_set_server_addr(cfg,proxy); + CONFIGURE_BOOL_VALUE(cfg,config,key,quality_reporting,"quality_reporting_enabled") - tmp=lp_config_get_string(config,key,"reg_route",NULL); - if (tmp!=NULL) linphone_proxy_config_set_route(cfg,tmp); + CONFIGURE_STRING_VALUE(cfg,config,key,quality_reporting_collector,"quality_reporting_collector") - linphone_proxy_config_enable_quality_reporting(cfg,lp_config_get_int(config,key,"quality_reporting_enabled",0)); - tmp=lp_config_get_string(config,key,"quality_reporting_collector",NULL); - if (tmp!=NULL) linphone_proxy_config_set_quality_reporting_collector(cfg,tmp); - interval=lp_config_get_int(config, key, "quality_reporting_interval", 0); - linphone_proxy_config_set_quality_reporting_interval(cfg, interval? MAX(interval, 120) : 0); + CONFIGURE_INT_VALUE(cfg,config,key,quality_reporting_interval,"quality_reporting_interval") - linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL)); + CONFIGURE_STRING_VALUE(cfg,config,key,contact_parameters,"contact_parameters") + CONFIGURE_STRING_VALUE(cfg,config,key,contact_uri_parameters,"contact_uri_parameters") - linphone_proxy_config_set_contact_uri_parameters(cfg,lp_config_get_string(config,key,"contact_uri_parameters",NULL)); - - linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",lp_config_get_default_int(config,"proxy","reg_expires",600))); - linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0)); - - linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0)); - - linphone_proxy_config_enable_avpf(cfg, lp_config_get_int(config, key, "avpf", 0)); - linphone_proxy_config_set_avpf_rr_interval(cfg, lp_config_get_int(config, key, "avpf_rr_interval", 5)); - - linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",lp_config_get_default_int(config,"proxy","dial_escape_plus",0))); - linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",lp_config_get_default_string(config,"proxy","dial_prefix",NULL))); + CONFIGURE_INT_VALUE(cfg,config,key,expires,"reg_expires") + CONFIGURE_BOOL_VALUE(cfg,config,key,register,"reg_sendregister") + CONFIGURE_BOOL_VALUE(cfg,config,key,publish,"publish") + CONFIGURE_BOOL_VALUE(cfg,config,key,avpf,"avpf") + CONFIGURE_INT_VALUE(cfg,config,key,avpf_rr_interval,"avpf_rr_interval") + CONFIGURE_INT_VALUE(cfg,config,key,dial_escape_plus,"dial_escape_plus") + CONFIGURE_STRING_VALUE(cfg,config,key,dial_prefix,"dial_prefix") tmp=lp_config_get_string(config,key,"type",NULL); if (tmp!=NULL && strlen(tmp)>0) linphone_proxy_config_set_sip_setup(cfg,tmp); - - linphone_proxy_config_set_privacy(cfg,lp_config_get_int(config,key,"privacy",lp_config_get_default_int(config,"proxy","privacy",LinphonePrivacyDefault))); - + CONFIGURE_INT_VALUE(cfg,config,key,privacy,"privacy") return cfg; } From 641e9fc74655fe455b8acd6b4761989049e64d19 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Mon, 30 Jun 2014 22:49:03 +0200 Subject: [PATCH 190/201] fix invalid read for new proxy config initialization --- coreapi/proxy.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/coreapi/proxy.c b/coreapi/proxy.c index f96401d6c..838a536a8 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -1225,7 +1225,11 @@ void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyC #define CONFIGURE_STRING_VALUE(obj,config,key,param,param_name) \ - linphone_proxy_config_set_##param(obj,lp_config_get_string(config,key,param_name,linphone_proxy_config_get_##param(obj))); + {\ + char* default_value = linphone_proxy_config_get_##param(obj)?ms_strdup(linphone_proxy_config_get_##param(obj)):NULL;\ + linphone_proxy_config_set_##param(obj,lp_config_get_string(config,key,param_name,default_value)); \ + if ( default_value) ms_free(default_value); \ + } #define CONFIGURE_BOOL_VALUE(obj,config,key,param,param_name) \ linphone_proxy_config_enable_##param(obj,lp_config_get_int(config,key,param_name,linphone_proxy_config_##param##_enabled(obj))); From 39b9fcd8e7144814188ee0c67bd273221fd2ddad Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 1 Jul 2014 11:52:52 +0200 Subject: [PATCH 191/201] protect chat message from being released in delivery error cb --- coreapi/chat.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 36f5beb89..c344d9771 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -316,7 +316,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM char* content_type; const char *identity=NULL; time_t t=time(NULL); - + linphone_chat_message_ref(msg); /* Check if we shall upload a file to a server */ if (msg->file_transfer_information != NULL) { /* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ @@ -337,7 +337,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM cbs.process_auth_requested=process_auth_requested; l=belle_http_request_listener_create_from_callbacks(&cbs,msg); /* give msg to listener to be able to start the actual file upload when server answer a 204 No content */ belle_http_provider_send_request(cr->lc->http_provider,req,l); - + linphone_chat_message_unref(msg); return; } @@ -388,6 +388,7 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM } linphone_chat_room_delete_composing_idle_timer(cr); linphone_chat_room_delete_composing_refresh_timer(cr); + linphone_chat_message_unref(msg); } /** From 80b306bb0223d5ad5efcfc97c2a0b4684f9f789f Mon Sep 17 00:00:00 2001 From: Gautier Pelloux-Prayer Date: Tue, 1 Jul 2014 13:54:16 +0200 Subject: [PATCH 192/201] update ms2 --- gtk/main.c | 2 ++ mediastreamer2 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gtk/main.c b/gtk/main.c index 538bb11a2..e9f14c545 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -2319,6 +2319,8 @@ core_start: linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file); + if (config_file) free(config_file); + /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/ gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core()); diff --git a/mediastreamer2 b/mediastreamer2 index f466a6e17..84ce0753e 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f466a6e17e4cb62d48d9ab27b2c231a29ca750dd +Subproject commit 84ce0753edfae002c0f5bcff17f80f6f9c285f14 From 484d05b02bc776d258e92ac4cf390b0bd4f3caba Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 1 Jul 2014 15:45:10 +0200 Subject: [PATCH 193/201] Fix wrong character in comment. --- coreapi/chat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index c344d9771..569d7a6a5 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -216,7 +216,7 @@ bool_t linphone_core_chat_enabled(const LinphoneCore *lc){ /** * Returns an array of chat rooms * @param lc #LinphoneCore object - * @return An array of #LinpĥoneChatRoom + * @return An array of #LinphoneChatRoom **/ MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) { return lc->chatrooms; From acca0f19ad4b1fe77033edbe7a571531de87ef85 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 1 Jul 2014 16:34:09 +0200 Subject: [PATCH 194/201] Normalize function name. --- console/commands.c | 2 +- coreapi/linphonecall.c | 2 +- coreapi/linphonecore.h | 3 ++- coreapi/linphonecore_jni.cc | 2 +- gtk/incall_view.c | 6 +++--- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/console/commands.c b/console/commands.c index c22c963b0..3af324b7c 100644 --- a/console/commands.c +++ b/console/commands.c @@ -2438,7 +2438,7 @@ static void lpc_display_call_states(LinphoneCore *lc){ for(;elem!=NULL;elem=elem->next){ const char *flag; call=(LinphoneCall*)elem->data; - bool_t in_conference=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + bool_t in_conference=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); tmp=linphone_call_get_remote_address_as_string (call); flag=in_conference ? "conferencing" : ""; flag=linphone_call_has_transfer_pending(call) ? "transfer pending" : flag; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e5dfbed58..042fe89c5 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1404,7 +1404,7 @@ bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams /** * Returns true if the call is part of the locally managed conference. **/ -bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp){ +bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp){ return cp->in_conference; } diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d1b6d1212..a4e91e2c3 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -389,7 +389,8 @@ LINPHONE_PUBLIC LinphoneMediaEncryption linphone_call_params_get_media_encryptio LINPHONE_PUBLIC void linphone_call_params_set_media_encryption(LinphoneCallParams *cp, LinphoneMediaEncryption e); LINPHONE_PUBLIC void linphone_call_params_enable_early_media_sending(LinphoneCallParams *cp, bool_t enabled); LINPHONE_PUBLIC bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams *cp); -LINPHONE_PUBLIC bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp); +#define linphone_call_params_local_conference_mode linphone_call_params_get_local_conference_mode /* Deprecated */ +LINPHONE_PUBLIC bool_t linphone_call_params_get_local_conference_mode(const LinphoneCallParams *cp); LINPHONE_PUBLIC void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw); LINPHONE_PUBLIC void linphone_call_params_destroy(LinphoneCallParams *cp); LINPHONE_PUBLIC bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index dd84cafba..3ab985981 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -2789,7 +2789,7 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_getVideoEnable } extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_localConferenceMode(JNIEnv *env, jobject thiz, jlong lcp){ - return (jboolean)linphone_call_params_local_conference_mode((LinphoneCallParams*)lcp); + return (jboolean)linphone_call_params_get_local_conference_mode((LinphoneCallParams*)lcp); } extern "C" jstring Java_org_linphone_core_LinphoneCallParamsImpl_getCustomHeader(JNIEnv *env, jobject thiz, jlong lcp, jstring jheader_name){ diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 0450f374c..979330123 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -442,7 +442,7 @@ void linphone_gtk_remove_in_call_view(LinphoneCall *call){ GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer (call); GtkWidget *main_window=linphone_gtk_get_main_window (); GtkWidget *nb=linphone_gtk_get_widget(main_window,"viewswitch"); - gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); int idx; g_return_if_fail(w!=NULL); idx=gtk_notebook_page_num(GTK_NOTEBOOK(nb),w); @@ -684,7 +684,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ GtkWidget *callee=linphone_gtk_get_widget(callview,"in_call_uri"); GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); - gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats"); display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); @@ -753,7 +753,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m if(callview==NULL) return; GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); - gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call)); + gboolean in_conf=linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call)); if (status==NULL) return; if (error_msg==NULL) From 71d498fd951721cb9dda39db62f41011a8729dbe Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 1 Jul 2014 21:57:31 +0200 Subject: [PATCH 195/201] fix potential crash during provisioning update po file and fr translation --- coreapi/chat.c | 4 +- gtk/main.c | 3 +- po/cs.po | 576 ++++++++++++++++++++++---------------- po/de.po | 574 ++++++++++++++++++++++---------------- po/es.po | 709 ++++++++++++++++++++++++++--------------------- po/fr.po | 732 +++++++++++++++++++++++++++---------------------- po/he.po | 687 ++++++++++++++++++++++++++-------------------- po/hu.po | 569 ++++++++++++++++++++++---------------- po/it.po | 695 ++++++++++++++++++++++++++-------------------- po/ja.po | 691 ++++++++++++++++++++++++++-------------------- po/nb_NO.po | 572 ++++++++++++++++++++++---------------- po/nl.po | 695 ++++++++++++++++++++++++++-------------------- po/pl.po | 691 ++++++++++++++++++++++++++-------------------- po/pt_BR.po | 691 ++++++++++++++++++++++++++-------------------- po/ru.po | 576 ++++++++++++++++++++++---------------- po/sr.po | 565 ++++++++++++++++++++++---------------- po/sv.po | 693 ++++++++++++++++++++++++++-------------------- po/zh_CN.po | 698 ++++++++++++++++++++++++++-------------------- po/zh_TW.po | 569 ++++++++++++++++++++++---------------- 19 files changed, 6296 insertions(+), 4694 deletions(-) diff --git a/coreapi/chat.c b/coreapi/chat.c index 569d7a6a5..7617f0e55 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -214,9 +214,9 @@ bool_t linphone_core_chat_enabled(const LinphoneCore *lc){ } /** - * Returns an array of chat rooms + * Returns an list of chat rooms * @param lc #LinphoneCore object - * @return An array of #LinphoneChatRoom + * @return A list of #LinphoneChatRoom **/ MSList* linphone_core_get_chat_rooms(LinphoneCore *lc) { return lc->chatrooms; diff --git a/gtk/main.c b/gtk/main.c index e9f14c545..4dd4f1a1f 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -2319,8 +2319,6 @@ core_start: linphone_gtk_init_liblinphone(config_file, factory_config_file, db_file); - if (config_file) free(config_file); - /* do not lower timeouts under 30 ms because it exhibits a bug on gtk+/win32, with cpu running 20% all the time...*/ gtk_timeout_add(30,(GtkFunction)linphone_gtk_iterate,(gpointer)linphone_gtk_get_core()); gtk_timeout_add(30,(GtkFunction)linphone_gtk_check_logs,(gpointer)linphone_gtk_get_core()); @@ -2333,6 +2331,7 @@ core_start: restart=FALSE; goto core_start; } + if (config_file) free(config_file); #ifndef HAVE_GTK_OSX /*workaround a bug on win32 that makes status icon still present in the systray even after program exit.*/ if (icon) gtk_status_icon_set_visible(icon,FALSE); diff --git a/po/cs.po b/po/cs.po index bfbfe77b8..048bb9624 100644 --- a/po/cs.po +++ b/po/cs.po @@ -18,7 +18,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-3.5.99.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2013-05-01 09:55+0200\n" "Last-Translator: Petr Pisar \n" "Language-Team: Czech \n" @@ -28,38 +28,38 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Volat komu: %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Poslat text komu: %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, c-format msgid "Recent calls (%i)" msgstr "Nedávné hovory (%i)" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "–" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 msgid "Aborted" msgstr "Přerušen" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 msgid "Missed" msgstr "Zmeškán" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 msgid "Declined" msgstr "Odmítnut" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -67,7 +67,7 @@ msgstr[0] "%i minuta" msgstr[1] "%i minuty" msgstr[2] "%i minut" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -75,12 +75,12 @@ msgstr[0] "%i sekunda" msgstr[1] "%i sekundy" msgstr[2] "%i sekund" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "%s\t%s" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" @@ -89,7 +89,7 @@ msgstr "" "%s\tKvalita: %s\n" "%s\t%s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -111,35 +111,35 @@ msgstr "Já" msgid "Couldn't find pixmap file: %s" msgstr "Nelze najít soubor s obrázkem: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Neplatný sipový kontakt!" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "Za běhu vypisuje některé ladicí informace na standardní výstup." -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "Soubor, kam zapisovat protokol." -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "Spustí linphone se zakázaným obrazem." -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Spustí se pouze do systémové oblasti, nezobrazí hlavní okno." -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "Zavolá právě teď na tuto adresu" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "je-li nastaveno, automaticky zvedne příchozí hovor" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -147,17 +147,22 @@ msgstr "" "Zadejte pracovní adresář (měl by být základní instalační adresář, například " "c:\\Program Files\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Potvrzení" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Průvodce nastavením účtu" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Hovor s %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -170,7 +175,7 @@ msgstr "" "do svého adresáře?\n" "Odpovíte-li ne, tato osobo bude dočasně blokována." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -179,59 +184,59 @@ msgstr "" "Prosím, zadejte heslo pro uživatele %s\n" "v doméně %s:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 msgid "Call error" msgstr "Chyba hovoru" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Hovor ukončen" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Odpovědět" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Odmítnout" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 msgid "Call paused" msgstr "Hovor odložen" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, c-format msgid "by %s" msgstr "kým: %s" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s navrhuje začít videohovor. Přijímáte?" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Odkaz na webovou stránku" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Lipnhone – internetový videofon" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (Výchozí)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Byly jsme přepojeni na %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -239,7 +244,7 @@ msgstr "" "Na tomto počítači nebyla objevena žádná zvuková karta.\n" "Nebudete moci vytáčet a přijímat a zvukové hovory." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Volný SIP videofon" @@ -251,7 +256,7 @@ msgstr "Přidat do adresáře" msgid "Presence status" msgstr "Stav" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Jméno" @@ -268,142 +273,142 @@ msgstr "Diskuze" msgid "Search in %s directory" msgstr "Hledat v adresáři %s" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Upravit kontakt „%s“" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Odstranit kontakt „%s“" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, c-format msgid "Delete chat history of '%s'" msgstr "Odstranit historii diskuze u kontaktu „%s“" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Přidat nový kontakt z adresáře %s" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Kmitočet (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Stav" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Min. rychlost (kb/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parametry" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Povoleno" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Zakázáno" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Účet" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "angličtina" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "francouzština" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "švédština" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "italština" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "španělština" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "brazilská portugalština" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "polština" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "němčina" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "ruština" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "japonština" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "dánština" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "maďarština" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "čeština" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "čínština" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "tradiční čínština" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "norština" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "hebrejština" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "srbština" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Aby se projevil výběr nového jazyka, je nutné znovu spustit linphone." # Media encryption type: -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Žádné" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "ZRTP" @@ -547,40 +552,40 @@ msgstr "" "zaslali e-mailem.\n" "Pak se sem vraťte a stiskněte tlačítko Další." -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Průvodce nastavením účtu" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Vítejte v průvodci nastavení účtu" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Průvodce nastavením účtu" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "Nastavit účet (krok 1/1)" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "Zadejte vaše sipové uživatelské jméno (krok 1/1)" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "Zadejte údaje o účtu (krok 1/2)" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "Ověření (krok 2/2)" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "Chyba" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "Ukončuje se" @@ -589,64 +594,64 @@ msgstr "Ukončuje se" msgid "Call #%i" msgstr "Hovor č. %i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Přepojit hovor č. %i s %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "Nepoužito" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "ICE není zapnuto" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 msgid "ICE failed" msgstr "ICE selhalo" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "Probíhá ICE" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "Prochází se jedním nebo více NATy" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "Přímé" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "Skrze relay server" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "UPnP není zapnuto" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 msgid "uPnP in progress" msgstr "Probíhá UPnP" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "UPnP není nedostupné" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "UPnP běží" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 msgid "uPnP failed" msgstr "UPnP selhalo" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "Přímé nebo skrze server" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" @@ -655,115 +660,115 @@ msgstr "" "příchozí: %f\n" "odchozí: %f (kb/s)" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "%.3f sekund" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Zavěsit" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Volá se…" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "Příchozí hovor" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "dobrá" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "průměrná" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "slabá" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "velmi slabá" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "příliš špatná" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "nedostupná" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "Zabezpečeno pomocí SRTP" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Zabezpečeno pomocí ZRTP – [ověřovací klíč: %s]" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "Nastavit na neověřeno" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Nastavit na ověřeno" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "Probíhá konference" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "Probíhá hovor" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "Odložený hovor" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Hovor skončil." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "Probíhá přepojení" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "Přepojení dokončeno." -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 msgid "Transfer failed." msgstr "Přepojení selhalo." -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Obnovit" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Odložit" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" @@ -772,7 +777,7 @@ msgstr "" "Nahrává se do\n" "%s %s" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "(Odloženo)" @@ -791,6 +796,88 @@ msgstr "Příchozí hovor od %s" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Vítejte!\n" +"Tento průvodce vám pomůže používat sipový účet při vašich hovorech." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Zařízení pro nahrávání:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Zdroj nahrávání:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Zařízení pro přehrávání:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Průvodce" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Průvodce účtem" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Jméno volaného" @@ -832,123 +919,123 @@ msgid "Call quality rating" msgstr "Hodnocení kvality hovoru" #: ../gtk/main.ui.h:17 +msgid "All users" +msgstr "všech uživatelích" + +#: ../gtk/main.ui.h:18 +msgid "Online users" +msgstr "připojených uživatelích" + +#: ../gtk/main.ui.h:19 +msgid "ADSL" +msgstr "ADSL" + +#: ../gtk/main.ui.h:20 +msgid "Fiber Channel" +msgstr "Fiber Channel" + +#: ../gtk/main.ui.h:21 +msgid "Default" +msgstr "Výchozí" + +#: ../gtk/main.ui.h:22 msgid "_Options" msgstr "V_olby" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Set configuration URI" msgstr "Konfigurace proxy a registrace" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:24 msgid "Always start video" msgstr "Vždy spustit obraz" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:25 msgid "Enable self-view" msgstr "Zobrazovat sám sebe" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:26 msgid "_Help" msgstr "Nápo_věda" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:27 msgid "Show debug window" msgstr "Zobrazit ladicí okno" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:28 msgid "_Homepage" msgstr "_Domovská stránka" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:29 msgid "Check _Updates" msgstr "Vyhledat akt_ualizace" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:30 msgid "Account assistant" msgstr "Průvodce účtem" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:32 msgid "SIP address or phone number:" msgstr "SIP adresa nebo telefonní číslo:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:33 msgid "Initiate a new call" msgstr "Zahájit nový hovor" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:34 msgid "Contacts" msgstr "Kontakty" -#: ../gtk/main.ui.h:29 +#: ../gtk/main.ui.h:35 msgid "Search" msgstr "Hledat" -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:36 msgid "Add contacts from directory" msgstr "Přidat kontakty z adresáře" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:37 msgid "Add contact" msgstr "Přidat kontakt" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:38 msgid "Recent calls" msgstr "Nedávné hovory" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:39 msgid "My current identity:" msgstr "Moje současná totožnost:" -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Uživatelské jméno" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Heslo" -#: ../gtk/main.ui.h:36 +#: ../gtk/main.ui.h:42 msgid "Internet connection:" msgstr "Připojení k Internetu:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:43 msgid "Automatically log me in" msgstr "Přihlašovat mě automaticky" -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 msgid "UserID" msgstr "Identifikátor uživatele" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:45 msgid "Login information" msgstr "Informace o přihlášení" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:46 msgid "Welcome !" msgstr "Vítejte!" -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "všech uživatelích" - -#: ../gtk/main.ui.h:42 -msgid "Online users" -msgstr "připojených uživatelích" - -#: ../gtk/main.ui.h:43 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/main.ui.h:44 -msgid "Fiber Channel" -msgstr "Fiber Channel" - -#: ../gtk/main.ui.h:45 -msgid "Default" -msgstr "Výchozí" - -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "Smazat" @@ -1070,23 +1157,32 @@ msgid "Contact params (optional):" msgstr "Směrování (volitelné):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Směrování (volitelné):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Přenos" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "Zaregistrovat se" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Zveřejnit stav přítomnosti" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Povolit" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Nastavit SIP účet" @@ -1513,6 +1609,11 @@ msgid "Video resolution sent" msgstr "Upřednostňované rozlišení obrazu:" #: ../gtk/call_statistics.ui.h:11 +#, fuzzy +msgid "RTP profile" +msgstr "RTP vlastnosti" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" msgstr "Statistické a ostatní údaje o hovoru" @@ -1719,19 +1820,19 @@ msgstr "Připojuje se…" msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "přerušen" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "dokončen" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "promeškán" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1746,77 +1847,77 @@ msgstr "" "Stav: %s\n" "Délka: %i min %i s\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Odchozí hovor" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Připraven." -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Potvrzení" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Vyhledává se umístění čísla…" -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Toto číslo nelze vyhledat." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Navazuje se spojení" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "Nelze volat" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Je nám líto, ale byl dosažen maximální počet současných hovorů." -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "vás volá" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr " a požaduje automatickou zvednutí." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "Upravují se parametry hovoru…" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Připojeno." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "Hovor přerušen" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "Hovor nebylo možné odložit" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Současný hovor se odkládá…" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "Hledá se adresa pomocí STUN…" -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "Shromažďují se místní kandidáti ICE…" @@ -1873,7 +1974,7 @@ msgstr "Délka" msgid "Unknown-bug" msgstr "Neznámá chyba" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1881,7 +1982,7 @@ msgstr "" "Adresa SIP proxy, kterou jste zadali, není platná. Musí začínat na „sip:“ a " "pak musí následovat jméno stroje." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1889,128 +1990,124 @@ msgstr "" "SIP identita, kterou jste zadali, není platná.\n" "Měla by mít tvar sip:uživatel@proxydoména, například sip:alice@example.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Nelze se přihlásit jako %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Vyzvání na druhé straně." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "Vyzvání na druhé straně…" -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Časná média." -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "Hovor s %s je odložen." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "Hovor přijat kým: %s – odložen." -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "Hovor obnoven." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "Hovor přijat kým: %s." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "Není slučitelné. Zkontrolujte nastavení kodeků a zabezpečení…" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "Byli jsme obnoveni." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "Byli jsme odloženi protistranou." -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "Hovor byl aktualizován protistranou." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Hovor ukončen." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Uživatel je zaneprázdněn." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Uživatel je dočasně nedostupný." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "Uživatel si nepřeje být rušen." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Volání odmítnuto." -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "Žádná odpověď." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Chyba protokolu." - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Přesměrováno" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "Neslučitelné parametry médií." -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "Volání se nezdařilo." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Registrace na %s byla úspěšná." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Odregistrování z %s hotovo." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "odpověď nedorazila včas" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrace na %s selhala: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, c-format msgid "Authentication token is %s" msgstr "Klíč k ověření totožnosti je %s" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -2018,6 +2115,12 @@ msgstr[0] "Máte %i zmeškaný hovor." msgstr[1] "Máte %i zmeškané hovory." msgstr[2] "Máte %i zmeškaných hovorů." +#~ msgid "No response." +#~ msgstr "Žádná odpověď." + +#~ msgid "Protocol error." +#~ msgstr "Chyba protokolu." + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2373,9 +2476,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "Call answered - connected." #~ msgstr "Hovoř přijat – spojen." -#~ msgid "Assistant" -#~ msgstr "Průvodce" - #~ msgid "Show debug messages" #~ msgstr "Zobrazit ladicí zprávy" @@ -2693,9 +2793,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "RTP port used for audio:" #~ msgstr "RTP port pro zvuk:" -#~ msgid "RTP properties" -#~ msgstr "RTP vlastnosti" - #~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" #~ msgstr "Místo RTP rfc2833 použít pro DTMF přenos SIP INFO zprávu" @@ -2708,9 +2805,6 @@ msgstr[2] "Máte %i zmeškaných hovorů." #~ msgid "micro" #~ msgstr "mikrofon" -#~ msgid "Recording source:" -#~ msgstr "Zdroj nahrávání:" - #~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" #~ msgstr "Potlačit ozvěnu (projeví se na druhém konci)" diff --git a/po/de.po b/po/de.po index 95a385def..baec9ff8d 100644 --- a/po/de.po +++ b/po/de.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2012-11-07 19:27+0100\n" "Last-Translator: Gerhard Stengel \n" "Language-Team: German \n" @@ -17,57 +17,57 @@ msgstr "" "X-Generator: Lokalize 1.5\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "„%s“ anrufen" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Text zu „%s“ schicken" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "Im Gespräch" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "nicht verfügbar" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 msgid "Aborted" msgstr "Abgebrochen" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 msgid "Missed" msgstr "Entgangen" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 msgid "Declined" msgstr "Abgewiesen" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i Minute" msgstr[1] "%i Minuten" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i Sekunde" msgstr[1] "%i Sekunden" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, fuzzy, c-format msgid "" "%s\tQuality: %s\n" @@ -76,7 +76,7 @@ msgstr "" "%s\t%s\tQualität: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -96,37 +96,37 @@ msgstr "Eigenes Telefon" msgid "Couldn't find pixmap file: %s" msgstr "Pixmapdatei %s kann nicht gefunden werden." -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Ungültiger SIP-Kontakt!" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "Ausgabe von Debug-Informationen auf stdout während der Laufzeit" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "Pfad zu einer Datei, in die Protokolle geschrieben werden." -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "Linphone mit ausgeschaltetem Video starten." -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "" "Nur im Systemabschnitt der Kontrollleiste starten, aber das Hauptfenster " "nicht zeigen." -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "Im Moment anzurufende Adresse" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "Falls aktiviert, werden eingehende Anrufe automatisch beantwortet" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -134,17 +134,22 @@ msgstr "" "Geben Sie einen Arbeitsordner an (sollte der Installationsordner sein, z. B. " "C:\\Programme\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Bestätigung" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Konto-Einrichtungsassistent" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Im Gespräch mit %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -157,7 +162,7 @@ msgstr "" "Ihrer Kontaktliste hinzufügen?\n" "Wenn Sie mit Nein antworten, wird diese Person vorläufig blockiert." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -166,59 +171,59 @@ msgstr "" "Geben Sie bitte Ihr Passwort für den Benutzernamen %s\n" " auf der Domäne %s ein:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 msgid "Call error" msgstr "Anruf fehlgeschlagen" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Anruf beendet" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Annehmen" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Abweisen" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 msgid "Call paused" msgstr "Anruf wird gehalten" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, c-format msgid "by %s" msgstr "von %s" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s schlägt vor, eine Videoübertragung zu starten. Nehmen Sie an?" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Website-Verknüpfung" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - ein Internet-Video-Telefon" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (Vorgabe)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Vermittlung nach %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -226,7 +231,7 @@ msgstr "" "Auf diesem Rechner können keine Soundkarten gefunden werden.\n" "Sie können keine Audio-Anrufe tätigen oder entgegennehmen." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Ein freies SIP-Video-Telefon" @@ -238,7 +243,7 @@ msgstr "Zum Adressbuch hinzufügen" msgid "Presence status" msgstr "Anwesenheitsstatus" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Name" @@ -256,143 +261,143 @@ msgstr "Chat Raum" msgid "Search in %s directory" msgstr "Im %s-Verzeichnis suchen" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Kontakt „%s“ bearbeiten" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Kontakt „%s“ löschen" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Kontakt „%s“ löschen" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Einen neuen Kontakt aus dem %s-Verzeichnis hinzufügen" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Rate (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Min. Bitrate (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parameter" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Freigegeben" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Gesperrt" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Englisch" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Französisch" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Schwedisch" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Italienisch" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Spanisch" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "Brasilianisches Portugiesisch" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Polnisch" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Deutsch" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Russisch" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "Japanisch" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Niederländisch" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Ungarisch" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Tschechisch" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "Chinesisch" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "Traditionelles Chinesisch" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "Norwegisch" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Linphone muss neu gestartet werden, damit die neue Spracheinstellung wirksam " "wird." -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Keinen" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -538,40 +543,40 @@ msgstr "" "wir Ihnen soeben per E-Mail geschickt haben.\n" "Danach gehen Sie hierher zurück und drücken auf „Vor“." -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Willkommen zum Konto-Einrichtungsassistenten" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "Konto einrichten (Schritt 1/1)" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "Geben Sie Ihren SIP-Benutzernamen ein (Schritt 1/1)" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "Geben Sie Ihre Zugangsdaten ein (Schritt 1/2)" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "Bestätigung (Schritt 2/2)" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "Fehler" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "Fertigstellen" @@ -580,68 +585,68 @@ msgstr "Fertigstellen" msgid "Call #%i" msgstr "Anruf #%i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Vermittlung zum Anruf #%i mit %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "Nicht verwendet" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "ICE nicht aktiviert" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 msgid "ICE failed" msgstr "ICE fehlgeschlagen" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "ICE läuft" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "Ein oder mehrere NATs werden durchquert" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "Direkt" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "Über einen Relay-Server" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 #, fuzzy msgid "uPnP not activated" msgstr "ICE nicht aktiviert" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "ICE läuft" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "nicht verfügbar" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "ICE fehlgeschlagen" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" @@ -650,122 +655,122 @@ msgstr "" "Herunterladen: %f\n" "Hochladen: %f (kbit/s)" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i Sekunde" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Verbindungsaufbau..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "Eingehender Anruf" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "gut" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "durchschnittlich" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "schlecht" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "sehr schlecht" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "zu schlecht" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "nicht verfügbar" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "Gesichert durch SRTP" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Gesichert durch ZRTP - [Auth.-Token: %s]" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "Auf „Ungeprüft“ setzen" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Auf „Geprüft“ setzen" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "In Konferenz" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "Im Gespräch" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "Gehaltener Anruf" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Anruf beendet." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "Vermittlung läuft" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "Vermittlung abgeschlossen." -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 msgid "Transfer failed." msgstr "Vermittlung fehlgeschlagen." -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Fortsetzen" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Halten" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, fuzzy msgid "(Paused)" msgstr "Halten" @@ -785,6 +790,89 @@ msgstr "Eingehendes Gespr�h" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Willkommen!\n" +"Dieser Assistent wird Ihnen dabei helfen, ein SIP-Konto für Ihre Anrufe zu " +"verwenden." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Aufnahmegerät:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Aufnahmequelle:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Wiedergabegerät:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Konto-Einrichtungsassistent" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Konto-Einrichtungsassistent" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Name des Angerufenen" @@ -827,123 +915,123 @@ msgid "Call quality rating" msgstr "Bewertung der Verbindungsqualität" #: ../gtk/main.ui.h:17 +msgid "All users" +msgstr "Alle Teilnehmer" + +#: ../gtk/main.ui.h:18 +msgid "Online users" +msgstr "Angemeldete Teilnehmer" + +#: ../gtk/main.ui.h:19 +msgid "ADSL" +msgstr "" + +#: ../gtk/main.ui.h:20 +msgid "Fiber Channel" +msgstr "Glasfaserkabel" + +#: ../gtk/main.ui.h:21 +msgid "Default" +msgstr "Vorgabe" + +#: ../gtk/main.ui.h:22 msgid "_Options" msgstr "_Optionen" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Set configuration URI" msgstr "Proxy/Registrator Konfigurationsbox" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:24 msgid "Always start video" msgstr "Video immer starten" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:25 msgid "Enable self-view" msgstr "Selbstansicht ein" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:26 msgid "_Help" msgstr "_Hilfe" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:27 msgid "Show debug window" msgstr "Debug-Fenster anzeigen" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:28 msgid "_Homepage" msgstr "" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:29 msgid "Check _Updates" msgstr "Auf _Aktualisierungen überprüfen" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:30 msgid "Account assistant" msgstr "Konto-Einrichtungsassistent" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:32 msgid "SIP address or phone number:" msgstr "SIP-Adresse oder Telefonnummer:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:33 msgid "Initiate a new call" msgstr "Einen neuen Anruf beginnen" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:34 msgid "Contacts" msgstr "Kontakte" -#: ../gtk/main.ui.h:29 +#: ../gtk/main.ui.h:35 msgid "Search" msgstr "Suchen" -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:36 msgid "Add contacts from directory" msgstr "Kontakte aus einem Verzeichnis hinzufügen" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:37 msgid "Add contact" msgstr "Kontakt hinzufügen" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:38 msgid "Recent calls" msgstr "Letzte Gespräche" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:39 msgid "My current identity:" msgstr "Aktuelle Identität:" -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Benutzername" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passwort" -#: ../gtk/main.ui.h:36 +#: ../gtk/main.ui.h:42 msgid "Internet connection:" msgstr "Internetverbindung:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:43 msgid "Automatically log me in" msgstr "Automatisch anmelden" -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 msgid "UserID" msgstr "Benutzer-ID" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:45 msgid "Login information" msgstr "Anmeldeinformationen" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:46 msgid "Welcome !" msgstr "Willkommen !" -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "Alle Teilnehmer" - -#: ../gtk/main.ui.h:42 -msgid "Online users" -msgstr "Angemeldete Teilnehmer" - -#: ../gtk/main.ui.h:43 -msgid "ADSL" -msgstr "" - -#: ../gtk/main.ui.h:44 -msgid "Fiber Channel" -msgstr "Glasfaserkabel" - -#: ../gtk/main.ui.h:45 -msgid "Default" -msgstr "Vorgabe" - -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1068,23 +1156,32 @@ msgid "Contact params (optional):" msgstr "Route (optional):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Route (optional):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Übertragung" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "Registrieren" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Anwesenheitsstatus veröffentlichen" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Freigeben" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "SIP-Konto einrichten" @@ -1517,6 +1614,11 @@ msgid "Video resolution sent" msgstr "Bevorzugte Video-Auflösung:" #: ../gtk/call_statistics.ui.h:11 +#, fuzzy +msgid "RTP profile" +msgstr "RTP-Eingabefilter" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" msgstr "Anrufstatistik und -informationen" @@ -1723,19 +1825,19 @@ msgstr "Verbinden..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "abgebrochen" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "beendet" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "entgangen" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1750,77 +1852,77 @@ msgstr "" "Status: %s\n" "Dauer: %i min %i sec\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Abgehender Anruf" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Bereit" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Bestätigung" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Telefonnummernziel wird gesucht..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Diese Nummer kann nicht aufgelöst werden." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Verbindungsaufbau" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "Anruf kann nicht getätigt werden." -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Die maximale Anzahl der gleichzeitigen Anrufe ist erreicht." -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "ruft Sie an" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr " und fragt nach automatischer Antwort." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "Die Anrufparameter werden verändert..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Verbunden." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "Anruf abgebrochen" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "Anruf kann nicht gehalten werden" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Aktueller Anruf wird gehalten..." -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "STUN-Ermittlung läuft..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "Lokale Kandidaten für ICE werden zusammengestellt..." @@ -1877,7 +1979,7 @@ msgstr "Dauer" msgid "Unknown-bug" msgstr "Unbekannter Fehler" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1885,7 +1987,7 @@ msgstr "" "Die von Ihnen eingegebene SIP-Proxy-Adresse ist ungültig, sie muss mit " "„sip:“ gefolgt vom Hostnamen beginnen." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1894,135 +1996,137 @@ msgstr "" "Sie sollte wie sip:benutzername@proxydomain aussehen, also z.B. sip:" "alice@beispiel.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Anmeldung als %s fehlgeschlagen" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Klingeln bei der Gegenseite." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "Klingeln bei der Gegenseite..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "Anruf mit %s wird gehalten." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "Der von %s entgegengenommene Anruf wird gehalten." -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "Anruf fortgesetzt." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "Anruf wird von %s entgegengenommen." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Inkompatibel, überprüfen Sie die Codecs..." -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "Anruf wird fortgesetzt." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "Anruf wird von der Gegenseite gehalten." -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "Anruf ist von der Gegenseite aktualisiert worden." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Anruf beendet." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Teilnehmer ist besetzt." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Teilnehmer zur Zeit nicht verfügbar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "Teilnehmer möchte nicht gestört werden." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Anruf abgewiesen" -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "Keine Antwort." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Protokollfehler" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Umgeleitet" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "Inkompatible Medienparameter." -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "Anruf fehlgeschlagen." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Registrierung auf %s erfolgreich." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Abmeldung von %s ist erfolgt." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "Zeitüberschreitung bei der Antwort" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrierung auf %s fehlgeschlagen: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, c-format msgid "Authentication token is %s" msgstr "Authentifizierungs-Token ist %s" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Sie haben %i Anruf in Abwesenheit." msgstr[1] "Sie haben %i Anrufe in Abwesenheit." +#~ msgid "No response." +#~ msgstr "Keine Antwort." + +#~ msgid "Protocol error." +#~ msgstr "Protokollfehler" + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2208,9 +2312,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "RTP output filter" #~ msgstr "RTP-Ausgabefilter" -#~ msgid "RTP input filter" -#~ msgstr "RTP-Eingabefilter" - #~ msgid "The free and wonderful speex codec" #~ msgstr "Der freie und herrliche Speex-Codec" @@ -2623,9 +2724,6 @@ msgstr[1] "Sie haben %i Anrufe in Abwesenheit." #~ msgid "micro" #~ msgstr "Mikrofon" -#~ msgid "Recording source:" -#~ msgstr "Aufnahmequelle:" - #~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" #~ msgstr "" #~ "Echounterdrückung einschalten (eliminiert das von Gesprächspartnet " diff --git a/po/es.po b/po/es.po index 92bfad869..37021a332 100644 --- a/po/es.po +++ b/po/es.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2012-12-06 15:54+0100\n" "Last-Translator: BERAUDO Guillaume \n" "Language-Team: es \n" @@ -15,62 +15,62 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Llamar a %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Enviar mensaje a %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "En llamada " -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "n/a" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "abortada" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "perdida" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "Rechazar" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i minuto" msgstr[1] "%i minutos" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i segundo" msgstr[1] "%i segundos" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, fuzzy, c-format msgid "%s\t%s" msgstr "" "%s\t%s\tCalidad: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, fuzzy, c-format msgid "" "%s\tQuality: %s\n" @@ -79,7 +79,7 @@ msgstr "" "%s\t%s\tCalidad: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, fuzzy, c-format msgid "" "%s\t\n" @@ -101,36 +101,36 @@ msgstr "Yo" msgid "Couldn't find pixmap file: %s" msgstr "No se pudo encontrar el archivo pixmap: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "¡Contacto SIP no válido!" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "" "registra a stdout cierta información de depuración durante la ejecución." -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "ruta a un fichero donde escribir logs." -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Iniciar sólo en la barra de tareas, no mostrar la interfaz principal." -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "dirección a la que llamar inmediatamente" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "si está activo, responder a llamadas entrantes automáticamente" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -138,17 +138,22 @@ msgstr "" "Especifique un directorio de trabajo (debería ser la raíz de la instalación, " "ej: c:\\Archivos de Programa\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Confirmación" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Asistente de configuración de cuenta" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Llamar con %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -161,7 +166,7 @@ msgstr "" "contactos?\n" "Si responde no, esta persona será bloqueada temporalmente." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -170,63 +175,63 @@ msgstr "" "Por favor, introduzca la contraseña para el usuario %s\n" " en el dominio %s:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "Error en la llamada." -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 #, fuzzy msgid "Call ended" msgstr "Llamada terminada" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Contestar" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "Rechazar" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "Llamada en pausa" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Puertos" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Enlace a la Web" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - un video-teléfono a través de Internet" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (Opción predeterminada)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Somos transferidos a %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -234,7 +239,7 @@ msgstr "" "No se ha encontrado una tarjeta de sonido en este equipo.\n" "No será posible realizar o recibir llamadas de audio." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Un video-teléfono SIP gratuito" @@ -248,7 +253,7 @@ msgstr "Añadir a la agenda" msgid "Presence status" msgstr "Estado de Presencia" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nombre" @@ -266,142 +271,142 @@ msgstr "" msgid "Search in %s directory" msgstr "Buscar en el directorio %s" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Editar contacto '%s'" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Eliminar contacto '%s'" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Eliminar contacto '%s'" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Añadir nuevo contacto desde el directorio %s" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Frecuencia (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Estado" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Bitrate mínimo (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parámetros" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Activado" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Desactivado" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Cuenta" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Inglés" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Francés" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Sueco" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Español" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "Portugués de Brasil" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Polaco" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Alemán" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Ruso" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "Japonés" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Holandés" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Húngaro" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Checo" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "Chino" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "Chino Tradicional" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "Noruego" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Deberá reiniciar linphone para aplicar la nueva selección de lenguaje" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 #, fuzzy msgid "None" msgstr "Ninguno." -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "ZRTP" @@ -550,41 +555,41 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Asistente de configuración de cuenta" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Bienvenido al asistente de configuración de cuenta" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Asistente de configuración de cuenta" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Configurar una cuenta SIP" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "" @@ -593,199 +598,199 @@ msgstr "" msgid "Call #%i" msgstr "Llamar a #%i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Transferir a llamada #%i con %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 #, fuzzy msgid "Not used" msgstr "No encontrado" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "La llamada ha fallado." -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Redigirida" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "Búsqueda STUN en proceso…" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "no disponible" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "La llamada ha fallado." -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i segundo" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 #, fuzzy msgid "Calling..." msgstr " Llamando..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "Llamada entrante" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "buena" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "media" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "mala" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "muy mala" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "demasiado mala" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "no disponible" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "Cifrada con SRTP" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Cifrada con ZRTP - [token de autenticación: %s]" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "Set sin verificar" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Set verificado" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "En conferencia" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "En llamada " -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "Llamada en pausa" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 #, fuzzy msgid "Call ended." msgstr "Llamada finalizada." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 #, fuzzy msgid "Transfer done." msgstr "Transferir" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Transferir" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Reanudar" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pausar" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, fuzzy msgid "(Paused)" msgstr "Pausar" @@ -805,6 +810,88 @@ msgstr "" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"¡Bienvenido/a !\n" +"Este asistente le ayudará a utilizar una cuenta SIP para sus llamadas." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Dispositivo de captura:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Fuente de grabación:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Dispositivo de reproducción:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Asistente de configuración de cuenta" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Asistente de configuración de cuenta" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -851,138 +938,138 @@ msgid "Call quality rating" msgstr "Calidad de la llamada" #: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "_Opciones" - -#: ../gtk/main.ui.h:18 -#, fuzzy -msgid "Set configuration URI" -msgstr "Confirmación" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -#, fuzzy -msgid "Enable self-view" -msgstr "Activar vista propia" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "_Ayuda" - -#: ../gtk/main.ui.h:22 -#, fuzzy -msgid "Show debug window" -msgstr "Mostrar ventana de depuración" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "_Pagina_de_Inicio" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "Buscar_Actualizaciones" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "Account assistant" -msgstr "Asistente de configuración de cuenta" - -#: ../gtk/main.ui.h:26 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "Dirección SIP o número de teléfono" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "Iniciar nueva llamada" - -#: ../gtk/main.ui.h:28 -#, fuzzy -msgid "Contacts" -msgstr "Contactos" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "Buscar" - -#: ../gtk/main.ui.h:30 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Añadir contactos desde un directorio" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "Añadir contacto" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "Llamadas recientes " - -#: ../gtk/main.ui.h:33 -#, fuzzy -msgid "My current identity:" -msgstr "Mi identidad actual:" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "Nombre de usuario" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "Contraseña:" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "Conexión a Internet" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "Iniciar sesión automáticamente" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "UserID" - -#: ../gtk/main.ui.h:39 -#, fuzzy -msgid "Login information" -msgstr "Datos de inicio de sesión" - -#: ../gtk/main.ui.h:40 -#, fuzzy -msgid "Welcome !" -msgstr "¡Bienvenido/a!" - -#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Todos los usuarios" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:18 #, fuzzy msgid "Online users" msgstr "Usuarios conectados" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "ADSL" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 msgid "Fiber Channel" msgstr "Canal de Fibra" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Default" msgstr "Predeterminado" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "_Opciones" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "Confirmación" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +#, fuzzy +msgid "Enable self-view" +msgstr "Activar vista propia" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "_Ayuda" + +#: ../gtk/main.ui.h:27 +#, fuzzy +msgid "Show debug window" +msgstr "Mostrar ventana de depuración" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "_Pagina_de_Inicio" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "Buscar_Actualizaciones" + +#: ../gtk/main.ui.h:30 +#, fuzzy +msgid "Account assistant" +msgstr "Asistente de configuración de cuenta" + +#: ../gtk/main.ui.h:32 +#, fuzzy +msgid "SIP address or phone number:" +msgstr "Dirección SIP o número de teléfono" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "Iniciar nueva llamada" + +#: ../gtk/main.ui.h:34 +#, fuzzy +msgid "Contacts" +msgstr "Contactos" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "Buscar" + +#: ../gtk/main.ui.h:36 +#, fuzzy +msgid "Add contacts from directory" +msgstr "Añadir contactos desde un directorio" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "Añadir contacto" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "Llamadas recientes " + +#: ../gtk/main.ui.h:39 +#, fuzzy +msgid "My current identity:" +msgstr "Mi identidad actual:" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +#, fuzzy +msgid "Username" +msgstr "Nombre de usuario" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +#, fuzzy +msgid "Password" +msgstr "Contraseña:" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "Conexión a Internet" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "Iniciar sesión automáticamente" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "UserID" + +#: ../gtk/main.ui.h:45 +#, fuzzy +msgid "Login information" +msgstr "Datos de inicio de sesión" + #: ../gtk/main.ui.h:46 +#, fuzzy +msgid "Welcome !" +msgstr "¡Bienvenido/a!" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1115,24 +1202,33 @@ msgid "Contact params (optional):" msgstr "Ruta (opcional):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Ruta (opcional):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Transporte " -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "Registrarse" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 #, fuzzy msgid "Publish presence information" msgstr "Publicar información de presencia" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Activar" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Configurar una cuenta SIP" @@ -1594,6 +1690,10 @@ msgid "Video resolution sent" msgstr "Resolución de vídeo preferida:" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 #, fuzzy msgid "Call statistics and information" msgstr "Información de contacto" @@ -1801,19 +1901,19 @@ msgstr "Conectando..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "abortada" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "completada" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "perdida" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1828,82 +1928,82 @@ msgstr "" "Estado: %s\n" "Duración: %i min %i seg\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Llamada saliente" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 #, fuzzy msgid "Ready" msgstr "Preparado" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Confirmación" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Buscando el número de teléfono del destinatario…" -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "No se ha podido resolver este número." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 #, fuzzy msgid "Contacting" msgstr "Contactando" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "No se pudo llamar" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Disculpe, se ha alcanzado el máximo número de llamadas simultáneas" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 #, fuzzy msgid "is contacting you" msgstr "le está llamando" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "y ha solicitado auto respuesta." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "Modificando parámetros de llamada…" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Conectado." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "Llamada abortada" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "No se pudo pausar la llamada" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Pausando la llamada actual..." -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "Búsqueda STUN en proceso…" -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1964,7 +2064,7 @@ msgstr "Duración" msgid "Unknown-bug" msgstr "Bug-desconocido" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1972,7 +2072,7 @@ msgstr "" "La dirección del Proxy SIP que ha introducido no es válida, debe empezar con " "\"sip:\" seguido del hostname." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1981,141 +2081,143 @@ msgstr "" "Debe ser del tipo sip:username@proxydomain, como por ejemplo sip:" "alice@example.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, fuzzy, c-format msgid "Could not login as %s" msgstr "No se pudo iniciar sesión como %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 #, fuzzy msgid "Remote ringing." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "El destinatario está sonando..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Medios iniciales." -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "La llamada con %s está puesta en pausa." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "Llamada respondida por %s - en espera." -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "Llamada reanudada." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, fuzzy, c-format msgid "Call answered by %s." msgstr "Llamada respondida por %s." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 #, fuzzy msgid "We have been resumed." msgstr "Nos han reanudado..." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 #, fuzzy msgid "Call is updated by remote." msgstr "La llamada ha sido actualizada por el destinatario..." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 #, fuzzy msgid "Call terminated." msgstr "Llamada finalizada." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "El usuario está ocupado." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "El usuario no está disponible temporalmente." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "El usuario no quiere que le molesten." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Llamada rechazada." -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "No hay respuesta." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Error de protocolo." - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Redigirida" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 #, fuzzy msgid "Call failed." msgstr "La llamada ha fallado." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Se ha registrado con éxito en %s." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Cancelación de registro en %s completada." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "timeout sin respuesta" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "El registro en %s ha fallado." -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "El tóken de autenticación es%s" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Tiene %i llamada perdida." msgstr[1] "Tiene %i llamadas perdidas." +#~ msgid "No response." +#~ msgstr "No hay respuesta." + +#~ msgid "Protocol error." +#~ msgstr "Error de protocolo." + #, fuzzy #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" @@ -2389,9 +2491,6 @@ msgstr[1] "Tiene %i llamadas perdidas." #~ msgid "micro" #~ msgstr "micrófono" -#~ msgid "Recording source:" -#~ msgstr "Fuente de grabación:" - #~ msgid "Run sip user agent on port:" #~ msgstr "Ejecutar el agente de usuario SIP en el puerto:" diff --git a/po/fr.po b/po/fr.po index 9f45b8dbc..892b7f1c9 100644 --- a/po/fr.po +++ b/po/fr.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 0.9.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2013-04-09 13:57+0100\n" "Last-Translator: Simon Morlat \n" "Language-Team: french \n" @@ -15,57 +15,57 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Appeler %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Chatter avec %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, c-format msgid "Recent calls (%i)" msgstr "Appels récents (%i)" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "inconnu" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 msgid "Aborted" msgstr "Abandonné" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 msgid "Missed" msgstr "Manqué" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 msgid "Declined" msgstr "Refusé" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i seconde" msgstr[1] "%i secondes" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" @@ -74,7 +74,7 @@ msgstr "" "%s\tQualité: %s\n" "%s\t%s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -94,35 +94,35 @@ msgstr "Moi" msgid "Couldn't find pixmap file: %s" msgstr "Icone non trouvée: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Contact sip invalide !" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "affiche des informations de debogage" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "chemin vers le fichier de logs." -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "Démarrer linphone avec la vidéo désactivée." -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Démarre iconifié, sans interface principale." -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "adresse à appeler maintenant" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "si positionné, répond automatiquement aux appels entrants" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -130,16 +130,20 @@ msgstr "" "Spécifie un répertoire de travail (qui devrait être le répertoire " "d'installation, par exemple c:\\Program Files\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 msgid "Configuration file" msgstr "Ficher de configuration" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +msgid "Run the audio assistant" +msgstr "Démarre l'assistant audio" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Appel avec %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -153,7 +157,8 @@ msgstr "" "Si vous répondez non, cette personne sera mise temporairement sur liste " "noire." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 +#, c-format msgid "" "Please enter your password for username %s\n" " at realm %s:" @@ -161,59 +166,59 @@ msgstr "" "Entrez le mot de passe pour %s\n" " sur le domaine %s:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 msgid "Call error" msgstr "Erreur lors de l'appel" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Appel terminé." -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Répondre" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Refuser" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 msgid "Call paused" msgstr "Appel en pause" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, c-format msgid "by %s" msgstr "b>par %s" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s propose de démarrer la vidéo. Acceptez-vous ?" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Lien site web" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - un téléphone video pour l'internet" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (par défaut)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Transfert vers %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -221,7 +226,7 @@ msgstr "" "Aucune carte son n'a été détectée sur cet ordinateur.\n" "Vous ne pourrez pas effectuer d'appels audio." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Un visiophone libre" @@ -233,7 +238,7 @@ msgstr "Ajouter au carnet d'adresse" msgid "Presence status" msgstr "Info de présence" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nom" @@ -250,142 +255,142 @@ msgstr "" msgid "Search in %s directory" msgstr "Rechercher dans l'annuaire de %s" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Editer le contact '%s'" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Supprimer le contact '%s'" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, c-format msgid "Delete chat history of '%s'" msgstr "Supprimer l'historique de chat de '%s'" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Ajouter un contact depuis l'annuaire %s" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Fréquence (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Etat" -#: ../gtk/propertybox.c:574 -msgid "Bitrate (kbit/s)" -msgstr "Débit (kbit/s)" +#: ../gtk/propertybox.c:568 +msgid "IP Bitrate (kbit/s)" +msgstr "Débit IP (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Paramètres" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Activé" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Désactivé" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Compte" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Anglais" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Suédois" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Italien" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Espagnol" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "Portugais brésilien" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Polonais" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Allemand" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Russe" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Néérlandais" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Hongrois" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Tchèque" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "简体中文" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "Chinois traditionnel" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "Norvégien" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "Hébreu" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "Serbe" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "La nouvelle selection de langue prendra effet au prochain démarrage de " "linphone." -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Aucun" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -529,40 +534,39 @@ msgstr "" "par email.\n" "Puis appuyez sur suivant." -#: ../gtk/setupwizard.c:572 -#, fuzzy +#: ../gtk/setupwizard.c:564 msgid "SIP account configuration assistant" msgstr "Assistant de configuration de compte." -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Bienvenue dans l'assistant de configuration de compte." -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Assistant de configuration de compte." -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "Configurez votre compte (étape 1/1)" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "Entrez votre identifiant sip (étape 1/1)" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "Entrez les informations concernant votre compte (étape 1/2)" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "Validation (étape 2/2)" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "Erreur" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "En cours d’arrêt." @@ -571,186 +575,186 @@ msgstr "En cours d’arrêt." msgid "Call #%i" msgstr "Appel #%i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Transférer vers l'appel #%i avec %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "Non utilisé" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "ICE non activé" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 msgid "ICE failed" msgstr "Erreur ICE" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "Négociation ICE en cours" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "Via un ou plusieurs NATs" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "En direct" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "Via un serveur relais" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "uPnP non activé" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 msgid "uPnP in progress" msgstr "uPnP en cours" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "uPnP est indisponible" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "uPnP en cours d’exécution" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 msgid "uPnP failed" msgstr "uPnP a échoué." -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "Directe ou via un serveur" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Raccrocher" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Tentative d'appel..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "Appel entrant" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "bon" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "moyen" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "faible" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "très faible" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "nulle" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "indisponible" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "Sécurisé par SRTP" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Sécurisé par ZRTP- [jeton: %s]" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "Marquer comme non vérifié" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Marquer comme vérifié" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "En conférence" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "Appel en cours" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "Appel en attente" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Appel terminé." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "Transfert en cours" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "Transfert terminé" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 msgid "Transfer failed." msgstr "Transfert échoué" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Reprendre" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "(en attente)" @@ -769,6 +773,82 @@ msgstr "chargement depuis %s" msgid "Downloading of remote configuration from %s failed." msgstr "Le chargement de la configuration depuis %s a échoué." +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Bienvenue!\n" +"Cet assistant va vous aider à régler les paramètres audio de votre ordinateur pour une utilisation optimale avec Linphone." + +#: ../gtk/audio_assistant.c:326 +msgid "Capture device" +msgstr "Périphérique de capture" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "Volume enregistré" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "Silencieux" + +#: ../gtk/audio_assistant.c:367 +msgid "Playback device" +msgstr "Périphérique d'écoute" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "Joue trois bips" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "Appuyer sur le bouton enregistrer et dites quelques mots" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "Ecoutez votre voix enregistrée" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "Démarrons Linphone maintenant" + +#: ../gtk/audio_assistant.c:488 +msgid "Audio Assistant" +msgstr "Assistant audio" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +msgid "Audio assistant" +msgstr "Assistant audio" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "Calibration du gain du microphone" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "Calibration du volume du haut parleur" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "Enregistrer et joue" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Nom du correspondant" @@ -810,122 +890,122 @@ msgid "Call quality rating" msgstr "Qualité de l'appel" #: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -msgid "Set configuration URI" -msgstr "URI de configuration" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "Toujours démarrer la vidéo" - -#: ../gtk/main.ui.h:20 -msgid "Enable self-view" -msgstr "Se voir" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "_Aide" - -#: ../gtk/main.ui.h:22 -msgid "Show debug window" -msgstr "Fenêtre de débogage" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "_Site web" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Account assistant" -msgstr "Assistant de compte" - -#: ../gtk/main.ui.h:26 -msgid "SIP address or phone number:" -msgstr "Adresse SIP ou numéro" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "Démarrer un nouvel appel" - -#: ../gtk/main.ui.h:28 -msgid "Contacts" -msgstr "Contacts" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "Rechercher" - -#: ../gtk/main.ui.h:30 -msgid "Add contacts from directory" -msgstr "Ajouter un contact depuis l'annuaire" - -#: ../gtk/main.ui.h:31 -msgid "Add contact" -msgstr "Ajouter un contact." - -#: ../gtk/main.ui.h:32 -msgid "Recent calls" -msgstr "Appels récents" - -#: ../gtk/main.ui.h:33 -msgid "My current identity:" -msgstr "Mon identité sip:" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Nom d'utilisateur" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Mot de passe" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "Connexion internet:" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "Me connecter automatiquement" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "Login information" -msgstr "Information de login" - -#: ../gtk/main.ui.h:40 -msgid "Welcome !" -msgstr "Bienvenue !" - -#: ../gtk/main.ui.h:41 msgid "All users" msgstr "Tous" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:18 msgid "Online users" msgstr "En ligne" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 msgid "Default" msgstr "Par défaut" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +msgid "Set configuration URI" +msgstr "URI de configuration" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "Toujours démarrer la vidéo" + +#: ../gtk/main.ui.h:25 +msgid "Enable self-view" +msgstr "Se voir" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "_Aide" + +#: ../gtk/main.ui.h:27 +msgid "Show debug window" +msgstr "Fenêtre de débogage" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "_Site web" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:30 +msgid "Account assistant" +msgstr "Assistant de compte" + +#: ../gtk/main.ui.h:32 +msgid "SIP address or phone number:" +msgstr "Adresse SIP ou numéro" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "Démarrer un nouvel appel" + +#: ../gtk/main.ui.h:34 +msgid "Contacts" +msgstr "Contacts" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "Rechercher" + +#: ../gtk/main.ui.h:36 +msgid "Add contacts from directory" +msgstr "Ajouter un contact depuis l'annuaire" + +#: ../gtk/main.ui.h:37 +msgid "Add contact" +msgstr "Ajouter un contact." + +#: ../gtk/main.ui.h:38 +msgid "Recent calls" +msgstr "Appels récents" + +#: ../gtk/main.ui.h:39 +msgid "My current identity:" +msgstr "Mon identité sip:" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +msgid "Username" +msgstr "Nom d'utilisateur" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +msgid "Password" +msgstr "Mot de passe" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "Connexion internet:" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "Me connecter automatiquement" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + +#: ../gtk/main.ui.h:45 +msgid "Login information" +msgstr "Information de login" + #: ../gtk/main.ui.h:46 +msgid "Welcome !" +msgstr "Bienvenue !" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "Supprimer" @@ -1034,22 +1114,30 @@ msgid "Contact params (optional):" msgstr "Paramètres de contact (optionnel):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Route (optionnel):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 msgid "Transport" msgstr "Transport" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "S'enregistrer" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Publier la présence" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +msgid "Enable AVPF" +msgstr "Activer AVPF" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Configurer un compte SIP" @@ -1446,18 +1534,16 @@ msgid "Audio IP bandwidth usage" msgstr "Bande passante audio" #: ../gtk/call_statistics.ui.h:5 -#, fuzzy msgid "Audio Media connectivity" -msgstr "Type d'encryption media" +msgstr "Connectivité audio" #: ../gtk/call_statistics.ui.h:6 msgid "Video IP bandwidth usage" msgstr "Bande passante video" #: ../gtk/call_statistics.ui.h:7 -#, fuzzy msgid "Video Media connectivity" -msgstr "Type d'encryption media" +msgstr "Connectivité video" #: ../gtk/call_statistics.ui.h:8 msgid "Round trip time" @@ -1472,6 +1558,10 @@ msgid "Video resolution sent" msgstr "Taille de video envoyée" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "Profil RTP" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" msgstr "Statistiques de l'appel et informations" @@ -1481,7 +1571,7 @@ msgstr "Configuer le mode tunnel" #: ../gtk/tunnel_config.ui.h:2 msgid "Host" -msgstr "" +msgstr "Hôte" #: ../gtk/tunnel_config.ui.h:3 msgid "Port" @@ -1489,11 +1579,11 @@ msgstr "" #: ../gtk/tunnel_config.ui.h:6 msgid "Configure tunnel" -msgstr "" +msgstr "Configuration du tunnel" #: ../gtk/tunnel_config.ui.h:9 msgid "Configure http proxy (optional)" -msgstr "" +msgstr "Configuration d'un proxy http (optionel)" #: ../gtk/keypad.ui.h:1 msgid "D" @@ -1556,23 +1646,20 @@ msgid "1" msgstr "" #: ../gtk/ldap.ui.h:1 -#, fuzzy msgid "LDAP Settings" -msgstr "Réglages" +msgstr "Paramètres LDAP" #: ../gtk/ldap.ui.h:6 msgid "Use TLS Connection" -msgstr "" +msgstr "Utiliser TLS" #: ../gtk/ldap.ui.h:7 -#, fuzzy msgid "Not yet available" -msgstr "uPnP est indisponible" +msgstr "Non disponible" #: ../gtk/ldap.ui.h:8 -#, fuzzy msgid "Connection" -msgstr "Codecs" +msgstr "Connexion" #: ../gtk/ldap.ui.h:9 msgid "Bind DN" @@ -1587,9 +1674,8 @@ msgid "Realm" msgstr "" #: ../gtk/ldap.ui.h:12 -#, fuzzy msgid "SASL" -msgstr "Son" +msgstr "SASL" #: ../gtk/ldap.ui.h:13 msgid "Base object:" @@ -1605,35 +1691,32 @@ msgid "Name Attribute:" msgstr "" #: ../gtk/ldap.ui.h:17 -#, fuzzy msgid "SIP address attribute:" -msgstr "Adresse SIP ou numéro" +msgstr "Attribut pour l'addresse SIP:" #: ../gtk/ldap.ui.h:18 msgid "Attributes to query:" -msgstr "" +msgstr "Attributs à chercher:" #: ../gtk/ldap.ui.h:19 -#, fuzzy msgid "Search" -msgstr "Rechercher une personne" +msgstr "Rechercher" #: ../gtk/ldap.ui.h:20 msgid "Timeout for search:" -msgstr "" +msgstr "Temps de recherche maximum:" #: ../gtk/ldap.ui.h:21 msgid "Max results:" -msgstr "" +msgstr "Nombre de résultats maximum:" #: ../gtk/ldap.ui.h:22 msgid "Follow Aliases" -msgstr "" +msgstr "Suivre les alias" #: ../gtk/ldap.ui.h:23 -#, fuzzy msgid "Miscellaneous" -msgstr "Video" +msgstr "Divers" #: ../gtk/ldap.ui.h:24 msgid "ANONYMOUS" @@ -1653,7 +1736,7 @@ msgstr "" #: ../gtk/config-uri.ui.h:1 msgid "Specifying a remote configuration URI" -msgstr "" +msgstr "Spécifier une URI de configuration" #: ../gtk/config-uri.ui.h:2 msgid "" @@ -1662,8 +1745,11 @@ msgid "" "Please enter or modify the configuration URI below. After clicking OK, " "Linphone will restart automatically in order to fetch and take into account " "the new configuration. " -msgstr "Cette boite de dialogue vous permet de spécifier une address http ou https où la configuration doit être téléchargée au démarrage\n" -"Entry l'URI ci dessous. Après avoir validé, Linphone va redémarrer automatiquement pour charger et prendre en compte la nouvelle configuration." +msgstr "" +"Cette boite de dialogue vous permet de spécifier une addresse http ou https " +"où la configuration doit être téléchargée au démarrage.\n" +"Veuillez entrer l'URI http(s) ci dessous. Après avoir validé, Linphone va redémarrer " +"automatiquement pour charger et prendre en compte la nouvelle configuration." #: ../gtk/config-uri.ui.h:4 msgid "https://" @@ -1675,21 +1761,23 @@ msgstr "Configuration en cours" #: ../gtk/provisioning-fetch.ui.h:2 msgid "Please wait while fetching configuration from server..." -msgstr "Veuillez patenter un instant pendant le chargement de la configuration distante..." +msgstr "" +"Veuillez patenter un instant pendant le chargement de la configuration " +"distante..." -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "abandonné" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "terminé" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "manqué" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1704,76 +1792,76 @@ msgstr "" "Etat: %s\n" "Durée: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Appel sortant" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Prêt." -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 msgid "Configuring" msgstr "Configuration en cours" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Recherche de la destination du numéro de téléphone..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "La destination n'a pu être trouvée." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Appel de" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "Echec de l'appel" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Désolé, le nombre maximum d'appels simultanés est atteint." -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "vous appelle" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "et sollicite un décrochage automatique." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "Modifications des paramètres d'appels..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "En ligne." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "Appel abandonné" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "La mise en attente a échoué" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Mise en attente de l'appel..." -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "Découverte STUN en cours" -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1829,7 +1917,7 @@ msgstr "En congé" msgid "Unknown-bug" msgstr "Bug inconnu" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1837,7 +1925,7 @@ msgstr "" "L'adresse SIP du proxy est invalide. Elle doit commencer par \"sip:\" suivie " "par un nom de domaine." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1846,135 +1934,137 @@ msgstr "" "Elle doit être de la forme sip:username@domain, comme par example sip:" "alice@example.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Echec de la connexion en tant que %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Sonnerie distante." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "Sonnerie distante..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Prise d'appel anticipée." -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "%s est maintenant en attente." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "Appel répondu par %s - en attente" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "Appel repris." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "Appel répondu par %s." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "Appel repris." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "L'appel a été mis en attente." -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 #, fuzzy msgid "Call is updated by remote." -msgstr "L'appel a été repris par le correspondant." +msgstr "Mise à jour de l'appel par le correspondant." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Appel terminé." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Occupé..." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "L'usager est temporairement indisponible." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "L'usager ne souhaite pas être dérangé" -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Appel décliné." -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "Pas de réponse." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Erreur de protocole" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Redirection" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "Paramètres media incompatibles." -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "L'appel a échoué." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Enregistrement sur %s effectué." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Désenregistrement sur %s effectué." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "Pas de réponse" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Echec de l'enregistrement sur %s: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, c-format msgid "Authentication token is %s" msgstr "Le jeton d'authentification est %s" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Vous avez manqué %i appel" msgstr[1] "Vous avez manqué %i appels" +#~ msgid "No response." +#~ msgstr "Pas de réponse." + +#~ msgid "Protocol error." +#~ msgstr "Erreur de protocole" + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" diff --git a/po/he.po b/po/he.po index bcbfa9161..878ac3e4a 100644 --- a/po/he.po +++ b/po/he.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.5.99.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2013-04-24 21:31+0200\n" "Last-Translator: Isratine Citizen \n" "Language-Team: Rahut Project \n" @@ -20,57 +20,57 @@ msgstr "" "X-Generator: Poedit 1.5.4\n" # צור קשר עם -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "התקשר אל %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "שלח טקסט אל %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, c-format msgid "Recent calls (%i)" msgstr "שיחות אחרונות (%i)" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "לא זמין (n/a)" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 msgid "Aborted" msgstr "ננטשה" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 msgid "Missed" msgstr "הוחמצה" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 msgid "Declined" msgstr "נדחתה" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "דקה %i" msgstr[1] "%i דקות" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "שניה %i" msgstr[1] "%i שניות" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" @@ -79,7 +79,7 @@ msgstr "" "%s\tאיכות: %s\n" "%s\t%s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -100,48 +100,48 @@ msgid "Couldn't find pixmap file: %s" msgstr "לא ניתן למצוא קובץ ‫pixmap: ‫%s" # איש־קשר -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "כתובת sip לא תקפה !" # cli -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 #, fuzzy msgid "log to stdout some debug information while running." msgstr "רשום אל stdout מידע ניפוי שגיאות מסוים בזמן ביצוע." # cli -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 #, fuzzy msgid "path to a file to write logs into." msgstr "נתיב אל קובץ שברצונך לרשום אליו את הרשומות." # cli -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 #, fuzzy msgid "Start linphone with video disabled." msgstr "התחל את לינפון עם וידאו מנוטרל." # cli -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 #, fuzzy msgid "Start only in the system tray, do not show the main interface." msgstr "התחל במגש המערכת בלבד, אל תציג את הממשק הראשי." # cli -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 #, fuzzy msgid "address to call right now" msgstr "כתובת להתקשרות ברגע זה" # cli -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 #, fuzzy msgid "if set automatically answer incoming calls" msgstr "באם אפשרות זו נקבעת ענה אוטומטית לקריאות נכנסות" # cli -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 #, fuzzy msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" @@ -151,19 +151,24 @@ msgstr "" "\\Linphone)" # וידוא -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "אימות" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "אשף הגדרת חשבון" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "התקשרות באמצעות %s" # הקשר שלהם # אם התשובה -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -176,7 +181,7 @@ msgstr "" "שלך ?\n" "היה ותשובתך תהיה לא, אדם זה יהיה מסומן באופן זמני ברשימה השחורה." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -186,65 +191,65 @@ msgstr "" " בתחום %s:" # שיחה -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 msgid "Call error" msgstr "שגיאת קריאה" # Conversation ended -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "שיחה הסתיימה" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "לענות" # דחיה -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "לדחות" # Conversation paused -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 msgid "Call paused" msgstr "שיחה הושהתה" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, c-format msgid "by %s" msgstr "על ידי %s" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "‏%s רוצה להתחיל וידאו. האם אתה מסכים ?" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "קישור אתר רשת" # ‫Linphone - וידאופון במרשתת -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "‫Linphone - וידאופון אינטרנטי" # משתמטת -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "‫%s (ברירת מחדל)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "אנחנו מועברים אל %s" # קריאות שמע -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -252,7 +257,7 @@ msgstr "" "לא אותרו כרטיסי קול במחשב זה.\n" "לא תהיה ביכולתך לשלוח או לקבל שיחות אודיו." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "וידאופון SIP חופשי" @@ -264,7 +269,7 @@ msgstr "הוסף אל ספר כתובות" msgid "Presence status" msgstr "מצב נוכחות" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "שם" @@ -282,148 +287,148 @@ msgstr "שיחה" msgid "Search in %s directory" msgstr "חיפוש במדור %s" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "ערוך איש קשר '%s'" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "מחק איש קשר '%s'" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, c-format msgid "Delete chat history of '%s'" msgstr "מחק היסטוריית שיחה של '%s'" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "הוסף איש קשר חדש מן מדור %s" # קצב תדר תדירות מהירות -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "שיעור (הרץ)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "מצב" # שיעור סיביות מינימלי -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "קצב נתונים מינימלי (קי״ב/שנ׳)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "פרמטרים" # מאופשר -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "מופעל" # מנוטרל -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "לא מופעל" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "חשבון" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "English" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Svenska" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Español" # português do Brasil -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "português brasileiro" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Polski" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Deutsch" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Русский" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Nederlands" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Magyar" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Česky" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "中文" # 繁体字 -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "繁體字" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "norsk" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "עברית" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "српски srpski" # selected הנבחרת -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "עליך לאתחל את לינפון כדי שהשפה החדשה תיכנס לתוקף." -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "ללא" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -570,44 +575,44 @@ msgstr "" "נא לאמת את חשבונך באמצעות הקלקה על הקישור ששלחנו לך עתה באמצעות דוא״ל.\n" "אחרי כן נא לחזור לכאן וללחוץ על הלחצן 'קדימה'." -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "אשף הגדרת חשבון" # Wizard אשף # סייע -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "ברוך בואך אל אשף הגדרת החשבון" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "אשף הגדרת חשבון" # שלב -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "הגדרת חשבונך (צעד 1/1)" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "הזנת שם משתמש sip (צעד 1/1)" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "הזנת מידע חשבון (צעד 1/2)" # תקפות -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "אימות (צעד 2/2)" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "שגיאה" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "מסיים כעת" @@ -616,64 +621,64 @@ msgstr "מסיים כעת" msgid "Call #%i" msgstr "שיחה מס׳ %i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "העברה אל שיחה מס׳ %i עם %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "לא בשימוש" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "‏ICE לא מופעלת" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 msgid "ICE failed" msgstr "‏ICE נכשלה" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "‏ICE מצויה כעת בעיצומה" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "עובר דרך NAT אחד או יותר" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "ישיר" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "דרך שרת ממסר" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "‏uPnP לא מופעלת" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 msgid "uPnP in progress" msgstr "‏uPnP מצויה כעת בעיצומה" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "‏uPnp לא זמינה" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "‏uPnP מורצת כעת" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 msgid "uPnP failed" msgstr "‏uPnP נכשלה" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "ישיר או דרך שרת" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" @@ -682,122 +687,122 @@ msgstr "" "הורדה: %f\n" "העלאה: %f (קי״ב/שנ׳)" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "%.3f שניות" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "נתק" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "מתקשר כעת..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "‭00::00::00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "קריאה נכנסת" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "טובה" # רגילה -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "ממוצעת" # weak חלשה חלושה רפויה רופפת -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "דלה" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "דלה מאוד" # רעה -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "גרועה מדי" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "לא זמינה" # באמצעות -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "מאובטחת על ידי SRTP" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "מאובטחת על ידי ZRTP - [אות אימות: %s]" # set or unset verification state of ZRTP SAS. -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "הגדר כלא מאומתת" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "הגדר כמאומתת" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "בשיחת ועידה" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "בשיחה כעת" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "שיחה מושהית" # שעות %02i דקות %02i שניות %02i # Force LTR time format (hours::minutes::seconds) with LRO chatacter (U+202D) -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "‭%02i::%02i::%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "שיחה הסתיימה." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "העברה מצויה כעת בעיצומה" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "העברה הסתיימה." -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 msgid "Transfer failed." msgstr "העברה נכשלה." -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "חזור" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "השהה" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" @@ -806,7 +811,7 @@ msgstr "" "מקליט אל תוך\n" "%s %s" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "(מושהה)" @@ -825,6 +830,87 @@ msgstr "" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"ברוך בואך !\n" +"אשף זה יסייע לך לעשות שימוש בחשבון SIP עבור שיחותייך." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "התקן לכידה:" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "התקן פס קול:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "אשף חשבון" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "אשף חשבון" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + # מתקשר Caller # זה ש: נתקשר או מתוקשר או הותקשר? #: ../gtk/main.ui.h:1 @@ -869,128 +955,128 @@ msgid "Call quality rating" msgstr "אומדן איכות שיחה" #: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "_אפשרויות" - -# וידוא -#: ../gtk/main.ui.h:18 -#, fuzzy -msgid "Set configuration URI" -msgstr "אימות" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "התחל תמיד וידאו" - -#: ../gtk/main.ui.h:20 -msgid "Enable self-view" -msgstr "אפשר ראות-עצמית" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "_עזרה" - -#: ../gtk/main.ui.h:22 -msgid "Show debug window" -msgstr "הצג חלון ניפוי שגיאות" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "_עמוד הבית" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "בדיקת _עדכונים" - -#: ../gtk/main.ui.h:25 -msgid "Account assistant" -msgstr "אשף חשבון" - -#: ../gtk/main.ui.h:26 -msgid "SIP address or phone number:" -msgstr "כתובת SIP או מספר טלפון" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "התחל שיחה חדשה" - -#: ../gtk/main.ui.h:28 -msgid "Contacts" -msgstr "אנשי קשר" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "חיפוש" - -#: ../gtk/main.ui.h:30 -msgid "Add contacts from directory" -msgstr "הוסף אנשי קשר מן מדור" - -#: ../gtk/main.ui.h:31 -msgid "Add contact" -msgstr "הוסף איש קשר" - -# קריאות אחרונות -#: ../gtk/main.ui.h:32 -msgid "Recent calls" -msgstr "שיחות אחרונות" - -# הזהות הנוכחית שלי -#: ../gtk/main.ui.h:33 -msgid "My current identity:" -msgstr "זהותי הנוכחית:" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "שם משתמש" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "סיסמה" - -# מרשתת -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "חיבור אינטרנט:" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "חבר אותי אוטומטית" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "מזהה משתמש" - -#: ../gtk/main.ui.h:39 -msgid "Login information" -msgstr "מידע התחברות" - -#: ../gtk/main.ui.h:40 -msgid "Welcome !" -msgstr "ברוך בואך !" - -#: ../gtk/main.ui.h:41 msgid "All users" msgstr "כל המשתמשים" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:18 msgid "Online users" msgstr "משתמשים מקוונים" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "‫ADSL" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 msgid "Fiber Channel" msgstr "ערוץ סיב" # משתמט -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 msgid "Default" msgstr "ברירת מחדל" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "_אפשרויות" + +# וידוא +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "אימות" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "התחל תמיד וידאו" + +#: ../gtk/main.ui.h:25 +msgid "Enable self-view" +msgstr "אפשר ראות-עצמית" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "_עזרה" + +#: ../gtk/main.ui.h:27 +msgid "Show debug window" +msgstr "הצג חלון ניפוי שגיאות" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "_עמוד הבית" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "בדיקת _עדכונים" + +#: ../gtk/main.ui.h:30 +msgid "Account assistant" +msgstr "אשף חשבון" + +#: ../gtk/main.ui.h:32 +msgid "SIP address or phone number:" +msgstr "כתובת SIP או מספר טלפון" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "התחל שיחה חדשה" + +#: ../gtk/main.ui.h:34 +msgid "Contacts" +msgstr "אנשי קשר" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "חיפוש" + +#: ../gtk/main.ui.h:36 +msgid "Add contacts from directory" +msgstr "הוסף אנשי קשר מן מדור" + +#: ../gtk/main.ui.h:37 +msgid "Add contact" +msgstr "הוסף איש קשר" + +# קריאות אחרונות +#: ../gtk/main.ui.h:38 +msgid "Recent calls" +msgstr "שיחות אחרונות" + +# הזהות הנוכחית שלי +#: ../gtk/main.ui.h:39 +msgid "My current identity:" +msgstr "זהותי הנוכחית:" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +msgid "Username" +msgstr "שם משתמש" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +msgid "Password" +msgstr "סיסמה" + +# מרשתת +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "חיבור אינטרנט:" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "חבר אותי אוטומטית" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "מזהה משתמש" + +#: ../gtk/main.ui.h:45 +msgid "Login information" +msgstr "מידע התחברות" + #: ../gtk/main.ui.h:46 +msgid "Welcome !" +msgstr "ברוך בואך !" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "מחק" @@ -1105,24 +1191,33 @@ msgid "Contact params (optional):" msgstr "ניתוב (רשות):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "ניתוב (רשות):" # מוביל -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "טרנספורט" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "רישום" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "פרסם מידע נוכחות" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "אפשר" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "הגדרת חשבון ‫SIP" @@ -1567,6 +1662,10 @@ msgid "Video resolution sent" msgstr "רזולוציית וידאו מועדפת:" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" msgstr "סטטיסטיקות ומידע שיחה" @@ -1773,20 +1872,20 @@ msgstr "מתחבר כעת..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "ננטשה" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "הסתיימה" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "הוחמצה" # needs to be tested -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1801,81 +1900,81 @@ msgstr "" "מצב: %s\n" "משך: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "קריאה יוצאת" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "מוכן" # וידוא -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "אימות" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "מחפש כעת עבור יעד מספר טלפון..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "לא ניתן לפתור את מספר זה." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "מתקשר כעת" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "לא ניתן להתקשר" # מספר השיחות המקבילות המרבי -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "הגענו אל המספר המרבי של שיחות מקבילות, עמך הסליחה" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "מתקשר/ת אליך" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr " ומבקש/ת מענה אוטומטי." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" # פרמטרי קריאה -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "מתאים כעת פרמטרים של שיחה..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "מקושר." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "קריאה בוטלה" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "לא ניתן להשהות את השיחה" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "משהה כעת שיחה נוכחית..." # במהלך (או) באמצע חיפוש... -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "בדיקת STUN מצויה כעת בעיצומה..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "צבירת מועמדים מקומיים של ICE מצויה כעת בעיצומה..." @@ -1937,7 +2036,7 @@ msgstr "משך זמן" msgid "Unknown-bug" msgstr "תקלה לא מוכרת" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1945,7 +2044,7 @@ msgstr "" "כתובת sip proxy שהזנת הינה שגויה, זו צריכה להתחיל עם‭\"sip:\" ‬ לאחר שם מארח." # כמו למשל -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1954,40 +2053,40 @@ msgstr "" "זו צריכה להיראות כמו sip:username@proxydomain, למשל sip:alice@example.net" # בשם כ־ -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "לא ניתן להתחבר בזהות %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "צלצול מרוחק." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "צלצול מרוחק..." # A SIP state -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "מדיה מוקדמת." -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "שיחה עם %s מושהית." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "קריאה נענתה על ידי %s - בהמתנה." # renewed -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "קריאה חודשה." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "קריאה נענתה על ידי %s." @@ -1995,106 +2094,108 @@ msgstr "קריאה נענתה על ידי %s." # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "חוסר תאימות, בדוק קודקים או הגדרות אבטחה..." -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "חזרנו." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "אנו מושהים על ידי צד אחר." # באופן מרוחק -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "שיחה עודכנה מרחוק." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "קריאה הסתיימה." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "משתמש עסוק כעת." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "משתמש לא זמין זמנית." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "משתמש לא מעוניין שיפריעו לו." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "קריאה סורבה." -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "אין תגובה." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "שגיאת פרוטוקול." - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "מכוון מחדש" # לא תואם # אי תאימות # אי התאמה -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "פרמטריי מדיה חסרי תואמים." -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "קריאה נכשלה." # הרשמה אצל %s הושלמה בהצלחה. -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "רישום אצל %s הושלם בהצלחה." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "אי רישום אצל %s סוים." # Pas de réponse # no response in defined time -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "אין היענות תוך זמן מוגדר" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "רישום אצל %s נכשל: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, c-format msgid "Authentication token is %s" msgstr "אות האימות הינה %s" # האם כדאי לחקות את הטלפונים הניידים? שיחות של נענו -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "החמצת שיחה %i." msgstr[1] "החמצת %i שיחות." +#~ msgid "No response." +#~ msgstr "אין תגובה." + +#~ msgid "Protocol error." +#~ msgstr "שגיאת פרוטוקול." + # לרוב #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" diff --git a/po/hu.po b/po/hu.po index fb2e08033..d69f7e8bc 100644 --- a/po/hu.po +++ b/po/hu.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2013-03-26 19:00+0100\n" "Last-Translator: Viktor \n" "Language-Team: \n" @@ -17,57 +17,57 @@ msgstr "" "X-Generator: Poedit 1.5.4\n" "Plural-Forms: nplurals=1; plural=1 == 1 ? 0 : 1;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "%s hívása" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Szöveg küldése a következőnek: %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "vonalban" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "-" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 msgid "Aborted" msgstr "Megszakítva" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 msgid "Missed" msgstr "Nem fogadott" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 msgid "Declined" msgstr "Elutasítva" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "%i perc" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "%i másodperc" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, fuzzy, c-format msgid "%s\t%s" msgstr "" "%s\t%s\t\n" "%s\t%s" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, fuzzy, c-format msgid "" "%s\tQuality: %s\n" @@ -76,7 +76,7 @@ msgstr "" "%s\t%s\tMinőség: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, fuzzy, c-format msgid "" "%s\t\n" @@ -98,35 +98,35 @@ msgstr "én" msgid "Couldn't find pixmap file: %s" msgstr "Nemtalálható a pixmap fájl: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Érvénytelen sip partner !" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "Futás közben némi hibakeresési információ az stdout-ra naplózása." -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "fájl elérési útja, melybe a naplók kerülnek." -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "Linphone indítása, videó kikpacsolva. " -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Csak a tálcaikon indítása, ne mutassa a fő ablakot." -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "Cím azonnali híváshoz" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "Bekapcsolva automatikusan válaszol a bejövő hívásokra" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -134,17 +134,22 @@ msgstr "" "Adjon meg egy munkakönyvtárat (ennek az installációs könyvtárnak kéne " "lennie, pl. C:\\Program Files\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Információk" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Fiók beállítása varázsló" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Hívás %s -el" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -157,7 +162,7 @@ msgstr "" "szeretné adni a partnerlistához?\n" "Ha nemmel válaszol, ez a személy átmenetileg tiltólistára kerül." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -166,59 +171,59 @@ msgstr "" "Kérem, adja meg jelszavát a következő felhasználónévhez: %s\n" "tartomány %s:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 msgid "Call error" msgstr "Hiba a hívás közben" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Hívás vége" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Hívás fogadása" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Elutasítás" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 msgid "Call paused" msgstr "Hívás várakoztatva" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, c-format msgid "by %s" msgstr "a következő által: %s" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "%s szerené elidítani a videót. Elfogadja?" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Internetes oldal" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - internetes videó telefon" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (Alapértelmezett)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Át vagyunk irányítva ide: %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -226,7 +231,7 @@ msgstr "" "Hangkártya nincs érzékelve ezen a számítógépen.\n" "Nem fog tudni hang hívásokat küldeni vagy fogadni." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Egy ingyenes SIP video-telefon" @@ -238,7 +243,7 @@ msgstr "Hozzáadás címjegyzékhez" msgid "Presence status" msgstr "Jelenlét státusz" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Név" @@ -255,143 +260,143 @@ msgstr "Csevegés" msgid "Search in %s directory" msgstr "Keresés ebben a könyvtárban: %s" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Kapcsolatinformációk szerkesztése: '%s'" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "'%s' partner törlése" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "'%s' partner törlése" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Új partner hozzáadása ebből a könyvtárból: %s" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Érték (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Állapot" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Min bitrate (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Paraméterek" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Engedélyezve" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Tiltva" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Hozzáférés" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "angol" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "francia" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "svéd" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "olasz" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "spanyol" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "brazil-portugál" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "lengyel" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "német" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "orosz" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "japán" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "holland" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "magyar" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "cseh" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "egyszerúsített kínai" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "tradícionális kínai" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "norvég" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "héber" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Újra kell indítania a linphone-t, hogy az új nyelv kiválasztása érvényre " "jusson. " -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Nincs" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "ZRTP" @@ -533,40 +538,40 @@ msgstr "" "hivatkozásra kattintva.\n" "Azután térjen vissza ide és kattintson a Következő gombra." -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Fiók beállítása varázsló" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "A fiók beállítása varázsló üdvözli Önt" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Fiók beállítása varázsló" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "Az Ön fiókjának beállítása (1/1 lépés)" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "Adja meg sip felhasználónevét (1/2 lépés)" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "Adja meg a fiókinformációt (1/2 lépés)" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "Érvényesítés (2/2 lépés)" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "Hiba" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "Befejezés" @@ -575,64 +580,64 @@ msgstr "Befejezés" msgid "Call #%i" msgstr "Hívás #%i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Átirányítás #%i híváshoz ezzel: %s " -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "Nem használt" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "ICE nincs aktiválva" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 msgid "ICE failed" msgstr "ICE nem sikerült" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "ICE folyamatban" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "Átmegy egy vagy több NAT-on" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "Közvetlen" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "Közvetítő kiszolgálón keresztül" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "uPnP nincs aktiválva" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 msgid "uPnP in progress" msgstr "uPnP folyamatban" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "uPnP nem elérhető" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "uPnP fut" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 msgid "uPnP failed" msgstr "uPnP nem sikerült" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "közvetlen vagy kiszolgálón keresztül" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" @@ -641,115 +646,115 @@ msgstr "" "letöltés: %f\n" "feltöltés: %f (kbit/mp)" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "%.3f másodperc" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "Befejezés" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Hívás folyamatban..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "Beérkező hívás" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "jó" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "közepes" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "gyenge" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "nagyon gyenge" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "rossz" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "nem elérhető" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "SRTP-vel titkosítva" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "ZRTP-vel titkosítva - [hitelesítési jel: %s]" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "Beállítás ellenőrizetlenként" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Beállítás ellenőrzöttként" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "Konferencián" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "vonalban" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "Várakoztatott hívás" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Hívás vége." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "Átvitel folyamatban" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "Átvitel befejezve." -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 msgid "Transfer failed." msgstr "Az átvitel sikertelen." -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Visszatérés" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Várakoztatás" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" @@ -758,7 +763,7 @@ msgstr "" "Felvétel a következőbe\n" "%s %s" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "(Várakoztatva)" @@ -777,6 +782,88 @@ msgstr "Beérkező hívás" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Üdvözöljük !\n" +"Ez a varázsló segít Önnek, hogy sip fiókot használjon hívásaihoz." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Felvevő hang eszköz:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Felvételi forrás:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Lejátszó hang eszköz:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Fiók varázsló" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Fiók varázsló" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Hívott neve" @@ -818,123 +905,123 @@ msgid "Call quality rating" msgstr "Hívásminőség" #: ../gtk/main.ui.h:17 +msgid "All users" +msgstr "Minden felhasználó" + +#: ../gtk/main.ui.h:18 +msgid "Online users" +msgstr "Elérhető" + +#: ../gtk/main.ui.h:19 +msgid "ADSL" +msgstr "ADSL" + +#: ../gtk/main.ui.h:20 +msgid "Fiber Channel" +msgstr "Fiber csatorna" + +#: ../gtk/main.ui.h:21 +msgid "Default" +msgstr "Alapértelmezett" + +#: ../gtk/main.ui.h:22 msgid "_Options" msgstr "_Beállítások" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Set configuration URI" msgstr "Proxy/Regisztráció konfigurációs doboz" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:24 msgid "Always start video" msgstr "Videó indítása mindig" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:25 msgid "Enable self-view" msgstr "Saját nézet" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:26 msgid "_Help" msgstr "_Segítség" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:27 msgid "Show debug window" msgstr "Hibakeresési ablak mutatása" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:28 msgid "_Homepage" msgstr "_Honlap" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:29 msgid "Check _Updates" msgstr "Frissítések keresése" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:30 msgid "Account assistant" msgstr "Fiók varázsló" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:32 msgid "SIP address or phone number:" msgstr "Adja meg a SIP címet vagy a telefonszámot:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:33 msgid "Initiate a new call" msgstr "Új hívás kezdeményezése" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:34 msgid "Contacts" msgstr "Partnerek" -#: ../gtk/main.ui.h:29 +#: ../gtk/main.ui.h:35 msgid "Search" msgstr "Keresés" -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:36 msgid "Add contacts from directory" msgstr "Partnerek hozzáadása könyvtárból" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:37 msgid "Add contact" msgstr "Partner hozzáadása" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:38 msgid "Recent calls" msgstr "Legutóbbi hívások" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:39 msgid "My current identity:" msgstr "Jelenlegi identitásom:" -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Felhasználónév" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Jelszó" -#: ../gtk/main.ui.h:36 +#: ../gtk/main.ui.h:42 msgid "Internet connection:" msgstr "Internet kapcsolat:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:43 msgid "Automatically log me in" msgstr "Jelentkeztessen be automatikusan" -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 msgid "UserID" msgstr "Felhasználó azonosító" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:45 msgid "Login information" msgstr "Bejelentkezési információ" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:46 msgid "Welcome !" msgstr "Üdvözöljük !" -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "Minden felhasználó" - -#: ../gtk/main.ui.h:42 -msgid "Online users" -msgstr "Elérhető" - -#: ../gtk/main.ui.h:43 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/main.ui.h:44 -msgid "Fiber Channel" -msgstr "Fiber csatorna" - -#: ../gtk/main.ui.h:45 -msgid "Default" -msgstr "Alapértelmezett" - -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "Törlés" @@ -1058,23 +1145,32 @@ msgid "Contact params (optional):" msgstr "Út (nem kötelező):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Út (nem kötelező):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Átvitel" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "Regisztráció" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Jelenléti információ közlése" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Engedélyezés" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "SIP fiók beállítása" @@ -1500,6 +1596,10 @@ msgid "Video resolution sent" msgstr "Kívánt videó felbontás:" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 msgid "Call statistics and information" msgstr "Hívási statisztika és információ" @@ -1706,19 +1806,19 @@ msgstr "Kapcsolódás..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "megszakítva" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "befejezve" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "elhibázva" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1733,77 +1833,77 @@ msgstr "" "Állapot: %s\n" "Időtartam: %i perc %i másodperc\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Kimenő hívás" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Kész" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Információk" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Telefonszám-cél keresése..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Nem sikkerült értelmezni a számot." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Kapcsolódás" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "Nem sikerült hívni" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Elnézést, elértük a egyidejű hívások maximális számát" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "kapcsolatba lépett veled." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "és automatikus választ kért." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "A hívási jellemzők módosítása..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Kapcsolódva." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "Hívás megszakítva" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "Nem sikerült várakoztatni a hívást" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Jelenlegi hívás várakoztatásának aktiválása..." -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "Stun keresés folyamatban..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "ICE helyi jelentkezők begyűjtése folyamatban..." @@ -1860,7 +1960,7 @@ msgstr "Időtartam" msgid "Unknown-bug" msgstr "Ismeretlen programhiba" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1868,7 +1968,7 @@ msgstr "" "Az Ön által megadott SIP proxy cím érvénytelen. \"sip:\"-tal kell kezdődnie, " "ezt egy hosztnév követi." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1877,134 +1977,136 @@ msgstr "" "Így kéne kinéznie: sip:felhasznalonev@proxytartomany, például sip:" "aladar@pelda.hu" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Nem sikerült belépni ezzel: %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Távoli csengés." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "Távoli csengés..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Korai médiák." -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "A hívás a következővel: %s várakoztatva" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "%s fogadta a hívást - várakoztatva." -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "Hívás visszatért" -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "%s válaszolt a hívásra." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" "Nem kompatibilis, ellenőrizze a kódek- vagy a biztonsági beállításokat..." -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "Visszatértünk." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "Megállítva a másik fél által." -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "A hívás távolról frissítve." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "A hívás befejezve." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "A felhasználó foglalt." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "A felhasználó ideiglenesen nem elérhető" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "A felhasználó nem akarja, hogy zavarják." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Hívás elutasítva" -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "Nincs válasz." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Protokol hiba." - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Átirányítva" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "Nem kompatibilis médiajellemzők." -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "Nem sikerült a hívás." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "A regisztáció a %s -n sikerült." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "A kiregisztrálás kész a következőn: %s ." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "időtúllépés után nincs válasz" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "A regisztáció a %s -n nem sikerült: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, c-format msgid "Authentication token is %s" msgstr "Hitelesítési jel: %s" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Van %i nem fogadott hivás." +#~ msgid "No response." +#~ msgstr "Nincs válasz." + +#~ msgid "Protocol error." +#~ msgstr "Protokol hiba." + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2390,9 +2492,6 @@ msgstr[0] "Van %i nem fogadott hivás." #~ msgid "micro" #~ msgstr "mikrofon" -#~ msgid "Recording source:" -#~ msgstr "Felvételi forrás:" - #~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" #~ msgstr "" #~ "Visszhang törlés engedélyezése (törli a visszhangot, amit hall a távoli " diff --git a/po/it.po b/po/it.po index 7328350ac..a04f95573 100644 --- a/po/it.po +++ b/po/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Linphone 3.2.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2002-10-15 HO:MI+ZONE\n" "Last-Translator: Matteo Piazza \n" "Language-Team: it \n" @@ -15,67 +15,67 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Chiamata %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Invia testo a %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "In chiamata con" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "annullato" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "mancante" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "Rifiuta" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -98,51 +98,56 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Contatto SIP non valido" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Informazioni" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Configuratore di account" + +#: ../gtk/main.c:590 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat con %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -154,74 +159,74 @@ msgstr "" "veda il tuo stato o aggiungerlo alla tua lista dei contatti Se rispondi no " "questo utente sarà momentaneamente bloccato." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" " at realm %s:" msgstr "Prego inserire la password per username %s e dominio %s" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "Cronologia" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Chiamata terminata" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Rifiuta" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "annullato" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Porte" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "" @@ -233,7 +238,7 @@ msgstr "" msgid "Presence status" msgstr "Presenza" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" @@ -251,141 +256,141 @@ msgstr "" msgid "Search in %s directory" msgstr "Cerca contatti nella directory %s" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Modifica contatto %s" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Elimina contatto %s" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Elimina contatto %s" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Aggiungi nuovo contatto dalla directory %s" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Stato" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Bitrate Min (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parametri" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Attivato" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Disattivato" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Account" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Inglese" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Francese" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Svedese" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Italiano" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Spagnolo" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Polacco" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Tedesco" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Russo" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "Giapponese" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Olandese" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Ungherese" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Ceco" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Riavviare il software per utilizzare la nuova lingua selezionata" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -529,41 +534,41 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Configuratore di account" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Benvenuto nel configuratore di account" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Configuratore di account" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Configurazione SIP account" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 #, fuzzy msgid "Terminating" msgstr "Termina chiamata" @@ -573,195 +578,195 @@ msgstr "Termina chiamata" msgid "Call #%i" msgstr "Chiamata %s" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "Filtro ICE" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Rediretto verso %s..." -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "Ricerca Stun in progresso ..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "Filtro ICE" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 #, fuzzy msgid "Calling..." msgstr "Linguaggio" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "Chimata in entrata" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "In chiamata con" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "Termina chiamata" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Chiamata terminata." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Chiamata rifiutata" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "" @@ -780,6 +785,87 @@ msgstr "Chiamata proveniente da %s" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Benvenuti !\n" +"La procedura vi aiutera a configurare un account SIP." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Dispositivo microfono:" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Dispositivo uscita audio:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Configuratore" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Configuratore di account" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -822,135 +908,135 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -#, fuzzy -msgid "Set configuration URI" -msgstr "Informazioni" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -msgid "Enable self-view" -msgstr "Self-view abilitato" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:22 -#, fuzzy -msgid "Show debug window" -msgstr "Linphone debug window" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "Account assistant" -msgstr "Configuratore di account" - -#: ../gtk/main.ui.h:26 -msgid "SIP address or phone number:" -msgstr "Indirizzo sip o numero." - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:28 -#, fuzzy -msgid "Contacts" -msgstr "In connessione" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:30 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Aggiungi nuovo contatto dalla directory %s" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "Trovato %i contatto" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "In chiamata" - -#: ../gtk/main.ui.h:33 -msgid "My current identity:" -msgstr "Identità corrente" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Username" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Password" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "Connessione Internet:" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "Login Automatico" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/main.ui.h:39 -msgid "Login information" -msgstr "Credenziali di accesso" - -#: ../gtk/main.ui.h:40 -msgid "Welcome !" -msgstr "Benvenuto !" - -#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:18 #, fuzzy msgid "Online users" msgstr "" "Tutti gli utenti\n" "Utenti Online" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "Fibra Ottica" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 msgid "Default" msgstr "Default" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "Informazioni" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +msgid "Enable self-view" +msgstr "Self-view abilitato" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:27 +#, fuzzy +msgid "Show debug window" +msgstr "Linphone debug window" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:30 +#, fuzzy +msgid "Account assistant" +msgstr "Configuratore di account" + +#: ../gtk/main.ui.h:32 +msgid "SIP address or phone number:" +msgstr "Indirizzo sip o numero." + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:34 +#, fuzzy +msgid "Contacts" +msgstr "In connessione" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "" + +#: ../gtk/main.ui.h:36 +#, fuzzy +msgid "Add contacts from directory" +msgstr "Aggiungi nuovo contatto dalla directory %s" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "Trovato %i contatto" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "In chiamata" + +#: ../gtk/main.ui.h:39 +msgid "My current identity:" +msgstr "Identità corrente" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +msgid "Username" +msgstr "Username" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +msgid "Password" +msgstr "Password" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "Connessione Internet:" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "Login Automatico" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + +#: ../gtk/main.ui.h:45 +msgid "Login information" +msgstr "Credenziali di accesso" + #: ../gtk/main.ui.h:46 +msgid "Welcome !" +msgstr "Benvenuto !" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1063,23 +1149,32 @@ msgid "Contact params (optional):" msgstr "Rotta (opzionale)" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Rotta (opzionale)" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Transporto" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Pubblica stato della presenza" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Attivato" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Configurazione SIP account" @@ -1525,6 +1620,11 @@ msgstr "Risoluzione video preferita" #: ../gtk/call_statistics.ui.h:11 #, fuzzy +msgid "RTP profile" +msgstr "RTP imput filter" + +#: ../gtk/call_statistics.ui.h:12 +#, fuzzy msgid "Call statistics and information" msgstr "Contact informazioni" @@ -1730,19 +1830,19 @@ msgstr "In connessione..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "comletato" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "mancante" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1757,82 +1857,82 @@ msgstr "" "Stato: %s\n" "Durata: %i mn %i sec\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Chiamata in uscita" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Pronto" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Informazioni" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Ricerca numero destinazione..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Impossibile risolvere il numero." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "In connessione" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 #, fuzzy msgid "is contacting you" msgstr "ti sta conttatando." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Connessione" -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "annullato" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 #, fuzzy msgid "Could not pause the call" msgstr "chiamata fallita" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 #, fuzzy msgid "Pausing the current call..." msgstr "Mostra chiamata corrente" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "Ricerca Stun in progresso ..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1889,7 +1989,7 @@ msgstr "Durata" msgid "Unknown-bug" msgstr "Bug-sconosciuto" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1897,7 +1997,7 @@ msgstr "" "L'indirizzo sip proxy utilizzato è invalido, deve iniziare con \"sip:\" " "seguito dall' hostaname." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1905,138 +2005,137 @@ msgstr "" "L'identità sip utilizza è invalida.\n" "Dovrebbre essere sip:username@proxydomain, esempio: sip:alice@example.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "impossibile login come %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "" -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "" -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat con %s" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "Chiamata terminata" -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Chiamata terminata." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Utente occupato" -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Utente non disponibile" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "L'utente non vuole essere disturbato" -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:603 -#, fuzzy -msgid "No response." -msgstr "timeout no risposta" - -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 #, fuzzy msgid "Redirected" msgstr "Rediretto verso %s..." -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 #, fuzzy msgid "Call failed." msgstr "Chiamata rifiutata" -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Registrazione su %s attiva" -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Unregistrazione su %s" -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "timeout no risposta" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrazione su %s fallita: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Linphone - Autenticazione richiesta" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "" msgstr[1] "" +#, fuzzy +#~ msgid "No response." +#~ msgstr "timeout no risposta" + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2194,9 +2293,6 @@ msgstr[1] "" #~ msgid "RTP output filter" #~ msgstr "RTP output filter" -#~ msgid "RTP input filter" -#~ msgstr "RTP imput filter" - #~ msgid "The free and wonderful speex codec" #~ msgstr "The free and wonderful speex codec" @@ -2345,9 +2441,6 @@ msgstr[1] "" #~ msgid "Sound playback filter for MacOS X Core Audio drivers" #~ msgstr "Sound playback filter for MacOS X Core Audio drivers" -#~ msgid "Assistant" -#~ msgstr "Configuratore" - #~ msgid "Start call" #~ msgstr "Inizia chiamata" diff --git a/po/ja.po b/po/ja.po index 900fc6cc3..3cb7d0a36 100644 --- a/po/ja.po +++ b/po/ja.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.10\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2003-01-21 00:05+9000\n" "Last-Translator: YAMAGUCHI YOSHIYA \n" "Language-Team: \n" @@ -17,66 +17,66 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "接続中" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "通話はキャンセルされました。" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "ライン入力" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -96,51 +96,55 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "pixmapファイルが見つかりません %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "情報" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -149,76 +153,76 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, c-format msgid "" "Please enter your password for username %s\n" " at realm %s:" msgstr "" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 #, fuzzy msgid "Call ended" msgstr "通話は拒否されました。" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "ライン入力" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "通話はキャンセルされました。" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "接続中" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "" @@ -232,7 +236,7 @@ msgstr "電話帳" msgid "Presence status" msgstr "状態" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名前" @@ -250,142 +254,142 @@ msgstr "" msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(接続するための情報がありません!)" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "状態" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "最低限のビットレート (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "パラメーター" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "使用する" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "使用しない" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Français" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "日本語" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Magyar" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "čeština" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "简体中文" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 #, fuzzy msgid "None" msgstr "ありません。" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -526,39 +530,39 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 msgid "SIP account configuration assistant" msgstr "" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "" @@ -567,195 +571,195 @@ msgstr "" msgid "Call #%i" msgstr "通話はキャンセルされました。" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "通話はキャンセルされました。" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 msgid "uPnP in progress" msgstr "" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "特に情報はありません" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "通話はキャンセルされました。" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 #, fuzzy msgid "Calling..." msgstr "接続中" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "接続中" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "接続中" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "接続中" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 #, fuzzy msgid "Call ended." msgstr "通話は拒否されました。" -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "通話はキャンセルされました。" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "" @@ -774,6 +778,83 @@ msgstr "" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "使用するサウンドデバイス" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "録音する音源" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "使用するサウンドデバイス" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -819,136 +900,136 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 -msgid "_Options" +msgid "All users" msgstr "" #: ../gtk/main.ui.h:18 #, fuzzy -msgid "Set configuration URI" -msgstr "情報" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -#, fuzzy -msgid "Enable self-view" -msgstr "使用する" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:26 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "レジストラサーバーのSIPアドレス" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:28 -#, fuzzy -msgid "Contacts" -msgstr "接続中" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:30 -#, fuzzy -msgid "Add contacts from directory" -msgstr "コーデックの情報" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "(接続するための情報がありません!)" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "接続中" - -#: ../gtk/main.ui.h:33 -#, fuzzy -msgid "My current identity:" -msgstr "個人情報" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "ユーザーマニュアル" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "パスワード" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/main.ui.h:39 -#, fuzzy -msgid "Login information" -msgstr "コーデックの情報" - -#: ../gtk/main.ui.h:40 -#, fuzzy -msgid "Welcome !" -msgstr "接続中" - -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:42 -#, fuzzy msgid "Online users" msgstr "ライン入力" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Default" msgstr "個人情報" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "情報" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +#, fuzzy +msgid "Enable self-view" +msgstr "使用する" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:27 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:30 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:32 +#, fuzzy +msgid "SIP address or phone number:" +msgstr "レジストラサーバーのSIPアドレス" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:34 +#, fuzzy +msgid "Contacts" +msgstr "接続中" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "" + +#: ../gtk/main.ui.h:36 +#, fuzzy +msgid "Add contacts from directory" +msgstr "コーデックの情報" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "(接続するための情報がありません!)" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "接続中" + +#: ../gtk/main.ui.h:39 +#, fuzzy +msgid "My current identity:" +msgstr "個人情報" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +#, fuzzy +msgid "Username" +msgstr "ユーザーマニュアル" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +#, fuzzy +msgid "Password" +msgstr "パスワード" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + +#: ../gtk/main.ui.h:45 +#, fuzzy +msgid "Login information" +msgstr "コーデックの情報" + #: ../gtk/main.ui.h:46 +#, fuzzy +msgid "Welcome !" +msgstr "接続中" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1064,24 +1145,33 @@ msgid "Contact params (optional):" msgstr "" #: ../gtk/sip_account.ui.h:9 -msgid "Route (optional):" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "" + +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "接続中" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 #, fuzzy msgid "Publish presence information" msgstr "コーデックの情報" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "使用する" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "" @@ -1534,6 +1624,10 @@ msgid "Video resolution sent" msgstr "" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 #, fuzzy msgid "Call statistics and information" msgstr "コーデックの情報" @@ -1740,19 +1834,19 @@ msgstr "コネクション" msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1762,82 +1856,82 @@ msgid "" "Duration: %i mn %i sec\n" msgstr "" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 #, fuzzy msgid "Ready" msgstr "準備完了。" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "情報" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "" #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 #, fuzzy msgid "Contacting" msgstr "接続中" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "pixmapファイルが見つかりません %s" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 #, fuzzy msgid "is contacting you" msgstr "から電話です。" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "接続しました。" -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "通話はキャンセルされました。" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1898,147 +1992,143 @@ msgstr "情報" msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, fuzzy, c-format msgid "Could not login as %s" msgstr "pixmapファイルが見つかりません %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 #, fuzzy msgid "Remote ringing." msgstr "登録中……" -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "登録中……" -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "電話をかける\n" "電話に出る" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 #, fuzzy msgid "Call terminated." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "ユーザーはビジーです" -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "ユーザーは、今出られません。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "ユーザーは手が離せないようです。" -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "通話は拒否されました。" -#: ../coreapi/callbacks.c:603 -msgid "No response." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 #, fuzzy msgid "Call failed." msgstr "通話はキャンセルされました。" -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "登録しました。" -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "登録しました。" -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "登録しました。" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "コーデックの情報" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -2233,9 +2323,6 @@ msgstr[1] "" #~ msgid "micro" #~ msgstr "マイク入力" -#~ msgid "Recording source:" -#~ msgstr "録音する音源" - #~ msgid "Run sip user agent on port:" #~ msgstr "SIPユーザーエージェントが起動するポート" diff --git a/po/nb_NO.po b/po/nb_NO.po index d6eeac5c0..d135aecc6 100644 --- a/po/nb_NO.po +++ b/po/nb_NO.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2011-04-05 01:56+0200\n" "Last-Translator: Øyvind Sæther \n" "Language-Team: Norwegian Bokmål \n" @@ -17,67 +17,67 @@ msgstr "" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Ring %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Send tekst til %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "I samtale med" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "avbrutt" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "ubesvart" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "Avvis" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -98,35 +98,35 @@ msgstr "Skru mikrofonen av" msgid "Couldn't find pixmap file: %s" msgstr "Fant ikke pixmap fli: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Ugyldig SIP kontakt !" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "skriv logg-informasjon under kjøring" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Start skjult i systemkurven, ikke vis programbildet." -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "address som skal ringes nå" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "besvarer innkommende samtaler automatisk om valgt" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -134,17 +134,22 @@ msgstr "" "Spesifiser arbeidsmappe (bør være base for installasjonen, f.eks: c:" "\\Programfiler\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Bekreftelse" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Brukerkontoveiviser" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Ring med %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -157,7 +162,7 @@ msgstr "" "din kontaktliste?\n" "Hvis du svarer nei vil personen bli svartelyst midlertidig." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -166,61 +171,61 @@ msgstr "" "Skriv inn ditt passord for brukernavn %s\n" " på domene %s:i>:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "Samtalehistorikk" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Samtale avsluttet" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Svarer" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avvis" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "Samtale avbrutt" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Porter" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Peker til nettsted" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (Standard)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Vi er overført til %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -228,7 +233,7 @@ msgstr "" "Klarte ikke å finne noe lydkort på denne datamaskinen.\n" "Du vil ikke kunne sende eller motta lydsamtaler." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" @@ -240,7 +245,7 @@ msgstr "" msgid "Presence status" msgstr "Tilstedestatus" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Navn" @@ -258,141 +263,141 @@ msgstr "" msgid "Search in %s directory" msgstr "Søk i %s katalogen" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Rediger kontakt '%s'" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Slett kontakt '%s'" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Slett kontakt '%s'" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Legg til kontakt fra %s katalogen" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Frekvens (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Min. datahastighet (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parametere" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "På" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Av" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Engelsk" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Fransk" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Svensk" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Italisensk" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Spansk" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "Portugisisk" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Polsk" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Tysk" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Russisk" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "Japansk" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Nederlandsk" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Ungarsk" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Tjekkisk" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "Kinesisk" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Du må restarte linphone for at det nye språkvalget skal iverksettes." -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -536,41 +541,41 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Velkommen til brukerkontoveiviseren" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Konfigurer en SIP konto" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 #, fuzzy msgid "Terminating" msgstr "Lägg på" @@ -580,193 +585,193 @@ msgstr "Lägg på" msgid "Call #%i" msgstr "Ring %s" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 #, fuzzy msgid "Not used" msgstr "Ikke funnet" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "ICE filter" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Omdirigert" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "STUN oppslag pågår..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "ICE filter" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "Innkommende samtale" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "I samtale med" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "Pauset samtale" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Samtale avsluttet." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 #, fuzzy msgid "Transfer done." msgstr "Overfører" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Overfører" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Fortsett" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Pause" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, fuzzy msgid "(Paused)" msgstr "Pause" @@ -786,6 +791,87 @@ msgstr "Inkommande samtal från %s" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Velkommen\n" +"Denne veiviseren vil hjelpe deg sette opp en SIP-konto for dine samtaler." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Mikrofonenhet:" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Avspillingsenhet:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Assistent" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Brukerkontoveiviser" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -828,125 +914,125 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 +msgid "All users" +msgstr "Alle brukere" + +#: ../gtk/main.ui.h:18 +msgid "Online users" +msgstr "Tilkoblede brukere" + +#: ../gtk/main.ui.h:19 +msgid "ADSL" +msgstr "ADSL" + +#: ../gtk/main.ui.h:20 +msgid "Fiber Channel" +msgstr "Fiber Kanal" + +#: ../gtk/main.ui.h:21 +msgid "Default" +msgstr "Standard" + +#: ../gtk/main.ui.h:22 msgid "_Options" msgstr "_Alternativer" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Set configuration URI" msgstr "Bekreftelse" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:24 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:25 msgid "Enable self-view" msgstr "Vis video av deg selv" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:26 msgid "_Help" msgstr "_Hjelp" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:27 msgid "Show debug window" msgstr "Vis avlusningsvindu" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:28 msgid "_Homepage" msgstr "H_jemmeside" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:29 msgid "Check _Updates" msgstr "Sjekk _Oppdateringer" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Account assistant" msgstr "Brukerkontoveiviser" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:32 msgid "SIP address or phone number:" msgstr "Sip adresse eller telefonnummer:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:33 msgid "Initiate a new call" msgstr "Start en ny samtale" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:34 msgid "Contacts" msgstr "Kontakter" -#: ../gtk/main.ui.h:29 +#: ../gtk/main.ui.h:35 msgid "Search" msgstr "Søk" -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:36 msgid "Add contacts from directory" msgstr "Legg til kontakter fra katalogen" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:37 msgid "Add contact" msgstr "Legg til kontakt" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:38 #, fuzzy msgid "Recent calls" msgstr "I samtale" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:39 msgid "My current identity:" msgstr "Min nåværende identitet:" -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Brukernavn" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Passord" -#: ../gtk/main.ui.h:36 +#: ../gtk/main.ui.h:42 msgid "Internet connection:" msgstr "Internet forbindelse:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:43 msgid "Automatically log me in" msgstr "Logg meg på automatisk" -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 msgid "UserID" msgstr "BrukerID" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:45 msgid "Login information" msgstr "Innlogginsinformasjon" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:46 msgid "Welcome !" msgstr "Velkommen!" -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "Alle brukere" - -#: ../gtk/main.ui.h:42 -msgid "Online users" -msgstr "Tilkoblede brukere" - -#: ../gtk/main.ui.h:43 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/main.ui.h:44 -msgid "Fiber Channel" -msgstr "Fiber Kanal" - -#: ../gtk/main.ui.h:45 -msgid "Default" -msgstr "Standard" - -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1070,23 +1156,32 @@ msgid "Contact params (optional):" msgstr "Route (valgfritt):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Route (valgfritt):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Transport" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Publiser tilstedestatus" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Aktiver" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Konfigurer en SIP konto" @@ -1519,6 +1614,11 @@ msgstr "Foretrukke video-oppløsning:" #: ../gtk/call_statistics.ui.h:11 #, fuzzy +msgid "RTP profile" +msgstr "RTP inn-filter" + +#: ../gtk/call_statistics.ui.h:12 +#, fuzzy msgid "Call statistics and information" msgstr "Kontaktinformasjon" @@ -1724,19 +1824,19 @@ msgstr "Tilknytter..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "avbrutt" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "Fullført" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "ubesvart" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1751,77 +1851,77 @@ msgstr "" "Status: %s\n" "Lengde: %i min %i sek\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Utgående samtale" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Klar" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Bekreftelse" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Ser etter telefonnummer for destinasjonen..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Kan ikke tilkoble dette nummeret." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Tilknytter" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "Kunne ikke ringe" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Beklager, du har nådd maksimalt antall samtidige samtaler" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "Kontakter deg." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr " og ba om autosvar." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "Endrer ringeparametre..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Tilkoblet" -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "Samtale avbrutt" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "Kunne ikke pause samtalen" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Pauser nåværende samtale" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "STUN oppslag pågår..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1878,7 +1978,7 @@ msgstr "Varighet" msgid "Unknown-bug" msgstr "Ukjent feil" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1886,7 +1986,7 @@ msgstr "" "SIP proxy adressen du har angitt er ugyldig, den må begynne med \"sip:\" " "etterfult av vertsnavn." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1894,136 +1994,138 @@ msgstr "" "SIP adressen du har angitt er feil. Adressen bør se ut som sip: " "brukernavn@domenenavn, f.eks sip:ola@eksempel.no" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Ikke ikke logge inn som %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Tidlig media" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "Samtalen med %s er pauset." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "Samtale besvart av %s - på vent." -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "Samtale gjenopptatt." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "Samtale besvart av %s." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 #, fuzzy msgid "We have been resumed." msgstr "Vi har blitt gjenopptatt..." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Samtale avsluttet." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Brukeren er opptatt." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Brukeren er midlertidig ikke tilgjengelig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "Brukeren vil ikke bli forstyrret." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Samtale avvist." -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "Ikke noe svar." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Protokollfeil." - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Omdirigert" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "Samtale feilet." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lykkes." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lykkes." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "ingen svar innen angitt tid" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislykkes: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Autorisering kreves" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Du har %i ubesvarte anrop." msgstr[1] "Du har %i missade samtal" +#~ msgid "No response." +#~ msgstr "Ikke noe svar." + +#~ msgid "Protocol error." +#~ msgstr "Protokollfeil." + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2217,9 +2319,6 @@ msgstr[1] "Du har %i missade samtal" #~ msgid "RTP output filter" #~ msgstr "RTP ut-filter" -#~ msgid "RTP input filter" -#~ msgstr "RTP inn-filter" - #~ msgid "The free and wonderful speex codec" #~ msgstr "En fri og fantatisk speex kodek" @@ -2386,9 +2485,6 @@ msgstr[1] "Du har %i missade samtal" #~ "Din dator er tilkoblet ett IPv6 nettverk. Linphone bruker IPv6 som " #~ "standard. Oppdater oppsettet om du vil bruke IPv6. " -#~ msgid "Assistant" -#~ msgstr "Assistent" - #~ msgid "Show debug messages" #~ msgstr "Visa debugfönstret" diff --git a/po/nl.po b/po/nl.po index 26b7a31f5..21a4523cd 100644 --- a/po/nl.po +++ b/po/nl.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: nl\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2007-09-05 10:40+0200\n" "Last-Translator: Hendrik-Jan Heins \n" "Language-Team: Nederlands \n" @@ -19,67 +19,67 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Call %s" msgstr "Oproepgeschiedenis" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "Contactlijst" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "afgebroken" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "gemist" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "lijn" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -99,51 +99,55 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Informatie" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:590 #, fuzzy, c-format msgid "Call with %s" msgstr "Chat met %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -152,75 +156,75 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, c-format msgid "" "Please enter your password for username %s\n" " at realm %s:" msgstr "" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "Linphone - Oproepgeschiedenis" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Oproep beeindigd" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "lijn" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "afgebroken" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Contactlijst" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Een Vrije SIP video-telefoon" @@ -233,7 +237,7 @@ msgstr "Adresboek" msgid "Presence status" msgstr "Aanwezigheidsstatus" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Naam" @@ -252,141 +256,141 @@ msgstr "Chat box" msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Bewerk contactgegevens" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Frequentie (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Minimale bitrate (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parameters" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Aan" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Uit" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Account" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Geen" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -527,39 +531,39 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 msgid "SIP account configuration assistant" msgstr "" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "" @@ -568,197 +572,197 @@ msgstr "" msgid "Call #%i" msgstr "Oproepgeschiedenis" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "Oproep geannuleerd." -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Doorgeschakeld naar %s..." -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "STUN adres wordt opgezocht..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "Geen informatie beschikbaar" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "Oproep geannuleerd." -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 #, fuzzy msgid "Calling..." msgstr "Contactlijst" -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "Inkomende oproep" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "Contactlijst" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 #, fuzzy msgid "Call ended." msgstr "Oproep beeindigd" -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Oproep geannuleerd." -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "" @@ -777,6 +781,83 @@ msgstr "Inkomende oproep" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Geluidsapparaat gebruiken:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Bron voor opname:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Geluidsapparaat gebruiken:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -822,138 +903,138 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 -msgid "_Options" +msgid "All users" msgstr "" #: ../gtk/main.ui.h:18 #, fuzzy -msgid "Set configuration URI" -msgstr "Proxy/registratieserver registratieveld" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -#, fuzzy -msgid "Enable self-view" -msgstr "Video aan" - -#: ../gtk/main.ui.h:21 -#, fuzzy -msgid "_Help" -msgstr "Help" - -#: ../gtk/main.ui.h:22 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:26 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "Geef het SIP adres of telefoonnummer in" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:28 -#, fuzzy -msgid "Contacts" -msgstr "Verbinden" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:30 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Contact informatie" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "Bewerk contactgegevens" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "Inkomende oproep" - -#: ../gtk/main.ui.h:33 -#, fuzzy -msgid "My current identity:" -msgstr "SIP-identiteit:" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "gebruikersnaam:" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "wachtwoord:" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:37 -#, fuzzy -msgid "Automatically log me in" -msgstr "Automatisch een geldige hostnaam raden" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/main.ui.h:39 -#, fuzzy -msgid "Login information" -msgstr "Contact informatie" - -#: ../gtk/main.ui.h:40 -#, fuzzy -msgid "Welcome !" -msgstr "Contactlijst" - -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:42 -#, fuzzy msgid "Online users" msgstr "Aanwezig" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Default" msgstr "SIP-identiteit:" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "Proxy/registratieserver registratieveld" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +#, fuzzy +msgid "Enable self-view" +msgstr "Video aan" + +#: ../gtk/main.ui.h:26 +#, fuzzy +msgid "_Help" +msgstr "Help" + +#: ../gtk/main.ui.h:27 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:30 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:32 +#, fuzzy +msgid "SIP address or phone number:" +msgstr "Geef het SIP adres of telefoonnummer in" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:34 +#, fuzzy +msgid "Contacts" +msgstr "Verbinden" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "" + +#: ../gtk/main.ui.h:36 +#, fuzzy +msgid "Add contacts from directory" +msgstr "Contact informatie" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "Bewerk contactgegevens" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "Inkomende oproep" + +#: ../gtk/main.ui.h:39 +#, fuzzy +msgid "My current identity:" +msgstr "SIP-identiteit:" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +#, fuzzy +msgid "Username" +msgstr "gebruikersnaam:" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +#, fuzzy +msgid "Password" +msgstr "wachtwoord:" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "" + +#: ../gtk/main.ui.h:43 +#, fuzzy +msgid "Automatically log me in" +msgstr "Automatisch een geldige hostnaam raden" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + +#: ../gtk/main.ui.h:45 +#, fuzzy +msgid "Login information" +msgstr "Contact informatie" + #: ../gtk/main.ui.h:46 +#, fuzzy +msgid "Welcome !" +msgstr "Contactlijst" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1072,24 +1153,33 @@ msgid "Contact params (optional):" msgstr "Route (optioneel):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Route (optioneel):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Contactlijst" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 #, fuzzy msgid "Publish presence information" msgstr "Toon informatie over aanwezigheid:" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Aan" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "" @@ -1546,6 +1636,10 @@ msgid "Video resolution sent" msgstr "" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 #, fuzzy msgid "Call statistics and information" msgstr "Contact informatie" @@ -1753,19 +1847,19 @@ msgstr "Verbinden" msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "voltooid" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "gemist" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1780,82 +1874,82 @@ msgstr "" "Status: %s\n" "Tijdsduur: %i mins %i secs\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Uitgaande oproep" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Gereed." -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Informatie" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Zoekt de lokatie van het telefoonnummer..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Kon dit nummer niet vinden." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Verbinden" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 #, fuzzy msgid "is contacting you" msgstr "belt u." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Verbonden." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "afgebroken" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 #, fuzzy msgid "Could not pause the call" msgstr "Kon niet oproepen" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 #, fuzzy msgid "Pausing the current call..." msgstr "Kon niet oproepen" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "STUN adres wordt opgezocht..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1917,147 +2011,143 @@ msgstr "Informatie" msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Kon pixmap bestand %s niet vinden" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 #, fuzzy msgid "Remote ringing." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "Externe diensten" -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Chat met %s" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "Oproep beeindigd" -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Oproepen of\n" "beantwoorden" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Oproep beeindigd." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Gebruiker is bezet." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Gebruiker is tijdelijk niet beschikbaar." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "De gebruiker wenst niet gestoord te worden." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Oproep geweigerd." -#: ../coreapi/callbacks.c:603 -msgid "No response." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 #, fuzzy msgid "Redirected" msgstr "Doorgeschakeld naar %s..." -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 #, fuzzy msgid "Call failed." msgstr "Oproep geannuleerd." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registratie op %s gelukt." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registratie op %s mislukt (time-out)." -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Authorisatie gegevens" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -2452,9 +2542,6 @@ msgstr[1] "U heeft %i oproep(en) gemist." #~ msgid "micro" #~ msgstr "microfoon" -#~ msgid "Recording source:" -#~ msgstr "Bron voor opname:" - #~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" #~ msgstr "" #~ "Activeer de echo-onderdrukking (onderdrukt de echo die de andere partij " diff --git a/po/pl.po b/po/pl.po index fbcbdbd6d..819c7ab7e 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2003-08-22 12:50+0200\n" "Last-Translator: Robert Nasiadek \n" "Language-Team: Polski \n" @@ -15,66 +15,66 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "Dzwonie do " -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "Połączenie odwołane." -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 msgid "Missed" msgstr "" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "linia" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -94,51 +94,55 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Informacja" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -147,76 +151,76 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, c-format msgid "" "Please enter your password for username %s\n" " at realm %s:" msgstr "" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 #, fuzzy msgid "Call ended" msgstr "Rozmowa odrzucona." -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linia" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "Połączenie odwołane." -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Dzwonie do " -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "" @@ -230,7 +234,7 @@ msgstr "Książka adresowa" msgid "Presence status" msgstr "Obecność" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nazwa" @@ -248,142 +252,142 @@ msgstr "" msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "(Brak informacji kontaktowych !)" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Jakość (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Min przepustowość (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parametr" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Włączone" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Wyłączone" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 #, fuzzy msgid "None" msgstr "Brak." -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -524,39 +528,39 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 msgid "SIP account configuration assistant" msgstr "" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "" @@ -565,195 +569,195 @@ msgstr "" msgid "Call #%i" msgstr "Połączenie odwołane." -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "Połączenie odwołane." -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 msgid "Direct" msgstr "" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 msgid "uPnP in progress" msgstr "" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "Brak informacji" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "Połączenie odwołane." -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 #, fuzzy msgid "Calling..." msgstr "Dzwonie do " -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "Dzwonie do " -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 #, fuzzy msgid "Call ended." msgstr "Rozmowa odrzucona." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Połączenie odwołane." -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "" @@ -772,6 +776,83 @@ msgstr "" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Użyj tego urządzenia dźwięku:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Źródło nagrywania:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Użyj tego urządzenia dźwięku:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -817,136 +898,136 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 -msgid "_Options" +msgid "All users" msgstr "" #: ../gtk/main.ui.h:18 #, fuzzy -msgid "Set configuration URI" -msgstr "Informacja" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -#, fuzzy -msgid "Enable self-view" -msgstr "Włączone" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:26 -#, fuzzy -msgid "SIP address or phone number:" -msgstr "Adres serwera rejestracji sip" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:28 -#, fuzzy -msgid "Contacts" -msgstr "Dzwonie do " - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:30 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Informacje o kodeku" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "(Brak informacji kontaktowych !)" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "Dzwonie do " - -#: ../gtk/main.ui.h:33 -#, fuzzy -msgid "My current identity:" -msgstr "Tożsamość" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "Podręcznik" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "Twoje hasło:" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/main.ui.h:39 -#, fuzzy -msgid "Login information" -msgstr "Informacje o kodeku" - -#: ../gtk/main.ui.h:40 -#, fuzzy -msgid "Welcome !" -msgstr "Dzwonie do " - -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:42 -#, fuzzy msgid "Online users" msgstr "linia" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Default" msgstr "Tożsamość" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "Informacja" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +#, fuzzy +msgid "Enable self-view" +msgstr "Włączone" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:27 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:30 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:32 +#, fuzzy +msgid "SIP address or phone number:" +msgstr "Adres serwera rejestracji sip" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:34 +#, fuzzy +msgid "Contacts" +msgstr "Dzwonie do " + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "" + +#: ../gtk/main.ui.h:36 +#, fuzzy +msgid "Add contacts from directory" +msgstr "Informacje o kodeku" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "(Brak informacji kontaktowych !)" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "Dzwonie do " + +#: ../gtk/main.ui.h:39 +#, fuzzy +msgid "My current identity:" +msgstr "Tożsamość" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +#, fuzzy +msgid "Username" +msgstr "Podręcznik" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +#, fuzzy +msgid "Password" +msgstr "Twoje hasło:" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + +#: ../gtk/main.ui.h:45 +#, fuzzy +msgid "Login information" +msgstr "Informacje o kodeku" + #: ../gtk/main.ui.h:46 +#, fuzzy +msgid "Welcome !" +msgstr "Dzwonie do " + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1062,24 +1143,33 @@ msgid "Contact params (optional):" msgstr "" #: ../gtk/sip_account.ui.h:9 -msgid "Route (optional):" +msgid "AVPF regular RTCP interval (sec):" msgstr "" #: ../gtk/sip_account.ui.h:10 +msgid "Route (optional):" +msgstr "" + +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Dzwonie do " -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 #, fuzzy msgid "Publish presence information" msgstr "Informacje o kodeku" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Włączony" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "" @@ -1533,6 +1623,10 @@ msgid "Video resolution sent" msgstr "" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 #, fuzzy msgid "Call statistics and information" msgstr "Informacje o kodeku" @@ -1739,19 +1833,19 @@ msgstr "Lącze" msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1761,82 +1855,82 @@ msgid "" "Duration: %i mn %i sec\n" msgstr "" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 #, fuzzy msgid "Ready" msgstr "Gotowy." -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Informacja" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "" -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "" #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 #, fuzzy msgid "Contacting" msgstr "Dzwonie do " -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "Nie można znaleźć pixmapy: %s" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 #, fuzzy msgid "is contacting you" msgstr "dzwoni do Ciebie." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Połączony" -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "Połączenie odwołane." -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1897,147 +1991,143 @@ msgstr "Informacja" msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Nie można znaleźć pixmapy: %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 #, fuzzy msgid "Remote ringing." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "Rejestruje..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Zadzwoń lub\n" "Odpowiedz" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 #, fuzzy msgid "Call terminated." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Osoba jest zajęta." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Osoba jest tymczasowo niedostępna." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "Osoba nie chce, aby jej przeszkadzać." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Rozmowa odrzucona." -#: ../coreapi/callbacks.c:603 -msgid "No response." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 #, fuzzy msgid "Call failed." msgstr "Połączenie odwołane." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Rejestracja powiodła się." -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Informacje o kodeku" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -2236,9 +2326,6 @@ msgstr[1] "" #~ msgid "micro" #~ msgstr "mikrofon" -#~ msgid "Recording source:" -#~ msgstr "Źródło nagrywania:" - #~ msgid "Run sip user agent on port:" #~ msgstr "Uruchom agenta sip na porcie:" diff --git a/po/pt_BR.po b/po/pt_BR.po index de51d73d7..21b309da3 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone-1.1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2006-07-11 23:30+0200\n" "Last-Translator: Rafael Caesar Lenzi \n" "Language-Team: pt_BR \n" @@ -17,67 +17,67 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, fuzzy, c-format msgid "Call %s" msgstr "Histórico de chamadas" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "Contatando " -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "Abortado" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "Perdido" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "linha" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -97,51 +97,55 @@ msgstr "" msgid "Couldn't find pixmap file: %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Informações" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +msgid "Run the audio assistant" +msgstr "" + +#: ../gtk/main.c:590 #, fuzzy, c-format msgid "Call with %s" msgstr "Bate-papo com %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -150,76 +154,76 @@ msgid "" "If you answer no, this person will be temporarily blacklisted." msgstr "" -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, c-format msgid "" "Please enter your password for username %s\n" " at realm %s:" msgstr "" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "Linphone - Histórico de chamadas" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 #, fuzzy msgid "Call ended" msgstr "Chamada cancelada." -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 #, fuzzy msgid "Decline" msgstr "linha" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "Abortado" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Contatando " -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "" @@ -232,7 +236,7 @@ msgstr "Catálogo de endereços" msgid "Presence status" msgstr "Status de presença" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Nome" @@ -251,142 +255,142 @@ msgstr "Sala de bate-papo" msgid "Search in %s directory" msgstr "" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, fuzzy, c-format msgid "Edit contact '%s'" msgstr "Edicar informação de contato" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, c-format msgid "Delete chat history of '%s'" msgstr "" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Taxa (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Bitrate mínimo (kbits/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parâmetros" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Ativado" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Desativado" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 #, fuzzy msgid "Account" msgstr "Aceitar" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Nenhum" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -527,39 +531,39 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 msgid "SIP account configuration assistant" msgstr "" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "" @@ -568,196 +572,196 @@ msgstr "" msgid "Call #%i" msgstr "Histórico de chamadas" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "Histórico de chamadas" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Redirecionado para %s..." -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 msgid "uPnP in progress" msgstr "" -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "Informações não disponíveis" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "Histórico de chamadas" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 #, fuzzy msgid "Calling..." msgstr "Contatando " -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "Camadas recebidas" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "Contatando " -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "Contatando " -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 #, fuzzy msgid "Call ended." msgstr "Chamada cancelada." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Histórico de chamadas" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "" @@ -776,6 +780,83 @@ msgstr "Camadas recebidas" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Dispositivo de captura de som:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Origem de gravação:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Dispositivo de som:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +msgid "Audio Assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +msgid "Audio assistant" +msgstr "" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -821,136 +902,136 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 -msgid "_Options" +msgid "All users" msgstr "" #: ../gtk/main.ui.h:18 #, fuzzy -msgid "Set configuration URI" -msgstr "Configuração de proxy/registrador" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -#, fuzzy -msgid "Enable self-view" -msgstr "Ativado" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:22 -msgid "Show debug window" -msgstr "" - -#: ../gtk/main.ui.h:23 -msgid "_Homepage" -msgstr "" - -#: ../gtk/main.ui.h:24 -msgid "Check _Updates" -msgstr "" - -#: ../gtk/main.ui.h:25 -msgid "Account assistant" -msgstr "" - -#: ../gtk/main.ui.h:26 -msgid "SIP address or phone number:" -msgstr "" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:28 -#, fuzzy -msgid "Contacts" -msgstr "Contatando " - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "" - -#: ../gtk/main.ui.h:30 -#, fuzzy -msgid "Add contacts from directory" -msgstr "Informação de contato" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "Edicar informação de contato" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "Camadas recebidas" - -#: ../gtk/main.ui.h:33 -#, fuzzy -msgid "My current identity:" -msgstr "Identificação SIP:" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -#, fuzzy -msgid "Username" -msgstr "Usuário" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -#, fuzzy -msgid "Password" -msgstr "Senha:" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "" - -#: ../gtk/main.ui.h:37 -#, fuzzy -msgid "Automatically log me in" -msgstr "Adquirir automaticamente um nome de servidor válido." - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "" - -#: ../gtk/main.ui.h:39 -#, fuzzy -msgid "Login information" -msgstr "Informação de contato" - -#: ../gtk/main.ui.h:40 -#, fuzzy -msgid "Welcome !" -msgstr "Contatando " - -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "" - -#: ../gtk/main.ui.h:42 -#, fuzzy msgid "Online users" msgstr "linha" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 msgid "Fiber Channel" msgstr "" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Default" msgstr "Identificação SIP:" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "Configuração de proxy/registrador" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +#, fuzzy +msgid "Enable self-view" +msgstr "Ativado" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:27 +msgid "Show debug window" +msgstr "" + +#: ../gtk/main.ui.h:28 +msgid "_Homepage" +msgstr "" + +#: ../gtk/main.ui.h:29 +msgid "Check _Updates" +msgstr "" + +#: ../gtk/main.ui.h:30 +msgid "Account assistant" +msgstr "" + +#: ../gtk/main.ui.h:32 +msgid "SIP address or phone number:" +msgstr "" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:34 +#, fuzzy +msgid "Contacts" +msgstr "Contatando " + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "" + +#: ../gtk/main.ui.h:36 +#, fuzzy +msgid "Add contacts from directory" +msgstr "Informação de contato" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "Edicar informação de contato" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "Camadas recebidas" + +#: ../gtk/main.ui.h:39 +#, fuzzy +msgid "My current identity:" +msgstr "Identificação SIP:" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +#, fuzzy +msgid "Username" +msgstr "Usuário" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +#, fuzzy +msgid "Password" +msgstr "Senha:" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "" + +#: ../gtk/main.ui.h:43 +#, fuzzy +msgid "Automatically log me in" +msgstr "Adquirir automaticamente um nome de servidor válido." + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "" + +#: ../gtk/main.ui.h:45 +#, fuzzy +msgid "Login information" +msgstr "Informação de contato" + #: ../gtk/main.ui.h:46 +#, fuzzy +msgid "Welcome !" +msgstr "Contatando " + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1068,24 +1149,33 @@ msgid "Contact params (optional):" msgstr "Rota (opcional):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Rota (opcional):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Contatando " -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 #, fuzzy msgid "Publish presence information" msgstr "Informar informação de presença" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Ativado" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "" @@ -1539,6 +1629,10 @@ msgid "Video resolution sent" msgstr "" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 #, fuzzy msgid "Call statistics and information" msgstr "Informação de contato" @@ -1745,19 +1839,19 @@ msgstr "Contatando " msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "Competado" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "Perdido" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, fuzzy, c-format msgid "" "%s at %s\n" @@ -1771,82 +1865,82 @@ msgstr "" "Status: %s\n" "Duração: %i min %i seg\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Chamadas efetuadas" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 #, fuzzy msgid "Ready" msgstr "Pronto." -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Informações" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Procurando por telefone de destino..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Não foi possível encontrar este número." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 #, fuzzy msgid "Contacting" msgstr "Contatando " -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 #, fuzzy msgid "is contacting you" msgstr "está chamado você." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Conectado." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "Abortado" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "" -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1905,147 +1999,143 @@ msgstr "Informações" msgid "Unknown-bug" msgstr "" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" msgstr "" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, fuzzy, c-format msgid "Could not login as %s" msgstr "Não é possível achar arquivo pixmap: %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 #, fuzzy msgid "Remote ringing." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "Serviços remotos" -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Bate-papo com %s" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "Chamada cancelada." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, fuzzy, c-format msgid "Call answered by %s." msgstr "" "Ligar ou\n" "atender" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "" -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Usuário está ocupado." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Usuário está temporáriamente indisponível." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "" -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "" -#: ../coreapi/callbacks.c:603 -msgid "No response." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 #, fuzzy msgid "Redirected" msgstr "Redirecionado para %s..." -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 #, fuzzy msgid "Call failed." msgstr "Histórico de chamadas" -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, fuzzy, c-format msgid "Registration on %s successful." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, fuzzy, c-format msgid "Unregistration on %s done." msgstr "Registro em %s efetuado." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, fuzzy, c-format msgid "Registration on %s failed: %s" msgstr "Registro falhou (tempo esgotado)." -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Informações de autenticação" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, fuzzy, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -2254,9 +2344,6 @@ msgstr[1] "Você perdeu %i ligação(ões)." #~ msgid "micro" #~ msgstr "microfone" -#~ msgid "Recording source:" -#~ msgstr "Origem de gravação:" - #~ msgid "Listen" #~ msgstr "Escutar" diff --git a/po/ru.po b/po/ru.po index cd4da5d08..d2a440a31 100644 --- a/po/ru.po +++ b/po/ru.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2010-01-22 18:43+0300\n" "Last-Translator: Maxim Prokopyev \n" "Language-Team: Russian \n" @@ -17,41 +17,41 @@ msgstr "" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Набрать %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Послать текст к %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "Соединен с" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "н/д" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "отмененный" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "пропущенный" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "Отклонить" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -59,7 +59,7 @@ msgstr[0] "%i минута" msgstr[1] "%i минуты" msgstr[2] "%i минут" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -67,14 +67,14 @@ msgstr[0] "%i секунда" msgstr[1] "%i секунды" msgstr[2] "%i секунд" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, fuzzy, c-format msgid "%s\t%s" msgstr "" "%s\t%s\tКачество: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, fuzzy, c-format msgid "" "%s\tQuality: %s\n" @@ -83,7 +83,7 @@ msgstr "" "%s\t%s\tКачество: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, fuzzy, c-format msgid "" "%s\t\n" @@ -105,37 +105,37 @@ msgstr "Я" msgid "Couldn't find pixmap file: %s" msgstr "Невозможно найти графический файл: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Неверный sip-контакт!" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "" "Вывод некоторой отладочной информации на устройство стандартного вывода во " "время работы" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "путь к файлу для записи журнала работы." -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Запускать только в системном лотке, не показывая главное окно" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "адрес для звонка" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "автоматически принимать входящие вызовы, если включено" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -143,17 +143,22 @@ msgstr "" "Укажите рабочий каталог (должен содержать установленные файлы приложения, " "например: c:\\Program Files\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Подтверждение" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Помощник настройки учётной записи" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Чат с %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -166,7 +171,7 @@ msgstr "" "его(её) в свой контактный лист?\n" "Если вы ответите Нет, этот человек будет временно заблокирован." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -175,59 +180,59 @@ msgstr "" "Пожалуйста, введите пароль для пользователя %s\n" " в домене %s:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 msgid "Call error" msgstr "Ошибка вызова" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Разговор окончен" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Ответить" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Отклонить" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 msgid "Call paused" msgstr "Вызов приостановлен" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Порты" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Ссылка на сайт" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - видео-телефон для интернета" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (По умолчанию)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Мы переведены на %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -235,7 +240,7 @@ msgstr "" "На этом компьютере не обнаружено ни одной звуковой карты.\n" "Вы не сможете совершать или принимать аудио-вызовы." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Свободный SIP видео-телефон" @@ -247,7 +252,7 @@ msgstr "Добавить в адресную книгу" msgid "Presence status" msgstr "Статус присутствия" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Имя" @@ -265,143 +270,143 @@ msgstr "Комната чата" msgid "Search in %s directory" msgstr "Поиск в директории %s" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Редактировать контакт '%s'" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Удалить контакт '%s'" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Удалить контакт '%s'" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Добавить новый контакт из директории '%s'" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Частота (Гц)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Статус" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Минимальный битрейт (кбит/с)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Параметры" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Включен" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Отключен" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Учетная запись" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Английский" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Французский" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Шведский" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Итальянский" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Испанский" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "Бразильский португальский" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Польский" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Немецкий" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Русский" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "Японский" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Нидерландский" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Венгерский" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Чешский" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "Китайский" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "Традиционный китайский" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "Норвежский" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Вы должны перезапустить Linphone для того, чтобы языковые настройки вступили " "в силу." -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Нет" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "SRTP" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "ZRTP" @@ -546,40 +551,40 @@ msgstr "" "только что выслали вам на электронную почту.\n" "Затем вернитесь и нажмите на кнопку Далее." -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Добро пожаловать в помощник настройки учётной записи" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 msgid "Configure your account (step 1/1)" msgstr "Настройте свою учётную запись (шаг 1/1)" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "Введите ваше имя пользователя SIP (шаг 1/1)" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "Введи информация об учётной записи (шаг 1/2)" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "Проверка (шаг 2/2)" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "Ошибка" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "Завершение" @@ -588,194 +593,194 @@ msgstr "Завершение" msgid "Call #%i" msgstr "Вызов #%i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Перевести на #%i с %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 #, fuzzy msgid "Not used" msgstr "Не найден" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "ICE фильтр" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Переадресован" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "Идет поиск Stun..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "недоступно" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "ICE фильтр" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Вызов..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "Входящий вызов" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "хорошее" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "среднее" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "плохое" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "очень плохое" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "слишком плохое" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "Защищено SRTP" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Защищено ZRTP - [токен: %s]" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "Не проверен" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверен" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "В конференции" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "Соединен с" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "Приостановленный вызов" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Звонок закончен." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 #, fuzzy msgid "Transfer done." msgstr "Перевести" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Перевести" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Продолжить" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Пауза" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, fuzzy msgid "(Paused)" msgstr "Пауза" @@ -795,6 +800,88 @@ msgstr "Входящий звонок от %s" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Добро пожаловать!\n" +"Этот помощник поможет вам использовать учётную запись SIP для ваших звонков." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Устройство захвата:" + +#: ../gtk/audio_assistant.c:327 +#, fuzzy +msgid "Recorded volume" +msgstr "Источник записи:" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Устройство воспроизведения:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Помощник" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Помощник настройки учётной записи" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Имя вызываемого абонента" @@ -837,123 +924,123 @@ msgid "Call quality rating" msgstr "Уровень качества звонка" #: ../gtk/main.ui.h:17 +msgid "All users" +msgstr "Все пользователи" + +#: ../gtk/main.ui.h:18 +msgid "Online users" +msgstr "Пользователи в сети" + +#: ../gtk/main.ui.h:19 +msgid "ADSL" +msgstr "ADSL" + +#: ../gtk/main.ui.h:20 +msgid "Fiber Channel" +msgstr "Оптоволокно" + +#: ../gtk/main.ui.h:21 +msgid "Default" +msgstr "По умолчанию" + +#: ../gtk/main.ui.h:22 msgid "_Options" msgstr "_Настройки" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Set configuration URI" msgstr "Прокси/Регистратор конфигуратор" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:24 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:25 msgid "Enable self-view" msgstr "Включить своё видео" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:26 msgid "_Help" msgstr "_Помощь" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:27 msgid "Show debug window" msgstr "Показать окно отладки" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:28 msgid "_Homepage" msgstr "_Домашняя страница" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:29 msgid "Check _Updates" msgstr "Проверить _Обновления" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:30 msgid "Account assistant" msgstr "Помощник настройки учётной записи" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:32 msgid "SIP address or phone number:" msgstr "SIP-адрес или номер телефона:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:33 msgid "Initiate a new call" msgstr "Совершить новый вызов" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:34 msgid "Contacts" msgstr "Контакты" -#: ../gtk/main.ui.h:29 +#: ../gtk/main.ui.h:35 msgid "Search" msgstr "Поиск" -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:36 msgid "Add contacts from directory" msgstr "Добавить контакты из директории" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:37 msgid "Add contact" msgstr "Добавить контакт" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:38 msgid "Recent calls" msgstr "Недавние вызовы" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:39 msgid "My current identity:" msgstr "Мой текущий идентификатор:" -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Имя пользователя" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Пароль" -#: ../gtk/main.ui.h:36 +#: ../gtk/main.ui.h:42 msgid "Internet connection:" msgstr "Интернет-соединение:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:43 msgid "Automatically log me in" msgstr "Входить автоматически" -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 msgid "UserID" msgstr "UserID" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:45 msgid "Login information" msgstr "Информация для входа" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:46 msgid "Welcome !" msgstr "Добро пожаловать!" -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "Все пользователи" - -#: ../gtk/main.ui.h:42 -msgid "Online users" -msgstr "Пользователи в сети" - -#: ../gtk/main.ui.h:43 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/main.ui.h:44 -msgid "Fiber Channel" -msgstr "Оптоволокно" - -#: ../gtk/main.ui.h:45 -msgid "Default" -msgstr "По умолчанию" - -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1076,23 +1163,32 @@ msgid "Contact params (optional):" msgstr "Маршрут (необязательно):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Маршрут (необязательно):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Транспорт" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "Зарегистрироваться" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Опубликовывать статус присутствия" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Включить" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Настроить учётную запись SIP" @@ -1531,6 +1627,11 @@ msgstr "Предпочтительное разрешение видео:" #: ../gtk/call_statistics.ui.h:11 #, fuzzy +msgid "RTP profile" +msgstr "RTP свойства" + +#: ../gtk/call_statistics.ui.h:12 +#, fuzzy msgid "Call statistics and information" msgstr "Контактная информация" @@ -1738,19 +1839,19 @@ msgstr "Подключение..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "отмененный" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "завершённый" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "пропущенный" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1765,77 +1866,77 @@ msgstr "" "Статус: %s\n" "Длительность: %i мин %i сек\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Исходящий звонок" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Готов" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Подтверждение" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Поиск адреса для телефонного номера..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Не могу найти этот номер." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Соединение" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "Не удалось позвонить" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Извините, мы превысили максимальное количество одновременных вызовов" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "пытается связаться с вами" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr " и ответил автоответчик." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "Изменение параметров вызова..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Соединён." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "Вызов отменён" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "Не удалось приостановить вызов" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Приостановление текущего вызова..." -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "Идет поиск Stun..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1892,7 +1993,7 @@ msgstr "Продолжительность" msgid "Unknown-bug" msgstr "Неизвестная ошибка" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1900,7 +2001,7 @@ msgstr "" "Введеный адрес SIP-прокси является недействительным, он должен выглядеть как " "\"sip:имя_хоста\"" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1909,132 +2010,128 @@ msgstr "" "Они должны выглядеть как sip:username@proxydomain, например such as sip:" "alice@example.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Невозможно зайти как %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Абонент вызывается." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "Абонент вызывается..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Гудки." -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "Вызов %s приостановлен." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "Вызов отвечен %s - в ожидании." -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "Разговор продолжен." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "Вызов отвечен %s." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 #, fuzzy msgid "Incompatible, check codecs or security settings..." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 #, fuzzy msgid "We have been resumed." msgstr "Наш вызов продолжен..." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 #, fuzzy msgid "Call is updated by remote." msgstr "Вызов обновлён вызываемым абонентом..." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Звонок прерван." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Пользователь занят." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Пользователь временно недоступен." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "Абонент не хочет отвечать." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Звонок отклонён." -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "Нет ответа." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Ошибка протокола." - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Переадресован" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 #, fuzzy msgid "Incompatible media parameters." msgstr "Несовместимо, проверьте кодеки..." -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "Не удалось совершить вызов." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Регистрация на %s прошла успешно." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Отмена регистрации на %s завершена." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "время ожидания истекло" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Регистрация на %s не удалась: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, c-format msgid "Authentication token is %s" msgstr "Аутентификационный токен: %s" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -2042,6 +2139,12 @@ msgstr[0] "У вас пропущен %i звонок." msgstr[1] "У вас пропущено %i звонка." msgstr[2] "У вас пропущено %i звонков." +#~ msgid "No response." +#~ msgstr "Нет ответа." + +#~ msgid "Protocol error." +#~ msgstr "Ошибка протокола." + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2271,9 +2374,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ "Ваш компьютер подключен по IPv6. Linphone по умолчанию использует IPv4. " #~ "Пожалуйста, обновите настройки если хотите использовать IPv6." -#~ msgid "Assistant" -#~ msgstr "Помощник" - #, fuzzy #~ msgid "Show debug messages" #~ msgstr "Показать окно ошибок" @@ -2602,9 +2702,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "RTP port used for audio:" #~ msgstr "RTP порт для аудио:" -#~ msgid "RTP properties" -#~ msgstr "RTP свойства" - #~ msgid "Use SIP INFO message instead of RTP rfc2833 for DTMF transmitting" #~ msgstr "" #~ "Используйте SIP INFO сообщения вместо RTP rfc2833 для DTMF препровождения" @@ -2618,9 +2715,6 @@ msgstr[2] "У вас пропущено %i звонков." #~ msgid "micro" #~ msgstr "Микрофон" -#~ msgid "Recording source:" -#~ msgstr "Источник записи:" - #~ msgid "Enable echo-canceler (cancels the echo heard by the remote party)" #~ msgstr "" #~ "Включить подавление эхо (подавляет эхо слышимое с удалённого устройства)" diff --git a/po/sr.po b/po/sr.po index 46e362a45..ed088ef14 100644 --- a/po/sr.po +++ b/po/sr.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2013-02-11 19:03+0200\n" "Last-Translator: Мирослав Николић \n" "Language-Team: Serbian \n" @@ -16,41 +16,41 @@ msgstr "" "Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n" "%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Позови „%s“" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Пошаљи текст за %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "У позиву" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "н/д" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "прекинути" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "пропуштени" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "Одбиј" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" @@ -59,7 +59,7 @@ msgstr[1] "%i минута" msgstr[2] "%i минута" msgstr[3] "Један минут" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" @@ -68,14 +68,14 @@ msgstr[1] "%i секунде" msgstr[2] "%i секунде" msgstr[3] "Једна секунда" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, fuzzy, c-format msgid "%s\t%s" msgstr "" "%s\t%s\tКвалитет: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, fuzzy, c-format msgid "" "%s\tQuality: %s\n" @@ -84,7 +84,7 @@ msgstr "" "%s\t%s\tКвалитет: %s\n" "%s\t%s %s\t" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, fuzzy, c-format msgid "" "%s\t\n" @@ -106,35 +106,35 @@ msgstr "Ја" msgid "Couldn't find pixmap file: %s" msgstr "Не могу да пронађем датотеку сличице: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "Неисправан сип контакт !" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "бележи у стандардни излаз неке податке за уклањање грешака док ради." -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "путања до датотеке за уписивање бележака." -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Покреће се само у системској фиоци, не приказује главно сучеље." -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "адреса за позивање управо сада" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "ако је подешено сам ће се јављати на долазне позиве" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -142,17 +142,22 @@ msgstr "" "Наводи радни директоријум (треба да буде основа инсталације, нпр: c:" "\\Program Files\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Потврђујем" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Помоћник подешавања налога" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Позив са корисником %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -165,7 +170,7 @@ msgstr "" "на ваш списак пријатеља ?\n" "Ако одговорите са не, ова особа ће привремено бити стављена на црни списак." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -174,59 +179,59 @@ msgstr "" "Унесите вашу лозинку за корисничко име %s\n" " на домену %s:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 msgid "Call error" msgstr "Грешка позива" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Позив је завршен" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "Јави се" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Одбиј" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 msgid "Call paused" msgstr "Позив је заустављен" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Кодеци" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Веза веб сајта" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Линфон — интернет телефон са снимком" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (основно)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "Преселили смо се на %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -234,7 +239,7 @@ msgstr "" "Ниједна звучна картица није откривен ана овом рачунару.\n" "Нећете бити у могућности да шаљете или да примате звучне позиве." -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "Слободан СИП телефон са снимком" @@ -246,7 +251,7 @@ msgstr "Додајте у адресар" msgid "Presence status" msgstr "Стање присуства" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Име" @@ -263,142 +268,142 @@ msgstr "" msgid "Search in %s directory" msgstr "Тражи у директоријуму „%s“" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Уредите контакт „%s“" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Обришите контакт „%s“" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Обришите контакт „%s“" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Додајте нови контакт из директоријума „%s“" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Проток (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Стање" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Најмањи проток бита (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Параметри" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "Укључено" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Искључено" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Налог" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Енглески" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Француски" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Шведски" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Италијански" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Шпански" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "Бразилски португалски" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Пољски" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Немачки" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Руски" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "Јапански" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Холандски" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Мађарски" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Чешки" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "Кинески" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "Традиционални кинески" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "Норвешки" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "" "Трба поново да покренете линфон да би нови изабрани језик ступио на снагу." -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "Ништа" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "СРТП" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "ЗРТП" @@ -544,41 +549,41 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Помоћник подешавања налога" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Добродошли у помоћника подешавања налога" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Помоћник подешавања налога" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Подесите СИП налог" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "" @@ -587,194 +592,194 @@ msgstr "" msgid "Call #%i" msgstr "Позови #%i" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "Пребаци позив #%i са %s" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 #, fuzzy msgid "Not used" msgstr "Нисам нашао" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "Позив није успео." -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Преусмерен" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "У току је тражење стуна..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 #, fuzzy msgid "uPnp not available" msgstr "недоступно" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "Позив није успео." -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, fuzzy, c-format msgid "%.3f seconds" msgstr "%i секунда" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Позивам..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "Долазни позив" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "добро" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "просечно" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "оскудно" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "јадно" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "много лоше" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "недоступно" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "Осигурано СРТП-ом" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "Осигурано ЗРТП-ом [потврђивање идентитета: %s]" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "Непроверено подешавање" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "Проверено подешавање" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "На конференцији" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "У позиву" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "Заустављен позив" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Позив је завршен." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 #, fuzzy msgid "Transfer done." msgstr "Пребаци" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Пребаци" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "Настави" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "Застани" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, fuzzy msgid "(Paused)" msgstr "Застани" @@ -794,6 +799,87 @@ msgstr "" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Добродошли !\n" +"Овај помоћник ће вам помоћи да користите СИП налог за ваше позиве." + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Уређај за снимање:" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Уређај за пуштање:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Помоћник подешавања налога" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Помоћник подешавања налога" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 msgid "Callee name" msgstr "Име позивника" @@ -836,124 +922,124 @@ msgid "Call quality rating" msgstr "Оцена квалитета позива" #: ../gtk/main.ui.h:17 +msgid "All users" +msgstr "Сви корисници" + +#: ../gtk/main.ui.h:18 +msgid "Online users" +msgstr "Корисницима на мрежи" + +#: ../gtk/main.ui.h:19 +msgid "ADSL" +msgstr "АДСЛ" + +#: ../gtk/main.ui.h:20 +msgid "Fiber Channel" +msgstr "Оптички канал" + +#: ../gtk/main.ui.h:21 +msgid "Default" +msgstr "Основно" + +#: ../gtk/main.ui.h:22 msgid "_Options" msgstr "_Могућности" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Set configuration URI" msgstr "Потврђујем" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:24 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:25 msgid "Enable self-view" msgstr "Укључи самовиђење" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:26 msgid "_Help" msgstr "По_моћ" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:27 msgid "Show debug window" msgstr "Прикажи прозорче прочишћавања" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:28 msgid "_Homepage" msgstr "_Матична страница" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:29 msgid "Check _Updates" msgstr "Провери _ажурирања" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Account assistant" msgstr "Помоћник подешавања налога" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:32 msgid "SIP address or phone number:" msgstr "СИП адреса или број телефона:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:33 msgid "Initiate a new call" msgstr "Започните нови позив" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:34 msgid "Contacts" msgstr "Пријатељи" -#: ../gtk/main.ui.h:29 +#: ../gtk/main.ui.h:35 msgid "Search" msgstr "Тражи" -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:36 msgid "Add contacts from directory" msgstr "Додај пријатеље из директоријума" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:37 msgid "Add contact" msgstr "Додај пријатеља" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:38 msgid "Recent calls" msgstr "Скорашњи позиви" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:39 msgid "My current identity:" msgstr "Мој тренутни идентитет:" -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "Корисничко име" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "Лозинка" -#: ../gtk/main.ui.h:36 +#: ../gtk/main.ui.h:42 msgid "Internet connection:" msgstr "Интернет веза:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:43 msgid "Automatically log me in" msgstr "Сам ме пријави" -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 msgid "UserID" msgstr "ИБ корисника" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:45 msgid "Login information" msgstr "Подаци пријављивања" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:46 msgid "Welcome !" msgstr "Добродошли !" -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "Сви корисници" - -#: ../gtk/main.ui.h:42 -msgid "Online users" -msgstr "Корисницима на мрежи" - -#: ../gtk/main.ui.h:43 -msgid "ADSL" -msgstr "АДСЛ" - -#: ../gtk/main.ui.h:44 -msgid "Fiber Channel" -msgstr "Оптички канал" - -#: ../gtk/main.ui.h:45 -msgid "Default" -msgstr "Основно" - -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1076,23 +1162,32 @@ msgid "Contact params (optional):" msgstr "Рута (изборно):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Рута (изборно):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Пренос" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "Упиши се" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Објави податке о присуству" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Укључи" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Подесите СИП налог" @@ -1523,6 +1618,10 @@ msgid "Video resolution sent" msgstr "Жељена резолуција снимка:" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 #, fuzzy msgid "Call statistics and information" msgstr "Подаци о пријатељу" @@ -1730,19 +1829,19 @@ msgstr "Повезујем се..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "прекинути" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "завршени" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "пропуштени" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1757,77 +1856,77 @@ msgstr "" "Стање: %s\n" "Трајање: %i мин %i сек\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Одлазни позив" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Спреман" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Потврђујем" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Тражим одредиште телефонског броја..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Не могу да решим овај број." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Ступам у везу" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "Не могу да позовем" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "Извините, достигли смо највећи број истовремених позива" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "вам се обраћа" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr " и затражени само-одговор." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "Мењам параметре позива..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Повезан сам." -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "Позив је прекинут" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "Не могу да зауставим позив" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "Заустављам тренутни позив..." -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "У току је тражење стуна..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1884,7 +1983,7 @@ msgstr "Трајање" msgid "Unknown-bug" msgstr "Непозната грешка" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1892,7 +1991,7 @@ msgstr "" "Адреса сип посредника коју сте унели је неисправна, мора почети на „sip:“ за " "којим следи назив домаћина." -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1901,130 +2000,126 @@ msgstr "" "Треба да изгледа као „sip:корисник@домен-посредника, као што је „sip:" "alice@example.net“" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Не могу да се пријавим као %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Удаљено звоњење." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "Удаљено звоњење..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Ранији медиј." -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "Позив са „%s“ је заустављен." -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "Позив на који је одговорио „%s“ — на чекању." -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "Позив је настављен." -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "На позив је одговорио „%s“." -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 #, fuzzy msgid "We have been resumed." msgstr "Позив нам је настављен..." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 #, fuzzy msgid "Call is updated by remote." msgstr "Позив је ажуриран удаљеним..." -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Позив је завршен." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Корисник је заузет." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Корисник је привремено недоступан." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "Корисник не жели да буде узнемираван." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Позив је одбијен." -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "Нема одговора." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "Грешка у протоколу." - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "Преусмерен" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "Позив није успео." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Уписивање на „%s“ је успело." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Исписивање са „%s“ је обављено." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "нема ограничења одговора" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Уписивање на „%s“ није успело: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, c-format msgid "Authentication token is %s" msgstr "Симбол потврђивања идентитета је „%s“" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." @@ -2033,6 +2128,12 @@ msgstr[1] "Пропустили сте %i позива." msgstr[2] "Пропустили сте %i позива." msgstr[3] "Пропустили сте један позив." +#~ msgid "No response." +#~ msgstr "Нема одговора." + +#~ msgid "Protocol error." +#~ msgstr "Грешка у протоколу." + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" diff --git a/po/sv.po b/po/sv.po index 7d5421323..67e07eab8 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2009-02-17 15:22+0100\n" "Last-Translator: Emmanuel Frécon \n" "Language-Team: SWEDISH \n" @@ -16,67 +16,67 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "Ringer %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "Skicka text till %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "I samtal med" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "avbrytade" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "missade" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "Avböj" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" msgstr[1] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -97,35 +97,35 @@ msgstr "Mikrofon av" msgid "Couldn't find pixmap file: %s" msgstr "Kunde inte hitta pixmap filen: %s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "ogiltig SIP kontakt!" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "skriv loggning information under körning" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "Starta ikonifierat, visa inte huvudfönstret" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "Samtalsmottagare" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "Om på, besvara automatisk alla inkommande samtal" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" @@ -133,17 +133,22 @@ msgstr "" "Välj en arbetskatalog som ska vara basen för installationen, såsom C:" "\\Program\\Linphone" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "Bekräftelse" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "Kontoinstallationsassistenten" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "Samtal med %s" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -156,7 +161,7 @@ msgstr "" "henne till din kontaktlista?\n" "Om du svarar nej, personen kommer att vara bannlyst." -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -165,67 +170,67 @@ msgstr "" "Mata in ditt lösenord för användaren %s\n" "vid domänen %s:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "Samtalshistorik" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "Samtalet slut" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "Avböj" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "avbrytade" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "Portar" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "Webbsajt" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - en video Internet telefon" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (Default)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." msgstr "" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "En gratis SIP video-telefon" @@ -237,7 +242,7 @@ msgstr "" msgid "Presence status" msgstr "Närvarostatus" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "Namn" @@ -255,141 +260,141 @@ msgstr "" msgid "Search in %s directory" msgstr "Sök i %s katalogen" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "Ändra kontakt '%s'" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "Ta bort kontakt '%s'" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "Ta bort kontakt '%s'" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "Lägg till kontakt ifrån %s katalogen" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "Frekvens (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "Status" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "Min. datahastighet (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "Parametrar" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "På" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "Av" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "Konto" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "Engelska" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "Fransk" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "Svenska" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "Italiensk" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "Spanska" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "Portugisiska" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "Polska" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "Tyska" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "Ryska" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "Japanska" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "Nederländksa" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "Hungerska" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "Tjekiska" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "Kinesiska" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "Du behöver starta om programmet för att det nya språket ska synas." -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -533,41 +538,41 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "Kontoinstallationsassistenten" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "Välkommen till kontoinstallationsassistenten" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "Kontoinstallationsassistenten" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "Konfigurera ett SIP konto" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 #, fuzzy msgid "Terminating" msgstr "Lägg på" @@ -577,194 +582,194 @@ msgstr "Lägg på" msgid "Call #%i" msgstr "Ringer %s" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 msgid "Not used" msgstr "" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "Samtalet avböjdes." -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "Omdirigerat till %s..." -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "STUN uppslagning pågår..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "Samtalet avböjdes." -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "Ringer..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00:00:00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "Inkommande samtal" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "I samtal med" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "Lägg på" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i:%02i:%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "Samtalet slut." -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "Samtalet avböjdes." -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "" @@ -783,6 +788,87 @@ msgstr "Inkommande samtal från %s" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"Välkommen!\n" +"Assistenten kommer att hjälpa dig använda ett SIP konto för dina samtal:" + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "Mikrofon enhet:" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "Uppspelningsenhet:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "Assistent" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "Kontoinstallationsassistenten" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -825,137 +911,137 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -#, fuzzy -msgid "Set configuration URI" -msgstr "Bekräftelse" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -msgid "Enable self-view" -msgstr "Själv bild" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:22 -#, fuzzy -msgid "Show debug window" -msgstr "Linphone debug fönster" - -#: ../gtk/main.ui.h:23 -#, fuzzy -msgid "_Homepage" -msgstr "Hemsidan" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Check _Updates" -msgstr "Letar efter uppdateringar" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "Account assistant" -msgstr "Kontoinstallationsassistenten" - -#: ../gtk/main.ui.h:26 -msgid "SIP address or phone number:" -msgstr "Användarnamn" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:28 -#, fuzzy -msgid "Contacts" -msgstr "Kontaktar" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "Sök" - -#: ../gtk/main.ui.h:30 -msgid "Add contacts from directory" -msgstr "Lägg till kontakt ifrån katalogen" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "Hittat kontakt %i" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "I samtal" - -#: ../gtk/main.ui.h:33 -msgid "My current identity:" -msgstr "Min nuvarande identitet" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "Användarnamn" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "Lösenord" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "Internet förbindelse:" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "Logga mig automatiskt" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "AnvändarID" - -#: ../gtk/main.ui.h:39 -msgid "Login information" -msgstr "Login information" - -#: ../gtk/main.ui.h:40 -msgid "Welcome !" -msgstr "Välkommen!" - -#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:18 #, fuzzy msgid "Online users" msgstr "" "Alla användare\n" "Online användare" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "Fiber" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 #, fuzzy msgid "Default" msgstr "%s (Default)" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "Bekräftelse" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +msgid "Enable self-view" +msgstr "Själv bild" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:27 +#, fuzzy +msgid "Show debug window" +msgstr "Linphone debug fönster" + +#: ../gtk/main.ui.h:28 +#, fuzzy +msgid "_Homepage" +msgstr "Hemsidan" + +#: ../gtk/main.ui.h:29 +#, fuzzy +msgid "Check _Updates" +msgstr "Letar efter uppdateringar" + +#: ../gtk/main.ui.h:30 +#, fuzzy +msgid "Account assistant" +msgstr "Kontoinstallationsassistenten" + +#: ../gtk/main.ui.h:32 +msgid "SIP address or phone number:" +msgstr "Användarnamn" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:34 +#, fuzzy +msgid "Contacts" +msgstr "Kontaktar" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "Sök" + +#: ../gtk/main.ui.h:36 +msgid "Add contacts from directory" +msgstr "Lägg till kontakt ifrån katalogen" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "Hittat kontakt %i" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "I samtal" + +#: ../gtk/main.ui.h:39 +msgid "My current identity:" +msgstr "Min nuvarande identitet" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +msgid "Username" +msgstr "Användarnamn" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +msgid "Password" +msgstr "Lösenord" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "Internet förbindelse:" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "Logga mig automatiskt" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "AnvändarID" + +#: ../gtk/main.ui.h:45 +msgid "Login information" +msgstr "Login information" + #: ../gtk/main.ui.h:46 +msgid "Welcome !" +msgstr "Välkommen!" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1067,23 +1153,32 @@ msgid "Contact params (optional):" msgstr "Route (tillval):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "Route (tillval):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "Transport" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "Publicera närvaro information" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "Möjliggör" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "Konfigurera ett SIP konto" @@ -1522,6 +1617,10 @@ msgid "Video resolution sent" msgstr "Video upplösning:" #: ../gtk/call_statistics.ui.h:11 +msgid "RTP profile" +msgstr "" + +#: ../gtk/call_statistics.ui.h:12 #, fuzzy msgid "Call statistics and information" msgstr "Kontakt information" @@ -1728,19 +1827,19 @@ msgstr "Kontaktar" msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "avslutade" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "missade" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1755,82 +1854,82 @@ msgstr "" "Status: %s\n" "Längd: %i min %i sek\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "Utgående samtal" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "Redo" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "Bekräftelse" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "Leta efter telefonnummer för destinationen..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "Kan inte nå dett nummer." #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "Kontaktar" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 #, fuzzy msgid "is contacting you" msgstr "kontaktar dig." -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "" -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "Kopplad" -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "avbrytade" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 #, fuzzy msgid "Could not pause the call" msgstr "Kunde inte ringa" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 #, fuzzy msgid "Pausing the current call..." msgstr "Nuvarande samtal" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "STUN uppslagning pågår..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1887,7 +1986,7 @@ msgstr "Förlopp" msgid "Unknown-bug" msgstr "Okänd bug" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." @@ -1895,7 +1994,7 @@ msgstr "" "SIP proxy adressen som du matade in är inte rätt, adressen måste starta med " "\"sip:\", följd av ett hostnamn" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1903,139 +2002,138 @@ msgstr "" "SIP adressen som du matade in är inte rätt. Adressen borde se ut som sip:" "namn@domän, såsom sip:peter@exempel.se" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "Kunde inte logga in som %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "Ringer hos motparten." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "Tidig media" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "Samtal med %s" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "Samtalet slut" -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "Samtalet slut." -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "Användare upptagen." -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "Användaren temporärt inte tillgänglig." #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "Användaren vill inte bli störd." -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:603 -#, fuzzy -msgid "No response." -msgstr "Inget svar inom angiven tid" - -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." msgstr "" -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 #, fuzzy msgid "Redirected" msgstr "Omdirigerat till %s..." -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 #, fuzzy msgid "Call failed." msgstr "Samtalet avböjdes." -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "Registrering hos %s lyckades." -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "Avregistrering hos %s lyckades." -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "Inget svar inom angiven tid" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "Registrering hos %s mislyckades: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Linphone - Autentisering krävs" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "Du har %i missat samtal" msgstr[1] "Du har %i missade samtal" +#, fuzzy +#~ msgid "No response." +#~ msgstr "Inget svar inom angiven tid" + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2342,9 +2440,6 @@ msgstr[1] "Du har %i missade samtal" #~ "Din dator verkar vara kopplad till ett IPv6 nätverk. Default, använder " #~ "linphone IPv4. Uppdatera din konfiguration om du vill använda IPv6." -#~ msgid "Assistant" -#~ msgstr "Assistent" - #~ msgid "Show debug messages" #~ msgstr "Visa debugfönstret" diff --git a/po/zh_CN.po b/po/zh_CN.po index f55f87dfd..af5a7d776 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.3.2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2011-01-08 23:51+0800\n" "Last-Translator: Aron Xu \n" "Language-Team: Chinese (simplified) \n" @@ -18,65 +18,65 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "呼叫 %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "发送消息给 %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "正在呼叫" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "中断" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "丢失" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "拒绝" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -97,51 +97,56 @@ msgstr "静音" msgid "Couldn't find pixmap file: %s" msgstr "无法打开位图文件:%s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "无效的 SIP 联系人!" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "运行时向标准输出记录调试信息。" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "启动到系统托盘,不显示主界面。" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "现在呼叫的地址" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "是否设置呼叫自动应答" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "指定工作目录(应为安装目录例如 C:\\Program Files\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "确认" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "帐户设置向导" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "与 %s 通话" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -153,68 +158,68 @@ msgstr "" "您是否允许他看到您的在线状态或者将它加为您的联系人允许?\n" "如果您回答否,则会将该人临时性的放入黑名单" -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" " at realm %s:" msgstr "请输入 %s@%s 的密码:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "呼叫历史" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "呼叫结束" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "呼入" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒绝" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "中断" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "端口" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "网站" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - 互联网视频电话" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (默认)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -222,7 +227,7 @@ msgstr "" "未在此计算机上检测到声卡。\n" "您无法发送或接收音频呼叫。" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "免费的 SIP 视频电话" @@ -234,7 +239,7 @@ msgstr "" msgid "Presence status" msgstr "在线状态" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名称" @@ -252,141 +257,141 @@ msgstr "" msgid "Search in %s directory" msgstr "在 %s 目录中查找 " -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "编辑联系人 %s" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "删除联系人 %s" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "删除联系人 %s" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "从 %s 目录增加联系人 " -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "采样率(Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "状态" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "最小比特率(kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "参数" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "启用" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "禁用" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "帐户" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "英语" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "法语" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "瑞典语" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "意大利语" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "西班牙语" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "巴西葡萄牙语" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "波兰语" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "德语" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "俄语" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "日语" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "荷兰语" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "匈牙利语" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "捷克语" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "中文" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重启 linphone 以使语言选择生效。" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -529,41 +534,41 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "帐户设置向导" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "欢迎使用帐户设置向导" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "帐户设置向导" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "配置 SIP 帐户" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 #, fuzzy msgid "Terminating" msgstr "终止呼叫" @@ -573,195 +578,195 @@ msgstr "终止呼叫" msgid "Call #%i" msgstr "呼叫 %s" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 #, fuzzy msgid "Not used" msgstr "未找到" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "ICE 过滤器" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "已重定向" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "正在进行 Stun 查找..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "ICE 过滤器" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "正在呼叫..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 #, fuzzy msgid "Incoming call" msgstr "呼入" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 #, fuzzy msgid "In call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 #, fuzzy msgid "Paused call" msgstr "正在呼叫" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "通话结束。" -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 msgid "Transfer done." msgstr "" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "呼叫失败。" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 msgid "(Paused)" msgstr "" @@ -780,6 +785,87 @@ msgstr "来自 %s 的呼叫" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"欢迎使用 Linphone!\n" +"设置向导将帮助您配置打网络电话的 SIP 帐户。" + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "录音设备:" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "回放设备:" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "配置向导" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "帐户设置向导" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -822,135 +908,135 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 -msgid "_Options" -msgstr "" - -#: ../gtk/main.ui.h:18 -#, fuzzy -msgid "Set configuration URI" -msgstr "确认" - -#: ../gtk/main.ui.h:19 -msgid "Always start video" -msgstr "" - -#: ../gtk/main.ui.h:20 -msgid "Enable self-view" -msgstr "启用自视" - -#: ../gtk/main.ui.h:21 -msgid "_Help" -msgstr "" - -#: ../gtk/main.ui.h:22 -#, fuzzy -msgid "Show debug window" -msgstr "Linphone 调试窗口" - -#: ../gtk/main.ui.h:23 -#, fuzzy -msgid "_Homepage" -msgstr "主页" - -#: ../gtk/main.ui.h:24 -#, fuzzy -msgid "Check _Updates" -msgstr "检查更新" - -#: ../gtk/main.ui.h:25 -#, fuzzy -msgid "Account assistant" -msgstr "帐户设置向导" - -#: ../gtk/main.ui.h:26 -msgid "SIP address or phone number:" -msgstr "SIP 地址或电话号码:" - -#: ../gtk/main.ui.h:27 -msgid "Initiate a new call" -msgstr "" - -#: ../gtk/main.ui.h:28 -msgid "Contacts" -msgstr "联系人" - -#: ../gtk/main.ui.h:29 -msgid "Search" -msgstr "搜索" - -#: ../gtk/main.ui.h:30 -msgid "Add contacts from directory" -msgstr "从目录增加联系人" - -#: ../gtk/main.ui.h:31 -#, fuzzy -msgid "Add contact" -msgstr "找到 %i 联系方式" - -#: ../gtk/main.ui.h:32 -#, fuzzy -msgid "Recent calls" -msgstr "呼入" - -#: ../gtk/main.ui.h:33 -msgid "My current identity:" -msgstr "当前地址:" - -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 -msgid "Username" -msgstr "用户名" - -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 -msgid "Password" -msgstr "密码" - -#: ../gtk/main.ui.h:36 -msgid "Internet connection:" -msgstr "网络连接:" - -#: ../gtk/main.ui.h:37 -msgid "Automatically log me in" -msgstr "自动登录" - -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 -msgid "UserID" -msgstr "用户 ID" - -#: ../gtk/main.ui.h:39 -msgid "Login information" -msgstr "登录信息" - -#: ../gtk/main.ui.h:40 -msgid "Welcome !" -msgstr "欢迎!" - -#: ../gtk/main.ui.h:41 msgid "All users" msgstr "" -#: ../gtk/main.ui.h:42 +#: ../gtk/main.ui.h:18 #, fuzzy msgid "Online users" msgstr "" "全部用户\n" "在线用户" -#: ../gtk/main.ui.h:43 +#: ../gtk/main.ui.h:19 msgid "ADSL" msgstr "" -#: ../gtk/main.ui.h:44 +#: ../gtk/main.ui.h:20 #, fuzzy msgid "Fiber Channel" msgstr "" "ADSL\n" "光纤" -#: ../gtk/main.ui.h:45 +#: ../gtk/main.ui.h:21 msgid "Default" msgstr "默认" +#: ../gtk/main.ui.h:22 +msgid "_Options" +msgstr "" + +#: ../gtk/main.ui.h:23 +#, fuzzy +msgid "Set configuration URI" +msgstr "确认" + +#: ../gtk/main.ui.h:24 +msgid "Always start video" +msgstr "" + +#: ../gtk/main.ui.h:25 +msgid "Enable self-view" +msgstr "启用自视" + +#: ../gtk/main.ui.h:26 +msgid "_Help" +msgstr "" + +#: ../gtk/main.ui.h:27 +#, fuzzy +msgid "Show debug window" +msgstr "Linphone 调试窗口" + +#: ../gtk/main.ui.h:28 +#, fuzzy +msgid "_Homepage" +msgstr "主页" + +#: ../gtk/main.ui.h:29 +#, fuzzy +msgid "Check _Updates" +msgstr "检查更新" + +#: ../gtk/main.ui.h:30 +#, fuzzy +msgid "Account assistant" +msgstr "帐户设置向导" + +#: ../gtk/main.ui.h:32 +msgid "SIP address or phone number:" +msgstr "SIP 地址或电话号码:" + +#: ../gtk/main.ui.h:33 +msgid "Initiate a new call" +msgstr "" + +#: ../gtk/main.ui.h:34 +msgid "Contacts" +msgstr "联系人" + +#: ../gtk/main.ui.h:35 +msgid "Search" +msgstr "搜索" + +#: ../gtk/main.ui.h:36 +msgid "Add contacts from directory" +msgstr "从目录增加联系人" + +#: ../gtk/main.ui.h:37 +#, fuzzy +msgid "Add contact" +msgstr "找到 %i 联系方式" + +#: ../gtk/main.ui.h:38 +#, fuzzy +msgid "Recent calls" +msgstr "呼入" + +#: ../gtk/main.ui.h:39 +msgid "My current identity:" +msgstr "当前地址:" + +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 +msgid "Username" +msgstr "用户名" + +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 +msgid "Password" +msgstr "密码" + +#: ../gtk/main.ui.h:42 +msgid "Internet connection:" +msgstr "网络连接:" + +#: ../gtk/main.ui.h:43 +msgid "Automatically log me in" +msgstr "自动登录" + +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 +msgid "UserID" +msgstr "用户 ID" + +#: ../gtk/main.ui.h:45 +msgid "Login information" +msgstr "登录信息" + #: ../gtk/main.ui.h:46 +msgid "Welcome !" +msgstr "欢迎!" + +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1075,23 +1161,32 @@ msgid "Contact params (optional):" msgstr "路由(可选):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "路由(可选):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "传输协议" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "发布在线状态" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "启用" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "配置 SIP 帐户" @@ -1535,6 +1630,11 @@ msgstr "视频分辨率:" #: ../gtk/call_statistics.ui.h:11 #, fuzzy +msgid "RTP profile" +msgstr "RTP 输入过滤器" + +#: ../gtk/call_statistics.ui.h:12 +#, fuzzy msgid "Call statistics and information" msgstr "联系人信息" @@ -1740,19 +1840,19 @@ msgstr "正在连接..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "完成" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "丢失" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1767,80 +1867,80 @@ msgstr "" "状态:%s\n" "状态:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "呼出" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "就绪" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "确认" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "查询电话号码目的地..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "该号码无法解析。" #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "联系中" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 #, fuzzy msgid "Could not call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "正在联系您" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr " 并询问了自动回答。" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "" -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "已连接。" -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 #, fuzzy msgid "Call aborted" msgstr "中断" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 #, fuzzy msgid "Could not pause the call" msgstr "无法呼叫" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "" -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "正在进行 Stun 查找..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1897,13 +1997,13 @@ msgstr "通话时间" msgid "Unknown-bug" msgstr "未知错误" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "您输入的 SIP 代理地址无效,它必须是以“sip:”开头,并紧随一个主机名。" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1911,135 +2011,137 @@ msgstr "" "您输入的地址无效。\n" "它应具有“sip:用户名@代理域”的形式,例如 sip:alice@example.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "无法登录为 %s" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "响铃。" -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 #, fuzzy msgid "Remote ringing..." msgstr "响铃。" -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, fuzzy, c-format msgid "Call with %s is paused." msgstr "与 %s 通话" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 #, fuzzy msgid "Call resumed." msgstr "呼叫结束" -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 msgid "We have been resumed." msgstr "" -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "通话结束。" -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "被叫正忙。" -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "您呼叫的用户暂时无法接通。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "用户已开启免打扰功能。" -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "呼叫被拒绝。" -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "没有响应。" +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "协议错误。" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "已重定向" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "呼叫失败。" -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "成功注册到 %s" -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "已在 %s 解除注册。" -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "没有响应,超时" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "注册到 %s 失败: %s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "Linphone - 需要认证" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您错过了 %i 个呼叫。" +#~ msgid "No response." +#~ msgstr "没有响应。" + +#~ msgid "Protocol error." +#~ msgstr "协议错误。" + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2199,9 +2301,6 @@ msgstr[0] "您错过了 %i 个呼叫。" #~ msgid "RTP output filter" #~ msgstr "RTP 输出过滤器" -#~ msgid "RTP input filter" -#~ msgstr "RTP 输入过滤器" - #~ msgid "The free and wonderful speex codec" #~ msgstr "优秀的自由软件编解码器 Speex" @@ -2339,9 +2438,6 @@ msgstr[0] "您错过了 %i 个呼叫。" #~ msgid "Sound playback filter for MacOS X Core Audio drivers" #~ msgstr "MacOS X 核心声音驱动音频回放过滤器" -#~ msgid "Assistant" -#~ msgstr "配置向导" - #~ msgid "Show debug messages" #~ msgstr "显示调试信息" diff --git a/po/zh_TW.po b/po/zh_TW.po index 52db94544..e44590a16 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: linphone 3.4\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-02-14 14:57+0100\n" +"POT-Creation-Date: 2014-07-01 21:24+0200\n" "PO-Revision-Date: 2011-04-06 21:24+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: \n" @@ -17,65 +17,65 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: ../gtk/calllogs.c:139 ../gtk/friendlist.c:969 +#: ../gtk/calllogs.c:148 ../gtk/friendlist.c:973 #, c-format msgid "Call %s" msgstr "播打給 %s" -#: ../gtk/calllogs.c:140 ../gtk/friendlist.c:970 +#: ../gtk/calllogs.c:149 ../gtk/friendlist.c:974 #, c-format msgid "Send text to %s" msgstr "傳送文字給 %s" -#: ../gtk/calllogs.c:223 +#: ../gtk/calllogs.c:232 #, fuzzy, c-format msgid "Recent calls (%i)" msgstr "通話中" -#: ../gtk/calllogs.c:300 +#: ../gtk/calllogs.c:312 msgid "n/a" msgstr "" -#: ../gtk/calllogs.c:303 +#: ../gtk/calllogs.c:315 #, fuzzy msgid "Aborted" msgstr "已放棄" -#: ../gtk/calllogs.c:306 +#: ../gtk/calllogs.c:318 #, fuzzy msgid "Missed" msgstr "未接" -#: ../gtk/calllogs.c:309 +#: ../gtk/calllogs.c:321 #, fuzzy msgid "Declined" msgstr "拒接" -#: ../gtk/calllogs.c:315 +#: ../gtk/calllogs.c:327 #, c-format msgid "%i minute" msgid_plural "%i minutes" msgstr[0] "" -#: ../gtk/calllogs.c:318 +#: ../gtk/calllogs.c:330 #, c-format msgid "%i second" msgid_plural "%i seconds" msgstr[0] "" -#: ../gtk/calllogs.c:321 ../gtk/calllogs.c:327 +#: ../gtk/calllogs.c:333 ../gtk/calllogs.c:339 #, c-format msgid "%s\t%s" msgstr "" -#: ../gtk/calllogs.c:323 +#: ../gtk/calllogs.c:335 #, c-format msgid "" "%s\tQuality: %s\n" "%s\t%s\t" msgstr "" -#: ../gtk/calllogs.c:329 +#: ../gtk/calllogs.c:341 #, c-format msgid "" "%s\t\n" @@ -96,52 +96,57 @@ msgstr "靜音" msgid "Couldn't find pixmap file: %s" msgstr "找不到 pixmap 檔:%s" -#: ../gtk/chat.c:363 ../gtk/friendlist.c:919 +#: ../gtk/chat.c:363 ../gtk/friendlist.c:923 msgid "Invalid sip contact !" msgstr "無效的 sip 連絡人!" -#: ../gtk/main.c:102 +#: ../gtk/main.c:107 msgid "log to stdout some debug information while running." msgstr "執行時將一些除錯資訊記錄到標準輸出。" -#: ../gtk/main.c:109 +#: ../gtk/main.c:114 msgid "path to a file to write logs into." msgstr "" -#: ../gtk/main.c:116 +#: ../gtk/main.c:121 msgid "Start linphone with video disabled." msgstr "" -#: ../gtk/main.c:123 +#: ../gtk/main.c:128 msgid "Start only in the system tray, do not show the main interface." msgstr "只在系統匣啟動,不要顯示主要介面。" -#: ../gtk/main.c:130 +#: ../gtk/main.c:135 msgid "address to call right now" msgstr "現在要打電話的位址" -#: ../gtk/main.c:137 +#: ../gtk/main.c:142 msgid "if set automatically answer incoming calls" msgstr "如啟用此項,將會自動接聽來電" -#: ../gtk/main.c:144 +#: ../gtk/main.c:149 msgid "" "Specifiy a working directory (should be the base of the installation, eg: c:" "\\Program Files\\Linphone)" msgstr "" "指定一個工作目錄(應該為安裝的根目錄,例如:c:\\Program Files\\Linphone)" -#: ../gtk/main.c:151 +#: ../gtk/main.c:156 #, fuzzy msgid "Configuration file" msgstr "確認" -#: ../gtk/main.c:573 +#: ../gtk/main.c:163 +#, fuzzy +msgid "Run the audio assistant" +msgstr "帳號設定助理" + +#: ../gtk/main.c:590 #, c-format msgid "Call with %s" msgstr "和 %s 通話" -#: ../gtk/main.c:1150 +#: ../gtk/main.c:1171 #, c-format msgid "" "%s would like to add you to his contact list.\n" @@ -153,7 +158,7 @@ msgstr "" "您是否要允許他看見您的上線狀態或將他加入您的連絡人清單?\n" "如果您回答否,這個人會被暫時列入黑名單。" -#: ../gtk/main.c:1227 +#: ../gtk/main.c:1248 #, fuzzy, c-format msgid "" "Please enter your password for username %s\n" @@ -162,61 +167,61 @@ msgstr "" "請輸入您使用者名稱 %s\n" "於網域 %s 的密碼:" -#: ../gtk/main.c:1339 +#: ../gtk/main.c:1364 #, fuzzy msgid "Call error" msgstr "通話紀錄" -#: ../gtk/main.c:1342 ../coreapi/linphonecore.c:3408 +#: ../gtk/main.c:1367 ../coreapi/linphonecore.c:3515 msgid "Call ended" msgstr "通話已結束" -#: ../gtk/main.c:1345 ../coreapi/linphonecore.c:250 +#: ../gtk/main.c:1370 ../coreapi/linphonecore.c:254 msgid "Incoming call" msgstr "來電" -#: ../gtk/main.c:1347 ../gtk/incall_view.c:508 ../gtk/main.ui.h:5 +#: ../gtk/main.c:1372 ../gtk/incall_view.c:513 ../gtk/main.ui.h:5 msgid "Answer" msgstr "接聽" -#: ../gtk/main.c:1349 ../gtk/main.ui.h:6 +#: ../gtk/main.c:1374 ../gtk/main.ui.h:6 msgid "Decline" msgstr "拒接" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy msgid "Call paused" msgstr "通話已放棄" -#: ../gtk/main.c:1355 +#: ../gtk/main.c:1380 #, fuzzy, c-format msgid "by %s" msgstr "連接埠" -#: ../gtk/main.c:1422 +#: ../gtk/main.c:1447 #, c-format msgid "%s proposed to start video. Do you accept ?" msgstr "" -#: ../gtk/main.c:1584 +#: ../gtk/main.c:1609 msgid "Website link" msgstr "網站連結" -#: ../gtk/main.c:1633 +#: ../gtk/main.c:1658 msgid "Linphone - a video internet phone" msgstr "Linphone - 網路視訊電話" -#: ../gtk/main.c:1725 +#: ../gtk/main.c:1750 #, c-format msgid "%s (Default)" msgstr "%s (預設值)" -#: ../gtk/main.c:2061 ../coreapi/callbacks.c:827 +#: ../gtk/main.c:2086 ../coreapi/callbacks.c:927 #, c-format msgid "We are transferred to %s" msgstr "我們被轉接到 %s" -#: ../gtk/main.c:2071 +#: ../gtk/main.c:2096 msgid "" "No sound cards have been detected on this computer.\n" "You won't be able to send or receive audio calls." @@ -224,7 +229,7 @@ msgstr "" "在這臺電腦中偵測不到音效卡。\n" "您將無法傳送或接收語音電話。" -#: ../gtk/main.c:2207 +#: ../gtk/main.c:2237 msgid "A free SIP video-phone" msgstr "自由的 SIP 視訊電話" @@ -236,7 +241,7 @@ msgstr "" msgid "Presence status" msgstr "上線狀態" -#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:556 ../gtk/contact.ui.h:1 +#: ../gtk/friendlist.c:709 ../gtk/propertybox.c:550 ../gtk/contact.ui.h:1 msgid "Name" msgstr "名稱" @@ -254,141 +259,141 @@ msgstr "" msgid "Search in %s directory" msgstr "在 %s 目錄中搜尋" -#: ../gtk/friendlist.c:971 +#: ../gtk/friendlist.c:975 #, c-format msgid "Edit contact '%s'" msgstr "編輯連絡人「%s」" -#: ../gtk/friendlist.c:972 +#: ../gtk/friendlist.c:976 #, c-format msgid "Delete contact '%s'" msgstr "刪除連絡人「%s」" -#: ../gtk/friendlist.c:973 +#: ../gtk/friendlist.c:977 #, fuzzy, c-format msgid "Delete chat history of '%s'" msgstr "刪除連絡人「%s」" -#: ../gtk/friendlist.c:1024 +#: ../gtk/friendlist.c:1028 #, c-format msgid "Add new contact from %s directory" msgstr "從 %s 目錄加入新的連絡人" -#: ../gtk/propertybox.c:562 +#: ../gtk/propertybox.c:556 msgid "Rate (Hz)" msgstr "頻率 (Hz)" -#: ../gtk/propertybox.c:568 +#: ../gtk/propertybox.c:562 msgid "Status" msgstr "狀態" -#: ../gtk/propertybox.c:574 +#: ../gtk/propertybox.c:568 #, fuzzy -msgid "Bitrate (kbit/s)" +msgid "IP Bitrate (kbit/s)" msgstr "最小頻寬 (kbit/s)" -#: ../gtk/propertybox.c:581 +#: ../gtk/propertybox.c:575 msgid "Parameters" msgstr "參數" -#: ../gtk/propertybox.c:624 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:618 ../gtk/propertybox.c:761 msgid "Enabled" msgstr "已啟用" -#: ../gtk/propertybox.c:626 ../gtk/propertybox.c:767 +#: ../gtk/propertybox.c:620 ../gtk/propertybox.c:761 msgid "Disabled" msgstr "已停用" -#: ../gtk/propertybox.c:813 +#: ../gtk/propertybox.c:807 msgid "Account" msgstr "帳號" -#: ../gtk/propertybox.c:1057 +#: ../gtk/propertybox.c:1061 msgid "English" msgstr "英語" -#: ../gtk/propertybox.c:1058 +#: ../gtk/propertybox.c:1062 msgid "French" msgstr "法語" -#: ../gtk/propertybox.c:1059 +#: ../gtk/propertybox.c:1063 msgid "Swedish" msgstr "瑞典語" -#: ../gtk/propertybox.c:1060 +#: ../gtk/propertybox.c:1064 msgid "Italian" msgstr "義大利語" -#: ../gtk/propertybox.c:1061 +#: ../gtk/propertybox.c:1065 msgid "Spanish" msgstr "西班牙語" -#: ../gtk/propertybox.c:1062 +#: ../gtk/propertybox.c:1066 msgid "Brazilian Portugese" msgstr "巴西葡萄牙語" -#: ../gtk/propertybox.c:1063 +#: ../gtk/propertybox.c:1067 msgid "Polish" msgstr "波蘭語" -#: ../gtk/propertybox.c:1064 +#: ../gtk/propertybox.c:1068 msgid "German" msgstr "德語" -#: ../gtk/propertybox.c:1065 +#: ../gtk/propertybox.c:1069 msgid "Russian" msgstr "俄語" -#: ../gtk/propertybox.c:1066 +#: ../gtk/propertybox.c:1070 msgid "Japanese" msgstr "日語" -#: ../gtk/propertybox.c:1067 +#: ../gtk/propertybox.c:1071 msgid "Dutch" msgstr "荷蘭語" -#: ../gtk/propertybox.c:1068 +#: ../gtk/propertybox.c:1072 msgid "Hungarian" msgstr "匈牙利語" -#: ../gtk/propertybox.c:1069 +#: ../gtk/propertybox.c:1073 msgid "Czech" msgstr "捷克語" -#: ../gtk/propertybox.c:1070 +#: ../gtk/propertybox.c:1074 msgid "Chinese" msgstr "中文" -#: ../gtk/propertybox.c:1071 +#: ../gtk/propertybox.c:1075 msgid "Traditional Chinese" msgstr "" -#: ../gtk/propertybox.c:1072 +#: ../gtk/propertybox.c:1076 msgid "Norwegian" msgstr "" -#: ../gtk/propertybox.c:1073 +#: ../gtk/propertybox.c:1077 msgid "Hebrew" msgstr "" -#: ../gtk/propertybox.c:1074 +#: ../gtk/propertybox.c:1078 msgid "Serbian" msgstr "" -#: ../gtk/propertybox.c:1141 +#: ../gtk/propertybox.c:1145 msgid "" "You need to restart linphone for the new language selection to take effect." msgstr "您需要重新啟動 linphone 才能讓新選擇的語言生效。" -#: ../gtk/propertybox.c:1219 +#: ../gtk/propertybox.c:1223 msgid "None" msgstr "" -#: ../gtk/propertybox.c:1223 +#: ../gtk/propertybox.c:1227 msgid "SRTP" msgstr "" -#: ../gtk/propertybox.c:1229 +#: ../gtk/propertybox.c:1233 msgid "ZRTP" msgstr "" @@ -531,41 +536,41 @@ msgid "" "Then come back here and press Next button." msgstr "" -#: ../gtk/setupwizard.c:572 +#: ../gtk/setupwizard.c:564 #, fuzzy msgid "SIP account configuration assistant" msgstr "帳號設定助理" -#: ../gtk/setupwizard.c:590 +#: ../gtk/setupwizard.c:582 msgid "Welcome to the account setup assistant" msgstr "歡迎使用帳號設定助理" -#: ../gtk/setupwizard.c:595 +#: ../gtk/setupwizard.c:587 msgid "Account setup assistant" msgstr "帳號設定助理" -#: ../gtk/setupwizard.c:601 +#: ../gtk/setupwizard.c:593 #, fuzzy msgid "Configure your account (step 1/1)" msgstr "設定 SIP 帳號" -#: ../gtk/setupwizard.c:606 +#: ../gtk/setupwizard.c:598 msgid "Enter your sip username (step 1/1)" msgstr "" -#: ../gtk/setupwizard.c:610 +#: ../gtk/setupwizard.c:602 msgid "Enter account information (step 1/2)" msgstr "" -#: ../gtk/setupwizard.c:619 +#: ../gtk/setupwizard.c:611 msgid "Validation (step 2/2)" msgstr "" -#: ../gtk/setupwizard.c:624 +#: ../gtk/setupwizard.c:616 msgid "Error" msgstr "" -#: ../gtk/setupwizard.c:628 +#: ../gtk/setupwizard.c:620 ../gtk/audio_assistant.c:519 msgid "Terminating" msgstr "" @@ -574,193 +579,193 @@ msgstr "" msgid "Call #%i" msgstr "播打給 %s" -#: ../gtk/incall_view.c:154 +#: ../gtk/incall_view.c:155 #, c-format msgid "Transfer to call #%i with %s" msgstr "" -#: ../gtk/incall_view.c:210 ../gtk/incall_view.c:213 +#: ../gtk/incall_view.c:211 ../gtk/incall_view.c:214 #, fuzzy msgid "Not used" msgstr "找不到" -#: ../gtk/incall_view.c:220 +#: ../gtk/incall_view.c:221 msgid "ICE not activated" msgstr "" -#: ../gtk/incall_view.c:222 +#: ../gtk/incall_view.c:223 #, fuzzy msgid "ICE failed" msgstr "ICE 過濾器" -#: ../gtk/incall_view.c:224 +#: ../gtk/incall_view.c:225 msgid "ICE in progress" msgstr "" -#: ../gtk/incall_view.c:226 +#: ../gtk/incall_view.c:227 msgid "Going through one or more NATs" msgstr "" -#: ../gtk/incall_view.c:228 +#: ../gtk/incall_view.c:229 #, fuzzy msgid "Direct" msgstr "已重新導向" -#: ../gtk/incall_view.c:230 +#: ../gtk/incall_view.c:231 msgid "Through a relay server" msgstr "" -#: ../gtk/incall_view.c:238 +#: ../gtk/incall_view.c:239 msgid "uPnP not activated" msgstr "" -#: ../gtk/incall_view.c:240 +#: ../gtk/incall_view.c:241 #, fuzzy msgid "uPnP in progress" msgstr "正在進行 Stun 搜尋..." -#: ../gtk/incall_view.c:242 +#: ../gtk/incall_view.c:243 msgid "uPnp not available" msgstr "" -#: ../gtk/incall_view.c:244 +#: ../gtk/incall_view.c:245 msgid "uPnP is running" msgstr "" -#: ../gtk/incall_view.c:246 +#: ../gtk/incall_view.c:247 #, fuzzy msgid "uPnP failed" msgstr "ICE 過濾器" -#: ../gtk/incall_view.c:256 ../gtk/incall_view.c:257 +#: ../gtk/incall_view.c:257 ../gtk/incall_view.c:258 msgid "Direct or through server" msgstr "" -#: ../gtk/incall_view.c:261 ../gtk/incall_view.c:272 +#: ../gtk/incall_view.c:266 ../gtk/incall_view.c:276 #, c-format msgid "" "download: %f\n" "upload: %f (kbit/s)" msgstr "" -#: ../gtk/incall_view.c:267 ../gtk/incall_view.c:268 +#: ../gtk/incall_view.c:271 ../gtk/incall_view.c:272 #, c-format msgid "%ix%i" msgstr "" -#: ../gtk/incall_view.c:297 +#: ../gtk/incall_view.c:301 #, c-format msgid "%.3f seconds" msgstr "" -#: ../gtk/incall_view.c:395 ../gtk/main.ui.h:12 +#: ../gtk/incall_view.c:399 ../gtk/main.ui.h:12 msgid "Hang up" msgstr "" -#: ../gtk/incall_view.c:487 +#: ../gtk/incall_view.c:492 msgid "Calling..." msgstr "播打..." -#: ../gtk/incall_view.c:490 ../gtk/incall_view.c:700 +#: ../gtk/incall_view.c:495 ../gtk/incall_view.c:698 msgid "00::00::00" msgstr "00::00::00" -#: ../gtk/incall_view.c:501 +#: ../gtk/incall_view.c:506 msgid "Incoming call" msgstr "來電" -#: ../gtk/incall_view.c:538 +#: ../gtk/incall_view.c:543 msgid "good" msgstr "" -#: ../gtk/incall_view.c:540 +#: ../gtk/incall_view.c:545 msgid "average" msgstr "" -#: ../gtk/incall_view.c:542 +#: ../gtk/incall_view.c:547 msgid "poor" msgstr "" -#: ../gtk/incall_view.c:544 +#: ../gtk/incall_view.c:549 msgid "very poor" msgstr "" -#: ../gtk/incall_view.c:546 +#: ../gtk/incall_view.c:551 msgid "too bad" msgstr "" -#: ../gtk/incall_view.c:547 ../gtk/incall_view.c:563 +#: ../gtk/incall_view.c:552 ../gtk/incall_view.c:568 msgid "unavailable" msgstr "" -#: ../gtk/incall_view.c:662 +#: ../gtk/incall_view.c:660 msgid "Secured by SRTP" msgstr "" -#: ../gtk/incall_view.c:668 +#: ../gtk/incall_view.c:666 #, c-format msgid "Secured by ZRTP - [auth token: %s]" msgstr "" -#: ../gtk/incall_view.c:674 +#: ../gtk/incall_view.c:672 msgid "Set unverified" msgstr "" -#: ../gtk/incall_view.c:674 ../gtk/main.ui.h:4 +#: ../gtk/incall_view.c:672 ../gtk/main.ui.h:4 msgid "Set verified" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In conference" msgstr "" -#: ../gtk/incall_view.c:695 +#: ../gtk/incall_view.c:693 msgid "In call" msgstr "通話中" -#: ../gtk/incall_view.c:731 +#: ../gtk/incall_view.c:729 msgid "Paused call" msgstr "暫停通話" -#: ../gtk/incall_view.c:744 +#: ../gtk/incall_view.c:742 #, c-format msgid "%02i::%02i::%02i" msgstr "%02i::%02i::%02i" -#: ../gtk/incall_view.c:762 +#: ../gtk/incall_view.c:760 msgid "Call ended." msgstr "通話結束。" -#: ../gtk/incall_view.c:793 +#: ../gtk/incall_view.c:791 msgid "Transfer in progress" msgstr "" -#: ../gtk/incall_view.c:796 +#: ../gtk/incall_view.c:794 #, fuzzy msgid "Transfer done." msgstr "轉接" -#: ../gtk/incall_view.c:799 +#: ../gtk/incall_view.c:797 #, fuzzy msgid "Transfer failed." msgstr "轉接" -#: ../gtk/incall_view.c:843 +#: ../gtk/incall_view.c:841 msgid "Resume" msgstr "繼續" -#: ../gtk/incall_view.c:850 ../gtk/main.ui.h:9 +#: ../gtk/incall_view.c:848 ../gtk/main.ui.h:9 msgid "Pause" msgstr "暫停" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, c-format msgid "" "Recording into\n" "%s %s" msgstr "" -#: ../gtk/incall_view.c:915 +#: ../gtk/incall_view.c:913 #, fuzzy msgid "(Paused)" msgstr "暫停" @@ -780,6 +785,87 @@ msgstr "" msgid "Downloading of remote configuration from %s failed." msgstr "" +#: ../gtk/audio_assistant.c:98 +msgid "No voice detected" +msgstr "" + +#: ../gtk/audio_assistant.c:99 +msgid "Too low" +msgstr "" + +#: ../gtk/audio_assistant.c:100 +msgid "Good" +msgstr "" + +#: ../gtk/audio_assistant.c:101 +msgid "Too loud" +msgstr "" + +#: ../gtk/audio_assistant.c:316 +#, fuzzy +msgid "" +"Welcome !\n" +"This assistant will help you to configure audio settings for Linphone" +msgstr "" +"歡迎!\n" +"這個助理會協助您使用電話的 SIP 帳號。" + +#: ../gtk/audio_assistant.c:326 +#, fuzzy +msgid "Capture device" +msgstr "捕捉裝置:" + +#: ../gtk/audio_assistant.c:327 +msgid "Recorded volume" +msgstr "" + +#: ../gtk/audio_assistant.c:331 +msgid "No voice" +msgstr "" + +#: ../gtk/audio_assistant.c:367 +#, fuzzy +msgid "Playback device" +msgstr "播放裝置" + +#: ../gtk/audio_assistant.c:368 +msgid "Play three beeps" +msgstr "" + +#: ../gtk/audio_assistant.c:400 +msgid "Press the record button and say some words" +msgstr "" + +#: ../gtk/audio_assistant.c:401 +msgid "Listen to your record voice" +msgstr "" + +#: ../gtk/audio_assistant.c:430 +msgid "Let's start Linphone now" +msgstr "" + +#: ../gtk/audio_assistant.c:488 +#, fuzzy +msgid "Audio Assistant" +msgstr "帳號設定助理" + +#: ../gtk/audio_assistant.c:498 ../gtk/main.ui.h:31 +#, fuzzy +msgid "Audio assistant" +msgstr "帳號設定助理" + +#: ../gtk/audio_assistant.c:503 +msgid "Mic Gain calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:509 +msgid "Speaker volume calibration" +msgstr "" + +#: ../gtk/audio_assistant.c:514 +msgid "Record and Play" +msgstr "" + #: ../gtk/main.ui.h:1 #, fuzzy msgid "Callee name" @@ -822,125 +908,125 @@ msgid "Call quality rating" msgstr "" #: ../gtk/main.ui.h:17 +msgid "All users" +msgstr "所有使用者" + +#: ../gtk/main.ui.h:18 +msgid "Online users" +msgstr "線上使用者" + +#: ../gtk/main.ui.h:19 +msgid "ADSL" +msgstr "ADSL" + +#: ../gtk/main.ui.h:20 +msgid "Fiber Channel" +msgstr "光纖通道" + +#: ../gtk/main.ui.h:21 +msgid "Default" +msgstr "預設值" + +#: ../gtk/main.ui.h:22 msgid "_Options" msgstr "選項(_O)" -#: ../gtk/main.ui.h:18 +#: ../gtk/main.ui.h:23 #, fuzzy msgid "Set configuration URI" msgstr "確認" -#: ../gtk/main.ui.h:19 +#: ../gtk/main.ui.h:24 msgid "Always start video" msgstr "" -#: ../gtk/main.ui.h:20 +#: ../gtk/main.ui.h:25 msgid "Enable self-view" msgstr "啟用自拍檢視" -#: ../gtk/main.ui.h:21 +#: ../gtk/main.ui.h:26 msgid "_Help" msgstr "求助(_H)" -#: ../gtk/main.ui.h:22 +#: ../gtk/main.ui.h:27 msgid "Show debug window" msgstr "顯示除錯視窗" -#: ../gtk/main.ui.h:23 +#: ../gtk/main.ui.h:28 msgid "_Homepage" msgstr "官方網頁(_H)" -#: ../gtk/main.ui.h:24 +#: ../gtk/main.ui.h:29 msgid "Check _Updates" msgstr "檢查更新(_U)" -#: ../gtk/main.ui.h:25 +#: ../gtk/main.ui.h:30 #, fuzzy msgid "Account assistant" msgstr "帳號設定助理" -#: ../gtk/main.ui.h:26 +#: ../gtk/main.ui.h:32 msgid "SIP address or phone number:" msgstr "SIP 位址或電話號碼:" -#: ../gtk/main.ui.h:27 +#: ../gtk/main.ui.h:33 msgid "Initiate a new call" msgstr "打出新電話" -#: ../gtk/main.ui.h:28 +#: ../gtk/main.ui.h:34 msgid "Contacts" msgstr "連絡人" -#: ../gtk/main.ui.h:29 +#: ../gtk/main.ui.h:35 msgid "Search" msgstr "搜尋" -#: ../gtk/main.ui.h:30 +#: ../gtk/main.ui.h:36 msgid "Add contacts from directory" msgstr "從目錄加入連絡人" -#: ../gtk/main.ui.h:31 +#: ../gtk/main.ui.h:37 msgid "Add contact" msgstr "加入聯絡人" -#: ../gtk/main.ui.h:32 +#: ../gtk/main.ui.h:38 #, fuzzy msgid "Recent calls" msgstr "通話中" -#: ../gtk/main.ui.h:33 +#: ../gtk/main.ui.h:39 msgid "My current identity:" msgstr "我目前的使用者識別:" -#: ../gtk/main.ui.h:34 ../gtk/tunnel_config.ui.h:7 +#: ../gtk/main.ui.h:40 ../gtk/tunnel_config.ui.h:7 msgid "Username" msgstr "使用者名稱" -#: ../gtk/main.ui.h:35 ../gtk/tunnel_config.ui.h:8 +#: ../gtk/main.ui.h:41 ../gtk/tunnel_config.ui.h:8 msgid "Password" msgstr "密碼" -#: ../gtk/main.ui.h:36 +#: ../gtk/main.ui.h:42 msgid "Internet connection:" msgstr "網路連線:" -#: ../gtk/main.ui.h:37 +#: ../gtk/main.ui.h:43 msgid "Automatically log me in" msgstr "將我自動登入" -#: ../gtk/main.ui.h:38 ../gtk/password.ui.h:3 +#: ../gtk/main.ui.h:44 ../gtk/password.ui.h:3 msgid "UserID" msgstr "使用者ID" -#: ../gtk/main.ui.h:39 +#: ../gtk/main.ui.h:45 msgid "Login information" msgstr "登入資訊" -#: ../gtk/main.ui.h:40 +#: ../gtk/main.ui.h:46 msgid "Welcome !" msgstr "歡迎使用!" -#: ../gtk/main.ui.h:41 -msgid "All users" -msgstr "所有使用者" - -#: ../gtk/main.ui.h:42 -msgid "Online users" -msgstr "線上使用者" - -#: ../gtk/main.ui.h:43 -msgid "ADSL" -msgstr "ADSL" - -#: ../gtk/main.ui.h:44 -msgid "Fiber Channel" -msgstr "光纖通道" - -#: ../gtk/main.ui.h:45 -msgid "Default" -msgstr "預設值" - -#: ../gtk/main.ui.h:46 +#: ../gtk/main.ui.h:47 msgid "Delete" msgstr "" @@ -1062,23 +1148,32 @@ msgid "Contact params (optional):" msgstr "路由 (選擇性):" #: ../gtk/sip_account.ui.h:9 +msgid "AVPF regular RTCP interval (sec):" +msgstr "" + +#: ../gtk/sip_account.ui.h:10 msgid "Route (optional):" msgstr "路由 (選擇性):" -#: ../gtk/sip_account.ui.h:10 +#: ../gtk/sip_account.ui.h:11 #, fuzzy msgid "Transport" msgstr "傳輸" -#: ../gtk/sip_account.ui.h:11 +#: ../gtk/sip_account.ui.h:12 msgid "Register" msgstr "" -#: ../gtk/sip_account.ui.h:12 +#: ../gtk/sip_account.ui.h:13 msgid "Publish presence information" msgstr "發布上線資訊" -#: ../gtk/sip_account.ui.h:13 +#: ../gtk/sip_account.ui.h:14 +#, fuzzy +msgid "Enable AVPF" +msgstr "啟用" + +#: ../gtk/sip_account.ui.h:15 msgid "Configure a SIP account" msgstr "設定 SIP 帳號" @@ -1510,6 +1605,11 @@ msgstr "偏好的視訊解析度:" #: ../gtk/call_statistics.ui.h:11 #, fuzzy +msgid "RTP profile" +msgstr "RTP 輸入過濾隱器" + +#: ../gtk/call_statistics.ui.h:12 +#, fuzzy msgid "Call statistics and information" msgstr "連絡人資訊" @@ -1715,19 +1815,19 @@ msgstr "連線中..." msgid "Please wait while fetching configuration from server..." msgstr "" -#: ../coreapi/linphonecore.c:238 +#: ../coreapi/linphonecore.c:242 msgid "aborted" msgstr "已放棄" -#: ../coreapi/linphonecore.c:241 +#: ../coreapi/linphonecore.c:245 msgid "completed" msgstr "已完成" -#: ../coreapi/linphonecore.c:244 +#: ../coreapi/linphonecore.c:248 msgid "missed" msgstr "未接" -#: ../coreapi/linphonecore.c:249 +#: ../coreapi/linphonecore.c:253 #, c-format msgid "" "%s at %s\n" @@ -1742,77 +1842,77 @@ msgstr "" "狀態:%s\n" "持續時間:%i 分 %i 秒\n" -#: ../coreapi/linphonecore.c:250 +#: ../coreapi/linphonecore.c:254 msgid "Outgoing call" msgstr "去電" -#: ../coreapi/linphonecore.c:1264 +#: ../coreapi/linphonecore.c:1287 msgid "Ready" msgstr "準備就緒" -#: ../coreapi/linphonecore.c:1372 +#: ../coreapi/linphonecore.c:2248 #, fuzzy msgid "Configuring" msgstr "確認" -#: ../coreapi/linphonecore.c:2331 +#: ../coreapi/linphonecore.c:2410 msgid "Looking for telephone number destination..." msgstr "尋找電話號碼目的端..." -#: ../coreapi/linphonecore.c:2334 +#: ../coreapi/linphonecore.c:2413 msgid "Could not resolve this number." msgstr "無法解析這個號碼。" #. must be known at that time -#: ../coreapi/linphonecore.c:2609 +#: ../coreapi/linphonecore.c:2695 msgid "Contacting" msgstr "正在連絡" -#: ../coreapi/linphonecore.c:2616 +#: ../coreapi/linphonecore.c:2702 msgid "Could not call" msgstr "無法通話" -#: ../coreapi/linphonecore.c:2765 +#: ../coreapi/linphonecore.c:2852 msgid "Sorry, we have reached the maximum number of simultaneous calls" msgstr "抱歉,我們已達瀏同步通話的最大數目" -#: ../coreapi/linphonecore.c:2952 +#: ../coreapi/linphonecore.c:3022 msgid "is contacting you" msgstr "正在連絡您" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid " and asked autoanswer." msgstr "並要求自動接聽。" -#: ../coreapi/linphonecore.c:2953 +#: ../coreapi/linphonecore.c:3023 msgid "." msgstr "." -#: ../coreapi/linphonecore.c:3020 +#: ../coreapi/linphonecore.c:3139 msgid "Modifying call parameters..." msgstr "修改通話參數..." -#: ../coreapi/linphonecore.c:3362 +#: ../coreapi/linphonecore.c:3469 msgid "Connected." msgstr "已連線。" -#: ../coreapi/linphonecore.c:3388 +#: ../coreapi/linphonecore.c:3495 msgid "Call aborted" msgstr "通話已放棄" -#: ../coreapi/linphonecore.c:3581 +#: ../coreapi/linphonecore.c:3685 msgid "Could not pause the call" msgstr "無法暫停通話" -#: ../coreapi/linphonecore.c:3586 +#: ../coreapi/linphonecore.c:3690 msgid "Pausing the current call..." msgstr "暫停目前的通話..." -#: ../coreapi/misc.c:394 +#: ../coreapi/misc.c:425 msgid "Stun lookup in progress..." msgstr "正在進行 Stun 搜尋..." -#: ../coreapi/misc.c:576 +#: ../coreapi/misc.c:607 msgid "ICE local candidates gathering in progress..." msgstr "" @@ -1869,14 +1969,14 @@ msgstr "時間長度" msgid "Unknown-bug" msgstr "不明錯誤" -#: ../coreapi/proxy.c:209 +#: ../coreapi/proxy.c:279 msgid "" "The sip proxy address you entered is invalid, it must start with \"sip:\" " "followed by a hostname." msgstr "" "您輸入的 sip 代理位址是無效的,它必須要以「sip:」開頭,後面接主機名稱。" -#: ../coreapi/proxy.c:215 +#: ../coreapi/proxy.c:285 msgid "" "The sip identity you entered is invalid.\n" "It should look like sip:username@proxydomain, such as sip:alice@example.net" @@ -1884,134 +1984,136 @@ msgstr "" "您輸入的 sip 身分是無效的。\n" "它應該看起來像 sip:使用者名稱@代理網域,像是 sip:alice@example.net" -#: ../coreapi/proxy.c:1125 +#: ../coreapi/proxy.c:1299 #, c-format msgid "Could not login as %s" msgstr "無法以 %s 登入" -#: ../coreapi/callbacks.c:289 +#: ../coreapi/callbacks.c:354 msgid "Remote ringing." msgstr "遠端響鈴。" -#: ../coreapi/callbacks.c:305 +#: ../coreapi/callbacks.c:370 msgid "Remote ringing..." msgstr "遠端響鈴..." -#: ../coreapi/callbacks.c:316 +#: ../coreapi/callbacks.c:381 msgid "Early media." msgstr "早期媒體。" -#: ../coreapi/callbacks.c:367 +#: ../coreapi/callbacks.c:432 #, c-format msgid "Call with %s is paused." msgstr "和 %s 的通話已暫停。" -#: ../coreapi/callbacks.c:380 +#: ../coreapi/callbacks.c:445 #, c-format msgid "Call answered by %s - on hold." msgstr "通話由 %s 接聽 - 保留中。" -#: ../coreapi/callbacks.c:391 +#: ../coreapi/callbacks.c:456 msgid "Call resumed." msgstr "通話已繼續。" -#: ../coreapi/callbacks.c:396 +#: ../coreapi/callbacks.c:461 #, c-format msgid "Call answered by %s." msgstr "通話由 %s 接聽。" -#: ../coreapi/callbacks.c:414 +#: ../coreapi/callbacks.c:480 msgid "Incompatible, check codecs or security settings..." msgstr "" -#: ../coreapi/callbacks.c:463 +#: ../coreapi/callbacks.c:531 #, fuzzy msgid "We have been resumed." msgstr "我們要繼續了..." -#: ../coreapi/callbacks.c:471 +#: ../coreapi/callbacks.c:541 msgid "We are paused by other party." msgstr "" -#: ../coreapi/callbacks.c:487 +#: ../coreapi/callbacks.c:558 msgid "Call is updated by remote." msgstr "" -#: ../coreapi/callbacks.c:558 +#: ../coreapi/callbacks.c:637 msgid "Call terminated." msgstr "通話已終止。" -#: ../coreapi/callbacks.c:586 +#: ../coreapi/callbacks.c:666 msgid "User is busy." msgstr "使用者現正忙碌。" -#: ../coreapi/callbacks.c:587 +#: ../coreapi/callbacks.c:667 msgid "User is temporarily unavailable." msgstr "使用者暫時無法聯繫。" #. char *retrymsg=_("%s. Retry after %i minute(s)."); -#: ../coreapi/callbacks.c:589 +#: ../coreapi/callbacks.c:669 msgid "User does not want to be disturbed." msgstr "使用者不想要被打擾。" -#: ../coreapi/callbacks.c:590 +#: ../coreapi/callbacks.c:670 msgid "Call declined." msgstr "通話被拒接。" -#: ../coreapi/callbacks.c:603 -msgid "No response." -msgstr "沒有回應。" +#: ../coreapi/callbacks.c:685 +msgid "Request timeout." +msgstr "" -#: ../coreapi/callbacks.c:607 -msgid "Protocol error." -msgstr "通訊協定錯誤。" - -#: ../coreapi/callbacks.c:623 +#: ../coreapi/callbacks.c:716 msgid "Redirected" msgstr "已重新導向" -#: ../coreapi/callbacks.c:665 +#: ../coreapi/callbacks.c:766 msgid "Incompatible media parameters." msgstr "" -#: ../coreapi/callbacks.c:677 +#: ../coreapi/callbacks.c:777 msgid "Call failed." msgstr "通話失敗。" -#: ../coreapi/callbacks.c:751 +#: ../coreapi/callbacks.c:852 #, c-format msgid "Registration on %s successful." msgstr "在 %s 註冊成功。" -#: ../coreapi/callbacks.c:752 +#: ../coreapi/callbacks.c:853 #, c-format msgid "Unregistration on %s done." msgstr "在 %s 取消註冊完成。" -#: ../coreapi/callbacks.c:772 +#: ../coreapi/callbacks.c:875 msgid "no response timeout" msgstr "沒有回應逾時" -#: ../coreapi/callbacks.c:775 +#: ../coreapi/callbacks.c:878 #, c-format msgid "Registration on %s failed: %s" msgstr "在 %s 註冊失敗:%s" -#: ../coreapi/callbacks.c:785 +#: ../coreapi/callbacks.c:885 msgid "Service unavailable, retrying" msgstr "" -#: ../coreapi/linphonecall.c:142 +#: ../coreapi/linphonecall.c:175 #, fuzzy, c-format msgid "Authentication token is %s" msgstr "驗證失敗" -#: ../coreapi/linphonecall.c:2678 +#: ../coreapi/linphonecall.c:2994 #, c-format msgid "You have missed %i call." msgid_plural "You have missed %i calls." msgstr[0] "您有 %i 通未接來電。" +#~ msgid "No response." +#~ msgstr "沒有回應。" + +#~ msgid "Protocol error." +#~ msgstr "通訊協定錯誤。" + #~ msgid "" #~ "Could not parse given sip address. A sip url usually looks like sip:" #~ "user@domain" @@ -2203,9 +2305,6 @@ msgstr[0] "您有 %i 通未接來電。" #~ msgid "RTP output filter" #~ msgstr "RTP 輸出過濾隱器" -#~ msgid "RTP input filter" -#~ msgstr "RTP 輸入過濾隱器" - #~ msgid "The free and wonderful speex codec" #~ msgstr "免費好用的 speex 編解碼器" From a21d7d863df199dd385120426a13dc336835bb0e Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Tue, 1 Jul 2014 22:00:41 +0200 Subject: [PATCH 196/201] improve message tester --- tester/liblinphone_tester.h | 2 ++ tester/message_tester.c | 30 ++++++++++++++----- tester/rcfiles/marie_remote_default_values_rc | 3 ++ tester/remote_provisioning_tester.c | 11 +++++-- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 239e30e0b..8fbeafc31 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -124,6 +124,7 @@ typedef struct _stats { int number_of_LinphoneTransferCallError; int number_of_LinphoneMessageReceived; + int number_of_LinphoneMessageReceivedWithFile; int number_of_LinphoneMessageReceivedLegacy; int number_of_LinphoneMessageExtBodyReceived; int number_of_LinphoneMessageInProgress; @@ -191,6 +192,7 @@ typedef struct _stats { int number_of_LinphoneCallEncryptedOn; int number_of_LinphoneCallEncryptedOff; + LinphoneChatMessage* last_received_chat_message; }stats; typedef struct _LinphoneCoreManager { diff --git a/tester/message_tester.c b/tester/message_tester.c index 85b5f2e00..daafac426 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -40,20 +40,22 @@ void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMess stats* counters; const char *text=linphone_chat_message_get_text(message); const char *external_body_url=linphone_chat_message_get_external_body_url(message); - const LinphoneContent *file_transfer_info=linphone_chat_message_get_file_transfer_information(message); - ms_message("Message from [%s] is [%s] , external URL [%s]",from?from:"" ,text?text:"" ,external_body_url?external_body_url:""); ms_free(from); counters = get_stats(lc); counters->number_of_LinphoneMessageReceived++; - if (file_transfer_info) { /* if we have a file transfer in RCS mode, start the download */ - linphone_chat_message_start_file_download(message); - } else if (linphone_chat_message_get_external_body_url(message)) { + if (linphone_chat_message_get_file_transfer_information(message)) + counters->number_of_LinphoneMessageReceivedWithFile++; + if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message); + linphone_chat_message_ref(counters->last_received_chat_message=message); + if (linphone_chat_message_get_external_body_url(message)) { counters->number_of_LinphoneMessageExtBodyReceived++; - if (message_external_body_url) + if (message_external_body_url) { CU_ASSERT_STRING_EQUAL(linphone_chat_message_get_external_body_url(message),message_external_body_url); + message_external_body_url=NULL; + } } } @@ -349,6 +351,8 @@ static void file_transfer_message(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); for (i=0;iidentity); chat_room = linphone_core_create_chat_room(pauline->lc,to); - + ms_free(to); /* create a file transfer message */ memset(&content,0,sizeof(content)); content.type="text"; @@ -372,7 +376,10 @@ static void file_transfer_message(void) { message = linphone_chat_room_create_file_transfer_message(chat_room, &content); linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,pauline->lc); - CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageExtBodyReceived,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceivedWithFile,1)); + if (marie->stat.last_received_info_message ) { + linphone_chat_message_start_file_download((const LinphoneChatMessage*)marie->stat.last_received_info_message); + } CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneMessageDelivered,1)); CU_ASSERT_EQUAL(pauline->stat.number_of_LinphoneMessageInProgress,1); @@ -391,6 +398,8 @@ static void file_transfer_message_io_error(void) { const char* big_file_content="big file"; /* setting dummy file content to something */ LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); /* setting dummy file content to something */ for (i=0;iidentity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); + /*simultate a network error*/ sal_set_send_error(marie->lc->sal, -1); linphone_chat_room_send_message2(chat_room,message,liblinphone_tester_chat_message_state_change,marie->lc); @@ -463,6 +475,8 @@ static void text_message_denied(void) { char* to = linphone_address_as_string(pauline->identity); LinphoneChatRoom* chat_room = linphone_core_create_chat_room(marie->lc,to); LinphoneChatMessage* message = linphone_chat_room_create_message(chat_room,"Bli bli bli \n blu"); + reset_counters(&marie->stat); + reset_counters(&pauline->stat); /*pauline doesn't want to be disturbed*/ linphone_core_disable_chat(pauline->lc,LinphoneReasonDoNotDisturb); diff --git a/tester/rcfiles/marie_remote_default_values_rc b/tester/rcfiles/marie_remote_default_values_rc index ec5e4f633..966d116fd 100644 --- a/tester/rcfiles/marie_remote_default_values_rc +++ b/tester/rcfiles/marie_remote_default_values_rc @@ -1,2 +1,5 @@ [misc] config-uri=http://smtp.linphone.org/marie_default + +[app] +toto=titi diff --git a/tester/remote_provisioning_tester.c b/tester/remote_provisioning_tester.c index d81df94d4..21e9a3f6a 100644 --- a/tester/remote_provisioning_tester.c +++ b/tester/remote_provisioning_tester.c @@ -84,9 +84,14 @@ static void remote_provisioning_default_values(void) { lpc = linphone_core_create_proxy_config(marie->lc); CU_ASSERT_TRUE(lpc->reg_sendregister == TRUE); CU_ASSERT_TRUE(lpc->expires == 604800); - CU_ASSERT_TRUE(strcmp(lpc->reg_proxy, "") == 0); - CU_ASSERT_TRUE(strcmp(lpc->reg_route, "") == 0); - CU_ASSERT_TRUE(strcmp(lpc->reg_identity, "sip:?@sip.linphone.org") == 0); + CU_ASSERT_STRING_EQUAL(lpc->reg_proxy, ""); + CU_ASSERT_STRING_EQUAL(lpc->reg_route, ""); + CU_ASSERT_STRING_EQUAL(lpc->reg_identity, "sip:?@sip.linphone.org"); + { + LpConfig* lp = linphone_core_get_config(marie->lc); + CU_ASSERT_STRING_EQUAL(lp_config_get_string(lp,"app","toto","empty"),"titi"); + } + linphone_core_manager_destroy(marie); } From b214e21ffe8af08a57f983acad9100ded900f6f8 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 1 Jul 2014 22:49:51 +0200 Subject: [PATCH 197/201] prevent receiving an incoming call when another is in the IncomingEarlyMedia state. --- coreapi/callbacks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 121291a00..c64a5d7e3 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -220,6 +220,7 @@ static bool_t already_a_call_pending(LinphoneCore *lc){ for(elem=lc->calls;elem!=NULL;elem=elem->next){ LinphoneCall *call=(LinphoneCall*)elem->data; if (call->state==LinphoneCallIncomingReceived + || call->state==LinphoneCallIncomingEarlyMedia || call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress || call->state==LinphoneCallOutgoingEarlyMedia From 823f20b21beec2ee41b369542c17c59c91cf2b87 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 1 Jul 2014 23:10:18 +0200 Subject: [PATCH 198/201] add documentation to createLinphoneCore() --- .../org/linphone/core/LinphoneCoreFactory.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index 0a6efc305..5838594dc 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -66,7 +66,24 @@ abstract public class LinphoneCoreFactory { * */ abstract public LinphoneAuthInfo createAuthInfo(String username, String userid, String passwd, String ha1, String realm, String domain); + /** + * Create a LinphoneCore object. The LinphoneCore is the root for all liblinphone operations. You need only one per application. + * @param listener listener to receive notifications from the core + * @param userConfig path where to read/write configuration (optional) + * @param factoryConfig path where to read factory configuration (optional) + * @param userdata any kind of application specific data + * @param context an application context, on android this MUST be the android.content.Context object used by the application. + * @return a LinphoneCore object. + * @throws LinphoneCoreException + */ abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, String userConfig,String factoryConfig,Object userdata, Object context) throws LinphoneCoreException; + /** + * Create a LinphoneCore object. The LinphoneCore is the root for all liblinphone operations. You need only one per application. + * @param listener listener to receive notifications from the core. + * @param context an application context, on android this MUST be the android.content.Context object used by the application. + * @return the LinphoneCore object. + * @throws LinphoneCoreException + */ abstract public LinphoneCore createLinphoneCore(LinphoneCoreListener listener, Object context) throws LinphoneCoreException; From 3d9c38aa8a9212063af16f06eb5fac921eefd947 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 1 Jul 2014 23:27:29 +0200 Subject: [PATCH 199/201] add logs to print core version at proxy config initial registration and when creating calls. Previously the version was only logged at startup, which seems not sufficient. It is important to be able to check the version running. --- coreapi/linphonecall.c | 2 +- coreapi/proxy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 042fe89c5..4380ecbeb 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -561,7 +561,7 @@ static void port_config_set(LinphoneCall *call, int stream_index, int min_port, static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){ int min_port, max_port; - + ms_message("New LinphoneCall [%p] initialized (LinphoneCore version: %s)",call,linphone_core_get_version()); call->magic=linphone_call_magic; call->refcnt=1; call->state=LinphoneCallIdle; diff --git a/coreapi/proxy.c b/coreapi/proxy.c index 838a536a8..a999d3b3c 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -411,7 +411,7 @@ static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ LinphoneAddress* proxy=linphone_address_new(obj->reg_proxy); char* proxy_string; LinphoneAddress *contact; - + ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)",obj,linphone_core_get_version()); proxy_string=linphone_address_as_string_uri_only(proxy); linphone_address_destroy(proxy); if (obj->op) From f59489c76df22bbeb147d801afb3f3ae80979aca Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Wed, 2 Jul 2014 14:13:07 +0200 Subject: [PATCH 200/201] Small documentation fixes. --- coreapi/linphonecore.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 9da626732..40f6b8422 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -120,7 +120,6 @@ typedef enum _LinphoneTransportType LinphoneTransportType; * return NULL. * * @ingroup linphone_address - * @var LinphoneAddress */ typedef struct SalAddress LinphoneAddress; @@ -2508,7 +2507,12 @@ LINPHONE_PUBLIC void linphone_core_init_default_params(LinphoneCore*lc, Linphone */ LINPHONE_PUBLIC bool_t linphone_core_tunnel_available(void); +/** + * Linphone tunnel object. + * @ingroup tunnel + */ typedef struct _LinphoneTunnel LinphoneTunnel; + /** * get tunnel instance if available */ From 85e6548b59135fdf697891fe8b83355d628e39c1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 2 Jul 2014 15:12:34 +0200 Subject: [PATCH 201/201] add setting to disable symmetric rtp --- coreapi/linphonecall.c | 2 ++ coreapi/misc.c | 5 +++++ coreapi/private.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 261a8d763..171b44fd8 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1632,6 +1632,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ if (call->audiostream != NULL) return; if (call->sessions[0].rtp_session==NULL){ call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6); + rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); }else{ call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]); } @@ -1692,6 +1693,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ if (call->sessions[1].rtp_session==NULL){ call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6); + rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); }else{ call->videostream=video_stream_new_with_sessions(&call->sessions[1]); } diff --git a/coreapi/misc.c b/coreapi/misc.c index 0cc6a3ac9..38b0efa5d 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -1537,3 +1537,8 @@ const char ** linphone_core_get_supported_file_formats(LinphoneCore *core){ } return core->supported_formats; } + +bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc){ + return lp_config_get_int(lc->config,"rtp","symmetric",1); +} + diff --git a/coreapi/private.h b/coreapi/private.h index 79537e742..b03365858 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -382,6 +382,7 @@ void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call); void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md); void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call); + const char * linphone_core_get_identity(LinphoneCore *lc); void linphone_core_start_waiting(LinphoneCore *lc, const char *purpose); @@ -397,6 +398,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call); bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md); extern SalCallbacks linphone_sal_callbacks; bool_t linphone_core_rtcp_enabled(const LinphoneCore *lc); +bool_t linphone_core_symmetric_rtp_enabled(LinphoneCore*lc); LinphoneCall * is_a_linphone_call(void *user_pointer); LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer);
  • v8G!Em;N={Zi}jXHj}D68OU;vsNV@1 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%0Do~f7 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%0A{>>au9l6 z{QXTaptF4$EfMMMd)g|?NH_&qU;5KhNFTVuQymr=Q?B81aPEV`w^02Z(Ek%Zg2;cm z+{(`X|EZ$(P1S#2U99~1%FV@3ozL}uU4QnurkG?8Huh<1Ao@H$V;X?&(XON<`KJ>NIA{sQFZ~Hj-gZN%@G^G?Fr9nInYaSo1PFxr`!Ea{VJY zp-Svr@mdJIsdxn=aanVmwHzB?7_IV#+K4CDp?RGFxZ{I9?O*>46dC`S^)n^$0>G^~ z3QoLUYL2m(=^W!vn31TCkz`)6G$%S_g>(h!iHX@I&745HlJne--ygZc{|_X%y8nlZ zhl=Wds@`Aubn&Zvdfp$6T2r*OlR3$ZL=ucAAZ>~c?jeMT++<6X7B^fP&t~Ki@xg+- z z{_ZS2Qg)lot;#@?IM$QkC6o@3L^&`HZ{D2!|58!=-rCjG$18uWa-{guc`Ja6^b3uz zYl03mbq1&1imH7<+Y~MRR$D&l|NRwvUvF-UFVEH)3~B}BhNaWgCI-CPX{vD)YnAR=+FLK zQ@plQnX}~vLkq3gz|IdOVu?W0&mUV zi3LMtHo}e&_gvQ$i7hcl2BAyRdAVT94I=Q;+BC7I2Q9jx`8MZuWFR3DcjTnZfd}0h zM+OPIO$K_{EwwKkp==a9daEe;RD~IKxO+-&5kSC*Rj=`$rs(Ryqi1v+C89>4SyE?x z)IUA?6rrN%$_mABr~J%;aB%S6PYO^SDH{zZ>$CqqT-5$Z^|k7Qm0zxWxcK3Wi~G9$ zNaMPucyURwWc25xRfL^3cTzh#Dym(ZfgnR5A+`UL{&}3H3 z+-B6P5>iOqL(YfWIB?3YCCrh!0EOMZl=pe$$aYg4w^KRb*QCuFzLwH^8!<>2g|*ha z+1~p@2XNZ@I@_sZlTnPNR>e6|3W3XGx+yw&61@iv;**r}10oPLLv-DDk4!QG5FCy9 zg;@!Wd<|uPyYwy_(A4AFZ;{*UdmQrCfoJCVrikY!$1-43naaW_t>og83O>C=M?>%a zyYAWmB6a@%BSmeq`fJtCRlc?Ot>TdjxZI7anj*lR9LpH`oN)a1_Xvf}40%m!(6`o4 zyBJQ_mE;mX3Jg#XlG~cMN_C9qgcE6#`e1j=sN5+j5Ou6sp235VxGcU+ z06i&YYR=2DHffI2crC||4^k?)E=+?B>bPX3%L9Lwg1XawRtB}GdZ?%;gS3! z0E1Mc+}xt#t9qpp>+AJ8uUvc0VW+>8@KdH9h><2>`u@#iF;SYv%IX8>-Aem}8tIg4 z6gf?MphrQKvZ&rCJhu*5p>$J0fki@jQ&VKOxU6p-ZO0Q*nMLtxOnRGOfm{O8+P5j1 zOW9kuTWN_T>?rw#dvinccDKX~w?DDO6N1Jlm28^aw=x2;KdZ4@!Y5FOwA_%ip7PBG zsMqaMVfEb1DVoXS%VZ>lcL!LKEdQ(3SjD|? zvw|dEA#v*-XP}XcK;VxvOBR-y zx8=iC?~kmR%NTDr#eRM)2M{*Yw8S(L&=bt8pXDMzZ!mWz7A)o1A!-T1_-)PiAy^o; zcaMJVq3@n`MfbBXuWZdTXUvgilT=<*`Jl91!3ulR`VKYUD+4!{;hiTO+QHx^T~J5U zB<+a8qrJ7{Qo*nX!YPnj?cCJ7%kJZ=844pQE+=rJZ3c=wA8U(3_s$qqOpl6Fpl? zmWrP(GXONMZ5p5Hcw>CDj z^66r+qA@dH*Ayu^+V&vjg28wIL#`@SwvSK@vLHzI0dg{g>=eZ^Kf%yK^u9Zxw)HN; zxAAE61FV)x*@b5dLZg^EVZ{B}YxC;Hn{on#v{Qm_))mAhiXoGZ<@53r@desgV`5lY z4k~_T{*d8VXy}2|z3OI3#a2FCuGU4D8vk7V;VdJ3SO?Li^Lw&^sNFBe8 zixxCh{baZXWw(zta+D$U;Nt&hidr2H;C+=-#cvkRToe!B<)-5|eR}jcB|V{x0n4$F zirEC5NAMQMn;(^wj%Os)6VBpEmq0N{n}OFXagOWGP(3%!g1pa+_SR)!OHV?bf=-2yRr%WH zhj|hbvKg*OIw8wI8kbBdv58prLdwk*Bz>tCiPvpYstpMJI^8+^6O>>WZV~z8WM>iX zP|az)u_^xY>9LFshxAe<1&RiYarJh`7;hzIi@?NJI#*v`-&(_Bp>@Ss6YrkdZK65L zS2T~9P+mBHNOwZL{QorutI*9tXY10b)g_oeunHOr<6H;ClCdyw0rf3N7bS}S4;RlB zwfX9gRQ}J(oB8z1`_Z_mDJIkd#hEeQbYp8Bm?jB49Im2VhccM(-+Qu1MJI}zU=;0WufqNb_(d|ufn&XGubHNX1v{fvKC>pyM zq|E^=G)>rgcD1ZCa)tfBsl>0>=eLA$<(fEv0~|Qd;}U9)W3*mPr|tIPH12O2?f6*Z znbGS_7}3XwmOV(X+p^^v|1hHqbEjA9%k@)C8oZrgKiS&V{g$Xty#^90qKi{5KZ1Jf zgUYaL$kaE?ygD-W~$n#s9yg`QIlidzH!Jm%hB$|I6~% zUuue1H48*JM9q(EqKG$Vp0-zeJfPnKe)cnHpLlmsAoB(WnW z6Ei-)wYlvg_+i6(8TBRM6kYKGKyPlTrhnO2oXvIFYbtq0029eBNeM=mcEhB1H$@_j zKbGOoCmwZwBl;q4sf&%=llaDTIVw7rJg>|p^8&=-<)+BPvqp}m1@8$d42~kzPWQ*^SBA* zPDbFKFsB!g;4xX)s1rl@lW>h{{KNVXk=nAiE03KoGHs_@Y(tEYb6B*nK>RRV#U6|``C#xtES5WdGgUNycUaK&Ivu4_K&6vsiJln)Tp(+LBelqq>T z7@ybGkn~w}>LQxofzA$QdkLOkY- z;}{px1rfAHDZNH@mdhk(OYBs!F;)Kq`Sehxy{l=XDzem5;)G7*jYwnR3pfhukRs|) zuw#`;6(JP~neyu4Ib!onH-l75ci5~aoC z=pmt@S?@DVv7{5cT{(L3JbuELC{g|pca$P7f#ZYEq%x(jP!SS+-e5GFGaCf+TC&gn zcf;;1de-=KI2tG*Le}Btrij+5O=RRnh6D*);J8o=T3}#hR$wM~UEoh)5O9v{5WKTU z>lEFRQflyYnr4j`30#^+kDysEYdQ||3`3T7Z*d_pW$ShL35b8=`i)Z#>yFw$>~RY(jyaPuyKj&~vJEbE|-(iV88= z-07J*rfRKD3o2|H#G)I*wut>4>;w$lPT6+nTAzkFQzUUbNZA(P zI@8`Ato_mE=h;H=CmEHA%j`T|LHB zmme=67*c6FH6^jH|A+qH73P0EUioe&0DtBBf3Ijd_SFoZGjaJZs5ly{YIa5qw$3?v zt|>m&$?=R~UWxVKZF)b0RKS*-5~S$@r32wTql@{$rV*xRb=0R7Mk0BRc+_VXw#82+ zAE;+{H|uLA?qcgP$Al&U3IzHgnQ@9=?mCcC?OVHqDVVmao2R%D)FpDJTn6TYjsAlZCK;)9CD`40FJYNNw`dL|IeXfy{O&J{GZ?BlP~+n&Y9+_oV4*TX2AB+ zPTGn66LWih=CIz#FtNr}TYNgeWvK<@(ZCzdS>u*C*7NEspP4@^Hc>}c@5U3v?l5A) zxG5z71BQjv8$u(w0l>j=a)bnKDvpc(!mWuQzz9pR?!h_kS_C)Hd~OSrWTe9=WeBz$ ztklPwD>C%sjSQlTp@#k_AqYDYni1`Ws$_xFq(@+Zwy^HQMNmZP8LMMikUBGKzsB}< zM=<3(aLN&~y&+FfBR{4{f?Ey*U{l%4H!1^;FaIn`dOEhi>Jd z37Bd)onh7;V_(gDi%P`nVzSBiPdL>2#)4~0w)8P3b#(N{;Zqhl}fl|NEB8X>xzp_Y^>5yy?iMGafggHv>|{)tBAsxD)=m88)O`r;6nm zKU#X+XMgT%t~+n*@zKgNnFu(4c8UAx0+%9HHP)n8P9gbXaa$_OPlQFbm6KS;2QTfj zVL?L};Q^RACyITmLpe~%0(I8-Px**)b>Wn34yh4&1u9gTqEz|Ooo7$~ znw4ImWpHT|41s>kNpfj_0HG0w2G?P(xn{?^bHnK4O*+&23y~YA>3o%eX4g(Jb8dl| z(F-fHd}ca}Z#d+G9*M>VC{6_5k4k7gz<=0k%g1z!J^}|YV-i>sJMJgh^*!c2cu0Zw z`--NQ6G&rHAU2XY&-*3IaCiGWjrB3z244^o&gv=2^niDW!>7)&CTZ}L1Q@$ zY)J`vWPN61%}&?|Ymo}N7AUzGy_$WBusgmjvabumi!^jjg)Rd)Sd9t_3Y3ErFRB8rKzv(40gtwo34ife!X~V)b$_s{g<1sn1E-bL=s#3BuQ4$oz0bFEoW`b{)tdARs*!@k)-z?;w#OU zwSb(dQwe!L;R0Y8cb}KXms-QowVYs3_oWrkl%z&b@2OOpB6OY_%OLko>Y)?+@xv}X zskJbS6x?v%#fQF!-jgo*!F!sTs{n4`=7U_YCuwK)Hw(wX%B2hIL^%djlCd#o&Z-eW z*E}dskpKb3Sx}>^=-e2=1>{48hS45Ypu|!c%O|8U5xD#f zO-)@mHlC4;7-~BQxU!ZFR=S4F2#o=*MMaH6eY>y5R<8`*{XbsRW~#f@4^)1k@=$Sn z*!|AUU#uk@zK4C!wlHlA%&dF1Jw zX6UpVd(wwgT^4gpmX8zSy+*l0SrzIQceFIwffQqga3!A?O=0OnJ7U+u=^pxm8|>o+ zTQ777up4i06;2Un0JzegP9mS1o>)ugi2PPSLsT+K2MPJGD8QVta`&J4zu#H?zpJa2 z->rP&t9=4+SyqC4ab$u+SKs8hyJQ`RWGx|GY z@go3GiN`x5m$k%pJ(a^XlXOPT7d{cMMoj8Gp#0&M=&q;6GIEj09L}TYeIdi2+ghS7 zyKVCqAX^a+4rTyxk6>@nAz24=7ftr&mZnxrkH2yt?+CPz<5&i$;Z+wd1xj zVY(DQV{V%cUT2Cl<1yYK>J<1x-W;#CE@4@dV;S(qgmQbZ6dlM#Tb=>36m0}`VEn`g z|9@%mmZJ9c)jwOkz4CLFON#F--g36(2)#4f84?Ekv3mVXDLm3jG|ZIrcu5^8TTOM> zha;OUQFu@0M1_er?qibk|N`XP4$S)lo9H zu)IL_NmL^g*1(d0i1EWALzYplrf?gZuC8BNwL_Blvs-ChX`A(d(K4LSgC}}9&4~y7 zK)}BDLsmi`+h*&Hyx-J#hNqFdyblwftIUElxF%{P{sCZ>L=>PUEh^mr;mVd9`;bu< zPO7kd{d1aspm;`6!;0p;8?n0531oNNSh&8O0FT;T(!;IGoxIG9-utw?Fp6Cpp&}7F zLYyknV6JJ!zTp_0s0ACKfsKJri%kW{%`yw z0w(v`L7n~Y6t(ZFjnV)AW0kKjIvGCxSM*0-X(0ebg)-+Onp-n!OqLe9-gO?sa+riNhKC7+N&M|zq*fP3-N0-M3% zmJxlAWrU51hd!Smxo;s9!9v4W<9JIP-y{|?ir8tf?&hGZpX%m-RRu^3{*~Hiw34nkQ|4rwSZ6POEpY2C35 z7LCP=bliK@wCfbci!JerPmgERF4NK_A`0cL7*=3JB!Sg{WUn+>|GN{Cct>HoC2H}h z@#)dVDrva)m)68f!-&4+1uze#_oggEjOnwXue9FIdr#&hLlaKQBV2qQT8!HP>po{w zO0bn2kn(ZjAdN*F6NmrcL!fi5x7i9Zo<8AIKMJ_cr58#3)z?Ve87;F;FDOmOZRz5Jx$?4xgeczwy`(e5>HJqP7&-19BbX-|(oGWy-p zmt<%Xt?#WhTHD>vt(N1@&gkb!KImka1}x7OA6I%~L(`=f?u_4;zytN`^}^0Qt(#3k zUd>2n4V4h!A!~SlGB%b2)kHB0Nua>j2{~3bl^I{AuUMK)9RxvOSf(?hby)vcHU7By zqfnI27z)0xb~XH;dghAJRFBs^dcdAvIEsjwtP`M<-(w->d$s^44rkCkJ5`jz`=e5_@R-D8am*03SD zQeo^AMVkZzE8Auo8u)76M~jJEeaE-ktBxC@a=Derf%`t-yyay#_<<6N;sPfr;Mz7z zHyVVPk{CYWc5_QK-Xy3qfGi3BWY|H=;_Rp0(T!GZlsbn;v1rJ2e1C*6?q+=(Z*ASe zB5~p`9W9gTjXse(pthuktl3P&n8eqT9!Y(Va!0 z(;qNbH3C$|4+KL#V2G0af4ZpcRDYrRHI+Y8{6X>bffYdG+Lm}%Nzspw-lc@s_w<2C zL!;*?PSCCb4IrEkK(h%kOjI_MyU3Qp_oEzh!j&*;NTD6o?T*T=FN zOx4IgwgAbUrC(`dYfij1p>hj!@&1WN9lX+8;%Gh#mtuuK!5Eg(77kgN$@wI?K0-(i@W2X#b*1QAT!4U9%vcpjwEM(N!x?-ApF4i}Tk z|36b{bNeSR;Py9eX^H5RX0i;MH`K*>!ugz5_l7^iJ=2j;NTJO_#eUkc&wprKDMW&B*byGr_Lh z*b?(Onj!;dkQCqt5MHO4x%7;ERD50b>s-0Vbu5)R%A9vvS|Nj5sNMK{$roB5w0y~v zqt!s#habtv5^oT@BlZXv>8!OraB$zm*S-*H4J`7|-S{o({UN6osvsY2eLZJFaCLI@ zGbbF&6Ww+W*W#$RK389v6=;s3+1x`(NEZ|~2;V;%r5-;4_D9HPA0A%by4MaZqo*c) zXnkr?k3gr|^1`;V(N@8lr`C*|1vY}d^{BMu)}#A>srdibtG`)2Rr$-6j}$*2PXHiN z6#Z&mq{uBua7IuV>6@XTH9v0o(=OM(63SRjQ)6)%E?T_k|9ip9ORbNwmy_ce!jOo? zPQtzsDEy7yl2us`mMZYr0+r$83#hC7h@3GpJrY{M?a2CuMz+gZMoK<@X7pa9HNXj_fe0+{ z+H{j#;9-n(G#jY)F%Hh^Srad!Y97DC|;88&iP+_**kQSwds65$=R4T0prJTky zO8*I;f?Q)Cv)uj>O7k>K#`n;&ie0U+)q21-aUZ3hx6y{{2k z1$eUV|6xXcGynT1s&B8Hc|E6p7e!;K<;Z7u?il^tiM=1#OC5nQXJ+x|>gs=ugjIwR zB;?%OL{TT6RUI2Z5U9=b{sn}c5)lLFDTL3Lh@Lvl%Xv ztH2eOpsd)Yyt1&?>zFYo4{glS={Dfo!p6pmmytvA|Gn#cOKXb#BddJt=mjN&Ww0MA zJ3_BC=prlmkuebDz*$y`sz8wXS*C5YV`-^kRPGK)YP_fQs5|O+j$Uf=s84u?lXD_> z;dxX4S~L`@X!>IE3yZvptTtQw47yH%HH`>r zUn+IpP)ORCS)$h+lkSr6zNbj#e@7MJi<$UADuNq~&U6ZDkT2L!05kkp5z?(r07W`! z*)kF+HZ3vQW8q4BSdK=u^`t3}j5O=eQ{M;NRd1*{YnI+p@D^_=tH9mv5)$3k5?wu8 zn$cUBP#KRH)<$XmeL;{leGknd&)p^>5`3sBk zY#l5m-V)7FBhTb7#m?oePudCYY>d{Vi6H;Dky}CBhyK80U6@}2vmu*Ja@EjlWWJYa z7InGU4SGV?Bv!W@az;fS)23)&vKxGr@2}ubkSeyXy9wGRj8^X}F#+%=PI1F5@#y1= zc~`|nhCNEOOh@6;>e0PoKd4`Xeho@3MuM9~*Ppa3`~21UrA6Shw5_|~2;K;>8#qc- z)~!bJWnxJ?F4G@NvueI!Kl+XiYRQ27Yb>|KhC4NuGXo^K)RFDr79`=$c(-jqv(Bv& z=Cl{qqC2wDYzOB^j!$H4uHeyAedGhB3+?wf9@@Q?BNpV&bo^NqPximdOTWAY?hvvTtyE>Oy9$&WQfLgDx(ciV#f#I&fQj{Y8Dti zqPZ_*q>a-Ht-GIt&OAuxR16q4ERoMpS~j{UkfFHye@{{SLiJx%k5>L@@ngk3BRqih zmI!SpbF$tEmnz+G9-TC)eoi{9v+<2B@zpX=>P;8C{R2o_4mM$jn|gjp;rQ{$ZvuQ7mCuV{y0&F1)2b7(1 zWhDnMa?lZkkLC+9+0nuPPz#Xme1hj&r(_AorbZuQ(#;*%7Yir^R6g`=(eaTs<^p!Z zf$Lj~Zcj2m3JI%Jg26-0xeDh!*^EVCdFn}2+KGY$+oLU~ruN^??Ec z5FK(FUuZ4Z{o8qb^yZ|s!*Q^$f*TPrVich#6y%-d;M^njD7kL^3yds0e?)I;u*Q=I z+YLpVOaHnX%oxD(v>)6a{*Ka+#vw36U$7O@Xe<)sc7r$7;CiLn0`^alo0Y2B5t4_c z^TEB2^v?|~PiTM5=;u$|mPs9gU{Ew6=?JWtr994xgjvK?e3iw@iQvg8gPkUj(fODo zHIHZ4w?NJR@CW4XKl6VktB+OwZe^-?ZNT&&67_FrIo`sI)KprHo-dC?eBf&O+CSvIf7MS#k-eQk=v-GpnUVFlmZXpm)k&Y>6Isa_snMVM{3k zOZ*8rLOCHASpb)FXCzSPL~k8$0q?Hjs6UmhmiTcA_%i?z={?|`CEd#!Z{m%vTmePr z+5`u;6)2F4X)K;5=5}5#>&gT?-7Gt!Kj7F~#dPjwkh{#WKYUFfKk+S){9r^oIYEwX9F(&G^gLQ#@ZlC0Ebd<4I9Q)|Pd z^wk`doQhmOfj|+SN-#I@mo2jd6R^IN84QU#^TMS!p<|C88a~j)hZ*lVchQ1r`BuEcG&+6x=VHS;Rz6wC^);Q66L7O(-cxkj67~&=lo)|4s28bAVRd_6@ z5EZ+1sH}TAZtkmd0d#Y*Eu^K0H^rl^%(4LomV^D6*wE+!f6J-Gmn@=qg%Ad>YhGxH zCwV%j@jfjI`)k%biBd2?dl_xgCL-g;inz<36vB;k4XyCclLTBp}Pl6^H- z@x(#)54FzeEpw>P5^uS$GT}y)4w})}w+;fMfQb4+>#Qv!qxP6s#!;t(#Gwt->IQy= z2?O4Q1jH9|dmFE&EkJ(3JN??$7Sc@BF{8&U;fIa3FAmd2pzOODR2QEGw}9u*KnN;0 zw$wRaq$#cSeFSJ;NOb=%E#UwBmg?WCJ_Q5#O!1HT=RrPRX;;|&sT@@9(C!qWT$~GM z1oaFu;|s3Mk&u-3j93oI6e^+S9nrCNVFHj5tt1i!2MAR}+|y%pd$HvRkuTgOKkhr` zxb-+1u6!uL0Px@TQR?E1La|WX(9fu)A3h|Ls zc_Y>ickaV2<2xQ}WF#8Wx^_R>U_?G-ab{%+;F9{2xT6 z%-?NX+7=h$^!UO-T!N{AMO+UCHY-nGI^fMET1=x&BE?2aY&TK+*0y6b&f#%MD3p^I z+7i2n6R!k(PlFSA!t@==&O5dCA&X~rJ~Miwk_tD_ zN{*~cWOp%fYJ5T>=o-Y$yBU-9Qr-ErzU{VF=2%*;rS*0n~fiRTl)@Jo-%1 z+9=VQp^TpQKM5IQGIDIf##Z2|SfsH7>;e-_$_9eVPyFxowe$ZUD{7~!-&LKcJYW2y z;;{?8#f?Ml%caC}ZfwHsIbl(7w~d;|A<^qvnyd!I^LA&NKaN+%-c8WBt|Sy0nGn8C zw2dKntdY?mn^?#vVurvnqs`Dx-*VHzo$(q`DbR+8HNLBTnS8{tMg~GOvBrVO=K)is ze5m3tSh*k8yY%ro(JsC6-b!2a!P8?Ike0L@KhA(8gXDPZ=5}dcsEMJ?g6npoJ*Jy; zz)0{s`59Opi5MIz=9H52vx0zS6_t-sqL2)HR~0y{Ew+6S5;4-!$Yd`w+jw)^2#3cq zx{=Zwc>$wX4AWGy9{9;5 zr5E+oy5ce4HMX>Q%furBnBP*m2Ka&iPQo>~wSARS4|j~-j6@7;Iq(JbH(62?Q1Z$G z+LVIE?93)eKIPdQDY02N6bFV^COJ`ch_?t}K84xfd*9H$(k(V4qnglVQxh``3=t2n zvNQAe6ntiL0u9fOGva6KgtfZic0yyWt-*;a2EcfMs&IEnt{OMA-H(#Lss!8*)ybLB!qb4rEv zZ4IEs&{6H~{}+nd1Jxg`URimya=7@y0q=44uQv|2MdW)dhZ}Ne)nq`06uBTm_IMU? zpx{DB+pkO+^5M7t#rCzVBdctdl8#{`Xq$lbR-8ZtRBUy=LVZa9WnWvg2+nQBM|Lz z&r`a-{buJ8TrpY|rcLLgaAlCbn+n8-3SDMwaH%2=n!PpiPfV&PNXwpafw?)p!c$f* z;&1FFn~t=vW_^&~JUDuN=PSlt%8y}u#~JXg_`qSg(D<63{lB#M9Q{AFqWZ_GS5^Le z@xSrUi}lgCqb13-3xq+`I;FP- zpcIYd9&d{s_}F*`k7VC3l zh%JQaca1Q8YKJS~e_kwVpR4{(^)r>lbyv&QzYFz+?U$#w9A}J;(XK5oSbc!(TLxloS+7?`TO)r`(}Ioj5=WY`9HC+ zN)8f$g1mp2wHT_U5apZ=*U;$SvT%rALkJsRiMpXJqGFtb40QBR{SpC0ot!#RwycL34;a3L%n4x>ggVl z6v0Nudy4ywj~FyuwSB9d@IeX;57*ZjZR=zDAy;YND#E17_4e1Yi0QEmI79j}V=qV+ z$jkR?p1^RebUlC(2npp=8_Vrm?2zvrEl!EL&!BGCSYgvqMdsSSUA_Gtd%KKhOvu#! ziO4F+#P^@ePk(KIt-ARCvzq_$TJ>J6|F0LH&A$30e{ijRj|omjLv!*rmXgP^e@d~G zgq4bSkI-PXeYd@3#)&20a?qK@a%tJGfS_p9+akK09^c7;Fs6Ox9J=aZUAkQ3eF!Fx zgY`ImmmHGqQVfOGQ9q69ddh6C2yM%qfa!w#6%(vM6~vE>Ho$52O7`XUd)edZ9GG$X zfd@3h+5B1-!GPmU;930(px_^>C+}>FU>dWUk#QVqRv%kBtBju7oTyW(KC!qAXKrZv z1rAP2uvGv=4Nr}Lp8)tYQ)!M!rGu0Ce`i zYb!rexu*F3k=Ocl_<L$`c8)^^OAr$!%J zTEHpRn7EkpF4(K+ZMN1CxBJzq3}a^VONQm^Y`#b}}$+={@1OjWkfWX`;% zg!o0X{piVoKZqk>c%PPe&L;9iHxj@YMR~7W&$QofZ=GRH66ZYt4Ie)!?*`A4_wC&M z|9nwPz-1*3a*u5X(|~T)95|Gq!-j6+y{c#3 z7`@nEck5i|sEB#)n|O%n;9}_UY%G3|i~rHS!%$@)nnm%pwrDmf(_cAS6(l^s9LruF zA5d<*iKUc;rYMTNs8CcEt>&@u?a_-HY6ZKahDRnJJPL-6y0Wq$?xvjOd!f#?jd^n{ zBbS#}6$9{W^85_*9E&q8Sa^RyTVC6~Piktsk&%o^zxRoCs|?_ZED8fI06D{2@tLgp zSYHM4=MYM9=V5&d$&3$+_H}St-KBj^TV&SL;|D5lAMXyOQP~1zqID?s=()n^7aK%c z5^or$u7}su{Xbm%E7|{Rsy|-Y;?w`;J{niF#WXoR{@mzml9q{7dp#LvHKUP~5&ept ziKmZ`HeE?}vW7k{w)5WhgQgT;%^35TREp<0D`9ztK@bzOES1vvk^lfsW!^`#94SWQ z`Z1A`fhGrPW2`ls!mV!|Tt8$=hs7fB?dey>GdXdmUhrp7W% z7GC?{dW#`EOe(rFIb7!nWQ;4z+p(SyBM(8jSDt6uBDJ2%dC=sWk9bsaJHgR$_MiE` zcM$)7tnzm%U-#8N|97J;UdpV@Tf#%i%e;|HRz5ix+Z)@WpQN$tO$SjU57I-kx#02p z+(d4raJGlSNpoS?)j-v$fYUR21qqZ*@xxvI0A<|Sg zB3GLHvB)HK*#YI0-V@^iP{}*W8|_DO&m!R-4MF?I7nH0u|M@)GW?K}@S(C_-Z)04q{f3F+#rM7q|r*d*t z$%P#c6XA6qti1w*M=Daal{;vvg@Q8LU9}y36ydt$Dbz5a#YKvuZa_qvH!=53L4L7DY(9(-kKM`#hmzy=@v zbX%m)$HsPU8hwj~hAl&eb{Q+6SEBNHRO5xk0|s;ImJkP+PjB_Hh4t2wt1*&aASkoT<=aS-yqIPffJ1f6hd8YVf{&B${XWO4NSl*Ygj7GZiB>(1;u=EL%HK?)B^WAu3`)L#Ej7T`)6FjgWPZsu8XtI`p%EJ8Ol7)87 zy~f2swxpeIzTNwHMTTbyBWmmI6WWUL3=cnf?fZO%Q(I(`N_&8s>s7lOA8U($lD5-t z9DT164#4Zfwpn@xQk}S?A+i6C_9u7-oUFHweui|c_Mo5cWYL(P0xR7;W3ychPZ6_; zb!VOMBT@MwK3mi$Iz1FbA8C66>5OKh#7?JR1xp(?bww9f5tgC_!4p@{I6Cr;EtJ|4 z`pf1Oik{kPSJD?eMgv-p_{ zzW%T4FFw~65$AL!S#pBd?WBBd_bxk&OI%iQ;Nee zp3eE(s0-@Oac{H6dFddRWWp9H*;cwM!U1%l8#G9Yfpa>i+djRRC)asT5q^0qXL(g? za4(O=)%1#ZUo2-Gx_%oI?Pr|odHd*Vn=o@x!aU;Q4=Fz<-;Wb5k?aDvyK$sPs$Gh! z<2Bm2viJI!;f406q>v93)OUx=Gs{gUg%7`E15zYJOofi$9HmBTGO(py(>}?&AIs@& z8S3&JT_Xbysz+@~UPs_9pQ{_-8$1c!|5OXr$HDp#FyxBe>|a>VJ$CuO+luP{Q@y)V zFPg<|$xGa*wr6;T$?*)hUgC^PICZHvFLe7ARK=6Ri25jkgqtubV5pTD!mbiqWjCOz9^HCl@(CXFDK$ACiKz--7 zll$jX82r-`*n}&hhB9%Ww`SF~s30bU46q=|&x&e-dWO;?NCEZ^;KBB1x$BT!Jw5sn zhRX6|!r_ExP#KT<7}*h!h2RTsb{t-MwDaoDj3t+3u{p__kj|`QjiIrhiGmQ#rOE!i)Adz;JpPS% z8&oZ!#uefJ4;OPqZK?XdR-dfAi%&21N8=-Haa58u$tmWi+MA}S{z~OaAn3o232kXI zLDM;gKBb}|0pIc{%{35^1jkZ?O49SqHDg&8f8-gleVVFtB#yDD5Fnwvy}P$_OWToH zzWUD55|5}Pe2o(!vEefZT)s_NGfFqm%P2O5BuoeAEPr@dD~js@40b|7$kXzNzcMfa zx0a(`kN8X<&-T3L!oj+Y3u61}j0OL;J_~b(w36QCb8kXz30O4!Lw#G-;~b(QIWIeR z;EH5lE+{-Kcfe8(1E$@xyQOtuf6-e$=kQ8foYlv2hHQ^eS%{zxgK{7l+xZ118wo$j zEw+R}-wG7j1kHbSdzK|kkH0iphSFw>PPg@KAQuo~|mX*9K_gxK&+?KAe~ z88LqP&4+_w$nQ`WLn&D7B>G1;KRp(BD>w)CjmE8QQ9qL4$!OF~ctuaSsLinf8ZjQp zwN=CHa0!=ZH0(Uwdah_V`u#*@exg^rSkeQ?pjY;dPqmkv&AW885GE5eC%OZ4jSfq? zmkZ&7C(_N4LYWf8NdbjSvFWxM+$L%oF0IY>^2-L|(2hsycwjGP+C7jF8k?NjVB7=#QE`Y?0B-DZC@{mVdWZu+X+JTvf4 zbqlMGRr6I^Iu$gc5w(shr4vDmiz2nOZTQmQ<)iz5xR@_$&s1kC-wprg{E*v!f#0G- zK#YvjITKIQ`|;4i8q&qH;@MGQ7K@)uq#GF_p_^w|rN+^^nGw_dPMC9v!C`LRshHuGSS&IJKeg^(Lyvw*d$l6|z$P|8!A1TK#qS zKfVS0&*=-i=0ksNyM0dDIfoZ+s0^e*wRbZ6&J_pVr{VxTGhKxKMEfj9fsMZK?9@JD zI7gf#`7(N2MhDExmbsBx%;Pi%qJJ21X^pB9by1&<54MdnGK+FIky3tAxHQVf1{WV* zLv^Ota6AMbR1GEQ9v8{?M4n*e!B&-?*ns1XB3HD(cEh`_?RZ-p&c|{f%0mzL=~WQY zXz<(7@vAdr)Nsan(?Sg@fkBfoEG>q%tX^(@rM zL9U1I@Vl>VT*>1H0=Q25=+;h8L5{hBD@(Llx;nrL(8rr6p5#`O`VU!tYuTtfq=o}q zc@$S&KWDWJ>?ApdzU71e2@Osz|M#HyKfYLL7XPq#aOgE2^v%ZQ?JwBzXC%dk9{+&( zJOV08UzFw@-+9Am&6|{gX}P18a#>LaIYUM3I*S=x zT{o~#z?=+>3q%popsH-yCT_?+kqgS$b03h9cYt zu^;=9p*;YD~r4y`n}3xWx29mdA{;;<%^YXt$bJIPgMSN%5PNudF5YK{%z$CD*v(a|5dBivFaPEZ?3+rI#GR3_4exB z)elxbT79Vc@#<66PgXx&ovog(u2wgzFI2y&`pwlZRlleD{na0;{yBP$cR?KfT=f^= z9sax3e^mX=>hD(nb@ks>|9$m8RsT!vQ0=nXRkgR&uCKkL_O-P;YwxceseP>WaP6_$ zCu*OneYQ4Vd$zV#J6rogZKw7v^e%s2?FVWA^PpRBcNf4TNoYrk0gmD=C0{gc{n z*ZyVg-_-t(+8@^b^B~pr`hD%tbIlF*c)hvJ>qhexUN>88{-Leb8+bk2`Wjx(wXWm! z`PPlRZnxgW>kF-0d3~`(PUg@TTJPuerPdK%Uv3@c^_A8myna&)#>PX9)+cz~X`STt z)z)Wt{bFm5*FVx);`N(bbzc8yYm?V+X}!SfA8S{5{nqv+ynb8za$djG)*8OOtu=f{ z`zBt$v;A&fzpH%*uixEfF5IE-X@7{-V)E;`NWWKhEo)Xg|g4pKO1U*Y9tC zn%DoKJ;Un{v=OaCf2zIA>z{5v$LkNa&++<0ZCIub{cxws>yLECc>U21rs&Y0?Pv{u zu5&G~f4-xA_zNBF!~fX1h1VbJXeB@1c`vVjv7_DiiOvUk{mITpc>Spkw(HPe>P+$a z)14=I-R+#3ZopoOSr_S@d{^icgy#AHFL%jaX z-etW0?B12U{@mU*y#D;&+j;$~dpGm?*Y@7S>tElaT6XAv-qU)1VejjC{Tq89=Jgl% z=$}9IOM5zPDOX=ncNYucHA^4iz&`cGfe8h+z7t>K@& zrZxQLYub(9dQGSE+pj&v>+ihwG_U{swQuD0U%aN%`Q6t}v+2bp#fI|#zXkvIpQ+rz zKfb&ljj!*B92Ir{$OWtWCl;OuvaSl8DQLNB)&XG@wQAGwfuYNT6Ty*12SId1(xE=_R*+z#_UWoFa!yl-s9BAEEe!}GOq$uCe!efYEnY;S%Ltn$80NneNB0EJUp z5or+uo)GPPpd)hgi!fP>9#CZkX~Sh2yE72Z6sVo)?85TWX#f)UDQ`|U#v1GcrY;pc zaQV>!O1V+|lp+m3q42P@bP^FgX6?p1IyDK|_`#rz{TVAXR&M9huda{Ar5$mjPUaL35*p)#fID-l zL$NbG4vmnyCS^u?%N;X66rU*2KW$g&0J^1fxm5UgVDW+tCC5pNbn@N^GnJ&1TZTtL89#G9V@j`)Oxpy@KQ$<=%8B;g1LCWr!!d?>3(H2 z9siX~;s(93AhEl6)G14)TWc)QHGAsP(85uZS;U7JImN_fP`dJsUlxk7UU?2kzegLO zRxR>cL2=YNmzkl-;Pp!we-j%=@D);{9#tnIBM&Fp&{)#=9E2Oe!iLnw4V`hF!+1{9 zSh5Nbaeo;Jh~(IVT<|54TvAh3YC?Q138MT41Lu~dYh^1-3#1g*%R9UK|EG%DZ1o2# z|EzL<@u$9Ou76{q^EFO^X7o;^t@H^lT+ik92vV3D(fL%axm=7>FngdARc=|CZzF}# zO+7brik7>F*Oy#r;qD0o^L0CU8*k~nNh)Eikx@}ksHX?&1S`u_fDm{gOPJcQOl+f3 z6HBV(!jHR%A}~dcGj9E~-606k1rV?sVs~HIZG5aF25}@Wqt7SlNsKOYx?9`7Xy7p# zZRqGm6m_6%Md@QtczR(O;8iyki-nVC;J?s^+c?@0u{eHO#xtZP;4wT!dq4V0Wcwqs z{~T&!es$f3@4_Ol3?W9R41c)X}RRQMN_Tqf zV5RFA7Ai3@$>%QW^HnRoN&(KT3&b`9+BUwOB2y*5>2u{D>AXd^GYhJkFxU^9g5}KV zZr2<*En+_meH6$AYYxIzziZ}RM$X#Fcn(6?_yN=i-g|)c&NX(4ckUZ4J4y3lbwNz_ z$Zlhv5*PPi^Z?q4?nosg&VqNvm;pRd&z$}t(#-g&LFy5Pgz)V4ju^jDsu@MRgi?JJ zyKKrvIsEz>_aTPqncipbbs$b1@aP*eENyTj$}Bm2=E6EUlVkidu2p#Xi#!A@*d>(BOo84B$wLLy0l_x}=#{@{O`)ypf}cmNN^mp|ik zeBgI++{bc|%|q+|BOKwBPZ>X)=FtLf3Wnsm&O4nU$v^@mB(V%uHowE!FARrV-1FG@ z4=Fv=O(tB~5jpm;9A9bZuIo7ZKw=`7TXVL)q|`1*Uv>I8Wk90B z)x8wP&a8qNeqLEjbG6EgHU5^cox1b^Lhs(#|b*Ilq{J8%pSFobwgV zf>X*>c<7&>@~UKuOKdru zh}-!AKUf+E+s)t^fK5c8_wiS-tE?1W184>mPG+u(TXF_fPi}|i(*+WngruB1$YQ4r?~iu2B+hjb>ezhGHjE{ zv@aokDjQNDv&sX{xJ+8Z!KyZR>NRmF+>W>5By z0!=lIDxa@mY;-iW;Mmv)Mql)yUdN!ETIpRC&iByGZ|rDn!SvXHFpGE=a%op7qSjZf z1k9tOT%am+Mc@?&QBYP6hodjYz$VaU5irZIbTrandhF@Z`;b<6Q#B<7KNDe|WCPOTB4LQ(B#puyBwM!1sHENlsSObG$9#Oox(Lc!PI=NK5@zZTzr z>xK!=irN3lHx$*+SNL;E1;#m-$UBWt)}!d-r1^l-!Y-Qnz1if~?pt11YZxy8hHzexxtZLltOKR3aK==bLSrC1!Ry>Cw!8R+o)nOku6aa<$*yZ)85Ol5`E{); zBH;UA=WffDk#HC&BkgH}2N+DmXZW|roUOq>)p zldVS3O={=NS_Zxvf--P8vAn7YoXV!Rnmdnm+_aTfS4PW7dhJh95?&zAARpZW?^$H9 zs9_0=&ag78t6!oUv|hq4ZfiF?--|zV=T>g_!*}&LIqtkV{mdc(py}~>5ssUf^@`PQ zIt$0@+7MP8F^bN+8{8Uyh@UI1-Cu+=R1bxs^Ii~s0rZrye#QyH5%K<@?Ej(SuNT$d zt^96fflvM``)J(U`JmGo83Ec*o$-hWa)|IZw*V8X0Zw;py)2$p1vh0`wN7nsPB z4tDf95elz&9tZM*$V~wG1SO!hUZ1mizViWjdgD`BB0IPfw48@zc|s?2NfXL%&ASIS z>Bbj2n%glswsU;+nj+U6X8$;;j&PP!`Q3X~TxCPvMm_kYl z&(A4J$AvLlby|fwr378XWo^340@b?a#EG+T9^3GCk_18`%w?4V++#3%haw#FgSfv!niJ=v z68TAK40dEN^%5W|jCh~YHcjKG*ZJF0ID;vXtR!w=zeRRz17k!M3Yx$^dbJrar_% zjt0Yz2@s2k&WG)gbEb3*J>-4k6Acttk^#;XU*7wR@SFXKLqU-D*Foq{}XujF1jL7*}bmhV{SLp%qt zgqKD?N5Y+ZET}%qRJtmwZZA_kENbu@3aV0lrIsx`;H(CR|BVj^<3PQ_Lu7RSFDbsS zsMV{#T%E4`BJ+Q~??M#7#rz#0zYm%=Ss1;~X~0y!)iO+^?yaZsi-895_7J{m6qK(v z-Q0P=$!m|X&z>&TWi>!4tuVOkUlQe9<@XO^iI^*qBo^E@%#lcq8gp@Ut)K@*uzsT;;6MdiDCJtDoX;!CfTvmLsxTaX{Oz9-Y?j3#q5-0hz#i$bti*l%?>zH^F9Uj&}Xw?9k zsCH~{MGmoO;{68n1Byhv*CIsZOeC~YUWEuH*_9Bgy`3}a`a=TuTejrt|2ms z9z0x8Z6*7Nbxr2OsQP%D@Y4V^20Qvh=V2{ytnu7I7MNhxQ*BeSYc8x2NSY7pDe}c8 zDO%9pccr(i#KznsTz6|&P?*eT&h6}`xJn04Fi&M59Q;ciH%}v{O98)e@O3!8Fz51g zx`N^hMs@YkJ6iqIqH9Yp;QOo#%Q<>5K+LA2ajAIodhn3spmvDL_9;6k`0%yl_=_Hv zw?s+olR4NoVLk{l_e$p>F50mil{r*totNS?{<_feguoOWr%I)QT?$UQNc2w~r6jWyOgJ(x zv-OU~d1Unfrz4$F>XCP(ohL*$Z|OYFy$A7<5yB==%ojihwy_L2LNkI(djU3?y$D#G z_jEMLgO%MfS|cSi_xYq4WfSK6bwYTVS(91fIwMj0Y~ZYSsj zIOhf@QyNxRhI9@tw$R=Bl&|2uiO6Mn2I(?)&Nb?pjs)u+t9LR)7(%b!H#*rKfX&c5JLhmI_IW|9MQJnXPYbl11lm=wE`3d#$uM z=Mx9M%#$5AO=BmcK_;=4`^VnvN^~x)o|-wOOLlsx>h&Sn-e&Auu;2WQDn`5*$iN#wc650P-igXRz~7 z=cK94R}YdPOOxm6Va+C4>SF_;-nftK2dh&nj-PTQN)VrNp9M`wF5*5}Gj`Xwww+H+ zK8>=OnKDcL>!!HsH#zQQ_D{v8a1LDx3f-PSbz*cHhJNF#=vvoGyu#c&?KPQe{jlN+ zaFHz3l47CqMjc+AcCiI@vuuN-bXCWVpUNPJPFkPT*!Y#TO_HZHK>%tbwXU-#V)OL> zeQVOVir^w$-+5YRn>9c>xu_FeCsmavfj@CzH%Pte)aKS{_S5bWa02H+BqvHXpp`>g zz~!CKm=AxTHpNd^i;V3%jiJUZAlaQ;TE};gq$n=5Op)&&E3XF%$v_SBO2T`;B6_ zC(UO%8tyQe!#bO&3=QC%jo*!WC%rm82eET=XNJR>9DntO(T9`poz5rj?gtwO@7ehO zDZnGwC>=p}QWN$p=_0Sl^AQcl&~B$GtafKE zm3NFBEi$AI1RdzxqY(n`2iL4y@hq*G;2-<%MajkgzhBfAtG``6S^1;I z@4Nf|-_$E%*lD{jIn|+rFi>=vSv|F+@gVa37S1Ann!AhIFioPww*zoW$3Gf@b5v+l zr{FAMSfoE_!-{4`Jl4_72r_9Kqi=LVgFLk^huMR{mNuog<~1|HMYD23ELUa_HXZ@V znWy>0Si;OM$y&`W%xrBgnS;r{$YE0x6fhta(v+S@k!2`JRyvEa?&IG$`f-wF)1!S; zi`=LO%W5ryrX>z>UQM(J8iG;EVG);f7Ffjecm@Yh`a0?;sqw8ox8>lLf>Zzu)8I&s z97{gYC1Z(?mlOv&I}lO4r8BSN&7z4(9PiPIXSwIAxG==IGbjjX zN>semv;u45imct{0?C)s9w{^AePMV1-(1u#t-e_KTgA^8Z!U_)yE__PKruC==zVl` ze*5Io>fD*-g^z74t=$Rya1CX>a3?|UM_tQ|54Tb8qE1^nMWjwOj`bo|7IJQ!TR@+w zj!Kcq&G6tS)@Igc$oQ6S4Y`%bktc_+Y_}#ShmhFT5;taO@mXPGt#z&2L(AgvC8-nG zq0^b>5{PoYR%y4A?b3DOn%iR!3`k~Viv6^KivqkE)ffZDExWR@AWjdtv>xuK znwLRnw`Kkfuq8TlZIk0Di$qVYXLvE8o;lWe)^tQh0w@^)JQi_Dh`3;1len9?=lk}f zwU7h52ddSOgWT$9G7>P!3`lgsLWBgP%bJ)#P%&g5423jw@}HbmL68h|0X>{!@3B-B zg;&#fF0a==GBD#8bsDkUIFi)BljiRK(?xBi`UlnHl_Lcl!3X|m%ycvpVR~#Q1C5am zq8=VHi786ESud?0NALY4cN3NSjoWptd!joQhP$O8iAbG$=SgMeZ=X#-2H=XnN=rc>|9O^c7+lUuMjpNn|DkUATmL-vaY(qYY-PvEJP3U?*i>ZB+_oOG~o(e}M{D_y3aOQ$_9DtKUZc z@4G68`Nu{0Xx!S-RD`@CXlWHND8Uo;=&U0pMyZQA!i>sZ`pTZ+D^Z-5V(}Dhkx&Sn z&utD#pG!OE%uzfL;P7cn!g9-4lm~~2`qr}LTeNi}G|&rdq2^0bE6$kU1>O*Cbk1re zIhnY$%et?yNQFeK-O&b+1rq6S$Wm82TlTikj26uFVLb`-WtOmL4!0&6(bkJUY`A)P z5nRoHtZ2O4*>qOp*g;lt)Q35+$f-sl|D3F(@Lx0@FgA>I;0ml->tyqFQDmo0aPV-} zqlG(>=nOv5j=p#SjRE1XY^<#oT-zi>xO_; zNNrt|_?es5^Bt-|3|@86SjFUbKFpEYso07v{KIFa* zGqT>_w_2QCAP0A~esaLb<+Z7x96afpJDR=(O7TFx-ynVgqFZ&uxSoTI=G@XE!3smZ z6kL?cJ1=n44n~-Els1Y0A!F2@4WtlhD}>zQ6o+#fcD|VEBfj_~2XG8RkM_CFww5#g z$Y{lv%$6J{2)7ysI}|e8_ym+F>t%aGmXySk--)jMzpwhos}q$!S$Wq*vj30niMXA* z=cxlc6A=J~pGlq}8ho*N_lvgPKuyP=EHYBTFw z#*<rTFjl_L#3Ffa$#dUbEY7&u=x=Kn! z2uQn8fO3G{_=mk9j&Oc{X(3z_u=PGayuN26PsTE`=xKjse_}y#Md?ii3hoxA8t>Ti zQ%~MLT6mIMjtTKSG_w81gV&9Lh6IR^mr7=o*pt5LTcuJi!D%|$c?A(Csh7dvkuq~M zLo1PDQ#xEqNn?&xqFOP>5raV9NXF0Q_S~rnV0@bLzi=vulyiKYdR$Q|&C-AxhoO!@ z(g=MIp`qGdUAz1L;i7h9^?NJ7T{%_!je_Yxc^{41o;cRC`cBfqQA)t^c&UEUMEs`MVXR8HyN!GHH0A^WJv#atCF0HF97xZbw;CN8XUQB%Xsa*D1d@3+ zuUDGacglw$i8|3Zea`Q>5kk>k;Q}i!7?S0e?r8+dN(_%&+Z*IXC{aKEA42xaxyvx(6TRp#+lXV3QOdK*dYlHUTssk)?mOa z6*5D|H-51TTUNG_y7eXM025Sx=plp*B9vzB%v2TNsK{c)n~k0o1-KJTm;VF*yHs7S zG>Shs8273f%(_*^Mc6K ztVwUr8dvPS(S$3br63_(52{B_Owp`L(ru9;pI|i1so+awtk%7!?@HsP1>yRETMId% zQ+roP#Kw2tIr@^O_v}2NxdRx;of+xo{GxFwJQrSqb>-JLmSju(*4usW+k2Prk7P}b zrb^^KY}ww^{1o8f8AJ$4uO@EE5iEni&)w-H$d?i)#=KVzAJYHZQ+0N3$>a~2<5k0ku+y*D6uQ{x$Ur{uG9GlC!M(J675#$^x@fu+8*)(D>%pNYVK zT^zf!|HS{x)!(RouJTOruP;XYf5qN4X6_EusOG_ZG*#MFa~+O$EY5p#*c#7ce^2J(0psj_>4vdY4w}tNY8RCzNW)q8IH#5C&zX z26p`0y*^ckGEVIAF10}s#n&n=%y&h9Z?KkD&&mrD5egVoP3i89S}RFC2|Xdq-IYJP z_cgZh85cgGZHM!o#M>{Aus7oEs=YVy&c|{n(T@%tmA3)msuug926ECX<2=7v2;MxBi`S4|Ed4a z!vB3wf6mM?4y!Un|x+h1Qq{OieXvnpI95+P(atlyoJPCdPEV1?;Yud#?s$iW$ zBbJ;g)w!%R?aY~{@w)Q_WAfPO3BZsFiKt?EvEA4cf&J9j{iB~hsjK@NfkQM=dRMTg z_`bmvc<0_*weMq%n={^bu*!Ilyoertu|9`eXhvEE;QqR?g4}hSLvW+^Gag>&Yt2?N zj>K5-Y4Mx7JN@F`b-L5z$44(RAsnN*JYsPatt{Cyk&D$IP7Wj9VA0Bw4c_z~@bS zH?f%M@$J#qE^R!HuP8wGj=nU~vvuyj(nxY|BDpe(t#a_fy+7~jI<@q0ni|;9F)75j8pR2r$Prt$+jYE6yVRw#=XVjvH zdT!5P22DNMP)f~g2#Q$k{ZR4F0D+#tHWD0KF6ZJcVtPEzsVSzbG8W*B2 zVPq7S4FD`D)=|#a;9~u=+j=ss#3zgNUP|Kwd+%a};50MhnxR{jCcTl2YjL)b^XoI` zq5#YX4I(!})CP_T?=4*z2g1&fJAZ0VlUaa=Y#m6QiF}9jBMAU{uz)S~6Myt(p~N}J zP%omK-wmgENR4G!nhR`%a6vFsg2x5U&BY>{z6Kbze66|DIuW1Vc;DVT+%tV(^fRRe z<_V0sR;36_yN~msG@dQOcOvM^0ro$>m!s)`MCbEhbh;wCmlkrX8o;v$L?DTxHZCfNc>5M)yj zEo*6X7l0?|`A$8j8=Y%|BliIa3KU``VIB$-T{cpOjS>~T(P zCyJfLP8?5SCz|>F?|ZN6eT8~e4`@)5lj%d1fJOt~``)|nuK)YLH-6)0fHZH~{s`Lz zOzhh6+m$e{a{|b6OwJa#o*>3|;>h`qltA`H4l6xtCNdhXeY=NHeQ^83ED`gzKVyj} z84Iv9EQ)WC3T&Kk!WnhYa^H_z4lxjttu&}L7y}=fMS5;%5pyM>vXL1`?Z&HjZH`_Z z-`X~c`y4+#EscUcfV7~impdT2i;~Vx1WOu}+A^0s*xWB}e@G`hdFrZ+?HeA?oav~W z3SC=XGRnR_!IRe3pQT17!xF*d{d%M!++@vR*S%5_!&TLsMkXM1F{v)i8N+kp9fn02 zBtf|G4{y5>Hq8uMl@Q?}wSgVYD0hw#I*SdV9KZ!Zj7n!D1Jdh-b@%_iqV{n0hbx~g z{!ww?So7b!W&3VB)*XbYv!>2iA{TST6YDC{(kZIn+>4y+0XG%wvVHnm=ukSlxy9Dk$+i+eG{T)PiWg(Q@*gr6lZSkFL*etPL!W@dh6Y8sO90Hs~d5!fYZ+ zJ%E;%2ajy`TPa;DtYH$(UDQEOFPtPf;p{v_2oEz~1j=e}>4Nvjzp_GVV}O=6R$5s^B`Tu8%+G_O=S8uJnO8?(8V>LkX2bx!Ie_XzM&Zy9l4(TW?t(yzwW_Fvxpz5r_ zJn<=!{s-UNLuy>MeLu^}!d<5hi9Sm)3d(42n1ALtKtTAeYbFpmOeZxUz5@F))LGHK zYe{IQU>on))~o|aaqk#!8$IaM*dH>o|M@p1eNA?F{{A$kqfu0>u*gFIAfn%f)<|c94?ppgW!If&+U_e z@C2b&X(=ha5|!R4d3ovfJ?!M{RK^=6m6?GX`nUj8wUN81{eX1H3VjGiw7(oVnSadx zK#mLN9~UMlFn9kC7PWQyf1U*YcYSd%dA)P~p!xW=xVUlabAW%toxU@&R5s#hC<=!@ z!VPP(Dpzi;JYPcg}*k^bzcULRpr~ z5I;$zmLRh$IbMN?*m@mE%?r05 zkT#vlfH$SJ=`hXjTx3F@MS4gz9*!Mx(7@8U;r{~x@`)IC|F0=(&1$!Lb>+F@FBI2s z&70S5i}#vRREFD?*eLLqa;N&#>Plr8k`ayS;OjxVMX7Cle9 zdENG2x46sB`4rhdWISN2lnGZaxsL|ZGd9&p1Oqf_pm=q%lzs5(BioO-)t$SHof-9x zDoo-E!xD3K@poD~{I3iqf{wG_-{}H{C*C(G{UZPbYdp%o^ZGVO(GAt^iNWFJd zh5u0>cQQf)N5G1LA#Ef`m#vM(`&1%p^9|9amn6I91Pq_cM5DM~ZKbr;lmE!drBY$3grdi#7 zLW*!Q%fC9IEyH2>VTShYz~)y`R&>>r=5g^W>dX5ULugo%E3fuG5} zuF47nV9A1j!=cl`DQ{n`bCu{bNCo5fQhJ>_lfS|jZO^c~vr{?6%T(&JH;CS?OP)f6 zD)-uwWvc)!=IxT40f%CzLmdC&_G50FGYm??oqD$3&{Papb{NX%YBA2n%Ujw?1;pH4 z8+LC-9C zwJs`UbId6tS%NB@QY=w2vMA0V;MZ-7e452gjbB{aMSculMAEyo0lwp;J8rQj(vHvC z5O`lKHzltR?y45q5J%?V>SUqZ^*eRRwg{&WPUcXPj8yC{3yC9TEoBk`{3Lhv^c%mt z;5U)yVs(d^N$aE4LF?}l7;LvLv$!NV6;;hj`M*Wll!+nr@0$ZTtT)yjW6wNFVUfs- z1dZb&pbF{Hx3)!Zy?-(THI$a5GbcnL=Nz9Lhr948Nn*qcpwbQc&U?CVZ)>QVXpNZn$qIOU9fy#98Bm8pA*UI*D?Bh&MUOl1ehV^!qc8#!- zI=ruPzrKA?&&v^<#Pi}tumr*-mKwus287G0E4Rhq4Aov`{GlbDKbAFK_l(Tknhm7I zbZxDMph>w-R|D)h$He6)47ev<>WjQW7|`5a$Iby!6MWAph#t~_Ck&qr7KloX3fNp# zdAxHh=s-CHQ_>sYPY4iR**?Iw%ub%#H-1}^>B~7KwfWCyzbydNTd6wX1AfW%664lg zh%h3p1B>9D6enGC694ALG43e|upaJ{Is@3Jp5nyVADM?c3)&(jLD(Sk)b(wWswHt$ zpKkBMH1}^mqc@*wW*~`@Z=MERjGr1Uw<0>-veV5fd05Szb*D|&Of7gpWKBfRKD$HbX@PWA(!Na9TnLk zKAXQ6D0(0s4EAkOMbK66p^QT7f?YDd0OC5IZ_mxj%~TL`zNL;qVr$BZf`8$lNojU z#Q6>NFXHDB{R>m>1LaR{e^C-M)qHxqDN7v9z=$C-)2cUn?k$BE8=H+avoT7qBguI4 zmipAiSDC!WX#~kEB^3C62-MB*pMuOg{-9yL}8sTfx( za>)U~dTkDb=>b0kLXnaqSuO1hs*r?0NGjd7Z7kwhogC?KCqXfI?}#ydnBzUrb8aHthqciuQWfr zEhbi0mREOAD6|wAs~v$5)L^F%~|cc4xK^vw8Tw^E9Lnh94{Jo(n z4&Lhet{p0psymwwGc$Kr)*9@+;K*2Q&=--~1RK^j$E(}(Z0qdQ{o`LFS%x1r!!3Rw ztt3%v*HznJaYiP?{wK^@Ocu#~u$gt1ofPIkcEw>6Tsgw$gCG&u!jmfP1g2Jgo73UC z{}aXURR7;Ut=_}@kKcKYSAK_ot@-NqOS+d?1gvR|;r;D$ig=arY?kgK6GE^Qaw7BrnMmPq(S*^h{Va91do<;F>1KSq^g z0TJwDnrbD-M6HmTNJ^Kl|IQ*4Gme%P3u=i#Bska~+7_2OZ4tMQUu^oI9>=-C;ebfn zweaieo-=;Cf6dh$L4GT&wX%Jbd%i!Xg)F_)JX*u(>H~qkk9CC8y>9!6u6|bkU*dG< zgvPK7uY&41%>OB`?ru$!=->Zc#djCAFI0cDdPC*MEAQbq-}tZQ?(H?5)KmroXZoa` zS~{cGhNy$-+8Xmgb_gPSIZigNKHd=#VfM*DuitJsRh`lIlW?lbP3yiEV`+PG7^J(1 z4bUbQuUVaMYtx2Z=@KkJvQc)rpTa7^4|^$pN}9{N_g>bTX6 zhY8o`;_VePlNmG)Ni+E*iN_f5>%a*yeLhD-KC|CHAD;~CfsH2w(I44%bniK>zlob< z>OIh@OBjfFg+pPBVgroHgeSsoj({)r;+X5*raa0P9WfT`#rEYJ_FW=tO<9ATwd4{w! zl7<|PpYfF>ky@rkPiF` zM9@^}X+m}GkNkJTr_LXtSI>CE7EhWwj;@>MCysZOLa+XFZ}8^!x@~F()F+{l=d2qB z*G*0j&JGVZzl@cz&&tBoOJ1^C0}aGqTckli?|D+~C*jqBq%`!1eLwakK-?VGk=vy*9FHQpUfF6Rk#d6>FakFM_h z#um)cODg}*yJcboMvs7uwpipteTY@_n(dQri5amUc3`;8ex@O48tQ!6=E$j9#q^oR zDoZrIG^8u1zDjpL>8e;Wur$Kbkg{LjewCx#AuXX@E#Pk!1*y)66Sh`L8}d**n2@61 z+CCxqnc7L^FkRA(UsnAD{V?m)72B_H4j{cU>hCEv;!^M2GB!v5=8!)>}KG%rN zO(I-kLS&nzMKCTv08+31itV?x4LK2RavNR@7*>VxEHfPLM zat(=8FCF>{lcf2q+(isk+6)##bQJ0lAKvyO;tUg zqPqQtZQB=jV7QQAIWU?}d0ee9OQ_#6O|3P^#P^>@6Z$qnI>+Vz?ks9AR{uEm|Jvft z^nGnEwRSl#XeYtv*m!2AQ|kQR=NM$am98_nCL@pLH7|-xmnVcS9S>*2#so)xz9s5c zti_Gv&nICm#tx^V8*Y=p(j3rZ^<^s&hH~!4Jm`nLEAy{$!Vi-CLGcS2 z##fh~WeUKdWdDJdSla2@$slaqJF0{?>&oL`C@IY#f{LWUE(zbcGQX|?f^=J`Q&PS* z$yj5ok6#wrkzO$(P-s*3`0P?lUA%61>{%Rg*U97E|%o%=}PLw=_2jrm;&hy0ya--?w zHZL4oZ7esAB9M`jJf_jG2zoaF$*Zn#4lj%3=agysA zx#`Jws=1hi*%9Q=c*)TYO7%O=^7x!d@~F=1y_J_+qH3SXVKhuw#(`b{TvLyMjyJ&q zpAfY-uWyN%oy_;SXHw4!p6!cX0+RJxU!vt%o~D;nXkOkDDf`YTLT6zJ#L6t-u`oU*hm0{2XA1hIRaCCDxauW#~82aKuqDlWNcXt_XMkPpJRrSLpx$F6RH8 zNZMMOnv9NeIz9&U*u76&M!J0|Te%*Zp4-8pI(-49CYX-*}%nI5sc zh?YWLWTdcGWMKK711ULhgEHi(B;S^W0#J@ojR znlO_P2Ko@kf*g zOKYO6($|ab{%;kv@2Xu6|L>ow>?*d-+bvK1L(NNC?`I=sr!rt|Njq_7kGutGCne!J zmNGRQ%^yrbMaHF@U1_D7IyjQimv2~-<(HT{Qgndvd#^gcZAOVY91uygx`eJgg zd12Trv(f@7b8u22p187Ql(9L}BY4B%C4}dx!=J&H$;~2_jB7&~Iq>{R15iX>Z>$lh zZ!$MD+BZCWaRYgYex_wi@srIH=j@n-=4opJYE0YtY3qh^T^jV2BA#=|R$Zai?jEf{ ziqRPhs89(8d;w+b@%@Vg#Z7g>gOsyQF*5L zfz-AA#(uwfcT4QH7{v^fW?EgIRRHOkoFMuVB^1I)Fcnfg7(_o-v2-73i{l`@Azy3V zV$$>J@dud*HRiU~4=ddyD*DC6CAr_+!1aMgs$#^(QN2D7Q?}3I{ zC;=aD1NprB#KGz=-A2oJ<8vCvM*8=UFVjPB8n{mHv2@MA1u`b{p42_m5=}fwkBqn? zdDV4^l@EfJE~E}^LLi~N>ls~IeTftlub~N4TY#a zwt}O1RjtROZdOLCq4pNXf@|rw_~6x5kIN9G_sZ7&lHROt@q}yG8v~Ei<+?2eA7bnR z90N<}bSm}%G;YfywYE`TP?KUT4JAv)eu^9zZo3SRb)+pDp7rI}qTSgR|Gsixyr$%LUOOM8o_0jgPx9-&q z%Axm3-XI*2^1MX{urM6nI(>Adr&FOpONaF5{jGa+VpBUlG2`^c8QRbU)21IJ26u>?%`ypTFtL6Ffa?Ww{SMxz9Ys0#IJ_u z_$Y4xktH!`FRmo|;= z8nQy+0IzR7;7m*g2qNKK%!QX$=Yo>6F1@^Y`!umJ=}w{L2_h|R%Mt6K*+;h}q;MBY z8XI-ZWZZcE-|pgr@c-7XsD7pLk1F-z&+*&R7sa}L+OwR2?CCu_MB-f`4!sNFDzoA_ z&YqN)zAeUQKvfq0pz})Ck{FM!w4iD~+A?b5ELEHE`bVq<$tBl0`mo?9q!tJu$>C^9uZxJNEa}vt?Emg!qo}=F{SVcbD!)=$DSn0DzMEfLEipl6 z^?xKiwHa$|@fVeYRw%H+cunfRkth=CC{ykg$J;FtK<>}k>9m6}Yns+0t(9S2Mt2=S zwP_KH5VguZ?w>X3GRkG4%=miC_#bm7awRN*Y`InIZKQz36OMS=vWHNntqnY#Xgz45 zH(H`wp3UJ3O78n?AZCj?6c$eixrNOU@H&1xN?Yl|ppPzSJuXSlY4J|HeJB;0?NFM+ z^lzOw2E>CUy$k?L=SJxe1bF7ZkWHz!M2tK$nZaR_@TkTTI`-IWBT<0BUUl~X>AIlx z*baAN)Qp_1RbTwXcfGVD36gn=CRFl61HSN6aGS&g$OD@LR3h|ct+k$Fb7pgjeMyfLX=OJcr zWkYhxZ3uOMS*HX^SOZA(K(2rSF!iV+a%s1W|3AcZy8jc!PYD12XRDW1-r|?Py}p{C zY`x%=&`!`3bEPxrIsmZ-pYJQ@wwOSZsO`;TL z&n;MOIkM}Fyl=usdel+OhK5O(5-dHCD3RQyPlq`B|A#dH^KV!0t^Co-bn%D2B@{rj z))Kko?9`XX8yU`dIO0v|K+7!58()IemmPaoNX28Z(em;BfXgBe7!td0v_vkse=37D zJ}qreHL&&;qF6C%k#Pr{PhG~(dPYl+M?FhN`1IdptrvNI*5txeIJ$21XX~`uxrA9X z_~OXYx(X|%yfDMugd@wYC{S7w8A&yb`z2k|`aDZIm;*%|>3xi(Ss4k0h~g`PD~geR zw;HWO5}6zXKvHDp;%Uw7iTF$6%@Cv)XDm3EpKghk8Oxs`AZcIdEcz1RE;6nFl;z?U zKoleX!(DRU#W9$NI(^eIvj|E+Tw2bi302B}rTf2J)Sj>YLiP5_mx`Y+mfx-Wzt$4# z;{KfDNpF=D8n>rEkXqvno<>RUU0a`?CWmk1O+#Jvjn-G}`ebBR68f}<_70sM+#>3Y zN4=9~?fLQJ@smmZhPyJ;`mz&`JS~=R49}snaexIPlO`g55wH$)iiL3X6Rj`tB2*+Z zuvH^({k~yjof2Eow4sb-B1N-Evd&w}JEyZCZt>d5``~2xwXd|kXflvND4mdjVH0{| zogjt4Bg0e7>v0#<9d*UC!t$N(gPrk;8#~i^v;X{_nb? z_7&!TE>`~U%6#$ri|eETUTGb(+nN#5q;KmXL(-C#C3Go|-YDH!v^dT8A)5MZ>nQsN zq$I;DP8hwoZJJ3w_>`-QU};ekDrJjoj|j?qWgk&(9^+@oB8i_5t_kpGt6VhtB zG3W)y{A2Ng#G}wx9+Ry_ThO`JFwYhW9IwR?+IRcx-%3k_%30;Vv{cXaTRJ^+S^PX4 zdX7INOKxb1G8x60(GxjRaqg%uGF~6qu|Duf_y2-|`u}IDA13<$=G6YBZkjK*MDDnM z>QsiFP9M!q_*>@bGDbVtjJ-vsahL*4jTau$dxG9jCQ#uZvA>7~)|nDU_9fbV5=Zw% zBd$NxGK$El95UVXOQU5|2>{JG9&TA(PEB=9OSJ}9H(sl3T5lxrsmohpXr7%qm7!OX zs_a?nsr7YbJzc#9+E340e?)N#L5igzeQBR)`jy6#wR6cC@C^J0msY~VjbK+`<;a>` z@C{^M#bg)q=?twlLeRyGcsFd;)lIBVhpNF{Jd!3zhq~5dl=j2@aDQ$7QJyY4MW$~j8(~{!GZW)Cuu}R!|NrepZLRv7 z%>P?2{*U5zUB`j1<_)d&Z-^T6? zpBjwG(v7hii~dMb0#$|b&S$}XE{;DkViY*+zS>>E87RHBit7FDj7wS#bA)!%^EqeD ziuF~7gEdwS>&og^X=|Qe^SMn2Q}m|*MdrYQC=CV6ywP$*${7JoQk%`LhK8g8cIjA) zT5!;V16|xQPURe8nB-$siyB%57FKZnFwH>dRPK(NwspQMrCp#ROoGWrs4o9kFKQ1} z+wlMY{^DO3^?|#;^WQd$mhntZ9ok7i#3V3B#fz>~v#5%LX4=&0=-VAjFKWyxJ*e+( ztrId|xf&ufp{S~ru9N;h