Add a parser for the x-mt line.

This change adds a parser for the x-mt line to the WebRTC SDP, and adds a collection in the SessionDescription for media transport.

x-mt line contains information about media transport settings.

This is an experimental line.

This change will be followed up by two other changes:
* Setting the offer with x-mt
* Using the x-mt line to pass it to the media transport

Bug: webrtc:9719
Change-Id: I46568610d4092a69ada7b7c1d3987d698ddba0be
Reviewed-on: https://webrtc-review.googlesource.com/c/124601
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Bjorn Mellem <mellem@webrtc.org>
Commit-Queue: Peter Slatala <psla@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26881}
This commit is contained in:
Piotr (Peter) Slatala
2019-02-27 11:34:26 -08:00
committed by Commit Bot
parent 4f6ef1894e
commit 13e570fcb0
3 changed files with 172 additions and 0 deletions

View File

@ -423,6 +423,8 @@ class SessionDescription {
SessionDescription* Copy() const;
struct MediaTransportSetting;
// Content accessors.
const ContentInfos& contents() const { return contents_; }
ContentInfos& contents() { return contents_; }
@ -510,6 +512,32 @@ class SessionDescription {
}
bool extmap_allow_mixed() const { return extmap_allow_mixed_; }
// Adds the media transport setting.
// Media transport name uniquely identifies the type of media transport.
// The name cannot be empty, or repeated in the previously added transport
// settings.
void AddMediaTransportSetting(const std::string& media_transport_name,
const std::string& media_transport_setting) {
RTC_DCHECK(!media_transport_name.empty());
for (const auto& setting : media_transport_settings_) {
RTC_DCHECK(media_transport_name != setting.transport_name)
<< "MediaTransportSetting was already registered, transport_name="
<< setting.transport_name;
}
media_transport_settings_.push_back(
{media_transport_name, media_transport_setting});
}
// Gets the media transport settings, in order of preference.
const std::vector<MediaTransportSetting>& MediaTransportSettings() const {
return media_transport_settings_;
}
struct MediaTransportSetting {
std::string transport_name;
std::string transport_setting;
};
private:
SessionDescription(const SessionDescription&);
@ -526,6 +554,8 @@ class SessionDescription {
// correctly. If it's included in offer to us we will respond that we support
// it.
bool extmap_allow_mixed_ = false;
std::vector<MediaTransportSetting> media_transport_settings_;
};
// Indicates whether a session description was sent by the local client or

View File

@ -46,6 +46,7 @@
#include "rtc_base/logging.h"
#include "rtc_base/message_digest.h"
#include "rtc_base/strings/string_builder.h"
#include "rtc_base/third_party/base64/base64.h"
using cricket::AudioContentDescription;
using cricket::Candidate;
@ -235,6 +236,13 @@ static const char kApplicationSpecificMaximum[] = "AS";
static const char kDefaultSctpmapProtocol[] = "webrtc-datachannel";
// This is a non-standardized media transport settings.
// This setting is going to be set in the offer. There may be one or more
// a=x-mt: settings, and they are in the priority order (the most preferred on
// top). x-mt setting format depends on the media transport, and is generated by
// |MediaTransportInterface::GetTransportParametersOffer|.
static const char kMediaTransportSettingLine[] = "x-mt";
// RTP payload type is in the 0-127 range. Use -1 to indicate "all" payload
// types.
const int kWildcardPayloadType = -1;
@ -2049,6 +2057,28 @@ bool ParseConnectionData(const std::string& line,
return true;
}
bool ParseMediaTransportLine(const std::string& line,
std::string* transport_name,
std::string* transport_setting,
SdpParseError* error) {
std::string value;
if (!GetValue(line, kMediaTransportSettingLine, &value, error)) {
return false;
}
std::string media_transport_settings_base64;
if (!rtc::tokenize_first(value, kSdpDelimiterColonChar, transport_name,
&media_transport_settings_base64)) {
return ParseFailedGetValue(line, kMediaTransportSettingLine, error);
}
if (!rtc::Base64::Decode(media_transport_settings_base64,
rtc::Base64::DO_STRICT, transport_setting,
nullptr)) {
return ParseFailedGetValue(line, kMediaTransportSettingLine, error);
}
return true;
}
bool ParseSessionDescription(const std::string& message,
size_t* pos,
std::string* session_id,
@ -2206,6 +2236,24 @@ bool ParseSessionDescription(const std::string& message,
return false;
}
session_extmaps->push_back(extmap);
} else if (HasAttribute(line, kMediaTransportSettingLine)) {
std::string transport_name;
std::string transport_setting;
if (!ParseMediaTransportLine(line, &transport_name, &transport_setting,
error)) {
return false;
}
for (const auto& setting : desc->MediaTransportSettings()) {
if (setting.transport_name == transport_name) {
// Ignore repeated transport names rather than failing to parse so
// that in the future the same transport could have multiple configs.
RTC_LOG(INFO) << "x-mt line with repeated transport, transport_name="
<< transport_name;
return true;
}
}
desc->AddMediaTransportSetting(transport_name, transport_setting);
}
}

