完成sdp的分析

This commit is contained in:
xiongziliang 2021-03-29 23:03:55 +08:00
parent 62036d0f5d
commit 87c53dab92
2 changed files with 198 additions and 37 deletions

View File

@ -189,7 +189,7 @@ SdpItem::Ptr RtcSdpBase::getItem(char key, const char *attr_key) const {
return item; return item;
} }
auto attr = dynamic_pointer_cast<SdpAttr>(item); auto attr = dynamic_pointer_cast<SdpAttr>(item);
if (attr && attr->detail->getKey() == attr_key) { if (attr && !strcmp(attr->detail->getKey() , attr_key)) {
return attr->detail; return attr->detail;
} }
} }
@ -554,23 +554,18 @@ string SdpAttrRtpMap::toString() const {
return SdpItem::toString(); return SdpItem::toString();
} }
void SdpAttrRtcpFb::parse(const string &str) { void SdpAttrRtcpFb::parse(const string &str_in) {
auto vec = split(str, " "); auto str = str_in + "\n";
if (vec.size() < 2) { char rtcp_type_buf[32] = {0};
if (2 != sscanf(str.data(), "%" SCNu8 " %31[^\n]", &pt, rtcp_type_buf)) {
SDP_THROW(); SDP_THROW();
} }
pt = atoi(vec[0].data()); rtcp_type = rtcp_type_buf;
vec.erase(vec.begin());
arr = std::move(vec);
} }
string SdpAttrRtcpFb::toString() const { string SdpAttrRtcpFb::toString() const {
if (value.empty()) { if (value.empty()) {
value = to_string(pt); value = to_string(pt) + " " + rtcp_type;
for (auto &item : arr) {
value += ' ';
value += item;
}
} }
return SdpItem::toString(); return SdpItem::toString();
} }
@ -870,6 +865,13 @@ void test_sdp(){
} }
InfoL << sdp1.toString(); InfoL << sdp1.toString();
InfoL << sdp2.toString(); InfoL << sdp2.toString();
RtcSession session1;
session1.loadFrom(str1);
RtcSession session2;
session2.loadFrom(str2);
InfoL;
} }
void RtcSession::loadFrom(const string &str) { void RtcSession::loadFrom(const string &str) {
@ -882,32 +884,153 @@ void RtcSession::loadFrom(const string &str) {
session_info = sdp.getSessionInfo(); session_info = sdp.getSessionInfo();
connection = sdp.getConnection(); connection = sdp.getConnection();
bandwidth = sdp.getBandwidth(); bandwidth = sdp.getBandwidth();
auto group = sdp.getItemClass<SdpAttrGroup>('a', "group"); msid_semantic = sdp.getItemClass<SdpAttrMsidSemantic>('a', "msid-semantic");
auto mids = group.mids;
for (auto &media : sdp.medias) { for (auto &media : sdp.medias) {
auto mline = media.getItemClass<SdpMedia>('m'); auto mline = media.getItemClass<SdpMedia>('m');
switch (mline.type) { switch (mline.type) {
case TrackVideo: case TrackVideo:
case TrackAudio: case TrackAudio:
case TrackApplication: case TrackApplication: break;
break;
default: throw std::invalid_argument(StrPrinter << "不识别的media类型:" << mline.toString()); default: throw std::invalid_argument(StrPrinter << "不识别的media类型:" << mline.toString());
} }
RtcMedia rtc_media; this->media.emplace_back();
auto &rtc_media = this->media.back();
rtc_media.type = mline.type; rtc_media.type = mline.type;
rtc_media.mid = media.getStringItem('a', "mid"); rtc_media.mid = media.getStringItem('a', "mid");
rtc_media.proto = mline.proto; rtc_media.proto = mline.proto;
rtc_media.type = mline.type; rtc_media.type = mline.type;
rtc_media.port = mline.port; rtc_media.port = mline.port;
rtc_media.direction = media.getDirection(); rtc_media.addr = media.getItemClass<SdpConnection>('c');
rtc_media.rtp_addr = media.getItemClass<SdpConnection>('c'); rtc_media.ice_ufrag = media.getStringItem('a', "ice-ufrag");
rtc_media.rtcp_addr = media.getItemClass<SdpAttrRtcp>('a',"rtcp"); rtc_media.ice_pwd = media.getStringItem('a', "ice-pwd");
rtc_media.ice_ufrag = media.getStringItem('a',"ice-ufrag"); rtc_media.role = media.getItemClass<SdpAttrSetup>('a', "setup").role;
rtc_media.ice_ufrag = media.getStringItem('a',"ice-pwd");
rtc_media.fingerprint = media.getItemClass<SdpAttrFingerprint>('a', "fingerprint"); rtc_media.fingerprint = media.getItemClass<SdpAttrFingerprint>('a', "fingerprint");
rtc_media.role = media.getItemClass<SdpAttrSetup>('a',"setup").role; rtc_media.ice_trickle = media.getItem('a', "ice-trickle").operator bool();
// rtc_media.rtcp_mux = rtc_media.ice_lite = media.getItem('a', "ice-lite").operator bool();
rtc_media.ice_renomination = media.getItem('a', "ice-renomination").operator bool();
rtc_media.candidate = media.getAllItem<SdpAttrCandidate>('a', "candidate");
if (mline.type == TrackType::TrackApplication) {
rtc_media.sctp_port = atoi(media.getStringItem('a', "sctp-port").data());
rtc_media.sctpmap = media.getItemClass<SdpAttrSctpMap>('a', "sctpmap");
continue;
}
rtc_media.rtcp_addr = media.getItemClass<SdpAttrRtcp>('a', "rtcp");
rtc_media.direction = media.getDirection();
rtc_media.extmap = media.getAllItem<SdpAttrExtmap>('a', "extmap");
rtc_media.rtcp_mux = media.getItem('a', "rtcp-mux").operator bool();
rtc_media.rtcp_rsize = media.getItem('a', "rtcp-rsize").operator bool();
map<uint32_t, RtcSSRC> rtc_ssrc_map;
for (auto &ssrc : media.getAllItem<SdpAttrSSRC>('a', "ssrc")) {
auto &rtc_ssrc = rtc_ssrc_map[ssrc.ssrc];
rtc_ssrc.ssrc = ssrc.ssrc;
if (ssrc.attribute == "cname") {
rtc_ssrc.cname = ssrc.attribute_value;
continue;
}
if (ssrc.attribute == "msid") {
rtc_ssrc.msid = ssrc.attribute_value;
continue;
}
if (ssrc.attribute == "mslabel") {
rtc_ssrc.mslabel = ssrc.attribute_value;
continue;
}
if (ssrc.attribute == "label") {
rtc_ssrc.label = ssrc.attribute_value;
continue;
}
}
uint32_t ssrc_rtp = 0, ssrc_rtx = 0, ssrc_rtp_low = 0, ssrc_rtp_mid = 0, ssrc_rtp_high = 0;
auto ssrc_groups = media.getAllItem<SdpAttrSSRCGroup>('a', "ssrc-group");
for (auto &group : ssrc_groups) {
if (group.isFID()) {
ssrc_rtp = group.u.fid.rtp_ssrc;
ssrc_rtx = group.u.fid.rtx_ssrc;
rtc_media.rtx = true;
} else if (group.isSIM()) {
rtc_media.simulcast = true;
ssrc_rtp_low = group.u.sim.rtp_ssrc_low;
ssrc_rtp_mid = group.u.sim.rtp_ssrc_mid;
ssrc_rtp_high = group.u.sim.rtp_ssrc_high;
}
}
if (!ssrc_rtp) {
//没有指定ssrc-group字段那么只有一个ssrc
if (rtc_ssrc_map.size() > 1) {
throw std::invalid_argument("sdp中不存在a=ssrc-group:FID字段,但是ssrc却有多个");
}
ssrc_rtp = rtc_ssrc_map.begin()->second.ssrc;
}
for (auto &pr : rtc_ssrc_map) {
auto &rtc_ssrc = pr.second;
if (rtc_ssrc.ssrc == ssrc_rtp) {
rtc_media.rtp_ssrc = rtc_ssrc;
}
if (rtc_ssrc.ssrc == ssrc_rtx) {
rtc_media.rtx_ssrc = rtc_ssrc;
}
if (rtc_ssrc.ssrc == ssrc_rtp_low) {
rtc_media.rtp_ssrc_low = rtc_ssrc;
}
if (rtc_ssrc.ssrc == ssrc_rtp_mid) {
rtc_media.rtp_ssrc_mid = rtc_ssrc;
}
if (rtc_ssrc.ssrc == ssrc_rtp_high) {
rtc_media.rtp_ssrc_high = rtc_ssrc;
}
}
auto rtpmap_arr = media.getAllItem<SdpAttrRtpMap>('a', "rtpmap");
auto rtcpfb_arr = media.getAllItem<SdpAttrRtcpFb>('a', "rtcp-fb");
auto fmtp_aar = media.getAllItem<SdpAttrFmtp>('a', "fmtp");
//方便根据pt查找rtpmap,一个pt必有一条
map<uint8_t, SdpAttrRtpMap &> rtpmap_map;
//方便根据pt查找rtcp-fb,一个pt可能有多条或0条
multimap<uint8_t, SdpAttrRtcpFb &> rtcpfb_map;
//方便根据pt查找fmtp一个pt最多一条
map<uint8_t, SdpAttrFmtp &> fmtp_map;
for (auto &rtpmap : rtpmap_arr) {
if (!rtpmap_map.emplace(rtpmap.pt, rtpmap).second) {
//添加失败,有多条
throw std::invalid_argument(StrPrinter << "该pt存在多条a=rtpmap:" << rtpmap.pt);
}
}
for (auto &rtpfb : rtcpfb_arr) {
rtcpfb_map.emplace(rtpfb.pt, rtpfb);
}
for (auto &fmtp : fmtp_aar) {
if (!fmtp_map.emplace(fmtp.pt, fmtp).second) {
//添加失败,有多条
throw std::invalid_argument(StrPrinter << "该pt存在多条a=fmtp:" << fmtp.pt);
}
}
for (auto &pt : mline.fmts) {
//遍历所有编码方案的pt
rtc_media.plan.emplace_back();
auto &plan = rtc_media.plan.back();
auto rtpmap_it = rtpmap_map.find(pt);
if (rtpmap_it == rtpmap_map.end()) {
throw std::invalid_argument(StrPrinter << "该pt不存在相对于的a=rtpmap:" << pt);
}
plan.pt = rtpmap_it->second.pt;
plan.codec = rtpmap_it->second.codec;
plan.sample_rate = rtpmap_it->second.sample_rate;
plan.channel = rtpmap_it->second.channel;
auto fmtp_it = fmtp_map.find(pt);
if (fmtp_it != fmtp_map.end()) {
plan.fmtp = fmtp_it->second.arr;
}
for (auto rtpfb_it = rtcpfb_map.find(pt);
rtpfb_it != rtcpfb_map.end() && rtpfb_it->second.pt == pt; ++rtpfb_it) {
plan.rtcp_fb.emplace_back(rtpfb_it->second.rtcp_type);
}
}
} }
group = sdp.getItemClass<SdpAttrGroup>('a', "group");
} }

View File

@ -294,7 +294,7 @@ class SdpAttrExtmap : public SdpItem {
public: public:
//https://aggresss.blog.csdn.net/article/details/106436703 //https://aggresss.blog.csdn.net/article/details/106436703
//a=extmap:1[/sendonly] urn:ietf:params:rtp-hdrext:ssrc-audio-level //a=extmap:1[/sendonly] urn:ietf:params:rtp-hdrext:ssrc-audio-level
int index; uint32_t index;
RtpDirection direction{RtpDirection::invalid}; RtpDirection direction{RtpDirection::invalid};
string ext; string ext;
void parse(const string &str) override; void parse(const string &str) override;
@ -307,8 +307,8 @@ public:
//a=rtpmap:111 opus/48000/2 //a=rtpmap:111 opus/48000/2
uint8_t pt; uint8_t pt;
string codec; string codec;
int sample_rate; uint32_t sample_rate;
int channel {0}; uint32_t channel {0};
void parse(const string &str) override; void parse(const string &str) override;
string toString() const override; string toString() const override;
const char* getKey() const override { return "rtpmap";} const char* getKey() const override { return "rtpmap";}
@ -323,7 +323,7 @@ public:
//a=rtcp-fb:120 goog-remb 支持 REMB (Receiver Estimated Maximum Bitrate) 。 //a=rtcp-fb:120 goog-remb 支持 REMB (Receiver Estimated Maximum Bitrate) 。
//a=rtcp-fb:120 transport-cc 支持 TCC (Transport Congest Control) 。 //a=rtcp-fb:120 transport-cc 支持 TCC (Transport Congest Control) 。
uint8_t pt; uint8_t pt;
vector<string> arr; string rtcp_type;
void parse(const string &str) override; void parse(const string &str) override;
string toString() const override; string toString() const override;
const char* getKey() const override { return "rtcp-fb";} const char* getKey() const override { return "rtcp-fb";}
@ -383,6 +383,8 @@ public:
} sim; } sim;
} u; } u;
bool isFID() const { return type == "FID"; }
bool isSIM() const { return type == "SIM"; }
void parse(const string &str) override; void parse(const string &str) override;
string toString() const override; string toString() const override;
const char* getKey() const override { return "ssrc-group";} const char* getKey() const override { return "ssrc-group";}
@ -395,7 +397,7 @@ public:
//a=sctpmap: sctpmap-number media-subtypes [streams] //a=sctpmap: sctpmap-number media-subtypes [streams]
uint16_t port; uint16_t port;
string subtypes; string subtypes;
int streams; uint32_t streams;
void parse(const string &str) override; void parse(const string &str) override;
string toString() const override; string toString() const override;
const char* getKey() const override { return "sctpmap";} const char* getKey() const override { return "sctpmap";}
@ -426,6 +428,7 @@ public:
vector<SdpItem::Ptr> items; vector<SdpItem::Ptr> items;
public: public:
virtual ~RtcSdpBase() = default;
virtual string toString() const; virtual string toString() const;
int getVersion() const; int getVersion() const;
@ -461,8 +464,31 @@ public:
return item->toString(); return item->toString();
} }
private:
SdpItem::Ptr getItem(char key, const char *attr_key = nullptr) const; SdpItem::Ptr getItem(char key, const char *attr_key = nullptr) const;
template<typename cls>
vector<cls> getAllItem(char key, const char *attr_key = nullptr) const {
vector<cls> ret;
for (auto item : items) {
if (item->getKey()[0] == key) {
if (!attr_key) {
auto c = dynamic_pointer_cast<cls>(item);
if (c) {
ret.emplace_back(*c);
}
} else {
auto attr = dynamic_pointer_cast<SdpAttr>(item);
if (attr && !strcmp(attr->detail->getKey(), attr_key)) {
auto c = dynamic_pointer_cast<cls>(attr->detail);
if (c) {
ret.emplace_back(*c);
}
}
}
}
}
return ret;
}
}; };
class RtcSessionSdp : public RtcSdpBase{ class RtcSessionSdp : public RtcSdpBase{
@ -486,7 +512,7 @@ enum class RtcSSRCType {
//ssrc相关信息 //ssrc相关信息
class RtcSSRC{ class RtcSSRC{
public: public:
RtcSSRCType type; uint32_t ssrc {0};
string cname; string cname;
string msid; string msid;
string mslabel; string mslabel;
@ -514,15 +540,22 @@ public:
string proto; string proto;
//////// rtp //////// //////// rtp ////////
RtcSSRC ssrc; RtcSSRC rtp_ssrc;
SdpConnection rtp_addr; // for simulcast
bool simulcast{false};
RtcSSRC rtp_ssrc_low;
RtcSSRC rtp_ssrc_mid;
RtcSSRC rtp_ssrc_high;
SdpConnection addr;
RtpDirection direction; RtpDirection direction;
vector<RtcCodecPlan> plan; vector<RtcCodecPlan> plan;
//////// rtx - rtcp //////// //////// rtx - rtcp ////////
bool rtx{false};
bool rtcp_mux; bool rtcp_mux;
bool rtcp_rsize; bool rtcp_rsize;
uint32_t rtx_ssrc; RtcSSRC rtx_ssrc;
SdpAttrRtcp rtcp_addr; SdpAttrRtcp rtcp_addr;
//////// ice //////// //////// ice ////////
@ -539,18 +572,23 @@ public:
//////// extmap //////// //////// extmap ////////
vector<SdpAttrExtmap> extmap; vector<SdpAttrExtmap> extmap;
//////// sctp ////////////
SdpAttrSctpMap sctpmap;
uint32_t sctp_port {0};
}; };
class RtcSession{ class RtcSession{
public: public:
int version; uint32_t version;
SdpOrigin origin; SdpOrigin origin;
string session_name; string session_name;
string session_info; string session_info;
SdpConnection connection; SdpConnection connection;
SdpBandwidth bandwidth; SdpBandwidth bandwidth;
set<TrackType> group_bundle; SdpAttrMsidSemantic msid_semantic;
vector<RtcMedia> media; vector<RtcMedia> media;
SdpAttrGroup group;
void loadFrom(const string &sdp); void loadFrom(const string &sdp);
}; };