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