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:

committed by
Commit Bot

parent
4f6ef1894e
commit
13e570fcb0
@ -423,6 +423,8 @@ class SessionDescription {
|
|||||||
|
|
||||||
SessionDescription* Copy() const;
|
SessionDescription* Copy() const;
|
||||||
|
|
||||||
|
struct MediaTransportSetting;
|
||||||
|
|
||||||
// Content accessors.
|
// Content accessors.
|
||||||
const ContentInfos& contents() const { return contents_; }
|
const ContentInfos& contents() const { return contents_; }
|
||||||
ContentInfos& contents() { return contents_; }
|
ContentInfos& contents() { return contents_; }
|
||||||
@ -510,6 +512,32 @@ class SessionDescription {
|
|||||||
}
|
}
|
||||||
bool extmap_allow_mixed() const { return extmap_allow_mixed_; }
|
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:
|
private:
|
||||||
SessionDescription(const SessionDescription&);
|
SessionDescription(const SessionDescription&);
|
||||||
|
|
||||||
@ -526,6 +554,8 @@ class SessionDescription {
|
|||||||
// correctly. If it's included in offer to us we will respond that we support
|
// correctly. If it's included in offer to us we will respond that we support
|
||||||
// it.
|
// it.
|
||||||
bool extmap_allow_mixed_ = false;
|
bool extmap_allow_mixed_ = false;
|
||||||
|
|
||||||
|
std::vector<MediaTransportSetting> media_transport_settings_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Indicates whether a session description was sent by the local client or
|
// Indicates whether a session description was sent by the local client or
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
#include "rtc_base/message_digest.h"
|
#include "rtc_base/message_digest.h"
|
||||||
#include "rtc_base/strings/string_builder.h"
|
#include "rtc_base/strings/string_builder.h"
|
||||||
|
#include "rtc_base/third_party/base64/base64.h"
|
||||||
|
|
||||||
using cricket::AudioContentDescription;
|
using cricket::AudioContentDescription;
|
||||||
using cricket::Candidate;
|
using cricket::Candidate;
|
||||||
@ -235,6 +236,13 @@ static const char kApplicationSpecificMaximum[] = "AS";
|
|||||||
|
|
||||||
static const char kDefaultSctpmapProtocol[] = "webrtc-datachannel";
|
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
|
// RTP payload type is in the 0-127 range. Use -1 to indicate "all" payload
|
||||||
// types.
|
// types.
|
||||||
const int kWildcardPayloadType = -1;
|
const int kWildcardPayloadType = -1;
|
||||||
@ -2049,6 +2057,28 @@ bool ParseConnectionData(const std::string& line,
|
|||||||
return true;
|
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,
|
bool ParseSessionDescription(const std::string& message,
|
||||||
size_t* pos,
|
size_t* pos,
|
||||||
std::string* session_id,
|
std::string* session_id,
|
||||||
@ -2206,6 +2236,24 @@ bool ParseSessionDescription(const std::string& message,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
session_extmaps->push_back(extmap);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4324,3 +4324,97 @@ TEST_F(WebRtcSdpTest, ParseNoMid) {
|
|||||||
ElementsAre(Field("name", &cricket::ContentInfo::name, ""),
|
ElementsAre(Field("name", &cricket::ContentInfo::name, ""),
|
||||||
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());
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user