From 6077331d03b6bde3e0ea19e3c1809d321bc174a4 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Fri, 26 Feb 2016 17:23:58 +0100 Subject: [PATCH] restrict the creation of additional outgoing calls to avoid conditions of conflicting access to soundcard --- coreapi/conference.cc | 2 -- coreapi/linphonecore.c | 21 ++++++++---- coreapi/private.h | 2 +- tester/multi_call_tester.c | 66 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/coreapi/conference.cc b/coreapi/conference.cc index 02f6d3763..48c46fdc5 100644 --- a/coreapi/conference.cc +++ b/coreapi/conference.cc @@ -42,7 +42,6 @@ public: bool operator==(const Participant &src) const; const LinphoneAddress *getUri() const {return m_uri;} LinphoneCall *getCall() const {return m_call;} - void setCall(LinphoneCall *call) {m_call = call;} private: LinphoneAddress *m_uri; @@ -222,7 +221,6 @@ Conference::Params::Params(const LinphoneCore *core): m_enableVideo(false) { } - Conference::Conference(LinphoneCore *core, const Conference::Params *params): m_core(core), m_localParticipantStream(NULL), diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index eb8bcefba..cb266123d 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3138,22 +3138,27 @@ void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *d 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)); /*also set in linphone_call_new_incoming*/ } -LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params) -{ +LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params){ const char *from=NULL; LinphoneProxyConfig *proxy=NULL; LinphoneAddress *parsed_url2=NULL; char *real_url=NULL; LinphoneCall *call; bool_t defer = FALSE; - LinphoneCallParams *cp = linphone_call_params_copy(params); + LinphoneCallParams *cp; - linphone_core_preempt_sound_resources(lc); + if (!(!linphone_call_params_audio_enabled(params) || linphone_call_params_get_audio_direction(params) == LinphoneMediaDirectionInactive) + && linphone_core_preempt_sound_resources(lc) == -1){ + ms_error("linphone_core_invite_address_with_params(): sound is required for this call but another call is already locking the sound resource. Call attempt is rejected."); + return NULL; + } if(!linphone_core_can_we_add_call(lc)){ linphone_core_notify_display_warning(lc,_("Sorry, we have reached the maximum number of simultaneous calls")); return NULL; } + + cp = linphone_call_params_copy(params); real_url=linphone_address_as_string(addr); proxy=linphone_core_lookup_known_proxy(lc,addr); @@ -4072,22 +4077,24 @@ int linphone_core_pause_all_calls(LinphoneCore *lc){ return 0; } -void linphone_core_preempt_sound_resources(LinphoneCore *lc){ +int linphone_core_preempt_sound_resources(LinphoneCore *lc){ LinphoneCall *current_call; + int err = 0; if (linphone_core_is_in_conference(lc)){ linphone_core_leave_conference(lc); - return; + return 0; } current_call=linphone_core_get_current_call(lc); if(current_call != NULL){ ms_message("Pausing automatically the current call."); - _linphone_core_pause_call(lc,current_call); + err = _linphone_core_pause_call(lc,current_call); } if (lc->ringstream){ linphone_core_stop_ringing(lc); } + return err; } /** diff --git a/coreapi/private.h b/coreapi/private.h index 7c9bfbb12..3cff77c44 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -1053,7 +1053,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse void linphone_call_set_broken(LinphoneCall *call); void linphone_call_repair_if_broken(LinphoneCall *call); void linphone_core_repair_calls(LinphoneCore *lc); -void linphone_core_preempt_sound_resources(LinphoneCore *lc); +int linphone_core_preempt_sound_resources(LinphoneCore *lc); int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call); /*conferencing subsystem*/ diff --git a/tester/multi_call_tester.c b/tester/multi_call_tester.c index a7f00e855..67f3e8676 100644 --- a/tester/multi_call_tester.c +++ b/tester/multi_call_tester.c @@ -50,12 +50,14 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { lcs=ms_list_append(lcs,laure->lc); BC_ASSERT_TRUE(call_with_caller_params(marie,pauline,marie_params)); + linphone_call_params_destroy(marie_params); pauline_called_by_marie=linphone_core_get_current_call(pauline->lc); if (enable_caller_privacy) linphone_call_params_set_privacy(laure_params,LinphonePrivacyId); BC_ASSERT_PTR_NOT_NULL(linphone_core_invite_address_with_params(laure->lc,pauline->identity,laure_params)); + linphone_call_params_destroy(laure_params); BC_ASSERT_TRUE(wait_for(laure->lc ,pauline->lc @@ -98,8 +100,7 @@ static void call_waiting_indication_with_param(bool_t enable_caller_privacy) { BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallEnd,1,10000)); BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallEnd,1,10000)); BC_ASSERT_TRUE(wait_for_list(lcs,&laure->stat.number_of_LinphoneCallEnd,1,10000)); - - + linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); linphone_core_manager_destroy(laure); @@ -113,6 +114,65 @@ static void call_waiting_indication_with_privacy(void) { call_waiting_indication_with_param(TRUE); } +static void second_call_rejection(bool_t second_without_audio){ + LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); + LinphoneCall *pauline_call; + LinphoneCallParams *params; + LinphoneCall *marie_call; + + /*start a call to pauline*/ + linphone_core_invite_address(marie->lc, pauline->identity); + BC_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,&marie->stat.number_of_LinphoneCallOutgoingRinging + ,1)); + + /*attempt to send a second call while the first one is not answered. + * It must be rejected by the core, since the audio resources are already engaged for the first call*/ + params = linphone_core_create_call_params(marie->lc, NULL); + linphone_call_params_enable_audio(params, !second_without_audio); + marie_call = linphone_core_invite_with_params(marie->lc, "sip:laure_non_exstent@test.linphone.org", params); + + linphone_call_params_destroy(params); + + if (second_without_audio){ + BC_ASSERT_PTR_NOT_NULL(marie_call); + BC_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,&marie->stat.number_of_LinphoneCallError + ,1)); + + }else{ + BC_ASSERT_PTR_NULL(marie_call); + } + + pauline_call = linphone_core_get_current_call(pauline->lc); + BC_ASSERT_PTR_NOT_NULL(pauline_call); + if (pauline_call){ + linphone_core_accept_call(pauline->lc, pauline_call); + } + BC_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,&marie->stat.number_of_LinphoneCallStreamsRunning + ,1)); + BC_ASSERT_TRUE(wait_for(marie->lc + ,pauline->lc + ,&pauline->stat.number_of_LinphoneCallStreamsRunning + ,1)); + end_call(pauline, marie); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void second_call_rejected_if_first_one_in_progress(void){ + second_call_rejection(FALSE); +} + +static void second_call_allowed_if_not_using_audio(void){ + second_call_rejection(TRUE); +} + static void incoming_call_accepted_when_outgoing_call_in_state(LinphoneCallState state) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_tcp_rc"); @@ -870,6 +930,8 @@ void eject_from_3_participants_remote_conference(void) { test_t multi_call_tests[] = { TEST_NO_TAG("Call waiting indication", call_waiting_indication), + TEST_NO_TAG("Second call rejected if first one in progress", second_call_rejected_if_first_one_in_progress), + TEST_NO_TAG("Second call allowed if not using audio", second_call_allowed_if_not_using_audio), TEST_NO_TAG("Call waiting indication with privacy", call_waiting_indication_with_privacy), TEST_NO_TAG("Incoming call accepted when outgoing call in progress", incoming_call_accepted_when_outgoing_call_in_progress), TEST_NO_TAG("Incoming call accepted when outgoing call in outgoing ringing", incoming_call_accepted_when_outgoing_call_in_outgoing_ringing),