Don't create channel_manager when media_engine is not set

Also remove a bunch of functions in ChannelManager that were just
forwarding to MediaEngineInterface.

Bug: webrtc:13931
Change-Id: Ia38591fd22c665cace16d032f5c1e384e413cded
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/261304
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36801}
This commit is contained in:
Harald Alvestrand 2022-05-06 15:15:34 +00:00 committed by WebRTC LUCI CQ
parent 3387a7fdb8
commit c48ad732d6
18 changed files with 446 additions and 378 deletions

View File

@ -377,6 +377,7 @@ rtc_source_set("media_session") {
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:logging", "../rtc_base:logging",
"../rtc_base:stringutils", "../rtc_base:stringutils",
"../rtc_base/memory:always_valid_pointer",
"../rtc_base/third_party/base64", "../rtc_base/third_party/base64",
] ]
absl_deps = [ absl_deps = [

View File

@ -31,6 +31,7 @@ std::unique_ptr<ChannelManager> ChannelManager::Create(
bool enable_rtx, bool enable_rtx,
rtc::Thread* worker_thread, rtc::Thread* worker_thread,
rtc::Thread* network_thread) { rtc::Thread* network_thread) {
RTC_CHECK(media_engine);
RTC_DCHECK(network_thread); RTC_DCHECK(network_thread);
RTC_DCHECK(worker_thread); RTC_DCHECK(worker_thread);
@ -51,12 +52,11 @@ ChannelManager::ChannelManager(
RTC_DCHECK_RUN_ON(signaling_thread_); RTC_DCHECK_RUN_ON(signaling_thread_);
RTC_DCHECK(worker_thread_); RTC_DCHECK(worker_thread_);
RTC_DCHECK(network_thread_); RTC_DCHECK(network_thread_);
RTC_CHECK(media_engine_);
if (media_engine_) { // TODO(tommi): Change VoiceEngine to do ctor time initialization so that
// TODO(tommi): Change VoiceEngine to do ctor time initialization so that // this isn't necessary.
// this isn't necessary. worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] { media_engine_->Init(); });
worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] { media_engine_->Init(); });
}
} }
ChannelManager::~ChannelManager() { ChannelManager::~ChannelManager() {
@ -71,27 +71,8 @@ ChannelManager::~ChannelManager() {
}); });
} }
void ChannelManager::GetSupportedAudioSendCodecs(
std::vector<AudioCodec>* codecs) const {
if (!media_engine_) {
return;
}
*codecs = media_engine_->voice().send_codecs();
}
void ChannelManager::GetSupportedAudioReceiveCodecs(
std::vector<AudioCodec>* codecs) const {
if (!media_engine_) {
return;
}
*codecs = media_engine_->voice().recv_codecs();
}
void ChannelManager::GetSupportedVideoSendCodecs( void ChannelManager::GetSupportedVideoSendCodecs(
std::vector<VideoCodec>* codecs) const { std::vector<VideoCodec>* codecs) const {
if (!media_engine_) {
return;
}
codecs->clear(); codecs->clear();
std::vector<VideoCodec> video_codecs = media_engine_->video().send_codecs(); std::vector<VideoCodec> video_codecs = media_engine_->video().send_codecs();
@ -106,9 +87,6 @@ void ChannelManager::GetSupportedVideoSendCodecs(
void ChannelManager::GetSupportedVideoReceiveCodecs( void ChannelManager::GetSupportedVideoReceiveCodecs(
std::vector<VideoCodec>* codecs) const { std::vector<VideoCodec>* codecs) const {
if (!media_engine_) {
return;
}
codecs->clear(); codecs->clear();
std::vector<VideoCodec> video_codecs = media_engine_->video().recv_codecs(); std::vector<VideoCodec> video_codecs = media_engine_->video().recv_codecs();
@ -123,32 +101,14 @@ void ChannelManager::GetSupportedVideoReceiveCodecs(
RtpHeaderExtensions ChannelManager::GetDefaultEnabledAudioRtpHeaderExtensions() RtpHeaderExtensions ChannelManager::GetDefaultEnabledAudioRtpHeaderExtensions()
const { const {
if (!media_engine_)
return {};
return GetDefaultEnabledRtpHeaderExtensions(media_engine_->voice()); return GetDefaultEnabledRtpHeaderExtensions(media_engine_->voice());
} }
std::vector<webrtc::RtpHeaderExtensionCapability>
ChannelManager::GetSupportedAudioRtpHeaderExtensions() const {
if (!media_engine_)
return {};
return media_engine_->voice().GetRtpHeaderExtensions();
}
RtpHeaderExtensions ChannelManager::GetDefaultEnabledVideoRtpHeaderExtensions() RtpHeaderExtensions ChannelManager::GetDefaultEnabledVideoRtpHeaderExtensions()
const { const {
if (!media_engine_)
return {};
return GetDefaultEnabledRtpHeaderExtensions(media_engine_->video()); return GetDefaultEnabledRtpHeaderExtensions(media_engine_->video());
} }
std::vector<webrtc::RtpHeaderExtensionCapability>
ChannelManager::GetSupportedVideoRtpHeaderExtensions() const {
if (!media_engine_)
return {};
return media_engine_->video().GetRtpHeaderExtensions();
}
std::unique_ptr<VoiceChannel> ChannelManager::CreateVoiceChannel( std::unique_ptr<VoiceChannel> ChannelManager::CreateVoiceChannel(
webrtc::Call* call, webrtc::Call* call,
const MediaConfig& media_config, const MediaConfig& media_config,

View File

@ -47,7 +47,7 @@ namespace cricket {
class ChannelManager : public ChannelFactoryInterface { class ChannelManager : public ChannelFactoryInterface {
public: public:
// Returns an initialized instance of ChannelManager. // Returns an initialized instance of ChannelManager.
// If media_engine is non-nullptr, then the returned ChannelManager instance // `media_engine` cannot be null. The returned ChannelManager instance
// will own that reference and media engine initialization // will own that reference and media engine initialization
static std::unique_ptr<ChannelManager> Create( static std::unique_ptr<ChannelManager> Create(
std::unique_ptr<MediaEngineInterface> media_engine, std::unique_ptr<MediaEngineInterface> media_engine,
@ -63,18 +63,11 @@ class ChannelManager : public ChannelFactoryInterface {
MediaEngineInterface* media_engine() { return media_engine_.get(); } MediaEngineInterface* media_engine() { return media_engine_.get(); }
rtc::UniqueRandomIdGenerator& ssrc_generator() { return ssrc_generator_; } rtc::UniqueRandomIdGenerator& ssrc_generator() { return ssrc_generator_; }
// Retrieves the list of supported audio & video codec types. // Retrieves the list of supported video codec types.
// Can be called before starting the media engine.
void GetSupportedAudioSendCodecs(std::vector<AudioCodec>* codecs) const;
void GetSupportedAudioReceiveCodecs(std::vector<AudioCodec>* codecs) const;
void GetSupportedVideoSendCodecs(std::vector<VideoCodec>* codecs) const; void GetSupportedVideoSendCodecs(std::vector<VideoCodec>* codecs) const;
void GetSupportedVideoReceiveCodecs(std::vector<VideoCodec>* codecs) const; void GetSupportedVideoReceiveCodecs(std::vector<VideoCodec>* codecs) const;
RtpHeaderExtensions GetDefaultEnabledAudioRtpHeaderExtensions() const; RtpHeaderExtensions GetDefaultEnabledAudioRtpHeaderExtensions() const;
std::vector<webrtc::RtpHeaderExtensionCapability>
GetSupportedAudioRtpHeaderExtensions() const;
RtpHeaderExtensions GetDefaultEnabledVideoRtpHeaderExtensions() const; RtpHeaderExtensions GetDefaultEnabledVideoRtpHeaderExtensions() const;
std::vector<webrtc::RtpHeaderExtensionCapability>
GetSupportedVideoRtpHeaderExtensions() const;
// The operations below all occur on the worker thread. // The operations below all occur on the worker thread.
// The caller is responsible for ensuring that destruction happens // The caller is responsible for ensuring that destruction happens
@ -123,7 +116,7 @@ class ChannelManager : public ChannelFactoryInterface {
void DestroyVideoChannel(VideoChannel* video_channel); void DestroyVideoChannel(VideoChannel* video_channel);
private: private:
const std::unique_ptr<MediaEngineInterface> media_engine_; // Nullable. const std::unique_ptr<MediaEngineInterface> media_engine_;
rtc::Thread* const signaling_thread_; rtc::Thread* const signaling_thread_;
rtc::Thread* const worker_thread_; rtc::Thread* const worker_thread_;
rtc::Thread* const network_thread_; rtc::Thread* const network_thread_;

View File

@ -144,9 +144,11 @@ ConnectionContext::ConnectionContext(
default_socket_factory_ = default_socket_factory_ =
std::make_unique<rtc::BasicPacketSocketFactory>(socket_factory); std::make_unique<rtc::BasicPacketSocketFactory>(socket_factory);
channel_manager_ = cricket::ChannelManager::Create( if (dependencies->media_engine) {
std::move(dependencies->media_engine), channel_manager_ = cricket::ChannelManager::Create(
/*enable_rtx=*/true, worker_thread(), network_thread()); std::move(dependencies->media_engine),
/*enable_rtx=*/true, worker_thread(), network_thread());
}
// Set warning levels on the threads, to give warnings when response // Set warning levels on the threads, to give warnings when response
// may be slower than is expected of the thread. // may be slower than is expected of the thread.

View File

@ -1557,21 +1557,22 @@ MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
const TransportDescriptionFactory* transport_desc_factory, const TransportDescriptionFactory* transport_desc_factory,
rtc::UniqueRandomIdGenerator* ssrc_generator) rtc::UniqueRandomIdGenerator* ssrc_generator)
: ssrc_generator_(ssrc_generator), : ssrc_generator_(ssrc_generator),
transport_desc_factory_(transport_desc_factory) { transport_desc_factory_(transport_desc_factory) {}
RTC_DCHECK(ssrc_generator_);
}
MediaSessionDescriptionFactory::MediaSessionDescriptionFactory( MediaSessionDescriptionFactory::MediaSessionDescriptionFactory(
ChannelManager* channel_manager, ChannelManager* channel_manager,
const TransportDescriptionFactory* transport_desc_factory) const TransportDescriptionFactory* transport_desc_factory)
: MediaSessionDescriptionFactory(transport_desc_factory, : MediaSessionDescriptionFactory(
&channel_manager->ssrc_generator()) { transport_desc_factory,
channel_manager->GetSupportedAudioSendCodecs(&audio_send_codecs_); channel_manager ? &channel_manager->ssrc_generator() : nullptr) {
channel_manager->GetSupportedAudioReceiveCodecs(&audio_recv_codecs_); if (channel_manager) {
channel_manager->GetSupportedVideoSendCodecs(&video_send_codecs_); audio_send_codecs_ = channel_manager->media_engine()->voice().send_codecs();
channel_manager->GetSupportedVideoReceiveCodecs(&video_recv_codecs_); audio_recv_codecs_ = channel_manager->media_engine()->voice().recv_codecs();
ComputeAudioCodecsIntersectionAndUnion(); channel_manager->GetSupportedVideoSendCodecs(&video_send_codecs_);
ComputeVideoCodecsIntersectionAndUnion(); channel_manager->GetSupportedVideoReceiveCodecs(&video_recv_codecs_);
ComputeAudioCodecsIntersectionAndUnion();
ComputeVideoCodecsIntersectionAndUnion();
}
} }
const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs() const AudioCodecs& MediaSessionDescriptionFactory::audio_sendrecv_codecs()
@ -2354,7 +2355,7 @@ bool MediaSessionDescriptionFactory::AddAudioContentForOffer(
if (!CreateMediaContentOffer( if (!CreateMediaContentOffer(
media_description_options, session_options, filtered_codecs, media_description_options, session_options, filtered_codecs,
sdes_policy, GetCryptos(current_content), crypto_suites, sdes_policy, GetCryptos(current_content), crypto_suites,
audio_rtp_extensions, ssrc_generator_, current_streams, audio.get(), audio_rtp_extensions, ssrc_generator(), current_streams, audio.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials())) {
return false; return false;
} }
@ -2466,7 +2467,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForOffer(
if (!CreateMediaContentOffer( if (!CreateMediaContentOffer(
media_description_options, session_options, filtered_codecs, media_description_options, session_options, filtered_codecs,
sdes_policy, GetCryptos(current_content), crypto_suites, sdes_policy, GetCryptos(current_content), crypto_suites,
video_rtp_extensions, ssrc_generator_, current_streams, video.get(), video_rtp_extensions, ssrc_generator(), current_streams, video.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials())) {
return false; return false;
} }
@ -2519,8 +2520,8 @@ bool MediaSessionDescriptionFactory::AddDataContentForOffer(
if (!CreateContentOffer(media_description_options, session_options, if (!CreateContentOffer(media_description_options, session_options,
sdes_policy, GetCryptos(current_content), sdes_policy, GetCryptos(current_content),
crypto_suites, RtpHeaderExtensions(), ssrc_generator_, crypto_suites, RtpHeaderExtensions(),
current_streams, data.get())) { ssrc_generator(), current_streams, data.get())) {
return false; return false;
} }
@ -2654,7 +2655,7 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
audio_transport->secure() ? cricket::SEC_DISABLED : secure(); audio_transport->secure() ? cricket::SEC_DISABLED : secure();
if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs, if (!SetCodecsInAnswer(offer_audio_description, filtered_codecs,
media_description_options, session_options, media_description_options, session_options,
ssrc_generator_, current_streams, audio_answer.get(), ssrc_generator(), current_streams, audio_answer.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials())) {
return false; return false;
} }
@ -2662,7 +2663,7 @@ bool MediaSessionDescriptionFactory::AddAudioContentForAnswer(
offer_audio_description, media_description_options, session_options, offer_audio_description, media_description_options, session_options,
sdes_policy, GetCryptos(current_content), sdes_policy, GetCryptos(current_content),
filtered_rtp_header_extensions(default_audio_rtp_header_extensions), filtered_rtp_header_extensions(default_audio_rtp_header_extensions),
ssrc_generator_, enable_encrypted_rtp_header_extensions_, ssrc_generator(), enable_encrypted_rtp_header_extensions_,
current_streams, bundle_enabled, audio_answer.get())) { current_streams, bundle_enabled, audio_answer.get())) {
return false; // Fails the session setup. return false; // Fails the session setup.
} }
@ -2783,7 +2784,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
video_transport->secure() ? cricket::SEC_DISABLED : secure(); video_transport->secure() ? cricket::SEC_DISABLED : secure();
if (!SetCodecsInAnswer(offer_video_description, filtered_codecs, if (!SetCodecsInAnswer(offer_video_description, filtered_codecs,
media_description_options, session_options, media_description_options, session_options,
ssrc_generator_, current_streams, video_answer.get(), ssrc_generator(), current_streams, video_answer.get(),
transport_desc_factory_->trials())) { transport_desc_factory_->trials())) {
return false; return false;
} }
@ -2791,7 +2792,7 @@ bool MediaSessionDescriptionFactory::AddVideoContentForAnswer(
offer_video_description, media_description_options, session_options, offer_video_description, media_description_options, session_options,
sdes_policy, GetCryptos(current_content), sdes_policy, GetCryptos(current_content),
filtered_rtp_header_extensions(default_video_rtp_header_extensions), filtered_rtp_header_extensions(default_video_rtp_header_extensions),
ssrc_generator_, enable_encrypted_rtp_header_extensions_, ssrc_generator(), enable_encrypted_rtp_header_extensions_,
current_streams, bundle_enabled, video_answer.get())) { current_streams, bundle_enabled, video_answer.get())) {
return false; // Failed the sessin setup. return false; // Failed the sessin setup.
} }
@ -2864,7 +2865,7 @@ bool MediaSessionDescriptionFactory::AddDataContentForAnswer(
if (!CreateMediaContentAnswer( if (!CreateMediaContentAnswer(
offer_data_description, media_description_options, session_options, offer_data_description, media_description_options, session_options,
sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(), sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
ssrc_generator_, enable_encrypted_rtp_header_extensions_, ssrc_generator(), enable_encrypted_rtp_header_extensions_,
current_streams, bundle_enabled, data_answer.get())) { current_streams, bundle_enabled, data_answer.get())) {
return false; // Fails the session setup. return false; // Fails the session setup.
} }

View File

@ -34,6 +34,7 @@
#include "pc/media_protocol_names.h" #include "pc/media_protocol_names.h"
#include "pc/session_description.h" #include "pc/session_description.h"
#include "pc/simulcast_description.h" #include "pc/simulcast_description.h"
#include "rtc_base/memory/always_valid_pointer.h"
#include "rtc_base/unique_id_generator.h" #include "rtc_base/unique_id_generator.h"
namespace webrtc { namespace webrtc {
@ -328,6 +329,10 @@ class MediaSessionDescriptionFactory {
void ComputeVideoCodecsIntersectionAndUnion(); void ComputeVideoCodecsIntersectionAndUnion();
rtc::UniqueRandomIdGenerator* ssrc_generator() const {
return ssrc_generator_.get();
}
bool is_unified_plan_ = false; bool is_unified_plan_ = false;
AudioCodecs audio_send_codecs_; AudioCodecs audio_send_codecs_;
AudioCodecs audio_recv_codecs_; AudioCodecs audio_recv_codecs_;
@ -341,8 +346,9 @@ class MediaSessionDescriptionFactory {
VideoCodecs video_sendrecv_codecs_; VideoCodecs video_sendrecv_codecs_;
// Union of send and recv. // Union of send and recv.
VideoCodecs all_video_codecs_; VideoCodecs all_video_codecs_;
// This object is not owned by the channel so it must outlive it. // This object may or may not be owned by this class.
rtc::UniqueRandomIdGenerator* const ssrc_generator_; webrtc::AlwaysValidPointer<rtc::UniqueRandomIdGenerator> const
ssrc_generator_;
bool enable_encrypted_rtp_header_extensions_ = false; bool enable_encrypted_rtp_header_extensions_ = false;
// TODO(zhihuang): Rename secure_ to sdec_policy_; rename the related getter // TODO(zhihuang): Rename secure_ to sdec_policy_; rename the related getter
// and setter. // and setter.

View File

@ -646,25 +646,27 @@ RTCError PeerConnection::Initialize(
sdp_handler_ = SdpOfferAnswerHandler::Create(this, configuration, sdp_handler_ = SdpOfferAnswerHandler::Create(this, configuration,
dependencies, context_.get()); dependencies, context_.get());
rtp_manager_ = std::make_unique<RtpTransmissionManager>( if (ConfiguredForMedia()) {
IsUnifiedPlan(), signaling_thread(), worker_thread(), channel_manager(), rtp_manager_ = std::make_unique<RtpTransmissionManager>(
&usage_pattern_, observer_, stats_.get(), [this]() { IsUnifiedPlan(), signaling_thread(), worker_thread(), channel_manager(),
RTC_DCHECK_RUN_ON(signaling_thread()); &usage_pattern_, observer_, stats_.get(), [this]() {
sdp_handler_->UpdateNegotiationNeeded(); RTC_DCHECK_RUN_ON(signaling_thread());
}); sdp_handler_->UpdateNegotiationNeeded();
});
// Add default audio/video transceivers for Plan B SDP. // Add default audio/video transceivers for Plan B SDP.
if (!IsUnifiedPlan()) { if (!IsUnifiedPlan()) {
rtp_manager()->transceivers()->Add( rtp_manager()->transceivers()->Add(
RtpTransceiverProxyWithInternal<RtpTransceiver>::Create( RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
signaling_thread(), signaling_thread(),
rtc::make_ref_counted<RtpTransceiver>(cricket::MEDIA_TYPE_AUDIO, rtc::make_ref_counted<RtpTransceiver>(cricket::MEDIA_TYPE_AUDIO,
channel_manager()))); channel_manager())));
rtp_manager()->transceivers()->Add( rtp_manager()->transceivers()->Add(
RtpTransceiverProxyWithInternal<RtpTransceiver>::Create( RtpTransceiverProxyWithInternal<RtpTransceiver>::Create(
signaling_thread(), signaling_thread(),
rtc::make_ref_counted<RtpTransceiver>(cricket::MEDIA_TYPE_VIDEO, rtc::make_ref_counted<RtpTransceiver>(cricket::MEDIA_TYPE_VIDEO,
channel_manager()))); channel_manager())));
}
} }
int delay_ms = configuration.report_usage_pattern_delay_ms int delay_ms = configuration.report_usage_pattern_delay_ms
@ -1178,8 +1180,10 @@ std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
const { const {
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
std::vector<rtc::scoped_refptr<RtpSenderInterface>> ret; std::vector<rtc::scoped_refptr<RtpSenderInterface>> ret;
for (const auto& sender : rtp_manager()->GetSendersInternal()) { if (ConfiguredForMedia()) {
ret.push_back(sender); for (const auto& sender : rtp_manager()->GetSendersInternal()) {
ret.push_back(sender);
}
} }
return ret; return ret;
} }
@ -1188,8 +1192,10 @@ std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
PeerConnection::GetReceivers() const { PeerConnection::GetReceivers() const {
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> ret; std::vector<rtc::scoped_refptr<RtpReceiverInterface>> ret;
for (const auto& receiver : rtp_manager()->GetReceiversInternal()) { if (ConfiguredForMedia()) {
ret.push_back(receiver); for (const auto& receiver : rtp_manager()->GetReceiversInternal()) {
ret.push_back(receiver);
}
} }
return ret; return ret;
} }
@ -1200,8 +1206,10 @@ PeerConnection::GetTransceivers() const {
RTC_CHECK(IsUnifiedPlan()) RTC_CHECK(IsUnifiedPlan())
<< "GetTransceivers is only supported with Unified Plan SdpSemantics."; << "GetTransceivers is only supported with Unified Plan SdpSemantics.";
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> all_transceivers; std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> all_transceivers;
for (const auto& transceiver : rtp_manager()->transceivers()->List()) { if (ConfiguredForMedia()) {
all_transceivers.push_back(transceiver); for (const auto& transceiver : rtp_manager()->transceivers()->List()) {
all_transceivers.push_back(transceiver);
}
} }
return all_transceivers; return all_transceivers;
} }
@ -1680,8 +1688,7 @@ void PeerConnection::SetAudioPlayout(bool playout) {
RTC_FROM_HERE, [this, playout] { SetAudioPlayout(playout); }); RTC_FROM_HERE, [this, playout] { SetAudioPlayout(playout); });
return; return;
} }
auto audio_state = auto audio_state = media_engine()->voice().GetAudioState();
context_->channel_manager()->media_engine()->voice().GetAudioState();
audio_state->SetPlayout(playout); audio_state->SetPlayout(playout);
} }
@ -1691,8 +1698,7 @@ void PeerConnection::SetAudioRecording(bool recording) {
RTC_FROM_HERE, [this, recording] { SetAudioRecording(recording); }); RTC_FROM_HERE, [this, recording] { SetAudioRecording(recording); });
return; return;
} }
auto audio_state = auto audio_state = media_engine()->voice().GetAudioState();
context_->channel_manager()->media_engine()->voice().GetAudioState();
audio_state->SetRecording(recording); audio_state->SetRecording(recording);
} }
@ -1712,7 +1718,7 @@ void PeerConnection::AddAdaptationResource(
} }
bool PeerConnection::ConfiguredForMedia() const { bool PeerConnection::ConfiguredForMedia() const {
return context_->channel_manager()->media_engine(); return context_->channel_manager();
} }
bool PeerConnection::StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output, bool PeerConnection::StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output,
@ -1822,12 +1828,13 @@ void PeerConnection::Close() {
NoteUsageEvent(UsageEvent::CLOSE_CALLED); NoteUsageEvent(UsageEvent::CLOSE_CALLED);
for (const auto& transceiver : rtp_manager()->transceivers()->List()) { if (ConfiguredForMedia()) {
transceiver->internal()->SetPeerConnectionClosed(); for (const auto& transceiver : rtp_manager()->transceivers()->List()) {
if (!transceiver->stopped()) transceiver->internal()->SetPeerConnectionClosed();
transceiver->StopInternal(); if (!transceiver->stopped())
transceiver->StopInternal();
}
} }
// Ensure that all asynchronous stats requests are completed before destroying // Ensure that all asynchronous stats requests are completed before destroying
// the transport controller below. // the transport controller below.
if (stats_collector_) { if (stats_collector_) {
@ -1844,7 +1851,9 @@ void PeerConnection::Close() {
// WebRTC session description factory, the session description factory would // WebRTC session description factory, the session description factory would
// call the transport controller. // call the transport controller.
sdp_handler_->ResetSessionDescFactory(); sdp_handler_->ResetSessionDescFactory();
rtp_manager_->Close(); if (ConfiguredForMedia()) {
rtp_manager_->Close();
}
network_thread()->Invoke<void>(RTC_FROM_HERE, [this] { network_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
// Data channels will already have been unset via the DestroyAllChannels() // Data channels will already have been unset via the DestroyAllChannels()
@ -2735,12 +2744,15 @@ void PeerConnection::ReportTransportStats() {
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls; rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
std::map<std::string, std::set<cricket::MediaType>> std::map<std::string, std::set<cricket::MediaType>>
media_types_by_transport_name; media_types_by_transport_name;
for (const auto& transceiver : rtp_manager()->transceivers()->UnsafeList()) { if (ConfiguredForMedia()) {
if (transceiver->internal()->channel()) { for (const auto& transceiver :
std::string transport_name( rtp_manager()->transceivers()->UnsafeList()) {
transceiver->internal()->channel()->transport_name()); if (transceiver->internal()->channel()) {
media_types_by_transport_name[transport_name].insert( std::string transport_name(
transceiver->media_type()); transceiver->internal()->channel()->transport_name());
media_types_by_transport_name[transport_name].insert(
transceiver->media_type());
}
} }
} }
@ -2888,10 +2900,13 @@ bool PeerConnection::OnTransportChanged(
DataChannelTransportInterface* data_channel_transport) { DataChannelTransportInterface* data_channel_transport) {
RTC_DCHECK_RUN_ON(network_thread()); RTC_DCHECK_RUN_ON(network_thread());
bool ret = true; bool ret = true;
for (const auto& transceiver : rtp_manager()->transceivers()->UnsafeList()) { if (ConfiguredForMedia()) {
cricket::ChannelInterface* channel = transceiver->internal()->channel(); for (const auto& transceiver :
if (channel && channel->mid() == mid) { rtp_manager()->transceivers()->UnsafeList()) {
ret = channel->SetRtpTransport(rtp_transport); cricket::ChannelInterface* channel = transceiver->internal()->channel();
if (channel && channel->mid() == mid) {
ret = channel->SetRtpTransport(rtp_transport);
}
} }
} }
@ -2976,4 +2991,10 @@ PeerConnection::InitializeRtcpCallback() {
}; };
} }
cricket::MediaEngineInterface* PeerConnection::media_engine() {
RTC_DCHECK(context_);
RTC_DCHECK(context_->channel_manager());
return context_->channel_manager()->media_engine();
}
} // namespace webrtc } // namespace webrtc

View File

@ -273,6 +273,9 @@ class PeerConnection : public PeerConnectionInternal,
rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>> rtc::scoped_refptr<RtpTransceiverProxyWithInternal<RtpTransceiver>>>
GetTransceiversInternal() const override { GetTransceiversInternal() const override {
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
if (!ConfiguredForMedia()) {
return {};
}
return rtp_manager()->transceivers()->List(); return rtp_manager()->transceivers()->List();
} }
@ -596,6 +599,7 @@ class PeerConnection : public PeerConnectionInternal,
cricket::ChannelManager* channel_manager() { cricket::ChannelManager* channel_manager() {
return context_->channel_manager(); return context_->channel_manager();
} }
cricket::MediaEngineInterface* media_engine();
const rtc::scoped_refptr<ConnectionContext> context_; const rtc::scoped_refptr<ConnectionContext> context_;
// Field trials active for this PeerConnection is the first of: // Field trials active for this PeerConnection is the first of:

View File

@ -129,14 +129,14 @@ RtpCapabilities PeerConnectionFactory::GetRtpSenderCapabilities(
switch (kind) { switch (kind) {
case cricket::MEDIA_TYPE_AUDIO: { case cricket::MEDIA_TYPE_AUDIO: {
cricket::AudioCodecs cricket_codecs; cricket::AudioCodecs cricket_codecs;
channel_manager()->GetSupportedAudioSendCodecs(&cricket_codecs); cricket_codecs = media_engine()->voice().send_codecs();
return ToRtpCapabilities( return ToRtpCapabilities(
cricket_codecs, cricket_codecs,
channel_manager()->GetDefaultEnabledAudioRtpHeaderExtensions()); channel_manager()->GetDefaultEnabledAudioRtpHeaderExtensions());
} }
case cricket::MEDIA_TYPE_VIDEO: { case cricket::MEDIA_TYPE_VIDEO: {
cricket::VideoCodecs cricket_codecs; cricket::VideoCodecs cricket_codecs;
channel_manager()->GetSupportedVideoSendCodecs(&cricket_codecs); cricket_codecs = media_engine()->video().send_codecs();
return ToRtpCapabilities( return ToRtpCapabilities(
cricket_codecs, cricket_codecs,
channel_manager()->GetDefaultEnabledVideoRtpHeaderExtensions()); channel_manager()->GetDefaultEnabledVideoRtpHeaderExtensions());
@ -156,7 +156,7 @@ RtpCapabilities PeerConnectionFactory::GetRtpReceiverCapabilities(
switch (kind) { switch (kind) {
case cricket::MEDIA_TYPE_AUDIO: { case cricket::MEDIA_TYPE_AUDIO: {
cricket::AudioCodecs cricket_codecs; cricket::AudioCodecs cricket_codecs;
channel_manager()->GetSupportedAudioReceiveCodecs(&cricket_codecs); cricket_codecs = media_engine()->voice().recv_codecs();
return ToRtpCapabilities( return ToRtpCapabilities(
cricket_codecs, cricket_codecs,
channel_manager()->GetDefaultEnabledAudioRtpHeaderExtensions()); channel_manager()->GetDefaultEnabledAudioRtpHeaderExtensions());
@ -195,6 +195,12 @@ void PeerConnectionFactory::StopAecDump() {
channel_manager()->StopAecDump(); channel_manager()->StopAecDump();
} }
cricket::MediaEngineInterface* PeerConnectionFactory::media_engine() const {
RTC_DCHECK(context_);
RTC_DCHECK(context_->channel_manager());
return context_->channel_manager()->media_engine();
}
RTCErrorOr<rtc::scoped_refptr<PeerConnectionInterface>> RTCErrorOr<rtc::scoped_refptr<PeerConnectionInterface>>
PeerConnectionFactory::CreatePeerConnectionOrError( PeerConnectionFactory::CreatePeerConnectionOrError(
const PeerConnectionInterface::RTCConfiguration& configuration, const PeerConnectionInterface::RTCConfiguration& configuration,
@ -312,7 +318,7 @@ std::unique_ptr<Call> PeerConnectionFactory::CreateCall_w(
RTC_DCHECK_RUN_ON(worker_thread()); RTC_DCHECK_RUN_ON(worker_thread());
webrtc::Call::Config call_config(event_log, network_thread()); webrtc::Call::Config call_config(event_log, network_thread());
if (!channel_manager()->media_engine() || !context_->call_factory()) { if (!channel_manager() || !context_->call_factory()) {
return nullptr; return nullptr;
} }
call_config.audio_state = call_config.audio_state =

View File

@ -120,6 +120,8 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface {
return context_->field_trials(); return context_->field_trials();
} }
cricket::MediaEngineInterface* media_engine() const;
protected: protected:
// Constructor used by the static Create() method. Modifies the dependencies. // Constructor used by the static Create() method. Modifies the dependencies.
PeerConnectionFactory(rtc::scoped_refptr<ConnectionContext> context, PeerConnectionFactory(rtc::scoped_refptr<ConnectionContext> context,

View File

@ -22,6 +22,7 @@
#include "api/sequence_checker.h" #include "api/sequence_checker.h"
#include "media/base/codec.h" #include "media/base/codec.h"
#include "media/base/media_constants.h" #include "media/base/media_constants.h"
#include "media/base/media_engine.h"
#include "pc/channel.h" #include "pc/channel.h"
#include "pc/channel_manager.h" #include "pc/channel_manager.h"
#include "pc/rtp_media_utils.h" #include "pc/rtp_media_utils.h"
@ -562,7 +563,6 @@ void RtpTransceiver::StopTransceiverProcedure() {
RTCError RtpTransceiver::SetCodecPreferences( RTCError RtpTransceiver::SetCodecPreferences(
rtc::ArrayView<RtpCodecCapability> codec_capabilities) { rtc::ArrayView<RtpCodecCapability> codec_capabilities) {
RTC_DCHECK(unified_plan_); RTC_DCHECK(unified_plan_);
// 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot // 3. If codecs is an empty list, set transceiver's [[PreferredCodecs]] slot
// to codecs and abort these steps. // to codecs and abort these steps.
if (codec_capabilities.empty()) { if (codec_capabilities.empty()) {
@ -581,15 +581,14 @@ RTCError RtpTransceiver::SetCodecPreferences(
RTCError result; RTCError result;
if (media_type_ == cricket::MEDIA_TYPE_AUDIO) { if (media_type_ == cricket::MEDIA_TYPE_AUDIO) {
std::vector<cricket::AudioCodec> recv_codecs, send_codecs; std::vector<cricket::AudioCodec> recv_codecs, send_codecs;
channel_manager_->GetSupportedAudioReceiveCodecs(&recv_codecs); recv_codecs = media_engine()->voice().recv_codecs();
channel_manager_->GetSupportedAudioSendCodecs(&send_codecs); send_codecs = media_engine()->voice().send_codecs();
result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs); result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
} else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) { } else if (media_type_ == cricket::MEDIA_TYPE_VIDEO) {
std::vector<cricket::VideoCodec> recv_codecs, send_codecs; std::vector<cricket::VideoCodec> recv_codecs, send_codecs;
channel_manager_->GetSupportedVideoReceiveCodecs(&recv_codecs); channel_manager_->GetSupportedVideoReceiveCodecs(&recv_codecs);
channel_manager_->GetSupportedVideoSendCodecs(&send_codecs); channel_manager_->GetSupportedVideoSendCodecs(&send_codecs);
result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs); result = VerifyCodecPreferences(codecs, send_codecs, recv_codecs);
} }
@ -672,4 +671,8 @@ void RtpTransceiver::SetPeerConnectionClosed() {
is_pc_closed_ = true; is_pc_closed_ = true;
} }
cricket::MediaEngineInterface* RtpTransceiver::media_engine() const {
return channel_manager_->media_engine();
}
} // namespace webrtc } // namespace webrtc

View File

@ -47,6 +47,7 @@
namespace cricket { namespace cricket {
class ChannelManager; class ChannelManager;
class MediaEngineInterface;
} }
namespace webrtc { namespace webrtc {
@ -338,6 +339,7 @@ class RtpTransceiver : public RtpTransceiverInterface,
RTC_GUARDED_BY(thread_); RTC_GUARDED_BY(thread_);
const std::function<void()> on_negotiation_needed_; const std::function<void()> on_negotiation_needed_;
cricket::MediaEngineInterface* media_engine() const;
}; };
BEGIN_PRIMARY_PROXY_MAP(RtpTransceiver) BEGIN_PRIMARY_PROXY_MAP(RtpTransceiver)

View File

@ -126,7 +126,7 @@ class RtpTransceiverUnifiedPlanTest : public ::testing::Test {
rtc::Thread::Current(), rtc::Thread::Current(),
receiver_), receiver_),
&channel_manager_, &channel_manager_,
channel_manager_.GetSupportedAudioRtpHeaderExtensions(), channel_manager_.media_engine()->voice().GetRtpHeaderExtensions(),
/* on_negotiation_needed= */ [] {})) {} /* on_negotiation_needed= */ [] {})) {}
static rtc::scoped_refptr<MockRtpReceiverInternal> MockReceiver() { static rtc::scoped_refptr<MockRtpReceiverInternal> MockReceiver() {

View File

@ -273,8 +273,8 @@ RtpTransmissionManager::CreateAndAddTransceiver(
rtc::make_ref_counted<RtpTransceiver>( rtc::make_ref_counted<RtpTransceiver>(
sender, receiver, channel_manager(), sender, receiver, channel_manager(),
sender->media_type() == cricket::MEDIA_TYPE_AUDIO sender->media_type() == cricket::MEDIA_TYPE_AUDIO
? channel_manager()->GetSupportedAudioRtpHeaderExtensions() ? media_engine()->voice().GetRtpHeaderExtensions()
: channel_manager()->GetSupportedVideoRtpHeaderExtensions(), : media_engine()->video().GetRtpHeaderExtensions(),
[this_weak_ptr = weak_ptr_factory_.GetWeakPtr()]() { [this_weak_ptr = weak_ptr_factory_.GetWeakPtr()]() {
if (this_weak_ptr) { if (this_weak_ptr) {
this_weak_ptr->OnNegotiationNeeded(); this_weak_ptr->OnNegotiationNeeded();
@ -690,4 +690,8 @@ RtpTransmissionManager::FindReceiverById(const std::string& receiver_id) const {
return nullptr; return nullptr;
} }
cricket::MediaEngineInterface* RtpTransmissionManager::media_engine() const {
return channel_manager()->media_engine();
}
} // namespace webrtc } // namespace webrtc

View File

@ -244,6 +244,8 @@ class RtpTransmissionManager : public RtpSenderBase::SetStreamsObserver {
PeerConnectionObserver* Observer() const; PeerConnectionObserver* Observer() const;
void OnNegotiationNeeded(); void OnNegotiationNeeded();
cricket::MediaEngineInterface* media_engine() const;
TransceiverList transceivers_; TransceiverList transceivers_;
// These lists store sender info seen in local/remote descriptions. // These lists store sender info seen in local/remote descriptions.

View File

@ -1258,10 +1258,17 @@ void SdpOfferAnswerHandler::Initialize(
} }
// ================================================================== // ==================================================================
// Access to pc_ variables // Access to pc_ and context_ variables
cricket::ChannelManager* SdpOfferAnswerHandler::channel_manager() const { cricket::ChannelManager* SdpOfferAnswerHandler::channel_manager() const {
return context_->channel_manager(); return context_->channel_manager();
} }
cricket::MediaEngineInterface* SdpOfferAnswerHandler::media_engine() const {
RTC_DCHECK(context_);
RTC_DCHECK(context_->channel_manager());
return context_->channel_manager()->media_engine();
}
TransceiverList* SdpOfferAnswerHandler::transceivers() { TransceiverList* SdpOfferAnswerHandler::transceivers() {
if (!pc_->rtp_manager()) { if (!pc_->rtp_manager()) {
return nullptr; return nullptr;
@ -1557,56 +1564,60 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
<< ")"; << ")";
return error; return error;
} }
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list; if (ConfiguredForMedia()) {
std::vector<rtc::scoped_refptr<MediaStreamInterface>> removed_streams; std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list;
for (const auto& transceiver_ext : transceivers()->List()) { std::vector<rtc::scoped_refptr<MediaStreamInterface>> removed_streams;
auto transceiver = transceiver_ext->internal(); for (const auto& transceiver_ext : transceivers()->List()) {
if (transceiver->stopped()) { auto transceiver = transceiver_ext->internal();
continue; if (transceiver->stopped()) {
} continue;
}
// 2.2.7.1.1.(6-9): Set sender and receiver's transport slots.
// Note that code paths that don't set MID won't be able to use // 2.2.7.1.1.(6-9): Set sender and receiver's transport slots.
// information about DTLS transports. // Note that code paths that don't set MID won't be able to use
if (transceiver->mid()) { // information about DTLS transports.
auto dtls_transport = LookupDtlsTransportByMid( if (transceiver->mid()) {
context_->network_thread(), transport_controller_s(), auto dtls_transport = LookupDtlsTransportByMid(
*transceiver->mid()); context_->network_thread(), transport_controller_s(),
transceiver->sender_internal()->set_transport(dtls_transport); *transceiver->mid());
transceiver->receiver_internal()->set_transport(dtls_transport); transceiver->sender_internal()->set_transport(dtls_transport);
} transceiver->receiver_internal()->set_transport(dtls_transport);
}
const ContentInfo* content =
FindMediaSectionForTransceiver(transceiver, local_description()); const ContentInfo* content =
if (!content) { FindMediaSectionForTransceiver(transceiver, local_description());
continue; if (!content) {
} continue;
const MediaContentDescription* media_desc = content->media_description(); }
// 2.2.7.1.6: If description is of type "answer" or "pranswer", then run const MediaContentDescription* media_desc =
// the following steps: content->media_description();
if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) { // 2.2.7.1.6: If description is of type "answer" or "pranswer", then run
// 2.2.7.1.6.1: If direction is "sendonly" or "inactive", and // the following steps:
// transceiver's [[FiredDirection]] slot is either "sendrecv" or if (type == SdpType::kPrAnswer || type == SdpType::kAnswer) {
// "recvonly", process the removal of a remote track for the media // 2.2.7.1.6.1: If direction is "sendonly" or "inactive", and
// description, given transceiver, removeList, and muteTracks. // transceiver's [[FiredDirection]] slot is either "sendrecv" or
if (!RtpTransceiverDirectionHasRecv(media_desc->direction()) && // "recvonly", process the removal of a remote track for the media
(transceiver->fired_direction() && // description, given transceiver, removeList, and muteTracks.
RtpTransceiverDirectionHasRecv(*transceiver->fired_direction()))) { if (!RtpTransceiverDirectionHasRecv(media_desc->direction()) &&
ProcessRemovalOfRemoteTrack(transceiver_ext, &remove_list, (transceiver->fired_direction() &&
&removed_streams); RtpTransceiverDirectionHasRecv(
*transceiver->fired_direction()))) {
ProcessRemovalOfRemoteTrack(transceiver_ext, &remove_list,
&removed_streams);
}
// 2.2.7.1.6.2: Set transceiver's [[CurrentDirection]] and
// [[FiredDirection]] slots to direction.
transceiver->set_current_direction(media_desc->direction());
transceiver->set_fired_direction(media_desc->direction());
} }
// 2.2.7.1.6.2: Set transceiver's [[CurrentDirection]] and
// [[FiredDirection]] slots to direction.
transceiver->set_current_direction(media_desc->direction());
transceiver->set_fired_direction(media_desc->direction());
} }
} auto observer = pc_->Observer();
auto observer = pc_->Observer(); for (const auto& transceiver : remove_list) {
for (const auto& transceiver : remove_list) { observer->OnRemoveTrack(transceiver->receiver());
observer->OnRemoveTrack(transceiver->receiver()); }
} for (const auto& stream : removed_streams) {
for (const auto& stream : removed_streams) { observer->OnRemoveStream(stream);
observer->OnRemoveStream(stream); }
} }
} else { } else {
// Media channels will be created only when offer is set. These may use new // Media channels will be created only when offer is set. These may use new
@ -1650,35 +1661,39 @@ RTCError SdpOfferAnswerHandler::ApplyLocalDescription(
} }
if (IsUnifiedPlan()) { if (IsUnifiedPlan()) {
// We must use List and not ListInternal here because if (ConfiguredForMedia()) {
// transceivers()->StableState() is indexed by the non-internal refptr. // We must use List and not ListInternal here because
for (const auto& transceiver_ext : transceivers()->List()) { // transceivers()->StableState() is indexed by the non-internal refptr.
auto transceiver = transceiver_ext->internal(); for (const auto& transceiver_ext : transceivers()->List()) {
if (transceiver->stopped()) { auto transceiver = transceiver_ext->internal();
continue; if (transceiver->stopped()) {
} continue;
const ContentInfo* content = }
FindMediaSectionForTransceiver(transceiver, local_description()); const ContentInfo* content =
if (!content) { FindMediaSectionForTransceiver(transceiver, local_description());
continue; if (!content) {
} continue;
cricket::ChannelInterface* channel = transceiver->channel(); }
if (content->rejected || !channel || channel->local_streams().empty()) { cricket::ChannelInterface* channel = transceiver->channel();
// 0 is a special value meaning "this sender has no associated send if (content->rejected || !channel || channel->local_streams().empty()) {
// stream". Need to call this so the sender won't attempt to configure // 0 is a special value meaning "this sender has no associated send
// a no longer existing stream and run into DCHECKs in the lower // stream". Need to call this so the sender won't attempt to configure
// layers. // a no longer existing stream and run into DCHECKs in the lower
transceiver->sender_internal()->SetSsrc(0); // layers.
} else { transceiver->sender_internal()->SetSsrc(0);
// Get the StreamParams from the channel which could generate SSRCs. } else {
const std::vector<StreamParams>& streams = channel->local_streams(); // Get the StreamParams from the channel which could generate SSRCs.
transceiver->sender_internal()->set_stream_ids(streams[0].stream_ids()); const std::vector<StreamParams>& streams = channel->local_streams();
auto encodings = transceiver->sender_internal()->init_send_encodings(); transceiver->sender_internal()->set_stream_ids(
transceiver->sender_internal()->SetSsrc(streams[0].first_ssrc()); streams[0].stream_ids());
if (!encodings.empty()) { auto encodings =
transceivers() transceiver->sender_internal()->init_send_encodings();
->StableState(transceiver_ext) transceiver->sender_internal()->SetSsrc(streams[0].first_ssrc());
->SetInitSendEncodings(encodings); if (!encodings.empty()) {
transceivers()
->StableState(transceiver_ext)
->SetInitSendEncodings(encodings);
}
} }
} }
} }
@ -1938,6 +1953,9 @@ void SdpOfferAnswerHandler::ApplyRemoteDescriptionUpdateTransceiverState(
SdpType sdp_type) { SdpType sdp_type) {
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(IsUnifiedPlan()); RTC_DCHECK(IsUnifiedPlan());
if (!ConfiguredForMedia()) {
return;
}
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
now_receiving_transceivers; now_receiving_transceivers;
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list; std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> remove_list;
@ -2725,7 +2743,9 @@ RTCError SdpOfferAnswerHandler::UpdateSessionState(
} else { } else {
RTC_DCHECK(type == SdpType::kAnswer); RTC_DCHECK(type == SdpType::kAnswer);
ChangeSignalingState(PeerConnectionInterface::kStable); ChangeSignalingState(PeerConnectionInterface::kStable);
transceivers()->DiscardStableStates(); if (ConfiguredForMedia()) {
transceivers()->DiscardStableStates();
}
} }
// Update internal objects according to the session description's media // Update internal objects according to the session description's media
@ -3151,6 +3171,9 @@ bool SdpOfferAnswerHandler::CheckIfNegotiationIsNeeded() {
if (!cricket::GetFirstDataContent(description->description()->contents())) if (!cricket::GetFirstDataContent(description->description()->contents()))
return true; return true;
} }
if (!ConfiguredForMedia()) {
return false;
}
// 5. For each transceiver in connection's set of transceivers, perform the // 5. For each transceiver in connection's set of transceivers, perform the
// following checks: // following checks:
@ -3262,7 +3285,6 @@ bool SdpOfferAnswerHandler::CheckIfNegotiationIsNeeded() {
} }
} }
} }
// If all the preceding checks were performed and true was not returned, // If all the preceding checks were performed and true was not returned,
// nothing remains to be negotiated; return false. // nothing remains to be negotiated; return false.
return false; return false;
@ -3841,38 +3863,43 @@ void SdpOfferAnswerHandler::GetOptionsForOffer(
void SdpOfferAnswerHandler::GetOptionsForPlanBOffer( void SdpOfferAnswerHandler::GetOptionsForPlanBOffer(
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options, const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
cricket::MediaSessionOptions* session_options) { cricket::MediaSessionOptions* session_options) {
// Figure out transceiver directional preferences. bool offer_new_data_description =
bool send_audio = data_channel_controller()->HasDataChannels();
!rtp_manager()->GetAudioTransceiver()->internal()->senders().empty(); bool send_audio = false;
bool send_video = bool send_video = false;
!rtp_manager()->GetVideoTransceiver()->internal()->senders().empty(); bool recv_audio = false;
bool recv_video = false;
// By default, generate sendrecv/recvonly m= sections. if (ConfiguredForMedia()) {
bool recv_audio = true; // Figure out transceiver directional preferences.
bool recv_video = true; send_audio =
!rtp_manager()->GetAudioTransceiver()->internal()->senders().empty();
send_video =
!rtp_manager()->GetVideoTransceiver()->internal()->senders().empty();
// By default, generate sendrecv/recvonly m= sections.
recv_audio = true;
recv_video = true;
}
// By default, only offer a new m= section if we have media to send with it. // By default, only offer a new m= section if we have media to send with it.
bool offer_new_audio_description = send_audio; bool offer_new_audio_description = send_audio;
bool offer_new_video_description = send_video; bool offer_new_video_description = send_video;
bool offer_new_data_description = if (ConfiguredForMedia()) {
data_channel_controller()->HasDataChannels(); // The "offer_to_receive_X" options allow those defaults to be overridden.
if (offer_answer_options.offer_to_receive_audio !=
// The "offer_to_receive_X" options allow those defaults to be overridden. PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) {
if (offer_answer_options.offer_to_receive_audio != recv_audio = (offer_answer_options.offer_to_receive_audio > 0);
PeerConnectionInterface::RTCOfferAnswerOptions::kUndefined) { offer_new_audio_description =
recv_audio = (offer_answer_options.offer_to_receive_audio > 0); offer_new_audio_description ||
offer_new_audio_description = (offer_answer_options.offer_to_receive_audio > 0);
offer_new_audio_description || }
(offer_answer_options.offer_to_receive_audio > 0); if (offer_answer_options.offer_to_receive_video !=
RTCOfferAnswerOptions::kUndefined) {
recv_video = (offer_answer_options.offer_to_receive_video > 0);
offer_new_video_description =
offer_new_video_description ||
(offer_answer_options.offer_to_receive_video > 0);
}
} }
if (offer_answer_options.offer_to_receive_video !=
RTCOfferAnswerOptions::kUndefined) {
recv_video = (offer_answer_options.offer_to_receive_video > 0);
offer_new_video_description =
offer_new_video_description ||
(offer_answer_options.offer_to_receive_video > 0);
}
absl::optional<size_t> audio_index; absl::optional<size_t> audio_index;
absl::optional<size_t> video_index; absl::optional<size_t> video_index;
absl::optional<size_t> data_index; absl::optional<size_t> data_index;
@ -3887,42 +3914,44 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBOffer(
&audio_index, &video_index, &data_index, session_options); &audio_index, &video_index, &data_index, session_options);
} }
// Add audio/video/data m= sections to the end if needed. if (ConfiguredForMedia()) {
if (!audio_index && offer_new_audio_description) { // Add audio/video/data m= sections to the end if needed.
cricket::MediaDescriptionOptions options( if (!audio_index && offer_new_audio_description) {
cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO, cricket::MediaDescriptionOptions options(
RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio), false); cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
options.header_extensions = RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio), false);
channel_manager()->GetSupportedAudioRtpHeaderExtensions(); options.header_extensions =
session_options->media_description_options.push_back(options); media_engine()->voice().GetRtpHeaderExtensions();
audio_index = session_options->media_description_options.size() - 1; session_options->media_description_options.push_back(options);
} audio_index = session_options->media_description_options.size() - 1;
if (!video_index && offer_new_video_description) { }
cricket::MediaDescriptionOptions options( if (!video_index && offer_new_video_description) {
cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO, cricket::MediaDescriptionOptions options(
RtpTransceiverDirectionFromSendRecv(send_video, recv_video), false); cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
options.header_extensions = RtpTransceiverDirectionFromSendRecv(send_video, recv_video), false);
channel_manager()->GetSupportedVideoRtpHeaderExtensions(); options.header_extensions =
session_options->media_description_options.push_back(options); media_engine()->video().GetRtpHeaderExtensions();
video_index = session_options->media_description_options.size() - 1; session_options->media_description_options.push_back(options);
video_index = session_options->media_description_options.size() - 1;
}
cricket::MediaDescriptionOptions* audio_media_description_options =
!audio_index
? nullptr
: &session_options->media_description_options[*audio_index];
cricket::MediaDescriptionOptions* video_media_description_options =
!video_index
? nullptr
: &session_options->media_description_options[*video_index];
AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(),
audio_media_description_options,
video_media_description_options,
offer_answer_options.num_simulcast_layers);
} }
if (!data_index && offer_new_data_description) { if (!data_index && offer_new_data_description) {
session_options->media_description_options.push_back( session_options->media_description_options.push_back(
GetMediaDescriptionOptionsForActiveData(cricket::CN_DATA)); GetMediaDescriptionOptionsForActiveData(cricket::CN_DATA));
data_index = session_options->media_description_options.size() - 1;
} }
cricket::MediaDescriptionOptions* audio_media_description_options =
!audio_index ? nullptr
: &session_options->media_description_options[*audio_index];
cricket::MediaDescriptionOptions* video_media_description_options =
!video_index ? nullptr
: &session_options->media_description_options[*video_index];
AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(),
audio_media_description_options,
video_media_description_options,
offer_answer_options.num_simulcast_layers);
} }
void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer( void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer(
@ -4028,27 +4057,29 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer(
// and not associated). Reuse media sections marked as recyclable first, // and not associated). Reuse media sections marked as recyclable first,
// otherwise append to the end of the offer. New media sections should be // otherwise append to the end of the offer. New media sections should be
// added in the order they were added to the PeerConnection. // added in the order they were added to the PeerConnection.
for (const auto& transceiver : transceivers()->ListInternal()) { if (ConfiguredForMedia()) {
if (transceiver->mid() || transceiver->stopping()) { for (const auto& transceiver : transceivers()->ListInternal()) {
continue; if (transceiver->mid() || transceiver->stopping()) {
continue;
}
size_t mline_index;
if (!recycleable_mline_indices.empty()) {
mline_index = recycleable_mline_indices.front();
recycleable_mline_indices.pop();
session_options->media_description_options[mline_index] =
GetMediaDescriptionOptionsForTransceiver(
transceiver, mid_generator_.GenerateString(),
/*is_create_offer=*/true);
} else {
mline_index = session_options->media_description_options.size();
session_options->media_description_options.push_back(
GetMediaDescriptionOptionsForTransceiver(
transceiver, mid_generator_.GenerateString(),
/*is_create_offer=*/true));
}
// See comment above for why CreateOffer changes the transceiver's state.
transceiver->set_mline_index(mline_index);
} }
size_t mline_index;
if (!recycleable_mline_indices.empty()) {
mline_index = recycleable_mline_indices.front();
recycleable_mline_indices.pop();
session_options->media_description_options[mline_index] =
GetMediaDescriptionOptionsForTransceiver(
transceiver, mid_generator_.GenerateString(),
/*is_create_offer=*/true);
} else {
mline_index = session_options->media_description_options.size();
session_options->media_description_options.push_back(
GetMediaDescriptionOptionsForTransceiver(
transceiver, mid_generator_.GenerateString(),
/*is_create_offer=*/true));
}
// See comment above for why CreateOffer changes the transceiver's state.
transceiver->set_mline_index(mline_index);
} }
// Lastly, add a m-section if we have local data channels and an m section // Lastly, add a m-section if we have local data channels and an m section
// does not already exist. // does not already exist.
@ -4088,25 +4119,32 @@ void SdpOfferAnswerHandler::GetOptionsForAnswer(
void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer( void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer(
const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options, const PeerConnectionInterface::RTCOfferAnswerOptions& offer_answer_options,
cricket::MediaSessionOptions* session_options) { cricket::MediaSessionOptions* session_options) {
// Figure out transceiver directional preferences. bool send_audio = false;
bool send_audio = bool recv_audio = false;
!rtp_manager()->GetAudioTransceiver()->internal()->senders().empty(); bool send_video = false;
bool send_video = bool recv_video = false;
!rtp_manager()->GetVideoTransceiver()->internal()->senders().empty();
// By default, generate sendrecv/recvonly m= sections. The direction is also if (ConfiguredForMedia()) {
// restricted by the direction in the offer. // Figure out transceiver directional preferences.
bool recv_audio = true; send_audio =
bool recv_video = true; !rtp_manager()->GetAudioTransceiver()->internal()->senders().empty();
send_video =
!rtp_manager()->GetVideoTransceiver()->internal()->senders().empty();
// The "offer_to_receive_X" options allow those defaults to be overridden. // By default, generate sendrecv/recvonly m= sections. The direction is also
if (offer_answer_options.offer_to_receive_audio != // restricted by the direction in the offer.
RTCOfferAnswerOptions::kUndefined) { recv_audio = true;
recv_audio = (offer_answer_options.offer_to_receive_audio > 0); recv_video = true;
}
if (offer_answer_options.offer_to_receive_video != // The "offer_to_receive_X" options allow those defaults to be overridden.
RTCOfferAnswerOptions::kUndefined) { if (offer_answer_options.offer_to_receive_audio !=
recv_video = (offer_answer_options.offer_to_receive_video > 0); RTCOfferAnswerOptions::kUndefined) {
recv_audio = (offer_answer_options.offer_to_receive_audio > 0);
}
if (offer_answer_options.offer_to_receive_video !=
RTCOfferAnswerOptions::kUndefined) {
recv_video = (offer_answer_options.offer_to_receive_video > 0);
}
} }
absl::optional<size_t> audio_index; absl::optional<size_t> audio_index;
@ -4129,10 +4167,12 @@ void SdpOfferAnswerHandler::GetOptionsForPlanBAnswer(
!video_index ? nullptr !video_index ? nullptr
: &session_options->media_description_options[*video_index]; : &session_options->media_description_options[*video_index];
AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(), if (ConfiguredForMedia()) {
audio_media_description_options, AddPlanBRtpSenderOptions(rtp_manager()->GetSendersInternal(),
video_media_description_options, audio_media_description_options,
offer_answer_options.num_simulcast_layers); video_media_description_options,
offer_answer_options.num_simulcast_layers);
}
} }
void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanAnswer( void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanAnswer(
@ -4477,6 +4517,9 @@ void SdpOfferAnswerHandler::UpdateRemoteSendersList(
void SdpOfferAnswerHandler::EnableSending() { void SdpOfferAnswerHandler::EnableSending() {
TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::EnableSending"); TRACE_EVENT0("webrtc", "SdpOfferAnswerHandler::EnableSending");
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
if (!ConfiguredForMedia()) {
return;
}
for (const auto& transceiver : transceivers()->ListInternal()) { for (const auto& transceiver : transceivers()->ListInternal()) {
cricket::ChannelInterface* channel = transceiver->channel(); cricket::ChannelInterface* channel = transceiver->channel();
if (channel) { if (channel) {
@ -4497,60 +4540,63 @@ RTCError SdpOfferAnswerHandler::PushdownMediaDescription(
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
RTC_DCHECK(sdesc); RTC_DCHECK(sdesc);
// Note: This will perform an Invoke over to the worker thread, which we'll if (ConfiguredForMedia()) {
// also do in a loop below. // Note: This will perform an Invoke over to the worker thread, which we'll
if (!UpdatePayloadTypeDemuxingState(source, bundle_groups_by_mid)) { // also do in a loop below.
// Note that this is never expected to fail, since RtpDemuxer doesn't return if (!UpdatePayloadTypeDemuxingState(source, bundle_groups_by_mid)) {
// an error when changing payload type demux criteria, which is all this // Note that this is never expected to fail, since RtpDemuxer doesn't
// does. // return an error when changing payload type demux criteria, which is all
return RTCError(RTCErrorType::INTERNAL_ERROR, // this does.
"Failed to update payload type demuxing state."); return RTCError(RTCErrorType::INTERNAL_ERROR,
} "Failed to update payload type demuxing state.");
// Push down the new SDP media section for each audio/video transceiver.
auto rtp_transceivers = transceivers()->ListInternal();
std::vector<
std::pair<cricket::ChannelInterface*, const MediaContentDescription*>>
channels;
for (const auto& transceiver : rtp_transceivers) {
const ContentInfo* content_info =
FindMediaSectionForTransceiver(transceiver, sdesc);
cricket::ChannelInterface* channel = transceiver->channel();
if (!channel || !content_info || content_info->rejected) {
continue;
}
const MediaContentDescription* content_desc =
content_info->media_description();
if (!content_desc) {
continue;
} }
transceiver->OnNegotiationUpdate(type, content_desc); // Push down the new SDP media section for each audio/video transceiver.
channels.push_back(std::make_pair(channel, content_desc)); auto rtp_transceivers = transceivers()->ListInternal();
} std::vector<
std::pair<cricket::ChannelInterface*, const MediaContentDescription*>>
channels;
for (const auto& transceiver : rtp_transceivers) {
const ContentInfo* content_info =
FindMediaSectionForTransceiver(transceiver, sdesc);
cricket::ChannelInterface* channel = transceiver->channel();
if (!channel || !content_info || content_info->rejected) {
continue;
}
const MediaContentDescription* content_desc =
content_info->media_description();
if (!content_desc) {
continue;
}
// This for-loop of invokes helps audio impairment during re-negotiations. transceiver->OnNegotiationUpdate(type, content_desc);
// One of the causes is that downstairs decoder creation is synchronous at the channels.push_back(std::make_pair(channel, content_desc));
// moment, and that a decoder is created for each codec listed in the SDP. }
//
// TODO(bugs.webrtc.org/12840): consider merging the invokes again after // This for-loop of invokes helps audio impairment during re-negotiations.
// these projects have shipped: // One of the causes is that downstairs decoder creation is synchronous at
// - bugs.webrtc.org/12462 // the moment, and that a decoder is created for each codec listed in the
// - crbug.com/1157227 // SDP.
// - crbug.com/1187289 //
for (const auto& entry : channels) { // TODO(bugs.webrtc.org/12840): consider merging the invokes again after
std::string error; // these projects have shipped:
bool success = // - bugs.webrtc.org/12462
context_->worker_thread()->Invoke<bool>(RTC_FROM_HERE, [&]() { // - crbug.com/1157227
return (source == cricket::CS_LOCAL) // - crbug.com/1187289
? entry.first->SetLocalContent(entry.second, type, error) for (const auto& entry : channels) {
: entry.first->SetRemoteContent(entry.second, type, error); std::string error;
}); bool success =
if (!success) { context_->worker_thread()->Invoke<bool>(RTC_FROM_HERE, [&]() {
return RTCError(RTCErrorType::INVALID_PARAMETER, error); return (source == cricket::CS_LOCAL)
? entry.first->SetLocalContent(entry.second, type, error)
: entry.first->SetRemoteContent(entry.second, type,
error);
});
if (!success) {
return RTCError(RTCErrorType::INVALID_PARAMETER, error);
}
} }
} }
// Need complete offer/answer with an SCTP m= section before starting SCTP, // Need complete offer/answer with an SCTP m= section before starting SCTP,
// according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19 // according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
if (pc_->sctp_mid() && local_description() && remote_description()) { if (pc_->sctp_mid() && local_description() && remote_description()) {
@ -4604,6 +4650,9 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() {
// run the following steps: // run the following steps:
if (!IsUnifiedPlan()) if (!IsUnifiedPlan())
return; return;
if (!ConfiguredForMedia()) {
return;
}
// Traverse a copy of the transceiver list. // Traverse a copy of the transceiver list.
auto transceiver_list = transceivers()->List(); auto transceiver_list = transceivers()->List();
for (auto transceiver : transceiver_list) { for (auto transceiver : transceiver_list) {
@ -4638,18 +4687,21 @@ void SdpOfferAnswerHandler::RemoveStoppedTransceivers() {
void SdpOfferAnswerHandler::RemoveUnusedChannels( void SdpOfferAnswerHandler::RemoveUnusedChannels(
const SessionDescription* desc) { const SessionDescription* desc) {
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
// Destroy video channel first since it may have a pointer to the if (ConfiguredForMedia()) {
// voice channel. // Destroy video channel first since it may have a pointer to the
const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc); // voice channel.
if (!video_info || video_info->rejected) { const cricket::ContentInfo* video_info =
rtp_manager()->GetVideoTransceiver()->internal()->ClearChannel(); cricket::GetFirstVideoContent(desc);
} if (!video_info || video_info->rejected) {
rtp_manager()->GetVideoTransceiver()->internal()->ClearChannel();
}
const cricket::ContentInfo* audio_info = cricket::GetFirstAudioContent(desc); const cricket::ContentInfo* audio_info =
if (!audio_info || audio_info->rejected) { cricket::GetFirstAudioContent(desc);
rtp_manager()->GetAudioTransceiver()->internal()->ClearChannel(); if (!audio_info || audio_info->rejected) {
rtp_manager()->GetAudioTransceiver()->internal()->ClearChannel();
}
} }
const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc); const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc);
if (!data_info) { if (!data_info) {
RTCError error(RTCErrorType::OPERATION_ERROR_WITH_DATA, RTCError error(RTCErrorType::OPERATION_ERROR_WITH_DATA,
@ -4967,7 +5019,7 @@ void SdpOfferAnswerHandler::GenerateMediaDescriptionOptions(
*audio_index = session_options->media_description_options.size() - 1; *audio_index = session_options->media_description_options.size() - 1;
} }
session_options->media_description_options.back().header_extensions = session_options->media_description_options.back().header_extensions =
channel_manager()->GetSupportedAudioRtpHeaderExtensions(); media_engine()->voice().GetRtpHeaderExtensions();
} else if (IsVideoContent(&content)) { } else if (IsVideoContent(&content)) {
// If we already have an video m= section, reject this extra one. // If we already have an video m= section, reject this extra one.
if (*video_index) { if (*video_index) {
@ -4984,7 +5036,7 @@ void SdpOfferAnswerHandler::GenerateMediaDescriptionOptions(
*video_index = session_options->media_description_options.size() - 1; *video_index = session_options->media_description_options.size() - 1;
} }
session_options->media_description_options.back().header_extensions = session_options->media_description_options.back().header_extensions =
channel_manager()->GetSupportedVideoRtpHeaderExtensions(); media_engine()->video().GetRtpHeaderExtensions();
} else if (IsUnsupportedContent(&content)) { } else if (IsUnsupportedContent(&content)) {
session_options->media_description_options.push_back( session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(cricket::MEDIA_TYPE_UNSUPPORTED, cricket::MediaDescriptionOptions(cricket::MEDIA_TYPE_UNSUPPORTED,
@ -5208,4 +5260,8 @@ bool SdpOfferAnswerHandler::UpdatePayloadTypeDemuxingState(
}); });
} }
bool SdpOfferAnswerHandler::ConfiguredForMedia() const {
return context_->channel_manager();
}
} // namespace webrtc } // namespace webrtc

View File

@ -478,7 +478,7 @@ class SdpOfferAnswerHandler : public SdpStateProvider,
// This enables media to flow on all configured audio/video channels. // This enables media to flow on all configured audio/video channels.
void EnableSending(); void EnableSending();
// Push the media parts of the local or remote session description // Push the media parts of the local or remote session description
// down to all of the channels. // down to all of the channels, and start SCTP if needed.
RTCError PushdownMediaDescription( RTCError PushdownMediaDescription(
SdpType type, SdpType type,
cricket::ContentSource source, cricket::ContentSource source,
@ -576,6 +576,7 @@ class SdpOfferAnswerHandler : public SdpStateProvider,
// ================================================================== // ==================================================================
// Access to pc_ variables // Access to pc_ variables
cricket::ChannelManager* channel_manager() const; cricket::ChannelManager* channel_manager() const;
cricket::MediaEngineInterface* media_engine() const;
TransceiverList* transceivers(); TransceiverList* transceivers();
const TransceiverList* transceivers() const; const TransceiverList* transceivers() const;
DataChannelController* data_channel_controller(); DataChannelController* data_channel_controller();
@ -595,6 +596,7 @@ class SdpOfferAnswerHandler : public SdpStateProvider,
// =================================================================== // ===================================================================
const cricket::AudioOptions& audio_options() { return audio_options_; } const cricket::AudioOptions& audio_options() { return audio_options_; }
const cricket::VideoOptions& video_options() { return video_options_; } const cricket::VideoOptions& video_options() { return video_options_; }
bool ConfiguredForMedia() const;
PeerConnectionSdpMethods* const pc_; PeerConnectionSdpMethods* const pc_;
ConnectionContext* const context_; ConnectionContext* const context_;

View File

@ -415,7 +415,10 @@ class FakePeerConnectionForStats : public FakePeerConnectionBase {
class TestChannelManager : public cricket::ChannelManager { class TestChannelManager : public cricket::ChannelManager {
public: public:
TestChannelManager(rtc::Thread* worker, rtc::Thread* network) TestChannelManager(rtc::Thread* worker, rtc::Thread* network)
: cricket::ChannelManager(nullptr, true, worker, network) {} : cricket::ChannelManager(std::make_unique<cricket::FakeMediaEngine>(),
true,
worker,
network) {}
}; };
rtc::Thread* const network_thread_; rtc::Thread* const network_thread_;