From 803d2052a178e5eaf191ec574fd975903a468bb5 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 1 Aug 2015 18:16:12 +0200 Subject: [PATCH 01/23] add Real Time Text api with stubbed implementation over SIP Messages. --- coreapi/call_params.c | 10 ++ coreapi/call_params.h | 23 +++- coreapi/chat.c | 97 +++++++++++++++++ coreapi/help/Makefile.am | 12 ++- coreapi/help/realtimetext_receiver.c | 117 ++++++++++++++++++++ coreapi/help/realtimetext_sender.c | 153 +++++++++++++++++++++++++++ coreapi/linphonecall.c | 10 ++ coreapi/linphonecore.c | 5 + coreapi/linphonecore.h | 38 +++++++ coreapi/private.h | 3 + tester/message_tester.c | 64 +++++++++++ 11 files changed, 528 insertions(+), 4 deletions(-) create mode 100644 coreapi/help/realtimetext_receiver.c create mode 100644 coreapi/help/realtimetext_sender.c diff --git a/coreapi/call_params.c b/coreapi/call_params.c index 828fba70c..f52aa9e27 100644 --- a/coreapi/call_params.c +++ b/coreapi/call_params.c @@ -263,6 +263,7 @@ LinphoneCallParams * linphone_call_params_new(void) { LinphoneCallParams *cp=belle_sip_object_new(LinphoneCallParams); cp->audio_dir=LinphoneMediaDirectionSendRecv; cp->video_dir=LinphoneMediaDirectionSendRecv; + cp->realtimetext_enabled=TRUE; /*fixme*/ return cp; } @@ -279,3 +280,12 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneCallParams, belle_sip_object_t, NULL, // marshal FALSE ); + +int linphone_call_params_enable_realtime_text(LinphoneCallParams *params, bool_t yesno) { + params->realtimetext_enabled=yesno; + return 0; +} + +bool_t linphone_call_params_realtime_text_enabled(const LinphoneCallParams *params) { + return params->realtimetext_enabled; +} diff --git a/coreapi/call_params.h b/coreapi/call_params.h index 8f9182af1..4f169c36d 100644 --- a/coreapi/call_params.h +++ b/coreapi/call_params.h @@ -348,14 +348,31 @@ LINPHONE_PUBLIC bool_t linphone_call_params_audio_multicast_enabled(const Linpho * @param yesno if yes, subsequent outgoing calls will propose multicast ip set by #linphone_core_set_video_multicast_addr * @ingroup media_parameters **/ -LINPHONE_PUBLIC void linphone_call_params_enable_video_multicast(LinphoneCallParams *param, bool_t yesno); +LINPHONE_PUBLIC void linphone_call_params_enable_video_multicast(LinphoneCallParams *params, bool_t yesno); /** * Use to get multicast state of video stream. - * @param core #LinphoneCallParams + * @param params #LinphoneCallParams * @return true if subsequent calls will propose multicast ip set by #linphone_core_set_video_multicast_addr * @ingroup media_parameters **/ -LINPHONE_PUBLIC bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *param); +LINPHONE_PUBLIC bool_t linphone_call_params_video_multicast_enabled(const LinphoneCallParams *params); + +/** + * Use to enable real time text following rfc4103. + * If enabled, outgoing calls put a m=text line in SDP offer . + * @param params #LinphoneCallParams + * @param yesno if yes, subsequent outgoing calls will propose rtt + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC int linphone_call_params_enable_realtime_text(LinphoneCallParams *params, bool_t yesno); + +/** + * Use to get real time text following rfc4103. + * @param params #LinphoneCallParams + * @returns returns true if call rtt is activated. + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC bool_t linphone_call_params_realtime_text_enabled(const LinphoneCallParams *params); /******************************************************************************* diff --git a/coreapi/chat.c b/coreapi/chat.c index 362079682..d9593af28 100644 --- a/coreapi/chat.c +++ b/coreapi/chat.c @@ -498,6 +498,11 @@ static void _linphone_chat_room_destroy(LinphoneChatRoom *cr){ cr->lc->chatrooms=ms_list_remove(cr->lc->chatrooms,(void *) cr); } linphone_address_destroy(cr->peer_url); + if (cr->pending_message) + linphone_chat_message_destroy(cr->pending_message); + if (cr->call) + linphone_call_unref(cr->call); + ms_free(cr->peer); } @@ -534,7 +539,15 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM char* content_type; const char *identity=NULL; time_t t=time(NULL); + /*stubed rtt text*/ + if (cr->call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(cr->call))) { + char crlf[4]="CRLF"; + linphone_chat_message_put_char(msg,*(uint32_t*)crlf); /*CRLF*/ + msg->state = LinphoneChatMessageStateDelivered; + return ; + } linphone_chat_message_ref(msg); + /* Check if we shall upload a file to a server */ if (msg->file_transfer_information != NULL && msg->content_type == NULL) { /* open a transaction with the server and send an empty request(RCS5.1 section 3.5.4.8.3.1) */ @@ -856,6 +869,51 @@ static void linphone_chat_room_notify_is_composing(LinphoneChatRoom *cr, const c void linphone_core_is_composing_received(LinphoneCore *lc, SalOp *op, const SalIsComposing *is_composing) { LinphoneChatRoom *cr = linphone_core_get_or_create_chat_room(lc, is_composing->from); if (cr != NULL) { + /*rtt stub*/ + LinphoneCall *call = linphone_core_find_call_from_uri(lc,cr->peer); + if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { + const char * rtt; + if (cr->call == NULL) { + /*attach cr to call*/ + cr->call = call; + linphone_call_ref(cr->call); + } + if (cr->pending_message == NULL) { + cr->pending_message = linphone_chat_room_create_message(cr,""); + } + + rtt = sal_custom_header_find(sal_op_get_recv_custom_header(op),"X-RTT"); + if (rtt) { + if (strcmp(rtt,"CRLF")==0) { + LinphoneChatMessage *msg = cr->pending_message; + /*forge a message*/ + linphone_chat_message_set_from(msg, cr->peer_url); + + { + LinphoneAddress *to; + to=sal_op_get_to(op) ? linphone_address_new(sal_op_get_to(op)) : linphone_address_new(linphone_core_get_identity(lc)); + msg->to=to; + } + + msg->time=ms_time(0); + msg->state=LinphoneChatMessageStateDelivered; + msg->is_read=FALSE; + msg->dir=LinphoneChatMessageIncoming; + msg->storage_id=linphone_chat_message_store(msg); + + if(cr->unread_count < 0) cr->unread_count = 1; + else cr->unread_count++; + + linphone_chat_room_message_received(cr,lc,msg); + linphone_chat_message_unref(msg); + cr->pending_message=NULL; + } else if (strcmp(rtt,"S P")==0) { + cr->pending_message->message=ms_strcat_printf(cr->pending_message->message," "); + } else { + cr->pending_message->message=ms_strcat_printf(cr->pending_message->message,rtt); + } + } + } linphone_chat_room_notify_is_composing(cr, is_composing->text); } } @@ -1018,6 +1076,42 @@ static void linphone_chat_room_send_is_composing_notification(LinphoneChatRoom * } } +uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr) { + if (cr->pending_message && strlen(cr->pending_message->message) > 0 ) { + return cr->pending_message->message[strlen(cr->pending_message->message)-1]; + } else return 0; +} +int linphone_chat_message_put_char(LinphoneChatMessage *msg,uint32_t charater) { + /*stubbed implementation using im-iscomposing+xml*/ + LinphoneChatRoom *cr=linphone_chat_message_get_chat_room(msg); + char *content; + SalOp *op = sal_op_new(cr->lc->sal); + char* value; + const char* from; + LinphoneCall *call = cr->call; + cr->is_composing = LinphoneIsComposingActive; + content = linphone_chat_room_create_is_composing_xml(cr); + linphone_configure_op(cr->lc, op, cr->peer_url, NULL, lp_config_get_int(cr->lc->config, "sip", "chat_msg_with_contact", 0)); + if (charater==' ') + value=ms_strdup("S P"); + else + value=ms_strdup_printf("%c%c%c%c",((char*)&charater)[0],((char*)&charater)[1],((char*)&charater)[2],((char*)&charater)[3]); + sal_op_set_sent_custom_header(op,sal_custom_header_append(NULL,"X-RTT",value)); + ms_free(value); + if (call->dir==LinphoneCallOutgoing) { + from = sal_op_get_from(call->op); + } else { + from = sal_op_get_to(call->op); + } + sal_message_send(op + , from + , cr->peer + , "application/im-iscomposing+xml" + , content + , NULL); + + return 0; +} static int linphone_chat_room_stop_composing(void *data, unsigned int revents) { LinphoneChatRoom *cr = (LinphoneChatRoom *)data; cr->is_composing = LinphoneIsComposingIdle; @@ -1454,3 +1548,6 @@ LinphoneChatMessage* linphone_chat_room_create_file_transfer_message(LinphoneCha msg->http_request=NULL; /* this will store the http request during file upload to the server */ return msg; } +LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room) { + return room->call; +} diff --git a/coreapi/help/Makefile.am b/coreapi/help/Makefile.am index 479d2b31d..895b1e99b 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 filetransfer +noinst_PROGRAMS=helloworld registration buddy_status chatroom notify filetransfer realtimetext_sender realtimetext_receiver helloworld_SOURCES=helloworld.c LINPHONE_TUTOS=$(helloworld_SOURCES) @@ -81,6 +81,16 @@ LINPHONE_TUTOS+=$(filetransfer_SOURCES) filetransfer_LDADD=$(helloworld_LDADD) +realtimetext_sender_SOURCES=realtimetext_sender.c +LINPHONE_TUTOS+=$(realtimetext_sender_SOURCES) + +realtimetext_sender_LDADD=$(helloworld_LDADD) + +realtimetext_receiver_SOURCES=realtimetext_receiver.c +LINPHONE_TUTOS+=$(realtimetext_receiver_SOURCES) + +realtimetext_receiver_LDADD=$(helloworld_LDADD) + AM_CFLAGS=\ -I$(top_srcdir)/coreapi \ $(STRICT_OPTIONS) \ diff --git a/coreapi/help/realtimetext_receiver.c b/coreapi/help/realtimetext_receiver.c new file mode 100644 index 000000000..2801a2237 --- /dev/null +++ b/coreapi/help/realtimetext_receiver.c @@ -0,0 +1,117 @@ + +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (simon.morlat@linphone.org) + +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 real_time_text Real Time Text Receiver + * @ingroup tutorials + This program is a _very_ simple usage example of liblinphone. + It just takes a sip-uri as first argument and attempts to call it + + @include helloworld.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; +} + +/* + * Call state notification callback + */ +static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){ + switch(cstate){ + case LinphoneCallIncomingReceived: + printf("It is now ringing remotely !\n"); + linphone_core_accept_call(lc,call); + break; + case LinphoneCallReleased: + printf("call terminated, exit...\n"); + running=FALSE; + break; + default: + printf("Unhandled notification %i\n",cstate); + } +} + +/* + * Completed message received + */ +static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message) { + char *from=linphone_address_as_string(linphone_chat_room_get_peer_address(room)); + printf(" Message [%s] received from [%s] \n",linphone_chat_message_get_text(message),from); + ms_free(from); +} + +/* + * + * Remote is typing + */ +static void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { + LinphoneCall *call = linphone_chat_room_get_call(room); /*get corresponding call*/ + uint32_t received_char; + if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) /*check if realtime text enabled for this call*/ + printf("%c",received_char=linphone_chat_room_get_char(room)); + /*else ignored*/ +} + +int main(int argc, char *argv[]){ + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc; + + + signal(SIGINT,stop); + +#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 call_state_changed callbacks + in order to get notifications about the progress of the call. + */ + vtable.call_state_changed=call_state_changed; + vtable.message_received=message_received; + vtable.is_composing_received=is_composing_received; + /* + Instanciate a LinphoneCore object given the LinphoneCoreVTable + */ + lc=linphone_core_new(&vtable,NULL,NULL,NULL); + + /* main loop for receiving notifications and doing background linphonecore work: */ + while(running){ + linphone_core_iterate(lc); + ms_usleep(50000); + } + + printf("Shutting down...\n"); + linphone_core_destroy(lc); + printf("Exited\n"); + return 0; +} + diff --git a/coreapi/help/realtimetext_sender.c b/coreapi/help/realtimetext_sender.c new file mode 100644 index 000000000..7f001dd08 --- /dev/null +++ b/coreapi/help/realtimetext_sender.c @@ -0,0 +1,153 @@ + +/* +linphone +Copyright (C) 2010 Belledonne Communications SARL + (simon.morlat@linphone.org) + +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 basic_call_tutorials Real Time Text Sender + * @ingroup tutorials + This program is a _very_ simple usage example of liblinphone. + It just takes a sip-uri as first argument and attempts to call it + + @include helloworld.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; +} + + + +int main(int argc, char *argv[]){ + LinphoneCoreVTable vtable={0}; + LinphoneCore *lc; + LinphoneCall *call=NULL; + LinphoneChatRoom *chat_room; + LinphoneChatMessage *chat_message=NULL; + const char *dest=NULL; + LCSipTransports tp; + tp.udp_port=LC_SIP_TRANSPORT_RANDOM; + tp.tcp_port=LC_SIP_TRANSPORT_RANDOM; + tp.tls_port=LC_SIP_TRANSPORT_RANDOM; + + /* take the destination sip uri from the command line arguments */ + if (argc>1){ + dest=argv[1]; + } + + signal(SIGINT,stop); + +#ifdef DEBUG + linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/ +#endif + + /* + Instanciate a LinphoneCore object given the LinphoneCoreVTable + */ + lc=linphone_core_new(&vtable,NULL,NULL,NULL); + + + linphone_core_set_sip_transports(lc,&tp); /*to avoid port colliding with receiver*/ + if (dest){ + /* + Place an outgoing call with rtt enabled + */ + LinphoneCallParams *cp = linphone_core_create_default_call_parameters(lc); + linphone_call_params_enable_realtime_text(cp,TRUE); /*enable real time text*/ + call=linphone_core_invite_with_params(lc,dest,cp); + linphone_call_params_destroy(cp); + if (call==NULL){ + printf("Could not place call to %s\n",dest); + goto end; + }else printf("Call to %s is in progress...",dest); + linphone_call_ref(call); + + } + /*wait for call to be established*/ + while (running && (linphone_call_get_state(call) == LinphoneCallOutgoingProgress + || linphone_call_get_state(call) == LinphoneCallOutgoingInit)) { + linphone_core_iterate(lc); + ms_usleep(50000); + } + /*check if call is establised*/ + switch (linphone_call_get_state(call)) { + case LinphoneCallError: + case LinphoneCallReleased: + case LinphoneCallEnd: + printf("Could not place call to %s\n",dest); + goto end; + break; + default: + break; + /*continue*/ + } + + chat_room=linphone_call_get_chat_room(call); /*create a chat room associated to this call*/ + + /* main loop for sending message and doing background linphonecore work: */ + while(running){ + char character; + system ("/bin/stty raw"); /*to disable buffing*/ + character = getchar(); + system ("/bin/stty cooked"); + if (character==0x03) {/*CTRL C*/ + running=0; + break; + } + if (character != EOF) { + /* user has typed something*/ + if (chat_message == NULL) { + /*create a new message*/ + chat_message = linphone_chat_room_create_message(chat_room,""); /*create an empty message*/ + } + if (character == '\r') { + /*new line, commiting message*/ + linphone_chat_room_send_chat_message(chat_room,chat_message); + chat_message = NULL; /*reset message*/ + } else { + linphone_chat_message_put_char(chat_message,character); /*send char in realtime*/ + } + } + linphone_core_iterate(lc); + ms_usleep(50000); + } + if (call && linphone_call_get_state(call)!=LinphoneCallEnd){ + /* terminate the call */ + printf("Terminating the call...\n"); + linphone_core_terminate_call(lc,call); + /*at this stage we don't need the call object */ + linphone_call_unref(call); + } + +end: + printf("Shutting down...\n"); + linphone_core_destroy(lc); + printf("Exited\n"); + return 0; +} + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index c6491e788..552d924b3 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1121,6 +1121,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro } discover_mtu(lc,linphone_address_get_domain(from)); + if (sal_custom_header_find(sal_op_get_recv_custom_header(op),"X-RTT")) { + call->current_params->realtimetext_enabled=TRUE; + } return call; } @@ -4096,3 +4099,10 @@ MSWebCam *linphone_call_get_video_device(const LinphoneCall *call) { return call->cam; } #endif + +LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call) { + /*stubbed implementation*/ + LinphoneChatRoom * chat_room = linphone_core_get_chat_room(call->core,linphone_call_get_remote_address(call)); + chat_room->call=linphone_call_ref(call); + return chat_room; +} diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 104acb0f2..01f785e14 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2971,6 +2971,11 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const parsed_url2=linphone_address_new(from); + /*rtt text stub*/ + if (cp->realtimetext_enabled) { + linphone_call_params_add_custom_header(cp,"X-RTT","on"); + } + call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),cp,proxy); if(linphone_core_add_call(lc,call)!= 0) diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index e7c9c439c..feee8e1f9 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -722,6 +722,15 @@ LINPHONE_PUBLIC const char *linphone_call_get_remote_contact(LinphoneCall *call) LINPHONE_PUBLIC float linphone_call_get_play_volume(LinphoneCall *call); LINPHONE_PUBLIC float linphone_call_get_record_volume(LinphoneCall *call); +struct _LinphoneChatRoom; +/** + * Create a new chat room for messaging from a call if not already existing, else return existing one + * @param call #LinphoneCall object + * @return #LinphoneChatRoom where messaging can take place. + */ +LINPHONE_PUBLIC struct _LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call); + + /** * @brief Get playback volume. * @@ -1353,6 +1362,14 @@ LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_lc(LinphoneChatRoom *cr); **/ LINPHONE_PUBLIC LinphoneCore* linphone_chat_room_get_core(LinphoneChatRoom *cr); +/** + * When realtime text is enabled #linphone_call_params_realtime_text_enabled, #LinphoneCoreIsComposingReceivedCb is call everytime a char is received from peer. + * At the end of remote typing a regular #LinphoneChatMessage is received with committed data from #LinphoneCoreMessageReceivedCb. + * @param[in] msg LinphoneChatMessage + * @returns RFC 4103/T.140 char + */ +LINPHONE_PUBLIC uint32_t linphone_chat_room_get_char(const LinphoneChatRoom *cr); + /** * Returns an list of chat rooms * @param[in] lc #LinphoneCore object @@ -1558,6 +1575,27 @@ LINPHONE_PUBLIC void linphone_chat_message_set_file_transfer_filepath(LinphoneCh * @return The path to the file to use for the file transfer. */ LINPHONE_PUBLIC const char * linphone_chat_message_get_file_transfer_filepath(LinphoneChatMessage *msg); + + + +/** + * Fulfill a chat message char by char. Message linked to a Real Time Text Call send char in realtime following RFC 4103/T.140 + * To commit a message, use #linphone_chat_room_send_message + * @param[in] msg LinphoneChatMessage + * @param[in] character T.140 char + * @returns 0 if succeed. + */ +LINPHONE_PUBLIC int linphone_chat_message_put_char(LinphoneChatMessage *msg,uint32_t charater); + +/** + * get Curent Call associated to this chatroom if any + * To commit a message, use #linphone_chat_room_send_message + * @param[in] room LinphoneChatRomm + * @returns LinphoneCall or NULL. + */ +LINPHONE_PUBLIC LinphoneCall *linphone_chat_room_get_call(const LinphoneChatRoom *room); + + /** * Get the LinphoneChatMessageCbs object associated with the LinphoneChatMessage. * @param[in] msg LinphoneChatMessage object diff --git a/coreapi/private.h b/coreapi/private.h index 92e5f61df..4ca55d129 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -141,6 +141,7 @@ struct _LinphoneCallParams{ bool_t internal_call_update; /*use mark that call update was requested internally (might be by ice)*/ bool_t video_multicast_enabled; bool_t audio_multicast_enabled; + bool_t realtimetext_enabled; }; BELLE_SIP_DECLARE_VPTR(LinphoneCallParams); @@ -578,6 +579,8 @@ struct _LinphoneChatRoom{ belle_sip_source_t *remote_composing_refresh_timer; belle_sip_source_t *composing_idle_timer; belle_sip_source_t *composing_refresh_timer; + LinphoneCall *call; + LinphoneChatMessage *pending_message; }; BELLE_SIP_DECLARE_VPTR(LinphoneChatRoom); diff --git a/tester/message_tester.c b/tester/message_tester.c index ca623e0b3..af4f1bc00 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -233,6 +233,69 @@ static void text_message_within_dialog(void) { linphone_core_manager_destroy(pauline); } +static void rtt_text_message(void) { + LinphoneChatRoom *pauline_chat_room, *marie_chat_room; + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + + LinphoneCallParams *marie_params = linphone_core_create_default_call_parameters(marie->lc); + LinphoneCall *pauline_call, *marie_call; + linphone_call_params_enable_realtime_text(marie_params,TRUE); + + BC_ASSERT_TRUE(call_with_caller_params(marie,pauline,marie_params)); + pauline_call=linphone_core_get_current_call(pauline->lc); + marie_call=linphone_core_get_current_call(marie->lc); + BC_ASSERT_TRUE(linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(pauline_call))); + + pauline_chat_room = linphone_call_get_chat_room(pauline_call); + BC_ASSERT_PTR_NOT_NULL(pauline_chat_room); + if (pauline_chat_room) { + LinphoneChatMessage* rtt_message = linphone_chat_room_create_message(pauline_chat_room,NULL); + + linphone_chat_message_put_char(rtt_message,'B'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,1)); + marie_chat_room = linphone_call_get_chat_room(marie_call); + BC_ASSERT_PTR_NOT_NULL(marie_chat_room); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'B',int,"%c"); + + linphone_chat_message_put_char(rtt_message,'L'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,2)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'L',int,"%c"); + + linphone_chat_message_put_char(rtt_message,'A'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,3)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'A',int,"%c"); + + linphone_chat_message_put_char(rtt_message,' '); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,4)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),' ',int,"%c"); + + linphone_chat_message_put_char(rtt_message,'B'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,5)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'B',int,"%c"); + + linphone_chat_message_put_char(rtt_message,'L'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,6)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'L',int,"%c"); + + linphone_chat_message_put_char(rtt_message,'A'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,7)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'A',int,"%c"); + + /*Commit the message, triggers a NEW LINE in T.140 */ + linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message); + + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + LinphoneChatMessage * msg = marie->stat.last_received_chat_message; + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(msg),"BLA BLA"); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + + static LinphoneAuthInfo* text_message_with_credential_from_auth_cb_auth_info; static void text_message_with_credential_from_auth_cb_auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) { ms_message("text_message_with_credential_from_auth_cb:Auth info requested for user id [%s] at realm [%s]\n" @@ -1726,6 +1789,7 @@ test_t message_tests[] = { ,{ "History count", history_messages_count } ,{ "History range", history_range_full_test } #endif + ,{ "Real Time Text base", rtt_text_message} }; test_suite_t message_test_suite = { From 3dff4de12e09ac519f0dc736b35f9f2421185938 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 1 Aug 2015 18:37:18 +0200 Subject: [PATCH 02/23] update rtt tutorials --- coreapi/help/realtimetext_receiver.c | 18 ++++++++---------- coreapi/help/realtimetext_sender.c | 18 +++++++++--------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/coreapi/help/realtimetext_receiver.c b/coreapi/help/realtimetext_receiver.c index 2801a2237..63801c516 100644 --- a/coreapi/help/realtimetext_receiver.c +++ b/coreapi/help/realtimetext_receiver.c @@ -1,8 +1,7 @@ /* linphone -Copyright (C) 2010 Belledonne Communications SARL - (simon.morlat@linphone.org) +Copyright (C) 2015 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 @@ -22,10 +21,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** * @defgroup real_time_text Real Time Text Receiver * @ingroup tutorials - This program is a _very_ simple usage example of liblinphone. - It just takes a sip-uri as first argument and attempts to call it + This program is able to receive chat message in real time on port 5060. Use realtimetext_sender to generate chat message + usage: ./realtimetext_receiver - @include helloworld.c + @include realtimetext_sender.c */ #ifdef IN_LINPHONE #include "linphonecore.h" @@ -74,9 +73,8 @@ static void message_received(LinphoneCore *lc, LinphoneChatRoom *room, Linphone */ static void is_composing_received(LinphoneCore *lc, LinphoneChatRoom *room) { LinphoneCall *call = linphone_chat_room_get_call(room); /*get corresponding call*/ - uint32_t received_char; if (call && linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) /*check if realtime text enabled for this call*/ - printf("%c",received_char=linphone_chat_room_get_char(room)); + printf("%c",linphone_chat_room_get_char(room)); /*else ignored*/ } @@ -95,9 +93,9 @@ int main(int argc, char *argv[]){ All are optional. Here we only use the call_state_changed callbacks in order to get notifications about the progress of the call. */ - vtable.call_state_changed=call_state_changed; - vtable.message_received=message_received; - vtable.is_composing_received=is_composing_received; + vtable.call_state_changed=call_state_changed; /*to receive incoming call*/ + vtable.message_received=message_received; /*to receive committed messages*/ + vtable.is_composing_received=is_composing_received; /*to receive char in real time*/ /* Instanciate a LinphoneCore object given the LinphoneCoreVTable */ diff --git a/coreapi/help/realtimetext_sender.c b/coreapi/help/realtimetext_sender.c index 7f001dd08..9ab25545b 100644 --- a/coreapi/help/realtimetext_sender.c +++ b/coreapi/help/realtimetext_sender.c @@ -1,8 +1,7 @@ /* linphone -Copyright (C) 2010 Belledonne Communications SARL - (simon.morlat@linphone.org) +Copyright (C) 2015 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 @@ -20,12 +19,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** - * @defgroup basic_call_tutorials Real Time Text Sender + * @defgroup real_time_text Real Time Text Sender * @ingroup tutorials - This program is a _very_ simple usage example of liblinphone. - It just takes a sip-uri as first argument and attempts to call it + This program just send chat message in real time to dest uri. Use realtimetext_receiver to receive message. + usage: ./realtimetext_sender sip:localhost:5060 - @include helloworld.c + + @include realtimetext_sender.c */ #ifdef IN_LINPHONE #include "linphonecore.h" @@ -94,7 +94,7 @@ int main(int argc, char *argv[]){ linphone_core_iterate(lc); ms_usleep(50000); } - /*check if call is establised*/ + /*check if call is established*/ switch (linphone_call_get_state(call)) { case LinphoneCallError: case LinphoneCallReleased: @@ -112,7 +112,7 @@ int main(int argc, char *argv[]){ /* main loop for sending message and doing background linphonecore work: */ while(running){ char character; - system ("/bin/stty raw"); /*to disable buffing*/ + system ("/bin/stty raw"); /*to disable terminal buffering*/ character = getchar(); system ("/bin/stty cooked"); if (character==0x03) {/*CTRL C*/ @@ -126,7 +126,7 @@ int main(int argc, char *argv[]){ chat_message = linphone_chat_room_create_message(chat_room,""); /*create an empty message*/ } if (character == '\r') { - /*new line, commiting message*/ + /*new line, committing message*/ linphone_chat_room_send_chat_message(chat_room,chat_message); chat_message = NULL; /*reset message*/ } else { From 303609ab4cc9304d6c2fd9c25709c98ac26f4118 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 1 Aug 2015 19:25:13 +0200 Subject: [PATCH 03/23] fix compilation issue --- tester/message_tester.c | 62 +++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/tester/message_tester.c b/tester/message_tester.c index af4f1bc00..08cf0613e 100644 --- a/tester/message_tester.c +++ b/tester/message_tester.c @@ -250,45 +250,47 @@ static void rtt_text_message(void) { pauline_chat_room = linphone_call_get_chat_room(pauline_call); BC_ASSERT_PTR_NOT_NULL(pauline_chat_room); if (pauline_chat_room) { - LinphoneChatMessage* rtt_message = linphone_chat_room_create_message(pauline_chat_room,NULL); + LinphoneChatMessage* rtt_message = linphone_chat_room_create_message(pauline_chat_room,NULL); - linphone_chat_message_put_char(rtt_message,'B'); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,1)); - marie_chat_room = linphone_call_get_chat_room(marie_call); - BC_ASSERT_PTR_NOT_NULL(marie_chat_room); - BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'B',int,"%c"); + linphone_chat_message_put_char(rtt_message,'B'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,1)); + marie_chat_room = linphone_call_get_chat_room(marie_call); + BC_ASSERT_PTR_NOT_NULL(marie_chat_room); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'B',int,"%c"); - linphone_chat_message_put_char(rtt_message,'L'); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,2)); - BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'L',int,"%c"); + linphone_chat_message_put_char(rtt_message,'L'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,2)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'L',int,"%c"); - linphone_chat_message_put_char(rtt_message,'A'); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,3)); - BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'A',int,"%c"); + linphone_chat_message_put_char(rtt_message,'A'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,3)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'A',int,"%c"); - linphone_chat_message_put_char(rtt_message,' '); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,4)); - BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),' ',int,"%c"); + linphone_chat_message_put_char(rtt_message,' '); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,4)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),' ',int,"%c"); - linphone_chat_message_put_char(rtt_message,'B'); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,5)); - BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'B',int,"%c"); + linphone_chat_message_put_char(rtt_message,'B'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,5)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'B',int,"%c"); - linphone_chat_message_put_char(rtt_message,'L'); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,6)); - BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'L',int,"%c"); + linphone_chat_message_put_char(rtt_message,'L'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,6)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'L',int,"%c"); - linphone_chat_message_put_char(rtt_message,'A'); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,7)); - BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'A',int,"%c"); + linphone_chat_message_put_char(rtt_message,'A'); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneIsComposingActiveReceived,7)); + BC_ASSERT_EQUAL(linphone_chat_room_get_char(marie_chat_room),'A',int,"%c"); - /*Commit the message, triggers a NEW LINE in T.140 */ - linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message); + /*Commit the message, triggers a NEW LINE in T.140 */ + linphone_chat_room_send_chat_message(pauline_chat_room, rtt_message); - BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); - LinphoneChatMessage * msg = marie->stat.last_received_chat_message; - BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); - BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(msg),"BLA BLA"); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneMessageReceived,1)); + { + LinphoneChatMessage * msg = marie->stat.last_received_chat_message; + BC_ASSERT_PTR_NOT_NULL(linphone_core_get_chat_room(marie->lc,pauline->identity)); + BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(msg),"BLA BLA"); + } } linphone_core_manager_destroy(marie); From 2e331a0ca00ecd11d602630aa7e163545be64ec4 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Sat, 1 Aug 2015 19:26:49 +0200 Subject: [PATCH 04/23] add rtt java API. No jni yet --- java/common/org/linphone/core/LinphoneCall.java | 7 +++++++ .../org/linphone/core/LinphoneCallParams.java | 14 ++++++++++++++ .../org/linphone/core/LinphoneChatMessage.java | 8 ++++++++ .../org/linphone/core/LinphoneChatRoom.java | 15 +++++++++++++++ java/impl/org/linphone/core/LinphoneCallImpl.java | 4 ++++ .../org/linphone/core/LinphoneCallParamsImpl.java | 10 ++++++++++ .../linphone/core/LinphoneChatMessageImpl.java | 4 ++++ .../org/linphone/core/LinphoneChatRoomImpl.java | 8 ++++++++ 8 files changed, 70 insertions(+) diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index cd74b6d07..1d65abaff 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -359,5 +359,12 @@ public interface LinphoneCall { * @return A player */ public LinphonePlayer getPlayer(); + + /** + * Create a new chat room for messaging from a call if not already existing, else return existing one + * @return LinphoneChatRoom where messaging can take place. + */ + public LinphoneChatRoom getChatRoom() ; + } diff --git a/java/common/org/linphone/core/LinphoneCallParams.java b/java/common/org/linphone/core/LinphoneCallParams.java index fa827faa2..f0be37ac4 100644 --- a/java/common/org/linphone/core/LinphoneCallParams.java +++ b/java/common/org/linphone/core/LinphoneCallParams.java @@ -158,4 +158,18 @@ public interface LinphoneCallParams { **/ boolean videoMulticastEnabled(); + /** + * Use to enable real time text following rfc4103. + * If enabled, outgoing calls put a m=text line in SDP offer . + * @param yesno if yes, subsequent outgoing calls will propose rtt + * + **/ + void enableRealTimeText(boolean yesno); + /** + * Use to get real time text following rfc4103. + * @returns returns true if call rtt is activated. + **/ + boolean realTimeTextEnabled(); + + } diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index b80c3a070..c022be40c 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -227,4 +227,12 @@ public interface LinphoneChatMessage { * Set the callbacks associated with the LinphoneChatMessage. */ void setListener(LinphoneChatMessage.LinphoneChatMessageListener listener); + /** + * Fulfill a chat message char by char. Message linked to a Real Time Text Call send char in realtime following RFC 4103/T.140 + * To commit a message, use #linphone_chat_room_send_message + * @param[in] character T.140 char + * @throw LinphoneCoreExeption . + */ + void putChar(long charater) throws LinphoneCoreException; + } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index f281b4bb6..9592e7269 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -144,4 +144,19 @@ public interface LinphoneChatRoom { * @param message */ void sendChatMessage(LinphoneChatMessage message); + + /** + * get Curent Call associated to this chatroom if any + * To commit a message, use #linphone_chat_room_send_message + * @returns LinphoneCall or NULL. + */ + public LinphoneCall getCall(); + /** + * When realtime text is enabled LinphoneCallParams.realTimeTextEnabled, LinphoneCoreListener.isComposingReceived is call every time a char is received from peer. + * At the end of remote typing a regular LinphoneChatMessage is received with committed data from LinphoneCoreListener.messageReceived . + * @returns RFC 4103/T.140 char + */ + long getChar(); + + } diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index de9e25364..af0875596 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -254,5 +254,9 @@ class LinphoneCallImpl implements LinphoneCall { public LinphonePlayer getPlayer() { return new LinphonePlayerImpl(getPlayer(nativePtr)); } + @Override + public LinphoneChatRoom getChatRoom() { + throw new RuntimeException("java binding not implemented yet"); + } } diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java index c4b356fa7..0bdbc56c6 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -171,4 +171,14 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { public boolean videoMulticastEnabled() { return videoMulticastEnabled(nativePtr); } + + @Override + public void enableRealTimeText(boolean yesno) { + throw new RuntimeException("java binding not implemented yet"); + } + + @Override + public boolean realTimeTextEnabled() { + throw new RuntimeException("java binding not implemented yet"); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 8665e4049..a55a8bd40 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -154,4 +154,8 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public void setListener(LinphoneChatMessageListener listener) { setListener(nativePtr, listener); } + @Override + public void putChar(long charater) throws LinphoneCoreException { + throw new RuntimeException("java binding not implemented yet"); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 7cf1fdbf7..067c3eca3 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -174,4 +174,12 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void sendChatMessage(LinphoneChatMessage message) { sendChatMessage(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr()); } + @Override + public LinphoneCall getCall() { + throw new RuntimeException("java binding not implemented yet"); + } + @Override + public long getChar() { + throw new RuntimeException("java binding not implemented yet"); + } } From 7f98e218f09997f0b3da1c0cc2221ed459a6203a Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 5 Aug 2015 16:52:35 +0200 Subject: [PATCH 05/23] Finished RTT JNI/Java API --- coreapi/linphonecore_jni.cc | 24 +++++++++++++++++++ .../linphone/core/LinphoneChatMessage.java | 2 +- .../org/linphone/core/LinphoneCallImpl.java | 4 +++- .../linphone/core/LinphoneCallParamsImpl.java | 6 +++-- .../core/LinphoneChatMessageImpl.java | 6 +++-- .../linphone/core/LinphoneChatRoomImpl.java | 9 +++++-- 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 509712753..b22cf34bf 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -6190,3 +6190,27 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_LinphoneCoreImpl_getVideoPreset const char *tmp = linphone_core_get_video_preset((LinphoneCore *)lc); return tmp ? env->NewStringUTF(tmp) : NULL; } + +extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getChatRoom(JNIEnv* env ,jobject thiz, jlong ptr) { + return (jlong) linphone_call_get_chat_room((LinphoneCall *) ptr); +} + +extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_enableRealTimeText(JNIEnv* env ,jobject thiz, jlong ptr, jboolean yesno) { + linphone_call_params_enable_realtime_text((LinphoneCallParams *)ptr, yesno); +} + +extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_realTimeTextEnabled(JNIEnv* env ,jobject thiz, jlong ptr) { + return linphone_call_params_realtime_text_enabled((LinphoneCallParams *)ptr); +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_putChar(JNIEnv* env ,jobject thiz, jlong ptr, jlong character) { + linphone_chat_message_put_char((LinphoneChatMessage *)ptr, character); +} + +extern "C" jobject Java_org_linphone_core_LinphoneChatRoomImpl_getCall(JNIEnv* env ,jobject thiz, jlong ptr) { + return getCall(env, linphone_chat_room_get_call((LinphoneChatRoom *)ptr)); +} + +extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_getChar(JNIEnv* env ,jobject thiz, jlong ptr) { + return linphone_chat_room_get_char((LinphoneChatRoom *)ptr); +} \ No newline at end of file diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index c022be40c..5f74293d8 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -233,6 +233,6 @@ public interface LinphoneChatMessage { * @param[in] character T.140 char * @throw LinphoneCoreExeption . */ - void putChar(long charater) throws LinphoneCoreException; + void putChar(long character) throws LinphoneCoreException; } diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java index af0875596..10b3575df 100644 --- a/java/impl/org/linphone/core/LinphoneCallImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallImpl.java @@ -254,9 +254,11 @@ class LinphoneCallImpl implements LinphoneCall { public LinphonePlayer getPlayer() { return new LinphonePlayerImpl(getPlayer(nativePtr)); } + + private native long getChatRoom(long nativePtr); @Override public LinphoneChatRoom getChatRoom() { - throw new RuntimeException("java binding not implemented yet"); + return new LinphoneChatRoomImpl(getChatRoom(nativePtr)); } } diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java index 0bdbc56c6..29e5d5c02 100644 --- a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java +++ b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java @@ -172,13 +172,15 @@ public class LinphoneCallParamsImpl implements LinphoneCallParams { return videoMulticastEnabled(nativePtr); } + private native void enableRealTimeText(long nativePtr, boolean yesno); @Override public void enableRealTimeText(boolean yesno) { - throw new RuntimeException("java binding not implemented yet"); + enableRealTimeText(nativePtr, yesno); } + private native boolean realTimeTextEnabled(long nativePtr); @Override public boolean realTimeTextEnabled() { - throw new RuntimeException("java binding not implemented yet"); + return realTimeTextEnabled(nativePtr); } } diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index a55a8bd40..54cd1ea64 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -154,8 +154,10 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public void setListener(LinphoneChatMessageListener listener) { setListener(nativePtr, listener); } + + private native void putChar(long nativePtr, long character); @Override - public void putChar(long charater) throws LinphoneCoreException { - throw new RuntimeException("java binding not implemented yet"); + public void putChar(long character) throws LinphoneCoreException { + putChar(nativePtr, character); } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 067c3eca3..b99426136 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -20,6 +20,7 @@ package org.linphone.core; import org.linphone.core.LinphoneChatMessage.State; import org.linphone.core.LinphoneChatMessage.StateListener; +import org.linphone.core.LinphoneCall; @SuppressWarnings("deprecation") class LinphoneChatRoomImpl implements LinphoneChatRoom { @@ -174,12 +175,16 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { public void sendChatMessage(LinphoneChatMessage message) { sendChatMessage(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr()); } + + private native Object getCall(long nativePtr); @Override public LinphoneCall getCall() { - throw new RuntimeException("java binding not implemented yet"); + return (LinphoneCall) getCall(nativePtr); } + + private native long getChar(long nativePtr); @Override public long getChar() { - throw new RuntimeException("java binding not implemented yet"); + return getChar(nativePtr); } } From 15b6353e308964638b0c68dc92db9252328c47b1 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 15 Sep 2015 17:13:30 +0200 Subject: [PATCH 06/23] Started rework of streams' indexes for RTT --- coreapi/bellesip_sal/sal_sdp.c | 2 + coreapi/linphonecall.c | 388 ++++++++++++++++++++++++--------- coreapi/linphonecore.c | 101 ++++++++- coreapi/linphonecore.h | 32 +++ coreapi/misc.c | 6 +- coreapi/private.h | 23 +- coreapi/sal.c | 5 +- include/sal/sal.h | 1 + mediastreamer2 | 2 +- oRTP | 2 +- 10 files changed, 439 insertions(+), 123 deletions(-) diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 9313a3d43..ec84ccfe4 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -739,6 +739,8 @@ static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, stream->type=SalAudio; } else if ( strcasecmp ( "video", mtype ) == 0 ) { stream->type=SalVideo; + } else if ( strcasecmp ( "text", mtype ) == 0 ) { + stream->type=SalText; } else { stream->type=SalOther; strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 ); diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 0f3602fb8..f1a284d24 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -118,6 +118,11 @@ static bool_t linphone_call_all_streams_encrypted(const LinphoneCall *call) { if (media_stream_secured((MediaStream *)call->videostream)) number_of_encrypted_stream++; } + if (call->textstream && media_stream_get_state((MediaStream *)call->textstream) == MSStreamStarted) { + number_of_active_stream++; + if (media_stream_secured((MediaStream *)call->textstream)) + number_of_encrypted_stream++; + } } return number_of_active_stream>0 && number_of_active_stream==number_of_encrypted_stream; } @@ -401,20 +406,22 @@ static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, SalSt return l; } -static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){ +static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc, const StunCandidate *tc){ int 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; + strcpy(md->streams[i].rtp_addr,ac->addr); + md->streams[i].rtp_port=ac->port; 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); } - } - if ((md->streams[i].type == SalVideo) && (vc->port != 0)) { - strcpy(md->streams[1].rtp_addr,vc->addr); - md->streams[1].rtp_port=vc->port; + } else if ((md->streams[i].type == SalVideo) && (vc->port != 0)) { + strcpy(md->streams[i].rtp_addr,vc->addr); + md->streams[i].rtp_port=vc->port; + } else if ((md->streams[i].type == SalText) && (tc->port != 0)) { + strcpy(md->streams[i].rtp_addr,tc->addr); + md->streams[i].rtp_port=tc->port; } } } @@ -594,7 +601,7 @@ static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDes break; } - for (i=0; i<2; ++i){ + for (i=0; inb_streams; ++i){ SalStreamDescription *sd = &md->streams[i]; sd->dir = SalStreamSendOnly; if (sd->type == SalVideo){ @@ -617,16 +624,15 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { LinphoneCallParams *params = call->params; LinphoneCore *lc = call->core; - /*multicast is only set in case of outgoing call*/ if (call->dir == LinphoneCallOutgoing && linphone_call_params_audio_multicast_enabled(params)) { - md->streams[0].ttl=linphone_core_get_audio_multicast_ttl(lc); - md->streams[0].multicast_role = SalMulticastSender; + md->streams[call->main_audio_stream_index].ttl=linphone_core_get_audio_multicast_ttl(lc); + md->streams[call->main_audio_stream_index].multicast_role = SalMulticastSender; } if (call->dir == LinphoneCallOutgoing && linphone_call_params_video_multicast_enabled(params)) { - md->streams[1].ttl=linphone_core_get_video_multicast_ttl(lc); - md->streams[1].multicast_role = SalMulticastSender; + md->streams[call->main_video_stream_index].ttl=linphone_core_get_video_multicast_ttl(lc); + md->streams[call->main_video_stream_index].multicast_role = SalMulticastSender; } subject=linphone_call_params_get_session_name(params); @@ -655,28 +661,28 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { else md->bandwidth=linphone_core_get_download_bandwidth(lc); /*set audio capabilities */ - strncpy(md->streams[0].rtp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtp_addr)); - strncpy(md->streams[0].rtcp_addr,linphone_call_get_public_ip_for_stream(call,0),sizeof(md->streams[0].rtcp_addr)); - 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=get_proto_from_call_params(params); - md->streams[0].dir=get_audio_dir_from_call_params(params); - md->streams[0].type=SalAudio; + strncpy(md->streams[call->main_audio_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtp_addr)); + strncpy(md->streams[call->main_audio_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_audio_stream_index),sizeof(md->streams[call->main_audio_stream_index].rtcp_addr)); + strncpy(md->streams[call->main_audio_stream_index].name,"Audio",sizeof(md->streams[call->main_audio_stream_index].name)-1); + md->streams[call->main_audio_stream_index].rtp_port=call->media_ports[call->main_audio_stream_index].rtp_port; + md->streams[call->main_audio_stream_index].rtcp_port=call->media_ports[call->main_audio_stream_index].rtcp_port; + md->streams[call->main_audio_stream_index].proto=get_proto_from_call_params(params); + md->streams[call->main_audio_stream_index].dir=get_audio_dir_from_call_params(params); + md->streams[call->main_audio_stream_index].type=SalAudio; if (params->down_ptime) - md->streams[0].ptime=params->down_ptime; + md->streams[call->main_audio_stream_index].ptime=params->down_ptime; else - md->streams[0].ptime=linphone_core_get_download_ptime(lc); + md->streams[call->main_audio_stream_index].ptime=linphone_core_get_download_ptime(lc); codec_hints.bandwidth_limit=params->audio_bw; codec_hints.max_codecs=-1; - codec_hints.previously_used=old_md ? old_md->streams[0].already_assigned_payloads : NULL; + codec_hints.previously_used=old_md ? old_md->streams[call->main_audio_stream_index].already_assigned_payloads : NULL; l=make_codec_list(lc, &codec_hints, SalAudio, lc->codecs_conf.audio_codecs); - md->streams[0].max_rate=get_max_codec_sample_rate(l); - md->streams[0].payloads=l; + md->streams[call->main_audio_stream_index].max_rate=get_max_codec_sample_rate(l); + md->streams[call->main_audio_stream_index].payloads=l; if (call->audiostream && call->audiostream->ms.sessions.rtp_session) { char* me = linphone_address_as_string_uri_only(call->me); - md->streams[0].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session); - strncpy(md->streams[0].rtcp_cname,me,sizeof(md->streams[0].rtcp_cname)); + md->streams[call->main_audio_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->audiostream->ms.sessions.rtp_session); + strncpy(md->streams[call->main_audio_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_audio_stream_index].rtcp_cname)); ms_free(me); } else @@ -684,23 +690,23 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { nb_active_streams++; if (params->has_video && (!params->internal_call_update || !call->current_params->video_declined)){ - strncpy(md->streams[1].rtp_addr,linphone_call_get_public_ip_for_stream(call,1),sizeof(md->streams[1].rtp_addr)); - strncpy(md->streams[1].rtcp_addr,linphone_call_get_public_ip_for_stream(call,1),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; - md->streams[1].dir=get_video_dir_from_call_params(params); - md->streams[1].type=SalVideo; + strncpy(md->streams[call->main_video_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtp_addr)); + strncpy(md->streams[call->main_video_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_video_stream_index),sizeof(md->streams[call->main_video_stream_index].rtcp_addr)); + strncpy(md->streams[call->main_video_stream_index].name,"Video",sizeof(md->streams[call->main_video_stream_index].name)-1); + md->streams[call->main_video_stream_index].rtp_port=call->media_ports[call->main_video_stream_index].rtp_port; + md->streams[call->main_video_stream_index].rtcp_port=call->media_ports[call->main_video_stream_index].rtcp_port; + md->streams[call->main_video_stream_index].proto=md->streams[call->main_video_stream_index].proto; + md->streams[call->main_video_stream_index].dir=get_video_dir_from_call_params(params); + md->streams[call->main_video_stream_index].type=SalVideo; codec_hints.bandwidth_limit=0; codec_hints.max_codecs=-1; - codec_hints.previously_used=old_md ? old_md->streams[1].already_assigned_payloads : NULL; + codec_hints.previously_used=old_md ? old_md->streams[call->main_video_stream_index].already_assigned_payloads : NULL; l=make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs); - md->streams[1].payloads=l; + md->streams[call->main_video_stream_index].payloads=l; if (call->videostream && call->videostream->ms.sessions.rtp_session) { char* me = linphone_address_as_string_uri_only(call->me); - md->streams[1].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session); - strncpy(md->streams[1].rtcp_cname,me,sizeof(md->streams[1].rtcp_cname)); + md->streams[call->main_video_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->videostream->ms.sessions.rtp_session); + strncpy(md->streams[call->main_video_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_video_stream_index].rtcp_cname)); ms_free(me); } else @@ -709,6 +715,33 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { } else { ms_message("Don't put video stream on local offer for call [%p]",call); } + + if (params->realtimetext_enabled) { + strncpy(md->streams[call->main_text_stream_index].rtp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtp_addr)); + strncpy(md->streams[call->main_text_stream_index].rtcp_addr,linphone_call_get_public_ip_for_stream(call,call->main_text_stream_index),sizeof(md->streams[call->main_text_stream_index].rtcp_addr)); + strncpy(md->streams[call->main_text_stream_index].name,"Text",sizeof(md->streams[call->main_text_stream_index].name)-1); + md->streams[call->main_text_stream_index].rtp_port=call->media_ports[call->main_text_stream_index].rtp_port; + md->streams[call->main_text_stream_index].rtcp_port=call->media_ports[call->main_text_stream_index].rtcp_port; + md->streams[call->main_text_stream_index].proto=md->streams[call->main_text_stream_index].proto; + md->streams[call->main_text_stream_index].dir=SalStreamSendRecv; + md->streams[call->main_text_stream_index].type=SalText; + codec_hints.bandwidth_limit=0; + codec_hints.max_codecs=-1; + codec_hints.previously_used=old_md ? old_md->streams[call->main_text_stream_index].already_assigned_payloads : NULL; + l=make_codec_list(lc, &codec_hints, SalText, lc->codecs_conf.text_codecs); + md->streams[call->main_text_stream_index].payloads=l; + if (call->textstream && call->textstream->ms.sessions.rtp_session) { + char* me = linphone_address_as_string_uri_only(call->me); + md->streams[call->main_text_stream_index].rtp_ssrc=rtp_session_get_send_ssrc(call->textstream->ms.sessions.rtp_session); + strncpy(md->streams[call->main_text_stream_index].rtcp_cname,me,sizeof(md->streams[call->main_text_stream_index].rtcp_cname)); + ms_free(me); + } + else + ms_warning("Cannot get text local ssrc for call [%p]",call); + nb_active_streams++; + } else { + ms_message("Don't put text stream on local offer for call [%p]",call); + } if (md->nb_streams < nb_active_streams) md->nb_streams = nb_active_streams; @@ -731,7 +764,7 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { setup_rtcp_fb(call, md); setup_rtcp_xr(call, md); - update_media_description_from_stun(md,&call->ac,&call->vc); + update_media_description_from_stun(md, &call->ac, &call->vc, &call->tc); call->localdesc=md; linphone_call_update_local_media_description_from_ice_or_upnp(call); linphone_address_destroy(addr); @@ -838,13 +871,17 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, linphone_address_ref(call->me); linphone_core_get_audio_port_range(call->core, &min_port, &max_port); - port_config_set(call,0,min_port,max_port); + port_config_set(call,call->main_audio_stream_index,min_port,max_port); linphone_core_get_video_port_range(call->core, &min_port, &max_port); - port_config_set(call,1,min_port,max_port); + port_config_set(call,call->main_video_stream_index,min_port,max_port); + + linphone_core_get_text_port_range(call->core, &min_port, &max_port); + port_config_set(call,call->main_text_stream_index,min_port,max_port); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO); + linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_TEXT], LINPHONE_CALL_STATS_TEXT); } void linphone_call_init_stats(LinphoneCallStats *stats, int type) { @@ -961,21 +998,25 @@ BELLE_SIP_INSTANCIATE_VPTR(LinphoneCall, belle_sip_object_t, ); void linphone_call_fill_media_multicast_addr(LinphoneCall *call) { if (linphone_call_params_audio_multicast_enabled(call->params)){ - strncpy(call->media_ports[0].multicast_ip, - linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[0].multicast_ip)); + strncpy(call->media_ports[call->main_audio_stream_index].multicast_ip, + linphone_core_get_audio_multicast_addr(call->core), sizeof(call->media_ports[call->main_audio_stream_index].multicast_ip)); } else - call->media_ports[0].multicast_ip[0]='\0'; + call->media_ports[call->main_audio_stream_index].multicast_ip[0]='\0'; if (linphone_call_params_video_multicast_enabled(call->params)){ - strncpy(call->media_ports[1].multicast_ip, - linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[1].multicast_ip)); + strncpy(call->media_ports[call->main_video_stream_index].multicast_ip, + linphone_core_get_video_multicast_addr(call->core), sizeof(call->media_ports[call->main_video_stream_index].multicast_ip)); } else - call->media_ports[1].multicast_ip[0]='\0'; + call->media_ports[call->main_video_stream_index].multicast_ip[0]='\0'; } LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg){ LinphoneCall *call = belle_sip_object_new(LinphoneCall); - + + call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; + call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; + call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT; + call->dir=LinphoneCallOutgoing; call->core=lc; linphone_call_outgoing_select_ip_version(call,to,cfg); @@ -1045,6 +1086,10 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro SalMediaDescription *md; LinphoneFirewallPolicy fpol; int i; + + call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; + call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; + call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); @@ -1102,6 +1147,16 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro if (md->streams[i].rtp_addr[0]!='\0' && ms_is_multicast(md->streams[i].rtp_addr)){ md->streams[i].multicast_role = SalMulticastReceiver; strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip)); + + if (sal_stream_description_active(&md->streams[i])) { + if (md->streams[i].type == SalAudio) { + call->main_audio_stream_index = i; + } else if (md->streams[i].type == SalVideo) { + call->main_video_stream_index = i; + } else if (md->streams[i].type == SalText) { + call->main_text_stream_index = i; + } + } } } } @@ -1163,12 +1218,14 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro */ void linphone_call_free_media_resources(LinphoneCall *call){ linphone_call_stop_media_streams(call); - ms_media_stream_sessions_uninit(&call->sessions[0]); - ms_media_stream_sessions_uninit(&call->sessions[1]); + ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]); + ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]); + ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]); linphone_call_delete_upnp_session(call); linphone_call_delete_ice_session(call); - linphone_call_stats_uninit(&call->stats[0]); - linphone_call_stats_uninit(&call->stats[1]); + linphone_call_stats_uninit(&call->stats[call->main_audio_stream_index]); + linphone_call_stats_uninit(&call->stats[call->main_video_stream_index]); + linphone_call_stats_uninit(&call->stats[call->main_text_stream_index]); } /* @@ -1458,7 +1515,7 @@ static unsigned int linphone_call_get_n_active_streams(const LinphoneCall *call) md = sal_call_get_remote_media_description(call->op); if (!md) return 0; - return sal_media_description_nb_active_streams_of_type(md, SalAudio) + sal_media_description_nb_active_streams_of_type(md, SalVideo); + return sal_media_description_nb_active_streams_of_type(md, SalAudio) + sal_media_description_nb_active_streams_of_type(md, SalVideo) + sal_media_description_nb_active_streams_of_type(md, SalText); } /** @@ -1535,6 +1592,8 @@ const LinphoneCallParams * linphone_call_get_current_params(LinphoneCall *call){ call->current_params->video_multicast_enabled = ms_is_multicast(rtp_addr); } else call->current_params->video_multicast_enabled = FALSE; + + sd=sal_media_description_find_best_stream(md,SalText); } return call->current_params; @@ -1558,6 +1617,7 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ 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); + unsigned int nb_text_streams = sal_media_description_nb_active_streams_of_type(md, SalText); for (i = 0; i < nb_video_streams; i++) { sd = sal_media_description_get_active_stream_of_type(md, SalVideo, i); @@ -1568,6 +1628,10 @@ const LinphoneCallParams * linphone_call_get_remote_params(LinphoneCall *call){ sd = sal_media_description_get_active_stream_of_type(md, SalAudio, i); if (sal_stream_description_has_srtp(sd) == TRUE) cp->media_encryption = LinphoneMediaEncryptionSRTP; } + for (i = 0; i < nb_text_streams; i++) { + sd = sal_media_description_get_active_stream_of_type(md, SalText, i); + 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)){ cp->low_bandwidth=TRUE; @@ -1926,8 +1990,9 @@ int linphone_call_prepare_ice(LinphoneCall *call, bool_t incoming_offer){ has_video=linphone_core_video_enabled(call->core) && linphone_core_media_description_contains_video_stream(remote); }else has_video=call->params->has_video; - _linphone_call_prepare_ice_for_stream(call,0,TRUE); - if (has_video) _linphone_call_prepare_ice_for_stream(call,1,TRUE); + _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,TRUE); + if (has_video) _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,TRUE); + if (call->params->realtimetext_enabled) _linphone_call_prepare_ice_for_stream(call,call->main_text_stream_index,TRUE); /*start ICE gathering*/ if (incoming_offer) linphone_call_update_ice_from_remote_media_description(call,remote); /*this may delete the ice session*/ @@ -2024,7 +2089,7 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); if (call->audiostream != NULL) return; - if (call->sessions[0].rtp_session==NULL){ + if (call->sessions[call->main_audio_stream_index].rtp_session==NULL){ SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalAudio); SalMediaDescription *remotedesc=NULL; SalStreamDescription *stream_desc = NULL; @@ -2032,24 +2097,24 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ if (remotedesc) stream_desc = sal_media_description_find_best_stream(remotedesc, SalAudio); - call->audiostream=audiostream=audio_stream_new2(linphone_call_get_bind_ip_for_stream(call,0), - multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[0].rtp_port, - multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[0].rtcp_port); + call->audiostream=audiostream=audio_stream_new2(linphone_call_get_bind_ip_for_stream(call,call->main_audio_stream_index), + multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_audio_stream_index].rtp_port, + multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_audio_stream_index].rtcp_port); if (multicast_role == SalMulticastReceiver) - linphone_call_join_multicast_group(call, 0, &audiostream->ms); + linphone_call_join_multicast_group(call, call->main_audio_stream_index, &audiostream->ms); rtp_session_enable_network_simulation(call->audiostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); cname = linphone_address_as_string_uri_only(call->me); audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool); ms_free(cname); rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); setup_dtls_params(call, &audiostream->ms); - media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[0]); + media_stream_reclaim_sessions(&audiostream->ms, &call->sessions[call->main_audio_stream_index]); }else{ - call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]); + call->audiostream=audio_stream_new_with_sessions(&call->sessions[call->main_audio_stream_index]); } audiostream=call->audiostream; - if (call->media_ports[0].rtp_port==-1){ - port_config_set_random_choosed(call,0,audiostream->ms.sessions.rtp_session); + if (call->media_ports[call->main_audio_stream_index].rtp_port==-1){ + port_config_set_random_choosed(call,call->main_audio_stream_index,audiostream->ms.sessions.rtp_session); } dscp=linphone_core_get_audio_dscp(lc); if (dscp!=-1) @@ -2098,17 +2163,17 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ rtp_session_get_transports(audiostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port)); + meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[call->main_audio_stream_index].rtp_port)); } if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port)); + meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[call->main_audio_stream_index].rtcp_port)); } } call->audiostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq); - _linphone_call_prepare_ice_for_stream(call,0,FALSE); + _linphone_call_prepare_ice_for_stream(call,call->main_audio_stream_index,FALSE); } void linphone_call_init_video_stream(LinphoneCall *call){ @@ -2125,7 +2190,7 @@ void linphone_call_init_video_stream(LinphoneCall *call){ int dscp=linphone_core_get_video_dscp(lc); const char *display_filter=linphone_core_get_video_display_filter(lc); - if (call->sessions[1].rtp_session==NULL){ + if (call->sessions[call->main_video_stream_index].rtp_session==NULL){ SalMulticastRole multicast_role = linphone_call_get_multicast_role(call,SalVideo); SalMediaDescription *remotedesc=NULL; SalStreamDescription *stream_desc = NULL; @@ -2133,24 +2198,24 @@ void linphone_call_init_video_stream(LinphoneCall *call){ if (remotedesc) stream_desc = sal_media_description_find_best_stream(remotedesc, SalVideo); - call->videostream=video_stream_new2(linphone_call_get_bind_ip_for_stream(call,1), - multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[1].rtp_port, - multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[1].rtcp_port); + call->videostream=video_stream_new2(linphone_call_get_bind_ip_for_stream(call,call->main_video_stream_index), + multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_video_stream_index].rtp_port, + multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_video_stream_index].rtcp_port); if (multicast_role == SalMulticastReceiver) - linphone_call_join_multicast_group(call, 1, &call->videostream->ms); + linphone_call_join_multicast_group(call, call->main_video_stream_index, &call->videostream->ms); rtp_session_enable_network_simulation(call->videostream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); cname = linphone_address_as_string_uri_only(call->me); video_stream_set_rtcp_information(call->videostream, cname, rtcp_tool); ms_free(cname); rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); setup_dtls_params(call, &call->videostream->ms); - media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[1]); + media_stream_reclaim_sessions(&call->videostream->ms, &call->sessions[call->main_video_stream_index]); }else{ - call->videostream=video_stream_new_with_sessions(&call->sessions[1]); + call->videostream=video_stream_new_with_sessions(&call->sessions[call->main_video_stream_index]); } - if (call->media_ports[1].rtp_port==-1){ - port_config_set_random_choosed(call,1,call->videostream->ms.sessions.rtp_session); + if (call->media_ports[call->main_video_stream_index].rtp_port==-1){ + port_config_set_random_choosed(call,call->main_video_stream_index,call->videostream->ms.sessions.rtp_session); } if (dscp!=-1) video_stream_set_dscp(call->videostream,dscp); @@ -2167,15 +2232,15 @@ void linphone_call_init_video_stream(LinphoneCall *call){ rtp_session_get_transports(call->videostream->ms.sessions.rtp_session,&meta_rtp,&meta_rtcp); if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port)); + meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[call->main_video_stream_index].rtp_port)); } if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { - meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port)); + meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[call->main_video_stream_index].rtcp_port)); } } call->videostream_app_evq = ortp_ev_queue_new(); rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq); - _linphone_call_prepare_ice_for_stream(call,1,FALSE); + _linphone_call_prepare_ice_for_stream(call,call->main_video_stream_index,FALSE); #ifdef TEST_EXT_RENDERER video_stream_set_render_callback(call->videostream,rendercb,NULL); #endif @@ -2185,9 +2250,61 @@ void linphone_call_init_video_stream(LinphoneCall *call){ #endif } +void linphone_call_init_text_stream(LinphoneCall *call){ + TextStream *textstream; + LinphoneCore *lc=call->core; + char* cname; + + if (call->textstream != NULL) return; + if (call->sessions[call->main_text_stream_index].rtp_session == NULL) { + SalMulticastRole multicast_role = linphone_call_get_multicast_role(call, SalText); + SalMediaDescription *remotedesc = NULL; + SalStreamDescription *stream_desc = NULL; + if (call->op) remotedesc = sal_call_get_remote_media_description(call->op); + if (remotedesc) stream_desc = sal_media_description_find_best_stream(remotedesc, SalText); + + call->textstream = textstream = text_stream_new2(linphone_call_get_bind_ip_for_stream(call,call->main_text_stream_index), + multicast_role == SalMulticastReceiver ? stream_desc->rtp_port : call->media_ports[call->main_text_stream_index].rtp_port, + multicast_role == SalMulticastReceiver ? 0 /*disabled for now*/ : call->media_ports[call->main_text_stream_index].rtcp_port); + if (multicast_role == SalMulticastReceiver) + linphone_call_join_multicast_group(call, call->main_text_stream_index, &textstream->ms); + rtp_session_enable_network_simulation(call->textstream->ms.sessions.rtp_session, &lc->net_conf.netsim_params); + cname = linphone_address_as_string_uri_only(call->me); + ms_free(cname); + rtp_session_set_symmetric_rtp(textstream->ms.sessions.rtp_session,linphone_core_symmetric_rtp_enabled(lc)); + setup_dtls_params(call, &textstream->ms); + media_stream_reclaim_sessions(&textstream->ms, &call->sessions[call->main_text_stream_index]); + } else { + call->textstream = text_stream_new_with_sessions(&call->sessions[call->main_text_stream_index]); + } + textstream = call->textstream; + if (call->media_ports[call->main_text_stream_index].rtp_port == -1) { + port_config_set_random_choosed(call, call->main_text_stream_index, textstream->ms.sessions.rtp_session); + } + + if (lc->rtptf){ + RtpTransport *meta_rtp; + RtpTransport *meta_rtcp; + + rtp_session_get_transports(textstream->ms.sessions.rtp_session, &meta_rtp, &meta_rtcp); + if (meta_rtp_transport_get_endpoint(meta_rtp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtp,lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[call->main_text_stream_index].rtp_port)); + } + if (meta_rtp_transport_get_endpoint(meta_rtcp) == NULL) { + meta_rtp_transport_set_endpoint(meta_rtcp,lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[call->main_text_stream_index].rtcp_port)); + } + } + + call->textstream_app_evq = ortp_ev_queue_new(); + rtp_session_register_event_queue(textstream->ms.sessions.rtp_session, call->textstream_app_evq); + + _linphone_call_prepare_ice_for_stream(call, call->main_text_stream_index, FALSE); +} + void linphone_call_init_media_streams(LinphoneCall *call){ linphone_call_init_audio_stream(call); linphone_call_init_video_stream(call); + linphone_call_init_text_stream(call); } @@ -2364,6 +2481,8 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m bw=get_ideal_audio_bw(call,md,desc); else if (desc->type==SalVideo) bw=get_video_bw(call,md,desc); + //else if (desc->type== SalText) + for(elem=desc->payloads;elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; @@ -2452,7 +2571,7 @@ static void configure_rtp_session_for_rtcp_fb(LinphoneCall *call, const SalStrea } static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *call, SalStreamType type) { - RtpSession *session; + RtpSession *session = NULL; const OrtpRtcpXrConfiguration *localconfig; const OrtpRtcpXrConfiguration *remoteconfig; OrtpRtcpXrConfiguration currentconfig; @@ -2480,8 +2599,10 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca } if (type == SalAudio) { session = call->audiostream->ms.sessions.rtp_session; - } else { + } else if (type == SalVideo) { session = call->videostream->ms.sessions.rtp_session; + } else if (type == SalText) { + session = call->textstream->ms.sessions.rtp_session; } rtp_session_configure_rtcp_xr(session, ¤tconfig); } @@ -2517,6 +2638,10 @@ void static start_dtls_on_all_streams(LinphoneCall *call) { ,sal_media_description_find_best_stream(result_desc,SalVideo) ,sal_media_description_find_best_stream(remote_desc,SalVideo)); #endif + if (call->textstream && (media_stream_get_state((const MediaStream *)call->textstream) == MSStreamStarted))/*dtls must start at the end of ice*/ + start_dtls(&call->textstream->ms.sessions + ,sal_media_description_find_best_stream(result_desc,SalText) + ,sal_media_description_find_best_stream(remote_desc,SalText)); return; } @@ -2552,6 +2677,10 @@ void static set_dtls_fingerprint_on_all_streams(LinphoneCall *call) { ,sal_media_description_find_best_stream(result_desc,SalVideo) ,sal_media_description_find_best_stream(remote_desc,SalVideo)); #endif + if (call->textstream && (media_stream_get_state((const MediaStream *)call->textstream) == MSStreamStarted))/*dtls must start at the end of ice*/ + set_dtls_fingerprint(&call->textstream->ms.sessions + ,sal_media_description_find_best_stream(result_desc,SalText) + ,sal_media_description_find_best_stream(remote_desc,SalText)); return; } @@ -2906,6 +3035,10 @@ static void linphone_call_start_video_stream(LinphoneCall *call, LinphoneCallSta #endif } +static void linphone_call_start_text_stream(LinphoneCall *call) { + //TODO textstream +} + static void setZrtpCryptoTypesParameters(MSZrtpParams *params, LinphoneCore *lc) { int i; @@ -2986,6 +3119,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex call->current_params->audio_codec = NULL; call->current_params->video_codec = NULL; + call->current_params->text_codec = NULL; if ((call->audiostream == NULL) && (call->videostream == NULL)) { ms_fatal("start_media_stream() called without prior init !"); @@ -3030,6 +3164,10 @@ void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState nex } #endif } + + if (call->params->realtimetext_enabled) { + linphone_call_start_text_stream(call); + } set_dtls_fingerprint_on_all_streams(call); @@ -3077,6 +3215,13 @@ void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescript 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)){ } + + local_st_desc = sal_media_description_find_secure_stream_of_type(call->localdesc, SalText); + old_stream = sal_media_description_find_secure_stream_of_type(old_md, SalText); + new_stream = sal_media_description_find_secure_stream_of_type(new_md, SalText); + if (call->textstream && local_st_desc && old_stream && new_stream && + update_stream_crypto_params(call,local_st_desc,old_stream,new_stream,&call->textstream->ms)){ + } start_dtls_on_all_streams(call); @@ -3104,8 +3249,10 @@ void linphone_call_delete_ice_session(LinphoneCall *call){ call->ice_session = NULL; if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = NULL; if (call->videostream != NULL) call->videostream->ms.ice_check_list = NULL; + if (call->textstream != NULL) call->textstream->ms.ice_check_list = NULL; call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated; call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated; + call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateNotActivated; } } @@ -3143,7 +3290,7 @@ static void update_rtp_stats(LinphoneCall *call, int stream_index) { static void linphone_call_stop_audio_stream(LinphoneCall *call) { if (call->audiostream!=NULL) { linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_AUDIO); - media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]); + media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[call->main_audio_stream_index]); if (call->audiostream->ec){ const char *state_str=NULL; @@ -3159,8 +3306,8 @@ static void linphone_call_stop_audio_stream(LinphoneCall *call) { linphone_call_remove_from_conf(call); } audio_stream_stop(call->audiostream); - update_rtp_stats(call, 0); - rtp_session_unregister_event_queue(call->sessions[0].rtp_session, call->audiostream_app_evq); + update_rtp_stats(call, call->main_audio_stream_index); + rtp_session_unregister_event_queue(call->sessions[call->main_audio_stream_index].rtp_session, call->audiostream_app_evq); ortp_ev_queue_flush(call->audiostream_app_evq); ortp_ev_queue_destroy(call->audiostream_app_evq); call->audiostream_app_evq=NULL; @@ -3173,12 +3320,12 @@ static void linphone_call_stop_video_stream(LinphoneCall *call) { #ifdef VIDEO_ENABLED if (call->videostream!=NULL){ linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_VIDEO); - media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]); + media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[call->main_video_stream_index]); linphone_call_log_fill_stats(call->log,(MediaStream*)call->videostream); video_stream_stop(call->videostream); call->videostream=NULL; - update_rtp_stats(call, 1); - rtp_session_unregister_event_queue(call->sessions[1].rtp_session, call->videostream_app_evq); + update_rtp_stats(call, call->main_video_stream_index); + rtp_session_unregister_event_queue(call->sessions[call->main_video_stream_index].rtp_session, call->videostream_app_evq); ortp_ev_queue_flush(call->videostream_app_evq); ortp_ev_queue_destroy(call->videostream_app_evq); call->videostream_app_evq=NULL; @@ -3192,12 +3339,29 @@ static void unset_rtp_profile(LinphoneCall *call, int i){ rtp_session_set_profile(call->sessions[i].rtp_session,&av_profile); } +static void linphone_call_stop_text_stream(LinphoneCall *call) { + if (call->textstream != NULL) { + linphone_reporting_update_media_info(call, LINPHONE_CALL_STATS_TEXT); + media_stream_reclaim_sessions(&call->textstream->ms, &call->sessions[call->main_text_stream_index]); + linphone_call_log_fill_stats(call->log, (MediaStream*)call->textstream); + text_stream_stop(call->textstream); + call->textstream = NULL; + update_rtp_stats(call, call->main_text_stream_index); + rtp_session_unregister_event_queue(call->sessions[call->main_text_stream_index].rtp_session, call->textstream_app_evq); + ortp_ev_queue_flush(call->textstream_app_evq); + ortp_ev_queue_destroy(call->textstream_app_evq); + call->textstream_app_evq = NULL; + call->current_params->text_codec = NULL; + } +} + void linphone_call_stop_media_streams(LinphoneCall *call){ if (call->audiostream || call->videostream) { if (call->audiostream && call->videostream) audio_stream_unlink_video(call->audiostream, call->videostream); linphone_call_stop_audio_stream(call); linphone_call_stop_video_stream(call); + linphone_call_stop_text_stream(call); if (call->core->msevq != NULL) { ms_event_queue_skip(call->core->msevq); @@ -3417,7 +3581,7 @@ static bool_t ice_in_progress(LinphoneCallStats *stats){ **/ bool_t linphone_call_media_in_progress(LinphoneCall *call){ bool_t ret=FALSE; - if (ice_in_progress(&call->stats[LINPHONE_CALL_STATS_AUDIO]) || ice_in_progress(&call->stats[LINPHONE_CALL_STATS_VIDEO])) + if (ice_in_progress(&call->stats[LINPHONE_CALL_STATS_AUDIO]) || ice_in_progress(&call->stats[LINPHONE_CALL_STATS_VIDEO]) || ice_in_progress(&call->stats[LINPHONE_CALL_STATS_TEXT])) ret=TRUE; /*TODO: could check zrtp state, upnp state*/ return ret; @@ -3682,8 +3846,8 @@ static void change_ice_media_destinations(LinphoneCall *call) { int rtcp_port; bool_t result; - if (call->audiostream && ice_session_check_list(call->ice_session, 0)) { - result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 0), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + if (call->audiostream && ice_session_check_list(call->ice_session, call->main_audio_stream_index)) { + result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, call->main_audio_stream_index), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); if (result == TRUE) { ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port); rtp_session_set_symmetric_rtp(call->audiostream->ms.sessions.rtp_session, FALSE); @@ -3691,8 +3855,8 @@ static void change_ice_media_destinations(LinphoneCall *call) { } } #ifdef VIDEO_ENABLED - if (call->videostream && ice_session_check_list(call->ice_session, 1)) { - result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, 1), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + if (call->videostream && ice_session_check_list(call->ice_session, call->main_video_stream_index)) { + result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, call->main_video_stream_index), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); if (result == TRUE) { ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port); rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session, FALSE); @@ -3700,6 +3864,14 @@ static void change_ice_media_destinations(LinphoneCall *call) { } } #endif + if (call->textstream && ice_session_check_list(call->ice_session, call->main_text_stream_index)) { + result = ice_check_list_selected_valid_remote_candidate(ice_session_check_list(call->ice_session, call->main_text_stream_index), &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port); + if (result == TRUE) { + ms_message("Change text stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, rtp_port, rtcp_addr, rtcp_port); + rtp_session_set_symmetric_rtp(call->textstream->ms.sessions.rtp_session, FALSE); + rtp_session_set_remote_addr_full(call->textstream->ms.sessions.rtp_session, rtp_addr, rtp_port, rtcp_addr, rtcp_port); + } + } } static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){ @@ -3846,7 +4018,7 @@ void linphone_call_notify_stats_updated(LinphoneCall *call, int stream_index){ } void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){ - MediaStream *ms=stream_index==0 ? (MediaStream *)call->audiostream : (MediaStream *)call->videostream; /*assumption to remove*/ + MediaStream *ms = stream_index == call->main_audio_stream_index ? (MediaStream *)call->audiostream : (stream_index == call->main_video_stream_index ? (MediaStream *)call->videostream : (MediaStream *)call->textstream); OrtpEvQueue *evq; OrtpEvent *ev; @@ -3863,13 +4035,16 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){ video_stream_iterate((VideoStream*)ms); #endif break; + case MSText: + text_stream_iterate((TextStream*)ms); + break; default: ms_error("linphone_call_handle_stream_events(): unsupported stream type."); return; break; } /*yes the event queue has to be taken at each iteration, because ice events may perform operations re-creating the streams*/ - while ((evq=stream_index==0 ? call->audiostream_app_evq : call->videostream_app_evq) && (NULL != (ev=ortp_ev_queue_get(evq)))){ + while ((evq = stream_index == call->main_audio_stream_index ? call->audiostream_app_evq : (stream_index == call->main_video_stream_index ? call->videostream_app_evq : call->textstream_app_evq)) && (NULL != (ev=ortp_ev_queue_get(evq)))){ OrtpEventType evt=ortp_event_get_type(ev); OrtpEventData *evd=ortp_event_get_data(ev); @@ -3894,6 +4069,8 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){ handle_ice_events(call, ev); } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){ linphone_core_dtmf_received(call,evd->info.telephone_event); + } else if (evt == ORTP_EVENT_RTT_CHARACTER_RECEIVED) { + //TODO } ortp_event_destroy(ev); } @@ -3932,8 +4109,9 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse linphone_upnp_call_process(call); #endif //BUILD_UPNP - linphone_call_handle_stream_events(call,0); - linphone_call_handle_stream_events(call,1); + linphone_call_handle_stream_events(call, call->main_audio_stream_index); + linphone_call_handle_stream_events(call, call->main_video_stream_index); + linphone_call_handle_stream_events(call, call->main_text_stream_index); if (call->state==LinphoneCallStreamsRunning && one_second_elapsed && call->audiostream!=NULL && call->audiostream->ms.state==MSStreamStarted && disconnect_timeout>0 ) disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout); @@ -4218,18 +4396,26 @@ LinphoneChatRoom * linphone_call_get_chat_room(LinphoneCall *call) { int linphone_call_get_stream_count(LinphoneCall *call) { // Revisit when multiple media streams will be implemented #ifdef VIDEO_ENABLED + if (linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { + return 3; + } return 2; #else + if (linphone_call_params_realtime_text_enabled(linphone_call_get_current_params(call))) { + return 2; + } return 1; #endif } MSFormatType linphone_call_get_stream_type(LinphoneCall *call, int stream_index) { // Revisit when multiple media streams will be implemented - if (stream_index == 0) { - return MSAudio; + if (stream_index == call->main_video_stream_index) { + return MSVideo; + } else if (stream_index == call->main_text_stream_index) { + return MSText; } - return MSVideo; + return MSAudio; } RtpTransport* linphone_call_get_meta_rtp_transport(LinphoneCall *call, int stream_index) { diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index e270488b7..1c8504b63 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -1027,6 +1027,15 @@ static void rtp_config_read(LinphoneCore *lc) linphone_core_set_video_port(lc, min_port); } + if (lp_config_get_range(lc->config, "rtp", "text_rtp_port", &min_port, &max_port, 11078, 11078) == TRUE) { + if (min_port <= 0) min_port = 1; + if (max_port > 65535) max_port = 65535; + linphone_core_set_text_port_range(lc, min_port, max_port); + } else { + min_port = lp_config_get_int(lc->config, "rtp", "text_rtp_port", 11078); + linphone_core_set_text_port(lc, min_port); + } + jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60); linphone_core_set_audio_jittcomp(lc,jitt_comp); jitt_comp=lp_config_get_int(lc->config,"rtp","video_jitt_comp",60); @@ -1121,7 +1130,7 @@ static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, Payload LpConfig *config=lc->config; *ret=NULL; - snprintf(codeckey,50,"%s_codec_%i",type==SalAudio ? "audio" : "video", index); + snprintf(codeckey,50,"%s_codec_%i",type == SalAudio ? "audio" : type == SalVideo ? "video" : "text", index); mime=lp_config_get_string(config,codeckey,"mime",NULL); if (mime==NULL || strlen(mime)==0 ) return FALSE; @@ -1133,15 +1142,17 @@ static bool_t get_codec(LinphoneCore *lc, SalStreamType type, int index, Payload ms_warning("Codec %s/%i read from conf is not supported by mediastreamer2, ignored.",mime,rate); return TRUE; } - pt=find_payload(type==SalAudio ? lc->default_audio_codecs : lc->default_video_codecs,mime,rate,channels,fmtp); + pt = find_payload(type == SalAudio ? lc->default_audio_codecs : type == SalVideo ? lc->default_video_codecs : lc->default_text_codecs ,mime,rate,channels,fmtp); if (!pt){ - MSList **default_list=(type==SalAudio) ? &lc->default_audio_codecs : &lc->default_video_codecs; - if (type==SalAudio) + MSList **default_list = (type==SalAudio) ? &lc->default_audio_codecs : type == SalVideo ? &lc->default_video_codecs : &lc->default_text_codecs; + if (type == SalAudio) ms_warning("Codec %s/%i/%i read from conf is not in the default list.",mime,rate,channels); - else + else if (type == SalVideo) ms_warning("Codec %s/%i read from conf is not in the default list.",mime,rate); + else + ms_warning("Codec %s read from conf is not in the default list.",mime); pt=payload_type_new(); - pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : PAYLOAD_VIDEO; + pt->type=(type==SalAudio) ? PAYLOAD_AUDIO_PACKETIZED : type == SalVideo ? PAYLOAD_VIDEO : PAYLOAD_TEXT; pt->mime_type=ortp_strdup(mime); pt->clock_rate=rate; pt->channels=channels; @@ -1199,6 +1210,7 @@ static void codecs_config_read(LinphoneCore *lc) PayloadType *pt; MSList *audio_codecs=NULL; MSList *video_codecs=NULL; + MSList *text_codecs=NULL; lc->codecs_conf.dyn_pt=96; lc->codecs_conf.telephone_event_pt=lp_config_get_int(lc->config,"misc","telephone_event_pt",101); @@ -1220,8 +1232,17 @@ static void codecs_config_read(LinphoneCore *lc) if( lp_config_get_int(lc->config, "misc", "add_missing_video_codecs", 1) == 1 ){ video_codecs=add_missing_codecs(lc->default_video_codecs,video_codecs); } + + for (i=0;get_codec(lc,SalText,i,&pt);i++){ + if (pt){ + text_codecs=codec_append_if_new(text_codecs, pt); + } + } + text_codecs = add_missing_codecs(lc->default_text_codecs, text_codecs); + linphone_core_set_audio_codecs(lc,audio_codecs); linphone_core_set_video_codecs(lc,video_codecs); + linphone_core_set_text_codecs(lc, text_codecs); linphone_core_update_allocated_audio_bandwidth(lc); } @@ -1402,7 +1423,7 @@ const char * linphone_core_get_version(void){ static void linphone_core_register_payload_type(LinphoneCore *lc, const PayloadType *const_pt, const char *recv_fmtp, bool_t enabled){ MSList **codec_list=const_pt->type==PAYLOAD_VIDEO ? &lc->default_video_codecs : &lc->default_audio_codecs; - if (linphone_core_codec_supported(lc, (const_pt->type == PAYLOAD_VIDEO) ? SalVideo : SalAudio, const_pt->mime_type)){ + if (linphone_core_codec_supported(lc, (const_pt->type == PAYLOAD_VIDEO) ? SalVideo : const_pt->type == PAYLOAD_TEXT ? SalText : SalAudio, const_pt->mime_type)){ PayloadType *pt=payload_type_clone(const_pt); int number=-1; payload_type_set_enable(pt,enabled); @@ -1428,8 +1449,8 @@ static void linphone_core_register_static_payloads(LinphoneCore *lc){ if (pt->type==PAYLOAD_VIDEO) continue; #endif if (find_payload_type_from_list( - pt->mime_type, pt->clock_rate, pt->type!=PAYLOAD_VIDEO ? pt->channels : LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS, - pt->type==PAYLOAD_VIDEO ? lc->default_video_codecs : lc->default_audio_codecs)==NULL){ + pt->mime_type, pt->clock_rate, pt->type == PAYLOAD_VIDEO || pt->type == PAYLOAD_TEXT ? LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS : pt->channels, + pt->type == PAYLOAD_VIDEO ? lc->default_video_codecs : pt->type == PAYLOAD_TEXT ? lc->default_text_codecs : lc->default_audio_codecs)==NULL){ linphone_core_register_payload_type(lc,pt,NULL,FALSE); } } @@ -1569,7 +1590,8 @@ static void linphone_core_register_default_codecs(LinphoneCore *lc){ linphone_core_register_payload_type(lc,&payload_type_aal2_g726_40,NULL,FALSE); linphone_core_register_payload_type(lc,&payload_type_codec2,NULL,FALSE); - + linphone_core_register_payload_type(lc,&payload_type_t140,NULL,TRUE); + linphone_core_register_payload_type(lc,&payload_type_t140_red,NULL,TRUE); #ifdef VIDEO_ENABLED @@ -1659,6 +1681,11 @@ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc) return lc->codecs_conf.video_codecs; } +const MSList *linphone_core_get_text_codecs(const LinphoneCore *lc) +{ + return lc->codecs_conf.text_codecs; +} + int linphone_core_set_primary_contact(LinphoneCore *lc, const char *contact) { LinphoneAddress *ctt; @@ -1788,6 +1815,15 @@ int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs){ return 0; } +int linphone_core_set_text_codecs(LinphoneCore *lc, MSList *codecs) { + if (lc->codecs_conf.text_codecs != NULL) + ms_list_free(lc->codecs_conf.text_codecs); + + lc->codecs_conf.text_codecs = codecs; + _linphone_core_codec_config_write(lc); + return 0; +} + /** * Enable RFC3389 generic confort noise algorithm (CN payload type). * It is disabled by default, because this algorithm is only relevant for legacy codecs (PCMU, PCMA, G722). @@ -1893,6 +1929,24 @@ void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, i *max_port = lc->rtp_conf.video_rtp_max_port; } +/** + * Returns the UDP port used for text streaming. + * + * @ingroup network_parameters +**/ +int linphone_core_get_text_port(const LinphoneCore *lc) { + return lc->rtp_conf.text_rtp_min_port; +} + +/** + * Get the video port range from which is randomly chosen the UDP port used for text streaming. + * + * @ingroup network_parameters + */ +void linphone_core_get_text_port_range(const LinphoneCore *lc, int *min_port, int *max_port) { + *min_port = lc->rtp_conf.text_rtp_min_port; + *max_port = lc->rtp_conf.text_rtp_max_port; +} /** * Returns the value in seconds of the no-rtp timeout. @@ -1992,6 +2046,26 @@ void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_ lc->rtp_conf.video_rtp_min_port=min_port; lc->rtp_conf.video_rtp_max_port=max_port; } + +/** + * Sets the UDP port used for text streaming. + * A value if -1 will request the system to allocate the local port randomly. + * This is recommended in order to avoid firewall warnings. + * + * @ingroup network_parameters +**/ +void linphone_core_set_text_port(LinphoneCore *lc, int port) { + lc->rtp_conf.text_rtp_min_port = lc->rtp_conf.text_rtp_max_port = port; +} + +/** + * Sets the UDP port range from which to randomly select the port used for text streaming. + * @ingroup media_parameters + */ +void linphone_core_set_text_port_range(LinphoneCore *lc, int min_port, int max_port) { + lc->rtp_conf.text_rtp_min_port = min_port; + lc->rtp_conf.text_rtp_max_port = max_port; +} /** * Sets the no-rtp timeout value in seconds. @@ -3843,7 +3917,7 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ } lc->current_call=NULL; linphone_core_notify_display_status(lc,_("Pausing the current call...")); - if (call->audiostream || call->videostream) + if (call->audiostream || call->videostream || call->textstream) linphone_call_stop_media_streams (call); call->paused_by_app=FALSE; return 0; @@ -6850,6 +6924,7 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate; params->media_encryption=linphone_core_get_media_encryption(lc); params->in_conference=FALSE; + params->realtimetext_enabled = linphone_core_realtime_text_enabled(lc); params->privacy=LinphonePrivacyDefault; params->avpf_enabled=FALSE; params->audio_dir=LinphoneMediaDirectionSendRecv; @@ -7184,3 +7259,7 @@ LINPHONE_PUBLIC const char *linphone_core_log_collection_upload_state_to_string( } return "UNKNOWN"; } + +bool_t linphone_core_realtime_text_enabled(LinphoneCore *lc) { + return lc->text_conf.enabled; +} diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 14f195b28..93350eaee 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -469,6 +469,7 @@ typedef struct _LinphoneVideoPolicy LinphoneVideoPolicy; #define LINPHONE_CALL_STATS_AUDIO 0 #define LINPHONE_CALL_STATS_VIDEO 1 +#define LINPHONE_CALL_STATS_TEXT 2 /** * Enum describing ICE states. @@ -2683,6 +2684,22 @@ LINPHONE_PUBLIC const MSList *linphone_core_get_video_codecs(const LinphoneCore LINPHONE_PUBLIC int linphone_core_set_video_codecs(LinphoneCore *lc, MSList *codecs); +/** + * Returns the list of available text codecs. + * @param[in] lc The LinphoneCore object + * @return \mslist{PayloadType} + * + * This list is unmodifiable. The ->data field of the MSList points a PayloadType + * structure holding the codec information. + * It is possible to make copy of the list with ms_list_copy() in order to modify it + * (such as the order of codecs). + * @ingroup media_parameters +**/ +LINPHONE_PUBLIC const MSList *linphone_core_get_text_codecs(const LinphoneCore *lc); + + +LINPHONE_PUBLIC int linphone_core_set_text_codecs(LinphoneCore *lc, MSList *codecs); + LINPHONE_PUBLIC void linphone_core_enable_generic_confort_noise(LinphoneCore *lc, bool_t enabled); LINPHONE_PUBLIC bool_t linphone_core_generic_confort_noise_enabled(const LinphoneCore *lc); @@ -2931,6 +2948,10 @@ LINPHONE_PUBLIC int linphone_core_get_video_port(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port); +LINPHONE_PUBLIC int linphone_core_get_text_port(const LinphoneCore *lc); + +LINPHONE_PUBLIC void linphone_core_get_text_port_range(const LinphoneCore *lc, int *min_port, int *max_port); + LINPHONE_PUBLIC int linphone_core_get_nortp_timeout(const LinphoneCore *lc); LINPHONE_PUBLIC void linphone_core_set_audio_port(LinphoneCore *lc, int port); @@ -2941,6 +2962,10 @@ LINPHONE_PUBLIC void linphone_core_set_video_port(LinphoneCore *lc, int port); LINPHONE_PUBLIC void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port); +LINPHONE_PUBLIC void linphone_core_set_text_port(LinphoneCore *lc, int port); + +LINPHONE_PUBLIC void linphone_core_set_text_port_range(LinphoneCore *lc, int min_port, int max_port); + LINPHONE_PUBLIC void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port); LINPHONE_PUBLIC void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info); @@ -4092,6 +4117,13 @@ LINPHONE_PUBLIC void linphone_core_set_video_preset(LinphoneCore *lc, const char */ LINPHONE_PUBLIC const char * linphone_core_get_video_preset(const LinphoneCore *lc); +/** + * Gets if realtime text is enabled or not + * @param[in] lc LinphoneCore object + * @return true if realtime text is enabled, false otherwise + */ +LINPHONE_PUBLIC bool_t linphone_core_realtime_text_enabled(LinphoneCore *lc); + #ifdef __cplusplus } #endif diff --git a/coreapi/misc.c b/coreapi/misc.c index 7547f1022..8fcd4c546 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -62,7 +62,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void clear_ice_check_list(LinphoneCall *call, IceCheckList *removed); bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const LinphonePayloadType *pt){ - if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){ + if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt) || ms_list_find(lc->codecs_conf.text_codecs, (PayloadType*)pt)){ return payload_type_enabled(pt); } ms_error("Getting enablement status of codec not in audio or video list of PayloadType !"); @@ -75,7 +75,7 @@ bool_t linphone_core_payload_type_is_vbr(LinphoneCore *lc, const LinphonePayload } int linphone_core_enable_payload_type(LinphoneCore *lc, LinphonePayloadType *pt, bool_t enabled){ - if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){ + if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt) || ms_list_find(lc->codecs_conf.text_codecs,pt)){ payload_type_set_enable(pt,enabled); _linphone_core_codec_config_write(lc); linphone_core_update_allocated_audio_bandwidth(lc); @@ -106,7 +106,7 @@ const char *linphone_core_get_payload_type_description(LinphoneCore *lc, Payload } void linphone_core_set_payload_type_bitrate(LinphoneCore *lc, LinphonePayloadType *pt, int bitrate){ - if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){ + if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt) || ms_list_find(lc->codecs_conf.text_codecs, (PayloadType*)pt)){ if (pt->type==PAYLOAD_VIDEO || pt->flags & PAYLOAD_TYPE_IS_VBR){ pt->normal_bitrate=bitrate*1000; pt->flags|=PAYLOAD_TYPE_BITRATE_OVERRIDE; diff --git a/coreapi/private.h b/coreapi/private.h index 3336463cb..ee2f2b8e1 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -117,6 +117,7 @@ struct _LinphoneCallParams{ LinphoneMediaEncryption media_encryption; PayloadType *audio_codec; /*audio codec currently in use */ PayloadType *video_codec; /*video codec currently in use */ + PayloadType *text_codec; /*text codec currently in use */ MSVideoSize sent_vsize; /* Size of the video currently being sent */ MSVideoSize recv_vsize; /* Size of the video currently being received */ float received_fps,sent_fps; @@ -251,6 +252,7 @@ struct _LinphoneCall{ SalMediaDescription *resultdesc; struct _RtpProfile *audio_profile; struct _RtpProfile *video_profile; + struct _RtpProfile *text_profile; struct _RtpProfile *rtp_io_audio_profile; struct _RtpProfile *rtp_io_video_profile; struct _LinphoneCallLog *log; @@ -262,11 +264,13 @@ struct _LinphoneCall{ LinphoneCallState prevstate; LinphoneCallState transfer_state; /*idle if no transfer*/ LinphoneProxyConfig *dest_proxy; - PortConfig media_ports[2]; - MSMediaStreamSessions sessions[2]; /*the rtp, srtp, zrtp contexts for each stream*/ - StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/ + int main_audio_stream_index, main_video_stream_index, main_text_stream_index; + PortConfig media_ports[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; + MSMediaStreamSessions sessions[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; /*the rtp, srtp, zrtp contexts for each stream*/ + StunCandidate ac, vc, tc; /*audio video text ip/port discovered by STUN*/ struct _AudioStream *audiostream; /**/ struct _VideoStream *videostream; + struct _TextStream *textstream; void *video_window_id; MSAudioEndpoint *endpoint; /*used for conferencing*/ char *refer_to; @@ -278,8 +282,9 @@ struct _LinphoneCall{ OrtpEvQueue *audiostream_app_evq; char *auth_token; OrtpEvQueue *videostream_app_evq; + OrtpEvQueue *textstream_app_evq; CallCallbackObj nextVideoFrameDecoded; - LinphoneCallStats stats[2]; + LinphoneCallStats stats[3]; /* audio, video, text */ #ifdef BUILD_UPNP UpnpSession *upnp_session; #endif //BUILD_UPNP @@ -453,6 +458,7 @@ void linphone_call_init_stats(LinphoneCallStats *stats, int type); void linphone_call_fix_call_parameters(LinphoneCall *call); void linphone_call_init_audio_stream(LinphoneCall *call); void linphone_call_init_video_stream(LinphoneCall *call); +void linphone_call_init_text_stream(LinphoneCall *call); void linphone_call_init_media_streams(LinphoneCall *call); void linphone_call_start_media_streams(LinphoneCall *call, LinphoneCallState target_state); void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call); @@ -656,6 +662,8 @@ typedef struct rtp_config char* video_multicast_addr; int video_multicast_ttl; bool_t video_multicast_enabled; + int text_rtp_min_port; + int text_rtp_max_port; }rtp_config_t; @@ -701,6 +709,7 @@ typedef struct codecs_config { MSList *audio_codecs; /* list of audio codecs in order of preference*/ MSList *video_codecs; + MSList *text_codecs; int dyn_pt; int telephone_event_pt; }codecs_config_t; @@ -718,6 +727,10 @@ typedef struct video_config{ bool_t reuse_preview_source; }video_config_t; +typedef struct text_config{ + bool_t enabled; +}text_config_t; + typedef struct ui_config { int is_daemon; @@ -781,11 +794,13 @@ struct _LinphoneCore struct _LpConfig *config; MSList *default_audio_codecs; MSList *default_video_codecs; + MSList *default_text_codecs; net_config_t net_conf; sip_config_t sip_conf; rtp_config_t rtp_conf; sound_config_t sound_conf; video_config_t video_conf; + text_config_t text_conf; codecs_config_t codecs_conf; ui_config_t ui_conf; autoreplier_config_t autoreplier_conf; diff --git a/coreapi/sal.c b/coreapi/sal.c index efbc2ea0d..ba8108eae 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -617,8 +617,9 @@ void sal_auth_info_delete(SalAuthInfo* auth_info) { const char* sal_stream_type_to_string(SalStreamType type) { switch (type) { - case SalAudio:return "audio"; - case SalVideo:return "video"; + case SalAudio: return "audio"; + case SalVideo: return "video"; + case SalText: return "text"; default: return "other"; } } diff --git a/include/sal/sal.h b/include/sal/sal.h index 12015b105..a96498a95 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -126,6 +126,7 @@ void *sal_get_user_pointer(const Sal *sal); typedef enum { SalAudio, SalVideo, + SalText, SalOther } SalStreamType; const char* sal_stream_type_to_string(SalStreamType type); diff --git a/mediastreamer2 b/mediastreamer2 index 93cf916ac..2df927914 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 93cf916ac44dea93db7744b1d66ea3655c8345d9 +Subproject commit 2df927914113b54610e9174d6c1f8615d22cb304 diff --git a/oRTP b/oRTP index bb95930a7..c3b24c490 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit bb95930a77e8a1432e5c31dc170f05ecd15518e5 +Subproject commit c3b24c490a1f1f22dda6a88d2d2e428ff610b915 From c8f1f3b61e81a1b86543d3272bb2ee4ba00da7b0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 16 Sep 2015 15:23:01 +0200 Subject: [PATCH 07/23] Do not use anymore nb_streams but SAL_MEDIA_DESCRIPTION_MAX_STREAMS and skip inactive ones because active streams won't be at the start of the array anymore --- coreapi/bellesip_sal/sal_op_call.c | 4 +- coreapi/bellesip_sal/sal_sdp.c | 3 +- coreapi/call_params.c | 2 +- coreapi/callbacks.c | 9 ++- coreapi/linphonecall.c | 113 ++++++++++++++++------------- coreapi/linphonecore.c | 10 ++- coreapi/misc.c | 69 +++++++++++++----- coreapi/offeranswer.c | 12 +-- coreapi/quality_reporting.c | 4 +- coreapi/sal.c | 25 ++++--- coreapi/upnp.c | 13 ++-- 11 files changed, 164 insertions(+), 100 deletions(-) diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 5474540ea..bdbae06ec 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -66,7 +66,7 @@ static void sdp_process(SalOp *h){ /*for backward compatibility purpose*/ if(h->cnx_ip_to_0000_if_sendonly_enabled && sal_media_description_has_dir(h->result,SalStreamSendOnly)) { set_addr_to_0000(h->result->addr); - for(i=0;iresult->nb_streams;++i){ + for(i=0;iresult->streams[i].dir == SalStreamSendOnly) set_addr_to_0000(h->result->streams[i].rtp_addr); set_addr_to_0000(h->result->streams[i].rtcp_addr); @@ -78,7 +78,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->nb_streams;++i){ + for(i=0;iresult->streams[i].rtp_port!=0){ /*if stream was accepted*/ strcpy(h->result->streams[i].rtp_addr,h->base.remote_media->streams[i].rtp_addr); diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index ec84ccfe4..940ee7438 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -416,7 +416,8 @@ 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; inb_streams; i++ ) { + for ( i=0; istreams[i])) continue; stream_description_to_sdp(session_desc, desc, &desc->streams[i]); } return session_desc; diff --git a/coreapi/call_params.c b/coreapi/call_params.c index 5f73a7d07..1f22ad4fd 100644 --- a/coreapi/call_params.c +++ b/coreapi/call_params.c @@ -266,7 +266,7 @@ LinphoneCallParams * linphone_call_params_new(void) { LinphoneCallParams *cp=belle_sip_object_new(LinphoneCallParams); cp->audio_dir=LinphoneMediaDirectionSendRecv; cp->video_dir=LinphoneMediaDirectionSendRecv; - cp->realtimetext_enabled=TRUE; /*fixme*/ + cp->realtimetext_enabled = FALSE; return cp; } diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index f58c2a77f..54394b719 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -49,7 +49,7 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c char *rtp_addr, *rtcp_addr; int i; - for (i = 0; i < new_md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_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]; @@ -188,8 +188,9 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia linphone_call_stop_media_streams (call); if (md_changed & SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED){ ms_message("Media ip type has changed, destroying sessions context on call [%p]",call); - ms_media_stream_sessions_uninit(&call->sessions[0]); - ms_media_stream_sessions_uninit(&call->sessions[1]); + ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]); + ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]); + if (call->params->realtimetext_enabled) ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]); } linphone_call_init_media_streams (call); } @@ -368,7 +369,7 @@ 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;inb_streams;++i){ + for (i=0;istreams[i])) continue; ref_stream=&cur_md->streams[i]; new_stream=&md->streams[i]; diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index f1a284d24..82e71db9e 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -408,7 +408,7 @@ static MSList *make_codec_list(LinphoneCore *lc, CodecConstraints * hints, SalSt static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc, const StunCandidate *tc){ int i; - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; if ((md->streams[i].type == SalAudio) && (ac->port != 0)) { strcpy(md->streams[i].rtp_addr,ac->addr); @@ -453,7 +453,7 @@ static int setup_encryption_key(SalSrtpCryptoAlgo *crypto, MSCryptoSuite suite, } static void setup_dtls_keys(LinphoneCall *call, SalMediaDescription *md){ int i; - for(i=0; inb_streams; i++) { + for(i=0; istreams[i])) continue; /* if media encryption is set to DTLS check presence of fingerprint in the call which shall have been set at stream init but it may have failed when retrieving certificate resulting in no fingerprint present and then DTLS not usable */ if (sal_stream_description_has_dtls(&md->streams[i]) == TRUE) { @@ -473,7 +473,7 @@ 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; inb_streams; i++) { + for(i=0; istreams[i])) continue; if (sal_stream_description_has_srtp(&md->streams[i]) == TRUE) { if (keep_srtp_keys && old_md && (sal_stream_description_active(&old_md->streams[i]) == TRUE) && (sal_stream_description_has_srtp(&old_md->streams[i]) == TRUE)) { @@ -499,7 +499,7 @@ static void setup_rtcp_fb(LinphoneCall *call, SalMediaDescription *md) { LinphoneCore *lc = call->core; int i; - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; md->streams[i].rtcp_fb.generic_nack_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_generic_nack_enabled", 0); md->streams[i].rtcp_fb.tmmbr_enabled = lp_config_get_int(lc->config, "rtp", "rtcp_fb_tmmbr_enabled", 0); @@ -537,7 +537,7 @@ 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", 1); } - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_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)); } @@ -563,7 +563,7 @@ void linphone_call_update_local_media_description_from_ice_or_upnp(LinphoneCall static void transfer_already_assigned_payload_types(SalMediaDescription *old, SalMediaDescription *md){ int i; - for(i=0;inb_streams;++i){ + for(i=0;istreams[i].already_assigned_payloads=old->streams[i].already_assigned_payloads; old->streams[i].already_assigned_payloads=NULL; } @@ -601,12 +601,14 @@ static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDes break; } - for (i=0; inb_streams; ++i){ + for (i=0; istreams[i]; - sd->dir = SalStreamSendOnly; - if (sd->type == SalVideo){ - if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) { - sd->dir = SalStreamInactive; + if (sd->dir != SalStreamInactive) { + sd->dir = SalStreamSendOnly; + if (sd->type == SalVideo){ + if (lp_config_get_int(call->core->config, "sip", "inactive_video_on_pause", 0)) { + sd->dir = SalStreamInactive; + } } } } @@ -747,17 +749,20 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { md->nb_streams = nb_active_streams; /* Deactivate inactive streams. */ - 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; - md->streams[i].type = call->biggestdesc->streams[i].type; - md->streams[i].dir = SalStreamInactive; - codec_hints.bandwidth_limit=0; - codec_hints.max_codecs=1; - codec_hints.previously_used=NULL; - l = make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs); - md->streams[i].payloads = l; + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (md->streams[i].dir == SalStreamInactive) { + md->streams[i].rtp_port = 0; + md->streams[i].rtcp_port = 0; + if (call->biggestdesc && i < call->biggestdesc->nb_streams) { + md->streams[i].proto = call->biggestdesc->streams[i].proto; + md->streams[i].type = call->biggestdesc->streams[i].type; + } + codec_hints.bandwidth_limit=0; + codec_hints.max_codecs=1; + codec_hints.previously_used=NULL; + l = make_codec_list(lc, &codec_hints, SalVideo, lc->codecs_conf.video_codecs); + md->streams[i].payloads = l; + } } setup_encryption_keys(call,md); setup_dtls_keys(call,md); @@ -876,8 +881,10 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, linphone_core_get_video_port_range(call->core, &min_port, &max_port); port_config_set(call,call->main_video_stream_index,min_port,max_port); - linphone_core_get_text_port_range(call->core, &min_port, &max_port); - port_config_set(call,call->main_text_stream_index,min_port,max_port); + if (call->params->realtimetext_enabled) { + linphone_core_get_text_port_range(call->core, &min_port, &max_port); + port_config_set(call,call->main_text_stream_index,min_port,max_port); + } linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO); @@ -1015,14 +1022,14 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; - call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT; + call->main_text_stream_index = params->realtimetext_enabled ? LINPHONE_CALL_STATS_TEXT : -1; call->dir=LinphoneCallOutgoing; call->core=lc; linphone_call_outgoing_select_ip_version(call,to,cfg); linphone_call_get_local_ip(call, to); - linphone_call_init_common(call, from, to); call->params = linphone_call_params_copy(params); + linphone_call_init_common(call, from, to); linphone_call_fill_media_multicast_addr(call); @@ -1087,9 +1094,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro LinphoneFirewallPolicy fpol; int i; - call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; - call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; - call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT; + call->main_audio_stream_index = -1; + call->main_video_stream_index = -1; + call->main_text_stream_index = -1; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); @@ -1122,8 +1129,8 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_address_clean(from); linphone_call_get_local_ip(call, from); - linphone_call_init_common(call, from, to); call->params = linphone_call_params_new(); + 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); @@ -1143,21 +1150,28 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_set_compatible_incoming_call_parameters(call, md); /* set multicast role & address if any*/ if (!sal_call_is_offerer(op)){ - for (i=0;inb_streams;i++){ + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (md->streams[i].dir == SalStreamInactive) { + continue; + } + if (md->streams[i].rtp_addr[0]!='\0' && ms_is_multicast(md->streams[i].rtp_addr)){ md->streams[i].multicast_role = SalMulticastReceiver; strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip)); - - if (sal_stream_description_active(&md->streams[i])) { - if (md->streams[i].type == SalAudio) { - call->main_audio_stream_index = i; - } else if (md->streams[i].type == SalVideo) { - call->main_video_stream_index = i; - } else if (md->streams[i].type == SalText) { - call->main_text_stream_index = i; - } - } } + + if (sal_stream_description_active(&md->streams[i])) { + if (md->streams[i].type == SalAudio) { + call->main_audio_stream_index = i; + ms_message("audio stream index updated: %i", i); + } else if (md->streams[i].type == SalVideo) { + call->main_video_stream_index = i; + ms_message("video stream index updated: %i", i); + } else if (md->streams[i].type == SalText) { + call->main_text_stream_index = i; + ms_message("text stream index updated: %i", i); + } + } } } } @@ -1220,12 +1234,12 @@ void linphone_call_free_media_resources(LinphoneCall *call){ linphone_call_stop_media_streams(call); ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]); ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]); - ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]); + if (call->params->realtimetext_enabled) ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]); linphone_call_delete_upnp_session(call); linphone_call_delete_ice_session(call); - linphone_call_stats_uninit(&call->stats[call->main_audio_stream_index]); - linphone_call_stats_uninit(&call->stats[call->main_video_stream_index]); - linphone_call_stats_uninit(&call->stats[call->main_text_stream_index]); + linphone_call_stats_uninit(&call->stats[LINPHONE_CALL_STATS_AUDIO]); + linphone_call_stats_uninit(&call->stats[LINPHONE_CALL_STATS_VIDEO]); + linphone_call_stats_uninit(&call->stats[LINPHONE_CALL_STATS_TEXT]); } /* @@ -2255,7 +2269,7 @@ void linphone_call_init_text_stream(LinphoneCall *call){ LinphoneCore *lc=call->core; char* cname; - if (call->textstream != NULL) return; + if (call->textstream != NULL || !call->params->realtimetext_enabled) return; if (call->sessions[call->main_text_stream_index].rtp_session == NULL) { SalMulticastRole multicast_role = linphone_call_get_multicast_role(call, SalText); SalMediaDescription *remotedesc = NULL; @@ -3356,7 +3370,7 @@ static void linphone_call_stop_text_stream(LinphoneCall *call) { } void linphone_call_stop_media_streams(LinphoneCall *call){ - if (call->audiostream || call->videostream) { + if (call->audiostream || call->videostream || call->textstream) { if (call->audiostream && call->videostream) audio_stream_unlink_video(call->audiostream, call->videostream); linphone_call_stop_audio_stream(call); @@ -4048,8 +4062,9 @@ void linphone_call_handle_stream_events(LinphoneCall *call, int stream_index){ OrtpEventType evt=ortp_event_get_type(ev); OrtpEventData *evd=ortp_event_get_data(ev); - linphone_call_stats_fill(&call->stats[stream_index],ms,ev); - linphone_call_notify_stats_updated(call,stream_index); + int stats_index = stream_index == call->main_audio_stream_index ? LINPHONE_CALL_STATS_AUDIO : (stream_index == call->main_video_stream_index ? LINPHONE_CALL_STATS_VIDEO : LINPHONE_CALL_STATS_TEXT); + linphone_call_stats_fill(&call->stats[stats_index],ms,ev); + linphone_call_notify_stats_updated(call,stats_index); if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){ if (ms->type==MSAudio) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 1c8504b63..c9a50638c 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2831,8 +2831,9 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){ linphone_call_create_op(call); linphone_call_stop_media_streams(call); - ms_media_stream_sessions_uninit(&call->sessions[0]); - ms_media_stream_sessions_uninit(&call->sessions[1]); + ms_media_stream_sessions_uninit(&call->sessions[call->main_audio_stream_index]); + ms_media_stream_sessions_uninit(&call->sessions[call->main_video_stream_index]); + if (call->params->realtimetext_enabled) ms_media_stream_sessions_uninit(&call->sessions[call->main_text_stream_index]); linphone_call_init_media_streams(call); return linphone_core_start_invite(lc,call, NULL); } @@ -6157,6 +6158,11 @@ void rtp_config_uninit(LinphoneCore *lc) } else { lp_config_set_range(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port, config->video_rtp_max_port); } + if (config->text_rtp_min_port == config->text_rtp_max_port) { + lp_config_set_int(lc->config, "rtp", "text_rtp_port", config->text_rtp_min_port); + } else { + lp_config_set_range(lc->config, "rtp", "text_rtp_port", config->text_rtp_min_port, config->text_rtp_max_port); + } lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp); lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp); lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout); diff --git a/coreapi/misc.c b/coreapi/misc.c index 8fcd4c546..6cad3002b 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -409,22 +409,23 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ const char *server=linphone_core_get_stun_server(lc); StunCandidate *ac=&call->ac; StunCandidate *vc=&call->vc; + StunCandidate *tc=&call->tc; if (lc->sip_conf.ipv6_enabled){ ms_warning("stun support is not implemented for ipv6"); return -1; } - if (call->media_ports[0].rtp_port==-1){ + if (call->media_ports[call->main_audio_stream_index].rtp_port==-1){ ms_warning("Stun-only support not available for system random port"); return -1; } if (server!=NULL){ const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc); - ortp_socket_t sock1=-1, sock2=-1; + ortp_socket_t sock1=-1, sock2=-1, sock3=-1; int loops=0; bool_t video_enabled=linphone_core_video_enabled(lc); - bool_t got_audio,got_video; - bool_t cone_audio=FALSE,cone_video=FALSE; + bool_t got_audio,got_video,got_text; + bool_t cone_audio=FALSE,cone_video=FALSE,cone_text=FALSE; struct timeval init,cur; double elapsed; int ret=0; @@ -436,14 +437,19 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ linphone_core_notify_display_status(lc,_("Stun lookup in progress...")); /*create the two audio and video RTP sockets, and send STUN message to our stun server */ - sock1=create_socket(call->media_ports[0].rtp_port); + sock1=create_socket(call->media_ports[call->main_audio_stream_index].rtp_port); if (sock1==-1) return -1; if (video_enabled){ - sock2=create_socket(call->media_ports[1].rtp_port); + sock2=create_socket(call->media_ports[call->main_video_stream_index].rtp_port); if (sock2==-1) return -1; } + if (call->params->realtimetext_enabled) { + sock3=create_socket(call->media_ports[call->main_text_stream_index].rtp_port); + if (sock3==-1) return -1; + } got_audio=FALSE; got_video=FALSE; + got_text=FALSE; ortp_gettimeofday(&init,NULL); do{ @@ -456,6 +462,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,22,TRUE); sendStunRequest(sock2,ai->ai_addr,ai->ai_addrlen,2,FALSE); } + if (sock3!=-1){ + sendStunRequest(sock3,ai->ai_addr,ai->ai_addrlen,33,TRUE); + sendStunRequest(sock3,ai->ai_addr,ai->ai_addrlen,3,FALSE); + } } ms_usleep(10000); @@ -477,6 +487,15 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ cone_video=TRUE; got_video=TRUE; } + if (recvStunResponse(sock3,tc->addr, + &tc->port,&id)>0){ + ms_message("STUN test result: local text port maps to %s:%i", + tc->addr, + tc->port); + if (id==33) + cone_text=TRUE; + got_text=TRUE; + } ortp_gettimeofday(&cur,NULL); elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0); if (elapsed>2000) { @@ -485,7 +504,7 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ break; } loops++; - }while(!(got_audio && (got_video||sock2==-1) ) ); + }while(!(got_audio && (got_video||sock2==-1) && (got_text||sock3==-1) ) ); if (ret==0) ret=(int)elapsed; if (!got_audio){ ms_error("No stun server response for audio port."); @@ -503,8 +522,18 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ } } } + if (sock3!=-1){ + if (!got_text){ + ms_error("No stun server response for text port."); + }else{ + if (!cone_text) { + ms_message("NAT is symmetric for text port."); + } + } + } close_socket(sock1); if (sock2!=-1) close_socket(sock2); + if (sock3!=-1) close_socket(sock3); return ret; } return -1; @@ -622,14 +651,14 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) return -1; } if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) { - ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtp_port, 1, NULL); - ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtcp_port, 2, NULL); + ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[call->main_audio_stream_index].rtp_port, 1, NULL); + ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[call->main_audio_stream_index].rtcp_port, 2, NULL); call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress; } if (linphone_core_video_enabled(lc) && (video_check_list != NULL) && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) { - ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtp_port, 1, NULL); - ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtcp_port, 2, NULL); + ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[call->main_video_stream_index].rtp_port, 1, NULL); + ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL); call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; } @@ -759,7 +788,7 @@ void _update_local_media_description_from_ice(SalMediaDescription *desc, IceSess } 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->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { SalStreamDescription *stream = &desc->streams[i]; IceCheckList *cl = ice_session_check_list(session, i); nb_candidates = 0; @@ -866,9 +895,10 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, ice_params_found=TRUE; } else { int i; - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (!sal_stream_description_active(stream)) continue; if (cl) { if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { ice_params_found=TRUE; @@ -887,9 +917,10 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, ice_session_restart(call->ice_session); ice_restarted = TRUE; } else { - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (!sal_stream_description_active(stream)) continue; if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) { ice_session_restart(call->ice_session); ice_restarted = TRUE; @@ -906,9 +937,10 @@ void linphone_call_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->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (!sal_stream_description_active(stream)) continue; if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) { if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) { if (ice_restarted == FALSE @@ -925,9 +957,10 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, } /* Create ICE check lists if needed and parse ICE attributes. */ - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { const SalStreamDescription *stream = &md->streams[i]; IceCheckList *cl = ice_session_check_list(call->ice_session, i); + if (!sal_stream_description_active(stream)) continue; /* if ((cl == NULL) && (i < md->n_active_streams)) { cl = ice_check_list_new(); @@ -986,7 +1019,7 @@ void linphone_call_update_ice_from_remote_media_description(LinphoneCall *call, } } } - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_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); @@ -1007,7 +1040,7 @@ void linphone_call_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; md && i < md->nb_streams; i++) { + for (i = 0; md && i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (md->streams[i].type == SalVideo && md->streams[i].rtp_port!=0) return TRUE; } diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 0b0edb931..f36f002a7 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -493,9 +493,10 @@ int offer_answer_initiate_outgoing(const SalMediaDescription *local_offer, int i,j; const SalStreamDescription *ls,*rs; - for(i=0,j=0;inb_streams;++i){ - ms_message("Processing for stream %i",i); + for(i=0,j=0;istreams[i]; + if (!sal_stream_description_active(ls)) continue; + ms_message("Processing for stream %i",i); rs=sal_media_description_find_stream((SalMediaDescription*)remote_answer,ls->proto,ls->type); if (rs) { initiate_outgoing(ls,rs,&result->streams[j]); @@ -522,7 +523,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;inb_streams;++i){ + for(i=0;istreams[i]; if (strcmp(ss->name,stream->name)==0){ ms_message("video stream already used in answer"); @@ -544,7 +545,7 @@ 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;inb_streams;++i){ + for(i=0;istreams[i]; if (!sal_stream_description_active(ss)) continue; if (ss->type==remote_stream->type && proto_compatible(ss->proto,remote_stream->proto) @@ -564,8 +565,9 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities int i; const SalStreamDescription *ls=NULL,*rs; - for(i=0;inb_streams;++i){ + for(i=0;istreams[i]; + if (!sal_stream_description_active(rs)) continue; if (rs->proto!=SalProtoOther){ ls=find_local_matching_stream(result,local_capabilities,rs); }else ms_warning("Unknown protocol for mline %i, declining",i); diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 4df8a2e0e..58e47310b 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -390,8 +390,8 @@ static int send_report(LinphoneCall* call, reporting_session_report_t * report, 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->nb_streams; ++count) { - if (smd->streams[count].type == sal_stream_type) { + for (count = 0; count < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++count) { + if (sal_stream_description_active(&smd->streams[count]) && smd->streams[count].type == sal_stream_type) { return &smd->streams[count]; } } diff --git a/coreapi/sal.c b/coreapi/sal.c index ba8108eae..78d1af051 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -55,7 +55,11 @@ SalTransport sal_transport_parse(const char* param) { SalMediaDescription *sal_media_description_new(){ SalMediaDescription *md=ms_new0(SalMediaDescription,1); + int i; md->refcount=1; + for(i=0;istreams[i].dir=SalStreamInactive; + } return md; } @@ -85,7 +89,7 @@ void sal_media_description_unref(SalMediaDescription *md){ SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ int i; - for(i=0;inb_streams;++i){ + for(i=0;istreams[i]; if (!sal_stream_description_active(ss)) continue; if (ss->proto==proto && ss->type==type) return ss; @@ -96,7 +100,7 @@ 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->nb_streams; ++i) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i) { if (!sal_stream_description_active(&md->streams[i])) continue; if (md->streams[i].type == type) nb++; } @@ -105,7 +109,7 @@ 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->nb_streams; ++i) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i) { if (!sal_stream_description_active(&md->streams[i])) continue; if (md->streams[i].type == type) { if (idx-- == 0) return &md->streams[i]; @@ -137,7 +141,7 @@ bool_t sal_media_description_empty(const SalMediaDescription *md){ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_dir){ int i; - for(i=0;inb_streams;++i){ + for(i=0;istreams[i]; if (!sal_stream_description_active(ss)) continue; ss->dir=stream_dir; @@ -147,7 +151,7 @@ void sal_media_description_set_dir(SalMediaDescription *md, SalStreamDir stream_ int sal_media_description_get_nb_active_streams(const SalMediaDescription *md) { int i; int nb = 0; - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (sal_stream_description_active(&md->streams[i])) nb++; } return nb; @@ -162,7 +166,7 @@ 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;inb_streams;++i){ + for(i=0;istreams[i]; if (!sal_stream_description_active(ss)) continue; if (ss->dir==stream_dir) { @@ -211,7 +215,7 @@ bool_t sal_stream_description_has_dtls(const SalStreamDescription *sd) { 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++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; if (sal_stream_description_has_avpf(&md->streams[i]) != TRUE) return FALSE; } @@ -221,7 +225,7 @@ bool_t sal_media_description_has_avpf(const SalMediaDescription *md) { 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++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; if (sal_stream_description_has_srtp(&md->streams[i]) != TRUE) return FALSE; } @@ -231,7 +235,7 @@ bool_t sal_media_description_has_srtp(const SalMediaDescription *md) { bool_t sal_media_description_has_dtls(const SalMediaDescription *md) { int i; if (md->nb_streams == 0) return FALSE; - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; if (sal_stream_description_has_dtls(&md->streams[i]) != TRUE) return FALSE; } @@ -336,7 +340,8 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD result |= SAL_MEDIA_DESCRIPTION_NETWORK_XXXCAST_CHANGED; if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED; if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; - for(i = 0; i < md1->nb_streams; ++i){ + for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ + if (!sal_stream_description_active(&md1->streams[i]) || !sal_stream_description_active(&md2->streams[i])) continue; result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } return result; diff --git a/coreapi/upnp.c b/coreapi/upnp.c index 68b82e2ed..72257ac60 100644 --- a/coreapi/upnp.c +++ b/coreapi/upnp.c @@ -698,19 +698,19 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool * Audio part */ linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtp_port:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[call->main_audio_stream_index].rtp_port:0, UPNP_CALL_RETRY_DELAY); linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[0].rtcp_port:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->media_ports[call->main_audio_stream_index].rtcp_port:0, UPNP_CALL_RETRY_DELAY); /* * Video part */ linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtp_port:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[call->main_video_stream_index].rtp_port:0, UPNP_CALL_RETRY_DELAY); linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp, - UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[1].rtcp_port:0, UPNP_CALL_RETRY_DELAY); + UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->media_ports[call->main_video_stream_index].rtcp_port:0, UPNP_CALL_RETRY_DELAY); } ms_mutex_unlock(&lupnp->mutex); @@ -731,8 +731,9 @@ int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, int i; const SalStreamDescription *stream; - for (i = 0; i < md->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { stream = &md->streams[i]; + if (!sal_stream_description_active(stream)) continue; if(stream->type == SalAudio) { audio = TRUE; } else if(stream->type == SalVideo) { @@ -1060,7 +1061,7 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription * SalStreamDescription *stream; UpnpStream *upnpStream; - for (i = 0; i < desc->nb_streams; i++) { + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { stream = &desc->streams[i]; if (!sal_stream_description_active(stream)) continue; upnpStream = NULL; From 405ca6abbdbda30457aa7890c3c81f295753b0f9 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 17 Sep 2015 11:35:57 +0200 Subject: [PATCH 08/23] Fix stream indexes computed too late --- .gitignore | 2 ++ coreapi/linphonecall.c | 46 ++++++++++++++++++++++++------------------ coreapi/misc.c | 8 ++++++++ coreapi/offeranswer.c | 2 +- coreapi/private.h | 2 ++ coreapi/sal.c | 7 ++++--- 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 36ee91daf..77767ee34 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,8 @@ coreapi/help/chatroom coreapi/help/doc/ coreapi/help/helloworld coreapi/help/registration +coreapi/help/realtimetext_receiver +coreapi/help/realtimetext_sender coreapi/test_ecc coreapi/test_lsd gtk/version_date.h diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 82e71db9e..eccae3c86 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -750,8 +750,8 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { /* Deactivate inactive streams. */ for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { - if (md->streams[i].dir == SalStreamInactive) { - md->streams[i].rtp_port = 0; + if (md->streams[i].rtp_port == 0) { + md->streams[i].dir = SalStreamInactive; md->streams[i].rtcp_port = 0; if (call->biggestdesc && i < call->biggestdesc->nb_streams) { md->streams[i].proto = call->biggestdesc->streams[i].proto; @@ -1022,7 +1022,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; - call->main_text_stream_index = params->realtimetext_enabled ? LINPHONE_CALL_STATS_TEXT : -1; + call->main_text_stream_index = params->realtimetext_enabled ? LINPHONE_CALL_STATS_TEXT : STREAM_INDEX_UNKNOWN; call->dir=LinphoneCallOutgoing; call->core=lc; @@ -1088,15 +1088,32 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c } +static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDescription *md) { + int i; + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { + if (!sal_stream_description_active(&md->streams[i])) continue; + if (md->streams[i].type == SalAudio && call->main_audio_stream_index == STREAM_INDEX_UNKNOWN) { + call->main_audio_stream_index = i; + ms_message("audio stream index updated: %i", i); + } else if (md->streams[i].type == SalVideo && call->main_video_stream_index == STREAM_INDEX_UNKNOWN) { + call->main_video_stream_index = i; + ms_message("video stream index updated: %i", i); + } else if (md->streams[i].type == SalText && call->main_text_stream_index == STREAM_INDEX_UNKNOWN) { + call->main_text_stream_index = i; + ms_message("text stream index updated: %i", i); + } + } +} + LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){ LinphoneCall *call = belle_sip_object_new(LinphoneCall); SalMediaDescription *md; LinphoneFirewallPolicy fpol; int i; - call->main_audio_stream_index = -1; - call->main_video_stream_index = -1; - call->main_text_stream_index = -1; + call->main_audio_stream_index = STREAM_INDEX_UNKNOWN; + call->main_video_stream_index = STREAM_INDEX_UNKNOWN; + call->main_text_stream_index = STREAM_INDEX_UNKNOWN; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); @@ -1106,6 +1123,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro linphone_call_incoming_select_ip_version(call); sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); + + md = sal_call_get_remote_media_description(op); + linphone_call_compute_streams_indexes(call, md); if (lc->sip_conf.ping_with_options){ #ifdef BUILD_UPNP @@ -1142,7 +1162,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro /*set privacy*/ 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 = linphone_core_video_enabled(lc) && lc->video_policy.automatically_accept; if (md) { // It is licit to receive an INVITE without SDP @@ -1159,19 +1178,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro md->streams[i].multicast_role = SalMulticastReceiver; strncpy(call->media_ports[i].multicast_ip,md->streams[i].rtp_addr,sizeof(call->media_ports[i].multicast_ip)); } - - if (sal_stream_description_active(&md->streams[i])) { - if (md->streams[i].type == SalAudio) { - call->main_audio_stream_index = i; - ms_message("audio stream index updated: %i", i); - } else if (md->streams[i].type == SalVideo) { - call->main_video_stream_index = i; - ms_message("video stream index updated: %i", i); - } else if (md->streams[i].type == SalText) { - call->main_text_stream_index = i; - ms_message("text stream index updated: %i", i); - } - } } } } diff --git a/coreapi/misc.c b/coreapi/misc.c index 6cad3002b..6ee4ab77e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -627,11 +627,13 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) const struct addrinfo *ai; IceCheckList *audio_check_list; IceCheckList *video_check_list; + IceCheckList *text_check_list; const char *server = linphone_core_get_stun_server(lc); if ((server == NULL) || (call->ice_session == NULL)) return -1; audio_check_list = ice_session_check_list(call->ice_session, 0); video_check_list = ice_session_check_list(call->ice_session, 1); + text_check_list = ice_session_check_list(call->ice_session, 2); if (audio_check_list == NULL) return -1; if (call->af==AF_INET6){ @@ -661,6 +663,12 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call) ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[call->main_video_stream_index].rtcp_port, 2, NULL); call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress; } + if (call->params->realtimetext_enabled && (text_check_list != NULL) + && (ice_check_list_state(text_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(text_check_list) == FALSE)) { + ice_add_local_candidate(text_check_list, "host", local_addr, call->media_ports[call->main_text_stream_index].rtp_port, 1, NULL); + ice_add_local_candidate(text_check_list, "host", local_addr, call->media_ports[call->main_text_stream_index].rtcp_port, 2, NULL); + call->stats[LINPHONE_CALL_STATS_TEXT].ice_state = LinphoneIceStateInProgress; + } ms_message("ICE: gathering candidate from [%s]",server); /* Gather local srflx candidates. */ diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index f36f002a7..36adfbbc1 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -544,7 +544,7 @@ 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; + int i; for(i=0;istreams[i]; if (!sal_stream_description_active(ss)) continue; diff --git a/coreapi/private.h b/coreapi/private.h index ee2f2b8e1..db684e281 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -240,6 +240,8 @@ typedef struct _PortConfig{ int rtcp_port; }PortConfig; +#define STREAM_INDEX_UNKNOWN -1 + struct _LinphoneCall{ belle_sip_object_t base; void *user_data; diff --git a/coreapi/sal.c b/coreapi/sal.c index 78d1af051..b164b2b48 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -57,8 +57,10 @@ SalMediaDescription *sal_media_description_new(){ SalMediaDescription *md=ms_new0(SalMediaDescription,1); int i; md->refcount=1; - for(i=0;istreams[i].dir=SalStreamInactive; + md->streams[i].rtp_port = 0; + md->streams[i].rtcp_port = 0; } return md; } @@ -86,8 +88,7 @@ void sal_media_description_unref(SalMediaDescription *md){ } } -SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, - SalMediaProto proto, SalStreamType type){ +SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type){ int i; for(i=0;istreams[i]; From ee7e0539806fa53c7cae9831bcf597482891f9c5 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 17 Sep 2015 14:38:00 +0200 Subject: [PATCH 09/23] Fix audio AVPF and video AVP in SDP issue --- coreapi/linphonecall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index eccae3c86..963195c09 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -697,7 +697,7 @@ void linphone_call_make_local_media_description(LinphoneCall *call) { strncpy(md->streams[call->main_video_stream_index].name,"Video",sizeof(md->streams[call->main_video_stream_index].name)-1); md->streams[call->main_video_stream_index].rtp_port=call->media_ports[call->main_video_stream_index].rtp_port; md->streams[call->main_video_stream_index].rtcp_port=call->media_ports[call->main_video_stream_index].rtcp_port; - md->streams[call->main_video_stream_index].proto=md->streams[call->main_video_stream_index].proto; + md->streams[call->main_video_stream_index].proto=md->streams[call->main_audio_stream_index].proto; md->streams[call->main_video_stream_index].dir=get_video_dir_from_call_params(params); md->streams[call->main_video_stream_index].type=SalVideo; codec_hints.bandwidth_limit=0; From 9127666fe5cf3404165ab173ac72671e9e918e80 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 17 Sep 2015 16:00:09 +0200 Subject: [PATCH 10/23] Do not use -1 for unused steams, instead use an unused index --- coreapi/linphonecall.c | 79 ++++++++++++++++++++++++++++++++++-------- coreapi/private.h | 2 -- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 963195c09..dbf8ab47b 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -881,10 +881,8 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, linphone_core_get_video_port_range(call->core, &min_port, &max_port); port_config_set(call,call->main_video_stream_index,min_port,max_port); - if (call->params->realtimetext_enabled) { - linphone_core_get_text_port_range(call->core, &min_port, &max_port); - port_config_set(call,call->main_text_stream_index,min_port,max_port); - } + linphone_core_get_text_port_range(call->core, &min_port, &max_port); + port_config_set(call,call->main_text_stream_index,min_port,max_port); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO); linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO); @@ -1022,7 +1020,7 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; - call->main_text_stream_index = params->realtimetext_enabled ? LINPHONE_CALL_STATS_TEXT : STREAM_INDEX_UNKNOWN; + call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT; call->dir=LinphoneCallOutgoing; call->core=lc; @@ -1089,18 +1087,73 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c } static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDescription *md) { - int i; + int i, j; + for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; - if (md->streams[i].type == SalAudio && call->main_audio_stream_index == STREAM_INDEX_UNKNOWN) { + if (md->streams[i].type == SalAudio && i != call->main_audio_stream_index) { call->main_audio_stream_index = i; ms_message("audio stream index updated: %i", i); - } else if (md->streams[i].type == SalVideo && call->main_video_stream_index == STREAM_INDEX_UNKNOWN) { + + // Check that the default value of a another stream doesn't match the new one + if (i == call->main_video_stream_index) { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (j != call->main_video_stream_index && j != call->main_text_stream_index) { + call->main_video_stream_index = j; + break; + } + } + } + if (i == call->main_text_stream_index) { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (j != call->main_video_stream_index && j != call->main_text_stream_index) { + call->main_text_stream_index = j; + break; + } + } + } + } else if (md->streams[i].type == SalVideo && i != call->main_video_stream_index) { call->main_video_stream_index = i; ms_message("video stream index updated: %i", i); - } else if (md->streams[i].type == SalText && call->main_text_stream_index == STREAM_INDEX_UNKNOWN) { + + // Check that the default value of a another stream doesn't match the new one + if (i == call->main_audio_stream_index) { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { + call->main_audio_stream_index = j; + break; + } + } + } + if (i == call->main_text_stream_index) { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { + call->main_text_stream_index = j; + break; + } + } + } + } else if (md->streams[i].type == SalText && i != call->main_text_stream_index) { call->main_text_stream_index = i; ms_message("text stream index updated: %i", i); + + // Check that the default value of a another stream doesn't match the new one + if (i == call->main_video_stream_index) { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { + call->main_video_stream_index = j; + break; + } + } + } + if (i == call->main_audio_stream_index) { + for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { + call->main_audio_stream_index = j; + break; + } + } + } } } } @@ -1111,9 +1164,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro LinphoneFirewallPolicy fpol; int i; - call->main_audio_stream_index = STREAM_INDEX_UNKNOWN; - call->main_video_stream_index = STREAM_INDEX_UNKNOWN; - call->main_text_stream_index = STREAM_INDEX_UNKNOWN; + call->main_audio_stream_index = LINPHONE_CALL_STATS_AUDIO; + call->main_video_stream_index = LINPHONE_CALL_STATS_VIDEO; + call->main_text_stream_index = LINPHONE_CALL_STATS_TEXT; call->dir=LinphoneCallIncoming; sal_op_set_user_pointer(op,call); @@ -2105,7 +2158,6 @@ void linphone_call_init_audio_stream(LinphoneCall *call){ char rtcp_tool[128]={0}; char* cname; - snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); if (call->audiostream != NULL) return; @@ -2202,7 +2254,6 @@ void linphone_call_init_video_stream(LinphoneCall *call){ char* cname; char rtcp_tool[128]; - snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version()); if (call->videostream == NULL){ diff --git a/coreapi/private.h b/coreapi/private.h index db684e281..ee2f2b8e1 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -240,8 +240,6 @@ typedef struct _PortConfig{ int rtcp_port; }PortConfig; -#define STREAM_INDEX_UNKNOWN -1 - struct _LinphoneCall{ belle_sip_object_t base; void *user_data; From 0b8dd545355d480a08634f3c726f5e2ad9807f36 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 17 Sep 2015 17:10:02 +0200 Subject: [PATCH 11/23] Fix crash in test Call without SDP --- coreapi/linphonecall.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index dbf8ab47b..200304a8b 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1178,7 +1178,9 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); md = sal_call_get_remote_media_description(op); - linphone_call_compute_streams_indexes(call, md); + if (md) { + linphone_call_compute_streams_indexes(call, md); + } if (lc->sip_conf.ping_with_options){ #ifdef BUILD_UPNP From cae3cd4f8d62e453dfc1d3c88295e1d846112fe3 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Thu, 17 Sep 2015 17:25:02 +0200 Subject: [PATCH 12/23] Fixed stun tester --- coreapi/misc.c | 7 +++---- tester/stun_tester.c | 13 +++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/coreapi/misc.c b/coreapi/misc.c index 6ee4ab77e..edad63c93 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -443,10 +443,9 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){ sock2=create_socket(call->media_ports[call->main_video_stream_index].rtp_port); if (sock2==-1) return -1; } - if (call->params->realtimetext_enabled) { - sock3=create_socket(call->media_ports[call->main_text_stream_index].rtp_port); - if (sock3==-1) return -1; - } + sock3=create_socket(call->media_ports[call->main_text_stream_index].rtp_port); + if (sock3==-1) return -1; + got_audio=FALSE; got_video=FALSE; got_text=FALSE; diff --git a/tester/stun_tester.c b/tester/stun_tester.c index 89762cab3..af2935194 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -72,8 +72,12 @@ static void linphone_stun_test_grab_ip() int tmp=0; memset(&dummy_call, 0, sizeof(LinphoneCall)); - dummy_call.media_ports[0].rtp_port = 7078; - dummy_call.media_ports[1].rtp_port = 9078; + dummy_call.main_audio_stream_index = 0; + dummy_call.main_video_stream_index = 1; + dummy_call.main_text_stream_index = 2; + dummy_call.media_ports[dummy_call.main_audio_stream_index].rtp_port = 7078; + dummy_call.media_ports[dummy_call.main_video_stream_index].rtp_port = 9078; + dummy_call.media_ports[dummy_call.main_text_stream_index].rtp_port = 11078; linphone_core_set_stun_server(lc_stun->lc, stun_address); BC_ASSERT_STRING_EQUAL(stun_address, linphone_core_get_stun_server(lc_stun->lc)); @@ -91,6 +95,8 @@ static void linphone_stun_test_grab_ip() BC_ASSERT( dummy_call.vc.addr[0] != '\0'); BC_ASSERT( dummy_call.vc.port != 0); #endif + BC_ASSERT( dummy_call.tc.addr[0] != '\0'); + BC_ASSERT( dummy_call.tc.port != 0); ms_message("STUN test result: local audio port maps to %s:%i", dummy_call.ac.addr, @@ -100,6 +106,9 @@ static void linphone_stun_test_grab_ip() dummy_call.vc.addr, dummy_call.vc.port); #endif + ms_message("STUN test result: local text port maps to %s:%i", + dummy_call.tc.addr, + dummy_call.tc.port); linphone_core_manager_destroy(lc_stun); } From 84a59d62f1fbeac0f811470f16327074d936da88 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 18 Sep 2015 14:52:01 +0200 Subject: [PATCH 13/23] Fixed nb_stream variable in resultdesc and fixed test to detect change between two media descs --- coreapi/offeranswer.c | 4 +++- coreapi/sal.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 36adfbbc1..28b994657 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -564,6 +564,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities SalMediaDescription *result, bool_t one_matching_codec){ int i; const SalStreamDescription *ls=NULL,*rs; + result->nb_streams = 0; for(i=0;istreams[i]; @@ -588,6 +589,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities result->streams[i].rtcp_xr.enabled = TRUE; } } + result->nb_streams++; }else { ms_message("Declining mline %i, no corresponding stream in local capabilities description.",i); /* create an inactive stream for the answer, as there where no matching stream in local capabilities */ @@ -603,7 +605,7 @@ int offer_answer_initiate_incoming(const SalMediaDescription *local_capabilities } } } - 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/sal.c b/coreapi/sal.c index b164b2b48..e25c80103 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -342,7 +342,7 @@ int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaD if (md1->nb_streams != md2->nb_streams) result |= SAL_MEDIA_DESCRIPTION_STREAMS_CHANGED; if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; for(i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; ++i){ - if (!sal_stream_description_active(&md1->streams[i]) || !sal_stream_description_active(&md2->streams[i])) continue; + if (!sal_stream_description_active(&md1->streams[i]) && !sal_stream_description_active(&md2->streams[i])) continue; result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } return result; From 9a792cbbf7e216bbe7bb33c20d863dbb7f4855a6 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 21 Sep 2015 16:29:35 +0200 Subject: [PATCH 14/23] Added log to see which index have each stream --- coreapi/linphonecall.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 200304a8b..7e5377efc 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1099,6 +1099,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe if (i == call->main_video_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { if (j != call->main_video_stream_index && j != call->main_text_stream_index) { + ms_message("%i was used for video stream ; now using %i", i, j); call->main_video_stream_index = j; break; } @@ -1107,6 +1108,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe if (i == call->main_text_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { if (j != call->main_video_stream_index && j != call->main_text_stream_index) { + ms_message("%i was used for text stream ; now using %i", i, j); call->main_text_stream_index = j; break; } @@ -1120,6 +1122,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe if (i == call->main_audio_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { + ms_message("%i was used for audio stream ; now using %i", i, j); call->main_audio_stream_index = j; break; } @@ -1128,6 +1131,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe if (i == call->main_text_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { + ms_message("%i was used for text stream ; now using %i", i, j); call->main_text_stream_index = j; break; } @@ -1141,6 +1145,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe if (i == call->main_video_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { + ms_message("%i was used for video stream ; now using %i", i, j); call->main_video_stream_index = j; break; } @@ -1149,6 +1154,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe if (i == call->main_audio_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { + ms_message("%i was used for audio stream ; now using %i", i, j); call->main_audio_stream_index = j; break; } From a42c3ee85e1c5a845d537afe68bdccb00d0cd98b Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 16 Sep 2015 16:46:51 +0200 Subject: [PATCH 15/23] add SIPP based tests --- configure.ac | 6 ++- tester/CMakeLists.txt | 10 +++- tester/Makefile.am | 3 +- tester/complex_sip_call.c | 105 ++++++++++++++++++++++++++++++++++++ tester/liblinphone_tester.h | 3 ++ tester/tester.c | 3 ++ 6 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 tester/complex_sip_call.c diff --git a/configure.ac b/configure.ac index c69661a8d..cd9f90903 100644 --- a/configure.ac +++ b/configure.ac @@ -132,7 +132,7 @@ AC_CONFIG_COMMANDS([libtool-hacking], dnl Add the languages which your application supports here. PKG_PROG_PKG_CONFIG -ALL_LINGUAS=$(cd po && echo *.po | sed 's/\.po//g') +ALL_LINGUAS=$(cd $srcdir/po && echo *.po | sed 's/\.po//g') AC_SUBST(ALL_LINGUAS) AC_DEFINE_UNQUOTED(LINPHONE_ALL_LANGS, "$ALL_LINGUAS", [All supported languages]) @@ -1057,6 +1057,10 @@ else fi AM_CONDITIONAL(HAVE_DOXYGEN, test "$DOXYGEN" != "false") +AC_CHECK_PROG([SIPP],[sipp], [true], [false]) +if test "x$SIPP" != "xfalse" ; then + AC_DEFINE(HAVE_SIPP,1,[defined when SIPP is available]) +fi AC_CONFIG_FILES([ Makefile diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 2b02ff6c0..811ee839f 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -45,7 +45,15 @@ set(SOURCE_FILES tunnel_tester.c upnp_tester.c video_tester.c -) + complex_sip_call.c + ) + +find_program(SIPP_PROGRAM NAMES sipp sipp.exe) +if(SIPP_PROGRAM) + add_definitions(-DHAVE_SIPP=1) +else() + message(WARNING "Could not find sipp!") +endif() add_definitions(-DBC_CONFIG_FILE="config.h") diff --git a/tester/Makefile.am b/tester/Makefile.am index c3c3552b1..deeb21149 100644 --- a/tester/Makefile.am +++ b/tester/Makefile.am @@ -33,7 +33,8 @@ liblinphonetester_la_SOURCES = \ tester.c \ upnp_tester.c \ video_tester.c \ - common/bc_tester_utils.c + common/bc_tester_utils.c \ + complex_sip_call.c liblinphonetester_ladir = $(includedir)/linphone liblinphonetester_la_HEADERS = common/bc_tester_utils.h diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c new file mode 100644 index 000000000..1a1ea750b --- /dev/null +++ b/tester/complex_sip_call.c @@ -0,0 +1,105 @@ +/* + liblinphone_tester - liblinphone test suite + Copyright (C) 2015 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, see . +*/ + + +#include "linphonecore.h" +#include "liblinphone_tester.h" +#include "lpconfig.h" +#include "private.h" + + +static FILE *sip_start(const char *senario, const char* dest_username, LinphoneAddress* dest_addres) { + char *dest; + char *command; + FILE *file; + + if (linphone_address_get_port(dest_addres)>0) + dest = ms_strdup_printf("%s:%i",linphone_address_get_domain(dest_addres),linphone_address_get_port(dest_addres)); + else + dest = ms_strdup_printf("%s",linphone_address_get_domain(dest_addres)); + + command = ms_strdup_printf("sipp -sf %s -s %s %s -trace_err -trace_msg -m 1 -d 1000 ",senario,dest_username,dest); + + ms_message("Starting sipp commad [%s]",command); + file = popen(command, "r"); + ms_free(command); + ms_free(dest); + return file; +} +/*static void dest_server_server_resolved(void *data, const char *name, struct addrinfo *ai_list) { + *(struct addrinfo **)data =ai_list; +}*/ +static void sip_update_within_icoming_reinvite_with_no_sdp(void) { + LinphoneCoreManager *mgr; +/* LinphoneProxyConfig *proxy = linphone_core_get_default_proxy_config(mgr->lc); + LinphoneAddress *dest = linphone_address_new(linphone_proxy_config_get_route(proxy) ?linphone_proxy_config_get_route(proxy):linphone_proxy_config_get_server_addr(proxy)); + struct addrinfo *addrinfo = NULL; + char ipstring [INET6_ADDRSTRLEN]; + int err; + int port = linphone_address_get_port(dest);*/ + char *identity_char; + + /*currently we use direct connection because sipp do not properly set ACK request uri*/ + mgr= linphone_core_manager_new2( "empty_rc", FALSE); + mgr->identity= linphone_core_get_primary_contact_parsed(mgr->lc); + linphone_address_set_username(mgr->identity,"marie"); + identity_char=linphone_address_as_string(mgr->identity); + linphone_core_set_primary_contact(mgr->lc,identity_char); + linphone_core_iterate(mgr->lc); + /* + sal_resolve_a( mgr->lc->sal + ,linphone_address_get_domain(dest) + ,linphone_address_get_port(dest) + ,AF_INET + ,(SalResolverCallback)dest_server_server_resolved + ,&addrinfo); + linphone_address_destroy(dest); + dest=linphone_address_new(NULL); + + wait_for(mgr->lc, mgr->lc, (int*)&addrinfo, 1); + err=getnameinfo((struct sockaddr *)addrinfo->ai_addr,addrinfo->ai_addrlen,ipstring,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST); + linphone_address_set_domain(dest, ipstring); + if (port > 0) + linphone_address_set_port(dest, port); + */ + char* scen = bc_tester_res("sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml"); + + FILE * sipp_out = sip_start(scen + , linphone_address_get_username(mgr->identity) + , mgr->identity); + + if (sipp_out) { + BC_ASSERT_TRUE(wait_for_until(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1,100000)); + linphone_core_accept_call(mgr->lc, linphone_core_get_current_call(mgr->lc)); + BC_ASSERT_TRUE(wait_for_until(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,100000)); + } + +} + +static test_t tests[] = { + { "SIP UPDATE within incoming reinvite witjout sdp", sip_update_within_icoming_reinvite_with_no_sdp}, +}; + +test_suite_t complex_sip_call_test_suite = { + "Complex SIP Call", + liblinphone_tester_setup, + NULL, + sizeof(tests) / sizeof(tests[0]), + tests +}; + diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index c3db2bf5e..f8b3de47a 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -52,6 +52,9 @@ extern test_suite_t video_test_suite; extern test_suite_t multicast_call_test_suite; extern test_suite_t multi_call_test_suite; extern test_suite_t proxy_config_test_suite; +#if HAVE_SIPP +extern test_suite_t complex_sip_call_test_suite; +#endif extern int manager_count; extern int liblinphone_tester_ipv6_available(void); diff --git a/tester/tester.c b/tester/tester.c index eded255ed..59da2fcaa 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -436,6 +436,9 @@ void liblinphone_tester_add_suites() { #endif bc_tester_add_suite(&multicast_call_test_suite); bc_tester_add_suite(&proxy_config_test_suite); +#if HAVE_SIPP + bc_tester_add_suite(&complex_sip_call_test_suite); +#endif } static int linphone_core_manager_get_max_audio_bw_base(const int array[],int array_size) { From 7c36fbc0053afd30c65eee0babdb99e582d37580 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 16 Sep 2015 17:36:05 +0200 Subject: [PATCH 16/23] add missing sipp scenario --- ...te_within_icoming_reinvite_with_no_sdp.xml | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 tester/sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml diff --git a/tester/sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml b/tester/sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml new file mode 100644 index 000000000..eef5c3cd2 --- /dev/null +++ b/tester/sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 0 + a=rtpmap:0 PCMU/8000 + + ]]> + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 INVITE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 3 UPDATE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 ACK + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 0 + a=rtpmap:0 PCMU/8000 + + ]]> + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 4 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + + + + + + From 60807065ca08d66762d1e223fec827e34daa818f Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Wed, 16 Sep 2015 21:14:40 +0200 Subject: [PATCH 17/23] fix compilation issue --- tester/complex_sip_call.c | 13 +++++++++---- tester/flexisip/flexisip.conf | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c index 1a1ea750b..40bfe7999 100644 --- a/tester/complex_sip_call.c +++ b/tester/complex_sip_call.c @@ -53,6 +53,8 @@ static void sip_update_within_icoming_reinvite_with_no_sdp(void) { int err; int port = linphone_address_get_port(dest);*/ char *identity_char; + char *scen; + FILE * sipp_out; /*currently we use direct connection because sipp do not properly set ACK request uri*/ mgr= linphone_core_manager_new2( "empty_rc", FALSE); @@ -77,17 +79,20 @@ static void sip_update_within_icoming_reinvite_with_no_sdp(void) { if (port > 0) linphone_address_set_port(dest, port); */ - char* scen = bc_tester_res("sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml"); + scen = bc_tester_res("sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml"); - FILE * sipp_out = sip_start(scen + sipp_out = sip_start(scen , linphone_address_get_username(mgr->identity) , mgr->identity); if (sipp_out) { - BC_ASSERT_TRUE(wait_for_until(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1,100000)); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1)); linphone_core_accept_call(mgr->lc, linphone_core_get_current_call(mgr->lc)); - BC_ASSERT_TRUE(wait_for_until(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2,100000)); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2)); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); + pclose(sipp_out); } + linphone_core_manager_destroy(mgr); } diff --git a/tester/flexisip/flexisip.conf b/tester/flexisip/flexisip.conf index 7fe250368..f1cce0bef 100644 --- a/tester/flexisip/flexisip.conf +++ b/tester/flexisip/flexisip.conf @@ -40,7 +40,7 @@ aliases=localhost sip2.linphone.org sipopen.example.org sip.example.org auth.exa #note: the ip addresses are explicitely specified here because the machine has several interfaces. In a simple case, using '*' instead of the explicit ip address is sufficient, #and there is no need to specify the ipv6 transport addresses. -transports=sip:94.23.19.176:5060 sips:94.23.19.176:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:94.23.19.176:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:94.23.19.176:5063;require-peer-certificate=1 sip:94.23.19.176:5064 sip:[2001:41d0:2:14b0::1]:5060 sips:[2001:41d0:2:14b0::1]:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:[2001:41d0:2:14b0::1]:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:[2001:41d0:2:14b0::1]:5063;require-peer-certificate=1 sip:[2001:41d0:2:14b0::1]:5064 +transports=sip:MacBook-Pro-de-jehan.local:5060 sips:MacBook-Pro-de-jehan.local:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:MacBook-Pro-de-jehan.local:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:MacBook-Pro-de-jehan.local:5063;require-peer-certificate=1 sip:MacBook-Pro-de-jehan.local:5064 sip:[2001:41d0:2:14b0::1]:5060 sips:[2001:41d0:2:14b0::1]:5061;tls-certificates-dir=/etc/flexisip/tls/certificates/cn sips:[2001:41d0:2:14b0::1]:5062;tls-certificates-dir=/etc/flexisip/tls/certificates/altname sips:[2001:41d0:2:14b0::1]:5063;require-peer-certificate=1 sip:[2001:41d0:2:14b0::1]:5064 # An absolute path of a directory where TLS server certificate and From 9a99b97a40f2a1d9fc647cfcb7a251e51cbec3c0 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 21 Sep 2015 17:14:03 +0200 Subject: [PATCH 18/23] Fix remaining stream_index == 0 ? audio stream : video stream issue + test to check call with video mline before audio in sdp --- .gitignore | 1 + coreapi/linphonecall.c | 2 +- tester/complex_sip_call.c | 42 +++++- ...l_with_video_mline_before_audio_in_sdp.xml | 125 ++++++++++++++++++ 4 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 tester/sipp/call_with_video_mline_before_audio_in_sdp.xml diff --git a/.gitignore b/.gitignore index 77767ee34..55975848a 100644 --- a/.gitignore +++ b/.gitignore @@ -94,3 +94,4 @@ tester/ZIDCache*.xml tester/stereo-record.wav .dirstamp git-clang-format.diff +tester/sipp/*.log diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 7e5377efc..3b482be9b 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2044,7 +2044,7 @@ static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, } static void _linphone_call_prepare_ice_for_stream(LinphoneCall *call, int stream_index, bool_t create_checklist){ - MediaStream *ms=stream_index == 0 ? (MediaStream*)call->audiostream : (MediaStream*)call->videostream; + MediaStream *ms = stream_index == call->main_audio_stream_index ? (MediaStream*)call->audiostream : stream_index == call->main_video_stream_index ? (MediaStream*)call->videostream : (MediaStream*)call->textstream; if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL)){ IceCheckList *cl; rtp_session_set_pktinfo(ms->sessions.rtp_session, TRUE); diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c index 40bfe7999..ee5858df0 100644 --- a/tester/complex_sip_call.c +++ b/tester/complex_sip_call.c @@ -33,7 +33,7 @@ static FILE *sip_start(const char *senario, const char* dest_username, LinphoneA else dest = ms_strdup_printf("%s",linphone_address_get_domain(dest_addres)); - command = ms_strdup_printf("sipp -sf %s -s %s %s -trace_err -trace_msg -m 1 -d 1000 ",senario,dest_username,dest); + command = ms_strdup_printf("sipp -sf %s -s %s %s -trace_err -trace_msg -rtp_echo -m 1 -d 1000",senario,dest_username,dest); ms_message("Starting sipp commad [%s]",command); file = popen(command, "r"); @@ -81,9 +81,7 @@ static void sip_update_within_icoming_reinvite_with_no_sdp(void) { */ scen = bc_tester_res("sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml"); - sipp_out = sip_start(scen - , linphone_address_get_username(mgr->identity) - , mgr->identity); + sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), mgr->identity); if (sipp_out) { BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1)); @@ -96,8 +94,42 @@ static void sip_update_within_icoming_reinvite_with_no_sdp(void) { } +static void call_with_video_mline_before_audio_in_sdp() { + LinphoneCoreManager *mgr; + char *identity_char; + char *scen; + FILE * sipp_out; + LinphoneCall *call = NULL; + + /*currently we use direct connection because sipp do not properly set ACK request uri*/ + mgr= linphone_core_manager_new2( "empty_rc", FALSE); + mgr->identity= linphone_core_get_primary_contact_parsed(mgr->lc); + linphone_address_set_username(mgr->identity,"marie"); + identity_char=linphone_address_as_string(mgr->identity); + linphone_core_set_primary_contact(mgr->lc,identity_char); + + linphone_core_iterate(mgr->lc); + + scen = bc_tester_res("sipp/call_with_video_mline_before_audio_in_sdp.xml"); + + sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), mgr->identity); + + if (sipp_out) { + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1)); + call = linphone_core_get_current_call(mgr->lc); + linphone_core_accept_call(mgr->lc, call); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_EQUAL(call->main_audio_stream_index, 1, int, "%d"); + BC_ASSERT_EQUAL(call->main_video_stream_index, 0, int, "%d"); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); + pclose(sipp_out); + } + linphone_core_manager_destroy(mgr); +} + static test_t tests[] = { - { "SIP UPDATE within incoming reinvite witjout sdp", sip_update_within_icoming_reinvite_with_no_sdp}, + { "SIP UPDATE within incoming reinvite without sdp", sip_update_within_icoming_reinvite_with_no_sdp }, + { "Call with video mline before audio in sdp", call_with_video_mline_before_audio_in_sdp }, }; test_suite_t complex_sip_call_test_suite = { diff --git a/tester/sipp/call_with_video_mline_before_audio_in_sdp.xml b/tester/sipp/call_with_video_mline_before_audio_in_sdp.xml new file mode 100644 index 000000000..bfb150cee --- /dev/null +++ b/tester/sipp/call_with_video_mline_before_audio_in_sdp.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=video [media_port+2] RTP/AVP 96 + a=rtpmap:96 VP8/90000 + m=audio [media_port] RTP/AVP 96 97 0 8 101 98 + a=rtpmap:96 speex/16000 + a=fmtp:96 vbr=on + a=rtpmap:97 speex/8000 + a=fmtp:97 vbr=on + a=rtpmap:101 telephone-event/16000 + a=rtpmap:98 telephone-event/8000 + + ]]> + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + + + + + From a8830ebf2b2472b189a070c1a1b6e17e6f499446 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 21 Sep 2015 17:50:30 +0200 Subject: [PATCH 19/23] Moved check rtcp tests to function + added few more asserts --- tester/complex_sip_call.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c index ee5858df0..8cbec7605 100644 --- a/tester/complex_sip_call.c +++ b/tester/complex_sip_call.c @@ -22,6 +22,23 @@ #include "lpconfig.h" #include "private.h" +void check_rtcp(LinphoneCall *call) { + MSTimeSpec ts; + + linphone_call_ref(call); + liblinphone_tester_clock_start(&ts); + do { + if (linphone_call_get_audio_stats(call)->round_trip_delay > 0.0 && (!linphone_call_log_video_enabled(linphone_call_get_call_log(call)) || linphone_call_get_video_stats(call)->round_trip_delay>0.0)) { + break; + } + } while (!liblinphone_tester_clock_elapsed(&ts, 15000)); + BC_ASSERT_GREATER(linphone_call_get_audio_stats(call)->round_trip_delay,0.0,float,"%f"); + if (linphone_call_log_video_enabled(linphone_call_get_call_log(call))) { + BC_ASSERT_GREATER(linphone_call_get_video_stats(call)->round_trip_delay,0.0,float,"%f"); + } + + linphone_call_unref(call); +} static FILE *sip_start(const char *senario, const char* dest_username, LinphoneAddress* dest_addres) { char *dest; @@ -103,11 +120,11 @@ static void call_with_video_mline_before_audio_in_sdp() { /*currently we use direct connection because sipp do not properly set ACK request uri*/ mgr= linphone_core_manager_new2( "empty_rc", FALSE); - mgr->identity= linphone_core_get_primary_contact_parsed(mgr->lc); + mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc); linphone_address_set_username(mgr->identity,"marie"); - identity_char=linphone_address_as_string(mgr->identity); + identity_char = linphone_address_as_string(mgr->identity); linphone_core_set_primary_contact(mgr->lc,identity_char); - + linphone_core_iterate(mgr->lc); scen = bc_tester_res("sipp/call_with_video_mline_before_audio_in_sdp.xml"); @@ -121,6 +138,11 @@ static void call_with_video_mline_before_audio_in_sdp() { BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); BC_ASSERT_EQUAL(call->main_audio_stream_index, 1, int, "%d"); BC_ASSERT_EQUAL(call->main_video_stream_index, 0, int, "%d"); + BC_ASSERT_TRUE(call->main_text_stream_index > 1); + BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); + + check_rtcp(call); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); pclose(sipp_out); } From 8b4db40d777f1f03f1a4e59e50ba37d745e04116 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 21 Sep 2015 17:54:41 +0200 Subject: [PATCH 20/23] Forgot wait_for in check_rtcp loop --- tester/complex_sip_call.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c index 8cbec7605..34c6496f1 100644 --- a/tester/complex_sip_call.c +++ b/tester/complex_sip_call.c @@ -27,14 +27,17 @@ void check_rtcp(LinphoneCall *call) { linphone_call_ref(call); liblinphone_tester_clock_start(&ts); + do { - if (linphone_call_get_audio_stats(call)->round_trip_delay > 0.0 && (!linphone_call_log_video_enabled(linphone_call_get_call_log(call)) || linphone_call_get_video_stats(call)->round_trip_delay>0.0)) { + if (linphone_call_get_audio_stats(call)->round_trip_delay > 0.0 && (!linphone_call_log_video_enabled(linphone_call_get_call_log(call)) || linphone_call_get_video_stats(call)->round_trip_delay > 0.0)) { break; } + wait_for_until(call->core, NULL, NULL, 0, 20); /*just to sleep while iterating*/ } while (!liblinphone_tester_clock_elapsed(&ts, 15000)); - BC_ASSERT_GREATER(linphone_call_get_audio_stats(call)->round_trip_delay,0.0,float,"%f"); + + BC_ASSERT_GREATER(linphone_call_get_audio_stats(call)->round_trip_delay, 0.0, float, "%f"); if (linphone_call_log_video_enabled(linphone_call_get_call_log(call))) { - BC_ASSERT_GREATER(linphone_call_get_video_stats(call)->round_trip_delay,0.0,float,"%f"); + BC_ASSERT_GREATER(linphone_call_get_video_stats(call)->round_trip_delay, 0.0, float, "%f"); } linphone_call_unref(call); From db6cb81f91268f05ad4c4437f535ac429717fe47 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 22 Sep 2015 09:43:37 +0200 Subject: [PATCH 21/23] Added test for classic call with audio mline before video --- tester/complex_sip_call.c | 39 ++++++ ...l_with_audio_mline_before_video_in_sdp.xml | 125 ++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tester/sipp/call_with_audio_mline_before_video_in_sdp.xml diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c index 34c6496f1..beeb62cdb 100644 --- a/tester/complex_sip_call.c +++ b/tester/complex_sip_call.c @@ -114,6 +114,44 @@ static void sip_update_within_icoming_reinvite_with_no_sdp(void) { } +static void call_with_audio_mline_before_video_in_sdp() { + LinphoneCoreManager *mgr; + char *identity_char; + char *scen; + FILE * sipp_out; + LinphoneCall *call = NULL; + + /*currently we use direct connection because sipp do not properly set ACK request uri*/ + mgr= linphone_core_manager_new2( "empty_rc", FALSE); + mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc); + linphone_address_set_username(mgr->identity,"marie"); + identity_char = linphone_address_as_string(mgr->identity); + linphone_core_set_primary_contact(mgr->lc,identity_char); + + linphone_core_iterate(mgr->lc); + + scen = bc_tester_res("sipp/call_with_audio_mline_before_video_in_sdp.xml"); + + sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), mgr->identity); + + if (sipp_out) { + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1)); + call = linphone_core_get_current_call(mgr->lc); + linphone_core_accept_call(mgr->lc, call); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d"); + BC_ASSERT_EQUAL(call->main_video_stream_index, 1, int, "%d"); + BC_ASSERT_TRUE(call->main_text_stream_index > 1); + BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); + + check_rtcp(call); + + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); + pclose(sipp_out); + } + linphone_core_manager_destroy(mgr); +} + static void call_with_video_mline_before_audio_in_sdp() { LinphoneCoreManager *mgr; char *identity_char; @@ -154,6 +192,7 @@ static void call_with_video_mline_before_audio_in_sdp() { static test_t tests[] = { { "SIP UPDATE within incoming reinvite without sdp", sip_update_within_icoming_reinvite_with_no_sdp }, + { "Call with audio mline before video in sdp", call_with_audio_mline_before_video_in_sdp }, { "Call with video mline before audio in sdp", call_with_video_mline_before_audio_in_sdp }, }; diff --git a/tester/sipp/call_with_audio_mline_before_video_in_sdp.xml b/tester/sipp/call_with_audio_mline_before_video_in_sdp.xml new file mode 100644 index 000000000..376a4aeb7 --- /dev/null +++ b/tester/sipp/call_with_audio_mline_before_video_in_sdp.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 96 97 0 8 101 98 + a=rtpmap:96 speex/16000 + a=fmtp:96 vbr=on + a=rtpmap:97 speex/8000 + a=fmtp:97 vbr=on + a=rtpmap:101 telephone-event/16000 + a=rtpmap:98 telephone-event/8000 + m=video [media_port+2] RTP/AVP 96 + a=rtpmap:96 VP8/90000 + + ]]> + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + + + + + From 0e439d9196841566c576d6bde4c8f9a08db9d869 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 22 Sep 2015 10:47:43 +0200 Subject: [PATCH 22/23] Fix and test for multiple mlines of same type in sdp --- coreapi/linphonecall.c | 52 +++++-- tester/complex_sip_call.c | 39 ++++++ .../call_with_multiple_audio_mline_in_sdp.xml | 132 ++++++++++++++++++ 3 files changed, 208 insertions(+), 15 deletions(-) create mode 100644 tester/sipp/call_with_multiple_audio_mline_in_sdp.xml diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 3b482be9b..43153a0cb 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -1088,16 +1088,23 @@ void linphone_call_set_compatible_incoming_call_parameters(LinphoneCall *call, c static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDescription *md) { int i, j; + bool_t audio_found = FALSE, video_found = FALSE, text_found = FALSE; for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; i++) { if (!sal_stream_description_active(&md->streams[i])) continue; - if (md->streams[i].type == SalAudio && i != call->main_audio_stream_index) { - call->main_audio_stream_index = i; - ms_message("audio stream index updated: %i", i); + if (md->streams[i].type == SalAudio) { + if (!audio_found) { + call->main_audio_stream_index = i; + audio_found = TRUE; + ms_message("audio stream index found: %i, updating main audio stream index", i); + } else { + ms_message("audio stream index found: %i, but main audio stream already set to %i", i, call->main_audio_stream_index); + } // Check that the default value of a another stream doesn't match the new one if (i == call->main_video_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) continue; if (j != call->main_video_stream_index && j != call->main_text_stream_index) { ms_message("%i was used for video stream ; now using %i", i, j); call->main_video_stream_index = j; @@ -1107,6 +1114,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe } if (i == call->main_text_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) continue; if (j != call->main_video_stream_index && j != call->main_text_stream_index) { ms_message("%i was used for text stream ; now using %i", i, j); call->main_text_stream_index = j; @@ -1114,13 +1122,19 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe } } } - } else if (md->streams[i].type == SalVideo && i != call->main_video_stream_index) { - call->main_video_stream_index = i; - ms_message("video stream index updated: %i", i); + } else if (md->streams[i].type == SalVideo) { + if (!video_found) { + call->main_video_stream_index = i; + video_found = TRUE; + ms_message("video stream index found: %i, updating main video stream index", i); + } else { + ms_message("video stream index found: %i, but main video stream already set to %i", i, call->main_video_stream_index); + } // Check that the default value of a another stream doesn't match the new one if (i == call->main_audio_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) continue; if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { ms_message("%i was used for audio stream ; now using %i", i, j); call->main_audio_stream_index = j; @@ -1130,6 +1144,7 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe } if (i == call->main_text_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) continue; if (j != call->main_audio_stream_index && j != call->main_text_stream_index) { ms_message("%i was used for text stream ; now using %i", i, j); call->main_text_stream_index = j; @@ -1137,25 +1152,32 @@ static void linphone_call_compute_streams_indexes(LinphoneCall *call, SalMediaDe } } } - } else if (md->streams[i].type == SalText && i != call->main_text_stream_index) { - call->main_text_stream_index = i; - ms_message("text stream index updated: %i", i); + } else if (md->streams[i].type == SalText) { + if (!text_found) { + call->main_text_stream_index = i; + text_found = TRUE; + ms_message("text stream index found: %i, updating main text stream index", i); + } else { + ms_message("text stream index found: %i, but main text stream already set to %i", i, call->main_text_stream_index); + } // Check that the default value of a another stream doesn't match the new one - if (i == call->main_video_stream_index) { + if (i == call->main_audio_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) continue; if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { - ms_message("%i was used for video stream ; now using %i", i, j); - call->main_video_stream_index = j; + ms_message("%i was used for audio stream ; now using %i", i, j); + call->main_audio_stream_index = j; break; } } } - if (i == call->main_audio_stream_index) { + if (i == call->main_video_stream_index) { for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_STREAMS; j++) { + if (sal_stream_description_active(&md->streams[j])) continue; if (j != call->main_video_stream_index && j != call->main_audio_stream_index) { - ms_message("%i was used for audio stream ; now using %i", i, j); - call->main_audio_stream_index = j; + ms_message("%i was used for video stream ; now using %i", i, j); + call->main_video_stream_index = j; break; } } diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c index beeb62cdb..da9a68165 100644 --- a/tester/complex_sip_call.c +++ b/tester/complex_sip_call.c @@ -190,10 +190,49 @@ static void call_with_video_mline_before_audio_in_sdp() { linphone_core_manager_destroy(mgr); } +static void call_with_multiple_audio_mline_in_sdp() { + LinphoneCoreManager *mgr; + char *identity_char; + char *scen; + FILE * sipp_out; + LinphoneCall *call = NULL; + + /*currently we use direct connection because sipp do not properly set ACK request uri*/ + mgr= linphone_core_manager_new2( "empty_rc", FALSE); + mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc); + linphone_address_set_username(mgr->identity,"marie"); + identity_char = linphone_address_as_string(mgr->identity); + linphone_core_set_primary_contact(mgr->lc,identity_char); + + linphone_core_iterate(mgr->lc); + + scen = bc_tester_res("sipp/call_with_multiple_audio_mline_in_sdp.xml"); + + sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), mgr->identity); + + if (sipp_out) { + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1)); + call = linphone_core_get_current_call(mgr->lc); + linphone_core_accept_call(mgr->lc, call); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d"); + BC_ASSERT_EQUAL(call->main_video_stream_index, 2, int, "%d"); + BC_ASSERT_TRUE(call->main_text_stream_index > 2); + BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); + + check_rtcp(call); + + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); + pclose(sipp_out); + } + linphone_core_manager_destroy(mgr); +} + static test_t tests[] = { { "SIP UPDATE within incoming reinvite without sdp", sip_update_within_icoming_reinvite_with_no_sdp }, { "Call with audio mline before video in sdp", call_with_audio_mline_before_video_in_sdp }, { "Call with video mline before audio in sdp", call_with_video_mline_before_audio_in_sdp }, + { "Call with multiple audio mline in sdp", call_with_multiple_audio_mline_in_sdp }, }; test_suite_t complex_sip_call_test_suite = { diff --git a/tester/sipp/call_with_multiple_audio_mline_in_sdp.xml b/tester/sipp/call_with_multiple_audio_mline_in_sdp.xml new file mode 100644 index 000000000..a47e3cc0c --- /dev/null +++ b/tester/sipp/call_with_multiple_audio_mline_in_sdp.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 96 97 0 8 101 98 + a=rtpmap:96 speex/16000 + a=fmtp:96 vbr=on + a=rtpmap:97 speex/8000 + a=fmtp:97 vbr=on + a=rtpmap:101 telephone-event/16000 + a=rtpmap:98 telephone-event/8000 + m=audio [media_port+1] RTP/AVP 96 97 0 8 101 98 + a=rtpmap:96 speex/16000 + a=fmtp:96 vbr=on + a=rtpmap:97 speex/8000 + a=fmtp:97 vbr=on + a=rtpmap:101 telephone-event/16000 + a=rtpmap:98 telephone-event/8000 + m=video [media_port+2] RTP/AVP 96 + a=rtpmap:96 VP8/90000 + + ]]> + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + + + + + From 52a5ab76e751c9f1c08bcdd9082d104223264f90 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Tue, 22 Sep 2015 10:55:43 +0200 Subject: [PATCH 23/23] Added test for multiple video streams in sdp --- tester/complex_sip_call.c | 39 ++++++ .../call_with_multiple_video_mline_in_sdp.xml | 129 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 tester/sipp/call_with_multiple_video_mline_in_sdp.xml diff --git a/tester/complex_sip_call.c b/tester/complex_sip_call.c index da9a68165..d82841f28 100644 --- a/tester/complex_sip_call.c +++ b/tester/complex_sip_call.c @@ -228,11 +228,50 @@ static void call_with_multiple_audio_mline_in_sdp() { linphone_core_manager_destroy(mgr); } +static void call_with_multiple_video_mline_in_sdp() { + LinphoneCoreManager *mgr; + char *identity_char; + char *scen; + FILE * sipp_out; + LinphoneCall *call = NULL; + + /*currently we use direct connection because sipp do not properly set ACK request uri*/ + mgr= linphone_core_manager_new2( "empty_rc", FALSE); + mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc); + linphone_address_set_username(mgr->identity,"marie"); + identity_char = linphone_address_as_string(mgr->identity); + linphone_core_set_primary_contact(mgr->lc,identity_char); + + linphone_core_iterate(mgr->lc); + + scen = bc_tester_res("sipp/call_with_multiple_video_mline_in_sdp.xml"); + + sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), mgr->identity); + + if (sipp_out) { + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1)); + call = linphone_core_get_current_call(mgr->lc); + linphone_core_accept_call(mgr->lc, call); + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1)); + BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d"); + BC_ASSERT_EQUAL(call->main_video_stream_index, 1, int, "%d"); + BC_ASSERT_TRUE(call->main_text_stream_index > 3); + BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call))); + + check_rtcp(call); + + BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1)); + pclose(sipp_out); + } + linphone_core_manager_destroy(mgr); +} + static test_t tests[] = { { "SIP UPDATE within incoming reinvite without sdp", sip_update_within_icoming_reinvite_with_no_sdp }, { "Call with audio mline before video in sdp", call_with_audio_mline_before_video_in_sdp }, { "Call with video mline before audio in sdp", call_with_video_mline_before_audio_in_sdp }, { "Call with multiple audio mline in sdp", call_with_multiple_audio_mline_in_sdp }, + { "Call with multiple video mline in sdp", call_with_multiple_video_mline_in_sdp }, }; test_suite_t complex_sip_call_test_suite = { diff --git a/tester/sipp/call_with_multiple_video_mline_in_sdp.xml b/tester/sipp/call_with_multiple_video_mline_in_sdp.xml new file mode 100644 index 000000000..77fd615e9 --- /dev/null +++ b/tester/sipp/call_with_multiple_video_mline_in_sdp.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut + Call-ID: [call_id] + CSeq: 1 INVITE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] + s=- + c=IN IP[media_ip_type] [media_ip] + t=0 0 + m=audio [media_port] RTP/AVP 96 97 0 8 101 98 + a=rtpmap:96 speex/16000 + a=fmtp:96 vbr=on + a=rtpmap:97 speex/8000 + a=fmtp:97 vbr=on + a=rtpmap:101 telephone-event/16000 + a=rtpmap:98 telephone-event/8000 + m=video [media_port+2] RTP/AVP 96 + a=rtpmap:96 VP8/90000 + m=video [media_port+3] RTP/AVP 96 + a=rtpmap:96 VP8/90000 + m=video [media_port+4] RTP/AVP 96 + a=rtpmap:96 VP8/90000 + + ]]> + + + + + + + + + + + + + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + ;tag=[pid]SIPpTag00[call_number] + To: sut [peer_tag_param] + Call-ID: [call_id] + CSeq: 2 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Performance Test + Content-Length: 0 + + ]]> + + + + + + + + + + + + +