|
@@ -63,6 +63,7 @@ Description::Description(const string &sdp, Type type, Role role)
|
|
std::istringstream ss(sdp);
|
|
std::istringstream ss(sdp);
|
|
std::optional<Media> currentMedia;
|
|
std::optional<Media> currentMedia;
|
|
|
|
|
|
|
|
+ int mlineIndex = 0;
|
|
bool finished;
|
|
bool finished;
|
|
do {
|
|
do {
|
|
string line;
|
|
string line;
|
|
@@ -76,7 +77,9 @@ Description::Description(const string &sdp, Type type, Role role)
|
|
if (currentMedia->type == "application")
|
|
if (currentMedia->type == "application")
|
|
mData.mid = currentMedia->mid;
|
|
mData.mid = currentMedia->mid;
|
|
else
|
|
else
|
|
- mMedia.emplace(currentMedia->mid, std::move(*currentMedia));
|
|
|
|
|
|
+ mMedia.emplace(mlineIndex, std::move(*currentMedia));
|
|
|
|
+
|
|
|
|
+ ++mlineIndex;
|
|
|
|
|
|
} else if (line.find(" ICE/SDP") != string::npos) {
|
|
} else if (line.find(" ICE/SDP") != string::npos) {
|
|
PLOG_WARNING << "SDP \"m=\" line has no corresponding mid, ignoring";
|
|
PLOG_WARNING << "SDP \"m=\" line has no corresponding mid, ignoring";
|
|
@@ -190,10 +193,7 @@ bool Description::hasMedia() const { return !mMedia.empty(); }
|
|
|
|
|
|
void Description::addMedia(const Description &source) {
|
|
void Description::addMedia(const Description &source) {
|
|
for (auto p : source.mMedia)
|
|
for (auto p : source.mMedia)
|
|
- if (p.first != mData.mid)
|
|
|
|
- mMedia.emplace(std::move(p));
|
|
|
|
- else
|
|
|
|
- PLOG_WARNING << "Media mid \"" << p.first << "\" is the same as data mid, ignoring";
|
|
|
|
|
|
+ mMedia.emplace(p);
|
|
}
|
|
}
|
|
|
|
|
|
Description::operator string() const { return generateSdp("\r\n"); }
|
|
Description::operator string() const { return generateSdp("\r\n"); }
|
|
@@ -214,9 +214,12 @@ string Description::generateSdp(const string &eol) const {
|
|
// see Negotiating Media Multiplexing Using the Session Description Protocol
|
|
// see Negotiating Media Multiplexing Using the Session Description Protocol
|
|
// https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54
|
|
// https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54
|
|
sdp << "a=group:BUNDLE";
|
|
sdp << "a=group:BUNDLE";
|
|
- for (const auto &m : mMedia)
|
|
|
|
- sdp << " " << m.first; // mid
|
|
|
|
- sdp << " " << mData.mid << eol;
|
|
|
|
|
|
+ for (int i = 0; i < mMedia.size() + 1; ++i)
|
|
|
|
+ if (auto it = mMedia.find(i); it != mMedia.end())
|
|
|
|
+ sdp << ' ' << it->second.mid;
|
|
|
|
+ else
|
|
|
|
+ sdp << ' ' << mData.mid;
|
|
|
|
+ sdp << eol;
|
|
|
|
|
|
sdp << "a=msid-semantic: WMS" << eol;
|
|
sdp << "a=msid-semantic: WMS" << eol;
|
|
|
|
|
|
@@ -224,35 +227,38 @@ string Description::generateSdp(const string &eol) const {
|
|
if (!mMedia.empty()) {
|
|
if (!mMedia.empty()) {
|
|
// Lip-sync
|
|
// Lip-sync
|
|
sdp << "a=group:LS";
|
|
sdp << "a=group:LS";
|
|
- for (const auto &m : mMedia)
|
|
|
|
- sdp << " " << m.first; // mid
|
|
|
|
|
|
+ for (const auto &p : mMedia)
|
|
|
|
+ sdp << " " << p.second.mid;
|
|
sdp << eol;
|
|
sdp << eol;
|
|
|
|
+ }
|
|
|
|
|
|
- // Descriptions and attributes
|
|
|
|
- for (const auto &m : mMedia) {
|
|
|
|
- const auto &media = m.second;
|
|
|
|
|
|
+ // Descriptions and attributes
|
|
|
|
+ for (int i = 0; i < mMedia.size() + 1; ++i) {
|
|
|
|
+ if (auto it = mMedia.find(i); it != mMedia.end()) {
|
|
|
|
+ // Non-data media
|
|
|
|
+ const auto &media = it->second;
|
|
sdp << "m=" << media.type << ' ' << 0 << ' ' << media.description << eol;
|
|
sdp << "m=" << media.type << ' ' << 0 << ' ' << media.description << eol;
|
|
sdp << "c=IN IP4 0.0.0.0" << eol;
|
|
sdp << "c=IN IP4 0.0.0.0" << eol;
|
|
sdp << "a=bundle-only" << eol;
|
|
sdp << "a=bundle-only" << eol;
|
|
sdp << "a=mid:" << media.mid << eol;
|
|
sdp << "a=mid:" << media.mid << eol;
|
|
for (const auto &attr : media.attributes)
|
|
for (const auto &attr : media.attributes)
|
|
sdp << "a=" << attr << eol;
|
|
sdp << "a=" << attr << eol;
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+ // Data
|
|
|
|
+ const string description = "UDP/DTLS/SCTP webrtc-datachannel";
|
|
|
|
+ sdp << "m=application" << ' ' << (!mMedia.empty() ? 0 : 9) << ' ' << description << eol;
|
|
|
|
+ sdp << "c=IN IP4 0.0.0.0" << eol;
|
|
|
|
+ if (!mMedia.empty())
|
|
|
|
+ sdp << "a=bundle-only" << eol;
|
|
|
|
+ sdp << "a=mid:" << mData.mid << eol;
|
|
|
|
+ if (mData.sctpPort)
|
|
|
|
+ sdp << "a=sctp-port:" << *mData.sctpPort << eol;
|
|
|
|
+ if (mData.maxMessageSize)
|
|
|
|
+ sdp << "a=max-message-size:" << *mData.maxMessageSize << eol;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // Data
|
|
|
|
- const string dataDescription = "UDP/DTLS/SCTP webrtc-datachannel";
|
|
|
|
- sdp << "m=application" << ' ' << (!mMedia.empty() ? 0 : 9) << ' ' << dataDescription << eol;
|
|
|
|
- sdp << "c=IN IP4 0.0.0.0" << eol;
|
|
|
|
- if (!mMedia.empty())
|
|
|
|
- sdp << "a=bundle-only" << eol;
|
|
|
|
- sdp << "a=mid:" << mData.mid << eol;
|
|
|
|
- if (mData.sctpPort)
|
|
|
|
- sdp << "a=sctp-port:" << *mData.sctpPort << eol;
|
|
|
|
- if (mData.maxMessageSize)
|
|
|
|
- sdp << "a=max-message-size:" << *mData.maxMessageSize << eol;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
// Common
|
|
// Common
|
|
if (!mEnded)
|
|
if (!mEnded)
|
|
sdp << "a=ice-options:trickle" << eol;
|
|
sdp << "a=ice-options:trickle" << eol;
|