SVC: Check scalability in AddTransceiver and SetParameters
ScalabilityMode should be validated against the currently allowed codecs or the currently used codec. Bug: webrtc:11607 Change-Id: Id2e6cbfad4f089de450150e1203657ed316e2f29 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/277403 Commit-Queue: Florent Castelli <orphis@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38433}
This commit is contained in:
parent
d806705623
commit
725ee24060
@ -65,8 +65,46 @@ std::vector<webrtc::RtpExtension> GetDefaultEnabledRtpHeaderExtensions(
|
||||
return extensions;
|
||||
}
|
||||
|
||||
webrtc::RTCError CheckScalabilityModeValues(
|
||||
const webrtc::RtpParameters& rtp_parameters,
|
||||
rtc::ArrayView<cricket::VideoCodec> codecs) {
|
||||
using webrtc::RTCErrorType;
|
||||
|
||||
if (codecs.empty()) {
|
||||
// This is an audio sender or an extra check in the stack where the codec
|
||||
// list is not available and we can't check the scalability_mode values.
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
||||
if (rtp_parameters.encodings[i].scalability_mode) {
|
||||
bool scalabilityModeFound = false;
|
||||
for (const cricket::VideoCodec& codec : codecs) {
|
||||
for (const auto& scalability_mode : codec.scalability_modes) {
|
||||
if (ScalabilityModeToString(scalability_mode) ==
|
||||
*rtp_parameters.encodings[i].scalability_mode) {
|
||||
scalabilityModeFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (scalabilityModeFound)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!scalabilityModeFound) {
|
||||
LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
|
||||
"Attempted to set RtpParameters scalabilityMode "
|
||||
"to an unsupported value for the current codecs.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
webrtc::RTCError CheckRtpParametersValues(
|
||||
const webrtc::RtpParameters& rtp_parameters) {
|
||||
const webrtc::RtpParameters& rtp_parameters,
|
||||
rtc::ArrayView<cricket::VideoCodec> codecs) {
|
||||
using webrtc::RTCErrorType;
|
||||
|
||||
for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
|
||||
@ -115,12 +153,20 @@ webrtc::RTCError CheckRtpParametersValues(
|
||||
}
|
||||
}
|
||||
|
||||
return webrtc::RTCError::OK();
|
||||
return CheckScalabilityModeValues(rtp_parameters, codecs);
|
||||
}
|
||||
|
||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
const webrtc::RtpParameters& old_rtp_parameters,
|
||||
const webrtc::RtpParameters& rtp_parameters) {
|
||||
return CheckRtpParametersInvalidModificationAndValues(old_rtp_parameters,
|
||||
rtp_parameters, {});
|
||||
}
|
||||
|
||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
const webrtc::RtpParameters& old_rtp_parameters,
|
||||
const webrtc::RtpParameters& rtp_parameters,
|
||||
rtc::ArrayView<cricket::VideoCodec> codecs) {
|
||||
using webrtc::RTCErrorType;
|
||||
if (rtp_parameters.encodings.size() != old_rtp_parameters.encodings.size()) {
|
||||
LOG_AND_RETURN_ERROR(
|
||||
@ -155,7 +201,7 @@ webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
"Attempted to set RtpParameters with modified SSRC");
|
||||
}
|
||||
|
||||
return CheckRtpParametersValues(rtp_parameters);
|
||||
return CheckRtpParametersValues(rtp_parameters, codecs);
|
||||
}
|
||||
|
||||
CompositeMediaEngine::CompositeMediaEngine(
|
||||
|
||||
@ -37,9 +37,28 @@ class Call;
|
||||
|
||||
namespace cricket {
|
||||
|
||||
webrtc::RTCError CheckRtpParametersValues(
|
||||
const webrtc::RtpParameters& new_parameters);
|
||||
// Checks that the scalability_mode value of each encoding is supported by at
|
||||
// least one video codec of the list. If the list is empty, no check is done.
|
||||
webrtc::RTCError CheckScalabilityModeValues(
|
||||
const webrtc::RtpParameters& new_parameters,
|
||||
rtc::ArrayView<cricket::VideoCodec> codecs);
|
||||
|
||||
// Checks the parameters have valid and supported values, and checks parameters
|
||||
// with CheckScalabilityModeValues().
|
||||
webrtc::RTCError CheckRtpParametersValues(
|
||||
const webrtc::RtpParameters& new_parameters,
|
||||
rtc::ArrayView<cricket::VideoCodec> codecs);
|
||||
|
||||
// Checks that the immutable values have not changed in new_parameters and
|
||||
// checks all parameters with CheckRtpParametersValues().
|
||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
const webrtc::RtpParameters& old_parameters,
|
||||
const webrtc::RtpParameters& new_parameters,
|
||||
rtc::ArrayView<cricket::VideoCodec> codecs);
|
||||
|
||||
// Checks that the immutable values have not changed in new_parameters and
|
||||
// checks parameters (except SVC) with CheckRtpParametersValues(). It should
|
||||
// usually be paired with a call to CheckScalabilityModeValues().
|
||||
webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
|
||||
const webrtc::RtpParameters& old_parameters,
|
||||
const webrtc::RtpParameters& new_parameters);
|
||||
|
||||
@ -2285,9 +2285,14 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetSendParameters(
|
||||
webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
|
||||
const webrtc::RtpParameters& new_parameters) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
// This is checked higher in the stack (RtpSender), so this is only checking
|
||||
// for users accessing the private APIs or tests, not specification
|
||||
// conformance.
|
||||
// TODO(orphis): Migrate tests to later make this a DCHECK only
|
||||
webrtc::RTCError error = CheckRtpParametersInvalidModificationAndValues(
|
||||
rtp_parameters_, new_parameters);
|
||||
if (!error.ok()) {
|
||||
// Error is propagated to the callback at a higher level
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@ -2241,6 +2241,7 @@ if (rtc_include_tests && !build_with_chromium) {
|
||||
"peer_connection_rtp_unittest.cc",
|
||||
"peer_connection_signaling_unittest.cc",
|
||||
"peer_connection_simulcast_unittest.cc",
|
||||
"peer_connection_svc_integrationtest.cc",
|
||||
"peer_connection_wrapper.cc",
|
||||
"peer_connection_wrapper.h",
|
||||
"proxy_unittest.cc",
|
||||
|
||||
@ -1075,7 +1075,14 @@ PeerConnection::AddTransceiver(
|
||||
"Attempted to set an unimplemented parameter of RtpParameters.");
|
||||
}
|
||||
|
||||
auto result = cricket::CheckRtpParametersValues(parameters);
|
||||
std::vector<cricket::VideoCodec> codecs;
|
||||
if (media_type == cricket::MEDIA_TYPE_VIDEO) {
|
||||
// Gather the current codec capabilities to allow checking scalabilityMode
|
||||
// against supported values.
|
||||
codecs = context_->media_engine()->video().send_codecs(false);
|
||||
}
|
||||
|
||||
auto result = cricket::CheckRtpParametersValues(parameters, codecs);
|
||||
if (!result.ok()) {
|
||||
LOG_AND_RETURN_ERROR(result.type(), result.message());
|
||||
}
|
||||
|
||||
243
pc/peer_connection_svc_integrationtest.cc
Normal file
243
pc/peer_connection_svc_integrationtest.cc
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
// Integration tests for PeerConnection.
|
||||
// These tests exercise a full stack for the SVC extension.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "api/rtc_error.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/rtp_transceiver_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "pc/test/integration_test_helpers.h"
|
||||
#include "rtc_base/gunit.h"
|
||||
#include "rtc_base/helpers.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
class PeerConnectionSVCIntegrationTest
|
||||
: public PeerConnectionIntegrationBaseTest {
|
||||
protected:
|
||||
PeerConnectionSVCIntegrationTest()
|
||||
: PeerConnectionIntegrationBaseTest(SdpSemantics::kUnifiedPlan) {}
|
||||
|
||||
RTCError SetCodecPreferences(
|
||||
rtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver,
|
||||
absl::string_view codec_name) {
|
||||
webrtc::RtpCapabilities capabilities =
|
||||
caller()->pc_factory()->GetRtpSenderCapabilities(
|
||||
cricket::MEDIA_TYPE_VIDEO);
|
||||
std::vector<RtpCodecCapability> codecs;
|
||||
for (const webrtc::RtpCodecCapability& codec_capability :
|
||||
capabilities.codecs) {
|
||||
if (codec_capability.name == codec_name)
|
||||
codecs.push_back(codec_capability);
|
||||
}
|
||||
return transceiver->SetCodecPreferences(codecs);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest, AddTransceiverAcceptsL1T1) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
encoding_parameters.scalability_mode = "L1T1";
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
EXPECT_TRUE(transceiver_or_error.ok());
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest, AddTransceiverAcceptsL3T3) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
encoding_parameters.scalability_mode = "L3T3";
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
EXPECT_TRUE(transceiver_or_error.ok());
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
AddTransceiverRejectsUnknownScalabilityMode) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
encoding_parameters.scalability_mode = "FOOBAR";
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
EXPECT_FALSE(transceiver_or_error.ok());
|
||||
EXPECT_EQ(transceiver_or_error.error().type(),
|
||||
webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest, SetParametersAcceptsL1T3WithVP8) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
|
||||
webrtc::RtpCapabilities capabilities =
|
||||
caller()->pc_factory()->GetRtpSenderCapabilities(
|
||||
cricket::MEDIA_TYPE_VIDEO);
|
||||
std::vector<RtpCodecCapability> vp8_codec;
|
||||
for (const webrtc::RtpCodecCapability& codec_capability :
|
||||
capabilities.codecs) {
|
||||
if (codec_capability.name == cricket::kVp8CodecName)
|
||||
vp8_codec.push_back(codec_capability);
|
||||
}
|
||||
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
ASSERT_TRUE(transceiver_or_error.ok());
|
||||
auto transceiver = transceiver_or_error.MoveValue();
|
||||
EXPECT_TRUE(transceiver->SetCodecPreferences(vp8_codec).ok());
|
||||
|
||||
webrtc::RtpParameters parameters = transceiver->sender()->GetParameters();
|
||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||
parameters.encodings[0].scalability_mode = "L1T3";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_TRUE(result.ok());
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest, SetParametersRejectsL3T3WithVP8) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
ASSERT_TRUE(transceiver_or_error.ok());
|
||||
auto transceiver = transceiver_or_error.MoveValue();
|
||||
EXPECT_TRUE(SetCodecPreferences(transceiver, cricket::kVp8CodecName).ok());
|
||||
|
||||
webrtc::RtpParameters parameters = transceiver->sender()->GetParameters();
|
||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||
parameters.encodings[0].scalability_mode = "L3T3";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
SetParametersAcceptsL1T3WithVP8AfterNegotiation) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
ASSERT_TRUE(transceiver_or_error.ok());
|
||||
auto transceiver = transceiver_or_error.MoveValue();
|
||||
EXPECT_TRUE(SetCodecPreferences(transceiver, cricket::kVp8CodecName).ok());
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
webrtc::RtpParameters parameters = transceiver->sender()->GetParameters();
|
||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||
parameters.encodings[0].scalability_mode = "L1T3";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_TRUE(result.ok());
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
SetParametersAcceptsL3T3WithVP9AfterNegotiation) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
ASSERT_TRUE(transceiver_or_error.ok());
|
||||
auto transceiver = transceiver_or_error.MoveValue();
|
||||
EXPECT_TRUE(SetCodecPreferences(transceiver, cricket::kVp9CodecName).ok());
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
webrtc::RtpParameters parameters = transceiver->sender()->GetParameters();
|
||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||
parameters.encodings[0].scalability_mode = "L3T3";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_TRUE(result.ok());
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
SetParametersRejectsL3T3WithVP8AfterNegotiation) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
ASSERT_TRUE(transceiver_or_error.ok());
|
||||
auto transceiver = transceiver_or_error.MoveValue();
|
||||
EXPECT_TRUE(SetCodecPreferences(transceiver, cricket::kVp8CodecName).ok());
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
webrtc::RtpParameters parameters = transceiver->sender()->GetParameters();
|
||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||
parameters.encodings[0].scalability_mode = "L3T3";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
TEST_F(PeerConnectionSVCIntegrationTest,
|
||||
SetParametersRejectsInvalidModeWithVP9AfterNegotiation) {
|
||||
ASSERT_TRUE(CreatePeerConnectionWrappers());
|
||||
ConnectFakeSignaling();
|
||||
|
||||
webrtc::RtpTransceiverInit init;
|
||||
webrtc::RtpEncodingParameters encoding_parameters;
|
||||
init.send_encodings.push_back(encoding_parameters);
|
||||
auto transceiver_or_error =
|
||||
caller()->pc()->AddTransceiver(caller()->CreateLocalVideoTrack(), init);
|
||||
ASSERT_TRUE(transceiver_or_error.ok());
|
||||
auto transceiver = transceiver_or_error.MoveValue();
|
||||
EXPECT_TRUE(SetCodecPreferences(transceiver, cricket::kVp9CodecName).ok());
|
||||
|
||||
caller()->CreateAndSetAndSignalOffer();
|
||||
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
|
||||
|
||||
webrtc::RtpParameters parameters = transceiver->sender()->GetParameters();
|
||||
ASSERT_EQ(parameters.encodings.size(), 1u);
|
||||
parameters.encodings[0].scalability_mode = "FOOBAR";
|
||||
auto result = transceiver->sender()->SetParameters(parameters);
|
||||
EXPECT_FALSE(result.ok());
|
||||
EXPECT_EQ(result.type(), webrtc::RTCErrorType::UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace webrtc
|
||||
@ -200,7 +200,7 @@ RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||
init_parameters_, parameters);
|
||||
init_parameters_, parameters, video_codec_preferences_);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
@ -208,13 +208,22 @@ RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
|
||||
}
|
||||
return worker_thread_->BlockingCall([&] {
|
||||
RtpParameters rtp_parameters = parameters;
|
||||
RtpParameters old_parameters = media_channel_->GetRtpSendParameters(ssrc_);
|
||||
if (!disabled_rids_.empty()) {
|
||||
// Need to add the inactive layers.
|
||||
RtpParameters old_parameters =
|
||||
media_channel_->GetRtpSendParameters(ssrc_);
|
||||
rtp_parameters = RestoreEncodingLayers(parameters, disabled_rids_,
|
||||
old_parameters.encodings);
|
||||
}
|
||||
|
||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||
old_parameters, rtp_parameters);
|
||||
if (!result.ok())
|
||||
return result;
|
||||
|
||||
result = CheckSVCParameters(rtp_parameters);
|
||||
if (!result.ok())
|
||||
return result;
|
||||
|
||||
return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
|
||||
});
|
||||
}
|
||||
@ -231,7 +240,7 @@ RTCError RtpSenderBase::SetParametersInternalWithAllLayers(
|
||||
}
|
||||
if (!media_channel_ || !ssrc_) {
|
||||
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
|
||||
init_parameters_, parameters);
|
||||
init_parameters_, parameters, video_codec_preferences_);
|
||||
if (result.ok()) {
|
||||
init_parameters_ = parameters;
|
||||
}
|
||||
@ -725,4 +734,20 @@ void VideoRtpSender::ClearSend() {
|
||||
[&] { video_media_channel()->SetVideoSend(ssrc_, nullptr, nullptr); });
|
||||
}
|
||||
|
||||
RTCError VideoRtpSender::CheckSVCParameters(const RtpParameters& parameters) {
|
||||
cricket::VideoCodec codec;
|
||||
video_media_channel()->GetSendCodec(&codec);
|
||||
|
||||
// Match the currently used codec against the codec preferences to gather
|
||||
// the SVC capabilities.
|
||||
std::vector<cricket::VideoCodec> codecs;
|
||||
for (const auto& codec_preference : video_codec_preferences_) {
|
||||
if (codec.Matches(codec_preference)) {
|
||||
codecs.push_back(codec_preference);
|
||||
}
|
||||
}
|
||||
|
||||
return cricket::CheckScalabilityModeValues(parameters, codecs);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -82,6 +82,11 @@ class RtpSenderInternal : public RtpSenderInterface {
|
||||
virtual RTCError SetParametersInternalWithAllLayers(
|
||||
const RtpParameters& parameters) = 0;
|
||||
|
||||
// Additional checks that are specific to the Sender type
|
||||
virtual RTCError CheckSVCParameters(const RtpParameters& parameters) {
|
||||
return webrtc::RTCError::OK();
|
||||
}
|
||||
|
||||
// Returns an ID that changes every time SetTrack() is called, but
|
||||
// otherwise remains constant. Used to generate IDs for stats.
|
||||
// The special value zero means that no track is attached.
|
||||
@ -93,6 +98,11 @@ class RtpSenderInternal : public RtpSenderInterface {
|
||||
const std::vector<std::string>& rid) = 0;
|
||||
|
||||
virtual void SetTransceiverAsStopped() = 0;
|
||||
|
||||
// Used by the owning transceiver to inform the sender on the currently
|
||||
// selected codecs.
|
||||
virtual void SetVideoCodecPreferences(
|
||||
std::vector<cricket::VideoCodec> codec_preferences) = 0;
|
||||
};
|
||||
|
||||
// Shared implementation for RtpSenderInternal interface.
|
||||
@ -203,6 +213,11 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
||||
is_transceiver_stopped_ = true;
|
||||
}
|
||||
|
||||
void SetVideoCodecPreferences(
|
||||
std::vector<cricket::VideoCodec> codec_preferences) override {
|
||||
video_codec_preferences_ = codec_preferences;
|
||||
}
|
||||
|
||||
protected:
|
||||
// If `set_streams_observer` is not null, it is invoked when SetStreams()
|
||||
// is called. `set_streams_observer` is not owned by this object. If not
|
||||
@ -238,6 +253,7 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
|
||||
|
||||
std::vector<std::string> stream_ids_;
|
||||
RtpParameters init_parameters_;
|
||||
std::vector<cricket::VideoCodec> video_codec_preferences_;
|
||||
|
||||
// TODO(tommi): `media_channel_` and several other member variables in this
|
||||
// class (ssrc_, stopped_, etc) are accessed from more than one thread without
|
||||
@ -395,6 +411,8 @@ class VideoRtpSender : public RtpSenderBase {
|
||||
|
||||
rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const override;
|
||||
|
||||
RTCError CheckSVCParameters(const RtpParameters& parameters) override;
|
||||
|
||||
protected:
|
||||
VideoRtpSender(rtc::Thread* worker_thread,
|
||||
const std::string& id,
|
||||
|
||||
@ -107,6 +107,25 @@ RTCError VerifyCodecPreferences(const std::vector<RtpCodecCapability>& codecs,
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
// Matches the list of codecs as capabilities (potentially without SVC related
|
||||
// information) to the list of send codecs and returns the list of codecs with
|
||||
// all the SVC related information.
|
||||
std::vector<cricket::VideoCodec> MatchCodecPreferences(
|
||||
const std::vector<RtpCodecCapability>& codecs,
|
||||
const std::vector<cricket::VideoCodec>& send_codecs) {
|
||||
std::vector<cricket::VideoCodec> result;
|
||||
|
||||
for (const auto& codec_preference : codecs) {
|
||||
for (const cricket::VideoCodec& send_codec : send_codecs) {
|
||||
if (send_codec.MatchesCapability(codec_preference)) {
|
||||
result.push_back(send_codec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TaskQueueBase* GetCurrentTaskQueueOrThread() {
|
||||
TaskQueueBase* current = TaskQueueBase::Current();
|
||||
if (!current)
|
||||
@ -142,6 +161,9 @@ RtpTransceiver::RtpTransceiver(
|
||||
RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO ||
|
||||
media_type_ == cricket::MEDIA_TYPE_VIDEO);
|
||||
RTC_DCHECK_EQ(sender->media_type(), receiver->media_type());
|
||||
if (sender->media_type() == cricket::MEDIA_TYPE_VIDEO)
|
||||
sender->internal()->SetVideoCodecPreferences(
|
||||
media_engine()->video().send_codecs(false));
|
||||
senders_.push_back(sender);
|
||||
receivers_.push_back(receiver);
|
||||
}
|
||||
@ -342,6 +364,14 @@ void RtpTransceiver::AddSender(
|
||||
RTC_DCHECK(sender);
|
||||
RTC_DCHECK_EQ(media_type(), sender->media_type());
|
||||
RTC_DCHECK(!absl::c_linear_search(senders_, sender));
|
||||
if (media_type() == cricket::MEDIA_TYPE_VIDEO) {
|
||||
std::vector<cricket::VideoCodec> send_codecs =
|
||||
media_engine()->video().send_codecs(false);
|
||||
sender->internal()->SetVideoCodecPreferences(
|
||||
codec_preferences_.empty()
|
||||
? send_codecs
|
||||
: MatchCodecPreferences(codec_preferences_, send_codecs));
|
||||
}
|
||||
senders_.push_back(sender);
|
||||
}
|
||||
|
||||
@ -590,6 +620,9 @@ RTCError RtpTransceiver::SetCodecPreferences(
|
||||
// to codecs and abort these steps.
|
||||
if (codec_capabilities.empty()) {
|
||||
codec_preferences_.clear();
|
||||
if (media_type() == cricket::MEDIA_TYPE_VIDEO)
|
||||
senders_.front()->internal()->SetVideoCodecPreferences(
|
||||
media_engine()->video().send_codecs(false));
|
||||
return RTCError::OK();
|
||||
}
|
||||
|
||||
@ -612,6 +645,11 @@ RTCError RtpTransceiver::SetCodecPreferences(
|
||||
send_codecs = media_engine()->video().send_codecs(context()->use_rtx());
|
||||
recv_codecs = media_engine()->video().recv_codecs(context()->use_rtx());
|
||||
result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
|
||||
|
||||
if (result.ok()) {
|
||||
senders_.front()->internal()->SetVideoCodecPreferences(
|
||||
MatchCodecPreferences(codecs, send_codecs));
|
||||
}
|
||||
}
|
||||
|
||||
if (result.ok()) {
|
||||
|
||||
@ -167,6 +167,7 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase {
|
||||
dependencies.network_thread = rtc::Thread::Current();
|
||||
dependencies.worker_thread = rtc::Thread::Current();
|
||||
dependencies.signaling_thread = rtc::Thread::Current();
|
||||
dependencies.media_engine = std::make_unique<cricket::FakeMediaEngine>();
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +60,11 @@ class MockRtpSenderInternal : public RtpSenderInternal {
|
||||
SetParametersInternalWithAllLayers,
|
||||
(const RtpParameters&),
|
||||
(override));
|
||||
MOCK_METHOD(RTCError, CheckSVCParameters, (const RtpParameters&), (override));
|
||||
MOCK_METHOD(void,
|
||||
SetVideoCodecPreferences,
|
||||
(std::vector<cricket::VideoCodec>),
|
||||
(override));
|
||||
MOCK_METHOD(rtc::scoped_refptr<DtmfSenderInterface>,
|
||||
GetDtmfSender,
|
||||
(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user