View File

@ -4324,3 +4324,97 @@ TEST_F(WebRtcSdpTest, ParseNoMid) {
ElementsAre(Field("name", &cricket::ContentInfo::name, ""),
Field("name", &cricket::ContentInfo::name, "")));
}
// Test that the media transport name and base64-decoded setting is parsed from
// an a=x-mt line.
TEST_F(WebRtcSdpTest, ParseMediaTransport) {
JsepSessionDescription output(kDummyType);
std::string sdp = kSdpSessionString;
sdp += "a=x-mt:rtp:dGVzdDY0\r\n";
SdpParseError error;
ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error))
<< error.description;
const auto& settings = output.description()->MediaTransportSettings();
ASSERT_EQ(1u, settings.size());
EXPECT_EQ("rtp", settings[0].transport_name);
EXPECT_EQ("test64", settings[0].transport_setting);
}
// Test that an a=x-mt line fails to parse if its setting is invalid base 64.
TEST_F(WebRtcSdpTest, ParseMediaTransportInvalidBase64) {
JsepSessionDescription output(kDummyType);
std::string sdp = kSdpSessionString;
sdp += "a=x-mt:rtp:ThisIsInvalidBase64\r\n";
SdpParseError error;
ASSERT_FALSE(webrtc::SdpDeserialize(sdp, &output, &error));
}
// Test that multiple a=x-mt lines are parsed in the order of preference (the
// order of the lines in the SDP).
TEST_F(WebRtcSdpTest, ParseMediaTransportMultipleLines) {
JsepSessionDescription output(kDummyType);
std::string sdp = kSdpSessionString;
sdp +=
"a=x-mt:rtp:dGVzdDY0\r\n"
"a=x-mt:generic:Z2VuZXJpY3NldHRpbmc=\r\n";
SdpParseError error;
ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error))
<< error.description;
const auto& settings = output.description()->MediaTransportSettings();
ASSERT_EQ(2u, settings.size());
EXPECT_EQ("rtp", settings[0].transport_name);
EXPECT_EQ("test64", settings[0].transport_setting);
EXPECT_EQ("generic", settings[1].transport_name);
EXPECT_EQ("genericsetting", settings[1].transport_setting);
}
// Test that only the first a=x-mt line associated with a transport name is
// parsed and the rest ignored.
TEST_F(WebRtcSdpTest, ParseMediaTransportSkipRepeatedTransport) {
JsepSessionDescription output(kDummyType);
std::string sdp = kSdpSessionString;
sdp +=
"a=x-mt:rtp:dGVzdDY0\r\n"
"a=x-mt:rtp:Z2VuZXJpY3NldHRpbmc=\r\n";
SdpParseError error;
// Repeated 'rtp' transport setting. We still parse the SDP successfully,
// but ignore the repeated transport.
ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
const auto& settings = output.description()->MediaTransportSettings();
EXPECT_EQ("test64", settings[0].transport_setting);
}
// Test that an a=x-mt line fails to parse if it is missing a setting.
TEST_F(WebRtcSdpTest, ParseMediaTransportMalformedLine) {
JsepSessionDescription output(kDummyType);
std::string sdp = kSdpSessionString;
sdp += "a=x-mt:rtp\r\n";
SdpParseError error;
ASSERT_FALSE(webrtc::SdpDeserialize(sdp, &output, &error));
}
// Test that an a=x-mt line fails to parse if its missing a name and setting.
TEST_F(WebRtcSdpTest, ParseMediaTransportMalformedLine2) {
JsepSessionDescription output(kDummyType);
std::string sdp = kSdpSessionString;
sdp += "a=x-mt\r\n";
SdpParseError error;
ASSERT_FALSE(webrtc::SdpDeserialize(sdp, &output, &error));
}
TEST_F(WebRtcSdpTest, ParseMediaTransportIgnoreNonsenseAttributeLines) {
JsepSessionDescription output(kDummyType);
std::string sdp = kSdpSessionString;
sdp += "a=x-nonsense:rtp:dGVzdDY0\r\n";
SdpParseError error;
ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error))
<< error.description;
EXPECT_TRUE(output.description()->MediaTransportSettings().empty());
}