From 6fa385f3a1add95b92afcd0bd665412ef6a0c859 Mon Sep 17 00:00:00 2001
From: xiongziliang <771730766@qq.com>
Date: Sun, 28 Mar 2021 23:31:21 +0800
Subject: [PATCH] sdp 支持ssrc-group属性

---
 webrtc/Sdp.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 webrtc/Sdp.h   | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
 2 files changed, 105 insertions(+), 33 deletions(-)

diff --git a/webrtc/Sdp.cpp b/webrtc/Sdp.cpp
index e9d6ec6..e122eaf 100644
--- a/webrtc/Sdp.cpp
+++ b/webrtc/Sdp.cpp
@@ -21,31 +21,31 @@ void registerSdpItem(){
 
 class DirectionInterface {
 public:
-    virtual RtpDirection getDirection() = 0;
+    virtual RtpDirection getDirection() const = 0;
 };
 
 class SdpDirectionSendonly : public SdpItem, public DirectionInterface{
 public:
-    const char* getKey() override { return getRtpDirectionString(getDirection());}
-    RtpDirection getDirection() override {return RtpDirection::sendonly;}
+    const char* getKey() const override { return getRtpDirectionString(getDirection());}
+    RtpDirection getDirection() const override {return RtpDirection::sendonly;}
 };
 
 class SdpDirectionRecvonly : public SdpItem, public DirectionInterface{
 public:
-    const char* getKey() override { return getRtpDirectionString(getDirection());}
-    RtpDirection getDirection() override {return RtpDirection::recvonly;}
+    const char* getKey() const override { return getRtpDirectionString(getDirection());}
+    RtpDirection getDirection() const override {return RtpDirection::recvonly;}
 };
 
 class SdpDirectionSendrecv : public SdpItem, public DirectionInterface{
 public:
-    const char* getKey() override { return getRtpDirectionString(getDirection());}
-    RtpDirection getDirection() override {return RtpDirection::sendrecv;}
+    const char* getKey() const override { return getRtpDirectionString(getDirection());}
+    RtpDirection getDirection() const override {return RtpDirection::sendrecv;}
 };
 
 class SdpDirectionInactive : public SdpItem, public DirectionInterface{
 public:
-    const char* getKey() override { return getRtpDirectionString(getDirection());}
-    RtpDirection getDirection() override {return RtpDirection::inactive;}
+    const char* getKey() const override { return getRtpDirectionString(getDirection());}
+    RtpDirection getDirection() const override {return RtpDirection::inactive;}
 };
 
 static bool registerAllItem(){
@@ -69,6 +69,7 @@ static bool registerAllItem(){
     registerSdpItem<SdpAttrRtcp>();
     registerSdpItem<SdpAttrIceUfrag>();
     registerSdpItem<SdpAttrIcePwd>();
+    registerSdpItem<SdpAttrIceOption>();
     registerSdpItem<SdpAttrFingerprint>();
     registerSdpItem<SdpAttrSetup>();
     registerSdpItem<SdpAttrMid>();
@@ -77,6 +78,7 @@ static bool registerAllItem(){
     registerSdpItem<SdpAttrRtcpFb>();
     registerSdpItem<SdpAttrFmtp>();
     registerSdpItem<SdpAttrSSRC>();
+    registerSdpItem<SdpAttrSSRCGroup>();
     registerSdpItem<SdpAttrSctpMap>();
     registerSdpItem<SdpAttrCandidate>();
     registerSdpItem<SdpDirectionSendonly>();
@@ -230,6 +232,8 @@ RtpDirection RtcMedia::getDirection() const{
 //////////////////////////////////////////////////////////////////////////////////////////
 
 #define SDP_THROW() throw std::invalid_argument(StrPrinter << "解析sdp " << getKey() << " 字段失败:" << str)
+#define SDP_THROW2() throw std::invalid_argument(StrPrinter << "生成sdp " << getKey() << " 字段失败")
+
 void SdpTime::parse(const string &str) {
     if (sscanf(str.data(), "%" PRIu64 " %" PRIu64, &start, &stop) != 2) {
         SDP_THROW();
@@ -555,6 +559,41 @@ string SdpAttrSSRC::toString() const  {
     return SdpItem::toString();
 }
 
+void SdpAttrSSRCGroup::parse(const string &str) {
+    auto vec = split(str, " ");
+    if (vec.size() == 3) {
+        if (vec[0] != "FID") {
+            SDP_THROW();
+        }
+        type = std::move(vec[0]);
+        u.fid.rtp_ssrc = atoi(vec[1].data());
+        u.fid.rtx_ssrc = atoi(vec[2].data());
+    } else if (vec.size() == 4) {
+        if (vec[0] != "SIM") {
+            SDP_THROW();
+        }
+        type = std::move(vec[0]);
+        u.sim.rtp_ssrc_low = atoi(vec[1].data());
+        u.sim.rtp_ssrc_mid = atoi(vec[2].data());
+        u.sim.rtp_ssrc_high = atoi(vec[3].data());
+    } else {
+        SDP_THROW();
+    }
+}
+
+string SdpAttrSSRCGroup::toString() const  {
+    if (value.empty()) {
+        if (type == "FID") {
+            value = type + " " + to_string(u.fid.rtp_ssrc) + " " + to_string(u.fid.rtx_ssrc);
+        } else if (type == "SIM") {
+            value = type + " " + to_string(u.sim.rtp_ssrc_low) + " " + to_string(u.sim.rtp_ssrc_mid) + " " + to_string(u.sim.rtp_ssrc_high);
+        } else {
+            SDP_THROW2();
+        }
+    }
+    return SdpItem::toString();
+}
+
 void SdpAttrSctpMap::parse(const string &str)  {
     char subtypes_buf[64] = {0};
     if (3 == sscanf(str.data(), "%" PRIu16 " %63[^ ] %" PRId32, &port, subtypes_buf, &streams)) {
diff --git a/webrtc/Sdp.h b/webrtc/Sdp.h
index c77e09c..e10ad09 100644
--- a/webrtc/Sdp.h
+++ b/webrtc/Sdp.h
@@ -87,7 +87,7 @@ public:
     virtual string toString() const {
         return value;
     }
-    virtual const char* getKey() = 0;
+    virtual const char* getKey() const = 0;
 
 protected:
     mutable string value;
@@ -97,14 +97,14 @@ template <char KEY>
 class SdpString : public SdpItem{
 public:
     // *=*
-    const char* getKey() override { static string key(1, KEY); return key.data();}
+    const char* getKey() const override { static string key(1, KEY); return key.data();}
 };
 
 class SdpCommon : public SdpItem {
 public:
     string key;
     SdpCommon(string key) { this->key = std::move(key); }
-    const char* getKey() override { return key.data();}
+    const char* getKey() const override { return key.data();}
 };
 
 class SdpTime : public SdpItem{
@@ -115,7 +115,7 @@ public:
     uint64_t stop {0};
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "t";}
+    const char* getKey() const override { return "t";}
 };
 
 class SdpOrigin : public SdpItem{
@@ -131,7 +131,7 @@ public:
     string address {"0.0.0.0"};
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "o";}
+    const char* getKey() const override { return "o";}
 };
 
 class SdpConnection : public SdpItem {
@@ -144,7 +144,7 @@ public:
     string address {"0.0.0.0"};
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "c";}
+    const char* getKey() const override { return "c";}
 };
 
 class SdpBandwidth : public SdpItem {
@@ -158,7 +158,7 @@ public:
 
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "b";}
+    const char* getKey() const override { return "b";}
 };
 
 class SdpMedia : public SdpItem {
@@ -172,7 +172,7 @@ public:
 
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "m";}
+    const char* getKey() const override { return "m";}
 };
 
 class SdpAttr : public SdpItem{
@@ -184,7 +184,7 @@ public:
     SdpItem::Ptr detail;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "a";}
+    const char* getKey() const override { return "a";}
 };
 
 class SdpAttrGroup : public SdpItem{
@@ -197,7 +197,7 @@ public:
     vector<string> mids;
     void parse(const string &str) override ;
     string toString() const override ;
-    const char* getKey() override { return "group";}
+    const char* getKey() const override { return "group";}
 };
 
 class SdpAttrMsidSemantic : public SdpItem {
@@ -226,7 +226,7 @@ public:
     string token;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "msid-semantic";}
+    const char* getKey() const override { return "msid-semantic";}
 };
 
 class SdpAttrRtcp : public SdpItem {
@@ -238,19 +238,25 @@ public:
     string address {"0.0.0.0"};
     void parse(const string &str) override;;
     string toString() const override;
-    const char* getKey() override { return "rtcp";}
+    const char* getKey() const override { return "rtcp";}
 };
 
 class SdpAttrIceUfrag : public SdpItem {
 public:
     //a=ice-ufrag:sXJ3
-    const char* getKey() override { return "ice-ufrag";}
+    const char* getKey() const override { return "ice-ufrag";}
 };
 
 class SdpAttrIcePwd : public SdpItem {
 public:
     //a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV
-    const char* getKey() override { return "ice-pwd";}
+    const char* getKey() const override { return "ice-pwd";}
+};
+
+class SdpAttrIceOption : public SdpItem {
+public:
+    //a=ice-options:trickle
+    const char* getKey() const override { return "ice-options";}
 };
 
 class SdpAttrFingerprint : public SdpItem {
@@ -260,7 +266,7 @@ public:
     string hash;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "fingerprint";}
+    const char* getKey() const override { return "fingerprint";}
 };
 
 class SdpAttrSetup : public SdpItem {
@@ -269,13 +275,13 @@ public:
     DtlsRole role{DtlsRole::actpass};
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "setup";}
+    const char* getKey() const override { return "setup";}
 };
 
 class SdpAttrMid : public SdpItem {
 public:
     //a=mid:audio
-    const char* getKey() override { return "mid";}
+    const char* getKey() const override { return "mid";}
 };
 
 class SdpAttrExtmap : public SdpItem {
@@ -285,7 +291,7 @@ public:
     string ext;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "extmap";}
