From 0357b3e7b6f7885bec3a47ce3a7f7155e0f9d90a Mon Sep 17 00:00:00 2001 From: Markus Handell Date: Mon, 16 Mar 2020 13:40:51 +0100 Subject: [PATCH] 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 Reviewed-by: Harald Alvestrand Reviewed-by: Karl Wiberg Cr-Commit-Position: refs/heads/master@{#30800} --- api/BUILD.gn | 7 + api/rtp_parameters.cc | 5 + api/rtp_parameters.h | 16 +- api/rtp_transceiver_direction.h | 27 ++++ api/rtp_transceiver_interface.cc | 5 + api/rtp_transceiver_interface.h | 17 +-- media/BUILD.gn | 1 + media/base/fake_media_engine.cc | 24 ++- media/base/fake_media_engine.h | 12 +- media/base/media_engine.cc | 10 ++ media/base/media_engine.h | 23 ++- media/base/media_engine_unittest.cc | 56 +++++++ media/engine/null_webrtc_video_engine.h | 5 +- media/engine/webrtc_video_engine.cc | 52 +++---- media/engine/webrtc_video_engine.h | 3 +- media/engine/webrtc_video_engine_unittest.cc | 7 +- media/engine/webrtc_voice_engine.cc | 27 ++-- media/engine/webrtc_voice_engine.h | 3 +- media/engine/webrtc_voice_engine_unittest.cc | 14 +- pc/BUILD.gn | 1 + pc/channel_manager.cc | 44 ++++-- pc/channel_manager.h | 8 +- pc/media_session.cc | 6 +- pc/peer_connection.cc | 8 +- pc/peer_connection_factory.cc | 28 ++-- ...er_connection_header_extension_unittest.cc | 144 ++++++++++++++++++ pc/rtp_transceiver.cc | 13 +- pc/rtp_transceiver.h | 10 +- pc/rtp_transceiver_unittest.cc | 32 ++++ 29 files changed, 486 insertions(+), 122 deletions(-) create mode 100644 api/rtp_transceiver_direction.h create mode 100644 media/base/media_engine_unittest.cc create mode 100644 pc/peer_connection_header_extension_unittest.cc diff --git a/api/BUILD.gn b/api/BUILD.gn index f6c28f81f4..8489065231 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -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", diff --git a/api/rtp_parameters.cc b/api/rtp_parameters.cc index 9b72960068..9affafb32d 100644 --- a/api/rtp_parameters.cc +++ b/api/rtp_parameters.cc @@ -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; diff --git a/api/rtp_parameters.h b/api/rtp_parameters.h index a22f764327..ee51b014a3 100644 --- a/api/rtp_parameters.h +++ b/api/rtp_parameters.h @@ -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); diff --git a/api/rtp_transceiver_direction.h b/api/rtp_transceiver_direction.h new file mode 100644 index 0000000000..3c7d4cb0ad --- /dev/null +++ b/api/rtp_transceiver_direction.h @@ -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_ diff --git a/api/rtp_transceiver_interface.cc b/api/rtp_transceiver_interface.cc index dc82fadd39..d4e2b26e33 100644 --- a/api/rtp_transceiver_interface.cc +++ b/api/rtp_transceiver_interface.cc @@ -36,4 +36,9 @@ std::vector RtpTransceiverInterface::codec_preferences() return {}; } +std::vector +RtpTransceiverInterface::HeaderExtensionsToOffer() const { + return {}; +} + } // namespace webrtc diff --git a/api/rtp_transceiver_interface.h b/api/rtp_transceiver_interface.h index 2af42aaa34..9dbafd46ec 100644 --- a/api/rtp_transceiver_interface.h +++ b/api/rtp_transceiver_interface.h @@ -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 codecs); virtual std::vector 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 HeaderExtensionsToOffer() + const; + protected: ~RtpTransceiverInterface() override = default; }; diff --git a/media/BUILD.gn b/media/BUILD.gn index 3b45cf217f..7e116cbf7e 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -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", diff --git a/media/base/fake_media_engine.cc b/media/base/fake_media_engine.cc index 8fc844fa78..e4d8917ea4 100644 --- a/media/base/fake_media_engine.cc +++ b/media/base/fake_media_engine.cc @@ -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 FakeVoiceEngine::GetAudioState() const { return rtc::scoped_refptr(); @@ -564,15 +561,22 @@ bool FakeVoiceEngine::StartAecDump(webrtc::FileWrapper file, } void FakeVoiceEngine::StopAecDump() {} +std::vector +FakeVoiceEngine::GetRtpHeaderExtensions() const { + return header_extensions_; +} + +void FakeVoiceEngine::SetRtpHeaderExtensions( + std::vector 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 +FakeVideoEngine::GetRtpHeaderExtensions() const { + return header_extensions_; +} +void FakeVideoEngine::SetRtpHeaderExtensions( + std::vector header_extensions) { + header_extensions_ = std::move(header_extensions); +} FakeMediaEngine::FakeMediaEngine() : CompositeMediaEngine(std::make_unique(), diff --git a/media/base/fake_media_engine.h b/media/base/fake_media_engine.h index 32ca11fe41..10dd546b3e 100644 --- a/media/base/fake_media_engine.h +++ b/media/base/fake_media_engine.h @@ -514,7 +514,6 @@ class FakeDataMediaChannel : public RtpHelper { class FakeVoiceEngine : public VoiceEngineInterface { public: FakeVoiceEngine(); - RtpCapabilities GetCapabilities() const override; void Init() override; rtc::scoped_refptr 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 GetRtpHeaderExtensions() + const override; + void SetRtpHeaderExtensions( + std::vector header_extensions); private: std::vector channels_; std::vector recv_codecs_; std::vector send_codecs_; bool fail_create_channel_; + std::vector 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 codecs() const override; void SetCodecs(const std::vector codecs); bool SetCapture(bool capture); + std::vector GetRtpHeaderExtensions() + const override; + void SetRtpHeaderExtensions( + std::vector header_extensions); private: std::vector channels_; @@ -570,6 +577,7 @@ class FakeVideoEngine : public VideoEngineInterface { bool capture_; VideoOptions options_; bool fail_create_channel_; + std::vector header_extensions_; friend class FakeMediaEngine; }; diff --git a/media/base/media_engine.cc b/media/base/media_engine.cc index 44ca3a9528..8050258728 100644 --- a/media/base/media_engine.cc +++ b/media/base/media_engine.cc @@ -55,6 +55,16 @@ webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp) { return parameters; } +std::vector GetDefaultEnabledRtpHeaderExtensions( + const RtpHeaderExtensionQueryInterface& query_interface) { + std::vector 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; diff --git a/media/base/media_engine.h b/media/base/media_engine.h index 173df50e34..713afcc24e 100644 --- a/media/base/media_engine.h +++ b/media/base/media_engine.h @@ -48,7 +48,17 @@ struct RtpCapabilities { std::vector 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 + GetRtpHeaderExtensions() const = 0; +}; + +class VoiceEngineInterface : public RtpHeaderExtensionQueryInterface { public: VoiceEngineInterface() = default; virtual ~VoiceEngineInterface() = default; @@ -71,7 +81,6 @@ class VoiceEngineInterface { virtual const std::vector& send_codecs() const = 0; virtual const std::vector& 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 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 GetDefaultEnabledRtpHeaderExtensions( + const RtpHeaderExtensionQueryInterface& query_interface); + } // namespace cricket #endif // MEDIA_BASE_MEDIA_ENGINE_H_ diff --git a/media/base/media_engine_unittest.cc b/media/base/media_engine_unittest.cc new file mode 100644 index 0000000000..f4c6f5f045 --- /dev/null +++ b/media/base/media_engine_unittest.cc @@ -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()); +}; + +} // namespace + +TEST(MediaEngineTest, ReturnsNotStoppedHeaderExtensions) { + MockRtpHeaderExtensionQueryInterface mock; + std::vector 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 diff --git a/media/engine/null_webrtc_video_engine.h b/media/engine/null_webrtc_video_engine.h index 590f0b0be7..fc556f6084 100644 --- a/media/engine/null_webrtc_video_engine.h +++ b/media/engine/null_webrtc_video_engine.h @@ -34,7 +34,10 @@ class NullWebRtcVideoEngine : public VideoEngineInterface { return std::vector(); } - RtpCapabilities GetCapabilities() const override { return RtpCapabilities(); } + std::vector GetRtpHeaderExtensions() + const override { + return {}; + } VideoMediaChannel* CreateMediaChannel( webrtc::Call* call, diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 48aea63cf8..2c6067ed00 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -503,39 +503,29 @@ std::vector WebRtcVideoEngine::codecs() const { return AssignPayloadTypesAndDefaultCodecs(encoder_factory_.get()); } -RtpCapabilities WebRtcVideoEngine::GetCapabilities() const { - RtpCapabilities capabilities; +std::vector +WebRtcVideoEngine::GetRtpHeaderExtensions() const { + std::vector 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( diff --git a/media/engine/webrtc_video_engine.h b/media/engine/webrtc_video_engine.h index 418576f3f0..9f5e6d3379 100644 --- a/media/engine/webrtc_video_engine.h +++ b/media/engine/webrtc_video_engine.h @@ -98,7 +98,8 @@ class WebRtcVideoEngine : public VideoEngineInterface { override; std::vector codecs() const override; - RtpCapabilities GetCapabilities() const override; + std::vector GetRtpHeaderExtensions() + const override; private: const std::unique_ptr decoder_factory_; diff --git a/media/engine/webrtc_video_engine_unittest.cc b/media/engine/webrtc_video_engine_unittest.cc index d33a2c3532..04751735e8 100644 --- a/media/engine/webrtc_video_engine_unittest.cc +++ b/media/engine/webrtc_video_engine_unittest.cc @@ -733,12 +733,13 @@ VideoMediaChannel* WebRtcVideoEngineTest::SetRecvParamsWithSupportedCodecs( void WebRtcVideoEngineTest::ExpectRtpCapabilitySupport(const char* uri, bool supported) const { - const RtpCapabilities capabilities = engine_.GetCapabilities(); + const std::vector 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)))); } diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc index 45b46bf82d..80055e718e 100644 --- a/media/engine/webrtc_voice_engine.cc +++ b/media/engine/webrtc_voice_engine.cc @@ -539,23 +539,20 @@ const std::vector& WebRtcVoiceEngine::recv_codecs() const { return recv_codecs_; } -RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const { +std::vector +WebRtcVoiceEngine::GetRtpHeaderExtensions() const { RTC_DCHECK(signal_thread_checker_.IsCurrent()); - RtpCapabilities capabilities; + std::vector 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) { diff --git a/media/engine/webrtc_voice_engine.h b/media/engine/webrtc_voice_engine.h index 7ff8690b2d..01b7123c7a 100644 --- a/media/engine/webrtc_voice_engine.h +++ b/media/engine/webrtc_voice_engine.h @@ -64,7 +64,8 @@ class WebRtcVoiceEngine final : public VoiceEngineInterface { const std::vector& send_codecs() const override; const std::vector& recv_codecs() const override; - RtpCapabilities GetCapabilities() const override; + std::vector GetRtpHeaderExtensions() + const override; // For tracking WebRtc channels. Needed because we have to pause them // all when switching devices. diff --git a/media/engine/webrtc_voice_engine_unittest.cc b/media/engine/webrtc_voice_engine_unittest.cc index 6cbbf0244b..5b6ed3a527 100644 --- a/media/engine/webrtc_voice_engine_unittest.cc +++ b/media/engine/webrtc_voice_engine_unittest.cc @@ -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 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 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); diff --git a/pc/BUILD.gn b/pc/BUILD.gn index d8561af442..4341ce1492 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -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", diff --git a/pc/channel_manager.cc b/pc/channel_manager.cc index ce8f473600..17e47512b4 100644 --- a/pc/channel_manager.cc +++ b/pc/channel_manager.cc @@ -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* 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* 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 +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 +ChannelManager::GetSupportedVideoRtpHeaderExtensions() const { + if (!media_engine_) + return {}; + return media_engine_->video().GetRtpHeaderExtensions(); +} + void ChannelManager::Terminate() { RTC_DCHECK(initialized_); if (!initialized_) { diff --git a/pc/channel_manager.h b/pc/channel_manager.h index 661ab4bbde..fa4bf7b925 100644 --- a/pc/channel_manager.h +++ b/pc/channel_manager.h @@ -75,10 +75,14 @@ class ChannelManager final { // Can be called before starting the media engine. void GetSupportedAudioSendCodecs(std::vector* codecs) const; void GetSupportedAudioReceiveCodecs(std::vector* codecs) const; - void GetSupportedAudioRtpHeaderExtensions(RtpHeaderExtensions* ext) const; void GetSupportedVideoCodecs(std::vector* codecs) const; - void GetSupportedVideoRtpHeaderExtensions(RtpHeaderExtensions* ext) const; void GetSupportedDataCodecs(std::vector* codecs) const; + RtpHeaderExtensions GetDefaultEnabledAudioRtpHeaderExtensions() const; + std::vector + GetSupportedAudioRtpHeaderExtensions() const; + RtpHeaderExtensions GetDefaultEnabledVideoRtpHeaderExtensions() const; + std::vector + GetSupportedVideoRtpHeaderExtensions() const; // Indicates whether the media engine is started. bool initialized() const { return initialized_; } diff --git a/pc/media_session.cc b/pc/media_session.cc index 9190f6eaf3..2f57e61d08 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -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(); } diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index 5fccf1f7f2..c6af185d47 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -1907,7 +1907,11 @@ PeerConnection::CreateAndAddTransceiver( RTC_DCHECK(!FindSenderById(sender->id())); auto transceiver = RtpTransceiverProxyWithInternal::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) { diff --git a/pc/peer_connection_factory.cc b/pc/peer_connection_factory.cc index 4237b47e54..a0a999fcc5 100644 --- a/pc/peer_connection_factory.cc +++ b/pc/peer_connection_factory.cc @@ -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(); diff --git a/pc/peer_connection_header_extension_unittest.cc b/pc/peer_connection_header_extension_unittest.cc new file mode 100644 index 0000000000..3f44d4f877 --- /dev/null +++ b/pc/peer_connection_header_extension_unittest.cc @@ -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 +#include + +#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> { + protected: + std::unique_ptr CreatePeerConnection( + cricket::MediaType media_type, + absl::optional semantics, + std::vector extensions) { + auto voice = std::make_unique(); + auto video = std::make_unique(); + if (media_type == cricket::MediaType::MEDIA_TYPE_AUDIO) + voice->SetRtpHeaderExtensions(extensions); + else + video->SetRtpHeaderExtensions(extensions); + auto media_engine = std::make_unique( + 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( + factory_dependencies.task_queue_factory.get()); + + auto pc_factory = + CreateModularPeerConnectionFactory(std::move(factory_dependencies)); + + auto fake_port_allocator = std::make_unique( + rtc::Thread::Current(), nullptr); + auto observer = std::make_unique(); + 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(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 extensions( + {RtpHeaderExtensionCapability("uri1", 1, + RtpTransceiverDirection::kStopped), + RtpHeaderExtensionCapability("uri2", 2, + RtpTransceiverDirection::kSendOnly), + RtpHeaderExtensionCapability("uri3", 3, + RtpTransceiverDirection::kRecvOnly), + RtpHeaderExtensionCapability("uri4", 4, + RtpTransceiverDirection::kSendRecv)}); + std::unique_ptr 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 wrapper = CreatePeerConnection( + media_type, semantics, + std::vector( + {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 diff --git a/pc/rtp_transceiver.cc b/pc/rtp_transceiver.cc index d3281d5e6e..ca57b91142 100644 --- a/pc/rtp_transceiver.cc +++ b/pc/rtp_transceiver.cc @@ -11,8 +11,10 @@ #include "pc/rtp_transceiver.h" #include +#include #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> sender, rtc::scoped_refptr> receiver, - cricket::ChannelManager* channel_manager) + cricket::ChannelManager* channel_manager, + std::vector 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 +RtpTransceiver::HeaderExtensionsToOffer() const { + return HeaderExtensionsToOffer_; +} + } // namespace webrtc diff --git a/pc/rtp_transceiver.h b/pc/rtp_transceiver.h index 7ab9e9849a..0668447b9f 100644 --- a/pc/rtp_transceiver.h +++ b/pc/rtp_transceiver.h @@ -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> sender, rtc::scoped_refptr> receiver, - cricket::ChannelManager* channel_manager); + cricket::ChannelManager* channel_manager, + std::vector HeaderExtensionsToOffer); ~RtpTransceiver() override; // Returns the Voice/VideoChannel set for this transceiver. May be null if @@ -190,6 +193,8 @@ class RtpTransceiver final std::vector codec_preferences() const override { return codec_preferences_; } + std::vector 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 codec_preferences_; + std::vector HeaderExtensionsToOffer_; }; BEGIN_SIGNALING_PROXY_MAP(RtpTransceiver) @@ -233,6 +239,8 @@ PROXY_METHOD1(webrtc::RTCError, SetCodecPreferences, rtc::ArrayView) PROXY_CONSTMETHOD0(std::vector, codec_preferences) +PROXY_CONSTMETHOD0(std::vector, + HeaderExtensionsToOffer) END_PROXY_MAP() } // namespace webrtc diff --git a/pc/rtp_transceiver_unittest.cc b/pc/rtp_transceiver_unittest.cc index 885a5a10c8..5e345739f1 100644 --- a/pc/rtp_transceiver_unittest.cc +++ b/pc/rtp_transceiver_unittest.cc @@ -12,10 +12,19 @@ #include "pc/rtp_transceiver.h" +#include + +#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(), + std::make_unique(), rtc::Thread::Current(), + rtc::Thread::Current()); + std::vector extensions({ + RtpHeaderExtensionCapability("uri1", 1, + RtpTransceiverDirection::kSendRecv), + RtpHeaderExtensionCapability("uri2", 2, + RtpTransceiverDirection::kRecvOnly), + }); + RtpTransceiver transceiver( + RtpSenderProxyWithInternal::Create( + rtc::Thread::Current(), + new rtc::RefCountedObject()), + RtpReceiverProxyWithInternal::Create( + rtc::Thread::Current(), + new rtc::RefCountedObject()), + &channel_manager, extensions); + EXPECT_EQ(transceiver.HeaderExtensionsToOffer(), extensions); +} + } // namespace webrtc