From da3007f50dec40995e371a10fa7a6e5a0da76379 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 18 Jun 2018 18:02:57 +0200 Subject: [PATCH 1/4] Handle call repair while in early-media. --- src/conference/session/call-session-p.h | 5 +- src/conference/session/call-session.cpp | 1 + src/conference/session/media-session-p.h | 1 + src/conference/session/media-session.cpp | 8 +++ tester/call_single_tester.c | 79 ++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index d8dbed101..595b7197d 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -88,6 +88,9 @@ protected: void setBroken (); void setContactOp (); + virtual void reinviteToRecoverFromConnectionLoss (); + virtual void repairByInviteWithReplaces (); + // CoreListener void onNetworkReachable (bool sipNetworkReachable, bool mediaNetworkReachable) override; void onRegistrationStateChanged (LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const std::string &message) override; @@ -98,8 +101,6 @@ private: LinphoneAddress * getFixedContact () const; - virtual void reinviteToRecoverFromConnectionLoss (); - void repairByInviteWithReplaces (); void repairIfBroken (); protected: diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index ef6394905..a7b03fe0f 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -786,6 +786,7 @@ void CallSessionPrivate::reinviteToRecoverFromConnectionLoss () { void CallSessionPrivate::repairByInviteWithReplaces () { L_Q(); + lInfo() << "CallSession [" << q << "] is going to have a new INVITE replacing the previous one in order to recover from lost connectivity"; string callId = op->getCallId(); const char *fromTag = op->getLocalTag(); const char *toTag = op->getRemoteTag(); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index efdfe04fd..dab25689e 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -249,6 +249,7 @@ private: void refreshSockets (); void reinviteToRecoverFromConnectionLoss () override; + void repairByInviteWithReplaces () override; #ifdef VIDEO_ENABLED void videoStreamEventCb (const MSFilter *f, const unsigned int eventId, const void *args); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 26967b041..512fb4a40 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -3823,6 +3823,14 @@ void MediaSessionPrivate::reinviteToRecoverFromConnectionLoss () { q->update(getParams()); } +void MediaSessionPrivate::repairByInviteWithReplaces () { + if ((state == CallSession::State::IncomingEarlyMedia) || (state == CallSession::State::OutgoingEarlyMedia)) { + stopStreams(); + initializeStreams(); + } + CallSessionPrivate::repairByInviteWithReplaces(); +} + // ----------------------------------------------------------------------------- #ifdef VIDEO_ENABLED diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index fedc3608f..77edd5f2a 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -5280,6 +5280,83 @@ end: linphone_core_manager_destroy(pauline); } +static void recovered_call_on_network_switch_in_early_media_base (bool_t callerLosesNetwork) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager *pauline = linphone_core_manager_new("pauline_tcp_rc"); + bctbx_list_t *lcs = NULL; + LinphoneCall *marie_call; + LinphoneCallLog *marie_call_log; + uint64_t connected_time = 0; + uint64_t ended_time = 0; + + lcs = bctbx_list_append(lcs, marie->lc); + lcs = bctbx_list_append(lcs, pauline->lc); + + /* Marie calls Pauline, and after the call has rung, transitions to an early-media session */ + marie_call = linphone_core_invite_address(marie->lc, pauline->identity); + marie_call_log = linphone_call_get_call_log(marie_call); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingReceived, 1, 3000)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingRinging, 1, 1000)); + + if (linphone_core_inc_invite_pending(pauline->lc)) { + /* Send a 183 to initiate the early media */ + linphone_call_accept_early_media(linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallIncomingEarlyMedia, 1, 2000) ); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallOutgoingEarlyMedia, 1, 2000) ); + BC_ASSERT_TRUE(linphone_call_get_all_muted(marie_call)); + + liblinphone_tester_check_rtcp(marie, pauline); + + if (callerLosesNetwork) { + /* Disconnect Marie's network and then reconnect it */ + linphone_core_set_network_reachable(marie->lc, FALSE); + wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableFalse, 1); + linphone_core_set_network_reachable(marie->lc, TRUE); + wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableTrue, 2); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2)); + } else { + /* Disconnect Pauline's network and then reconnect it */ + linphone_core_set_network_reachable(pauline->lc, FALSE); + wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableFalse, 1); + linphone_core_set_network_reachable(pauline->lc, TRUE); + wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableTrue, 2); + BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 2)); + } + + wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000); + + if (linphone_core_get_current_call(pauline->lc) + && (linphone_call_get_state(linphone_core_get_current_call(pauline->lc)) == LinphoneCallIncomingEarlyMedia) + ) { + linphone_call_accept(linphone_core_get_current_call(pauline->lc)); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallConnected, 1, 1000)); + connected_time = ms_get_cur_time_ms(); + BC_ASSERT_TRUE(wait_for_list(lcs, &marie->stat.number_of_LinphoneCallStreamsRunning, 1, 1000)); + BC_ASSERT_PTR_EQUAL(marie_call, linphone_core_get_current_call(marie->lc)); + BC_ASSERT_FALSE(linphone_call_get_all_muted(marie_call)); + + liblinphone_tester_check_rtcp(marie, pauline); + wait_for_list(lcs, 0, 1, 2000); /* Just to have a call duration != 0 */ + + end_call(pauline, marie); + ended_time = ms_get_cur_time_ms(); + BC_ASSERT_LOWER(labs((long)((linphone_call_log_get_duration(marie_call_log) * 1000) - (int64_t)(ended_time - connected_time))), 1500, long, "%ld"); + } + } + + bctbx_list_free(lcs); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void recovered_call_on_network_switch_in_early_media_1 (void) { + recovered_call_on_network_switch_in_early_media_base(TRUE); +} + +static void recovered_call_on_network_switch_in_early_media_2 (void) { + recovered_call_on_network_switch_in_early_media_base(FALSE); +} + static void _call_with_network_switch(bool_t use_ice, bool_t with_socket_refresh, bool_t enable_rtt, bool_t caller_pause, bool_t callee_pause) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); @@ -6553,6 +6630,8 @@ test_t call_tests[] = { TEST_ONE_TAG("Recovered call on network switch during re-invite 2", recovered_call_on_network_switch_during_reinvite_2, "CallRecovery"), TEST_ONE_TAG("Recovered call on network switch during re-invite 3", recovered_call_on_network_switch_during_reinvite_3, "CallRecovery"), TEST_ONE_TAG("Recovered call on network switch during re-invite 4", recovered_call_on_network_switch_during_reinvite_4, "CallRecovery"), + TEST_ONE_TAG("Recovered call on network switch in early media 1", recovered_call_on_network_switch_in_early_media_1, "CallRecovery"), + TEST_ONE_TAG("Recovered call on network switch in early media 2", recovered_call_on_network_switch_in_early_media_2, "CallRecovery"), TEST_ONE_TAG("Call with network switch in paused state", call_with_network_switch_in_paused_state, "CallRecovery"), TEST_ONE_TAG("Call with network switch in paused by remote state", call_with_network_switch_in_paused_by_remote_state, "CallRecovery"), TEST_ONE_TAG("Call with network switch and ICE", call_with_network_switch_and_ice, "ICE"), From 184388008ea30b095c04c93030b22ebfb691ca31 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 19 Jun 2018 11:12:24 +0200 Subject: [PATCH 2/4] Allow network state change to be notified immediately without linphone_core_iterate() being called. --- coreapi/linphonecore.c | 24 ++++++++++++++++-------- tester/call_single_tester.c | 8 ++++---- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7787940b2..135013f8a 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3184,6 +3184,16 @@ bool_t linphone_core_content_encoding_supported(const LinphoneCore *lc, const ch return (strcmp(handle_content_encoding, content_encoding) == 0) && lc->sal->isContentEncodingAvailable(content_encoding); } +static void notify_network_reachable_change (LinphoneCore *lc) { + if (!lc->network_reachable_to_be_notified) + return; + + lc->network_reachable_to_be_notified = FALSE; + linphone_core_notify_network_reachable(lc, lc->sip_network_reachable); + if (lc->sip_network_reachable) + linphone_core_resolve_stun_server(lc); +} + static void monitor_network_state(LinphoneCore *lc, time_t curtime){ bool_t new_status=lc->network_last_status; char newip[LINPHONE_IPADDR_SIZE]; @@ -3212,6 +3222,8 @@ static void monitor_network_state(LinphoneCore *lc, time_t curtime){ } lc->network_last_check=curtime; } + + notify_network_reachable_change(lc); } static void proxy_update(LinphoneCore *lc){ @@ -3304,13 +3316,6 @@ void linphone_core_iterate(LinphoneCore *lc){ int64_t diff_time; bool one_second_elapsed = false; - if (lc->network_reachable_to_be_notified) { - lc->network_reachable_to_be_notified=FALSE; - linphone_core_notify_network_reachable(lc,lc->sip_network_reachable); - if (lc->sip_network_reachable) { - linphone_core_resolve_stun_server(lc); - } - } if (lc->prevtime_ms == 0){ lc->prevtime_ms = curtime_ms; } @@ -6327,19 +6332,22 @@ static void disable_internal_network_reachability_detection(LinphoneCore *lc){ } } -void linphone_core_set_network_reachable(LinphoneCore* lc,bool_t isReachable) { +void linphone_core_set_network_reachable(LinphoneCore *lc, bool_t isReachable) { disable_internal_network_reachability_detection(lc); set_network_reachable(lc, isReachable, ms_time(NULL)); + notify_network_reachable_change(lc); } void linphone_core_set_media_network_reachable(LinphoneCore *lc, bool_t is_reachable){ disable_internal_network_reachability_detection(lc); set_media_network_reachable(lc, is_reachable); + notify_network_reachable_change(lc); } void linphone_core_set_sip_network_reachable(LinphoneCore *lc, bool_t is_reachable){ disable_internal_network_reachability_detection(lc); set_sip_network_reachable(lc, is_reachable, ms_time(NULL)); + notify_network_reachable_change(lc); } bool_t linphone_core_is_network_reachable(LinphoneCore* lc) { diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index 77edd5f2a..efa33266c 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -5310,16 +5310,16 @@ static void recovered_call_on_network_switch_in_early_media_base (bool_t callerL if (callerLosesNetwork) { /* Disconnect Marie's network and then reconnect it */ linphone_core_set_network_reachable(marie->lc, FALSE); - wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableFalse, 1); + BC_ASSERT_EQUAL(marie->stat.number_of_NetworkReachableFalse, 1, int, "%d"); linphone_core_set_network_reachable(marie->lc, TRUE); - wait_for(marie->lc, pauline->lc, &marie->stat.number_of_NetworkReachableTrue, 2); + BC_ASSERT_EQUAL(marie->stat.number_of_NetworkReachableTrue, 2, int, "%d"); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &marie->stat.number_of_LinphoneRegistrationOk, 2)); } else { /* Disconnect Pauline's network and then reconnect it */ linphone_core_set_network_reachable(pauline->lc, FALSE); - wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableFalse, 1); + BC_ASSERT_EQUAL(pauline->stat.number_of_NetworkReachableFalse, 1, int, "%d"); linphone_core_set_network_reachable(pauline->lc, TRUE); - wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_NetworkReachableTrue, 2); + BC_ASSERT_EQUAL(pauline->stat.number_of_NetworkReachableTrue, 2, int, "%d"); BC_ASSERT_TRUE(wait_for(marie->lc, pauline->lc, &pauline->stat.number_of_LinphoneRegistrationOk, 2)); } From 5d65d0ef728452896a513de7f6b15af08e5f0089 Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Tue, 19 Jun 2018 14:14:00 +0200 Subject: [PATCH 3/4] Restart streams when receiving an INVITE with Replaces header. --- src/conference/session/call-session-p.h | 2 +- src/conference/session/media-session-p.h | 1 + src/conference/session/media-session.cpp | 6 ++++++ tester/call_single_tester.c | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/conference/session/call-session-p.h b/src/conference/session/call-session-p.h index 595b7197d..b2ddba767 100644 --- a/src/conference/session/call-session-p.h +++ b/src/conference/session/call-session-p.h @@ -60,7 +60,7 @@ public: void pingReply (); void referred (const Address &referToAddr); virtual void remoteRinging (); - void replaceOp (SalCallOp *newOp); + virtual void replaceOp (SalCallOp *newOp); virtual void terminated (); void updated (bool isUpdate); void updatedByRemote (); diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index dab25689e..1b65012a5 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -46,6 +46,7 @@ public: void pauseForTransfer (); void pausedByRemote (); void remoteRinging () override; + void replaceOp (SalCallOp *newOp) override; int resumeAfterFailedTransfer (); void resumed (); void startPendingRefer (); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 512fb4a40..aa5d8b16b 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -320,6 +320,12 @@ void MediaSessionPrivate::remoteRinging () { } } +void MediaSessionPrivate::replaceOp (SalCallOp *newOp) { + CallSessionPrivate::replaceOp(newOp); + stopStreams(); + initializeStreams(); +} + int MediaSessionPrivate::resumeAfterFailedTransfer () { L_Q(); if (automaticallyPaused && (state == CallSession::State::Pausing)) diff --git a/tester/call_single_tester.c b/tester/call_single_tester.c index efa33266c..8f57fa11a 100644 --- a/tester/call_single_tester.c +++ b/tester/call_single_tester.c @@ -5324,6 +5324,7 @@ static void recovered_call_on_network_switch_in_early_media_base (bool_t callerL } wait_for_until(marie->lc, pauline->lc, NULL, 1, 2000); + liblinphone_tester_check_rtcp(marie, pauline); if (linphone_core_get_current_call(pauline->lc) && (linphone_call_get_state(linphone_core_get_current_call(pauline->lc)) == LinphoneCallIncomingEarlyMedia) From da12783df2efc9d6aa2d525d5047d5ab4a1e3c89 Mon Sep 17 00:00:00 2001 From: Benjamin Reis Date: Tue, 19 Jun 2018 15:40:13 +0200 Subject: [PATCH 4/4] update streams when receiving REPLACE INVITE --- src/conference/session/media-session.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index aa5d8b16b..f8216ca56 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -322,8 +322,7 @@ void MediaSessionPrivate::remoteRinging () { void MediaSessionPrivate::replaceOp (SalCallOp *newOp) { CallSessionPrivate::replaceOp(newOp); - stopStreams(); - initializeStreams(); + updateStreams(newOp->getFinalMediaDescription(), state); } int MediaSessionPrivate::resumeAfterFailedTransfer () { @@ -1182,7 +1181,7 @@ void MediaSessionPrivate::getLocalIp (const Address &remoteAddr) { struct addrinfo *res = nullptr; string host(remoteAddr.getDomain()); int err; - + if (host[0] == '[') host = host.substr(1, host.size() - 2); memset(&hints, 0, sizeof(hints));