pc: Add asynchronous RtpSender::SetParameters() call

As the synchronous version only posts a task to recreate the encoder
later, it is not possible to catch errors and state changes that
could appear then.
The asynchronous version of SetParameters() aims to solve this by
providing a callback to wait for the completion of the encoder
reconfiguration, allowing any error to be propagate and subsequent
getParameters() call to have up to date information.

Bug: webrtc:11607
Change-Id: I5548e75aa14a97f8d9c0c94df1e72e9cd40887b2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/278420
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38627}
This commit is contained in:
Florent Castelli 2022-10-18 17:05:16 +02:00 committed by WebRTC LUCI CQ
parent 7d8d64323c
commit acabb3641b
43 changed files with 567 additions and 95 deletions

View file

@ -193,6 +193,40 @@ rtc_library("dtls_transport_interface") {
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
rtc_library("dtmf_sender_interface") {
visibility = [ "*" ]
sources = [ "dtmf_sender_interface.h" ]
deps = [
":media_stream_interface",
"../rtc_base:refcount",
]
}
rtc_library("rtp_sender_interface") {
visibility = [ "*" ]
sources = [
"rtp_sender_interface.cc",
"rtp_sender_interface.h",
]
deps = [
":dtls_transport_interface",
":dtmf_sender_interface",
":frame_transformer_interface",
":media_stream_interface",
":rtc_error",
":rtp_parameters",
":scoped_refptr",
"../rtc_base:checks",
"../rtc_base:refcount",
"../rtc_base/system:rtc_export",
"crypto:frame_encryptor_interface",
"video_codecs:video_codecs_api",
]
absl_deps = [ "//third_party/abseil-cpp/absl/functional:any_invocable" ]
}
rtc_library("libjingle_peerconnection_api") {
visibility = [ "*" ]
cflags = []
@ -200,7 +234,6 @@ rtc_library("libjingle_peerconnection_api") {
"crypto_params.h",
"data_channel_interface.cc",
"data_channel_interface.h",
"dtmf_sender_interface.h",
"jsep.cc",
"jsep.h",
"jsep_ice_candidate.cc",
@ -212,7 +245,6 @@ rtc_library("libjingle_peerconnection_api") {
"peer_connection_interface.h",
"rtp_receiver_interface.cc",
"rtp_receiver_interface.h",
"rtp_sender_interface.h",
"rtp_transceiver_interface.cc",
"rtp_transceiver_interface.h",
"sctp_transport_interface.cc",
@ -221,6 +253,15 @@ rtc_library("libjingle_peerconnection_api") {
"set_remote_description_observer_interface.h",
"uma_metrics.h",
"video_track_source_proxy_factory.h",
# Remove when downstream has been updated
"dtmf_sender_interface.h",
"rtp_sender_interface.h",
]
public_deps = [ # no-presubmit-check TODO(webrtc:8603)
# Remove when downstream has been updated
":dtmf_sender_interface",
":rtp_sender_interface",
]
deps = [
":array_view",
@ -244,6 +285,7 @@ rtc_library("libjingle_peerconnection_api") {
":rtc_stats_api",
":rtp_packet_info",
":rtp_parameters",
":rtp_sender_interface",
":rtp_transceiver_direction",
":scoped_refptr",
":sequence_checker",
@ -294,6 +336,7 @@ rtc_library("libjingle_peerconnection_api") {
absl_deps = [
"//third_party/abseil-cpp/absl/algorithm:container",
"//third_party/abseil-cpp/absl/base:core_headers",
"//third_party/abseil-cpp/absl/functional:any_invocable",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
@ -1014,6 +1057,7 @@ if (rtc_include_tests) {
sources = [ "test/mock_dtmf_sender.h" ]
deps = [
":dtmf_sender_interface",
":libjingle_peerconnection_api",
"../test:test_support",
]
@ -1175,6 +1219,7 @@ if (rtc_include_tests) {
deps = [
":libjingle_peerconnection_api",
":rtp_sender_interface",
"../test:test_support",
]
}

View file

@ -0,0 +1,22 @@
/*
* 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.
*/
#include "api/rtp_sender_interface.h"
#include "rtc_base/checks.h"
namespace webrtc {
void RtpSenderInterface::SetParametersAsync(const RtpParameters& parameters,
SetParametersCallback callback) {
RTC_DCHECK_NOTREACHED() << "Default implementation called";
}
} // namespace webrtc

View file

@ -18,6 +18,7 @@
#include <string>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "api/crypto/frame_encryptor_interface.h"
#include "api/dtls_transport_interface.h"
#include "api/dtmf_sender_interface.h"
@ -33,6 +34,8 @@
namespace webrtc {
using SetParametersCallback = absl::AnyInvocable<void(RTCError) &&>;
class RTC_EXPORT RtpSenderInterface : public rtc::RefCountInterface {
public:
// Returns true if successful in setting the track.
@ -79,6 +82,8 @@ class RTC_EXPORT RtpSenderInterface : public rtc::RefCountInterface {
// rtpparameters.h
// The encodings are in increasing quality order for simulcast.
virtual RTCError SetParameters(const RtpParameters& parameters) = 0;
virtual void SetParametersAsync(const RtpParameters& parameters,
SetParametersCallback callback);
// Returns null for a video sender.
virtual rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const = 0;

View file

@ -46,6 +46,10 @@ class MockRtpSender : public RtpSenderInterface {
(const, override));
MOCK_METHOD(RtpParameters, GetParameters, (), (const, override));
MOCK_METHOD(RTCError, SetParameters, (const RtpParameters&), (override));
MOCK_METHOD(void,
SetParametersAsync,
(const RtpParameters&, SetParametersCallback),
(override));
MOCK_METHOD(rtc::scoped_refptr<DtmfSenderInterface>,
GetDtmfSender,
(),

View file

@ -70,6 +70,7 @@ rtc_library("audio") {
"../common_audio:common_audio_c",
"../logging:rtc_event_audio",
"../logging:rtc_stream_config",
"../media:rtc_media_base",
"../modules/async_audio_processing",
"../modules/audio_coding",
"../modules/audio_coding:audio_coding_module_typedefs",

View file

@ -2,6 +2,7 @@ include_rules = [
"+call",
"+common_audio",
"+logging/rtc_event_log",
"+media/base",
"+modules/async_audio_processing",
"+modules/audio_coding",
"+modules/audio_device",

View file

@ -31,6 +31,7 @@
#include "common_audio/vad/include/vad.h"
#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h"
#include "logging/rtc_event_log/rtc_stream_config.h"
#include "media/base/media_channel.h"
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
#include "modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
#include "modules/audio_processing/include/audio_processing.h"
@ -174,7 +175,7 @@ AudioSendStream::AudioSendStream(
RTC_DCHECK(rtp_rtcp_module_);
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
ConfigureStream(config, true);
ConfigureStream(config, true, nullptr);
UpdateCachedTargetAudioBitrateConstraints();
}
@ -195,9 +196,10 @@ const webrtc::AudioSendStream::Config& AudioSendStream::GetConfig() const {
}
void AudioSendStream::Reconfigure(
const webrtc::AudioSendStream::Config& new_config) {
const webrtc::AudioSendStream::Config& new_config,
SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
ConfigureStream(new_config, false);
ConfigureStream(new_config, false, std::move(callback));
}
AudioSendStream::ExtensionIds AudioSendStream::FindExtensionIds(
@ -229,7 +231,8 @@ int AudioSendStream::TransportSeqNumId(const AudioSendStream::Config& config) {
void AudioSendStream::ConfigureStream(
const webrtc::AudioSendStream::Config& new_config,
bool first_time) {
bool first_time,
SetParametersCallback callback) {
RTC_LOG(LS_INFO) << "AudioSendStream::ConfigureStream: "
<< new_config.ToString();
UpdateEventLogStreamConfig(event_log_, new_config,
@ -327,6 +330,10 @@ void AudioSendStream::ConfigureStream(
if (!ReconfigureSendCodec(new_config)) {
RTC_LOG(LS_ERROR) << "Failed to set up send codec state.";
webrtc::InvokeSetParametersCallback(
callback, webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR,
"Failed to set up send codec state."));
}
// Set currently known overhead (used in ANA, opus only).
@ -352,6 +359,8 @@ void AudioSendStream::ConfigureStream(
if (!first_time) {
UpdateCachedTargetAudioBitrateConstraints();
}
webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
}
void AudioSendStream::Start() {

View file

@ -88,7 +88,8 @@ class AudioSendStream final : public webrtc::AudioSendStream,
// webrtc::AudioSendStream implementation.
const webrtc::AudioSendStream::Config& GetConfig() const override;
void Reconfigure(const webrtc::AudioSendStream::Config& config) override;
void Reconfigure(const webrtc::AudioSendStream::Config& config,
SetParametersCallback callback) override;
void Start() override;
void Stop() override;
void SendAudioData(std::unique_ptr<AudioFrame> audio_frame) override;
@ -129,7 +130,9 @@ class AudioSendStream final : public webrtc::AudioSendStream,
void StoreEncoderProperties(int sample_rate_hz, size_t num_channels)
RTC_RUN_ON(worker_thread_checker_);
void ConfigureStream(const Config& new_config, bool first_time)
void ConfigureStream(const Config& new_config,
bool first_time,
SetParametersCallback callback)
RTC_RUN_ON(worker_thread_checker_);
bool SetupSendCodec(const Config& new_config)
RTC_RUN_ON(worker_thread_checker_);

View file

@ -550,7 +550,7 @@ TEST(AudioSendStreamTest, SendCodecAppliesAudioNetworkAdaptor) {
auto stream_config = helper.config();
stream_config.audio_network_adaptor_config = kAnaReconfigString;
send_stream->Reconfigure(stream_config);
send_stream->Reconfigure(stream_config, nullptr);
}
}
@ -590,7 +590,7 @@ TEST(AudioSendStreamTest, AudioNetworkAdaptorReceivesOverhead) {
auto stream_config = helper.config();
stream_config.audio_network_adaptor_config = kAnaConfigString;
send_stream->Reconfigure(stream_config);
send_stream->Reconfigure(stream_config, nullptr);
}
}
@ -791,7 +791,7 @@ TEST(AudioSendStreamTest, DontRecreateEncoder) {
AudioSendStream::Config::SendCodecSpec(9, kG722Format);
helper.config().send_codec_spec->cng_payload_type = 105;
auto send_stream = helper.CreateAudioSendStream();
send_stream->Reconfigure(helper.config());
send_stream->Reconfigure(helper.config(), nullptr);
}
}
@ -816,7 +816,7 @@ TEST(AudioSendStreamTest, ReconfigureTransportCcResetsFirst) {
.Times(1);
}
send_stream->Reconfigure(new_config);
send_stream->Reconfigure(new_config, nullptr);
}
}
@ -928,11 +928,11 @@ TEST(AudioSendStreamTest, ReconfigureWithFrameEncryptor) {
new_config.frame_encryptor = mock_frame_encryptor_0;
EXPECT_CALL(*helper.channel_send(), SetFrameEncryptor(Ne(nullptr)))
.Times(1);
send_stream->Reconfigure(new_config);
send_stream->Reconfigure(new_config, nullptr);
// Not updating the frame encryptor shouldn't force it to reconfigure.
EXPECT_CALL(*helper.channel_send(), SetFrameEncryptor(_)).Times(0);
send_stream->Reconfigure(new_config);
send_stream->Reconfigure(new_config, nullptr);
// Updating frame encryptor to a new object should force a call to the
// proxy.
@ -942,7 +942,7 @@ TEST(AudioSendStreamTest, ReconfigureWithFrameEncryptor) {
new_config.crypto_options.sframe.require_frame_encryption = true;
EXPECT_CALL(*helper.channel_send(), SetFrameEncryptor(Ne(nullptr)))
.Times(1);
send_stream->Reconfigure(new_config);
send_stream->Reconfigure(new_config, nullptr);
}
}
} // namespace test

View file

@ -48,6 +48,7 @@ rtc_library("call_interfaces") {
"../api:rtc_error",
"../api:rtp_headers",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api:transport_api",
"../api/adaptation:resource_adaptation_api",
@ -76,6 +77,7 @@ rtc_library("call_interfaces") {
"../rtc_base/network:sent_packet",
]
absl_deps = [
"//third_party/abseil-cpp/absl/functional:any_invocable",
"//third_party/abseil-cpp/absl/functional:bind_front",
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
@ -373,6 +375,7 @@ rtc_library("video_stream_api") {
"../api:frame_transformer_interface",
"../api:rtp_headers",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api:transport_api",
"../api/adaptation:resource_adaptation_api",
@ -390,7 +393,10 @@ rtc_library("video_stream_api") {
"../rtc_base:stringutils",
"../video/config:encoder_config",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
absl_deps = [
"//third_party/abseil-cpp/absl/functional:any_invocable",
"//third_party/abseil-cpp/absl/types:optional",
]
}
rtc_library("simulated_network") {

View file

@ -25,6 +25,7 @@
#include "api/crypto/frame_encryptor_interface.h"
#include "api/frame_transformer_interface.h"
#include "api/rtp_parameters.h"
#include "api/rtp_sender_interface.h"
#include "api/scoped_refptr.h"
#include "call/audio_sender.h"
#include "call/rtp_config.h"
@ -173,7 +174,8 @@ class AudioSendStream : public AudioSender {
virtual const webrtc::AudioSendStream::Config& GetConfig() const = 0;
// Reconfigure the stream according to the Configuration.
virtual void Reconfigure(const Config& config) = 0;
virtual void Reconfigure(const Config& config,
SetParametersCallback callback) = 0;
// Starts stream activity.
// When a stream is active, it can receive, process and deliver packets.

View file

@ -25,7 +25,10 @@ class MockAudioSendStream : public AudioSendStream {
GetConfig,
(),
(const, override));
MOCK_METHOD(void, Reconfigure, (const Config& config), (override));
MOCK_METHOD(void,
Reconfigure,
(const Config& config, SetParametersCallback callback),
(override));
MOCK_METHOD(void, Start, (), (override));
MOCK_METHOD(void, Stop, (), (override));
// GMock doesn't like move-only types, such as std::unique_ptr.

View file

@ -23,6 +23,7 @@
#include "api/crypto/crypto_options.h"
#include "api/frame_transformer_interface.h"
#include "api/rtp_parameters.h"
#include "api/rtp_sender_interface.h"
#include "api/scoped_refptr.h"
#include "api/video/video_content_type.h"
#include "api/video/video_frame.h"
@ -251,6 +252,9 @@ class VideoSendStream {
// with the VideoStream settings.
virtual void ReconfigureVideoEncoder(VideoEncoderConfig config) = 0;
virtual void ReconfigureVideoEncoder(VideoEncoderConfig config,
SetParametersCallback callback) = 0;
virtual Stats GetStats() = 0;
virtual void GenerateKeyFrame(const std::vector<std::string>& rids) = 0;

View file

@ -690,6 +690,7 @@ if (is_linux || is_chromeos || is_win) {
"../api:create_peerconnection_factory",
"../api:libjingle_peerconnection_api",
"../api:media_stream_interface",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api/audio:audio_mixer_api",
"../api/audio_codecs:audio_codecs_api",

View file

@ -57,6 +57,7 @@ rtc_library("rtc_media_base") {
"../api:media_stream_interface",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api:sequence_checker",
"../api/audio:audio_frame_processor",

View file

@ -30,6 +30,7 @@
#include "modules/audio_processing/include/audio_processing.h"
#include "rtc_base/copy_on_write_buffer.h"
#include "rtc_base/network_route.h"
#include "rtc_base/thread.h"
using webrtc::RtpExtension;
@ -149,20 +150,25 @@ class RtpHelper : public Base {
}
virtual webrtc::RTCError SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback) {
auto parameters_iterator = rtp_send_parameters_.find(ssrc);
if (parameters_iterator != rtp_send_parameters_.end()) {
auto result = CheckRtpParametersInvalidModificationAndValues(
parameters_iterator->second, parameters);
if (!result.ok())
return result;
if (!result.ok()) {
return webrtc::InvokeSetParametersCallback(callback, result);
}
parameters_iterator->second = parameters;
return webrtc::RTCError::OK();
return webrtc::InvokeSetParametersCallback(callback,
webrtc::RTCError::OK());
}
// Replicate the behavior of the real media channel: return false
// when setting parameters for unknown SSRCs.
return webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR);
return InvokeSetParametersCallback(
callback, webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR));
}
virtual webrtc::RtpParameters GetRtpReceiveParameters(uint32_t ssrc) const {

View file

@ -12,6 +12,19 @@
#include "media/base/rtp_utils.h"
namespace webrtc {
webrtc::RTCError InvokeSetParametersCallback(SetParametersCallback& callback,
RTCError error) {
if (callback) {
std::move(callback)(error);
callback = nullptr;
}
return error;
}
} // namespace webrtc
namespace cricket {
using webrtc::FrameDecryptorInterface;
using webrtc::FrameEncryptorInterface;

View file

@ -26,6 +26,7 @@
#include "api/media_stream_interface.h"
#include "api/rtc_error.h"
#include "api/rtp_parameters.h"
#include "api/rtp_sender_interface.h"
#include "api/task_queue/pending_task_safety_flag.h"
#include "api/transport/data_channel_transport_interface.h"
#include "api/transport/rtp/rtp_source.h"
@ -61,6 +62,10 @@ class Timing;
namespace webrtc {
class AudioSinkInterface;
class VideoFrame;
webrtc::RTCError InvokeSetParametersCallback(SetParametersCallback& callback,
RTCError error);
} // namespace webrtc
namespace cricket {
@ -277,7 +282,8 @@ class MediaChannel {
virtual webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const = 0;
virtual webrtc::RTCError SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) = 0;
const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback = nullptr) = 0;
virtual void SetEncoderToPacketizerFrameTransformer(
uint32_t ssrc,

View file

@ -15,6 +15,7 @@
#include "absl/algorithm/container.h"
#include "absl/strings/string_view.h"
#include "api/call/audio_sink.h"
#include "media/base/media_channel.h"
#include "modules/rtp_rtcp/source/rtp_util.h"
#include "rtc_base/checks.h"
#include "rtc_base/gunit.h"
@ -31,8 +32,10 @@ FakeAudioSendStream::FakeAudioSendStream(
: id_(id), config_(config) {}
void FakeAudioSendStream::Reconfigure(
const webrtc::AudioSendStream::Config& config) {
const webrtc::AudioSendStream::Config& config,
webrtc::SetParametersCallback callback) {
config_ = config;
webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
}
const webrtc::AudioSendStream::Config& FakeAudioSendStream::GetConfig() const {
@ -275,6 +278,12 @@ webrtc::VideoSendStream::Stats FakeVideoSendStream::GetStats() {
void FakeVideoSendStream::ReconfigureVideoEncoder(
webrtc::VideoEncoderConfig config) {
ReconfigureVideoEncoder(std::move(config), nullptr);
}
void FakeVideoSendStream::ReconfigureVideoEncoder(
webrtc::VideoEncoderConfig config,
webrtc::SetParametersCallback callback) {
int width, height;
if (last_frame_) {
width = last_frame_->width();
@ -326,6 +335,7 @@ void FakeVideoSendStream::ReconfigureVideoEncoder(
codec_settings_set_ = config.encoder_specific_settings != nullptr;
encoder_config_ = std::move(config);
++num_encoder_reconfigurations_;
webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
}
void FakeVideoSendStream::UpdateActiveSimulcastLayers(

View file

@ -62,7 +62,8 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream {
private:
// webrtc::AudioSendStream implementation.
void Reconfigure(const webrtc::AudioSendStream::Config& config) override;
void Reconfigure(const webrtc::AudioSendStream::Config& config,
webrtc::SetParametersCallback callback) override;
void Start() override { sending_ = true; }
void Stop() override { sending_ = false; }
void SendAudioData(std::unique_ptr<webrtc::AudioFrame> audio_frame) override {
@ -213,7 +214,10 @@ class FakeVideoSendStream final
rtc::VideoSourceInterface<webrtc::VideoFrame>* source,
const webrtc::DegradationPreference& degradation_preference) override;
webrtc::VideoSendStream::Stats GetStats() override;
void ReconfigureVideoEncoder(webrtc::VideoEncoderConfig config) override;
void ReconfigureVideoEncoder(webrtc::VideoEncoderConfig config,
webrtc::SetParametersCallback callback) override;
bool sending_;
webrtc::VideoSendStream::Config config_;

View file

@ -1042,7 +1042,8 @@ webrtc::RtpParameters WebRtcVideoChannel::GetRtpSendParameters(
webrtc::RTCError WebRtcVideoChannel::SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(&thread_checker_);
TRACE_EVENT0("webrtc", "WebRtcVideoChannel::SetRtpSendParameters");
auto it = send_streams_.find(ssrc);
@ -1050,7 +1051,8 @@ webrtc::RTCError WebRtcVideoChannel::SetRtpSendParameters(
RTC_LOG(LS_ERROR) << "Attempting to set RTP send parameters for stream "
"with ssrc "
<< ssrc << " which doesn't exist.";
return webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR);
return webrtc::InvokeSetParametersCallback(
callback, webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR));
}
// TODO(deadbeef): Handle setting parameters with a list of codecs in a
@ -1059,7 +1061,8 @@ webrtc::RTCError WebRtcVideoChannel::SetRtpSendParameters(
if (current_parameters.codecs != parameters.codecs) {
RTC_DLOG(LS_ERROR) << "Using SetParameters to change the set of codecs "
"is not currently supported.";
return webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR);
return webrtc::InvokeSetParametersCallback(
callback, webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR));
}
if (!parameters.encodings.empty()) {
@ -1085,7 +1088,7 @@ webrtc::RTCError WebRtcVideoChannel::SetRtpSendParameters(
SetPreferredDscp(new_dscp);
}
return it->second->SetRtpParameters(parameters);
return it->second->SetRtpParameters(parameters, std::move(callback));
}
webrtc::RtpParameters WebRtcVideoChannel::GetRtpReceiveParameters(
@ -2156,7 +2159,7 @@ bool WebRtcVideoChannel::WebRtcVideoSendStream::SetVideoSend(
old_options.is_screencast = options->is_screencast;
}
if (parameters_.options != old_options) {
ReconfigureEncoder();
ReconfigureEncoder(nullptr);
}
}
@ -2283,7 +2286,7 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetSendParameters(
}
if (params.max_bandwidth_bps) {
parameters_.max_bitrate_bps = *params.max_bandwidth_bps;
ReconfigureEncoder();
ReconfigureEncoder(nullptr);
}
if (params.conference_mode) {
parameters_.conference_mode = *params.conference_mode;
@ -2305,7 +2308,8 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetSendParameters(
}
webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
const webrtc::RtpParameters& new_parameters) {
const webrtc::RtpParameters& new_parameters,
webrtc::SetParametersCallback callback) {
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
@ -2366,7 +2370,9 @@ webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
// Codecs are currently handled at the WebRtcVideoChannel level.
rtp_parameters_.codecs.clear();
if (reconfigure_encoder || new_send_state) {
ReconfigureEncoder();
// Callback responsibility is delegated to ReconfigureEncoder()
ReconfigureEncoder(std::move(callback));
callback = nullptr;
}
if (new_send_state) {
UpdateSendState();
@ -2376,7 +2382,7 @@ webrtc::RTCError WebRtcVideoChannel::WebRtcVideoSendStream::SetRtpParameters(
stream_->SetSource(source_, GetDegradationPreference());
}
}
return webrtc::RTCError::OK();
return webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
}
webrtc::RtpParameters
@ -2564,11 +2570,13 @@ WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig(
return encoder_config;
}
void WebRtcVideoChannel::WebRtcVideoSendStream::ReconfigureEncoder() {
void WebRtcVideoChannel::WebRtcVideoSendStream::ReconfigureEncoder(
webrtc::SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(&thread_checker_);
if (!stream_) {
// The webrtc::VideoSendStream `stream_` has not yet been created but other
// parameters has changed.
webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
return;
}
@ -2583,7 +2591,7 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::ReconfigureEncoder() {
encoder_config.encoder_specific_settings =
ConfigureVideoEncoderSettings(codec_settings.codec);
stream_->ReconfigureVideoEncoder(encoder_config.Copy());
stream_->ReconfigureVideoEncoder(encoder_config.Copy(), std::move(callback));
encoder_config.encoder_specific_settings = NULL;

View file

@ -149,7 +149,8 @@ class WebRtcVideoChannel : public VideoMediaChannel,
webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const override;
webrtc::RTCError SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) override;
const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback) override;
webrtc::RtpParameters GetRtpReceiveParameters(uint32_t ssrc) const override;
webrtc::RtpParameters GetDefaultRtpReceiveParameters() const override;
bool GetSendCodec(VideoCodec* send_codec) override;
@ -363,7 +364,8 @@ class WebRtcVideoChannel : public VideoMediaChannel,
~WebRtcVideoSendStream();
void SetSendParameters(const ChangedSendParameters& send_params);
webrtc::RTCError SetRtpParameters(const webrtc::RtpParameters& parameters);
webrtc::RTCError SetRtpParameters(const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback);
webrtc::RtpParameters GetRtpParameters() const;
void SetFrameEncryptor(
@ -422,7 +424,7 @@ class WebRtcVideoChannel : public VideoMediaChannel,
void RecreateWebRtcStream();
webrtc::VideoEncoderConfig CreateVideoEncoderConfig(
const VideoCodec& codec) const;
void ReconfigureEncoder();
void ReconfigureEncoder(webrtc::SetParametersCallback callback);
// Calls Start or Stop according to whether or not `sending_` is true,
// and whether or not the encoding in `rtp_parameters_` is active.

View file

@ -5294,10 +5294,10 @@ TEST_F(WebRtcVideoChannelTest, TestSetDscpOptions) {
// Various priorities map to various dscp values.
parameters.encodings[0].network_priority = webrtc::Priority::kHigh;
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrc, parameters).ok());
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrc, parameters, nullptr).ok());
EXPECT_EQ(rtc::DSCP_AF41, network_interface->dscp());
parameters.encodings[0].network_priority = webrtc::Priority::kVeryLow;
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrc, parameters).ok());
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrc, parameters, nullptr).ok());
EXPECT_EQ(rtc::DSCP_CS1, network_interface->dscp());
// Packets should also self-identify their dscp in PacketOptions.

View file

@ -789,19 +789,19 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
void SetSendCodecSpec(
const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec) {
UpdateSendCodecSpec(send_codec_spec);
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
void SetRtpExtensions(const std::vector<webrtc::RtpExtension>& extensions) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
config_.rtp.extensions = extensions;
rtp_parameters_.header_extensions = extensions;
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
void SetExtmapAllowMixed(bool extmap_allow_mixed) {
config_.rtp.extmap_allow_mixed = extmap_allow_mixed;
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
void SetMid(const std::string& mid) {
@ -810,14 +810,14 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
return;
}
config_.rtp.mid = mid;
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
void SetFrameEncryptor(
rtc::scoped_refptr<webrtc::FrameEncryptorInterface> frame_encryptor) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
config_.frame_encryptor = frame_encryptor;
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
void SetAudioNetworkAdaptorConfig(
@ -830,7 +830,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
audio_network_adaptor_config_from_options_ = audio_network_adaptor_config;
UpdateAudioNetworkAdaptorConfig();
UpdateAllowedBitrateRange();
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
bool SetMaxSendBitrate(int bps) {
@ -848,7 +848,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
if (send_rate != config_.send_codec_spec->target_bitrate_bps) {
config_.send_codec_spec->target_bitrate_bps = send_rate;
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
return true;
}
@ -958,11 +958,12 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
return rtp_parameters_;
}
webrtc::RTCError SetRtpParameters(const webrtc::RtpParameters& parameters) {
webrtc::RTCError SetRtpParameters(const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback) {
webrtc::RTCError error = CheckRtpParametersInvalidModificationAndValues(
rtp_parameters_, parameters);
if (!error.ok()) {
return error;
return webrtc::InvokeSetParametersCallback(callback, error);
}
absl::optional<int> send_rate;
@ -971,7 +972,8 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
parameters.encodings[0].max_bitrate_bps,
*audio_codec_spec_);
if (!send_rate) {
return webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR);
return webrtc::InvokeSetParametersCallback(
callback, webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR));
}
}
@ -1001,7 +1003,9 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
// used.
UpdateAudioNetworkAdaptorConfig();
UpdateAllowedBitrateRange();
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(std::move(callback));
} else {
webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
}
rtp_parameters_.rtcp.cname = config_.rtp.c_name;
@ -1016,7 +1020,7 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
config_.frame_transformer = std::move(frame_transformer);
ReconfigureAudioSendStream();
ReconfigureAudioSendStream(nullptr);
}
private:
@ -1106,10 +1110,10 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
audio_network_adaptor_config_from_options_;
}
void ReconfigureAudioSendStream() {
void ReconfigureAudioSendStream(webrtc::SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(&worker_thread_checker_);
RTC_DCHECK(stream_);
stream_->Reconfigure(config_);
stream_->Reconfigure(config_, std::move(callback));
}
int NumPreferredChannels() const override { return num_encoded_channels_; }
@ -1389,14 +1393,16 @@ webrtc::RtpParameters WebRtcVoiceMediaChannel::GetRtpSendParameters(
webrtc::RTCError WebRtcVoiceMediaChannel::SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(worker_thread_);
auto it = send_streams_.find(ssrc);
if (it == send_streams_.end()) {
RTC_LOG(LS_WARNING) << "Attempting to set RTP send parameters for stream "
"with ssrc "
<< ssrc << " which doesn't exist.";
return webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR);
return webrtc::InvokeSetParametersCallback(
callback, webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR));
}
// TODO(deadbeef): Handle setting parameters with a list of codecs in a
@ -1405,7 +1411,8 @@ webrtc::RTCError WebRtcVoiceMediaChannel::SetRtpSendParameters(
if (current_parameters.codecs != parameters.codecs) {
RTC_DLOG(LS_ERROR) << "Using SetParameters to change the set of codecs "
"is not currently supported.";
return webrtc::RTCError(webrtc::RTCErrorType::UNSUPPORTED_PARAMETER);
return webrtc::InvokeSetParametersCallback(
callback, webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR));
}
if (!parameters.encodings.empty()) {
@ -1440,7 +1447,7 @@ webrtc::RTCError WebRtcVoiceMediaChannel::SetRtpSendParameters(
// Codecs are handled at the WebRtcVoiceMediaChannel level.
webrtc::RtpParameters reduced_params = parameters;
reduced_params.codecs.clear();
return it->second->SetRtpParameters(reduced_params);
return it->second->SetRtpParameters(reduced_params, std::move(callback));
}
webrtc::RtpParameters WebRtcVoiceMediaChannel::GetRtpReceiveParameters(

View file

@ -156,7 +156,8 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel,
webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const override;
webrtc::RTCError SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) override;
const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback) override;
webrtc::RtpParameters GetRtpReceiveParameters(uint32_t ssrc) const override;
webrtc::RtpParameters GetDefaultRtpReceiveParameters() const override;

View file

@ -3207,10 +3207,10 @@ TEST_P(WebRtcVoiceEngineTestFake, TestSetDscpOptions) {
// Various priorities map to various dscp values.
parameters.encodings[0].network_priority = webrtc::Priority::kHigh;
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrcZ, parameters).ok());
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrcZ, parameters, nullptr).ok());
EXPECT_EQ(rtc::DSCP_EF, network_interface.dscp());
parameters.encodings[0].network_priority = webrtc::Priority::kVeryLow;
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrcZ, parameters).ok());
ASSERT_TRUE(channel->SetRtpSendParameters(kSsrcZ, parameters, nullptr).ok());
EXPECT_EQ(rtc::DSCP_CS1, network_interface.dscp());
// Packets should also self-identify their dscp in PacketOptions.

View file

@ -415,6 +415,7 @@ rtc_source_set("rtp_sender_proxy") {
deps = [
":proxy",
"../api:libjingle_peerconnection_api",
"../api:rtp_sender_interface",
]
}
@ -1091,6 +1092,7 @@ rtc_source_set("sdp_offer_answer") {
"../api:media_stream_interface",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:rtp_transceiver_direction",
"../api:scoped_refptr",
"../api:sequence_checker",
@ -1181,6 +1183,7 @@ rtc_source_set("peer_connection") {
"../api:rtc_error",
"../api:rtc_stats_api",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:rtp_transceiver_direction",
"../api:scoped_refptr",
"../api:sequence_checker",
@ -1276,6 +1279,7 @@ rtc_source_set("legacy_stats_collector") {
"../api:libjingle_peerconnection_api",
"../api:media_stream_interface",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api:sequence_checker",
"../api/audio_codecs:audio_codecs_api",
@ -1544,6 +1548,7 @@ rtc_library("rtp_transceiver") {
"../api:libjingle_peerconnection_api",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:rtp_transceiver_direction",
"../api:scoped_refptr",
"../api:sequence_checker",
@ -1588,6 +1593,7 @@ rtc_library("rtp_transmission_manager") {
"../api:media_stream_interface",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:rtp_transceiver_direction",
"../api:scoped_refptr",
"../api:sequence_checker",
@ -1618,6 +1624,7 @@ rtc_library("transceiver_list") {
"../api:libjingle_peerconnection_api",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api:sequence_checker",
"../rtc_base:checks",
@ -1853,12 +1860,14 @@ rtc_library("rtp_sender") {
":legacy_stats_collector_interface",
"../api:audio_options_api",
"../api:dtls_transport_interface",
"../api:dtmf_sender_interface",
"../api:frame_transformer_interface",
"../api:libjingle_peerconnection_api",
"../api:media_stream_interface",
"../api:priority",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api:sequence_checker",
"../api/crypto:frame_encryptor_interface",
@ -1912,6 +1921,7 @@ rtc_library("dtmf_sender") {
]
deps = [
":proxy",
"../api:dtmf_sender_interface",
"../api:libjingle_peerconnection_api",
"../api:scoped_refptr",
"../api:sequence_checker",
@ -2179,6 +2189,7 @@ if (rtc_include_tests && !build_with_chromium) {
"../api:rtc_error",
"../api:rtc_stats_api",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../rtc_base:checks",
"../rtc_base:gunit_helpers",
@ -2193,6 +2204,7 @@ if (rtc_include_tests && !build_with_chromium) {
deps = [
":integration_test_helpers",
":pc_test_utils",
"../api:dtmf_sender_interface",
"../api:libjingle_peerconnection_api",
"../api:scoped_refptr",
"../api/units:time_delta",
@ -2314,6 +2326,7 @@ if (rtc_include_tests && !build_with_chromium) {
"../api:candidate",
"../api:create_peerconnection_factory",
"../api:dtls_transport_interface",
"../api:dtmf_sender_interface",
"../api:fake_frame_decryptor",
"../api:fake_frame_encryptor",
"../api:field_trials_view",
@ -2329,6 +2342,7 @@ if (rtc_include_tests && !build_with_chromium) {
"../api:packet_socket_factory",
"../api:priority",
"../api:rtc_error",
"../api:rtp_sender_interface",
"../api:rtp_transceiver_direction",
"../api:scoped_refptr",
"../api/adaptation:resource_adaptation_api",
@ -2523,6 +2537,7 @@ if (rtc_include_tests && !build_with_chromium) {
"../api:rtc_error",
"../api:rtc_stats_api",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:rtp_transceiver_direction",
"../api:scoped_refptr",
"../api/audio:audio_mixer_api",

View file

@ -88,6 +88,46 @@ RtpParameters RestoreEncodingLayers(
return result;
}
class SignalingThreadCallback {
public:
SignalingThreadCallback(rtc::Thread* signaling_thread,
SetParametersCallback callback)
: signaling_thread_(signaling_thread), callback_(std::move(callback)) {}
SignalingThreadCallback(SignalingThreadCallback&& other)
: signaling_thread_(other.signaling_thread_),
callback_(std::move(other.callback_)) {
other.callback_ = nullptr;
}
~SignalingThreadCallback() {
if (callback_) {
Resolve(RTCError(RTCErrorType::INTERNAL_ERROR));
RTC_CHECK_NOTREACHED();
}
}
void operator()(const RTCError& error) { Resolve(error); }
private:
void Resolve(const RTCError& error) {
if (!signaling_thread_->IsCurrent()) {
signaling_thread_->PostTask(
[callback = std::move(callback_), error]() mutable {
webrtc::InvokeSetParametersCallback(callback, error);
});
callback_ = nullptr;
return;
}
webrtc::InvokeSetParametersCallback(callback_, error);
callback_ = nullptr;
}
rtc::Thread* signaling_thread_;
SetParametersCallback callback_;
};
} // namespace
// Returns true if any RtpParameters member that isn't implemented contains a
@ -189,14 +229,20 @@ RtpParameters RtpSenderBase::GetParameters() const {
return result;
}
RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
void RtpSenderBase::SetParametersInternal(const RtpParameters& parameters,
SetParametersCallback callback,
bool blocking) {
RTC_DCHECK_RUN_ON(signaling_thread_);
RTC_DCHECK(!stopped_);
if (UnimplementedRtpParameterHasValue(parameters)) {
LOG_AND_RETURN_ERROR(
RTCError error(
RTCErrorType::UNSUPPORTED_PARAMETER,
"Attempted to set an unimplemented parameter of RtpParameters.");
RTC_LOG(LS_ERROR) << error.message() << " ("
<< ::webrtc::ToString(error.type()) << ")";
webrtc::InvokeSetParametersCallback(callback, error);
return;
}
if (!media_channel_ || !ssrc_) {
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
@ -204,9 +250,11 @@ RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
if (result.ok()) {
init_parameters_ = parameters;
}
return result;
webrtc::InvokeSetParametersCallback(callback, result);
return;
}
return worker_thread_->BlockingCall([&] {
auto task = [&, callback = std::move(callback),
parameters = std::move(parameters)]() mutable {
RtpParameters rtp_parameters = parameters;
RtpParameters old_parameters = media_channel_->GetRtpSendParameters(ssrc_);
if (!disabled_rids_.empty()) {
@ -215,17 +263,26 @@ RTCError RtpSenderBase::SetParametersInternal(const RtpParameters& parameters) {
old_parameters.encodings);
}
auto result = cricket::CheckRtpParametersInvalidModificationAndValues(
RTCError result = cricket::CheckRtpParametersInvalidModificationAndValues(
old_parameters, rtp_parameters);
if (!result.ok())
return result;
if (!result.ok()) {
webrtc::InvokeSetParametersCallback(callback, result);
return;
}
result = CheckSVCParameters(rtp_parameters);
if (!result.ok())
return result;
if (!result.ok()) {
webrtc::InvokeSetParametersCallback(callback, result);
return;
}
return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
});
media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters,
std::move(callback));
};
if (blocking)
worker_thread_->BlockingCall(task);
else
worker_thread_->PostTask(std::move(task));
}
RTCError RtpSenderBase::SetParametersInternalWithAllLayers(
@ -248,13 +305,12 @@ RTCError RtpSenderBase::SetParametersInternalWithAllLayers(
}
return worker_thread_->BlockingCall([&] {
RtpParameters rtp_parameters = parameters;
return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters);
return media_channel_->SetRtpSendParameters(ssrc_, rtp_parameters, nullptr);
});
}
RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
RTCError RtpSenderBase::CheckSetParameters(const RtpParameters& parameters) {
RTC_DCHECK_RUN_ON(signaling_thread_);
TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
if (is_transceiver_stopped_) {
LOG_AND_RETURN_ERROR(
RTCErrorType::INVALID_STATE,
@ -264,10 +320,6 @@ RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
"Cannot set parameters on a stopped sender.");
}
if (stopped_) {
LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_STATE,
"Cannot set parameters on a stopped sender.");
}
if (!last_transaction_id_) {
LOG_AND_RETURN_ERROR(
RTCErrorType::INVALID_STATE,
@ -281,11 +333,55 @@ RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
" the last value returned from getParameters()");
}
RTCError result = SetParametersInternal(parameters);
return RTCError::OK();
}
RTCError RtpSenderBase::SetParameters(const RtpParameters& parameters) {
RTC_DCHECK_RUN_ON(signaling_thread_);
TRACE_EVENT0("webrtc", "RtpSenderBase::SetParameters");
RTCError result = CheckSetParameters(parameters);
if (!result.ok())
return result;
// Some tests rely on working in single thread mode without a run loop and a
// blocking call is required to keep them working. The encoder configuration
// also involves another thread with an asynchronous task, thus we still do
// need to wait for the callback to be resolved this way.
std::unique_ptr<rtc::Event> done_event = std::make_unique<rtc::Event>();
SetParametersInternal(
parameters,
[done = done_event.get(), &result](RTCError error) {
result = error;
done->Set();
},
true);
done_event->Wait(rtc::Event::kForever);
last_transaction_id_.reset();
return result;
}
void RtpSenderBase::SetParametersAsync(const RtpParameters& parameters,
SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(signaling_thread_);
RTC_DCHECK(callback);
TRACE_EVENT0("webrtc", "RtpSenderBase::SetParametersAsync");
RTCError result = CheckSetParameters(parameters);
if (!result.ok()) {
webrtc::InvokeSetParametersCallback(callback, result);
return;
}
SetParametersInternal(
parameters,
SignalingThreadCallback(
signaling_thread_,
[this, callback = std::move(callback)](RTCError error) mutable {
last_transaction_id_.reset();
webrtc::InvokeSetParametersCallback(callback, error);
}),
false);
}
void RtpSenderBase::SetStreams(const std::vector<std::string>& stream_ids) {
set_stream_ids(stream_ids);
if (set_streams_observer_)
@ -372,7 +468,7 @@ void RtpSenderBase::SetSsrc(uint32_t ssrc) {
}
current_parameters.degradation_preference =
init_parameters_.degradation_preference;
media_channel_->SetRtpSendParameters(ssrc_, current_parameters);
media_channel_->SetRtpSendParameters(ssrc_, current_parameters, nullptr);
init_parameters_.encodings.clear();
init_parameters_.degradation_preference = absl::nullopt;
});

View file

@ -73,7 +73,9 @@ class RtpSenderInternal : public RtpSenderInterface {
// `GetParameters` and `SetParameters` operate with a transactional model.
// Allow access to get/set parameters without invalidating transaction id.
virtual RtpParameters GetParametersInternal() const = 0;
virtual RTCError SetParametersInternal(const RtpParameters& parameters) = 0;
virtual void SetParametersInternal(const RtpParameters& parameters,
SetParametersCallback,
bool blocking) = 0;
// GetParameters and SetParameters will remove deactivated simulcast layers
// and restore them on SetParameters. This is probably a Bad Idea, but we
@ -130,11 +132,16 @@ class RtpSenderBase : public RtpSenderInternal, public ObserverInterface {
RtpParameters GetParameters() const override;
RTCError SetParameters(const RtpParameters& parameters) override;
void SetParametersAsync(const RtpParameters& parameters,
SetParametersCallback callback) override;
// `GetParameters` and `SetParameters` operate with a transactional model.
// Allow access to get/set parameters without invalidating transaction id.
RtpParameters GetParametersInternal() const override;
RTCError SetParametersInternal(const RtpParameters& parameters) override;
void SetParametersInternal(const RtpParameters& parameters,
SetParametersCallback callback = nullptr,
bool blocking = true) override;
RTCError CheckSetParameters(const RtpParameters& parameters);
RtpParameters GetParametersInternalWithAllLayers() const override;
RTCError SetParametersInternalWithAllLayers(
const RtpParameters& parameters) override;

View file

@ -35,6 +35,10 @@ PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids)
PROXY_CONSTMETHOD0(std::vector<RtpEncodingParameters>, init_send_encodings)
PROXY_CONSTMETHOD0(RtpParameters, GetParameters)
PROXY_METHOD1(RTCError, SetParameters, const RtpParameters&)
PROXY_METHOD2(void,
SetParametersAsync,
const RtpParameters&,
SetParametersCallback)
PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender)
PROXY_METHOD1(void,
SetFrameEncryptor,

View file

@ -855,6 +855,20 @@ TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParameters) {
DestroyAudioRtpSender();
}
TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersAsync) {
CreateAudioRtpSender();
RtpParameters params = audio_rtp_sender_->GetParameters();
EXPECT_EQ(1u, params.encodings.size());
absl::optional<webrtc::RTCError> result;
audio_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
DestroyAudioRtpSender();
}
TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersBeforeNegotiation) {
audio_rtp_sender_ =
AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr, nullptr);
@ -865,8 +879,34 @@ TEST_F(RtpSenderReceiverTest, AudioSenderCanSetParametersBeforeNegotiation) {
EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok());
params = audio_rtp_sender_->GetParameters();
EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok());
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000);
EXPECT_TRUE(audio_rtp_sender_->SetParameters(params).ok());
DestroyAudioRtpSender();
}
TEST_F(RtpSenderReceiverTest,
AudioSenderCanSetParametersAsyncBeforeNegotiation) {
audio_rtp_sender_ =
AudioRtpSender::Create(worker_thread_, /*id=*/"", nullptr, nullptr);
absl::optional<webrtc::RTCError> result;
RtpParameters params = audio_rtp_sender_->GetParameters();
ASSERT_EQ(1u, params.encodings.size());
params.encodings[0].max_bitrate_bps = 90000;
audio_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
params = audio_rtp_sender_->GetParameters();
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000);
audio_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
DestroyAudioRtpSender();
}
@ -941,6 +981,25 @@ TEST_F(RtpSenderReceiverTest,
DestroyAudioRtpSender();
}
TEST_F(RtpSenderReceiverTest,
AudioSenderSetParametersAsyncInvalidatesTransactionId) {
CreateAudioRtpSender();
RtpParameters params = audio_rtp_sender_->GetParameters();
EXPECT_EQ(1u, params.encodings.size());
absl::optional<webrtc::RTCError> result;
audio_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
audio_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_EQ(RTCErrorType::INVALID_STATE, result->type());
DestroyAudioRtpSender();
}
TEST_F(RtpSenderReceiverTest, AudioSenderDetectTransactionIdModification) {
CreateAudioRtpSender();
@ -1047,6 +1106,20 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParameters) {
DestroyVideoRtpSender();
}
TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersAsync) {
CreateVideoRtpSender();
RtpParameters params = video_rtp_sender_->GetParameters();
EXPECT_EQ(1u, params.encodings.size());
absl::optional<webrtc::RTCError> result;
video_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
DestroyVideoRtpSender();
}
TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) {
video_rtp_sender_ =
VideoRtpSender::Create(worker_thread_, /*id=*/"", nullptr);
@ -1063,6 +1136,30 @@ TEST_F(RtpSenderReceiverTest, VideoSenderCanSetParametersBeforeNegotiation) {
DestroyVideoRtpSender();
}
TEST_F(RtpSenderReceiverTest,
VideoSenderCanSetParametersAsyncBeforeNegotiation) {
video_rtp_sender_ =
VideoRtpSender::Create(worker_thread_, /*id=*/"", nullptr);
absl::optional<webrtc::RTCError> result;
RtpParameters params = video_rtp_sender_->GetParameters();
ASSERT_EQ(1u, params.encodings.size());
params.encodings[0].max_bitrate_bps = 90000;
video_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
params = video_rtp_sender_->GetParameters();
EXPECT_EQ(params.encodings[0].max_bitrate_bps, 90000);
video_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
DestroyVideoRtpSender();
}
TEST_F(RtpSenderReceiverTest, VideoSenderInitParametersMovedAfterNegotiation) {
AddVideoTrack(false);
@ -1215,6 +1312,25 @@ TEST_F(RtpSenderReceiverTest,
DestroyVideoRtpSender();
}
TEST_F(RtpSenderReceiverTest,
VideoSenderSetParametersAsyncInvalidatesTransactionId) {
CreateVideoRtpSender();
RtpParameters params = video_rtp_sender_->GetParameters();
EXPECT_EQ(1u, params.encodings.size());
absl::optional<webrtc::RTCError> result;
video_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_TRUE(result->ok());
video_rtp_sender_->SetParametersAsync(
params, [&result](webrtc::RTCError error) { result = error; });
run_loop_.Flush();
EXPECT_EQ(RTCErrorType::INVALID_STATE, result->type());
DestroyVideoRtpSender();
}
TEST_F(RtpSenderReceiverTest, VideoSenderDetectTransactionIdModification) {
CreateVideoRtpSender();
@ -1745,9 +1861,9 @@ TEST_F(RtpSenderReceiverTest,
RtpParameters parameters = video_rtp_sender_->GetParameters();
RtpParameters new_parameters = video_rtp_sender_->GetParametersInternal();
new_parameters.encodings[0].active = false;
video_rtp_sender_->SetParametersInternal(new_parameters);
video_rtp_sender_->SetParametersInternal(new_parameters, nullptr, true);
new_parameters.encodings[0].active = true;
video_rtp_sender_->SetParametersInternal(new_parameters);
video_rtp_sender_->SetParametersInternal(new_parameters, nullptr, true);
parameters.encodings[0].active = false;
EXPECT_TRUE(video_rtp_sender_->SetParameters(parameters).ok());
}

View file

@ -52,9 +52,13 @@ class MockRtpSenderInternal : public RtpSenderInternal {
(),
(const, override));
MOCK_METHOD(RTCError, SetParameters, (const RtpParameters&), (override));
MOCK_METHOD(RTCError,
MOCK_METHOD(void,
SetParametersAsync,
(const RtpParameters&, SetParametersCallback),
(override));
MOCK_METHOD(void,
SetParametersInternal,
(const RtpParameters&),
(const RtpParameters&, SetParametersCallback, bool blocking),
(override));
MOCK_METHOD(RTCError,
SetParametersInternalWithAllLayers,

View file

@ -71,7 +71,9 @@ class MockVoiceMediaChannel : public VoiceMediaChannel {
(const, override));
MOCK_METHOD(webrtc::RTCError,
SetRtpSendParameters,
(uint32_t ssrc, const webrtc::RtpParameters& parameters),
(uint32_t ssrc,
const webrtc::RtpParameters& parameters,
webrtc::SetParametersCallback callback),
(override));
MOCK_METHOD(
void,

View file

@ -1062,11 +1062,13 @@ if (is_ios || is_mac) {
":videorendereradapter_objc",
":videosource_objc",
":videotoolbox_objc",
"../api:dtmf_sender_interface",
"../api:libjingle_peerconnection_api",
"../api:media_stream_interface",
"../api:rtc_event_log_output_file",
"../api:rtc_stats_api",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api/audio_codecs:audio_codecs_api",
"../api/audio_codecs:builtin_audio_decoder_factory",

View file

@ -765,10 +765,12 @@ if (current_os == "linux" || is_android) {
":native_api_stacktrace",
"..:media_constraints",
"../../api:callfactory_api",
"../../api:dtmf_sender_interface",
"../../api:libjingle_peerconnection_api",
"../../api:media_stream_interface",
"../../api:rtc_event_log_output_file",
"../../api:rtp_parameters",
"../../api:rtp_sender_interface",
"../../api:turn_customizer",
"../../api/crypto:options",
"../../api/rtc_event_log:rtc_event_log_factory",

View file

@ -15,7 +15,9 @@ rtc_library("video_stream_encoder_interface") {
]
deps = [
"../api:fec_controller_api",
"../api:rtc_error",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:scoped_refptr",
"../api/adaptation:resource_adaptation_api",
"../api/units:data_rate",
@ -407,6 +409,7 @@ rtc_library("video_stream_encoder_impl") {
":video_stream_encoder_interface",
"../api:field_trials_view",
"../api:rtp_parameters",
"../api:rtp_sender_interface",
"../api:sequence_checker",
"../api/adaptation:resource_adaptation_api",
"../api/task_queue:pending_task_safety_flag",
@ -426,6 +429,7 @@ rtc_library("video_stream_encoder_impl") {
"../api/video_codecs:video_codecs_api",
"../call/adaptation:resource_adaptation",
"../common_video",
"../media:rtc_media_base",
"../modules:module_api_public",
"../modules/video_coding",
"../modules/video_coding:video_codec_interface",
@ -469,6 +473,7 @@ rtc_library("video_stream_encoder_impl") {
"//third_party/abseil-cpp/absl/algorithm:container",
"//third_party/abseil-cpp/absl/base:core_headers",
"//third_party/abseil-cpp/absl/cleanup",
"//third_party/abseil-cpp/absl/container:inlined_vector",
"//third_party/abseil-cpp/absl/types:optional",
]
}

View file

@ -55,12 +55,20 @@ class MockVideoStreamEncoder : public VideoStreamEncoderInterface {
MOCK_METHOD(void,
MockedConfigureEncoder,
(const VideoEncoderConfig&, size_t));
MOCK_METHOD(void,
MockedConfigureEncoder,
(const VideoEncoderConfig&, size_t, SetParametersCallback));
// gtest generates implicit copy which is not allowed on VideoEncoderConfig,
// so we can't mock ConfigureEncoder directly.
void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length) {
MockedConfigureEncoder(config, max_data_payload_length);
}
void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length,
SetParametersCallback) {
MockedConfigureEncoder(config, max_data_payload_length);
}
};
} // namespace webrtc

View file

@ -301,11 +301,17 @@ void VideoSendStream::SetSource(
}
void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config) {
ReconfigureVideoEncoder(std::move(config), nullptr);
}
void VideoSendStream::ReconfigureVideoEncoder(VideoEncoderConfig config,
SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(&thread_checker_);
RTC_DCHECK_EQ(content_type_, config.content_type);
video_stream_encoder_->ConfigureEncoder(
std::move(config),
config_.rtp.max_packet_size - CalculateMaxHeaderSize(config_.rtp));
config_.rtp.max_packet_size - CalculateMaxHeaderSize(config_.rtp),
std::move(callback));
}
VideoSendStream::Stats VideoSendStream::GetStats() {

View file

@ -89,7 +89,9 @@ class VideoSendStream : public webrtc::VideoSendStream {
void SetSource(rtc::VideoSourceInterface<webrtc::VideoFrame>* source,
const DegradationPreference& degradation_preference) override;
void ReconfigureVideoEncoder(VideoEncoderConfig) override;
void ReconfigureVideoEncoder(VideoEncoderConfig config) override;
void ReconfigureVideoEncoder(VideoEncoderConfig config,
SetParametersCallback callback) override;
Stats GetStats() override;
void StopPermanentlyAndGetRtpStates(RtpStateMap* rtp_state_map,

View file

@ -35,6 +35,7 @@
#include "call/adaptation/resource_adaptation_processor.h"
#include "call/adaptation/video_source_restrictions.h"
#include "call/adaptation/video_stream_adapter.h"
#include "media/base/media_channel.h"
#include "modules/video_coding/include/video_codec_initializer.h"
#include "modules/video_coding/svc/svc_rate_allocator.h"
#include "modules/video_coding/utility/vp8_constants.h"
@ -879,9 +880,16 @@ void VideoStreamEncoder::SetStartBitrate(int start_bitrate_bps) {
void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length) {
ConfigureEncoder(std::move(config), max_data_payload_length, nullptr);
}
void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length,
SetParametersCallback callback) {
RTC_DCHECK_RUN_ON(worker_queue_);
encoder_queue_.PostTask(
[this, config = std::move(config), max_data_payload_length]() mutable {
[this, config = std::move(config), max_data_payload_length,
callback = std::move(callback)]() mutable {
RTC_DCHECK_RUN_ON(&encoder_queue_);
RTC_DCHECK(sink_);
RTC_LOG(LS_INFO) << "ConfigureEncoder requested.";
@ -912,7 +920,13 @@ void VideoStreamEncoder::ConfigureEncoder(VideoEncoderConfig config,
// minimize the number of reconfigurations. The codec configuration
// depends on incoming video frame size.
if (last_frame_info_) {
if (callback) {
encoder_configuration_callbacks_.push_back(std::move(callback));
}
ReconfigureEncoder();
} else {
webrtc::InvokeSetParametersCallback(callback, webrtc::RTCError::OK());
}
});
}
@ -1369,6 +1383,8 @@ void VideoStreamEncoder::ReconfigureEncoder() {
stream_resource_manager_.ConfigureQualityScaler(info);
stream_resource_manager_.ConfigureBandwidthQualityScaler(info);
webrtc::RTCError encoder_configuration_result = webrtc::RTCError::OK();
if (!encoder_initialized_) {
RTC_LOG(LS_WARNING) << "Failed to initialize "
<< CodecTypeToPayloadString(codec.codecType)
@ -1378,8 +1394,19 @@ void VideoStreamEncoder::ReconfigureEncoder() {
if (switch_encoder_on_init_failures_) {
RequestEncoderSwitch();
} else {
encoder_configuration_result =
webrtc::RTCError(RTCErrorType::UNSUPPORTED_OPERATION);
}
}
if (!encoder_configuration_callbacks_.empty()) {
for (auto& callback : encoder_configuration_callbacks_) {
webrtc::InvokeSetParametersCallback(callback,
encoder_configuration_result);
}
encoder_configuration_callbacks_.clear();
}
}
void VideoStreamEncoder::RequestEncoderSwitch() {

View file

@ -17,8 +17,10 @@
#include <string>
#include <vector>
#include "absl/container/inlined_vector.h"
#include "api/adaptation/resource.h"
#include "api/field_trials_view.h"
#include "api/rtp_sender_interface.h"
#include "api/sequence_checker.h"
#include "api/task_queue/pending_task_safety_flag.h"
#include "api/units/data_rate.h"
@ -106,6 +108,9 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length) override;
void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length,
SetParametersCallback callback) override;
// Permanently stop encoding. After this method has returned, it is
// guaranteed that no encoded frames will be delivered to the sink.
@ -302,6 +307,8 @@ class VideoStreamEncoder : public VideoStreamEncoderInterface,
// Set when configuration must create a new encoder object, e.g.,
// because of a codec change.
bool pending_encoder_creation_ RTC_GUARDED_BY(&encoder_queue_);
absl::InlinedVector<SetParametersCallback, 2> encoder_configuration_callbacks_
RTC_GUARDED_BY(&encoder_queue_);
absl::optional<VideoFrameInfo> last_frame_info_
RTC_GUARDED_BY(&encoder_queue_);

View file

@ -15,7 +15,9 @@
#include "api/adaptation/resource.h"
#include "api/fec_controller_override.h"
#include "api/rtc_error.h"
#include "api/rtp_parameters.h" // For DegradationPreference.
#include "api/rtp_sender_interface.h"
#include "api/scoped_refptr.h"
#include "api/units/data_rate.h"
#include "api/video/video_bitrate_allocator.h"
@ -131,6 +133,9 @@ class VideoStreamEncoderInterface {
// packetization for H.264.
virtual void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length) = 0;
virtual void ConfigureEncoder(VideoEncoderConfig config,
size_t max_data_payload_length,
SetParametersCallback callback) = 0;
// Permanently stop encoding. After this method has returned, it is
// guaranteed that no encoded frames will be delivered to the sink.

View file

@ -885,7 +885,7 @@ class VideoStreamEncoderTest : public ::testing::Test {
&video_source_, webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
video_stream_encoder_->SetStartBitrate(kTargetBitrate.bps());
video_stream_encoder_->ConfigureEncoder(std::move(video_encoder_config),
kMaxPayloadLength);
kMaxPayloadLength, nullptr);
video_stream_encoder_->WaitUntilTaskQueueIsIdle();
}