RtpTransceiverInterface: add header_extensions_to_offer()

This change adds exposure of a new transceiver method for getting
the total set of supported extensions stored as an attribute,
and their direction. If the direction is kStopped, the extension
is not signalled in Unified Plan SDP negotiation.

Note: SDP negotiation is not modified by this change.

Changes:
- RtpHeaderExtensionCapability gets a new RtpTransceiverDirection,
  indicating either kStopped (extension available but not signalled),
  or other (extension signalled).
- RtpTransceiver gets the new method as described above. The
  default value of the attribute comes from the voice and video
  engines as before.

https://chromestatus.com/feature/5680189201711104.
go/rtp-header-extension-ip
Intent to prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/65YdUi02yZk

Bug: chromium:1051821
Change-Id: I440443b474db5b1cfe8c6b25b6c10a3ff9c21a8c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/170235
Commit-Queue: Markus Handell <handellm@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30800}
This commit is contained in:
Markus Handell 2020-03-16 13:40:51 +01:00 committed by Commit Bot
parent 645f24cb86
commit 0357b3e7b6
29 changed files with 486 additions and 122 deletions

View file

@ -171,6 +171,7 @@ rtc_library("libjingle_peerconnection_api") {
":rtc_stats_api",
":rtp_packet_info",
":rtp_parameters",
":rtp_transceiver_direction",
":scoped_refptr",
"audio:audio_mixer_api",
"audio_codecs:audio_codecs_api",
@ -297,6 +298,11 @@ rtc_source_set("track_id_stream_label_map") {
sources = [ "test/track_id_stream_label_map.h" ]
}
rtc_source_set("rtp_transceiver_direction") {
visibility = [ "*" ]
sources = [ "rtp_transceiver_direction.h" ]
}
rtc_library("rtp_parameters") {
visibility = [ "*" ]
sources = [
@ -307,6 +313,7 @@ rtc_library("rtp_parameters") {
]
deps = [
":array_view",
":rtp_transceiver_direction",
"../rtc_base:checks",
"../rtc_base:stringutils",
"../rtc_base/system:rtc_export",

View file

@ -38,6 +38,11 @@ RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
const std::string& uri,
int preferred_id)
: uri(uri), preferred_id(preferred_id) {}
RtpHeaderExtensionCapability::RtpHeaderExtensionCapability(
const std::string& uri,
int preferred_id,
RtpTransceiverDirection direction)
: uri(uri), preferred_id(preferred_id), direction(direction) {}
RtpHeaderExtensionCapability::~RtpHeaderExtensionCapability() = default;
RtpExtension::RtpExtension() = default;

View file

@ -19,6 +19,7 @@
#include "absl/types/optional.h"
#include "api/media_types.h"
#include "api/rtp_transceiver_direction.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
@ -200,7 +201,8 @@ struct RTC_EXPORT RtpCodecCapability {
bool operator!=(const RtpCodecCapability& o) const { return !(*this == o); }
};
// Used in RtpCapabilities; represents the capabilities/preferences of an
// Used in RtpCapabilities and RtpTransceiverInterface's header extensions query
// and setup methods; represents the capabilities/preferences of an
// implementation for a header extension.
//
// Just called "RtpHeaderExtension" in ORTC, but the "Capability" suffix was
@ -210,7 +212,7 @@ struct RTC_EXPORT RtpCodecCapability {
// Note that ORTC includes a "kind" field, but we omit this because it's
// redundant; if you call "RtpReceiver::GetCapabilities(MEDIA_TYPE_AUDIO)",
// you know you're getting audio capabilities.
struct RtpHeaderExtensionCapability {
struct RTC_EXPORT RtpHeaderExtensionCapability {
// URI of this extension, as defined in RFC8285.
std::string uri;
@ -221,15 +223,23 @@ struct RtpHeaderExtensionCapability {
// TODO(deadbeef): Not implemented.
bool preferred_encrypt = false;
// The direction of the extension. The kStopped value is only used with
// RtpTransceiverInterface::header_extensions_offered() and
// SetOfferedRtpHeaderExtensions().
RtpTransceiverDirection direction = RtpTransceiverDirection::kSendRecv;
// Constructors for convenience.
RtpHeaderExtensionCapability();
explicit RtpHeaderExtensionCapability(const std::string& uri);
RtpHeaderExtensionCapability(const std::string& uri, int preferred_id);
RtpHeaderExtensionCapability(const std::string& uri,
int preferred_id,
RtpTransceiverDirection direction);
~RtpHeaderExtensionCapability();
bool operator==(const RtpHeaderExtensionCapability& o) const {
return uri == o.uri && preferred_id == o.preferred_id &&
preferred_encrypt == o.preferred_encrypt;
preferred_encrypt == o.preferred_encrypt && direction == o.direction;
}
bool operator!=(const RtpHeaderExtensionCapability& o) const {
return !(*this == o);

View file

@ -0,0 +1,27 @@
/*
* Copyright 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_RTP_TRANSCEIVER_DIRECTION_H_
#define API_RTP_TRANSCEIVER_DIRECTION_H_
namespace webrtc {
// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection
enum class RtpTransceiverDirection {
kSendRecv,
kSendOnly,
kRecvOnly,
kInactive,
kStopped,
};
} // namespace webrtc
#endif // API_RTP_TRANSCEIVER_DIRECTION_H_

View file

@ -36,4 +36,9 @@ std::vector<RtpCodecCapability> RtpTransceiverInterface::codec_preferences()
return {};
}
std::vector<RtpHeaderExtensionCapability>
RtpTransceiverInterface::HeaderExtensionsToOffer() const {
return {};
}
} // namespace webrtc

View file

@ -20,21 +20,13 @@
#include "api/rtp_parameters.h"
#include "api/rtp_receiver_interface.h"
#include "api/rtp_sender_interface.h"
#include "api/rtp_transceiver_direction.h"
#include "api/scoped_refptr.h"
#include "rtc_base/ref_count.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverdirection
enum class RtpTransceiverDirection {
kSendRecv,
kSendOnly,
kRecvOnly,
kInactive,
kStopped,
};
// Structure for initializing an RtpTransceiver in a call to
// PeerConnectionInterface::AddTransceiver.
// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit
@ -134,6 +126,13 @@ class RTC_EXPORT RtpTransceiverInterface : public rtc::RefCountInterface {
rtc::ArrayView<RtpCodecCapability> codecs);
virtual std::vector<RtpCodecCapability> codec_preferences() const;
// Readonly attribute which contains the set of header extensions that was set
// with SetOfferedRtpHeaderExtensions, or a default set if it has not been
// called.
// https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
virtual std::vector<RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
const;
protected:
~RtpTransceiverInterface() override = default;
};

View file

@ -599,6 +599,7 @@ if (rtc_include_tests) {
]
sources = [
"base/codec_unittest.cc",
"base/media_engine_unittest.cc",
"base/rtp_data_engine_unittest.cc",
"base/rtp_utils_unittest.cc",
"base/sdp_fmtp_utils_unittest.cc",

View file

@ -513,9 +513,6 @@ FakeVoiceEngine::FakeVoiceEngine() : fail_create_channel_(false) {
// sanity checks against that.
SetCodecs({AudioCodec(101, "fake_audio_codec", 0, 0, 1)});
}
RtpCapabilities FakeVoiceEngine::GetCapabilities() const {
return RtpCapabilities();
}
void FakeVoiceEngine::Init() {}
rtc::scoped_refptr<webrtc::AudioState> FakeVoiceEngine::GetAudioState() const {
return rtc::scoped_refptr<webrtc::AudioState>();
@ -564,15 +561,22 @@ bool FakeVoiceEngine::StartAecDump(webrtc::FileWrapper file,
}
void FakeVoiceEngine::StopAecDump() {}
std::vector<webrtc::RtpHeaderExtensionCapability>
FakeVoiceEngine::GetRtpHeaderExtensions() const {
return header_extensions_;
}
void FakeVoiceEngine::SetRtpHeaderExtensions(
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions) {
header_extensions_ = std::move(header_extensions);
}
FakeVideoEngine::FakeVideoEngine()
: capture_(false), fail_create_channel_(false) {
// Add a fake video codec. Note that the name must not be "" as there are
// sanity checks against that.
codecs_.push_back(VideoCodec(0, "fake_video_codec"));
}
RtpCapabilities FakeVideoEngine::GetCapabilities() const {
return RtpCapabilities();
}
bool FakeVideoEngine::SetOptions(const VideoOptions& options) {
options_ = options;
return true;
@ -609,6 +613,14 @@ bool FakeVideoEngine::SetCapture(bool capture) {
capture_ = capture;
return true;
}
std::vector<webrtc::RtpHeaderExtensionCapability>
FakeVideoEngine::GetRtpHeaderExtensions() const {
return header_extensions_;
}
void FakeVideoEngine::SetRtpHeaderExtensions(
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions) {
header_extensions_ = std::move(header_extensions);
}
FakeMediaEngine::FakeMediaEngine()
: CompositeMediaEngine(std::make_unique<FakeVoiceEngine>(),

View file

@ -514,7 +514,6 @@ class FakeDataMediaChannel : public RtpHelper<DataMediaChannel> {
class FakeVoiceEngine : public VoiceEngineInterface {
public:
FakeVoiceEngine();
RtpCapabilities GetCapabilities() const override;
void Init() override;
rtc::scoped_refptr<webrtc::AudioState> GetAudioState() const override;
@ -536,12 +535,17 @@ class FakeVoiceEngine : public VoiceEngineInterface {
int GetInputLevel();
bool StartAecDump(webrtc::FileWrapper file, int64_t max_size_bytes) override;
void StopAecDump() override;
std::vector<webrtc::RtpHeaderExtensionCapability> GetRtpHeaderExtensions()
const override;
void SetRtpHeaderExtensions(
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions);
private:
std::vector<FakeVoiceMediaChannel*> channels_;
std::vector<AudioCodec> recv_codecs_;
std::vector<AudioCodec> send_codecs_;
bool fail_create_channel_;
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions_;
friend class FakeMediaEngine;
};
@ -549,7 +553,6 @@ class FakeVoiceEngine : public VoiceEngineInterface {
class FakeVideoEngine : public VideoEngineInterface {
public:
FakeVideoEngine();
RtpCapabilities GetCapabilities() const override;
bool SetOptions(const VideoOptions& options);
VideoMediaChannel* CreateMediaChannel(
webrtc::Call* call,
@ -563,6 +566,10 @@ class FakeVideoEngine : public VideoEngineInterface {
std::vector<VideoCodec> codecs() const override;
void SetCodecs(const std::vector<VideoCodec> codecs);
bool SetCapture(bool capture);
std::vector<webrtc::RtpHeaderExtensionCapability> GetRtpHeaderExtensions()
const override;
void SetRtpHeaderExtensions(
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions);
private:
std::vector<FakeVideoMediaChannel*> channels_;
@ -570,6 +577,7 @@ class FakeVideoEngine : public VideoEngineInterface {
bool capture_;
VideoOptions options_;
bool fail_create_channel_;
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions_;
friend class FakeMediaEngine;
};

View file

@ -55,6 +55,16 @@ webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp) {
return parameters;
}
std::vector<webrtc::RtpExtension> GetDefaultEnabledRtpHeaderExtensions(
const RtpHeaderExtensionQueryInterface& query_interface) {
std::vector<webrtc::RtpExtension> extensions;
for (const auto& entry : query_interface.GetRtpHeaderExtensions()) {
if (entry.direction != webrtc::RtpTransceiverDirection::kStopped)
extensions.emplace_back(entry.uri, *entry.preferred_id);
}
return extensions;
}
webrtc::RTCError CheckRtpParametersValues(
const webrtc::RtpParameters& rtp_parameters) {
using webrtc::RTCErrorType;

View file

@ -48,7 +48,17 @@ struct RtpCapabilities {
std::vector<webrtc::RtpExtension> header_extensions;
};
class VoiceEngineInterface {
class RtpHeaderExtensionQueryInterface {
public:
virtual ~RtpHeaderExtensionQueryInterface() = default;
// Returns a vector of RtpHeaderExtensionCapability, whose direction is
// kStopped if the extension is stopped (not used) by default.
virtual std::vector<webrtc::RtpHeaderExtensionCapability>
GetRtpHeaderExtensions() const = 0;
};
class VoiceEngineInterface : public RtpHeaderExtensionQueryInterface {
public:
VoiceEngineInterface() = default;
virtual ~VoiceEngineInterface() = default;
@ -71,7 +81,6 @@ class VoiceEngineInterface {
virtual const std::vector<AudioCodec>& send_codecs() const = 0;
virtual const std::vector<AudioCodec>& recv_codecs() const = 0;
virtual RtpCapabilities GetCapabilities() const = 0;
// Starts AEC dump using existing file, a maximum file size in bytes can be
// specified. Logging is stopped just before the size limit is exceeded.
@ -83,7 +92,7 @@ class VoiceEngineInterface {
virtual void StopAecDump() = 0;
};
class VideoEngineInterface {
class VideoEngineInterface : public RtpHeaderExtensionQueryInterface {
public:
VideoEngineInterface() = default;
virtual ~VideoEngineInterface() = default;
@ -100,7 +109,6 @@ class VideoEngineInterface {
video_bitrate_allocator_factory) = 0;
virtual std::vector<VideoCodec> codecs() const = 0;
virtual RtpCapabilities GetCapabilities() const = 0;
};
// MediaEngineInterface is an abstraction of a media engine which can be
@ -167,6 +175,13 @@ class DataEngineInterface {
webrtc::RtpParameters CreateRtpParametersWithOneEncoding();
webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp);
// Returns a vector of RTP extensions as visible from RtpSender/Receiver
// GetCapabilities(). The returned vector only shows what will definitely be
// offered by default, i.e. the list of extensions returned from
// GetRtpHeaderExtensions() that are not kStopped.
std::vector<webrtc::RtpExtension> GetDefaultEnabledRtpHeaderExtensions(
const RtpHeaderExtensionQueryInterface& query_interface);
} // namespace cricket
#endif // MEDIA_BASE_MEDIA_ENGINE_H_

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "media/base/media_engine.h"
#include "test/gmock.h"
using ::testing::ElementsAre;
using ::testing::Field;
using ::testing::Return;
using ::testing::StrEq;
using ::webrtc::RtpExtension;
using ::webrtc::RtpHeaderExtensionCapability;
using ::webrtc::RtpTransceiverDirection;
namespace cricket {
namespace {
class MockRtpHeaderExtensionQueryInterface
: public RtpHeaderExtensionQueryInterface {
public:
MOCK_CONST_METHOD0(GetRtpHeaderExtensions,
std::vector<RtpHeaderExtensionCapability>());
};
} // namespace
TEST(MediaEngineTest, ReturnsNotStoppedHeaderExtensions) {
MockRtpHeaderExtensionQueryInterface mock;
std::vector<RtpHeaderExtensionCapability> extensions(
{RtpHeaderExtensionCapability("uri1", 1,
RtpTransceiverDirection::kInactive),
RtpHeaderExtensionCapability("uri2", 2,
RtpTransceiverDirection::kSendRecv),
RtpHeaderExtensionCapability("uri3", 3,
RtpTransceiverDirection::kStopped),
RtpHeaderExtensionCapability("uri4", 4,
RtpTransceiverDirection::kSendOnly),
RtpHeaderExtensionCapability("uri5", 5,
RtpTransceiverDirection::kRecvOnly)});
EXPECT_CALL(mock, GetRtpHeaderExtensions).WillOnce(Return(extensions));
EXPECT_THAT(GetDefaultEnabledRtpHeaderExtensions(mock),
ElementsAre(Field(&RtpExtension::uri, StrEq("uri1")),
Field(&RtpExtension::uri, StrEq("uri2")),
Field(&RtpExtension::uri, StrEq("uri4")),
Field(&RtpExtension::uri, StrEq("uri5"))));
}
} // namespace cricket

View file

@ -34,7 +34,10 @@ class NullWebRtcVideoEngine : public VideoEngineInterface {
return std::vector<VideoCodec>();
}
RtpCapabilities GetCapabilities() const override { return RtpCapabilities(); }
std::vector<webrtc::RtpHeaderExtensionCapability> GetRtpHeaderExtensions()
const override {
return {};
}
VideoMediaChannel* CreateMediaChannel(
webrtc::Call* call,

View file

@ -503,39 +503,29 @@ std::vector<VideoCodec> WebRtcVideoEngine::codecs() const {
return AssignPayloadTypesAndDefaultCodecs(encoder_factory_.get());
}
RtpCapabilities WebRtcVideoEngine::GetCapabilities() const {
RtpCapabilities capabilities;
std::vector<webrtc::RtpHeaderExtensionCapability>
WebRtcVideoEngine::GetRtpHeaderExtensions() const {
std::vector<webrtc::RtpHeaderExtensionCapability> result;
int id = 1;
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kTimestampOffsetUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kAbsSendTimeUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kVideoRotationUri, id++));
capabilities.header_extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kTransportSequenceNumberUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kPlayoutDelayUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kVideoContentTypeUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kVideoTimingUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kFrameMarkingUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kColorSpaceUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kMidUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kRidUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kRepairedRidUri, id++));
if (webrtc::field_trial::IsEnabled("WebRTC-GenericDescriptorAdvertised")) {
capabilities.header_extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kGenericFrameDescriptorUri00, id++));
for (const auto& uri :
{webrtc::RtpExtension::kTimestampOffsetUri,
webrtc::RtpExtension::kAbsSendTimeUri,
webrtc::RtpExtension::kVideoRotationUri,
webrtc::RtpExtension::kTransportSequenceNumberUri,
webrtc::RtpExtension::kPlayoutDelayUri,
webrtc::RtpExtension::kVideoContentTypeUri,
webrtc::RtpExtension::kVideoTimingUri,
webrtc::RtpExtension::kFrameMarkingUri,
webrtc::RtpExtension::kColorSpaceUri, webrtc::RtpExtension::kMidUri,
webrtc::RtpExtension::kRidUri, webrtc::RtpExtension::kRepairedRidUri}) {
result.emplace_back(uri, id++, webrtc::RtpTransceiverDirection::kSendRecv);
}
return capabilities;
result.emplace_back(
webrtc::RtpExtension::kGenericFrameDescriptorUri00, id,
webrtc::field_trial::IsEnabled("WebRTC-GenericDescriptorAdvertised")
? webrtc::RtpTransceiverDirection::kSendRecv
: webrtc::RtpTransceiverDirection::kStopped);
return result;
}
WebRtcVideoChannel::WebRtcVideoChannel(

View file

@ -98,7 +98,8 @@ class WebRtcVideoEngine : public VideoEngineInterface {
override;
std::vector<VideoCodec> codecs() const override;
RtpCapabilities GetCapabilities() const override;
std::vector<webrtc::RtpHeaderExtensionCapability> GetRtpHeaderExtensions()
const override;
private:
const std::unique_ptr<webrtc::VideoDecoderFactory> decoder_factory_;

View file

@ -733,12 +733,13 @@ VideoMediaChannel* WebRtcVideoEngineTest::SetRecvParamsWithSupportedCodecs(
void WebRtcVideoEngineTest::ExpectRtpCapabilitySupport(const char* uri,
bool supported) const {
const RtpCapabilities capabilities = engine_.GetCapabilities();
const std::vector<webrtc::RtpExtension> header_extensions =
GetDefaultEnabledRtpHeaderExtensions(engine_);
if (supported) {
EXPECT_THAT(capabilities.header_extensions,
EXPECT_THAT(header_extensions,
::testing::Contains(::testing::Field(&RtpExtension::uri, uri)));
} else {
EXPECT_THAT(capabilities.header_extensions,
EXPECT_THAT(header_extensions,
::testing::Each(::testing::Field(&RtpExtension::uri,
::testing::StrNe(uri))));
}

View file

@ -539,23 +539,20 @@ const std::vector<AudioCodec>& WebRtcVoiceEngine::recv_codecs() const {
return recv_codecs_;
}
RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const {
std::vector<webrtc::RtpHeaderExtensionCapability>
WebRtcVoiceEngine::GetRtpHeaderExtensions() const {
RTC_DCHECK(signal_thread_checker_.IsCurrent());
RtpCapabilities capabilities;
std::vector<webrtc::RtpHeaderExtensionCapability> result;
int id = 1;
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kAudioLevelUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kAbsSendTimeUri, id++));
capabilities.header_extensions.push_back(webrtc::RtpExtension(
webrtc::RtpExtension::kTransportSequenceNumberUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kMidUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kRidUri, id++));
capabilities.header_extensions.push_back(
webrtc::RtpExtension(webrtc::RtpExtension::kRepairedRidUri, id++));
return capabilities;
for (const auto& uri :
{webrtc::RtpExtension::kAudioLevelUri,
webrtc::RtpExtension::kAbsSendTimeUri,
webrtc::RtpExtension::kTransportSequenceNumberUri,
webrtc::RtpExtension::kMidUri, webrtc::RtpExtension::kRidUri,
webrtc::RtpExtension::kRepairedRidUri}) {
result.emplace_back(uri, id++, webrtc::RtpTransceiverDirection::kSendRecv);
}
return result;
}
void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel* channel) {

View file

@ -64,7 +64,8 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface {
const std::vector<AudioCodec>& send_codecs() const override;
const std::vector<AudioCodec>& recv_codecs() const override;
RtpCapabilities GetCapabilities() const override;
std::vector<webrtc::RtpHeaderExtensionCapability> GetRtpHeaderExtensions()
const override;
// For tracking WebRtc channels. Needed because we have to pause them
// all when switching devices.

View file

@ -2016,8 +2016,9 @@ class WebRtcVoiceEngineWithSendSideBweTest : public WebRtcVoiceEngineTestFake {
TEST_F(WebRtcVoiceEngineWithSendSideBweTest,
SupportsTransportSequenceNumberHeaderExtension) {
const cricket::RtpCapabilities capabilities = engine_->GetCapabilities();
EXPECT_THAT(capabilities.header_extensions,
const std::vector<webrtc::RtpExtension> header_extensions =
GetDefaultEnabledRtpHeaderExtensions(*engine_);
EXPECT_THAT(header_extensions,
Contains(::testing::Field(
"uri", &RtpExtension::uri,
webrtc::RtpExtension::kTransportSequenceNumberUri)));
@ -3204,17 +3205,18 @@ TEST_F(WebRtcVoiceEngineTestFake, ConfiguresAudioReceiveStreamRtpExtensions) {
}
// Set up receive extensions.
cricket::RtpCapabilities capabilities = engine_->GetCapabilities();
const std::vector<webrtc::RtpExtension> header_extensions =
GetDefaultEnabledRtpHeaderExtensions(*engine_);
cricket::AudioRecvParameters recv_parameters;
recv_parameters.extensions = capabilities.header_extensions;
recv_parameters.extensions = header_extensions;
channel_->SetRecvParameters(recv_parameters);
EXPECT_EQ(2u, call_.GetAudioReceiveStreams().size());
for (uint32_t ssrc : ssrcs) {
const auto* s = call_.GetAudioReceiveStream(ssrc);
EXPECT_NE(nullptr, s);
const auto& s_exts = s->GetConfig().rtp.extensions;
EXPECT_EQ(capabilities.header_extensions.size(), s_exts.size());
for (const auto& e_ext : capabilities.header_extensions) {
EXPECT_EQ(header_extensions.size(), s_exts.size());
for (const auto& e_ext : header_extensions) {
for (const auto& s_ext : s_exts) {
if (e_ext.id == s_ext.id) {
EXPECT_EQ(e_ext.uri, s_ext.uri);

View file

@ -519,6 +519,7 @@ if (rtc_include_tests) {
"peer_connection_data_channel_unittest.cc",
"peer_connection_end_to_end_unittest.cc",
"peer_connection_factory_unittest.cc",
"peer_connection_header_extension_unittest.cc",
"peer_connection_histogram_unittest.cc",
"peer_connection_ice_unittest.cc",
"peer_connection_integrationtest.cc",

View file

@ -79,14 +79,6 @@ void ChannelManager::GetSupportedAudioReceiveCodecs(
*codecs = media_engine_->voice().recv_codecs();
}
void ChannelManager::GetSupportedAudioRtpHeaderExtensions(
RtpHeaderExtensions* ext) const {
if (!media_engine_) {
return;
}
*ext = media_engine_->voice().GetCapabilities().header_extensions;
}
void ChannelManager::GetSupportedVideoCodecs(
std::vector<VideoCodec>* codecs) const {
if (!media_engine_) {
@ -104,14 +96,6 @@ void ChannelManager::GetSupportedVideoCodecs(
}
}
void ChannelManager::GetSupportedVideoRtpHeaderExtensions(
RtpHeaderExtensions* ext) const {
if (!media_engine_) {
return;
}
*ext = media_engine_->video().GetCapabilities().header_extensions;
}
void ChannelManager::GetSupportedDataCodecs(
std::vector<DataCodec>* codecs) const {
*codecs = data_engine_->data_codecs();
@ -140,6 +124,34 @@ bool ChannelManager::Init() {
return initialized_;
}
RtpHeaderExtensions ChannelManager::GetDefaultEnabledAudioRtpHeaderExtensions()
const {
if (!media_engine_)
return {};
return GetDefaultEnabledRtpHeaderExtensions(media_engine_->voice());
}
std::vector<webrtc::RtpHeaderExtensionCapability>
ChannelManager::GetSupportedAudioRtpHeaderExtensions() const {
if (!media_engine_)
return {};
return media_engine_->voice().GetRtpHeaderExtensions();
}
RtpHeaderExtensions ChannelManager::GetDefaultEnabledVideoRtpHeaderExtensions()
const {
if (!media_engine_)
return {};
return GetDefaultEnabledRtpHeaderExtensions(media_engine_->video());
}
std::vector<webrtc::RtpHeaderExtensionCapability>
ChannelManager::GetSupportedVideoRtpHeaderExtensions() const {
if (!media_engine_)
return {};
return media_engine_->video().GetRtpHeaderExtensions();
}
void ChannelManager::Terminate() {
RTC_DCHECK(initialized_);
if (!initialized_) {

View file

@ -75,10 +75,14 @@ class ChannelManager final {
// Can be called before starting the media engine.
void GetSupportedAudioSendCodecs(std::vector<AudioCodec>* codecs) const;
void GetSupportedAudioReceiveCodecs(std::vector<AudioCodec>* codecs) const;
void GetSupportedAudioRtpHeaderExtensions(RtpHeaderExtensions* ext) const;
void GetSupportedVideoCodecs(std::vector<VideoCodec>* codecs) const;
void GetSupportedVideoRtpHeaderExtensions(RtpHeaderExtensions* ext) const;
void GetSupportedDataCodecs(std::vector<DataCodec>* codecs) const;
RtpHeaderExtensions GetDefaultEnabledAudioRtpHeaderExtensions() const;
std::vector<webrtc::RtpHeaderExtensionCapability>
GetSupportedAudioRtpHeaderExtensions() const;
RtpHeaderExtensions GetDefaultEnabledVideoRtpHeaderExtensions() const;
std::vector<webrtc::RtpHeaderExtensionCapability>
GetSupportedVideoRtpHeaderExtensions() const;
// Indicates whether the media engine is started.
bool initialized() const { return initialized_; }

View file

@ -1365,9 +1365,11 @@ MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
: MediaSessionDescriptionFactory(transport_desc_factory, ssrc_generator) {
channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_);
channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_);
channel_manager->GetSupportedAudioRtpHeaderExtensions(&audio_rtp_extensions_);
audio_rtp_extensions_ =
channel_manager->GetDefaultEnabledAudioRtpHeaderExtensions();
channel_manager->GetSupportedVideoCodecs(&video_codecs_);
channel_manager->GetSupportedVideoRtpHeaderExtensions(&video_rtp_extensions_);
video_rtp_extensions_ =
channel_manager->GetDefaultEnabledVideoRtpHeaderExtensions();
channel_manager->GetSupportedDataCodecs(&rtp_data_codecs_);
ComputeAudioCodecsIntersectionAndUnion();
}

View file

@ -1907,7 +1907,11 @@ PeerConnection::CreateAndAddTransceiver(
RTC_DCHECK(!FindSenderById(sender->id()));
auto transceiver = RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
signaling_thread(),
new RtpTransceiver(sender, receiver, channel_manager()));
new RtpTransceiver(
sender, receiver, channel_manager(),
sender->media_type() == cricket::MEDIA_TYPE_AUDIO
? channel_manager()->GetSupportedAudioRtpHeaderExtensions()
: channel_manager()->GetSupportedVideoRtpHeaderExtensions()));
transceivers_.push_back(transceiver);
transceiver->internal()->SignalNegotiationNeeded.connect(
this, &PeerConnection::OnNegotiationNeeded);
@ -4983,6 +4987,7 @@ void PeerConnection::GetOptionsForPlanBOffer(
cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
false));
audio_index = session_options->media_description_options.size() - 1;
}
if (!video_index && offer_new_video_description) {
@ -4991,6 +4996,7 @@ void PeerConnection::GetOptionsForPlanBOffer(
cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
RtpTransceiverDirectionFromSendRecv(send_video, recv_video),
false));
video_index = session_options->media_description_options.size() - 1;
}
if (!data_index && offer_new_data_description) {

View file

@ -160,19 +160,17 @@ RtpCapabilities PeerConnectionFactory::GetRtpSenderCapabilities(
switch (kind) {
case cricket::MEDIA_TYPE_AUDIO: {
cricket::AudioCodecs cricket_codecs;
cricket::RtpHeaderExtensions cricket_extensions;
channel_manager_->GetSupportedAudioSendCodecs(&cricket_codecs);
channel_manager_->GetSupportedAudioRtpHeaderExtensions(
&cricket_extensions);
return ToRtpCapabilities(cricket_codecs, cricket_extensions);
return ToRtpCapabilities(
cricket_codecs,
channel_manager_->GetDefaultEnabledAudioRtpHeaderExtensions());
}
case cricket::MEDIA_TYPE_VIDEO: {
cricket::VideoCodecs cricket_codecs;
cricket::RtpHeaderExtensions cricket_extensions;
channel_manager_->GetSupportedVideoCodecs(&cricket_codecs);
channel_manager_->GetSupportedVideoRtpHeaderExtensions(
&cricket_extensions);
return ToRtpCapabilities(cricket_codecs, cricket_extensions);
return ToRtpCapabilities(
cricket_codecs,
channel_manager_->GetDefaultEnabledVideoRtpHeaderExtensions());
}
case cricket::MEDIA_TYPE_DATA:
return RtpCapabilities();
@ -187,19 +185,17 @@ RtpCapabilities PeerConnectionFactory::GetRtpReceiverCapabilities(
switch (kind) {
case cricket::MEDIA_TYPE_AUDIO: {
cricket::AudioCodecs cricket_codecs;
cricket::RtpHeaderExtensions cricket_extensions;
channel_manager_->GetSupportedAudioReceiveCodecs(&cricket_codecs);
channel_manager_->GetSupportedAudioRtpHeaderExtensions(
&cricket_extensions);
return ToRtpCapabilities(cricket_codecs, cricket_extensions);
return ToRtpCapabilities(
cricket_codecs,
channel_manager_->GetDefaultEnabledAudioRtpHeaderExtensions());
}
case cricket::MEDIA_TYPE_VIDEO: {
cricket::VideoCodecs cricket_codecs;
cricket::RtpHeaderExtensions cricket_extensions;
channel_manager_->GetSupportedVideoCodecs(&cricket_codecs);
channel_manager_->GetSupportedVideoRtpHeaderExtensions(
&cricket_extensions);
return ToRtpCapabilities(cricket_codecs, cricket_extensions);
return ToRtpCapabilities(
cricket_codecs,
channel_manager_->GetDefaultEnabledVideoRtpHeaderExtensions());
}
case cricket::MEDIA_TYPE_DATA:
return RtpCapabilities();

View file

@ -0,0 +1,144 @@
/*
* Copyright 2020 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <memory>
#include <tuple>
#include "api/rtc_event_log/rtc_event_log_factory.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "media/base/fake_media_engine.h"
#include "p2p/base/fake_port_allocator.h"
#include "pc/media_session.h"
#include "pc/peer_connection_wrapper.h"
#include "rtc_base/gunit.h"
#include "rtc_base/strings/string_builder.h"
#include "test/gmock.h"
namespace webrtc {
using ::testing::Combine;
using ::testing::ElementsAre;
using ::testing::Field;
using ::testing::Return;
using ::testing::Values;
class PeerConnectionHeaderExtensionTest
: public ::testing::TestWithParam<
std::tuple<cricket::MediaType, SdpSemantics>> {
protected:
std::unique_ptr<PeerConnectionWrapper> CreatePeerConnection(
cricket::MediaType media_type,
absl::optional<SdpSemantics> semantics,
std::vector<RtpHeaderExtensionCapability> extensions) {
auto voice = std::make_unique<cricket::FakeVoiceEngine>();
auto video = std::make_unique<cricket::FakeVideoEngine>();
if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO)
voice->SetRtpHeaderExtensions(extensions);
else
video->SetRtpHeaderExtensions(extensions);
auto media_engine = std::make_unique<cricket::CompositeMediaEngine>(
std::move(voice), std::move(video));
PeerConnectionFactoryDependencies factory_dependencies;
factory_dependencies.network_thread = rtc::Thread::Current();
factory_dependencies.worker_thread = rtc::Thread::Current();
factory_dependencies.signaling_thread = rtc::Thread::Current();
factory_dependencies.task_queue_factory = CreateDefaultTaskQueueFactory();
factory_dependencies.media_engine = std::move(media_engine);
factory_dependencies.call_factory = CreateCallFactory();
factory_dependencies.event_log_factory =
std::make_unique<RtcEventLogFactory>(
factory_dependencies.task_queue_factory.get());
auto pc_factory =
CreateModularPeerConnectionFactory(std::move(factory_dependencies));
auto fake_port_allocator = std::make_unique<cricket::FakePortAllocator>(
rtc::Thread::Current(), nullptr);
auto observer = std::make_unique<MockPeerConnectionObserver>();
PeerConnectionInterface::RTCConfiguration config;
if (semantics)
config.sdp_semantics = *semantics;
auto pc = pc_factory->CreatePeerConnection(
config, std::move(fake_port_allocator), nullptr, observer.get());
observer->SetPeerConnectionInterface(pc.get());
return std::make_unique<PeerConnectionWrapper>(pc_factory, pc,
std::move(observer));
}
};
TEST_P(PeerConnectionHeaderExtensionTest, TransceiverOffersHeaderExtensions) {
cricket::MediaType media_type;
SdpSemantics semantics;
std::tie(media_type, semantics) = GetParam();
if (semantics != SdpSemantics::kUnifiedPlan)
return;
std::vector<RtpHeaderExtensionCapability> extensions(
{RtpHeaderExtensionCapability("uri1", 1,
RtpTransceiverDirection::kStopped),
RtpHeaderExtensionCapability("uri2", 2,
RtpTransceiverDirection::kSendOnly),
RtpHeaderExtensionCapability("uri3", 3,
RtpTransceiverDirection::kRecvOnly),
RtpHeaderExtensionCapability("uri4", 4,
RtpTransceiverDirection::kSendRecv)});
std::unique_ptr<PeerConnectionWrapper> wrapper =
CreatePeerConnection(media_type, semantics, extensions);
auto transceiver = wrapper->AddTransceiver(media_type);
EXPECT_EQ(transceiver->HeaderExtensionsToOffer(), extensions);
}
TEST_P(PeerConnectionHeaderExtensionTest,
SenderReceiverCapabilitiesReturnNotStoppedExtensions) {
cricket::MediaType media_type;
SdpSemantics semantics;
std::tie(media_type, semantics) = GetParam();
std::unique_ptr<PeerConnectionWrapper> wrapper = CreatePeerConnection(
media_type, semantics,
std::vector<RtpHeaderExtensionCapability>(
{RtpHeaderExtensionCapability("uri1", 1,
RtpTransceiverDirection::kSendRecv),
RtpHeaderExtensionCapability("uri2", 2,
RtpTransceiverDirection::kStopped),
RtpHeaderExtensionCapability("uri3", 3,
RtpTransceiverDirection::kRecvOnly)}));
EXPECT_THAT(wrapper->pc_factory()
->GetRtpSenderCapabilities(media_type)
.header_extensions,
ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri1"),
Field(&RtpHeaderExtensionCapability::uri, "uri3")));
EXPECT_EQ(wrapper->pc_factory()
->GetRtpReceiverCapabilities(media_type)
.header_extensions,
wrapper->pc_factory()
->GetRtpSenderCapabilities(media_type)
.header_extensions);
}
INSTANTIATE_TEST_SUITE_P(
,
PeerConnectionHeaderExtensionTest,
Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
Values(cricket::MediaType::MEDIA_TYPE_AUDIO,
cricket::MediaType::MEDIA_TYPE_VIDEO)),
[](const testing::TestParamInfo<
PeerConnectionHeaderExtensionTest::ParamType>& info) {
cricket::MediaType media_type;
SdpSemantics semantics;
std::tie(media_type, semantics) = info.param;
return (rtc::StringBuilder("With")
<< (semantics == SdpSemantics::kPlanB ? "PlanB" : "UnifiedPlan")
<< "And"
<< (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO ? "Voice"
: "Video")
<< "Engine")
.str();
});
} // namespace webrtc

View file

@ -11,8 +11,10 @@
#include "pc/rtp_transceiver.h"
#include <string>
#include <utility>
#include "absl/algorithm/container.h"
#include "api/rtp_parameters.h"
#include "pc/channel_manager.h"
#include "pc/rtp_media_utils.h"
#include "pc/rtp_parameters_conversion.h"
@ -31,10 +33,12 @@ RtpTransceiver::RtpTransceiver(
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
receiver,
cricket::ChannelManager* channel_manager)
cricket::ChannelManager* channel_manager,
std::vector<RtpHeaderExtensionCapability> header_extensions_offered)
: unified_plan_(true),
media_type_(sender->media_type()),
channel_manager_(channel_manager) {
channel_manager_(channel_manager),
HeaderExtensionsToOffer_(std::move(header_extensions_offered)) {
RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
media_type_ == cricket::MEDIA_TYPE_VIDEO);
RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
@ -358,4 +362,9 @@ RTCError RtpTransceiver::SetCodecPreferences(
return RTCError::OK();
}
std::vector<RtpHeaderExtensionCapability>
RtpTransceiver::HeaderExtensionsToOffer() const {
return HeaderExtensionsToOffer_;
}
} // namespace webrtc

View file

@ -64,11 +64,14 @@ class RtpTransceiver final
// Construct a Unified Plan-style RtpTransceiver with the given sender and
// receiver. The media type will be derived from the media types of the sender
// and receiver. The sender and receiver should have the same media type.
// |HeaderExtensionsToOffer| is used for initializing the return value of
// HeaderExtensionsToOffer().
RtpTransceiver(
rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender,
rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
receiver,
cricket::ChannelManager* channel_manager);
cricket::ChannelManager* channel_manager,
std::vector<RtpHeaderExtensionCapability> HeaderExtensionsToOffer);
~RtpTransceiver() override;
// Returns the Voice/VideoChannel set for this transceiver. May be null if
@ -190,6 +193,8 @@ class RtpTransceiver final
std::vector<RtpCodecCapability> codec_preferences() const override {
return codec_preferences_;
}
std::vector<RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
const override;
private:
void OnFirstPacketReceived(cricket::ChannelInterface* channel);
@ -215,6 +220,7 @@ class RtpTransceiver final
cricket::ChannelInterface* channel_ = nullptr;
cricket::ChannelManager* channel_manager_ = nullptr;
std::vector<RtpCodecCapability> codec_preferences_;
std::vector<RtpHeaderExtensionCapability> HeaderExtensionsToOffer_;
};
BEGIN_SIGNALING_PROXY_MAP(RtpTransceiver)
@ -233,6 +239,8 @@ PROXY_METHOD1(webrtc::RTCError,
SetCodecPreferences,
rtc::ArrayView<RtpCodecCapability>)
PROXY_CONSTMETHOD0(std::vector<RtpCodecCapability>, codec_preferences)
PROXY_CONSTMETHOD0(std::vector<RtpHeaderExtensionCapability>,
HeaderExtensionsToOffer)
END_PROXY_MAP()
} // namespace webrtc

View file

@ -12,10 +12,19 @@
#include "pc/rtp_transceiver.h"
#include <memory>
#include "media/base/fake_media_engine.h"
#include "pc/test/mock_channel_interface.h"
#include "pc/test/mock_rtp_receiver_internal.h"
#include "pc/test/mock_rtp_sender_internal.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Field;
using ::testing::Not;
using ::testing::Return;
using ::testing::ReturnRef;
@ -69,4 +78,27 @@ TEST(RtpTransceiverTest, CanUnsetChannelOnStoppedTransceiver) {
EXPECT_EQ(nullptr, transceiver.channel());
}
TEST(RtpTransceiverTest,
InitsWithChannelManagerRtpHeaderExtensionCapabilities) {
cricket::ChannelManager channel_manager(
std::make_unique<cricket::FakeMediaEngine>(),
std::make_unique<cricket::FakeDataEngine>(), rtc::Thread::Current(),
rtc::Thread::Current());
std::vector<RtpHeaderExtensionCapability> extensions({
RtpHeaderExtensionCapability("uri1", 1,
RtpTransceiverDirection::kSendRecv),
RtpHeaderExtensionCapability("uri2", 2,
RtpTransceiverDirection::kRecvOnly),
});
RtpTransceiver transceiver(
RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
rtc::Thread::Current(),
new rtc::RefCountedObject<MockRtpSenderInternal>()),
RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
rtc::Thread::Current(),
new rtc::RefCountedObject<MockRtpReceiverInternal>()),
&channel_manager, extensions);
EXPECT_EQ(transceiver.HeaderExtensionsToOffer(), extensions);
}
} // namespace webrtc