diff --git a/ortc/ortcrtpreceiveradapter.cc b/ortc/ortcrtpreceiveradapter.cc index 67f4de642e..16cb2485d0 100644 --- a/ortc/ortcrtpreceiveradapter.cc +++ b/ortc/ortcrtpreceiveradapter.cc @@ -151,22 +151,29 @@ void OrtcRtpReceiverAdapter::MaybeRecreateInternalReceiver() { internal_receiver_ = nullptr; switch (kind_) { case cricket::MEDIA_TYPE_AUDIO: { + auto* audio_receiver = + new AudioRtpReceiver(rtp_transport_controller_->worker_thread(), + rtc::CreateRandomUuid(), {}); auto* voice_channel = rtp_transport_controller_->voice_channel(); - internal_receiver_ = new AudioRtpReceiver( - rtp_transport_controller_->worker_thread(), rtc::CreateRandomUuid(), - {}, ssrc, (voice_channel ? voice_channel->media_channel() : nullptr)); + RTC_DCHECK(voice_channel); + audio_receiver->SetMediaChannel(voice_channel->media_channel()); + internal_receiver_ = audio_receiver; break; } case cricket::MEDIA_TYPE_VIDEO: { + auto* video_receiver = + new VideoRtpReceiver(rtp_transport_controller_->worker_thread(), + rtc::CreateRandomUuid(), {}); auto* video_channel = rtp_transport_controller_->video_channel(); - internal_receiver_ = new VideoRtpReceiver( - rtp_transport_controller_->worker_thread(), rtc::CreateRandomUuid(), - {}, ssrc, (video_channel ? video_channel->media_channel() : nullptr)); + RTC_DCHECK(video_channel); + video_receiver->SetMediaChannel(video_channel->media_channel()); + internal_receiver_ = video_receiver; break; } case cricket::MEDIA_TYPE_DATA: RTC_NOTREACHED(); } + internal_receiver_->SetupMediaChannel(ssrc); } } // namespace webrtc diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc index 6281d57e3d..75eead61f9 100644 --- a/pc/peerconnection.cc +++ b/pc/peerconnection.cc @@ -1314,12 +1314,12 @@ PeerConnection::CreateReceiver(cricket::MediaType media_type, if (media_type == cricket::MEDIA_TYPE_AUDIO) { receiver = RtpReceiverProxyWithInternal::Create( signaling_thread(), - new AudioRtpReceiver(worker_thread(), receiver_id, {}, 0, nullptr)); + new AudioRtpReceiver(worker_thread(), receiver_id, {})); } else { RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO); receiver = RtpReceiverProxyWithInternal::Create( signaling_thread(), - new VideoRtpReceiver(worker_thread(), receiver_id, {}, 0, nullptr)); + new VideoRtpReceiver(worker_thread(), receiver_id, {})); } return receiver; } @@ -1766,7 +1766,27 @@ RTCError PeerConnection::ApplyLocalDescription( AllocateSctpSids(role); } - if (!IsUnifiedPlan()) { + if (IsUnifiedPlan()) { + for (auto transceiver : transceivers_) { + const ContentInfo* content = + FindMediaSectionForTransceiver(transceiver, local_description()); + if (!content) { + continue; + } + if (content->rejected && !transceiver->stopped()) { + transceiver->Stop(); + } + if (!content->rejected) { + const auto& stream = content->media_description()->streams()[0]; + transceiver->internal()->sender_internal()->set_stream_ids( + {stream.sync_label}); + transceiver->internal()->sender_internal()->SetSsrc( + stream.first_ssrc()); + } + } + } else { + // Plan B semantics. + // Update state and SSRC of local MediaStreams and DataChannels based on the // local session description. const cricket::ContentInfo* audio_content = @@ -2029,6 +2049,11 @@ RTCError PeerConnection::ApplyRemoteDescription( if (content->rejected && !transceiver->stopped()) { transceiver->Stop(); } + if (!content->rejected) { + const auto& stream = content->media_description()->streams()[0]; + transceiver->internal()->receiver_internal()->SetupMediaChannel( + stream.first_ssrc()); + } } for (auto event : track_events) { observer_->OnAddTrack(event.receiver, event.streams); @@ -2773,12 +2798,12 @@ void PeerConnection::CreateAudioReceiver( const RtpSenderInfo& remote_sender_info) { std::vector> streams; streams.push_back(rtc::scoped_refptr(stream)); - rtc::scoped_refptr> - receiver = RtpReceiverProxyWithInternal::Create( - signaling_thread(), - new AudioRtpReceiver(worker_thread(), remote_sender_info.sender_id, - streams, remote_sender_info.first_ssrc, - voice_media_channel())); + auto* audio_receiver = new AudioRtpReceiver( + worker_thread(), remote_sender_info.sender_id, streams); + audio_receiver->SetMediaChannel(voice_media_channel()); + audio_receiver->SetupMediaChannel(remote_sender_info.first_ssrc); + auto receiver = RtpReceiverProxyWithInternal::Create( + signaling_thread(), audio_receiver); GetAudioTransceiver()->internal()->AddReceiver(receiver); observer_->OnAddTrack(receiver, std::move(streams)); } @@ -2788,12 +2813,12 @@ void PeerConnection::CreateVideoReceiver( const RtpSenderInfo& remote_sender_info) { std::vector> streams; streams.push_back(rtc::scoped_refptr(stream)); - rtc::scoped_refptr> - receiver = RtpReceiverProxyWithInternal::Create( - signaling_thread(), - new VideoRtpReceiver(worker_thread(), remote_sender_info.sender_id, - streams, remote_sender_info.first_ssrc, - video_media_channel())); + auto* video_receiver = new VideoRtpReceiver( + worker_thread(), remote_sender_info.sender_id, streams); + video_receiver->SetMediaChannel(video_media_channel()); + video_receiver->SetupMediaChannel(remote_sender_info.first_ssrc); + auto receiver = RtpReceiverProxyWithInternal::Create( + signaling_thread(), video_receiver); GetVideoTransceiver()->internal()->AddReceiver(receiver); observer_->OnAddTrack(receiver, std::move(streams)); } diff --git a/pc/peerconnection_integrationtest.cc b/pc/peerconnection_integrationtest.cc index 8decc9603d..7bf6ad862e 100644 --- a/pc/peerconnection_integrationtest.cc +++ b/pc/peerconnection_integrationtest.cc @@ -84,6 +84,7 @@ using webrtc::PeerConnectionFactory; using webrtc::PeerConnectionProxy; using webrtc::RTCErrorType; using webrtc::RtpReceiverInterface; +using webrtc::SdpSemantics; using webrtc::SdpType; using webrtc::SessionDescriptionInterface; using webrtc::StreamCollectionInterface; @@ -3625,6 +3626,23 @@ TEST_F(PeerConnectionIntegrationTest, ClosingConnectionStopsPacketFlow) { EXPECT_EQ(sent_packets_a, sent_packets_b); } +// Test that a basic 1 audio and 1 video track call works when Unified Plan +// semantics configured for both sides. +TEST_F(PeerConnectionIntegrationTest, UnifiedPlanMediaFlows) { + PeerConnectionInterface::RTCConfiguration config; + config.sdp_semantics = SdpSemantics::kUnifiedPlan; + ASSERT_TRUE(CreatePeerConnectionWrappersWithConfig(config, config)); + ConnectFakeSignaling(); + caller()->AddAudioVideoTracks(); + callee()->AddAudioVideoTracks(); + caller()->CreateAndSetAndSignalOffer(); + ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout); + ExpectNewFramesReceivedWithWait( + kDefaultExpectedAudioFrameCount, kDefaultExpectedVideoFrameCount, + kDefaultExpectedAudioFrameCount, kDefaultExpectedVideoFrameCount, + kMaxWaitForFramesMs); +} + } // namespace #endif // if !defined(THREAD_SANITIZER) diff --git a/pc/remoteaudiosource.cc b/pc/remoteaudiosource.cc index a260be89fd..f58e23d828 100644 --- a/pc/remoteaudiosource.cc +++ b/pc/remoteaudiosource.cc @@ -23,35 +23,33 @@ namespace webrtc { -class RemoteAudioSource::Sink : public AudioSinkInterface { +// This proxy is passed to the underlying media engine to receive audio data as +// they come in. The data will then be passed back up to the RemoteAudioSource +// which will fan it out to all the sinks that have been added to it. +class RemoteAudioSource::AudioDataProxy : public AudioSinkInterface { public: - explicit Sink(RemoteAudioSource* source) : source_(source) {} - ~Sink() override { source_->OnAudioChannelGone(); } + explicit AudioDataProxy(RemoteAudioSource* source) : source_(source) { + RTC_DCHECK(source); + } + ~AudioDataProxy() override { source_->OnAudioChannelGone(); } - private: + // AudioSinkInterface implementation. void OnData(const AudioSinkInterface::Data& audio) override { - if (source_) - source_->OnData(audio); + source_->OnData(audio); } + private: const rtc::scoped_refptr source_; - RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(Sink); + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioDataProxy); }; -rtc::scoped_refptr RemoteAudioSource::Create( - rtc::Thread* worker_thread, - cricket::VoiceMediaChannel* media_channel, - uint32_t ssrc) { - rtc::scoped_refptr ret( - new rtc::RefCountedObject()); - ret->Initialize(worker_thread, media_channel, ssrc); - return ret; -} - -RemoteAudioSource::RemoteAudioSource() +RemoteAudioSource::RemoteAudioSource(rtc::Thread* worker_thread) : main_thread_(rtc::Thread::Current()), + worker_thread_(worker_thread), state_(MediaSourceInterface::kLive) { RTC_DCHECK(main_thread_); + RTC_DCHECK(worker_thread_); } RemoteAudioSource::~RemoteAudioSource() { @@ -60,17 +58,24 @@ RemoteAudioSource::~RemoteAudioSource() { RTC_DCHECK(sinks_.empty()); } -void RemoteAudioSource::Initialize(rtc::Thread* worker_thread, - cricket::VoiceMediaChannel* media_channel, - uint32_t ssrc) { - RTC_DCHECK(main_thread_->IsCurrent()); - // To make sure we always get notified when the channel goes out of scope, - // we register for callbacks here and not on demand in AddSink. - if (media_channel) { // May be null in tests. - worker_thread->Invoke(RTC_FROM_HERE, [&] { - media_channel->SetRawAudioSink(ssrc, rtc::MakeUnique(this)); - }); - } +void RemoteAudioSource::Start(cricket::VoiceMediaChannel* media_channel, + uint32_t ssrc) { + RTC_DCHECK_RUN_ON(main_thread_); + RTC_DCHECK(media_channel); + // Register for callbacks immediately before AddSink so that we always get + // notified when a channel goes out of scope (signaled when "AudioDataProxy" + // is destroyed). + worker_thread_->Invoke(RTC_FROM_HERE, [&] { + media_channel->SetRawAudioSink(ssrc, rtc::MakeUnique(this)); + }); +} + +void RemoteAudioSource::Stop(cricket::VoiceMediaChannel* media_channel, + uint32_t ssrc) { + RTC_DCHECK_RUN_ON(main_thread_); + RTC_DCHECK(media_channel); + worker_thread_->Invoke( + RTC_FROM_HERE, [&] { media_channel->SetRawAudioSink(ssrc, nullptr); }); } MediaSourceInterface::SourceState RemoteAudioSource::state() const { @@ -86,8 +91,9 @@ bool RemoteAudioSource::remote() const { void RemoteAudioSource::SetVolume(double volume) { RTC_DCHECK_GE(volume, 0); RTC_DCHECK_LE(volume, 10); - for (auto* observer : audio_observers_) + for (auto* observer : audio_observers_) { observer->OnSetVolume(volume); + } } void RemoteAudioSource::RegisterAudioObserver(AudioObserver* observer) { diff --git a/pc/remoteaudiosource.h b/pc/remoteaudiosource.h index eadbccacc7..4d87331f91 100644 --- a/pc/remoteaudiosource.h +++ b/pc/remoteaudiosource.h @@ -28,50 +28,46 @@ class Thread; namespace webrtc { // This class implements the audio source used by the remote audio track. +// This class works by configuring itself as a sink with the underlying media +// engine, then when receiving data will fan out to all added sinks. class RemoteAudioSource : public Notifier, rtc::MessageHandler { public: - // Creates an instance of RemoteAudioSource. - static rtc::scoped_refptr Create( - rtc::Thread* worker_thread, - cricket::VoiceMediaChannel* media_channel, - uint32_t ssrc); + explicit RemoteAudioSource(rtc::Thread* worker_thread); + + // Register and unregister remote audio source with the underlying media + // engine. + void Start(cricket::VoiceMediaChannel* media_channel, uint32_t ssrc); + void Stop(cricket::VoiceMediaChannel* media_channel, uint32_t ssrc); // MediaSourceInterface implementation. MediaSourceInterface::SourceState state() const override; bool remote() const override; - void AddSink(AudioTrackSinkInterface* sink) override; - void RemoveSink(AudioTrackSinkInterface* sink) override; - - protected: - RemoteAudioSource(); - ~RemoteAudioSource() override; - - // Post construction initialize where we can do things like save a reference - // to ourselves (need to be fully constructed). - void Initialize(rtc::Thread* worker_thread, - cricket::VoiceMediaChannel* media_channel, - uint32_t ssrc); - - private: - typedef std::list AudioObserverList; - // AudioSourceInterface implementation. void SetVolume(double volume) override; void RegisterAudioObserver(AudioObserver* observer) override; void UnregisterAudioObserver(AudioObserver* observer) override; - class Sink; + void AddSink(AudioTrackSinkInterface* sink) override; + void RemoveSink(AudioTrackSinkInterface* sink) override; + + protected: + ~RemoteAudioSource() override; + + private: + // These are callbacks from the media engine. + class AudioDataProxy; void OnData(const AudioSinkInterface::Data& audio); void OnAudioChannelGone(); void OnMessage(rtc::Message* msg) override; - AudioObserverList audio_observers_; + rtc::Thread* const main_thread_; + rtc::Thread* const worker_thread_; + std::list audio_observers_; rtc::CriticalSection sink_lock_; std::list sinks_; - rtc::Thread* const main_thread_; SourceState state_; }; diff --git a/pc/rtpreceiver.cc b/pc/rtpreceiver.cc index e318c17e14..05990f4e03 100644 --- a/pc/rtpreceiver.cc +++ b/pc/rtpreceiver.cc @@ -35,17 +35,12 @@ int GenerateUniqueId() { AudioRtpReceiver::AudioRtpReceiver( rtc::Thread* worker_thread, const std::string& receiver_id, - const std::vector>& streams, - uint32_t ssrc, - cricket::VoiceMediaChannel* media_channel) + const std::vector>& streams) : worker_thread_(worker_thread), id_(receiver_id), - ssrc_(ssrc), - track_(AudioTrackProxy::Create( - rtc::Thread::Current(), - AudioTrack::Create( - receiver_id, - RemoteAudioSource::Create(worker_thread, media_channel, ssrc)))), + source_(new rtc::RefCountedObject(worker_thread)), + track_(AudioTrackProxy::Create(rtc::Thread::Current(), + AudioTrack::Create(receiver_id, source_))), cached_track_enabled_(track_->enabled()), attachment_id_(GenerateUniqueId()) { RTC_DCHECK(worker_thread_); @@ -53,8 +48,6 @@ AudioRtpReceiver::AudioRtpReceiver( track_->RegisterObserver(this); track_->GetSource()->RegisterAudioObserver(this); SetStreams(streams); - SetMediaChannel(media_channel); - Reconfigure(); } AudioRtpReceiver::~AudioRtpReceiver() { @@ -74,8 +67,9 @@ bool AudioRtpReceiver::SetOutputVolume(double volume) { RTC_DCHECK_GE(volume, 0.0); RTC_DCHECK_LE(volume, 10.0); RTC_DCHECK(media_channel_); + RTC_DCHECK(ssrc_); return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return media_channel_->SetOutputVolume(ssrc_, volume); + return media_channel_->SetOutputVolume(*ssrc_, volume); }); } @@ -83,7 +77,7 @@ void AudioRtpReceiver::OnSetVolume(double volume) { RTC_DCHECK_GE(volume, 0); RTC_DCHECK_LE(volume, 10); cached_volume_ = volume; - if (!media_channel_) { + if (!media_channel_ || !ssrc_) { RTC_LOG(LS_ERROR) << "AudioRtpReceiver::OnSetVolume: No audio channel exists."; return; @@ -99,21 +93,21 @@ void AudioRtpReceiver::OnSetVolume(double volume) { } RtpParameters AudioRtpReceiver::GetParameters() const { - if (!media_channel_ || stopped_) { + if (!media_channel_ || !ssrc_ || stopped_) { return RtpParameters(); } return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return media_channel_->GetRtpReceiveParameters(ssrc_); + return media_channel_->GetRtpReceiveParameters(*ssrc_); }); } bool AudioRtpReceiver::SetParameters(const RtpParameters& parameters) { TRACE_EVENT0("webrtc", "AudioRtpReceiver::SetParameters"); - if (!media_channel_ || stopped_) { + if (!media_channel_ || !ssrc_ || stopped_) { return false; } return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return media_channel_->SetRtpReceiveParameters(ssrc_, parameters); + return media_channel_->SetRtpReceiveParameters(*ssrc_, parameters); }); } @@ -122,7 +116,7 @@ void AudioRtpReceiver::Stop() { if (stopped_) { return; } - if (media_channel_) { + if (media_channel_ && ssrc_) { // Allow that SetOutputVolume fail. This is the normal case when the // underlying media channel has already been deleted. SetOutputVolume(0.0); @@ -130,6 +124,23 @@ void AudioRtpReceiver::Stop() { stopped_ = true; } +void AudioRtpReceiver::SetupMediaChannel(uint32_t ssrc) { + if (!media_channel_) { + RTC_LOG(LS_ERROR) + << "AudioRtpReceiver::SetupMediaChannel: No audio channel exists."; + return; + } + if (ssrc_ == ssrc) { + return; + } + if (ssrc_) { + source_->Stop(media_channel_, *ssrc_); + } + ssrc_ = ssrc; + source_->Start(media_channel_, *ssrc_); + Reconfigure(); +} + void AudioRtpReceiver::SetStreams( const std::vector>& streams) { // Remove remote track from any streams that are going away. @@ -164,13 +175,16 @@ void AudioRtpReceiver::SetStreams( } std::vector AudioRtpReceiver::GetSources() const { + if (!media_channel_ || !ssrc_ || stopped_) { + return {}; + } return worker_thread_->Invoke>( - RTC_FROM_HERE, [&] { return media_channel_->GetSources(ssrc_); }); + RTC_FROM_HERE, [&] { return media_channel_->GetSources(*ssrc_); }); } void AudioRtpReceiver::Reconfigure() { RTC_DCHECK(!stopped_); - if (!media_channel_) { + if (!media_channel_ || !ssrc_) { RTC_LOG(LS_ERROR) << "AudioRtpReceiver::Reconfigure: No audio channel exists."; return; @@ -203,12 +217,9 @@ void AudioRtpReceiver::NotifyFirstPacketReceived() { VideoRtpReceiver::VideoRtpReceiver( rtc::Thread* worker_thread, const std::string& receiver_id, - const std::vector>& streams, - uint32_t ssrc, - cricket::VideoMediaChannel* media_channel) + const std::vector>& streams) : worker_thread_(worker_thread), id_(receiver_id), - ssrc_(ssrc), source_(new RefCountedObject(&broadcaster_, true /* remote */)), track_(VideoTrackProxy::Create( @@ -224,7 +235,6 @@ VideoRtpReceiver::VideoRtpReceiver( RTC_DCHECK(worker_thread_); SetStreams(streams); source_->SetState(MediaSourceInterface::kLive); - SetMediaChannel(media_channel); } VideoRtpReceiver::~VideoRtpReceiver() { @@ -235,26 +245,27 @@ VideoRtpReceiver::~VideoRtpReceiver() { bool VideoRtpReceiver::SetSink(rtc::VideoSinkInterface* sink) { RTC_DCHECK(media_channel_); + RTC_DCHECK(ssrc_); return worker_thread_->Invoke( - RTC_FROM_HERE, [&] { return media_channel_->SetSink(ssrc_, sink); }); + RTC_FROM_HERE, [&] { return media_channel_->SetSink(*ssrc_, sink); }); } RtpParameters VideoRtpReceiver::GetParameters() const { - if (!media_channel_ || stopped_) { + if (!media_channel_ || !ssrc_ || stopped_) { return RtpParameters(); } return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return media_channel_->GetRtpReceiveParameters(ssrc_); + return media_channel_->GetRtpReceiveParameters(*ssrc_); }); } bool VideoRtpReceiver::SetParameters(const RtpParameters& parameters) { TRACE_EVENT0("webrtc", "VideoRtpReceiver::SetParameters"); - if (!media_channel_ || stopped_) { + if (!media_channel_ || !ssrc_ || stopped_) { return false; } return worker_thread_->Invoke(RTC_FROM_HERE, [&] { - return media_channel_->SetRtpReceiveParameters(ssrc_, parameters); + return media_channel_->SetRtpReceiveParameters(*ssrc_, parameters); }); } @@ -265,7 +276,7 @@ void VideoRtpReceiver::Stop() { } source_->SetState(MediaSourceInterface::kEnded); source_->OnSourceDestroyed(); - if (!media_channel_) { + if (!media_channel_ || !ssrc_) { RTC_LOG(LS_WARNING) << "VideoRtpReceiver::Stop: No video channel exists."; } else { // Allow that SetSink fail. This is the normal case when the underlying @@ -275,6 +286,21 @@ void VideoRtpReceiver::Stop() { stopped_ = true; } +void VideoRtpReceiver::SetupMediaChannel(uint32_t ssrc) { + if (!media_channel_) { + RTC_LOG(LS_ERROR) + << "VideoRtpReceiver::SetupMediaChannel: No video channel exists."; + } + if (ssrc_ == ssrc) { + return; + } + if (ssrc_) { + SetSink(nullptr); + } + ssrc_ = ssrc; + SetSink(&broadcaster_); +} + void VideoRtpReceiver::SetStreams( const std::vector>& streams) { // Remove remote track from any streams that are going away. @@ -318,15 +344,7 @@ void VideoRtpReceiver::SetObserver(RtpReceiverObserverInterface* observer) { void VideoRtpReceiver::SetMediaChannel( cricket::VideoMediaChannel* media_channel) { - if (media_channel_) { - SetSink(nullptr); - } media_channel_ = media_channel; - if (media_channel_) { - if (!SetSink(&broadcaster_)) { - RTC_NOTREACHED(); - } - } } void VideoRtpReceiver::NotifyFirstPacketReceived() { diff --git a/pc/rtpreceiver.h b/pc/rtpreceiver.h index 82c3134a26..887f828312 100644 --- a/pc/rtpreceiver.h +++ b/pc/rtpreceiver.h @@ -34,6 +34,11 @@ class RtpReceiverInternal : public RtpReceiverInterface { public: virtual void Stop() = 0; + // Configures the RtpReceiver with the underlying media channel, with the + // given SSRC as the stream identifier. If |ssrc| is 0, the receiver will + // receive packets on unsignaled SSRCs. + virtual void SetupMediaChannel(uint32_t ssrc) = 0; + // This SSRC is used as an identifier for the receiver between the API layer // and the WebRtcVideoEngine, WebRtcVoiceEngine layer. virtual uint32_t ssrc() const = 0; @@ -53,16 +58,10 @@ class AudioRtpReceiver : public ObserverInterface, public AudioSourceInterface::AudioObserver, public rtc::RefCountedObject { public: - // An SSRC of 0 will create a receiver that will match the first SSRC it - // sees. - // TODO(deadbeef): Use rtc::Optional, or have another constructor that - // doesn't take an SSRC, and make this one DCHECK(ssrc != 0). AudioRtpReceiver( rtc::Thread* worker_thread, const std::string& receiver_id, - const std::vector>& streams, - uint32_t ssrc, - cricket::VoiceMediaChannel* media_channel); + const std::vector>& streams); virtual ~AudioRtpReceiver(); // ObserverInterface implementation @@ -95,7 +94,8 @@ class AudioRtpReceiver : public ObserverInterface, // RtpReceiverInternal implementation. void Stop() override; - uint32_t ssrc() const override { return ssrc_; } + void SetupMediaChannel(uint32_t ssrc) override; + uint32_t ssrc() const override { return ssrc_.value_or(0); } void NotifyFirstPacketReceived() override; void SetStreams(const std::vector>& streams) override; @@ -115,9 +115,10 @@ class AudioRtpReceiver : public ObserverInterface, rtc::Thread* const worker_thread_; const std::string id_; - const uint32_t ssrc_; - cricket::VoiceMediaChannel* media_channel_ = nullptr; + const rtc::scoped_refptr source_; const rtc::scoped_refptr track_; + cricket::VoiceMediaChannel* media_channel_ = nullptr; + rtc::Optional ssrc_; std::vector> streams_; bool cached_track_enabled_; double cached_volume_ = 1; @@ -134,9 +135,7 @@ class VideoRtpReceiver : public rtc::RefCountedObject { VideoRtpReceiver( rtc::Thread* worker_thread, const std::string& receiver_id, - const std::vector>& streams, - uint32_t ssrc, - cricket::VideoMediaChannel* media_channel); + const std::vector>& streams); virtual ~VideoRtpReceiver(); @@ -164,7 +163,8 @@ class VideoRtpReceiver : public rtc::RefCountedObject { // RtpReceiverInternal implementation. void Stop() override; - uint32_t ssrc() const override { return ssrc_; } + void SetupMediaChannel(uint32_t ssrc) override; + uint32_t ssrc() const override { return ssrc_.value_or(0); } void NotifyFirstPacketReceived() override; void SetStreams(const std::vector>& streams) override; @@ -180,8 +180,8 @@ class VideoRtpReceiver : public rtc::RefCountedObject { rtc::Thread* const worker_thread_; const std::string id_; - uint32_t ssrc_; cricket::VideoMediaChannel* media_channel_ = nullptr; + rtc::Optional ssrc_; // |broadcaster_| is needed since the decoder can only handle one sink. // It might be better if the decoder can handle multiple sinks and consider // the VideoSinkWants. diff --git a/pc/rtpsenderreceiver_unittest.cc b/pc/rtpsenderreceiver_unittest.cc index 9da9c6dc01..ff425e2f82 100644 --- a/pc/rtpsenderreceiver_unittest.cc +++ b/pc/rtpsenderreceiver_unittest.cc @@ -183,8 +183,9 @@ class RtpSenderReceiverTest : public testing::Test, void CreateAudioRtpReceiver( std::vector> streams = {}) { audio_rtp_receiver_ = new AudioRtpReceiver( - rtc::Thread::Current(), kAudioTrackId, std::move(streams), kAudioSsrc, - voice_media_channel_); + rtc::Thread::Current(), kAudioTrackId, std::move(streams)); + audio_rtp_receiver_->SetMediaChannel(voice_media_channel_); + audio_rtp_receiver_->SetupMediaChannel(kAudioSsrc); audio_track_ = audio_rtp_receiver_->audio_track(); VerifyVoiceChannelOutput(); } @@ -192,8 +193,9 @@ class RtpSenderReceiverTest : public testing::Test, void CreateVideoRtpReceiver( std::vector> streams = {}) { video_rtp_receiver_ = new VideoRtpReceiver( - rtc::Thread::Current(), kVideoTrackId, std::move(streams), kVideoSsrc, - video_media_channel_); + rtc::Thread::Current(), kVideoTrackId, std::move(streams)); + video_rtp_receiver_->SetMediaChannel(video_media_channel_); + video_rtp_receiver_->SetupMediaChannel(kVideoSsrc); video_track_ = video_rtp_receiver_->video_track(); VerifyVideoChannelOutput(); }