Skip to content

Commit

Permalink
RtpTransceiverInterface: introduce HeaderExtensionsNegotiated.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Commit-Queue: Markus Handell <[email protected]>
Cr-Commit-Position: refs/heads/master@{#32860}
  • Loading branch information
Markus Handell authored and Commit Bot committed Dec 17, 2020
1 parent d95a47d commit 5932fe1
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 4 deletions.
5 changes: 5 additions & 0 deletions api/rtp_transceiver_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
6 changes: 6 additions & 0 deletions api/rtp_transceiver_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions pc/channel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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());

Expand Down
10 changes: 9 additions & 1 deletion pc/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions pc/channel_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
30 changes: 30 additions & 0 deletions pc/peer_connection_header_extension_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 13 additions & 0 deletions pc/rtp_transceiver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 4 additions & 0 deletions pc/rtp_transceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>)
Expand Down
64 changes: 61 additions & 3 deletions pc/rtp_transceiver_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -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
4 changes: 4 additions & 0 deletions pc/test/mock_channel_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class MockChannelInterface : public cricket::ChannelInterface {
SetRtpTransport,
(webrtc::RtpTransportInternal*),
(override));
MOCK_METHOD(RtpHeaderExtensions,
GetNegotiatedRtpHeaderExtensions,
(),
(const));
};

} // namespace cricket
Expand Down

0 comments on commit 5932fe1

Please sign in to comment.