diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc index b13d5e169d..78b832ff3c 100644 --- a/talk/session/media/channel.cc +++ b/talk/session/media/channel.cc @@ -569,7 +569,7 @@ void BaseChannel::HandlePacket(bool rtcp, talk_base::Buffer* packet, return; } - if (!has_received_packet_) { + if (!has_received_packet_ && !rtcp) { has_received_packet_ = true; signaling_thread()->Post(this, MSG_FIRSTPACKETRECEIVED); } diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h index 2aec552f72..2e4eaf3891 100644 --- a/talk/session/media/channel.h +++ b/talk/session/media/channel.h @@ -222,7 +222,7 @@ class BaseChannel return remote_streams_; } - // Used for latency measurements. + // Used for measuring the latency of the first media packet. sigslot::signal1 SignalFirstPacketReceived; // Used to alert UI when the muted status changes, perhaps autonomously. diff --git a/talk/session/media/channel_unittest.cc b/talk/session/media/channel_unittest.cc index 6e88fd284c..17d3bc7429 100644 --- a/talk/session/media/channel_unittest.cc +++ b/talk/session/media/channel_unittest.cc @@ -181,6 +181,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { media_info_callbacks2_(), mute_callback_recved_(false), mute_callback_value_(false), + first_packet_received_on_channel1_(0), + first_packet_received_on_channel2_(0), ssrc_(0), error_(T::MediaChannel::ERROR_NONE) { } @@ -234,6 +236,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { this, &ChannelTest::OnMediaChannelError); channel1_->SignalAutoMuted.connect( this, &ChannelTest::OnMediaMuted); + channel1_->SignalFirstPacketReceived.connect( + this, &ChannelTest::OnFirstPacketReceived); + channel2_->SignalFirstPacketReceived.connect( + this, &ChannelTest::OnFirstPacketReceived); if ((flags1 & DTLS) && (flags2 & DTLS)) { flags1 = (flags1 & ~SECURE); flags2 = (flags2 & ~SECURE); @@ -285,6 +291,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { this, &ChannelTest::OnMediaMonitor); channel2_->SignalMediaError.connect( this, &ChannelTest::OnMediaChannelError); + channel1_->SignalFirstPacketReceived.connect( + this, &ChannelTest::OnFirstPacketReceived); + channel2_->SignalFirstPacketReceived.connect( + this, &ChannelTest::OnFirstPacketReceived); CreateContent(flags, kPcmuCodec, kH264Codec, &local_media_content1_); CreateContent(flags, kPcmuCodec, kH264Codec, @@ -573,6 +583,14 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { error_ = error; } + void OnFirstPacketReceived(cricket::BaseChannel* channel) { + if (channel == channel1_.get()) { + first_packet_received_on_channel1_++; + } else if (channel == channel2_.get()) { + first_packet_received_on_channel2_++; + } + } + void OnMediaMuted(cricket::BaseChannel* channel, bool muted) { mute_callback_recved_ = true; mute_callback_value_ = muted; @@ -1344,26 +1362,38 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { // Test that we properly send RTP without SRTP from a thread. void SendRtpToRtpOnThread() { - bool sent_rtp1, sent_rtp2, sent_rtcp1, sent_rtcp2; - CreateChannels(RTCP, RTCP); + bool sent_rtp1, sent_rtp2; + CreateChannels(0, 0); EXPECT_TRUE(SendInitiate()); EXPECT_TRUE(SendAccept()); CallOnThread(&ChannelTest::SendRtp1, &sent_rtp1); CallOnThread(&ChannelTest::SendRtp2, &sent_rtp2); - CallOnThread(&ChannelTest::SendRtcp1, &sent_rtcp1); - CallOnThread(&ChannelTest::SendRtcp2, &sent_rtcp2); EXPECT_TRUE_WAIT(CheckRtp1(), 1000); EXPECT_TRUE_WAIT(CheckRtp2(), 1000); EXPECT_TRUE_WAIT(sent_rtp1, 1000); EXPECT_TRUE_WAIT(sent_rtp2, 1000); EXPECT_TRUE(CheckNoRtp1()); EXPECT_TRUE(CheckNoRtp2()); + EXPECT_EQ(1, first_packet_received_on_channel1_); + EXPECT_EQ(1, first_packet_received_on_channel2_); + } + + // Test that we properly send RTCP without SRTP from a thread. + void SendRtcpToRtcpOnThread() { + bool sent_rtcp1, sent_rtcp2; + CreateChannels(RTCP, RTCP); + EXPECT_TRUE(SendInitiate()); + EXPECT_TRUE(SendAccept()); + CallOnThread(&ChannelTest::SendRtcp1, &sent_rtcp1); + CallOnThread(&ChannelTest::SendRtcp2, &sent_rtcp2); EXPECT_TRUE_WAIT(CheckRtcp1(), 1000); EXPECT_TRUE_WAIT(CheckRtcp2(), 1000); EXPECT_TRUE_WAIT(sent_rtcp1, 1000); EXPECT_TRUE_WAIT(sent_rtcp2, 1000); EXPECT_TRUE(CheckNoRtcp1()); EXPECT_TRUE(CheckNoRtcp2()); + EXPECT_EQ(0, first_packet_received_on_channel1_); + EXPECT_EQ(0, first_packet_received_on_channel2_); } // Test that we properly send SRTP with RTCP from a thread. @@ -1869,6 +1899,10 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { int media_info_callbacks2_; bool mute_callback_recved_; bool mute_callback_value_; + // They are implemented as counters to make sure that + // SignalFirstPacketReceived is only fired at most once on each channel. + int first_packet_received_on_channel1_; + int first_packet_received_on_channel2_; uint32 ssrc_; typename T::MediaChannel::Error error_; @@ -2168,6 +2202,10 @@ TEST_F(VoiceChannelTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } +TEST_F(VoiceChannelTest, SendRtcpToRtcpOnThread) { + Base::SendRtcpToRtcpOnThread(); +} + TEST_F(VoiceChannelTest, SendSrtpToSrtpOnThread) { Base::SendSrtpToSrtpOnThread(); } @@ -2587,6 +2625,10 @@ TEST_F(VideoChannelTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } +TEST_F(VideoChannelTest, SendRtcpToRtcpOnThread) { + Base::SendRtcpToRtcpOnThread(); +} + TEST_F(VideoChannelTest, SendSrtpToSrtpOnThread) { Base::SendSrtpToSrtpOnThread(); } @@ -2898,6 +2940,10 @@ TEST_F(DataChannelTest, SendRtpToRtpOnThread) { Base::SendRtpToRtpOnThread(); } +TEST_F(DataChannelTest, SendRtcpToRtcpOnThread) { + Base::SendRtcpToRtcpOnThread(); +} + TEST_F(DataChannelTest, SendSrtpToSrtpOnThread) { Base::SendSrtpToSrtpOnThread(); }