Module: sems Branch: master Commit: 19f7ad04e728ffe2b4f32498cb112a821fd45ea3 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sems/?a=commit;h=19f7ad04e728ffe2b4f32498cb112a821fd45ea3
Author: Václav Kubart <[email protected]> Committer: Václav Kubart <[email protected]> Date: Wed Feb 8 15:29:12 2012 +0100 configurable order of codecs in SDP via SBC call control profile --- apps/sbc/SBC.cpp | 6 ++- apps/sbc/SBCCallProfile.cpp | 117 +++++++++++++++++++++++++++++++++++++++++++ apps/sbc/SBCCallProfile.h | 24 +++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/apps/sbc/SBC.cpp b/apps/sbc/SBC.cpp index a326005..4c88244 100644 --- a/apps/sbc/SBC.cpp +++ b/apps/sbc/SBC.cpp @@ -843,7 +843,7 @@ void SBCDialog::onInvite(const AmSipRequest& req) removeHeader(invite_req.hdrs,PARAM_HDR); removeHeader(invite_req.hdrs,"P-App-Name"); - if (call_profile.sdpfilter_enabled) { + if (call_profile.sdpfilter_enabled || call_profile.payload_order.size()) { b2b_mode = B2BMode_SDPFilter; } @@ -1037,6 +1037,7 @@ int SBCDialog::filterBody(AmSdp& sdp, bool is_a2b) { if (call_profile.sdpfilter != Transparent) { filterSDP(sdp, call_profile.sdpfilter, call_profile.sdpfilter_list); } + call_profile.orderSDP(sdp); } return 0; } @@ -1585,7 +1586,7 @@ SBCCalleeSession::SBCCalleeSession(const AmB2BCallerSession* caller, { dlg.rel100.setState(Am100rel::REL100_IGNORED); - if (call_profile.sdpfilter_enabled) { + if (call_profile.sdpfilter_enabled || call_profile.payload_order.size()) { b2b_mode = B2BMode_SDPFilter; } @@ -1714,6 +1715,7 @@ int SBCCalleeSession::filterBody(AmSdp& sdp, bool is_a2b) { if (call_profile.sdpfilter != Transparent) { filterSDP(sdp, call_profile.sdpfilter, call_profile.sdpfilter_list); } + call_profile.orderSDP(sdp); } return 0; } diff --git a/apps/sbc/SBCCallProfile.cpp b/apps/sbc/SBCCallProfile.cpp index 9cb8b87..0e76ad6 100644 --- a/apps/sbc/SBCCallProfile.cpp +++ b/apps/sbc/SBCCallProfile.cpp @@ -279,6 +279,12 @@ bool SBCCallProfile::readFromConfiguration(const string& name, outbound_interface = cfg.getParameter("outbound_interface"); + if (!readPayloadOrder(cfg.getParameter("payload_order"))) return false; + if (payload_order.size() && (!sdpfilter_enabled)) { + sdpfilter_enabled = true; + sdpfilter = Transparent; + } + md5hash = "<unknown>"; if (!cfg.getMD5(profile_file_name, md5hash)){ ERROR("calculating MD5 of file %s\n", profile_file_name.c_str()); @@ -396,6 +402,26 @@ bool SBCCallProfile::readFromConfiguration(const string& name, INFO("SBC: append headers '%s'\n", append_headers.c_str()); } + if (payload_order.size() > 0) { + INFO("SBC: payload order:\n"); + for (vector<PayloadDesc>::iterator i = payload_order.begin(); i != payload_order.end(); ++i) + INFO("SBC: - %s\n", i->print().c_str()); + } + + return true; +} + +static bool payloadDescsEqual(const vector<PayloadDesc> &a, const vector<PayloadDesc> &b) +{ + // not sure if this function is really needed (seems that vectors can be + // compared using builtin operator== but anyway ...) + if (a.size() != b.size()) return false; + vector<PayloadDesc>::const_iterator ia = a.begin(); + vector<PayloadDesc>::const_iterator ib = b.begin(); + for (; ia != a.end(); ++ia, ++ib) { + if (!(*ia == *ib)) return false; + } + return true; } @@ -443,6 +469,7 @@ bool SBCCallProfile::operator==(const SBCCallProfile& rhs) const { auth_aleg_credentials.user == rhs.auth_aleg_credentials.user && auth_aleg_credentials.pwd == rhs.auth_aleg_credentials.pwd; } + res = res && payloadDescsEqual(payload_order, rhs.payload_order); return res; } @@ -485,6 +512,12 @@ string SBCCallProfile::print() const { res += "rtprelay_enabled: " + string(rtprelay_enabled?"true":"false") + "\n"; res += "force_symmetric_rtp: " + force_symmetric_rtp; res += "msgflags_symmetric_rtp: " + string(msgflags_symmetric_rtp?"true":"false") + "\n"; + res += "payload_order: "; + for (vector<PayloadDesc>::const_iterator i = payload_order.begin(); i != payload_order.end(); ++i) { + if (i != payload_order.begin()) res += ","; + res += i->print(); + } + res += "\n"; if (reply_translations.size()) { @@ -502,3 +535,87 @@ string SBCCallProfile::print() const { return res; } +bool SBCCallProfile::readPayloadOrder(const std::string &src) +{ + vector<string> elems = explode(src, ","); + for (vector<string>::iterator it=elems.begin(); it != elems.end(); ++it) { + PayloadDesc payload; + if (!payload.read(*it)) return false; + payload_order.push_back(payload); + } + return true; +} + +void SBCCallProfile::orderSDP(AmSdp& sdp) +{ + if (payload_order.size() < 1) return; // nothing to do - no predefined order + + DBG("ordering SDP\n"); + for (vector<SdpMedia>::iterator m_it = + sdp.media.begin(); m_it != sdp.media.end(); ++m_it) { + SdpMedia& media = *m_it; + + int pos = 0; + unsigned idx; + unsigned cnt = media.payloads.size(); + + // TODO: optimize + // for each predefined payloads in their order + for (vector<PayloadDesc>::iterator i = payload_order.begin(); i != payload_order.end(); ++i) { + // try to find this payload in SDP + // (not needed to go through already sorted members and current + // destination pos) + for (idx = pos + 1; idx < cnt; idx++) { + if (i->match(media.payloads[idx])) { + // found, exchange elements at pos and idx + SdpPayload p = media.payloads[idx]; + media.payloads[idx] = media.payloads[pos]; + media.payloads[pos] = p; + + ++pos; // next payload index + break; + } + } + } + } +} + +////////////////////////////////////////////////////////////////////////////////// + +bool PayloadDesc::match(const SdpPayload &p) const +{ + //FIXME: payload names case sensitive? + if ((name.size() > 0) && (name != p.encoding_name)) return false; + if (clock_rate && (p.clock_rate > 0) && clock_rate != (unsigned)p.clock_rate) return false; + return true; +} + +bool PayloadDesc::read(const std::string &s) +{ + vector<string> elems = explode(s, "/"); + if (elems.size() > 1) { + name = elems[0]; + str2i(elems[1], clock_rate); + } + else if (elems.size() > 0) { + name = elems[0]; + clock_rate = 0; + } + return true; +} + +string PayloadDesc::print() const +{ + std::string s(name); + s += " / "; + if (!clock_rate) s += "whatever rate"; + else s += int2str(clock_rate); + return s; +} + +bool PayloadDesc::operator==(const PayloadDesc &other) const +{ + if (name != other.name) return false; + if (clock_rate != other.clock_rate) return false; + return true; +} diff --git a/apps/sbc/SBCCallProfile.h b/apps/sbc/SBCCallProfile.h index 3a720ec..6ae6861 100644 --- a/apps/sbc/SBCCallProfile.h +++ b/apps/sbc/SBCCallProfile.h @@ -55,6 +55,26 @@ struct CCInterface { typedef std::list<CCInterface> CCInterfaceListT; typedef CCInterfaceListT::iterator CCInterfaceListIteratorT; +class PayloadDesc { + protected: + std::string name; + unsigned clock_rate; // 0 means "doesn't matter" + + public: + bool match(const SdpPayload &p) const; + std::string print() const; + bool operator==(const PayloadDesc &other) const; + + /* FIXME: really want all of this? + * reads from format: name/clock_rate, nothing need to be set + * for example: + * PCMU + * bla/48000 + * /48000 + * */ + bool read(const std::string &s); +}; + struct SBCCallProfile : public AmObject { string md5hash; @@ -118,6 +138,10 @@ struct SBCCallProfile string outbound_interface; + std::vector<PayloadDesc> payload_order; + bool readPayloadOrder(const std::string &src); + void orderSDP(AmSdp& sdp); // do the SDP changes + // todo: RTP transcoding mode SBCCallProfile() _______________________________________________ Semsdev mailing list [email protected] http://lists.iptel.org/mailman/listinfo/semsdev
