diff --git a/apps/sbc/SBC.cpp b/apps/sbc/SBC.cpp index da753c42..6460ffba 100644 --- a/apps/sbc/SBC.cpp +++ b/apps/sbc/SBC.cpp @@ -547,8 +547,7 @@ void SBCDialog::onInvite(const AmSipRequest& req) } if (call_profile.rtprelay_enabled) { - DBG("Enabling RTP relay mode\n"); - rtp_relay_enabled = true; + DBG("Enabling RTP relay mode for SBC call\n"); // force symmetric RTP? if (!call_profile.force_symmetric_rtp.empty()) { @@ -576,11 +575,14 @@ void SBCDialog::onInvite(const AmSipRequest& req) } } } + + enableRtpRelay(req); } m_state = BB_Dialing; invite_req = req; + est_invite_cseq = req.cseq; removeHeader(invite_req.hdrs,PARAM_HDR); removeHeader(invite_req.hdrs,"P-App-Name"); diff --git a/core/AmB2BSession.cpp b/core/AmB2BSession.cpp index b15ca805..73fc74b6 100644 --- a/core/AmB2BSession.cpp +++ b/core/AmB2BSession.cpp @@ -42,7 +42,9 @@ AmB2BSession::AmB2BSession() : sip_relay_only(true), b2b_mode(B2BMode_Transparent), rtp_relay_enabled(false), - rtp_relay_force_symmetric_rtp(false) + rtp_relay_force_symmetric_rtp(false), + relay_rtp_streams(NULL), relay_rtp_streams_cnt(0), + est_invite_cseq(0) { for (unsigned int i=0; i req_sdp; // filter relayed INVITE/UPDATE body if (fwd && b2b_mode != B2BMode_Transparent && (req.method == SIP_METH_INVITE || req.method == SIP_METH_UPDATE || req.method == SIP_METH_ACK)) { + if (req.cseq == est_invite_cseq && req.method == SIP_METH_INVITE) + req_sdp.reset(invite_sdp.release()); + if (NULL == req_sdp.get()) + req_sdp.reset(new AmSdp()); + DBG("filtering body for request '%s' (c/t '%s')\n", req.method.c_str(), req.content_type.c_str()); // todo: handle filtering errors - filterBody(r_ev->req.content_type, r_ev->req.body, filter_sdp, a_leg); + filterBody(r_ev->req.content_type, r_ev->req.body, *req_sdp.get(), a_leg); } if (rtp_relay_enabled && (req.method == SIP_METH_INVITE || req.method == SIP_METH_UPDATE || - req.method == SIP_METH_ACK || req.method == SIP_METH_ACK)) { - updateRelayStreams(r_ev->req.content_type, r_ev->req.body, filter_sdp); + req.method == SIP_METH_ACK || req.method == SIP_METH_ACK) + // don't update for initial INVITE again + && (!(req.cseq == est_invite_cseq && req.method == SIP_METH_INVITE)) + ) { + + if (NULL == req_sdp.get()) { + if (req.cseq == est_invite_cseq && req.method == SIP_METH_INVITE) + req_sdp.reset(invite_sdp.release()); + if (NULL == req_sdp.get()) + req_sdp.reset(new AmSdp()); + } + + updateRelayStreams(r_ev->req.content_type, r_ev->req.body, *req_sdp.get()); } relayEvent(r_ev); } -/** update RTP relay streams with address/port from SDP body */ +/** update RTP relay streams with address/port from SDP body + create rtp_relay_streams if not existing +*/ void AmB2BSession::updateRelayStreams(const string& content_type, const string& body, AmSdp& parser_sdp) { if (body.empty() || (content_type != SIP_APPLICATION_SDP)) @@ -240,13 +265,25 @@ void AmB2BSession::updateRelayStreams(const string& content_type, const string& } } + if (NULL == relay_rtp_streams) { + relay_rtp_streams_cnt = parser_sdp.media.size(); + if (relay_rtp_streams_cnt > MAX_RELAY_STREAMS) { + WARN("got SDP with more media streams (%zd) than MAX_RELAY_STREAMS (%u)," + "consider changing MAX_RELAY_STREAMS and rebuilding SEMS.\n", + relay_rtp_streams_cnt, MAX_RELAY_STREAMS); + relay_rtp_streams_cnt = MAX_RELAY_STREAMS; + } + + relay_rtp_streams = new AmRtpStream[relay_rtp_streams_cnt]; + DBG("Created %u RTP relay streams\n", relay_rtp_streams_cnt); + } + unsigned int media_index = 0; for (std::vector::iterator it = parser_sdp.media.begin(); it != parser_sdp.media.end(); it++) { - if (media_index >= MAX_RELAY_STREAMS) { - ERROR("trying to relay SDP with more media lines than MAX_RELAY_STREAMS (%u)" - "(consider increasing MAX_RELAY_STREAMS and rebuilding SEMS)\n", - MAX_RELAY_STREAMS); + if (media_index >= relay_rtp_streams_cnt) { + WARN("trying to relay SDP with more media lines than " + "relay streams initialized (%u)\n", relay_rtp_streams_cnt); break; } string r_addr = it->conn.address; @@ -291,10 +328,9 @@ bool AmB2BSession::replaceConnectionAddress(const string& content_type, unsigned int media_index = 0; for (std::vector::iterator it = parser_sdp.media.begin(); it != parser_sdp.media.end(); it++) { - if (media_index >= MAX_RELAY_STREAMS) { - ERROR("trying to relay SDP with more media lines than MAX_RELAY_STREAMS (%u)" - "(consider increasing MAX_RELAY_STREAMS and rebuilding SEMS)\n", - MAX_RELAY_STREAMS); + if (media_index >= relay_rtp_streams_cnt) { + WARN("trying to relay SDP with more media lines than " + "relay streams initialized (%u)\n", relay_rtp_streams_cnt); break; } if (!it->conn.address.empty()) @@ -654,6 +690,17 @@ int AmB2BSession::filterBody(AmSdp& sdp, bool is_a2b) { return 0; } +void AmB2BSession::enableRtpRelay(const AmSipRequest& initial_invite_req) { + DBG("enabled RTP relay mode for B2B call '%s'\n", + getLocalTag().c_str()); + rtp_relay_enabled = true; + + // save AmSdp object of initial INVITE body + invite_sdp.reset(new AmSdp()); + updateRelayStreams(initial_invite_req.content_type, initial_invite_req.body, + *invite_sdp.get()); +} + void AmB2BSession::enableRtpRelay() { DBG("enabled RTP relay mode for B2B call '%s'\n", getLocalTag().c_str()); @@ -675,8 +722,16 @@ void AmB2BSession::setupRelayStreams(AmB2BSession* other_session) { return; } + if (NULL == relay_rtp_streams) { + relay_rtp_streams_cnt = other_session->relay_rtp_streams_cnt; + DBG("creating %u RTP streams from other_session\n", + relay_rtp_streams_cnt); + relay_rtp_streams = new AmRtpStream[relay_rtp_streams_cnt]; + } + + // link the other streams as our relay streams - for (unsigned int i=0; irelay_rtp_streams[i].setRelayStream(&relay_rtp_streams[i]); other_stream_fds[i] = other_session->relay_rtp_streams[i].getLocalSocket(); // set local IP (todo: option for other interface!) @@ -686,7 +741,7 @@ void AmB2BSession::setupRelayStreams(AmB2BSession* other_session) { } void AmB2BSession::clearRtpReceiverRelay() { - for (unsigned int i=0; iremoveStream(other_stream_fds[i]); @@ -919,9 +974,8 @@ void AmB2BCallerSession::initializeRTPRelay(AmB2BCalleeSession* callee_session) setupRelayStreams(callee_session); // bind caller session's relay_streams to a port - for (unsigned int i=0; icontent_type, co_ev->body); + // save CSeq of establising INVITE + est_invite_cseq = dlg.cseq - 1; + return; } diff --git a/core/AmB2BSession.h b/core/AmB2BSession.h index 6257b2c1..a06d99e6 100644 --- a/core/AmB2BSession.h +++ b/core/AmB2BSession.h @@ -142,6 +142,10 @@ class AmB2BSession: public AmSession /** Requests received for relaying */ std::map recvd_req; + /** CSeq of the INVITE that established this call */ + unsigned int est_invite_cseq; + auto_ptr invite_sdp; + /** content-type of established session */ string established_content_type; /** body of established session */ @@ -220,9 +224,12 @@ class AmB2BSession: public AmSession /** force symmetric RTP */ bool rtp_relay_force_symmetric_rtp; + /** RTP streams which receive from our side and are used for relaying RTP from the other side */ - AmRtpStream relay_rtp_streams[MAX_RELAY_STREAMS]; + AmRtpStream* relay_rtp_streams; + /** number of relay RTP streams */ + unsigned int relay_rtp_streams_cnt; /** fd of the other streams' sockets (to remove from RtpReceiver at end of relaying) */ int other_stream_fds[MAX_RELAY_STREAMS]; @@ -239,6 +246,8 @@ class AmB2BSession: public AmSession void set_sip_relay_only(bool r); B2BMode getB2BMode() const; + /** set RTP relay mode enabled for initial INVITE */ + void enableRtpRelay(const AmSipRequest& initial_invite_req); /** set RTP relay mode enabled */ void enableRtpRelay(); /** set RTP relay mode disabled */