From 0d87a22d1dd050cb0d7431085b99546d5cd94ff1 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 3 Sep 2015 21:21:16 +0200 Subject: [PATCH] fix bugs in Paused state management. It was possible to transition from Paused to PausedByRemote, which actually breaks the Paused state, and eventually allows the pauser to be resumed by the paused. --- coreapi/call_params.c | 3 + coreapi/call_params.h | 2 +- coreapi/callbacks.c | 19 ++-- coreapi/linphonecall.c | 29 +++++- coreapi/linphonecore.c | 41 ++++---- coreapi/private.h | 2 +- coreapi/sal.c | 17 +-- tester/call_tester.c | 200 +++++++++++++++++++++++++++--------- tester/liblinphone_tester.h | 2 + tester/tester.c | 7 ++ 10 files changed, 229 insertions(+), 93 deletions(-) diff --git a/coreapi/call_params.c b/coreapi/call_params.c index 828fba70c..f9a1a1a4d 100644 --- a/coreapi/call_params.c +++ b/coreapi/call_params.c @@ -43,6 +43,9 @@ SalStreamDir sal_dir_from_call_params_dir(LinphoneMediaDirection cpdir) { return SalStreamRecvOnly; case LinphoneMediaDirectionSendRecv: return SalStreamSendRecv; + case LinphoneMediaDirectionInvalid: + ms_error("LinphoneMediaDirectionInvalid shall not be used."); + return SalStreamInactive; } return SalStreamSendRecv; } diff --git a/coreapi/call_params.h b/coreapi/call_params.h index 29c0a1223..a45eb8999 100644 --- a/coreapi/call_params.h +++ b/coreapi/call_params.h @@ -34,11 +34,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Indicates for a given media the stream direction * */ enum _LinphoneMediaDirection { + LinphoneMediaDirectionInvalid = -1, LinphoneMediaDirectionInactive, /** No active media not supported yet*/ LinphoneMediaDirectionSendOnly, /** Send only mode*/ LinphoneMediaDirectionRecvOnly, /** recv only mode*/ LinphoneMediaDirectionSendRecv, /** send receive*/ - }; /** * Typedef for enum diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 015f10615..0f62eb9a0 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -329,7 +329,7 @@ static void call_received(SalOp *h){ call=linphone_call_new_incoming(lc,from_addr,to_addr,h); - linphone_call_make_local_media_description(lc,call); + linphone_call_make_local_media_description(call); sal_call_set_local_media_description(call->op,call->localdesc); md=sal_call_get_final_media_description(call->op); if (md){ @@ -637,7 +637,12 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t if (sal_media_description_has_dir(rmd,SalStreamSendRecv) || sal_media_description_has_dir(rmd,SalStreamRecvOnly)){ call_resumed(lc,call); }else{ - _linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state)); + /*we are staying in PausedByRemote*/ + linphone_core_notify_display_status(lc,_("Call is updated by remote.")); + linphone_call_set_state(call, LinphoneCallUpdatedByRemote,"Call updated by remote"); + if (call->defer_update == FALSE){ + linphone_core_accept_call_update(lc,call,NULL); + } } break; /*SIP UPDATE CASE*/ @@ -662,12 +667,8 @@ static void call_updated(LinphoneCore *lc, LinphoneCall *call, SalOp *op, bool_t } break; case LinphoneCallPaused: - if (sal_media_description_has_dir(rmd,SalStreamSendOnly) || sal_media_description_has_dir(rmd,SalStreamInactive)){ - call_paused_by_remote(lc,call); - }else{ - /*we'll remain in pause state but accept the offer anyway according to default parameters*/ - _linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state)); - } + /*we'll remain in pause state but accept the offer anyway according to default parameters*/ + _linphone_core_accept_call_update(lc,call,NULL,call->state,linphone_call_state_to_string(call->state)); break; case LinphoneCallUpdating: case LinphoneCallPausing: @@ -702,7 +703,7 @@ static void call_updating(SalOp *op, bool_t is_update){ } if (call->state!=LinphoneCallPaused){ /*Refresh the local description, but in paused state, we don't change anything.*/ - linphone_call_make_local_media_description(lc,call); + linphone_call_make_local_media_description(call); sal_call_set_local_media_description(call->op,call->localdesc); } if (rmd == NULL){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index d4c9f43d5..45a78f47f 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -582,11 +582,30 @@ static const char *linphone_call_get_public_ip_for_stream(LinphoneCall *call, in return public_ip; } -void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call) { - linphone_call_make_local_media_description_with_params(lc, call, call->params); +static void force_streams_dir_according_to_state(LinphoneCall *call, SalMediaDescription *md){ + int i; + + switch (call->state){ + case LinphoneCallPausing: + case LinphoneCallPaused: + break; + default: + return; + break; + } + + for (i=0; i<2; ++i){ + SalStreamDescription *sd = &md->streams[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; + } + } + } } -void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params) { +void linphone_call_make_local_media_description(LinphoneCall *call) { MSList *l; SalMediaDescription *old_md=call->localdesc; int i; @@ -595,6 +614,9 @@ void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, Li LinphoneAddress *addr; const char *subject; CodecConstraints codec_hints={0}; + 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)) { @@ -718,6 +740,7 @@ void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, Li call->localdesc_changed=sal_media_description_equals(md,old_md); sal_media_description_unref(old_md); } + force_streams_dir_according_to_state(call, md); } static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){ diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 19bb7b5a1..3d124d147 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -2768,7 +2768,7 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const Linph linphone_call_set_contact_op(call); linphone_core_stop_dtmf_stream(lc); - linphone_call_make_local_media_description(lc,call); + linphone_call_make_local_media_description(call); if (lc->ringstream==NULL) { if (lc->sound_conf.play_sndcard && lc->sound_conf.capt_sndcard){ @@ -3171,7 +3171,7 @@ int linphone_core_accept_early_media_with_params(LinphoneCore* lc, LinphoneCall* // if parameters are passed, update the media description if ( params ) { linphone_call_set_new_params(call,params); - linphone_call_make_local_media_description ( lc,call ); + linphone_call_make_local_media_description (call); sal_call_set_local_media_description ( call->op,call->localdesc ); sal_op_set_sent_custom_header ( call->op,params->custom_headers ); } @@ -3209,7 +3209,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ linphone_call_fill_media_multicast_addr(call); - if (!no_user_consent) linphone_call_make_local_media_description(lc,call); + if (!no_user_consent) linphone_call_make_local_media_description(call); #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); @@ -3350,15 +3350,24 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho * the call state notification, to deactivate the automatic answer that would just confirm the audio but reject the video. * Then, when the user responds to dialog prompt, it becomes possible to call linphone_core_accept_call_update() to answer * the reINVITE, with eventually video enabled in the LinphoneCallParams argument. + * + * The #LinphoneCallUpdatedByRemote notification can also arrive when receiving an INVITE without SDP. In such case, an unchanged offer is made + * in the 200Ok, and when the ACK containing the SDP answer is received, #LinphoneCallUpdatedByRemote is triggered to notify the application of possible + * changes in the media session. However in such case defering the update has no meaning since we just generating an offer. * - * @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a #LinphoneCallUpdatedByRemote notification, which is illegal. + * @return 0 if successful, -1 if the linphone_core_defer_call_update() was done outside a valid #LinphoneCallUpdatedByRemote notification. **/ int linphone_core_defer_call_update(LinphoneCore *lc, LinphoneCall *call){ if (call->state==LinphoneCallUpdatedByRemote){ + if (call->expect_media_in_ack){ + ms_error("linphone_core_defer_call_update() is not possible during a late offer incoming reINVITE (INVITE without SDP)"); + return -1; + } call->defer_update=TRUE; return 0; + }else{ + ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote"); } - ms_error("linphone_core_defer_call_update() not done in state LinphoneCallUpdatedByRemote"); return -1; } @@ -3370,7 +3379,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call, return 0; } } - linphone_call_make_local_media_description(lc,call); + linphone_call_make_local_media_description(call); linphone_call_update_remote_session_id_and_ver(call); linphone_call_stop_ice_for_inactive_streams(call); @@ -3587,7 +3596,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, linphone_call_set_compatible_incoming_call_parameters(call, md); } linphone_call_prepare_ice(call,TRUE); - linphone_call_make_local_media_description(lc,call); + linphone_call_make_local_media_description(call); sal_call_set_local_media_description(call->op,call->localdesc); sal_op_set_sent_custom_header(call->op,params->custom_headers); } @@ -3797,10 +3806,8 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ } /* Internal version that does not play tone indication*/ -int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) -{ +int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ const char *subject=NULL; - LinphoneCallParams *params; if (call->state!=LinphoneCallStreamsRunning && call->state!=LinphoneCallPausedByRemote){ ms_warning("Cannot pause this call, it is not active."); @@ -3814,15 +3821,8 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) ms_error("No reason to pause this call, it is already paused or inactive."); return -1; } - params = linphone_call_params_copy(call->params); - linphone_call_params_set_audio_direction(params, LinphoneMediaDirectionSendOnly); - if (lp_config_get_int(lc->config, "sip", "inactive_video_on_pause", 0)) { - linphone_call_params_set_video_direction(params, LinphoneMediaDirectionInactive); - } else { - linphone_call_params_set_video_direction(params, LinphoneMediaDirectionSendOnly); - } - linphone_call_make_local_media_description_with_params(lc, call, params); - linphone_call_params_unref(params); + linphone_call_set_state(call, LinphoneCallPausing, "Pausing call"); + linphone_call_make_local_media_description(call); #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); @@ -3836,7 +3836,6 @@ int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) linphone_core_notify_display_status(lc,_("Pausing the current call...")); if (call->audiostream || call->videostream) linphone_call_stop_media_streams (call); - linphone_call_set_state(call,LinphoneCallPausing,"Pausing call"); call->paused_by_app=FALSE; return 0; } @@ -3903,7 +3902,7 @@ int linphone_core_resume_call(LinphoneCore *lc, LinphoneCall *call){ prevents the participants to hear it while the 200OK comes back.*/ if (call->audiostream) audio_stream_play(call->audiostream, NULL); - linphone_call_make_local_media_description(lc,call); + linphone_call_make_local_media_description(call); #ifdef BUILD_UPNP if(call->upnp_session != NULL) { linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); diff --git a/coreapi/private.h b/coreapi/private.h index da3290788..4c8f1e1f4 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -897,7 +897,7 @@ int linphone_core_set_as_current_call(LinphoneCore *lc, LinphoneCall *call); int linphone_core_get_calls_nb(const LinphoneCore *lc); void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const char *message); -void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call); +void linphone_call_make_local_media_description(LinphoneCall *call); void linphone_call_make_local_media_description_with_params(LinphoneCore *lc, LinphoneCall *call, LinphoneCallParams *params); void linphone_call_increment_local_media_description(LinphoneCall *call); void linphone_call_fill_media_multicast_addr(LinphoneCall *call); diff --git a/coreapi/sal.c b/coreapi/sal.c index c9f3facf7..efbc2ea0d 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -160,26 +160,27 @@ static bool_t is_null_address(const char *addr){ /*check for the presence of at least one stream with requested direction */ 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){ const SalStreamDescription *ss=&md->streams[i]; if (!sal_stream_description_active(ss)) continue; - if (ss->dir==stream_dir) return TRUE; - /*compatibility check for phones that only used the null address and no attributes */ - if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))) + if (ss->dir==stream_dir) { return TRUE; + } + /*compatibility check for phones that only used the null address and no attributes */ + if (ss->dir==SalStreamSendRecv && stream_dir==SalStreamSendOnly && (is_null_address(md->addr) || is_null_address(ss->rtp_addr))){ + return TRUE; + } } return FALSE; } bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir stream_dir){ if (stream_dir==SalStreamRecvOnly){ - if (has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)) return FALSE; - else return TRUE; + return has_dir(md, SalStreamRecvOnly) && !(has_dir(md,SalStreamSendOnly) || has_dir(md,SalStreamSendRecv)); }else if (stream_dir==SalStreamSendOnly){ - if (has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)) return FALSE; - else return TRUE; + return has_dir(md, SalStreamSendOnly) && !(has_dir(md,SalStreamRecvOnly) || has_dir(md,SalStreamSendRecv)); }else if (stream_dir==SalStreamSendRecv){ return has_dir(md,SalStreamSendRecv); }else{ diff --git a/tester/call_tester.c b/tester/call_tester.c index 809a9dec9..953632bb7 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -1240,6 +1240,74 @@ end: static void call_paused_resumed(void) { call_paused_resumed_base(FALSE); } + +static void call_paused_by_both() { + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCall* call_pauline, *call_marie; + const rtp_stats_t * stats; + MSList *lcs = NULL; + bool_t call_ok; + + lcs = ms_list_append(lcs, pauline->lc); + lcs = ms_list_append(lcs, marie->lc); + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + + if (!call_ok) goto end; + + call_pauline = linphone_core_get_current_call(pauline->lc); + call_marie = linphone_core_get_current_call(marie->lc); + + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + linphone_core_pause_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + + /*stay in pause a little while in order to generate traffic*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + + /*marie pauses the call also*/ + linphone_core_pause_call(marie->lc, call_marie); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausing,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + /*pauline must stay in paused state*/ + BC_ASSERT_EQUAL(pauline->stat.number_of_LinphoneCallPaused, 1, int, "%i"); + check_media_direction(pauline, call_pauline, lcs, LinphoneMediaDirectionInactive, LinphoneMediaDirectionInvalid); + check_media_direction(marie, call_marie, lcs, LinphoneMediaDirectionInactive, LinphoneMediaDirectionInvalid); + + + /*now pauline wants to resume*/ + linphone_core_resume_call(pauline->lc, call_pauline); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallResuming,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + /*Marie must stay in paused state*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); + BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallPaused, 1, int, "%i"); + + /*now marie wants to resume also*/ + linphone_core_resume_call(marie->lc, call_marie); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallResuming,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + /*same here: wait a while for a bit of a traffic, we need to receive a RTCP packet*/ + wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + + /*since RTCP streams are reset when call is paused/resumed, there should be no loss at all*/ + stats = rtp_session_get_stats(call_pauline->sessions->rtp_session); + BC_ASSERT_EQUAL(stats->cum_packet_loss, 0, int, "%d"); + + end_call(marie, pauline); + +end: + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); + ms_list_free(lcs); +} + #define CHECK_CURRENT_LOSS_RATE() \ rtcp_count_current = pauline->stat.number_of_rtcp_sent; \ /*wait for an RTCP packet to have an accurate cumulative lost value*/ \ @@ -3225,48 +3293,59 @@ void check_media_direction(LinphoneCoreManager* mgr, LinphoneCall *call, MSList* if (call) { const LinphoneCallParams *params = linphone_call_get_current_params(call); #ifdef VIDEO_ENABLED - int current_recv_iframe = mgr->stat.number_of_IframeDecoded; - int expected_recv_iframe=0; - int dummy = 0; + if (video_dir != LinphoneMediaDirectionInvalid){ + int current_recv_iframe = mgr->stat.number_of_IframeDecoded; + int expected_recv_iframe=0; + int dummy = 0; - BC_ASSERT_EQUAL(video_dir,linphone_call_params_get_video_direction(params), int, "%d"); - linphone_call_set_next_video_frame_decoded_callback(call,linphone_call_iframe_decoded_cb,mgr->lc); - linphone_call_send_vfu_request(call); + if (video_dir != LinphoneMediaDirectionInactive){ + BC_ASSERT_TRUE(linphone_call_params_video_enabled(params)); + } + BC_ASSERT_EQUAL(linphone_call_params_get_video_direction(params), video_dir, int, "%d"); + linphone_call_set_next_video_frame_decoded_callback(call,linphone_call_iframe_decoded_cb,mgr->lc); + linphone_call_send_vfu_request(call); - wait_for_list(lcs,&dummy,1,2000); /*on some device, it may take 3 to 4s to get audio from mic*/ + wait_for_list(lcs,&dummy,1,2000); /*on some device, it may take 3 to 4s to get audio from mic*/ - switch (video_dir) { - case LinphoneMediaDirectionInactive: - BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5); - case LinphoneMediaDirectionSendOnly: - expected_recv_iframe = 0; - BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5); - break; - case LinphoneMediaDirectionRecvOnly: - BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5); - case LinphoneMediaDirectionSendRecv: - expected_recv_iframe = 1; - break; - } - - BC_ASSERT_TRUE(wait_for_list(lcs, &mgr->stat.number_of_IframeDecoded,current_recv_iframe + expected_recv_iframe,3000)); -#endif - BC_ASSERT_EQUAL(audio_dir,linphone_call_params_get_audio_direction(params), int, "%d"); - switch (audio_dir) { + switch (video_dir) { case LinphoneMediaDirectionInactive: - BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5); + BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5); case LinphoneMediaDirectionSendOnly: + expected_recv_iframe = 0; BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5); - if (audio_dir == LinphoneMediaDirectionSendOnly) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000)); break; case LinphoneMediaDirectionRecvOnly: - BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5); + BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->upload_bandwidth<5); case LinphoneMediaDirectionSendRecv: - BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_download_bandwidth,70,4000)); - if (audio_dir == LinphoneMediaDirectionSendRecv) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000)); + expected_recv_iframe = 1; + break; + default: break; } + + BC_ASSERT_TRUE(wait_for_list(lcs, &mgr->stat.number_of_IframeDecoded,current_recv_iframe + expected_recv_iframe,3000)); + } +#endif + if (audio_dir != LinphoneMediaDirectionInvalid){ + BC_ASSERT_EQUAL(linphone_call_params_get_audio_direction(params), audio_dir, int, "%d"); + switch (audio_dir) { + case LinphoneMediaDirectionInactive: + BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5); + case LinphoneMediaDirectionSendOnly: + BC_ASSERT_TRUE(linphone_call_get_video_stats(call)->download_bandwidth<5); + if (audio_dir == LinphoneMediaDirectionSendOnly) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000)); + break; + case LinphoneMediaDirectionRecvOnly: + BC_ASSERT_TRUE(linphone_call_get_audio_stats(call)->upload_bandwidth<5); + case LinphoneMediaDirectionSendRecv: + BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_download_bandwidth,70,4000)); + if (audio_dir == LinphoneMediaDirectionSendRecv) BC_ASSERT_TRUE(wait_for_list(lcs,mgr->stat.current_audio_upload_bandwidth,70,4000)); + break; + default: + break; + } + } } } @@ -3281,11 +3360,11 @@ static void accept_call_in_send_only_base(LinphoneCoreManager* pauline, Linphone linphone_core_enable_video(pauline->lc,TRUE,TRUE); linphone_core_set_video_policy(pauline->lc,&pol); - linphone_core_set_video_device(pauline->lc,"Mire: Mire (synthetic moving picture)"); + linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id); linphone_core_enable_video(marie->lc,TRUE,TRUE); linphone_core_set_video_policy(marie->lc,&pol); - linphone_core_set_video_device(marie->lc,"Mire: Mire (synthetic moving picture)"); + linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id); linphone_call_set_next_video_frame_decoded_callback(linphone_core_invite_address(pauline->lc,marie->identity) ,linphone_call_iframe_decoded_cb @@ -4095,8 +4174,8 @@ static void video_call_with_re_invite_inactive_followed_by_re_invite_base(Linpho marie = linphone_core_manager_new( "marie_rc"); pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); linphone_core_set_avpf_mode(pauline->lc,TRUE); - linphone_core_set_video_device(pauline->lc,"Mire: Mire (synthetic moving picture)"); - linphone_core_set_video_device(marie->lc,"Mire: Mire (synthetic moving picture)"); + linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id); + linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id); linphone_core_set_avpf_mode(marie->lc,TRUE); lcs=ms_list_append(lcs,pauline->lc); lcs=ms_list_append(lcs,marie->lc); @@ -4281,13 +4360,24 @@ static void call_with_complex_late_offering(void){ LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); LinphoneCall* call_pauline; LinphoneCall* call_marie; + LinphoneVideoPolicy vpol = {TRUE, TRUE}; + bool_t call_ok; - BC_ASSERT_TRUE(call(pauline,marie)); + linphone_core_enable_video(pauline->lc, TRUE, TRUE); + linphone_core_enable_video(marie->lc, TRUE, TRUE); + linphone_core_set_video_policy(pauline->lc, &vpol); + linphone_core_set_video_policy(marie->lc, &vpol); + linphone_core_set_video_device(pauline->lc,liblinphone_tester_mire_id); + linphone_core_set_video_device(marie->lc,liblinphone_tester_mire_id); + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (!call_ok) goto end; call_pauline = linphone_core_get_current_call(pauline->lc); call_marie = linphone_core_get_current_call(marie->lc); //Invite inactive Audio/video (Marie pause Pauline) + ms_message("CONTEXT: Marie sends INVITE with SDP with all streams inactive"); params=linphone_core_create_call_params(marie->lc,call_marie); linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionInactive); linphone_call_params_set_video_direction(params,LinphoneMediaDirectionInactive); @@ -4295,66 +4385,75 @@ static void call_with_complex_late_offering(void){ linphone_core_update_call(marie->lc, call_marie ,params); linphone_call_params_destroy(params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPaused,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); - //Marie send INVITE without SDP + //Marie sends INVITE without SDP + ms_message("CONTEXT: Marie sends INVITE without SDP for setting streams in send-only mode"); linphone_core_enable_sdp_200_ack(marie->lc,TRUE); params=linphone_core_create_call_params(marie->lc,call_marie); linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendOnly); linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendOnly); linphone_core_update_call(marie->lc, call_marie , params); linphone_call_params_destroy(params); - + //Pauline OK with sendonly - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,1)); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPaused,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,3)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,2)); linphone_core_enable_sdp_200_ack(marie->lc,FALSE); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); //Pauline pause Marie + ms_message("CONTEXT: Pauline pauses the call"); linphone_core_pause_call(pauline->lc,call_pauline); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausing,1)); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); //Pauline resume Marie - wait_for_until(pauline->lc, marie->lc, NULL, 5, 5000); + ms_message("CONTEXT: Pauline resumes the call"); + wait_for_until(pauline->lc, marie->lc, NULL, 5, 2000); linphone_core_resume_call(pauline->lc,call_pauline); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,4)); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallResuming,1)); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,3)); wait_for_until(pauline->lc, marie->lc, NULL, 0, 2000); //Marie invite inactive Audio/Video + ms_message("CONTEXT: Marie sends INVITE with SDP with all streams inactive"); params=linphone_core_create_call_params(marie->lc,call_marie); linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionInactive); linphone_call_params_set_video_direction(params,LinphoneMediaDirectionInactive); linphone_core_update_call(marie->lc, call_marie,params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,3)); linphone_call_params_destroy(params); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3)); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPaused,3)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallPausedByRemote,4)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,5)); - //Marie send INVITE without SDP + //Marie sends INVITE without SDP + ms_message("CONTEXT: Marie sends INVITE without SDP in the purpose of re-enabling streams in sendrecv mode"); linphone_core_enable_sdp_200_ack(marie->lc,TRUE); params=linphone_core_create_call_params(marie->lc,call_marie); linphone_call_params_set_audio_direction(params,LinphoneMediaDirectionSendRecv); linphone_call_params_set_video_direction(params,LinphoneMediaDirectionSendRecv); linphone_core_update_call(marie->lc, call_marie,params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallUpdating,3)); linphone_call_params_destroy(params); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallUpdatedByRemote,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,5)); linphone_core_enable_sdp_200_ack(marie->lc,FALSE); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,4)); - BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallPaused,4)); end_call(marie,pauline); - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneCallEnd, 1)); - BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &marie->stat.number_of_LinphoneCallEnd, 1)); +end: linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); @@ -4830,6 +4929,7 @@ test_t call_tests[] = { { "Call without SDP", call_with_no_sdp}, { "Call without SDP and ACK without SDP", call_with_no_sdp_ack_without_sdp}, { "Call paused resumed", call_paused_resumed }, + { "Call paused by both parties", call_paused_by_both }, { "Call paused resumed with loss", call_paused_resumed_with_loss }, { "Call paused resumed from callee", call_paused_resumed_from_callee }, { "SRTP call", srtp_call }, diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 660505049..c3db2bf5e 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -335,6 +335,8 @@ int liblinphone_tester_setup(); void liblinphone_tester_init(void(*ftester_printf)(int level, const char *fmt, va_list args)); void liblinphone_tester_uninit(void); +extern const char *liblinphone_tester_mire_id; + #ifdef __cplusplus }; diff --git a/tester/tester.c b/tester/tester.c index b6d6c6980..eded255ed 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -44,6 +44,8 @@ const char* test_password="secret"; const char* test_route="sip2.linphone.org"; const char *userhostsfile = "tester_hosts"; +const char *liblinphone_tester_mire_id="Mire: Mire (synthetic moving picture)"; + static void network_reachable(LinphoneCore *lc, bool_t reachable) { stats* counters; ms_message("Network reachable [%s]",reachable?"TRUE":"FALSE"); @@ -237,6 +239,10 @@ bool_t transport_supported(LinphoneTransportType transport) { } +static void display_status(LinphoneCore *lc, const char *status){ + ms_message("display_status(): %s",status); +} + LinphoneCoreManager* linphone_core_manager_init(const char* rc_file) { LinphoneCoreManager* mgr= ms_new0(LinphoneCoreManager,1); char *rc_path = NULL; @@ -260,6 +266,7 @@ LinphoneCoreManager* linphone_core_manager_init(const char* rc_file) { mgr->v_table.network_reachable=network_reachable; mgr->v_table.dtmf_received=dtmf_received; mgr->v_table.call_stats_updated=call_stats_updated; + mgr->v_table.display_status=display_status; reset_counters(&mgr->stat); if (rc_file) rc_path = ms_strdup_printf("rcfiles/%s", rc_file);