mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 19:00:01 +08:00
基本完成sdp的解析和生成
This commit is contained in:
parent
f4746d161c
commit
81f29fea61
@ -38,7 +38,7 @@ typedef enum {
|
|||||||
TrackVideo = 0,
|
TrackVideo = 0,
|
||||||
TrackAudio,
|
TrackAudio,
|
||||||
TrackTitle,
|
TrackTitle,
|
||||||
TrackData,
|
TrackApplication,
|
||||||
TrackMax = 4
|
TrackMax = 4
|
||||||
} TrackType;
|
} TrackType;
|
||||||
|
|
||||||
|
535
webrtc/Sdp.cpp
535
webrtc/Sdp.cpp
@ -3,6 +3,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "Sdp.h"
|
#include "Sdp.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
using onCreateSdpItem = function<SdpItem::Ptr(const string &key, const string &value)>;
|
using onCreateSdpItem = function<SdpItem::Ptr(const string &key, const string &value)>;
|
||||||
static unordered_map<string, onCreateSdpItem> sdpItemCreator;
|
static unordered_map<string, onCreateSdpItem> sdpItemCreator;
|
||||||
@ -15,10 +16,38 @@ void registerSdpItem(){
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
Item item;
|
Item item;
|
||||||
InfoL << "register sdp item:" << item.getKey();
|
|
||||||
sdpItemCreator.emplace(item.getKey(), std::move(func));
|
sdpItemCreator.emplace(item.getKey(), std::move(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DirectionInterface {
|
||||||
|
public:
|
||||||
|
virtual RtpDirection getDirection() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SdpDirectionSendonly : public SdpItem, public DirectionInterface{
|
||||||
|
public:
|
||||||
|
const char* getKey() override { return getRtpDirectionString(getDirection());}
|
||||||
|
RtpDirection getDirection() override {return RtpDirection::sendonly;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SdpDirectionRecvonly : public SdpItem, public DirectionInterface{
|
||||||
|
public:
|
||||||
|
const char* getKey() override { return getRtpDirectionString(getDirection());}
|
||||||
|
RtpDirection getDirection() override {return RtpDirection::recvonly;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SdpDirectionSendrecv : public SdpItem, public DirectionInterface{
|
||||||
|
public:
|
||||||
|
const char* getKey() override { return getRtpDirectionString(getDirection());}
|
||||||
|
RtpDirection getDirection() override {return RtpDirection::sendrecv;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SdpDirectionInactive : public SdpItem, public DirectionInterface{
|
||||||
|
public:
|
||||||
|
const char* getKey() override { return getRtpDirectionString(getDirection());}
|
||||||
|
RtpDirection getDirection() override {return RtpDirection::inactive;}
|
||||||
|
};
|
||||||
|
|
||||||
static bool registerAllItem(){
|
static bool registerAllItem(){
|
||||||
registerSdpItem<SdpString<'v'> >();
|
registerSdpItem<SdpString<'v'> >();
|
||||||
registerSdpItem<SdpString<'s'> >();
|
registerSdpItem<SdpString<'s'> >();
|
||||||
@ -49,9 +78,87 @@ static bool registerAllItem(){
|
|||||||
registerSdpItem<SdpAttrFmtp>();
|
registerSdpItem<SdpAttrFmtp>();
|
||||||
registerSdpItem<SdpAttrSSRC>();
|
registerSdpItem<SdpAttrSSRC>();
|
||||||
registerSdpItem<SdpAttrSctpMap>();
|
registerSdpItem<SdpAttrSctpMap>();
|
||||||
|
registerSdpItem<SdpAttrCandidate>();
|
||||||
|
registerSdpItem<SdpDirectionSendonly>();
|
||||||
|
registerSdpItem<SdpDirectionRecvonly>();
|
||||||
|
registerSdpItem<SdpDirectionSendrecv>();
|
||||||
|
registerSdpItem<SdpDirectionInactive>();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TrackType getTrackType(const string &str){
|
||||||
|
if (str == "video") {
|
||||||
|
return TrackVideo;
|
||||||
|
}
|
||||||
|
if (str == "audio") {
|
||||||
|
return TrackAudio;
|
||||||
|
}
|
||||||
|
if (str == "application") {
|
||||||
|
return TrackApplication;
|
||||||
|
}
|
||||||
|
return TrackInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getTrackString(TrackType type){
|
||||||
|
switch (type) {
|
||||||
|
case TrackVideo : return "video";
|
||||||
|
case TrackAudio : return "audio";
|
||||||
|
case TrackApplication : return "application";
|
||||||
|
default: return "invalid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DtlsRole getDtlsRole(const string &str){
|
||||||
|
if (str == "active") {
|
||||||
|
return DtlsRole::active;
|
||||||
|
}
|
||||||
|
if (str == "passive") {
|
||||||
|
return DtlsRole::passive;
|
||||||
|
}
|
||||||
|
if (str == "actpass") {
|
||||||
|
return DtlsRole::actpass;
|
||||||
|
}
|
||||||
|
return DtlsRole::invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getDtlsRoleString(DtlsRole role){
|
||||||
|
switch (role) {
|
||||||
|
case DtlsRole::active : return "active";
|
||||||
|
case DtlsRole::passive : return "passive";
|
||||||
|
case DtlsRole::actpass : return "actpass";
|
||||||
|
default: return "invalid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpDirection getRtpDirection(const string &str){
|
||||||
|
if (str == "sendonly") {
|
||||||
|
return RtpDirection::sendonly;
|
||||||
|
}
|
||||||
|
if (str == "recvonly") {
|
||||||
|
return RtpDirection::recvonly;
|
||||||
|
}
|
||||||
|
if (str == "sendrecv") {
|
||||||
|
return RtpDirection::sendrecv;
|
||||||
|
}
|
||||||
|
if (str == "inactive") {
|
||||||
|
return RtpDirection::inactive;
|
||||||
|
}
|
||||||
|
return RtpDirection::invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getRtpDirectionString(RtpDirection val){
|
||||||
|
switch (val) {
|
||||||
|
case RtpDirection::sendonly : return "sendonly";
|
||||||
|
case RtpDirection::recvonly : return "recvonly";
|
||||||
|
case RtpDirection::sendrecv : return "sendrecv";
|
||||||
|
case RtpDirection::inactive : return "inactive";
|
||||||
|
default: return "invalid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void RtcSdp::parse(const string &str) {
|
void RtcSdp::parse(const string &str) {
|
||||||
static auto flag = registerAllItem();
|
static auto flag = registerAllItem();
|
||||||
RtcMedia *media = nullptr;
|
RtcMedia *media = nullptr;
|
||||||
@ -85,11 +192,142 @@ void RtcSdp::parse(const string &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string RtcSdp::toString() const {
|
string RtcSdp::toString() const {
|
||||||
return std::string();
|
_StrPrinter printer;
|
||||||
|
for (auto &item : items) {
|
||||||
|
printer << item->getKey() << "=" << item->toString() << "\r\n";
|
||||||
|
}
|
||||||
|
for (auto &media : medias) {
|
||||||
|
printer << media.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(printer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
string RtcMedia::toString() const {
|
||||||
|
_StrPrinter printer;
|
||||||
|
for (auto &item : items) {
|
||||||
|
printer << item->getKey() << "=" << item->toString() << "\r\n";
|
||||||
|
}
|
||||||
|
return std::move(printer);
|
||||||
|
}
|
||||||
|
|
||||||
|
RtpDirection RtcMedia::getDirection() const{
|
||||||
|
for (auto &item : items) {
|
||||||
|
auto attr = dynamic_pointer_cast<SdpAttr>(item);
|
||||||
|
if (attr) {
|
||||||
|
auto dir = dynamic_pointer_cast<DirectionInterface>(attr->detail);
|
||||||
|
if (dir) {
|
||||||
|
return dir->getDirection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RtpDirection::invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define SDP_THROW() throw std::invalid_argument(StrPrinter << "解析sdp " << getKey() << " 字段失败:" << str)
|
||||||
|
void SdpTime::parse(const string &str) {
|
||||||
|
if (sscanf(str.data(), "%" PRIu64 " %" PRIu64, &start, &stop) != 2) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpTime::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(start) + " " + to_string(stop);
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpOrigin::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() != 6) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
username = vec[0];
|
||||||
|
session_id = vec[1];
|
||||||
|
session_version = vec[2];
|
||||||
|
nettype = vec[3];
|
||||||
|
addrtype = vec[4];
|
||||||
|
address = vec[6];
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpOrigin::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = username + " " + session_id + " " + session_version + " " + nettype + " " + addrtype + " " + address;
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpConnection::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() != 3) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
nettype = vec[0];
|
||||||
|
addrtype = vec[1];
|
||||||
|
address = vec[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpConnection::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = nettype + " " + addrtype + " " + address;
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpBandwidth::parse(const string &str) {
|
||||||
|
auto vec = split(str, ":");
|
||||||
|
if (vec.size() != 2) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
bwtype = vec[0];
|
||||||
|
bandwidth = atoi(vec[1].data());
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpBandwidth::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = bwtype + ":" + to_string(bandwidth);
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpMedia::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() < 4) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
type = getTrackType(vec[0]);
|
||||||
|
if (type == TrackInvalid) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
port = atoi(vec[1].data());
|
||||||
|
proto = vec[2];
|
||||||
|
for (int i = 3; i < vec.size(); ++i) {
|
||||||
|
auto pt = atoi(vec[i].data());
|
||||||
|
if (type != TrackApplication && pt > 0xFF) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
fmts.emplace_back(pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpMedia::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = string(getTrackString(type)) + " " + to_string(port) + " " + proto;
|
||||||
|
for (auto fmt : fmts) {
|
||||||
|
value += ' ';
|
||||||
|
value += to_string(fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SdpAttr::parse(const string &str) {
|
void SdpAttr::parse(const string &str) {
|
||||||
SdpItem::parse(str);
|
|
||||||
auto pos = str.find(':');
|
auto pos = str.find(':');
|
||||||
auto key = pos == string::npos ? str : str.substr(0, pos);
|
auto key = pos == string::npos ? str : str.substr(0, pos);
|
||||||
auto value = pos == string::npos ? string() : str.substr(pos + 1);
|
auto value = pos == string::npos ? string() : str.substr(pos + 1);
|
||||||
@ -102,10 +340,290 @@ void SdpAttr::parse(const string &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string SdpAttr::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
auto detail_value = detail->toString();
|
||||||
|
if (detail_value.empty()) {
|
||||||
|
value = detail->getKey();
|
||||||
|
} else {
|
||||||
|
value = string(detail->getKey()) + ":" + detail_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrGroup::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() < 2) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
type = vec[0];
|
||||||
|
vec.erase(vec.begin());
|
||||||
|
mids = std::move(vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrGroup::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = type;
|
||||||
|
for (auto mid : mids) {
|
||||||
|
value += ' ';
|
||||||
|
value += mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrMsidSemantic::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() < 1) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
msid = vec[0];
|
||||||
|
token = vec.size() > 1 ? vec[1] : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrMsidSemantic::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
if (token.empty()) {
|
||||||
|
value = string(" ") + msid;
|
||||||
|
} else {
|
||||||
|
value = string(" ") + msid + " " + token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrRtcp::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() != 4) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
port = atoi(vec[0].data());
|
||||||
|
nettype = vec[1];
|
||||||
|
addrtype = vec[2];
|
||||||
|
address = vec[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrRtcp::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(port) + " " + nettype + " " + addrtype + " " + address;
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrFingerprint::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() != 2) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
algorithm = vec[0];
|
||||||
|
hash = vec[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrFingerprint::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = algorithm + " " + hash;
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrSetup::parse(const string &str) {
|
||||||
|
role = getDtlsRole(str);
|
||||||
|
if (role == DtlsRole::invalid) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrSetup::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = getDtlsRoleString(role);
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrExtmap::parse(const string &str) {
|
||||||
|
char buf[128] = {0};
|
||||||
|
if (sscanf(str.data(), "%" PRId32 " %127s", &index, buf) != 2) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
ext = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrExtmap::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(index) + " " + ext;
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrRtpMap::parse(const string &str) {
|
||||||
|
char buf[32] = {0};
|
||||||
|
if (sscanf(str.data(), "%" PRId8 " %31[^/]/%" PRId32 "/%" PRId32, &pt, buf, &sample_rate, &channel) != 4) {
|
||||||
|
if (sscanf(str.data(), "%" PRId8 " %31[^/]/%" PRId32, &pt, buf, &sample_rate) != 3) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
codec = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrRtpMap::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(pt) + " " + codec + "/" + to_string(sample_rate);
|
||||||
|
if (channel) {
|
||||||
|
value += '/';
|
||||||
|
value += to_string(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrRtcpFb::parse(const string &str) {
|
||||||
|
auto vec = split(str, " ");
|
||||||
|
if (vec.size() < 2) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
pt = atoi(vec[0].data());
|
||||||
|
vec.erase(vec.begin());
|
||||||
|
arr = std::move(vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrRtcpFb::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(pt);
|
||||||
|
for (auto &item : arr) {
|
||||||
|
value += ' ';
|
||||||
|
value += item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrFmtp::parse(const string &str) {
|
||||||
|
auto pos = str.find(' ');
|
||||||
|
if (pos == string::npos) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
pt = atoi(str.substr(0, pos).data());
|
||||||
|
auto vec = split(str.substr(pos + 1), ";");
|
||||||
|
for (auto &item : vec) {
|
||||||
|
trim(item);
|
||||||
|
auto pr_vec = split(item, "=");
|
||||||
|
if (pr_vec.size() != 2) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
arr.emplace_back(std::make_pair(pr_vec[0], pr_vec[1]));
|
||||||
|
}
|
||||||
|
if (arr.empty()) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrFmtp::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(pt);
|
||||||
|
int i = 0;
|
||||||
|
for (auto &pr : arr) {
|
||||||
|
value += (i++ ? ';' : ' ');
|
||||||
|
value += pr.first + "=" + pr.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrSSRC::parse(const string &str) {
|
||||||
|
char attr_buf[32] = {0};
|
||||||
|
char attr_val_buf[128] = {0};
|
||||||
|
if (3 == sscanf(str.data(), "%" PRIu32 " %31[^:]:%127[^\0]", &ssrc, attr_buf, attr_val_buf)) {
|
||||||
|
attribute = attr_buf;
|
||||||
|
attribute_value = attr_val_buf;
|
||||||
|
} else if (2 == sscanf(str.data(), "%" PRIu32 " %31s", &ssrc, attr_buf)) {
|
||||||
|
attribute = attr_buf;
|
||||||
|
} else {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrSSRC::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(ssrc) + ' ';
|
||||||
|
value += attribute;
|
||||||
|
if (!attribute_value.empty()) {
|
||||||
|
value += ':';
|
||||||
|
value += attribute_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)) {
|
||||||
|
subtypes = subtypes_buf;
|
||||||
|
} else {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrSctpMap::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(port);
|
||||||
|
value += ' ';
|
||||||
|
value += subtypes;
|
||||||
|
value += ' ';
|
||||||
|
value += to_string(streams);
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SdpAttrCandidate::parse(const string &str) {
|
||||||
|
char transport_buf[16] = {0};
|
||||||
|
char address_buf[32] = {0};
|
||||||
|
char type_buf[16] = {0};
|
||||||
|
|
||||||
|
if (7 != sscanf(str.data(), "%" PRIu32 " %" PRIu32 " %15[^ ] %" PRIu32 " %31[^ ] %" PRIu16 " typ %15[^ \0]",
|
||||||
|
&foundation, &component, transport_buf, &priority, address_buf, &port, type_buf)) {
|
||||||
|
SDP_THROW();
|
||||||
|
}
|
||||||
|
transport = transport_buf;
|
||||||
|
address = address_buf;
|
||||||
|
type = type_buf;
|
||||||
|
auto pos = str.find(type);
|
||||||
|
if (pos != string::npos) {
|
||||||
|
auto remain = str.substr(pos + type.size());
|
||||||
|
trim(remain);
|
||||||
|
if (!remain.empty()) {
|
||||||
|
auto vec = split(remain, " ");
|
||||||
|
string key;
|
||||||
|
for (auto &item : vec) {
|
||||||
|
if (key.empty()) {
|
||||||
|
key = item;
|
||||||
|
} else {
|
||||||
|
arr.emplace_back(std::make_pair(std::move(key), std::move(item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string SdpAttrCandidate::toString() const {
|
||||||
|
if (value.empty()) {
|
||||||
|
value = to_string(foundation) + " " + to_string(component) + " " + transport + " " + to_string(priority) +
|
||||||
|
" " + address + " " + to_string(port) + " typ " + type;
|
||||||
|
for (auto &pr : arr) {
|
||||||
|
value += ' ';
|
||||||
|
value += pr.first;
|
||||||
|
value += ' ';
|
||||||
|
value += pr.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SdpItem::toString();
|
||||||
|
}
|
||||||
|
|
||||||
void test_sdp(){
|
void test_sdp(){
|
||||||
char str1[] = "v=0\n"
|
char str1[] = "v=0\n"
|
||||||
"o=- 380154348540553537 2 IN IP4 127.0.0.1\n"
|
"o=- 380154348540553537 2 IN IP4 127.0.0.1\n"
|
||||||
"s=-\n"
|
"s=-\n"
|
||||||
|
"b=CT:1900\n"
|
||||||
"t=0 0\n"
|
"t=0 0\n"
|
||||||
"a=group:BUNDLE video\n"
|
"a=group:BUNDLE video\n"
|
||||||
"a=msid-semantic: WMS\n"
|
"a=msid-semantic: WMS\n"
|
||||||
@ -212,7 +730,7 @@ void test_sdp(){
|
|||||||
"a=ssrc:611523443 msid:616cfbb1-33a3-4d8c-8275-a199d6005549 bf270496-a23e-47b5-b901-ef23096cd961\n"
|
"a=ssrc:611523443 msid:616cfbb1-33a3-4d8c-8275-a199d6005549 bf270496-a23e-47b5-b901-ef23096cd961\n"
|
||||||
"a=ssrc:611523443 mslabel:616cfbb1-33a3-4d8c-8275-a199d6005549\n"
|
"a=ssrc:611523443 mslabel:616cfbb1-33a3-4d8c-8275-a199d6005549\n"
|
||||||
"a=ssrc:611523443 label:bf270496-a23e-47b5-b901-ef23096cd961\n"
|
"a=ssrc:611523443 label:bf270496-a23e-47b5-b901-ef23096cd961\n"
|
||||||
"a=candidate:1 1 udp %u %s %u typ host\n"
|
"a=candidate:3575467457 1 udp 2113937151 10.15.83.23 57857 typ host generation 0 ufrag 6R0z network-cost 999\n"
|
||||||
"m=application 9 DTLS/SCTP 5000\n"
|
"m=application 9 DTLS/SCTP 5000\n"
|
||||||
"c=IN IP4 0.0.0.0\n"
|
"c=IN IP4 0.0.0.0\n"
|
||||||
"a=ice-ufrag:sXJ3\n"
|
"a=ice-ufrag:sXJ3\n"
|
||||||
@ -220,7 +738,8 @@ void test_sdp(){
|
|||||||
"a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79\n"
|
"a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79\n"
|
||||||
"a=setup:actpass\n"
|
"a=setup:actpass\n"
|
||||||
"a=mid:data\n"
|
"a=mid:data\n"
|
||||||
"a=sctpmap:5000 webrtc-datachannel 1024";
|
"a=sctpmap:5000 webrtc-datachannel 1024\n"
|
||||||
|
"a=sctp-port:5000";
|
||||||
|
|
||||||
RtcSdp sdp1;
|
RtcSdp sdp1;
|
||||||
sdp1.parse(str1);
|
sdp1.parse(str1);
|
||||||
@ -228,6 +747,12 @@ void test_sdp(){
|
|||||||
RtcSdp sdp2;
|
RtcSdp sdp2;
|
||||||
sdp2.parse(str2);
|
sdp2.parse(str2);
|
||||||
|
|
||||||
|
for (auto media : sdp1.medias) {
|
||||||
|
InfoL << getRtpDirectionString(media.getDirection());
|
||||||
|
}
|
||||||
|
for (auto media : sdp2.medias) {
|
||||||
|
InfoL << getRtpDirectionString(media.getDirection());
|
||||||
|
}
|
||||||
InfoL << sdp1.toString();
|
InfoL << sdp1.toString();
|
||||||
InfoL << sdp2.toString();
|
InfoL << sdp2.toString();
|
||||||
}
|
}
|
||||||
|
338
webrtc/Sdp.h
338
webrtc/Sdp.h
@ -12,107 +12,6 @@ using namespace std;
|
|||||||
using namespace mediakit;
|
using namespace mediakit;
|
||||||
|
|
||||||
//https://datatracker.ietf.org/doc/rfc4566/?include_text=1
|
//https://datatracker.ietf.org/doc/rfc4566/?include_text=1
|
||||||
|
|
||||||
//v=0
|
|
||||||
//o=- 2584450093346841581 2 IN IP4 127.0.0.1
|
|
||||||
//s=-
|
|
||||||
//t=0 0
|
|
||||||
//a=group:BUNDLE audio video data
|
|
||||||
//a=msid-semantic: WMS 616cfbb1-33a3-4d8c-8275-a199d6005549
|
|
||||||
//m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
|
|
||||||
//c=IN IP4 0.0.0.0
|
|
||||||
//a=rtcp:9 IN IP4 0.0.0.0
|
|
||||||
//a=ice-ufrag:sXJ3
|
|
||||||
//a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV
|
|
||||||
//a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79
|
|
||||||
//a=setup:actpass
|
|
||||||
//a=mid:audio
|
|
||||||
//a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
|
||||||
//a=sendrecv
|
|
||||||
//a=rtcp-mux
|
|
||||||
//a=rtpmap:111 opus/48000/2
|
|
||||||
//a=rtcp-fb:111 transport-cc
|
|
||||||
//a=fmtp:111 minptime=10;useinbandfec=1
|
|
||||||
//a=rtpmap:103 ISAC/16000
|
|
||||||
//a=rtpmap:104 ISAC/32000
|
|
||||||
//a=rtpmap:9 G722/8000
|
|
||||||
//a=rtpmap:0 PCMU/8000
|
|
||||||
//a=rtpmap:8 PCMA/8000
|
|
||||||
//a=rtpmap:106 CN/32000
|
|
||||||
//a=rtpmap:105 CN/16000
|
|
||||||
//a=rtpmap:13 CN/8000
|
|
||||||
//a=rtpmap:110 telephone-event/48000
|
|
||||||
//a=rtpmap:112 telephone-event/32000
|
|
||||||
//a=rtpmap:113 telephone-event/16000
|
|
||||||
//a=rtpmap:126 telephone-event/8000
|
|
||||||
//a=ssrc:120276603 cname:iSkJ2vn5cYYubTve
|
|
||||||
//a=ssrc:120276603 msid:616cfbb1-33a3-4d8c-8275-a199d6005549 1da3d329-7399-4fe9-b20f-69606bebd363
|
|
||||||
//a=ssrc:120276603 mslabel:616cfbb1-33a3-4d8c-8275-a199d6005549
|
|
||||||
//a=ssrc:120276603 label:1da3d329-7399-4fe9-b20f-69606bebd363
|
|
||||||
//m=video 9 UDP/TLS/RTP/SAVPF 96 98 100 102 127 97 99 101 125
|
|
||||||
//c=IN IP4 0.0.0.0
|
|
||||||
//a=rtcp:9 IN IP4 0.0.0.0
|
|
||||||
//a=ice-ufrag:sXJ3
|
|
||||||
//a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV
|
|
||||||
//a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79
|
|
||||||
//a=setup:actpass
|
|
||||||
//a=mid:video
|
|
||||||
//a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
|
|
||||||
//a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
|
|
||||||
//a=extmap:4 urn:3gpp:video-orientation
|
|
||||||
//a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
|
|
||||||
//a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
|
|
||||||
//a=sendrecv
|
|
||||||
//a=rtcp-mux
|
|
||||||
//a=rtcp-rsize
|
|
||||||
//a=rtpmap:96 VP8/90000
|
|
||||||
//a=rtcp-fb:96 ccm fir
|
|
||||||
//a=rtcp-fb:96 nack
|
|
||||||
//a=rtcp-fb:96 nack pli
|
|
||||||
//a=rtcp-fb:96 goog-remb
|
|
||||||
//a=rtcp-fb:96 transport-cc
|
|
||||||
//a=rtpmap:98 VP9/90000
|
|
||||||
//a=rtcp-fb:98 ccm fir
|
|
||||||
//a=rtcp-fb:98 nack
|
|
||||||
//a=rtcp-fb:98 nack pli
|
|
||||||
//a=rtcp-fb:98 goog-remb
|
|
||||||
//a=rtcp-fb:98 transport-cc
|
|
||||||
//a=rtpmap:100 H264/90000
|
|
||||||
//a=rtcp-fb:100 ccm fir
|
|
||||||
//a=rtcp-fb:100 nack
|
|
||||||
//a=rtcp-fb:100 nack pli
|
|
||||||
//a=rtcp-fb:100 goog-remb
|
|
||||||
//a=rtcp-fb:100 transport-cc
|
|
||||||
//a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
|
|
||||||
//a=rtpmap:102 red/90000
|
|
||||||
//a=rtpmap:127 ulpfec/90000
|
|
||||||
//a=rtpmap:97 rtx/90000
|
|
||||||
//a=fmtp:97 apt=96
|
|
||||||
//a=rtpmap:99 rtx/90000
|
|
||||||
//a=fmtp:99 apt=98
|
|
||||||
//a=rtpmap:101 rtx/90000
|
|
||||||
//a=fmtp:101 apt=100
|
|
||||||
//a=rtpmap:125 rtx/90000
|
|
||||||
//a=fmtp:125 apt=102
|
|
||||||
//a=ssrc-group:FID 2580761338 611523443
|
|
||||||
//a=ssrc:2580761338 cname:iSkJ2vn5cYYubTve
|
|
||||||
//a=ssrc:2580761338 msid:616cfbb1-33a3-4d8c-8275-a199d6005549 bf270496-a23e-47b5-b901-ef23096cd961
|
|
||||||
//a=ssrc:2580761338 mslabel:616cfbb1-33a3-4d8c-8275-a199d6005549
|
|
||||||
//a=ssrc:2580761338 label:bf270496-a23e-47b5-b901-ef23096cd961
|
|
||||||
//a=ssrc:611523443 cname:iSkJ2vn5cYYubTve
|
|
||||||
//a=ssrc:611523443 msid:616cfbb1-33a3-4d8c-8275-a199d6005549 bf270496-a23e-47b5-b901-ef23096cd961
|
|
||||||
//a=ssrc:611523443 mslabel:616cfbb1-33a3-4d8c-8275-a199d6005549
|
|
||||||
//a=ssrc:611523443 label:bf270496-a23e-47b5-b901-ef23096cd961
|
|
||||||
//a=candidate:1 1 udp %u %s %u typ host
|
|
||||||
//m=application 9 DTLS/SCTP 5000
|
|
||||||
//c=IN IP4 0.0.0.0
|
|
||||||
//a=ice-ufrag:sXJ3
|
|
||||||
//a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV
|
|
||||||
//a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79
|
|
||||||
//a=setup:actpass
|
|
||||||
//a=mid:data
|
|
||||||
//a=sctpmap:5000 webrtc-datachannel 1024
|
|
||||||
|
|
||||||
//Session description
|
//Session description
|
||||||
// v= (protocol version)
|
// v= (protocol version)
|
||||||
// o= (originator and session identifier)
|
// o= (originator and session identifier)
|
||||||
@ -148,7 +47,7 @@ enum class RtpDirection {
|
|||||||
//只发送
|
//只发送
|
||||||
sendonly,
|
sendonly,
|
||||||
//只接收
|
//只接收
|
||||||
revonly,
|
recvonly,
|
||||||
//同时发送接收
|
//同时发送接收
|
||||||
sendrecv,
|
sendrecv,
|
||||||
//禁止发送数据
|
//禁止发送数据
|
||||||
@ -171,10 +70,16 @@ enum class SdpType {
|
|||||||
answer
|
answer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TrackType getTrackType(const string &str);
|
||||||
|
const char* getTrackString(TrackType type);
|
||||||
|
DtlsRole getDtlsRole(const string &str);
|
||||||
|
const char* getDtlsRoleString(DtlsRole role);
|
||||||
|
RtpDirection getRtpDirection(const string &str);
|
||||||
|
const char* getRtpDirectionString(RtpDirection val);
|
||||||
|
|
||||||
class SdpItem {
|
class SdpItem {
|
||||||
public:
|
public:
|
||||||
using Ptr = std::shared_ptr<SdpItem>;
|
using Ptr = std::shared_ptr<SdpItem>;
|
||||||
string value;
|
|
||||||
virtual ~SdpItem() = default;
|
virtual ~SdpItem() = default;
|
||||||
virtual void parse(const string &str) {
|
virtual void parse(const string &str) {
|
||||||
value = str;
|
value = str;
|
||||||
@ -183,6 +88,9 @@ public:
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
virtual const char* getKey() = 0;
|
virtual const char* getKey() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
mutable string value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <char KEY>
|
template <char KEY>
|
||||||
@ -203,10 +111,10 @@ class SdpTime : public SdpItem{
|
|||||||
public:
|
public:
|
||||||
//5.9. Timing ("t=")
|
//5.9. Timing ("t=")
|
||||||
// t=<start-time> <stop-time>
|
// t=<start-time> <stop-time>
|
||||||
uint64_t start;
|
uint64_t start {0};
|
||||||
uint64_t stop;
|
uint64_t stop {0};
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "t";}
|
const char* getKey() override { return "t";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -215,14 +123,14 @@ public:
|
|||||||
// 5.2. Origin ("o=")
|
// 5.2. Origin ("o=")
|
||||||
// o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
|
// o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
|
||||||
// o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
|
// o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
|
||||||
string username;
|
string username {"-"};
|
||||||
string session_id;
|
string session_id;
|
||||||
string session_version;
|
string session_version;
|
||||||
string nettype;
|
string nettype {"IN"};
|
||||||
string addrtype;
|
string addrtype {"IP4"};
|
||||||
string address;
|
string address {"0.0.0.0"};
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "o";}
|
const char* getKey() override { return "o";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -231,11 +139,11 @@ public:
|
|||||||
// 5.7. Connection Data ("c=")
|
// 5.7. Connection Data ("c=")
|
||||||
// c=IN IP4 224.2.17.12/127
|
// c=IN IP4 224.2.17.12/127
|
||||||
// c=<nettype> <addrtype> <connection-address>
|
// c=<nettype> <addrtype> <connection-address>
|
||||||
string nettype;
|
string nettype {"IN"};
|
||||||
string addrtype;
|
string addrtype {"IP4"};
|
||||||
string address;
|
string address {"0.0.0.0"};
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "c";}
|
const char* getKey() override { return "c";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -245,11 +153,11 @@ public:
|
|||||||
//b=<bwtype>:<bandwidth>
|
//b=<bwtype>:<bandwidth>
|
||||||
|
|
||||||
//AS、CT
|
//AS、CT
|
||||||
string bwtype;
|
string bwtype {"AS"};
|
||||||
int bandwidth;
|
uint32_t bandwidth {0};
|
||||||
|
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "b";}
|
const char* getKey() override { return "b";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -259,11 +167,11 @@ public:
|
|||||||
// m=<media> <port> <proto> <fmt> ...
|
// m=<media> <port> <proto> <fmt> ...
|
||||||
TrackType type;
|
TrackType type;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
vector<string> proto;
|
string proto;
|
||||||
vector<uint8_t> fmt;
|
vector<uint32_t> fmts;
|
||||||
|
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "m";}
|
const char* getKey() override { return "m";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -275,7 +183,7 @@ public:
|
|||||||
//a=<attribute>:<value>
|
//a=<attribute>:<value>
|
||||||
SdpItem::Ptr detail;
|
SdpItem::Ptr detail;
|
||||||
void parse(const string &str) override;
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "a";}
|
const char* getKey() override { return "a";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -285,50 +193,63 @@ public:
|
|||||||
// BUNDLE group is included at the session-level.
|
// BUNDLE group is included at the session-level.
|
||||||
//a=group:LS session level attribute MUST be included wth the 'mid'
|
//a=group:LS session level attribute MUST be included wth the 'mid'
|
||||||
// identifiers that are part of the same lip sync group.
|
// identifiers that are part of the same lip sync group.
|
||||||
string type;
|
string type {"BUNDLE"};
|
||||||
vector<string> mid;
|
vector<string> mids;
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override ;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override ;
|
||||||
const char* getKey() override { return "group";}
|
const char* getKey() override { return "group";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrMsidSemantic : public SdpItem {
|
class SdpAttrMsidSemantic : public SdpItem {
|
||||||
public:
|
public:
|
||||||
string name{"WMS"};
|
//https://tools.ietf.org/html/draft-alvestrand-rtcweb-msid-02#section-3
|
||||||
string mid;
|
//3. The Msid-Semantic Attribute
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
//
|
||||||
string toString() const override { return SdpItem::toString(); };
|
// In order to fully reproduce the semantics of the SDP and SSRC
|
||||||
|
// grouping frameworks, a session-level attribute is defined for
|
||||||
|
// signalling the semantics associated with an msid grouping.
|
||||||
|
//
|
||||||
|
// This OPTIONAL attribute gives the message ID and its group semantic.
|
||||||
|
// a=msid-semantic: examplefoo LS
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// The ABNF of msid-semantic is:
|
||||||
|
//
|
||||||
|
// msid-semantic-attr = "msid-semantic:" " " msid token
|
||||||
|
// token = <as defined in RFC 4566>
|
||||||
|
//
|
||||||
|
// The semantic field may hold values from the IANA registries
|
||||||
|
// "Semantics for the "ssrc-group" SDP Attribute" and "Semantics for the
|
||||||
|
// "group" SDP Attribute".
|
||||||
|
//a=msid-semantic: WMS 616cfbb1-33a3-4d8c-8275-a199d6005549
|
||||||
|
string msid{"WMS"};
|
||||||
|
string token;
|
||||||
|
void parse(const string &str) override;
|
||||||
|
string toString() const override;
|
||||||
const char* getKey() override { return "msid-semantic";}
|
const char* getKey() override { return "msid-semantic";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrRtcp : public SdpItem {
|
class SdpAttrRtcp : public SdpItem {
|
||||||
public:
|
public:
|
||||||
// c=IN IP4 224.2.17.12/127
|
// a=rtcp:9 IN IP4 0.0.0.0
|
||||||
// c=<nettype> <addrtype> <connection-address>
|
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
string nettype;
|
string nettype {"IN"};
|
||||||
string addrtype;
|
string addrtype {"IP4"};
|
||||||
string address;
|
string address {"0.0.0.0"};
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "rtcp";}
|
const char* getKey() override { return "rtcp";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrIceUfrag : public SdpItem {
|
class SdpAttrIceUfrag : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=ice-ufrag:sXJ3
|
//a=ice-ufrag:sXJ3
|
||||||
string value;
|
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
|
||||||
string toString() const override { return SdpItem::toString(); };
|
|
||||||
const char* getKey() override { return "ice-ufrag";}
|
const char* getKey() override { return "ice-ufrag";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrIcePwd : public SdpItem {
|
class SdpAttrIcePwd : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV
|
//a=ice-pwd:yEclOTrLg1gEubBFefOqtmyV
|
||||||
string value;
|
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
|
||||||
string toString() const override { return SdpItem::toString(); };
|
|
||||||
const char* getKey() override { return "ice-pwd";}
|
const char* getKey() override { return "ice-pwd";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -336,27 +257,24 @@ class SdpAttrFingerprint : public SdpItem {
|
|||||||
public:
|
public:
|
||||||
//a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79
|
//a=fingerprint:sha-256 22:14:B5:AF:66:12:C7:C7:8D:EF:4B:DE:40:25:ED:5D:8F:17:54:DD:88:33:C0:13:2E:FD:1A:FA:7E:7A:1B:79
|
||||||
string algorithm;
|
string algorithm;
|
||||||
string value;
|
string hash;
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "fingerprint";}
|
const char* getKey() override { return "fingerprint";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrSetup : public SdpItem {
|
class SdpAttrSetup : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=setup:actpass
|
//a=setup:actpass
|
||||||
DtlsRole role{DtlsRole::invalid};
|
DtlsRole role{DtlsRole::actpass};
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "setup";}
|
const char* getKey() override { return "setup";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrMid : public SdpItem {
|
class SdpAttrMid : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=mid:audio
|
//a=mid:audio
|
||||||
string mid;
|
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
|
||||||
string toString() const override { return SdpItem::toString(); };
|
|
||||||
const char* getKey() override { return "mid";}
|
const char* getKey() override { return "mid";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -364,9 +282,9 @@ class SdpAttrExtmap : public SdpItem {
|
|||||||
public:
|
public:
|
||||||
//a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
//a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
|
||||||
int index;
|
int index;
|
||||||
string value;
|
string ext;
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "extmap";}
|
const char* getKey() override { return "extmap";}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -376,68 +294,85 @@ public:
|
|||||||
uint8_t pt;
|
uint8_t pt;
|
||||||
string codec;
|
string codec;
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int channel;
|
int channel {0};
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "rtpmap";}
|
const char* getKey() override { return "rtpmap";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrRtcpFb : public SdpItem {
|
class SdpAttrRtcpFb : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=rtcp-fb:111 transport-cc
|
//a=rtcp-fb:98 nack pli
|
||||||
uint8_t pt;
|
uint8_t pt;
|
||||||
string value;
|
vector<string> arr;
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "rtcp-fb";}
|
const char* getKey() override { return "rtcp-fb";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrFmtp : public SdpItem {
|
class SdpAttrFmtp : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=rtcp-fb:111 transport-cc
|
//fmtp:96 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
|
||||||
uint8_t pt;
|
uint8_t pt;
|
||||||
map<string, string> values;
|
vector<std::pair<string, string> > arr;
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "fmtp";}
|
const char* getKey() override { return "fmtp";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrSSRC : public SdpItem {
|
class SdpAttrSSRC : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=ssrc:120276603 cname:iSkJ2vn5cYYubTve
|
//a=ssrc:120276603 cname:iSkJ2vn5cYYubTve
|
||||||
|
//a=ssrc:<ssrc-id> <attribute>
|
||||||
|
//a=ssrc:<ssrc-id> <attribute>:<value>
|
||||||
uint32_t ssrc;
|
uint32_t ssrc;
|
||||||
string key;
|
string attribute;
|
||||||
string value;
|
string attribute_value;
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "ssrc";}
|
const char* getKey() override { return "ssrc";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrSctpMap : public SdpItem {
|
class SdpAttrSctpMap : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=ssrc:120276603 cname:iSkJ2vn5cYYubTve
|
//https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-05
|
||||||
|
//a=sctpmap:5000 webrtc-datachannel 1024
|
||||||
|
//a=sctpmap: sctpmap-number media-subtypes [streams]
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
string name;
|
string subtypes;
|
||||||
int mtu;
|
int streams;
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
void parse(const string &str) override;
|
||||||
string toString() const override { return SdpItem::toString(); };
|
string toString() const override;
|
||||||
const char* getKey() override { return "sctpmap";}
|
const char* getKey() override { return "sctpmap";}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SdpAttrCandidate : public SdpItem {
|
class SdpAttrCandidate : public SdpItem {
|
||||||
public:
|
public:
|
||||||
//a=candidate:%s 1 udp %u %s %u typ %s
|
//https://tools.ietf.org/html/rfc5245
|
||||||
void parse(const string &str) override {SdpItem::parse(str); };
|
//15.1. "candidate" Attribute
|
||||||
string toString() const override { return SdpItem::toString(); };
|
//a=candidate:4 1 udp 2 192.168.1.7 58107 typ host
|
||||||
|
//a=candidate:<foundation> <component-id> <transport> <priority> <address> <port> typ <cand-type>
|
||||||
|
uint32_t foundation;
|
||||||
|
uint32_t component;
|
||||||
|
string transport {"udp"};
|
||||||
|
uint32_t priority;
|
||||||
|
string address;
|
||||||
|
uint16_t port;
|
||||||
|
string type;
|
||||||
|
vector<std::pair<string, string> > arr;
|
||||||
|
|
||||||
|
void parse(const string &str) override;
|
||||||
|
string toString() const override;
|
||||||
const char* getKey() override { return "candidate";}
|
const char* getKey() override { return "candidate";}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class RtcMedia {
|
class RtcMedia {
|
||||||
public:
|
public:
|
||||||
vector<SdpItem::Ptr> items;
|
vector<SdpItem::Ptr> items;
|
||||||
|
string toString() const;
|
||||||
bool haveAttr(const char *attr) const;
|
bool haveAttr(const char *attr) const;
|
||||||
string getAttrValue(const char *attr) const;
|
string getAttrValue(const char *attr) const;
|
||||||
|
RtpDirection getDirection() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RtcSdp {
|
class RtcSdp {
|
||||||
@ -447,41 +382,6 @@ public:
|
|||||||
|
|
||||||
void parse(const string &str);
|
void parse(const string &str);
|
||||||
string toString() const;
|
string toString() const;
|
||||||
|
|
||||||
#if 0
|
|
||||||
/////Session description(会话级别描述)////
|
|
||||||
//v= (protocol version)
|
|
||||||
int version;
|
|
||||||
//o= (session origin information )
|
|
||||||
SdpOrigin origin;
|
|
||||||
//s= (session name)
|
|
||||||
string session_name;
|
|
||||||
//t= (time the session is active)
|
|
||||||
SdpTime time;
|
|
||||||
|
|
||||||
//// 非必须 ////
|
|
||||||
//i=* (session information)
|
|
||||||
string information;
|
|
||||||
//u=* (URI of description)
|
|
||||||
string url;
|
|
||||||
//e=* (email address)
|
|
||||||
string email;
|
|
||||||
//p=* (phone number)
|
|
||||||
string phone;
|
|
||||||
//c=* (connection information -- not required if included in all media)
|
|
||||||
SdpConnection connection;
|
|
||||||
//b=* (zero or more bandwidth information lines)
|
|
||||||
SdpBandwidth bandwidth;
|
|
||||||
//z=* (time zone adjustments)
|
|
||||||
//z=<adjustment time> <offset> <adjustment time> <offset> ....
|
|
||||||
string time_zone;
|
|
||||||
//k=* (encryption key)
|
|
||||||
//k=<method>, k=<method>:<encryption key>
|
|
||||||
string crypt_key;
|
|
||||||
//r=* (zero or more repeat times)
|
|
||||||
//r=<repeat interval> <active duration> <offsets from start-time>
|
|
||||||
string repeat;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user