From 184a3fd6489b2602a21c415cad3c51a7b035040b Mon Sep 17 00:00:00 2001 From: zhihuang Date: Tue, 14 Jun 2016 11:47:14 -0700 Subject: [PATCH] Forward the SignalFirstPacketReceived to RtpReceiver. The RtpReceiverObserverInterface is created. The SignalFirstPacketReceived will be forwarded from BaseChannel to WebRtcSession. WebRtcSession will forward SignalFirstAudioPacketReceived and SignalFirstVideoPacketReceived to the RtpReceiverInterface. The application can listen to the Signal by implementing and registering a RtpReceiverObserver. Review-Url: https://codereview.webrtc.org/1999853002 Cr-Commit-Position: refs/heads/master@{#13139} --- webrtc/api/mediastreamprovider.h | 6 +++ webrtc/api/peerconnection_unittest.cc | 77 +++++++++++++++++++++++++++ webrtc/api/rtpreceiver.cc | 36 +++++++++++++ webrtc/api/rtpreceiver.h | 22 +++++++- webrtc/api/rtpreceiverinterface.h | 15 ++++++ webrtc/api/webrtcsession.cc | 19 +++++++ webrtc/api/webrtcsession.h | 5 ++ webrtc/pc/channel.h | 5 ++ 8 files changed, 183 insertions(+), 2 deletions(-) diff --git a/webrtc/api/mediastreamprovider.h b/webrtc/api/mediastreamprovider.h index b508c39f7e..784a95423d 100644 --- a/webrtc/api/mediastreamprovider.h +++ b/webrtc/api/mediastreamprovider.h @@ -72,6 +72,9 @@ class AudioProviderInterface { uint32_t ssrc, const RtpParameters& parameters) = 0; + // Called when the first audio packet is received. + sigslot::signal0<> SignalFirstAudioPacketReceived; + protected: virtual ~AudioProviderInterface() {} }; @@ -105,6 +108,9 @@ class VideoProviderInterface { uint32_t ssrc, const RtpParameters& parameters) = 0; + // Called when the first video packet is received. + sigslot::signal0<> SignalFirstVideoPacketReceived; + protected: virtual ~VideoProviderInterface() {} }; diff --git a/webrtc/api/peerconnection_unittest.cc b/webrtc/api/peerconnection_unittest.cc index 20cd7a6439..4b06b90d01 100644 --- a/webrtc/api/peerconnection_unittest.cc +++ b/webrtc/api/peerconnection_unittest.cc @@ -146,6 +146,25 @@ class SignalingMessageReceiver { virtual ~SignalingMessageReceiver() {} }; +class MockRtpReceiverObserver : public webrtc::RtpReceiverObserverInterface { + public: + MockRtpReceiverObserver(cricket::MediaType media_type) + : expected_media_type_(media_type) {} + + void OnFirstPacketReceived(cricket::MediaType media_type) override { + ASSERT_EQ(expected_media_type_, media_type); + first_packet_received_ = true; + } + + bool first_packet_received() { return first_packet_received_; } + + virtual ~MockRtpReceiverObserver() {} + + private: + bool first_packet_received_ = false; + cricket::MediaType expected_media_type_; +}; + class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, public SignalingMessageReceiver, public ObserverInterface { @@ -780,6 +799,21 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, return pc()->ice_gathering_state(); } + std::vector> const& + rtp_receiver_observers() { + return rtp_receiver_observers_; + } + + void SetRtpReceiverObservers() { + rtp_receiver_observers_.clear(); + for (auto receiver : pc()->GetReceivers()) { + std::unique_ptr observer( + new MockRtpReceiverObserver(receiver->media_type())); + receiver->SetObserver(observer.get()); + rtp_receiver_observers_.push_back(std::move(observer)); + } + } + private: class DummyDtmfObserver : public DtmfSenderObserverInterface { public: @@ -870,6 +904,8 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, std::unique_ptr desc( webrtc::CreateSessionDescription("offer", msg, nullptr)); EXPECT_TRUE(DoSetRemoteDescription(desc.release())); + // Set the RtpReceiverObserver after receivers are created. + SetRtpReceiverObservers(); std::unique_ptr answer; EXPECT_TRUE(DoCreateAnswer(&answer)); std::string sdp; @@ -886,6 +922,8 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, std::unique_ptr desc( webrtc::CreateSessionDescription("answer", msg, nullptr)); EXPECT_TRUE(DoSetRemoteDescription(desc.release())); + // Set the RtpReceiverObserver after receivers are created. + SetRtpReceiverObservers(); } bool DoCreateOfferAnswer(std::unique_ptr* desc, @@ -1026,6 +1064,8 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver, rtc::scoped_refptr data_channel_; std::unique_ptr data_observer_; + + std::vector> rtp_receiver_observers_; }; class P2PTestConductor : public testing::Test { @@ -1314,6 +1354,16 @@ class P2PTestConductor : public testing::Test { return old; } + bool AllObserversReceived( + const std::vector>& observers) { + for (auto& observer : observers) { + if (!observer->first_packet_received()) { + return false; + } + } + return true; + } + private: // |ss_| is used by |network_thread_| so it must be destroyed later. std::unique_ptr pss_; @@ -1332,6 +1382,33 @@ class P2PTestConductor : public testing::Test { // https://code.google.com/p/webrtc/issues/detail?id=1205 for details. #if !defined(THREAD_SANITIZER) +TEST_F(P2PTestConductor, TestRtpReceiverObserverCallbackFunction) { + ASSERT_TRUE(CreateTestClients()); + LocalP2PTest(); + EXPECT_TRUE_WAIT( + AllObserversReceived(initializing_client()->rtp_receiver_observers()), + kMaxWaitForFramesMs); + EXPECT_TRUE_WAIT( + AllObserversReceived(receiving_client()->rtp_receiver_observers()), + kMaxWaitForFramesMs); +} + +// The observers are expected to fire the signal even if they are set after the +// first packet is received. +TEST_F(P2PTestConductor, TestSetRtpReceiverObserverAfterFirstPacketIsReceived) { + ASSERT_TRUE(CreateTestClients()); + LocalP2PTest(); + // Reset the RtpReceiverObservers. + initializing_client()->SetRtpReceiverObservers(); + receiving_client()->SetRtpReceiverObservers(); + EXPECT_TRUE_WAIT( + AllObserversReceived(initializing_client()->rtp_receiver_observers()), + kMaxWaitForFramesMs); + EXPECT_TRUE_WAIT( + AllObserversReceived(receiving_client()->rtp_receiver_observers()), + kMaxWaitForFramesMs); +} + // This test sets up a Jsep call between two parties and test Dtmf. // TODO(holmer): Disabled due to sometimes crashing on buildbots. // See issue webrtc/2378. diff --git a/webrtc/api/rtpreceiver.cc b/webrtc/api/rtpreceiver.cc index 9df336e1f0..882bc2be8d 100644 --- a/webrtc/api/rtpreceiver.cc +++ b/webrtc/api/rtpreceiver.cc @@ -35,6 +35,8 @@ AudioRtpReceiver::AudioRtpReceiver(MediaStreamInterface* stream, track_->GetSource()->RegisterAudioObserver(this); Reconfigure(); stream->AddTrack(track_); + provider_->SignalFirstAudioPacketReceived.connect( + this, &AudioRtpReceiver::OnFirstAudioPacketReceived); } AudioRtpReceiver::~AudioRtpReceiver() { @@ -83,6 +85,22 @@ void AudioRtpReceiver::Reconfigure() { provider_->SetAudioPlayout(ssrc_, track_->enabled()); } +void AudioRtpReceiver::SetObserver(RtpReceiverObserverInterface* observer) { + observer_ = observer; + // If received the first packet before setting the observer, call the + // observer. + if (received_first_packet_) { + observer_->OnFirstPacketReceived(media_type()); + } +} + +void AudioRtpReceiver::OnFirstAudioPacketReceived() { + if (observer_) { + observer_->OnFirstPacketReceived(media_type()); + } + received_first_packet_ = true; +} + VideoRtpReceiver::VideoRtpReceiver(MediaStreamInterface* stream, const std::string& track_id, rtc::Thread* worker_thread, @@ -104,6 +122,8 @@ VideoRtpReceiver::VideoRtpReceiver(MediaStreamInterface* stream, source_->SetState(MediaSourceInterface::kLive); provider_->SetVideoPlayout(ssrc_, true, &broadcaster_); stream->AddTrack(track_); + provider_->SignalFirstVideoPacketReceived.connect( + this, &VideoRtpReceiver::OnFirstVideoPacketReceived); } VideoRtpReceiver::~VideoRtpReceiver() { @@ -132,4 +152,20 @@ void VideoRtpReceiver::Stop() { provider_ = nullptr; } +void VideoRtpReceiver::SetObserver(RtpReceiverObserverInterface* observer) { + observer_ = observer; + // If received the first packet before setting the observer, call the + // observer. + if (received_first_packet_) { + observer_->OnFirstPacketReceived(media_type()); + } +} + +void VideoRtpReceiver::OnFirstVideoPacketReceived() { + if (observer_) { + observer_->OnFirstPacketReceived(media_type()); + } + received_first_packet_ = true; +} + } // namespace webrtc diff --git a/webrtc/api/rtpreceiver.h b/webrtc/api/rtpreceiver.h index 001264d7a7..3b1fd926cb 100644 --- a/webrtc/api/rtpreceiver.h +++ b/webrtc/api/rtpreceiver.h @@ -22,6 +22,7 @@ #include "webrtc/api/remoteaudiosource.h" #include "webrtc/api/videotracksource.h" #include "webrtc/base/basictypes.h" +#include "webrtc/base/sigslot.h" #include "webrtc/media/base/videobroadcaster.h" namespace webrtc { @@ -34,7 +35,8 @@ class RtpReceiverInternal : public RtpReceiverInterface { class AudioRtpReceiver : public ObserverInterface, public AudioSourceInterface::AudioObserver, - public rtc::RefCountedObject { + public rtc::RefCountedObject, + public sigslot::has_slots<> { public: AudioRtpReceiver(MediaStreamInterface* stream, const std::string& track_id, @@ -66,17 +68,25 @@ class AudioRtpReceiver : public ObserverInterface, // RtpReceiverInternal implementation. void Stop() override; + void SetObserver(RtpReceiverObserverInterface* observer) override; + + cricket::MediaType media_type() override { return cricket::MEDIA_TYPE_AUDIO; } + private: void Reconfigure(); + void OnFirstAudioPacketReceived(); const std::string id_; const uint32_t ssrc_; AudioProviderInterface* provider_; // Set to null in Stop(). const rtc::scoped_refptr track_; bool cached_track_enabled_; + RtpReceiverObserverInterface* observer_ = nullptr; + bool received_first_packet_ = false; }; -class VideoRtpReceiver : public rtc::RefCountedObject { +class VideoRtpReceiver : public rtc::RefCountedObject, + public sigslot::has_slots<> { public: VideoRtpReceiver(MediaStreamInterface* stream, const std::string& track_id, @@ -103,7 +113,13 @@ class VideoRtpReceiver : public rtc::RefCountedObject { // RtpReceiverInternal implementation. void Stop() override; + void SetObserver(RtpReceiverObserverInterface* observer) override; + + cricket::MediaType media_type() override { return cricket::MEDIA_TYPE_VIDEO; } + private: + void OnFirstVideoPacketReceived(); + std::string id_; uint32_t ssrc_; VideoProviderInterface* provider_; @@ -115,6 +131,8 @@ class VideoRtpReceiver : public rtc::RefCountedObject { // the VideoRtpReceiver is stopped. rtc::scoped_refptr source_; rtc::scoped_refptr track_; + RtpReceiverObserverInterface* observer_ = nullptr; + bool received_first_packet_ = false; }; } // namespace webrtc diff --git a/webrtc/api/rtpreceiverinterface.h b/webrtc/api/rtpreceiverinterface.h index 49888381e1..4943023111 100644 --- a/webrtc/api/rtpreceiverinterface.h +++ b/webrtc/api/rtpreceiverinterface.h @@ -20,9 +20,18 @@ #include "webrtc/api/proxy.h" #include "webrtc/base/refcount.h" #include "webrtc/base/scoped_ref_ptr.h" +#include "webrtc/pc/mediasession.h" namespace webrtc { +class RtpReceiverObserverInterface { + public: + virtual void OnFirstPacketReceived(cricket::MediaType media_type) = 0; + + protected: + virtual ~RtpReceiverObserverInterface() {} +}; + class RtpReceiverInterface : public rtc::RefCountInterface { public: virtual rtc::scoped_refptr track() const = 0; @@ -37,6 +46,10 @@ class RtpReceiverInterface : public rtc::RefCountInterface { virtual RtpParameters GetParameters() const = 0; virtual bool SetParameters(const RtpParameters& parameters) = 0; + virtual void SetObserver(RtpReceiverObserverInterface* observer) = 0; + + virtual cricket::MediaType media_type() = 0; + protected: virtual ~RtpReceiverInterface() {} }; @@ -47,6 +60,8 @@ PROXY_CONSTMETHOD0(rtc::scoped_refptr, track) PROXY_CONSTMETHOD0(std::string, id) PROXY_CONSTMETHOD0(RtpParameters, GetParameters); PROXY_METHOD1(bool, SetParameters, const RtpParameters&) +PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*); +PROXY_METHOD0(cricket::MediaType, media_type); END_SIGNALING_PROXY() } // namespace webrtc diff --git a/webrtc/api/webrtcsession.cc b/webrtc/api/webrtcsession.cc index a7c712c6a1..b9a3fc8453 100644 --- a/webrtc/api/webrtcsession.cc +++ b/webrtc/api/webrtcsession.cc @@ -1767,6 +1767,8 @@ bool WebRtcSession::CreateVoiceChannel(const cricket::ContentInfo* content, voice_channel_->SignalDtlsSetupFailure.connect( this, &WebRtcSession::OnDtlsSetupFailure); + voice_channel_->SignalFirstPacketReceived.connect( + this, &WebRtcSession::OnChannelFirstPacketReceived); SignalVoiceChannelCreated(); voice_channel_->SignalSentPacket.connect(this, @@ -1790,6 +1792,8 @@ bool WebRtcSession::CreateVideoChannel(const cricket::ContentInfo* content, } video_channel_->SignalDtlsSetupFailure.connect( this, &WebRtcSession::OnDtlsSetupFailure); + video_channel_->SignalFirstPacketReceived.connect( + this, &WebRtcSession::OnChannelFirstPacketReceived); SignalVideoChannelCreated(); video_channel_->SignalSentPacket.connect(this, @@ -1831,6 +1835,21 @@ void WebRtcSession::OnDtlsSetupFailure(cricket::BaseChannel*, bool rtcp) { rtcp ? kDtlsSetupFailureRtcp : kDtlsSetupFailureRtp); } +void WebRtcSession::OnChannelFirstPacketReceived( + cricket::BaseChannel* channel) { + ASSERT(signaling_thread()->IsCurrent()); + + if (!received_first_audio_packet_ && + channel->media_type() == cricket::MEDIA_TYPE_AUDIO) { + received_first_audio_packet_ = true; + SignalFirstAudioPacketReceived(); + } else if (!received_first_video_packet_ && + channel->media_type() == cricket::MEDIA_TYPE_VIDEO) { + received_first_video_packet_ = true; + SignalFirstVideoPacketReceived(); + } +} + void WebRtcSession::OnDataChannelMessageReceived( cricket::DataChannel* channel, const cricket::ReceiveDataParams& params, diff --git a/webrtc/api/webrtcsession.h b/webrtc/api/webrtcsession.h index 9ba7605e67..76af6c7c3d 100644 --- a/webrtc/api/webrtcsession.h +++ b/webrtc/api/webrtcsession.h @@ -310,6 +310,8 @@ class WebRtcSession : public AudioProviderInterface, void OnCertificateReady( const rtc::scoped_refptr& certificate); void OnDtlsSetupFailure(cricket::BaseChannel*, bool rtcp); + // Called when the channel received the first packet. + void OnChannelFirstPacketReceived(cricket::BaseChannel*); // For unit test. bool waiting_for_certificate_for_testing() const; @@ -527,6 +529,9 @@ class WebRtcSession : public AudioProviderInterface, // Declares the RTCP mux policy for the WebRTCSession. PeerConnectionInterface::RtcpMuxPolicy rtcp_mux_policy_; + bool received_first_video_packet_ = false; + bool received_first_audio_packet_ = false; + RTC_DISALLOW_COPY_AND_ASSIGN(WebRtcSession); }; } // namespace webrtc diff --git a/webrtc/pc/channel.h b/webrtc/pc/channel.h index 5dca31804d..211f810b85 100644 --- a/webrtc/pc/channel.h +++ b/webrtc/pc/channel.h @@ -168,6 +168,8 @@ class BaseChannel SrtpFilter* srtp_filter() { return &srtp_filter_; } + virtual cricket::MediaType media_type() = 0; + protected: virtual MediaChannel* media_channel() const { return media_channel_; } // Sets the |transport_channel_| (and |rtcp_transport_channel_|, if |rtcp_| is @@ -436,6 +438,7 @@ class VoiceChannel : public BaseChannel { webrtc::RtpParameters GetRtpReceiveParameters_w(uint32_t ssrc) const; bool SetRtpReceiveParameters_w(uint32_t ssrc, webrtc::RtpParameters parameters); + cricket::MediaType media_type() override { return cricket::MEDIA_TYPE_AUDIO; } private: // overrides from BaseChannel @@ -520,6 +523,7 @@ class VideoChannel : public BaseChannel { webrtc::RtpParameters GetRtpReceiveParameters(uint32_t ssrc) const; bool SetRtpReceiveParameters(uint32_t ssrc, const webrtc::RtpParameters& parameters); + cricket::MediaType media_type() override { return cricket::MEDIA_TYPE_VIDEO; } private: // overrides from BaseChannel @@ -591,6 +595,7 @@ class DataChannel : public BaseChannel { sigslot::signal1 SignalReadyToSendData; // Signal for notifying that the remote side has closed the DataChannel. sigslot::signal1 SignalStreamClosedRemotely; + cricket::MediaType media_type() override { return cricket::MEDIA_TYPE_DATA; } protected: // downcasts a MediaChannel.