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);