+    const char* getKey() const override { return "extmap";}
 };
 
 class SdpAttrRtpMap : public SdpItem {
@@ -297,7 +303,7 @@ public:
     int channel {0};
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "rtpmap";}
+    const char* getKey() const override { return "rtpmap";}
 };
 
 class SdpAttrRtcpFb : public SdpItem {
@@ -307,7 +313,7 @@ public:
     vector<string> arr;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "rtcp-fb";}
+    const char* getKey() const override { return "rtcp-fb";}
 };
 
 class SdpAttrFmtp : public SdpItem {
@@ -317,7 +323,7 @@ public:
     vector<std::pair<string, string> > arr;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "fmtp";}
+    const char* getKey() const override { return "fmtp";}
 };
 
 class SdpAttrSSRC : public SdpItem {
@@ -330,7 +336,34 @@ public:
     string attribute_value;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "ssrc";}
+    const char* getKey() const override { return "ssrc";}
+};
+
+class SdpAttrSSRCGroup : public SdpItem {
+public:
+    //a=ssrc-group 定义参考 RFC 5576 ,用于描述多个 ssrc 之间的关联,常见的有两种:
+
+    //a=ssrc-group:FID 2430709021 3715850271
+    // FID (Flow Identification) 最初用在 FEC 的关联中,WebRTC 中通常用于关联一组常规 RTP stream 和 重传 RTP stream 。
+
+    //a=ssrc-group:SIM 360918977 360918978 360918980
+    // 在 Chrome 独有的 SDP munging 风格的 simulcast 中使用,将三组编码质量由低到高的 MediaStreamTrack 关联在一起。
+    string type{"FID"};
+    union {
+        struct {
+            uint32_t rtp_ssrc;
+            uint32_t rtx_ssrc;
+        } fid;
+        struct {
+            uint32_t rtp_ssrc_low;
+            uint32_t rtp_ssrc_mid;
+            uint32_t rtp_ssrc_high;
+        } sim;
+    } u;
+
+    void parse(const string &str) override;
+    string toString() const override;
+    const char* getKey() const override { return "ssrc-group";}
 };
 
 class SdpAttrSctpMap : public SdpItem {
@@ -343,7 +376,7 @@ public:
     int streams;
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "sctpmap";}
+    const char* getKey() const override { return "sctpmap";}
 };
 
 class SdpAttrCandidate : public SdpItem {
@@ -363,7 +396,7 @@ public:
 
     void parse(const string &str) override;
     string toString() const override;
-    const char* getKey() override { return "candidate";}
+    const char* getKey() const override { return "candidate";}
 };
 
 class RtcMedia {
--
libgit2 0.26.0