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 = {