From d5eaa1c5a2c17a57611470bfacdcf49c2fa5ae51 Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Thu, 5 Jan 2023 11:04:30 +0100 Subject: [PATCH] MT#56321 call_transfer: add support of 183 in failed transfers We have to add support for playing an early announce for those failed trasnfers, which for example reach the timeout. This means there is a need to do the following: - send 183 from early announce DSM module - receive 183 on the B2B leg, which was sending an INVITE to the transfer destination - update the caller with an actual media capabilities, so it is able to receive the early announcement The mechanism behind that is that: - if Proxy in the other leg, which was used to reach the party (to which the transfer has been done), requests the force usage of the announcement for the caller in the very first leg (with the caller who is on hold now) - then the DSM functionality adds the 'P-Early-Announce: force' header in 183 to let sems-b2b in the very first leg know, that there is a need to embed the audio from the early media into the media session with the caller. - hence, caller gets a media re-negotiation - and the leg with the DSM doesn't get updated, since it's still remains in the Early stage of the dialog All the solution is built around two important things: - Proxy uses the P-App-Param called ';force_early_announce=1' to show to the DSM that it needs a "forcive" early media, which must "override" the MoH for the caller, if it's being played. - Sems-b2b uses the header 'P-Early-Announce' to let the very original leg with sems-b2b know, that there is a need to embed early media into the already established media session with a caller Original ticket number: TT#187351 Change-Id: I2cda231e877d9ba91eaa1738322b0981618c1dbf --- apps/sbc/CallLeg.cpp | 31 ++++++++++++++++++++++++++++--- core/AmB2BMedia.cpp | 4 ++++ core/AmSipDialog.cpp | 2 +- core/AmSipDialog.h | 7 +++++++ core/sip/defs.h | 1 + 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/apps/sbc/CallLeg.cpp b/apps/sbc/CallLeg.cpp index 9fb55ab8..6e5ab876 100644 --- a/apps/sbc/CallLeg.cpp +++ b/apps/sbc/CallLeg.cpp @@ -535,9 +535,34 @@ void CallLeg::b2bInitial2xx(AmSipReply& reply, bool forward) void CallLeg::onInitialReply(B2BSipReplyEvent *e) { - if (e->reply.code < 200) b2bInitial1xx(e->reply, e->forward); - else if (e->reply.code < 300) b2bInitial2xx(e->reply, e->forward); - else b2bInitialErr(e->reply, e->forward); + /* 100-199 */ + if (e->reply.code < 200) { + string announce = getHeader(e->reply.hdrs, SIP_HDR_P_EARLY_ANNOUNCE); + dlg->setForcedEarlyAnnounce(announce.find("force") != std::string::npos); + + /* exceptionally treat 183 with the 'P-Early-Announce: force', + similarly to the 200OK response, this will properly update the caller + with the late SDP capabilities (an early announcement), + which has been put on hold during the transfer + + DSM applications using it: + - early_dbprompt (early_announce) */ + if (e->reply.code == 183 && !announce.empty() && dlg->getForcedEarlyAnnounce()) { + b2bInitial2xx(e->reply, e->forward); + } else { + b2bInitial1xx(e->reply, e->forward); + } + } + + /* 200-299 */ + else if (e->reply.code < 300) { + b2bInitial2xx(e->reply, e->forward); + } + + /* 300-699 */ + else { + b2bInitialErr(e->reply, e->forward); + } } void CallLeg::b2bInitialErr(AmSipReply& reply, bool forward) diff --git a/core/AmB2BMedia.cpp b/core/AmB2BMedia.cpp index 5df69085..f1296876 100644 --- a/core/AmB2BMedia.cpp +++ b/core/AmB2BMedia.cpp @@ -874,14 +874,18 @@ void AmB2BMedia::updateStreamPair(AudioStreamPair &pair) TRACE("updating stream in A leg\n"); pair.a.setDtmfSink(b); + if (pair.b.getInput()) pair.a.setRelayStream(NULL); // don't mix relayed RTP into the other's input else pair.a.setRelayStream(pair.b.getStream()); + if (have_a) pair.a.initStream(playout_type, a_leg_local_sdp, a_leg_remote_sdp, pair.media_idx); TRACE("updating stream in B leg\n"); pair.b.setDtmfSink(a); + if (pair.a.getInput()) pair.b.setRelayStream(NULL); // don't mix relayed RTP into the other's input else pair.b.setRelayStream(pair.a.getStream()); + if (have_b) pair.b.initStream(playout_type, b_leg_local_sdp, b_leg_remote_sdp, pair.media_idx); TRACE("audio streams updated\n"); diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index bec06024..168340cf 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -65,7 +65,7 @@ AmSipDialog::AmSipDialog(AmSipDialogEventHandler* h) offeranswer_enabled(true), early_session_started(false),session_started(false), pending_invites(0), - sdp_local(), sdp_remote() + sdp_local(), sdp_remote(), force_early_announce(false) { } diff --git a/core/AmSipDialog.h b/core/AmSipDialog.h index 79d732c8..2cfb8e42 100644 --- a/core/AmSipDialog.h +++ b/core/AmSipDialog.h @@ -59,6 +59,9 @@ protected: // Reliable provisional reply support Am100rel rel100; + /* dialog variables needed to properly handle 183->200OK faking */ + bool force_early_announce; + int onTxReply(const AmSipRequest& req, AmSipReply& reply, int& flags); int onTxRequest(AmSipRequest& req, int& flags); @@ -99,6 +102,10 @@ protected: void setOAForceSDP(bool force) { oa.setForceSDP(force); } bool getOAForceSDP() const { return oa.getForceSDP(); } + /* getter/setter for faked 183 as 200OK responses, TT#187351 */ + void setForcedEarlyAnnounce(bool value) { force_early_announce = value; } + bool getForcedEarlyAnnounce() { return force_early_announce; } + const AmSdp& getLocalSdp() { return oa.getLocalSdp(); } const AmSdp& getRemoteSdp() { return oa.getRemoteSdp(); } diff --git a/core/sip/defs.h b/core/sip/defs.h index 9b3ecfb9..4d8746df 100644 --- a/core/sip/defs.h +++ b/core/sip/defs.h @@ -54,6 +54,7 @@ #define SIP_HDR_EVENT "Event" #define SIP_HDR_SUBSCRIPTION_STATE "Subscription-State" #define SIP_HDR_REPLACES "Replaces" +#define SIP_HDR_P_EARLY_ANNOUNCE "P-Early-Announce" #define SIP_HDR_COL(_hdr) _hdr ":" #define SIP_HDR_COLSP(_hdr) SIP_HDR_COL(_hdr) " "