mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00
RtpTransceiverInterface: introduce HeaderExtensionsNegotiated.
This changes adds exposure of a new transceiver method for accessing header extensions that have been negotiated, following spec details in https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface. The change contains unit tests testing the functionality. Note: support for signalling directionality of header extensions in the SDP isn't implemented yet. https://chromestatus.com/feature/5680189201711104. Intent to prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/65YdUi02yZk Bug: chromium:1051821 Change-Id: If963beed37e96eed2dff3a2822db4e30caaea4a0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/198126 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Markus Handell <handellm@webrtc.org> Cr-Commit-Position: refs/heads/master@{#32860}
This commit is contained in:
parent
d95a47d08f
commit
5932fe1392
10 changed files with 164 additions and 4 deletions
|
@ -64,6 +64,11 @@ webrtc::RTCError RtpTransceiverInterface::SetOfferedRtpHeaderExtensions(
|
|||
return webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
std::vector<RtpHeaderExtensionCapability>
|
||||
RtpTransceiverInterface::HeaderExtensionsNegotiated() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
// TODO(bugs.webrtc.org/11839) Remove default implementations when clients
|
||||
// are updated.
|
||||
void RtpTransceiverInterface::SetDirection(
|
||||
|
|
|
@ -156,6 +156,12 @@ class RTC_EXPORT RtpTransceiverInterface : public rtc::RefCountInterface {
|
|||
virtual std::vector<RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
|
||||
const;
|
||||
|
||||
// Readonly attribute which is either empty if negotation has not yet
|
||||
// happened, or a vector of the negotiated header extensions.
|
||||
// https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
|
||||
virtual std::vector<RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
|
||||
const;
|
||||
|
||||
// The SetOfferedRtpHeaderExtensions method modifies the next SDP negotiation
|
||||
// so that it negotiates use of header extensions which are not kStopped.
|
||||
// https://w3c.github.io/webrtc-extensions/#rtcrtptransceiver-interface
|
||||
|
|
|
@ -836,6 +836,23 @@ void BaseChannel::SignalSentPacket_n(const rtc::SentPacket& sent_packet) {
|
|||
});
|
||||
}
|
||||
|
||||
void BaseChannel::SetNegotiatedHeaderExtensions_w(
|
||||
const RtpHeaderExtensions& extensions) {
|
||||
TRACE_EVENT0("webrtc", __func__);
|
||||
RtpHeaderExtensions extensions_copy = extensions;
|
||||
invoker_.AsyncInvoke<void>(
|
||||
RTC_FROM_HERE, signaling_thread(),
|
||||
[this, extensions_copy = std::move(extensions_copy)] {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
negotiated_header_extensions_ = std::move(extensions_copy);
|
||||
});
|
||||
}
|
||||
|
||||
RtpHeaderExtensions BaseChannel::GetNegotiatedRtpHeaderExtensions() const {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
return negotiated_header_extensions_;
|
||||
}
|
||||
|
||||
VoiceChannel::VoiceChannel(rtc::Thread* worker_thread,
|
||||
rtc::Thread* network_thread,
|
||||
rtc::Thread* signaling_thread,
|
||||
|
@ -895,6 +912,9 @@ bool VoiceChannel::SetLocalContent_w(const MediaContentDescription* content,
|
|||
|
||||
const AudioContentDescription* audio = content->as_audio();
|
||||
|
||||
if (type == SdpType::kAnswer)
|
||||
SetNegotiatedHeaderExtensions_w(audio->rtp_header_extensions());
|
||||
|
||||
RtpHeaderExtensions rtp_header_extensions =
|
||||
GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
|
||||
SetReceiveExtensions(rtp_header_extensions);
|
||||
|
@ -954,6 +974,9 @@ bool VoiceChannel::SetRemoteContent_w(const MediaContentDescription* content,
|
|||
|
||||
const AudioContentDescription* audio = content->as_audio();
|
||||
|
||||
if (type == SdpType::kAnswer)
|
||||
SetNegotiatedHeaderExtensions_w(audio->rtp_header_extensions());
|
||||
|
||||
RtpHeaderExtensions rtp_header_extensions =
|
||||
GetFilteredRtpHeaderExtensions(audio->rtp_header_extensions());
|
||||
|
||||
|
@ -1057,6 +1080,9 @@ bool VideoChannel::SetLocalContent_w(const MediaContentDescription* content,
|
|||
|
||||
const VideoContentDescription* video = content->as_video();
|
||||
|
||||
if (type == SdpType::kAnswer)
|
||||
SetNegotiatedHeaderExtensions_w(video->rtp_header_extensions());
|
||||
|
||||
RtpHeaderExtensions rtp_header_extensions =
|
||||
GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
|
||||
SetReceiveExtensions(rtp_header_extensions);
|
||||
|
@ -1149,6 +1175,9 @@ bool VideoChannel::SetRemoteContent_w(const MediaContentDescription* content,
|
|||
|
||||
const VideoContentDescription* video = content->as_video();
|
||||
|
||||
if (type == SdpType::kAnswer)
|
||||
SetNegotiatedHeaderExtensions_w(video->rtp_header_extensions());
|
||||
|
||||
RtpHeaderExtensions rtp_header_extensions =
|
||||
GetFilteredRtpHeaderExtensions(video->rtp_header_extensions());
|
||||
|
||||
|
|
10
pc/channel.h
10
pc/channel.h
|
@ -223,7 +223,7 @@ class BaseChannel : public ChannelInterface,
|
|||
// called.
|
||||
bool IsReadyToReceiveMedia_w() const RTC_RUN_ON(worker_thread());
|
||||
bool IsReadyToSendMedia_w() const RTC_RUN_ON(worker_thread());
|
||||
rtc::Thread* signaling_thread() { return signaling_thread_; }
|
||||
rtc::Thread* signaling_thread() const { return signaling_thread_; }
|
||||
|
||||
void FlushRtcpMessages_n() RTC_RUN_ON(network_thread());
|
||||
|
||||
|
@ -309,6 +309,11 @@ class BaseChannel : public ChannelInterface,
|
|||
// Return description of media channel to facilitate logging
|
||||
std::string ToString() const;
|
||||
|
||||
void SetNegotiatedHeaderExtensions_w(const RtpHeaderExtensions& extensions);
|
||||
|
||||
// ChannelInterface overrides
|
||||
RtpHeaderExtensions GetNegotiatedRtpHeaderExtensions() const override;
|
||||
|
||||
bool has_received_packet_ = false;
|
||||
|
||||
private:
|
||||
|
@ -375,6 +380,9 @@ class BaseChannel : public ChannelInterface,
|
|||
// like in Simulcast.
|
||||
// This object is not owned by the channel so it must outlive it.
|
||||
rtc::UniqueRandomIdGenerator* const ssrc_generator_;
|
||||
|
||||
RtpHeaderExtensions negotiated_header_extensions_
|
||||
RTC_GUARDED_BY(signaling_thread());
|
||||
};
|
||||
|
||||
// VoiceChannel is a specialization that adds support for early media, DTMF,
|
||||
|
|
|
@ -66,6 +66,9 @@ class ChannelInterface {
|
|||
// * A DtlsSrtpTransport for DTLS-SRTP.
|
||||
virtual bool SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) = 0;
|
||||
|
||||
// Returns the last negotiated header extensions.
|
||||
virtual RtpHeaderExtensions GetNegotiatedRtpHeaderExtensions() const = 0;
|
||||
|
||||
protected:
|
||||
virtual ~ChannelInterface() = default;
|
||||
};
|
||||
|
|
|
@ -166,6 +166,36 @@ TEST_P(PeerConnectionHeaderExtensionTest, OffersUnstoppedModifiedExtensions) {
|
|||
Field(&RtpExtension::uri, "uri3")));
|
||||
}
|
||||
|
||||
TEST_P(PeerConnectionHeaderExtensionTest, NegotiatedExtensionsAreAccessible) {
|
||||
cricket::MediaType media_type;
|
||||
SdpSemantics semantics;
|
||||
std::tie(media_type, semantics) = GetParam();
|
||||
if (semantics != SdpSemantics::kUnifiedPlan)
|
||||
return;
|
||||
std::unique_ptr<PeerConnectionWrapper> pc1 =
|
||||
CreatePeerConnection(media_type, semantics);
|
||||
auto transceiver1 = pc1->AddTransceiver(media_type);
|
||||
auto modified_extensions = transceiver1->HeaderExtensionsToOffer();
|
||||
modified_extensions[3].direction = RtpTransceiverDirection::kStopped;
|
||||
transceiver1->SetOfferedRtpHeaderExtensions(modified_extensions);
|
||||
auto offer = pc1->CreateOfferAndSetAsLocal(
|
||||
PeerConnectionInterface::RTCOfferAnswerOptions());
|
||||
|
||||
std::unique_ptr<PeerConnectionWrapper> pc2 =
|
||||
CreatePeerConnection(media_type, semantics);
|
||||
auto transceiver2 = pc2->AddTransceiver(media_type);
|
||||
pc2->SetRemoteDescription(std::move(offer));
|
||||
auto answer = pc2->CreateAnswerAndSetAsLocal(
|
||||
PeerConnectionInterface::RTCOfferAnswerOptions());
|
||||
pc1->SetRemoteDescription(std::move(answer));
|
||||
|
||||
// PC1 has exts 2-4 unstopped and PC2 has exts 1-3 unstopped -> ext 2, 3
|
||||
// survives.
|
||||
EXPECT_THAT(transceiver1->HeaderExtensionsNegotiated(),
|
||||
ElementsAre(Field(&RtpHeaderExtensionCapability::uri, "uri2"),
|
||||
Field(&RtpHeaderExtensionCapability::uri, "uri3")));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
,
|
||||
PeerConnectionHeaderExtensionTest,
|
||||
|
|
|
@ -12,12 +12,14 @@
|
|||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#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"
|
||||
#include "pc/session_description.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
|
@ -455,6 +457,17 @@ RtpTransceiver::HeaderExtensionsToOffer() const {
|
|||
return header_extensions_to_offer_;
|
||||
}
|
||||
|
||||
std::vector<RtpHeaderExtensionCapability>
|
||||
RtpTransceiver::HeaderExtensionsNegotiated() const {
|
||||
if (!channel_)
|
||||
return {};
|
||||
std::vector<RtpHeaderExtensionCapability> result;
|
||||
for (const auto& ext : channel_->GetNegotiatedRtpHeaderExtensions()) {
|
||||
result.emplace_back(ext.uri, ext.id, RtpTransceiverDirection::kSendRecv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RTCError RtpTransceiver::SetOfferedRtpHeaderExtensions(
|
||||
rtc::ArrayView<const RtpHeaderExtensionCapability>
|
||||
header_extensions_to_offer) {
|
||||
|
|
|
@ -207,6 +207,8 @@ class RtpTransceiver final
|
|||
}
|
||||
std::vector<RtpHeaderExtensionCapability> HeaderExtensionsToOffer()
|
||||
const override;
|
||||
std::vector<RtpHeaderExtensionCapability> HeaderExtensionsNegotiated()
|
||||
const override;
|
||||
RTCError SetOfferedRtpHeaderExtensions(
|
||||
rtc::ArrayView<const RtpHeaderExtensionCapability>
|
||||
header_extensions_to_offer) override;
|
||||
|
@ -264,6 +266,8 @@ PROXY_METHOD1(webrtc::RTCError,
|
|||
PROXY_CONSTMETHOD0(std::vector<RtpCodecCapability>, codec_preferences)
|
||||
PROXY_CONSTMETHOD0(std::vector<RtpHeaderExtensionCapability>,
|
||||
HeaderExtensionsToOffer)
|
||||
PROXY_CONSTMETHOD0(std::vector<RtpHeaderExtensionCapability>,
|
||||
HeaderExtensionsNegotiated)
|
||||
PROXY_METHOD1(webrtc::RTCError,
|
||||
SetOfferedRtpHeaderExtensions,
|
||||
rtc::ArrayView<const RtpHeaderExtensionCapability>)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "media/base/fake_media_engine.h"
|
||||
#include "pc/test/mock_channel_interface.h"
|
||||
#include "pc/test/mock_rtp_receiver_internal.h"
|
||||
|
@ -22,9 +24,7 @@
|
|||
#include "test/gtest.h"
|
||||
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using ::testing::Field;
|
||||
using ::testing::Not;
|
||||
using ::testing::Optional;
|
||||
using ::testing::Property;
|
||||
using ::testing::Return;
|
||||
using ::testing::ReturnRef;
|
||||
|
@ -206,4 +206,62 @@ TEST_F(RtpTransceiverTestForHeaderExtensions,
|
|||
EXPECT_EQ(transceiver_.HeaderExtensionsToOffer(), extensions_);
|
||||
}
|
||||
|
||||
TEST_F(RtpTransceiverTestForHeaderExtensions,
|
||||
NoNegotiatedHdrExtsWithoutChannel) {
|
||||
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(), ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(RtpTransceiverTestForHeaderExtensions,
|
||||
NoNegotiatedHdrExtsWithChannelWithoutNegotiation) {
|
||||
cricket::MockChannelInterface mock_channel;
|
||||
sigslot::signal1<cricket::ChannelInterface*> signal;
|
||||
ON_CALL(mock_channel, SignalFirstPacketReceived)
|
||||
.WillByDefault(ReturnRef(signal));
|
||||
transceiver_.SetChannel(&mock_channel);
|
||||
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(), ElementsAre());
|
||||
}
|
||||
|
||||
TEST_F(RtpTransceiverTestForHeaderExtensions, ReturnsNegotiatedHdrExts) {
|
||||
cricket::MockChannelInterface mock_channel;
|
||||
sigslot::signal1<cricket::ChannelInterface*> signal;
|
||||
ON_CALL(mock_channel, SignalFirstPacketReceived)
|
||||
.WillByDefault(ReturnRef(signal));
|
||||
cricket::RtpHeaderExtensions extensions = {webrtc::RtpExtension("uri1", 1),
|
||||
webrtc::RtpExtension("uri2", 2)};
|
||||
EXPECT_CALL(mock_channel, GetNegotiatedRtpHeaderExtensions)
|
||||
.WillOnce(Return(extensions));
|
||||
transceiver_.SetChannel(&mock_channel);
|
||||
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(),
|
||||
ElementsAre(RtpHeaderExtensionCapability(
|
||||
"uri1", 1, RtpTransceiverDirection::kSendRecv),
|
||||
RtpHeaderExtensionCapability(
|
||||
"uri2", 2, RtpTransceiverDirection::kSendRecv)));
|
||||
}
|
||||
|
||||
TEST_F(RtpTransceiverTestForHeaderExtensions,
|
||||
ReturnsNegotiatedHdrExtsSecondTime) {
|
||||
cricket::MockChannelInterface mock_channel;
|
||||
sigslot::signal1<cricket::ChannelInterface*> signal;
|
||||
ON_CALL(mock_channel, SignalFirstPacketReceived)
|
||||
.WillByDefault(ReturnRef(signal));
|
||||
cricket::RtpHeaderExtensions extensions = {webrtc::RtpExtension("uri1", 1),
|
||||
webrtc::RtpExtension("uri2", 2)};
|
||||
|
||||
EXPECT_CALL(mock_channel, GetNegotiatedRtpHeaderExtensions)
|
||||
.WillOnce(Return(extensions));
|
||||
transceiver_.SetChannel(&mock_channel);
|
||||
transceiver_.HeaderExtensionsNegotiated();
|
||||
testing::Mock::VerifyAndClearExpectations(&mock_channel);
|
||||
|
||||
extensions = {webrtc::RtpExtension("uri3", 4),
|
||||
webrtc::RtpExtension("uri5", 6)};
|
||||
EXPECT_CALL(mock_channel, GetNegotiatedRtpHeaderExtensions)
|
||||
.WillOnce(Return(extensions));
|
||||
EXPECT_THAT(transceiver_.HeaderExtensionsNegotiated(),
|
||||
ElementsAre(RtpHeaderExtensionCapability(
|
||||
"uri3", 4, RtpTransceiverDirection::kSendRecv),
|
||||
RtpHeaderExtensionCapability(
|
||||
"uri5", 6, RtpTransceiverDirection::kSendRecv)));
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -60,6 +60,10 @@ class MockChannelInterface : public cricket::ChannelInterface {
|
|||
SetRtpTransport,
|
||||
(webrtc::RtpTransportInternal*),
|
||||
(override));
|
||||
MOCK_METHOD(RtpHeaderExtensions,
|
||||
GetNegotiatedRtpHeaderExtensions,
|
||||
(),
|
||||
(const));
|
||||
};
|
||||
|
||||
} // namespace cricket
|
||||
|
|
Loading…
Reference in a new issue