summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/sdp/SipccSdpMediaSection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/sdp/SipccSdpMediaSection.cpp')
-rw-r--r--dom/media/webrtc/sdp/SipccSdpMediaSection.cpp401
1 files changed, 401 insertions, 0 deletions
diff --git a/dom/media/webrtc/sdp/SipccSdpMediaSection.cpp b/dom/media/webrtc/sdp/SipccSdpMediaSection.cpp
new file mode 100644
index 0000000000..4304ca541e
--- /dev/null
+++ b/dom/media/webrtc/sdp/SipccSdpMediaSection.cpp
@@ -0,0 +1,401 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "sdp/SipccSdpMediaSection.h"
+
+#include <ostream>
+#include "sdp/SdpParser.h"
+
+extern "C" {
+#include "sipcc_sdp.h"
+}
+
+#ifdef CRLF
+# undef CRLF
+#endif
+#define CRLF "\r\n"
+
+namespace mozilla {
+
+SipccSdpMediaSection::SipccSdpMediaSection(
+ const SipccSdpMediaSection& aOrig,
+ const SipccSdpAttributeList* sessionLevel)
+ : SdpMediaSection(aOrig),
+ mMediaType(aOrig.mMediaType),
+ mPort(aOrig.mPort),
+ mPortCount(aOrig.mPortCount),
+ mProtocol(aOrig.mProtocol),
+ mFormats(aOrig.mFormats),
+ mConnection(new SdpConnection(*aOrig.mConnection)),
+ mBandwidths(aOrig.mBandwidths),
+ mAttributeList(aOrig.mAttributeList, sessionLevel) {}
+
+unsigned int SipccSdpMediaSection::GetPort() const { return mPort; }
+
+void SipccSdpMediaSection::SetPort(unsigned int port) { mPort = port; }
+
+unsigned int SipccSdpMediaSection::GetPortCount() const { return mPortCount; }
+
+SdpMediaSection::Protocol SipccSdpMediaSection::GetProtocol() const {
+ return mProtocol;
+}
+
+const SdpConnection& SipccSdpMediaSection::GetConnection() const {
+ return *mConnection;
+}
+
+SdpConnection& SipccSdpMediaSection::GetConnection() { return *mConnection; }
+
+uint32_t SipccSdpMediaSection::GetBandwidth(const std::string& type) const {
+ auto found = mBandwidths.find(type);
+ if (found == mBandwidths.end()) {
+ return 0;
+ }
+ return found->second;
+}
+
+const std::vector<std::string>& SipccSdpMediaSection::GetFormats() const {
+ return mFormats;
+}
+
+const SdpAttributeList& SipccSdpMediaSection::GetAttributeList() const {
+ return mAttributeList;
+}
+
+SdpAttributeList& SipccSdpMediaSection::GetAttributeList() {
+ return mAttributeList;
+}
+
+SdpDirectionAttribute SipccSdpMediaSection::GetDirectionAttribute() const {
+ return SdpDirectionAttribute(mAttributeList.GetDirection());
+}
+
+bool SipccSdpMediaSection::Load(sdp_t* sdp, uint16_t level,
+ InternalResults& results) {
+ switch (sdp_get_media_type(sdp, level)) {
+ case SDP_MEDIA_AUDIO:
+ mMediaType = kAudio;
+ break;
+ case SDP_MEDIA_VIDEO:
+ mMediaType = kVideo;
+ break;
+ case SDP_MEDIA_APPLICATION:
+ mMediaType = kApplication;
+ break;
+ case SDP_MEDIA_TEXT:
+ mMediaType = kText;
+ break;
+
+ default:
+ results.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported media section type");
+ return false;
+ }
+
+ mPort = sdp_get_media_portnum(sdp, level);
+ int32_t pc = sdp_get_media_portcount(sdp, level);
+ if (pc == SDP_INVALID_VALUE) {
+ // SDP_INVALID_VALUE (ie; -2) is used when there is no port count. :(
+ mPortCount = 0;
+ } else if (pc > static_cast<int32_t>(UINT16_MAX) || pc < 0) {
+ results.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Invalid port count");
+ return false;
+ } else {
+ mPortCount = pc;
+ }
+
+ if (!LoadProtocol(sdp, level, results)) {
+ return false;
+ }
+
+ if (!LoadFormats(sdp, level, results)) {
+ return false;
+ }
+
+ if (!mAttributeList.Load(sdp, level, results)) {
+ return false;
+ }
+
+ if (!ValidateSimulcast(sdp, level, results)) {
+ return false;
+ }
+
+ if (!mBandwidths.Load(sdp, level, results)) {
+ return false;
+ }
+
+ return LoadConnection(sdp, level, results);
+}
+
+bool SipccSdpMediaSection::LoadProtocol(sdp_t* sdp, uint16_t level,
+ InternalResults& results) {
+ switch (sdp_get_media_transport(sdp, level)) {
+ case SDP_TRANSPORT_RTPAVP:
+ mProtocol = kRtpAvp;
+ break;
+ case SDP_TRANSPORT_RTPSAVP:
+ mProtocol = kRtpSavp;
+ break;
+ case SDP_TRANSPORT_RTPAVPF:
+ mProtocol = kRtpAvpf;
+ break;
+ case SDP_TRANSPORT_RTPSAVPF:
+ mProtocol = kRtpSavpf;
+ break;
+ case SDP_TRANSPORT_UDPTLSRTPSAVP:
+ mProtocol = kUdpTlsRtpSavp;
+ break;
+ case SDP_TRANSPORT_UDPTLSRTPSAVPF:
+ mProtocol = kUdpTlsRtpSavpf;
+ break;
+ case SDP_TRANSPORT_TCPDTLSRTPSAVP:
+ mProtocol = kTcpDtlsRtpSavp;
+ break;
+ case SDP_TRANSPORT_TCPDTLSRTPSAVPF:
+ mProtocol = kTcpDtlsRtpSavpf;
+ break;
+ case SDP_TRANSPORT_DTLSSCTP:
+ mProtocol = kDtlsSctp;
+ break;
+ case SDP_TRANSPORT_UDPDTLSSCTP:
+ mProtocol = kUdpDtlsSctp;
+ break;
+ case SDP_TRANSPORT_TCPDTLSSCTP:
+ mProtocol = kTcpDtlsSctp;
+ break;
+
+ default:
+ results.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported media transport type");
+ return false;
+ }
+ return true;
+}
+
+bool SipccSdpMediaSection::LoadFormats(sdp_t* sdp, uint16_t level,
+ InternalResults& results) {
+ sdp_media_e mtype = sdp_get_media_type(sdp, level);
+
+ if (mtype == SDP_MEDIA_APPLICATION) {
+ sdp_transport_e ttype = sdp_get_media_transport(sdp, level);
+ if ((ttype == SDP_TRANSPORT_UDPDTLSSCTP) ||
+ (ttype == SDP_TRANSPORT_TCPDTLSSCTP)) {
+ if (sdp_get_media_sctp_fmt(sdp, level) ==
+ SDP_SCTP_MEDIA_FMT_WEBRTC_DATACHANNEL) {
+ mFormats.push_back("webrtc-datachannel");
+ }
+ } else {
+ uint32_t ptype = sdp_get_media_sctp_port(sdp, level);
+ std::ostringstream osPayloadType;
+ osPayloadType << ptype;
+ mFormats.push_back(osPayloadType.str());
+ }
+ } else if (mtype == SDP_MEDIA_AUDIO || mtype == SDP_MEDIA_VIDEO) {
+ uint16_t count = sdp_get_media_num_payload_types(sdp, level);
+ for (uint16_t i = 0; i < count; ++i) {
+ sdp_payload_ind_e indicator; // we ignore this, which is fine
+ uint32_t ptype =
+ sdp_get_media_payload_type(sdp, level, i + 1, &indicator);
+
+ if (GET_DYN_PAYLOAD_TYPE_VALUE(ptype) > UINT8_MAX) {
+ results.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Format is too large");
+ return false;
+ }
+
+ std::ostringstream osPayloadType;
+ // sipcc stores payload types in a funny way. When sipcc and the SDP it
+ // parsed differ on what payload type number should be used for a given
+ // codec, sipcc's value goes in the lower byte, and the SDP's value in
+ // the upper byte. When they do not differ, only the lower byte is used.
+ // We want what was in the SDP, verbatim.
+ osPayloadType << GET_DYN_PAYLOAD_TYPE_VALUE(ptype);
+ mFormats.push_back(osPayloadType.str());
+ }
+ }
+
+ return true;
+}
+
+bool SipccSdpMediaSection::ValidateSimulcast(sdp_t* sdp, uint16_t level,
+ InternalResults& results) const {
+ if (!GetAttributeList().HasAttribute(SdpAttribute::kSimulcastAttribute)) {
+ return true;
+ }
+
+ const SdpSimulcastAttribute& simulcast(GetAttributeList().GetSimulcast());
+ if (!ValidateSimulcastVersions(sdp, level, simulcast.sendVersions, sdp::kSend,
+ results)) {
+ return false;
+ }
+ if (!ValidateSimulcastVersions(sdp, level, simulcast.recvVersions, sdp::kRecv,
+ results)) {
+ return false;
+ }
+ return true;
+}
+
+bool SipccSdpMediaSection::ValidateSimulcastVersions(
+ sdp_t* sdp, uint16_t level, const SdpSimulcastAttribute::Versions& versions,
+ sdp::Direction direction, InternalResults& results) const {
+ for (const SdpSimulcastAttribute::Version& version : versions) {
+ for (const SdpSimulcastAttribute::Encoding& encoding : version.choices) {
+ const SdpRidAttributeList::Rid* ridAttr = FindRid(encoding.rid);
+ if (!ridAttr || (ridAttr->direction != direction)) {
+ std::ostringstream os;
+ os << "No rid attribute for \'" << encoding.rid << "\'";
+ results.AddParseError(sdp_get_media_line_number(sdp, level), os.str());
+ results.AddParseError(sdp_get_media_line_number(sdp, level), os.str());
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool SipccSdpMediaSection::LoadConnection(sdp_t* sdp, uint16_t level,
+ InternalResults& results) {
+ if (!sdp_connection_valid(sdp, level)) {
+ level = SDP_SESSION_LEVEL;
+ if (!sdp_connection_valid(sdp, level)) {
+ results.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Missing c= line");
+ return false;
+ }
+ }
+
+ sdp_nettype_e type = sdp_get_conn_nettype(sdp, level);
+ if (type != SDP_NT_INTERNET) {
+ results.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported network type");
+ return false;
+ }
+
+ sdp::AddrType addrType;
+ switch (sdp_get_conn_addrtype(sdp, level)) {
+ case SDP_AT_IP4:
+ addrType = sdp::kIPv4;
+ break;
+ case SDP_AT_IP6:
+ addrType = sdp::kIPv6;
+ break;
+ default:
+ results.AddParseError(sdp_get_media_line_number(sdp, level),
+ "Unsupported address type");
+ return false;
+ }
+
+ std::string address = sdp_get_conn_address(sdp, level);
+ int16_t ttl = static_cast<uint16_t>(sdp_get_mcast_ttl(sdp, level));
+ if (ttl < 0) {
+ ttl = 0;
+ }
+ int32_t numAddr =
+ static_cast<uint32_t>(sdp_get_mcast_num_of_addresses(sdp, level));
+ if (numAddr < 0) {
+ numAddr = 0;
+ }
+ mConnection = MakeUnique<SdpConnection>(addrType, address, ttl, numAddr);
+ return true;
+}
+
+void SipccSdpMediaSection::AddCodec(const std::string& pt,
+ const std::string& name, uint32_t clockrate,
+ uint16_t channels) {
+ mFormats.push_back(pt);
+
+ SdpRtpmapAttributeList* rtpmap = new SdpRtpmapAttributeList();
+ if (mAttributeList.HasAttribute(SdpAttribute::kRtpmapAttribute)) {
+ const SdpRtpmapAttributeList& old = mAttributeList.GetRtpmap();
+ for (auto it = old.mRtpmaps.begin(); it != old.mRtpmaps.end(); ++it) {
+ rtpmap->mRtpmaps.push_back(*it);
+ }
+ }
+ SdpRtpmapAttributeList::CodecType codec = SdpRtpmapAttributeList::kOtherCodec;
+ if (name == "opus") {
+ codec = SdpRtpmapAttributeList::kOpus;
+ } else if (name == "G722") {
+ codec = SdpRtpmapAttributeList::kG722;
+ } else if (name == "PCMU") {
+ codec = SdpRtpmapAttributeList::kPCMU;
+ } else if (name == "PCMA") {
+ codec = SdpRtpmapAttributeList::kPCMA;
+ } else if (name == "VP8") {
+ codec = SdpRtpmapAttributeList::kVP8;
+ } else if (name == "VP9") {
+ codec = SdpRtpmapAttributeList::kVP9;
+ } else if (name == "H264") {
+ codec = SdpRtpmapAttributeList::kH264;
+ }
+
+ rtpmap->PushEntry(pt, codec, name, clockrate, channels);
+ mAttributeList.SetAttribute(rtpmap);
+}
+
+void SipccSdpMediaSection::ClearCodecs() {
+ mFormats.clear();
+ mAttributeList.RemoveAttribute(SdpAttribute::kRtpmapAttribute);
+ mAttributeList.RemoveAttribute(SdpAttribute::kFmtpAttribute);
+ mAttributeList.RemoveAttribute(SdpAttribute::kSctpmapAttribute);
+ mAttributeList.RemoveAttribute(SdpAttribute::kRtcpFbAttribute);
+}
+
+void SipccSdpMediaSection::AddDataChannel(const std::string& name,
+ uint16_t port, uint16_t streams,
+ uint32_t message_size) {
+ // Only one allowed, for now. This may change as the specs (and deployments)
+ // evolve.
+ mFormats.clear();
+ if ((mProtocol == kUdpDtlsSctp) || (mProtocol == kTcpDtlsSctp)) {
+ // new data channel format according to draft 21
+ mFormats.push_back(name);
+ mAttributeList.SetAttribute(
+ new SdpNumberAttribute(SdpAttribute::kSctpPortAttribute, port));
+ if (message_size) {
+ mAttributeList.SetAttribute(new SdpNumberAttribute(
+ SdpAttribute::kMaxMessageSizeAttribute, message_size));
+ }
+ } else {
+ // old data channels format according to draft 05
+ std::string port_str = std::to_string(port);
+ mFormats.push_back(port_str);
+ SdpSctpmapAttributeList* sctpmap = new SdpSctpmapAttributeList();
+ sctpmap->PushEntry(port_str, name, streams);
+ mAttributeList.SetAttribute(sctpmap);
+ if (message_size) {
+ // This is a workaround to allow detecting Firefox's w/o EOR support
+ mAttributeList.SetAttribute(new SdpNumberAttribute(
+ SdpAttribute::kMaxMessageSizeAttribute, message_size));
+ }
+ }
+}
+
+void SipccSdpMediaSection::Serialize(std::ostream& os) const {
+ os << "m=" << mMediaType << " " << mPort;
+ if (mPortCount) {
+ os << "/" << mPortCount;
+ }
+ os << " " << mProtocol;
+ for (auto i = mFormats.begin(); i != mFormats.end(); ++i) {
+ os << " " << (*i);
+ }
+ os << CRLF;
+
+ // We dont do i=
+
+ if (mConnection) {
+ os << *mConnection;
+ }
+
+ mBandwidths.Serialize(os);
+
+ // We dont do k= because they're evil
+
+ os << mAttributeList;
+}
+
+} // namespace mozilla