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

Reply via email to