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}
diff --git a/webrtc/api/mediastreamprovider.h b/webrtc/api/mediastreamprovider.h
index b508c39..784a954 100644
--- a/webrtc/api/mediastreamprovider.h
+++ b/webrtc/api/mediastreamprovider.h
@@ -72,6 +72,9 @@
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 @@
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 20cd7a6..4b06b90 100644
--- a/webrtc/api/peerconnection_unittest.cc
+++ b/webrtc/api/peerconnection_unittest.cc
@@ -146,6 +146,25 @@
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 @@
return pc()->ice_gathering_state();
}
+ std::vector<std::unique_ptr<MockRtpReceiverObserver>> const&
+ rtp_receiver_observers() {
+ return rtp_receiver_observers_;
+ }
+
+ void SetRtpReceiverObservers() {
+ rtp_receiver_observers_.clear();
+ for (auto receiver : pc()->GetReceivers()) {
+ std::unique_ptr<MockRtpReceiverObserver> 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 @@
std::unique_ptr<SessionDescriptionInterface> desc(
webrtc::CreateSessionDescription("offer", msg, nullptr));
EXPECT_TRUE(DoSetRemoteDescription(desc.release()));
+ // Set the RtpReceiverObserver after receivers are created.
+ SetRtpReceiverObservers();
std::unique_ptr<SessionDescriptionInterface> answer;
EXPECT_TRUE(DoCreateAnswer(&answer));
std::string sdp;
@@ -886,6 +922,8 @@
std::unique_ptr<SessionDescriptionInterface> desc(
webrtc::CreateSessionDescription("answer", msg, nullptr));
EXPECT_TRUE(DoSetRemoteDescription(desc.release()));
+ // Set the RtpReceiverObserver after receivers are created.
+ SetRtpReceiverObservers();
}
bool DoCreateOfferAnswer(std::unique_ptr<SessionDescriptionInterface>* desc,
@@ -1026,6 +1064,8 @@
rtc::scoped_refptr<DataChannelInterface> data_channel_;
std::unique_ptr<MockDataChannelObserver> data_observer_;
+
+ std::vector<std::unique_ptr<MockRtpReceiverObserver>> rtp_receiver_observers_;
};
class P2PTestConductor : public testing::Test {
@@ -1314,6 +1354,16 @@
return old;
}
+ bool AllObserversReceived(
+ const std::vector<std::unique_ptr<MockRtpReceiverObserver>>& 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<rtc::PhysicalSocketServer> pss_;
@@ -1332,6 +1382,33 @@
// 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 9df336e..882bc2b 100644
--- a/webrtc/api/rtpreceiver.cc
+++ b/webrtc/api/rtpreceiver.cc
@@ -35,6 +35,8 @@
track_->GetSource()->RegisterAudioObserver(this);
Reconfigure();
stream->AddTrack(track_);
+ provider_->SignalFirstAudioPacketReceived.connect(
+ this, &AudioRtpReceiver::OnFirstAudioPacketReceived);
}
AudioRtpReceiver::~AudioRtpReceiver() {
@@ -83,6 +85,22 @@
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 @@
source_->SetState(MediaSourceInterface::kLive);
provider_->SetVideoPlayout(ssrc_, true, &broadcaster_);
stream->AddTrack(track_);
+ provider_->SignalFirstVideoPacketReceived.connect(
+ this, &VideoRtpReceiver::OnFirstVideoPacketReceived);
}
VideoRtpReceiver::~VideoRtpReceiver() {
@@ -132,4 +152,20 @@
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 001264d..3b1fd92 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 AudioRtpReceiver : public ObserverInterface,
public AudioSourceInterface::AudioObserver,
- public rtc::RefCountedObject<RtpReceiverInternal> {
+ public rtc::RefCountedObject<RtpReceiverInternal>,
+ public sigslot::has_slots<> {
public:
AudioRtpReceiver(MediaStreamInterface* stream,
const std::string& track_id,
@@ -66,17 +68,25 @@
// 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<AudioTrackInterface> track_;
bool cached_track_enabled_;
+ RtpReceiverObserverInterface* observer_ = nullptr;
+ bool received_first_packet_ = false;
};
-class VideoRtpReceiver : public rtc::RefCountedObject<RtpReceiverInternal> {
+class VideoRtpReceiver : public rtc::RefCountedObject<RtpReceiverInternal>,
+ public sigslot::has_slots<> {
public:
VideoRtpReceiver(MediaStreamInterface* stream,
const std::string& track_id,
@@ -103,7 +113,13 @@
// 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 @@
// the VideoRtpReceiver is stopped.
rtc::scoped_refptr<VideoTrackSource> source_;
rtc::scoped_refptr<VideoTrackInterface> track_;
+ RtpReceiverObserverInterface* observer_ = nullptr;
+ bool received_first_packet_ = false;
};
} // namespace webrtc
diff --git a/webrtc/api/rtpreceiverinterface.h b/webrtc/api/rtpreceiverinterface.h
index 4988838..4943023 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<MediaStreamTrackInterface> track() const = 0;
@@ -37,6 +46,10 @@
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(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 a7c712c..b9a3fc8 100644
--- a/webrtc/api/webrtcsession.cc
+++ b/webrtc/api/webrtcsession.cc
@@ -1767,6 +1767,8 @@
voice_channel_->SignalDtlsSetupFailure.connect(
this, &WebRtcSession::OnDtlsSetupFailure);
+ voice_channel_->SignalFirstPacketReceived.connect(
+ this, &WebRtcSession::OnChannelFirstPacketReceived);
SignalVoiceChannelCreated();
voice_channel_->SignalSentPacket.connect(this,
@@ -1790,6 +1792,8 @@
}
video_channel_->SignalDtlsSetupFailure.connect(
this, &WebRtcSession::OnDtlsSetupFailure);
+ video_channel_->SignalFirstPacketReceived.connect(
+ this, &WebRtcSession::OnChannelFirstPacketReceived);
SignalVideoChannelCreated();
video_channel_->SignalSentPacket.connect(this,
@@ -1831,6 +1835,21 @@
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 9ba7605..76af6c7 100644
--- a/webrtc/api/webrtcsession.h
+++ b/webrtc/api/webrtcsession.h
@@ -310,6 +310,8 @@
void OnCertificateReady(
const rtc::scoped_refptr<rtc::RTCCertificate>& 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 @@
// 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