Fix RtpReceiver.GetParameters when SSRCs aren't signaled.
When SSRCs aren't signaled, an SSRC of 0 is used internally to mean
"the default receive stream". But this wasn't working with the
implementation of GetRtpReceiveParameters in the audio/video
engines. This was breaking RtpReceiver.GetParameters in this situation,
as well as the new getStats implementation (which relies on
GetParameters).
The new implementation will fail if *no* default receive stream is
configured (meaning no default sink is set), and otherwise will return
a default RtpEncodingParameters (later it will be filled with relevant
SDP parameters as they're implemented).
BUG=webrtc:6971
Review-Url: https://codereview.webrtc.org/2806173002
Cr-Original-Commit-Position: refs/heads/master@{#17803}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 3bc15103aea1dd2fdfc01b833b62f34171c82e81
diff --git a/media/base/mediachannel.h b/media/base/mediachannel.h
index ca02c72..6f14b7a 100644
--- a/media/base/mediachannel.h
+++ b/media/base/mediachannel.h
@@ -973,6 +973,11 @@
virtual bool SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) = 0;
+ // Get the receive parameters for the incoming stream identified by |ssrc|.
+ // If |ssrc| is 0, retrieve the receive parameters for the default receive
+ // stream, which is used when SSRCs are not signaled. Note that calling with
+ // an |ssrc| of 0 will return encoding parameters with an unset |ssrc|
+ // member.
virtual webrtc::RtpParameters GetRtpReceiveParameters(
uint32_t ssrc) const = 0;
virtual bool SetRtpReceiveParameters(
@@ -1053,6 +1058,11 @@
virtual bool SetRtpSendParameters(
uint32_t ssrc,
const webrtc::RtpParameters& parameters) = 0;
+ // Get the receive parameters for the incoming stream identified by |ssrc|.
+ // If |ssrc| is 0, retrieve the receive parameters for the default receive
+ // stream, which is used when SSRCs are not signaled. Note that calling with
+ // an |ssrc| of 0 will return encoding parameters with an unset |ssrc|
+ // member.
virtual webrtc::RtpParameters GetRtpReceiveParameters(
uint32_t ssrc) const = 0;
virtual bool SetRtpReceiveParameters(
@@ -1070,7 +1080,7 @@
const VideoOptions* options,
rtc::VideoSourceInterface<webrtc::VideoFrame>* source) = 0;
// Sets the sink object to be used for the specified stream.
- // If SSRC is 0, the renderer is used for the 'default' stream.
+ // If SSRC is 0, the sink is used for the 'default' stream.
virtual bool SetSink(uint32_t ssrc,
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) = 0;
// Gets quality stats for the channel.
diff --git a/media/engine/webrtcvideoengine2.cc b/media/engine/webrtcvideoengine2.cc
index 087fc4e..e92598d 100644
--- a/media/engine/webrtcvideoengine2.cc
+++ b/media/engine/webrtcvideoengine2.cc
@@ -865,20 +865,33 @@
webrtc::RtpParameters WebRtcVideoChannel2::GetRtpReceiveParameters(
uint32_t ssrc) const {
+ webrtc::RtpParameters rtp_params;
rtc::CritScope stream_lock(&stream_crit_);
- auto it = receive_streams_.find(ssrc);
- if (it == receive_streams_.end()) {
- LOG(LS_WARNING) << "Attempting to get RTP receive parameters for stream "
- << "with ssrc " << ssrc << " which doesn't exist.";
- return webrtc::RtpParameters();
+ // SSRC of 0 represents an unsignaled receive stream.
+ if (ssrc == 0) {
+ if (!default_unsignalled_ssrc_handler_.GetDefaultSink()) {
+ LOG(LS_WARNING) << "Attempting to get RTP parameters for the default, "
+ "unsignaled video receive stream, but not yet "
+ "configured to receive such a stream.";
+ return rtp_params;
+ }
+ rtp_params.encodings.emplace_back();
+ } else {
+ auto it = receive_streams_.find(ssrc);
+ if (it == receive_streams_.end()) {
+ LOG(LS_WARNING) << "Attempting to get RTP receive parameters for stream "
+ << "with SSRC " << ssrc << " which doesn't exist.";
+ return webrtc::RtpParameters();
+ }
+ // TODO(deadbeef): Return stream-specific parameters, beyond just SSRC.
+ rtp_params.encodings.emplace_back();
+ rtp_params.encodings[0].ssrc = it->second->GetFirstPrimarySsrc();
}
- // TODO(deadbeef): Return stream-specific parameters.
- webrtc::RtpParameters rtp_params = CreateRtpParametersWithOneEncoding();
+ // Add codecs, which any stream is prepared to receive.
for (const VideoCodec& codec : recv_params_.codecs) {
rtp_params.codecs.push_back(codec.ToCodecParameters());
}
- rtp_params.encodings[0].ssrc = it->second->GetFirstPrimarySsrc();
return rtp_params;
}
@@ -887,11 +900,22 @@
const webrtc::RtpParameters& parameters) {
TRACE_EVENT0("webrtc", "WebRtcVideoChannel2::SetRtpReceiveParameters");
rtc::CritScope stream_lock(&stream_crit_);
- auto it = receive_streams_.find(ssrc);
- if (it == receive_streams_.end()) {
- LOG(LS_ERROR) << "Attempting to set RTP receive parameters for stream "
- << "with ssrc " << ssrc << " which doesn't exist.";
- return false;
+
+ // SSRC of 0 represents an unsignaled receive stream.
+ if (ssrc == 0) {
+ if (!default_unsignalled_ssrc_handler_.GetDefaultSink()) {
+ LOG(LS_WARNING) << "Attempting to set RTP parameters for the default, "
+ "unsignaled video receive stream, but not yet "
+ "configured to receive such a stream.";
+ return false;
+ }
+ } else {
+ auto it = receive_streams_.find(ssrc);
+ if (it == receive_streams_.end()) {
+ LOG(LS_WARNING) << "Attempting to set RTP receive parameters for stream "
+ << "with SSRC " << ssrc << " which doesn't exist.";
+ return false;
+ }
}
webrtc::RtpParameters current_parameters = GetRtpReceiveParameters(ssrc);
diff --git a/media/engine/webrtcvideoengine2.h b/media/engine/webrtcvideoengine2.h
index 0a2f4a5..2c7d36c 100644
--- a/media/engine/webrtcvideoengine2.h
+++ b/media/engine/webrtcvideoengine2.h
@@ -83,6 +83,9 @@
rtc::VideoSinkInterface<webrtc::VideoFrame>* GetDefaultSink() const;
void SetDefaultSink(VideoMediaChannel* channel,
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink);
+
+ uint32_t default_recv_ssrc() const { return default_recv_ssrc_; }
+
virtual ~DefaultUnsignalledSsrcHandler() = default;
private:
diff --git a/media/engine/webrtcvideoengine2_unittest.cc b/media/engine/webrtcvideoengine2_unittest.cc
index 37e227f..40d1a3f 100644
--- a/media/engine/webrtcvideoengine2_unittest.cc
+++ b/media/engine/webrtcvideoengine2_unittest.cc
@@ -4136,6 +4136,49 @@
EXPECT_EQ(initial_params, channel_->GetRtpReceiveParameters(last_ssrc_));
}
+// Test that GetRtpReceiveParameters returns parameters correctly when SSRCs
+// aren't signaled. It should always return an empty "RtpEncodingParameters",
+// even after a packet is received and the unsignaled SSRC is known.
+TEST_F(WebRtcVideoChannel2Test, GetRtpReceiveParametersWithUnsignaledSsrc) {
+ // Call necessary methods to configure receiving a default stream as
+ // soon as it arrives.
+ cricket::VideoRecvParameters parameters;
+ parameters.codecs.push_back(GetEngineCodec("VP8"));
+ parameters.codecs.push_back(GetEngineCodec("VP9"));
+ EXPECT_TRUE(channel_->SetRecvParameters(parameters));
+
+ // Call GetRtpReceiveParameters before configured to receive an unsignaled
+ // stream. Should return nothing.
+ EXPECT_EQ(webrtc::RtpParameters(), channel_->GetRtpReceiveParameters(0));
+
+ // Set a sink for an unsignaled stream.
+ cricket::FakeVideoRenderer renderer;
+ // Value of "0" means "unsignaled stream".
+ EXPECT_TRUE(channel_->SetSink(0, &renderer));
+
+ // Call GetRtpReceiveParameters before the SSRC is known. Value of "0"
+ // in this method means "unsignaled stream".
+ webrtc::RtpParameters rtp_parameters = channel_->GetRtpReceiveParameters(0);
+ ASSERT_EQ(1u, rtp_parameters.encodings.size());
+ EXPECT_FALSE(rtp_parameters.encodings[0].ssrc);
+
+ // Receive VP8 packet.
+ uint8_t data[kMinRtpPacketLen];
+ cricket::RtpHeader rtpHeader;
+ rtpHeader.payload_type = GetEngineCodec("VP8").id;
+ rtpHeader.seq_num = rtpHeader.timestamp = 0;
+ rtpHeader.ssrc = kIncomingUnsignalledSsrc;
+ cricket::SetRtpHeader(data, sizeof(data), rtpHeader);
+ rtc::CopyOnWriteBuffer packet(data, sizeof(data));
+ rtc::PacketTime packet_time;
+ channel_->OnPacketReceived(&packet, packet_time);
+
+ // The |ssrc| member should still be unset.
+ rtp_parameters = channel_->GetRtpReceiveParameters(0);
+ ASSERT_EQ(1u, rtp_parameters.encodings.size());
+ EXPECT_FALSE(rtp_parameters.encodings[0].ssrc);
+}
+
void WebRtcVideoChannel2Test::TestReceiverLocalSsrcConfiguration(
bool receiver_first) {
EXPECT_TRUE(channel_->SetSendParameters(send_parameters_));
diff --git a/media/engine/webrtcvoiceengine.cc b/media/engine/webrtcvoiceengine.cc
index 4aa97e0..2384ac2 100644
--- a/media/engine/webrtcvoiceengine.cc
+++ b/media/engine/webrtcvoiceengine.cc
@@ -1755,19 +1755,31 @@
webrtc::RtpParameters WebRtcVoiceMediaChannel::GetRtpReceiveParameters(
uint32_t ssrc) const {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- auto it = recv_streams_.find(ssrc);
- if (it == recv_streams_.end()) {
- LOG(LS_WARNING) << "Attempting to get RTP receive parameters for stream "
- << "with ssrc " << ssrc << " which doesn't exist.";
- return webrtc::RtpParameters();
+ webrtc::RtpParameters rtp_params;
+ // SSRC of 0 represents the default receive stream.
+ if (ssrc == 0) {
+ if (!default_sink_) {
+ LOG(LS_WARNING) << "Attempting to get RTP parameters for the default, "
+ "unsignaled audio receive stream, but not yet "
+ "configured to receive such a stream.";
+ return rtp_params;
+ }
+ rtp_params.encodings.emplace_back();
+ } else {
+ auto it = recv_streams_.find(ssrc);
+ if (it == recv_streams_.end()) {
+ LOG(LS_WARNING) << "Attempting to get RTP receive parameters for stream "
+ << "with ssrc " << ssrc << " which doesn't exist.";
+ return webrtc::RtpParameters();
+ }
+ rtp_params.encodings.emplace_back();
+ // TODO(deadbeef): Return stream-specific parameters.
+ rtp_params.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
}
- // TODO(deadbeef): Return stream-specific parameters.
- webrtc::RtpParameters rtp_params = CreateRtpParametersWithOneEncoding();
for (const AudioCodec& codec : recv_codecs_) {
rtp_params.codecs.push_back(codec.ToCodecParameters());
}
- rtp_params.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
return rtp_params;
}
@@ -1775,11 +1787,21 @@
uint32_t ssrc,
const webrtc::RtpParameters& parameters) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- auto it = recv_streams_.find(ssrc);
- if (it == recv_streams_.end()) {
- LOG(LS_WARNING) << "Attempting to set RTP receive parameters for stream "
- << "with ssrc " << ssrc << " which doesn't exist.";
- return false;
+ // SSRC of 0 represents the default receive stream.
+ if (ssrc == 0) {
+ if (!default_sink_) {
+ LOG(LS_WARNING) << "Attempting to set RTP parameters for the default, "
+ "unsignaled audio receive stream, but not yet "
+ "configured to receive such a stream.";
+ return false;
+ }
+ } else {
+ auto it = recv_streams_.find(ssrc);
+ if (it == recv_streams_.end()) {
+ LOG(LS_WARNING) << "Attempting to set RTP receive parameters for stream "
+ << "with ssrc " << ssrc << " which doesn't exist.";
+ return false;
+ }
}
webrtc::RtpParameters current_parameters = GetRtpReceiveParameters(ssrc);
@@ -2320,6 +2342,7 @@
bool WebRtcVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
std::vector<uint32_t> ssrcs(1, ssrc);
+ // SSRC of 0 represents the default receive stream.
if (ssrc == 0) {
default_recv_volume_ = volume;
ssrcs = unsignaled_recv_ssrcs_;
diff --git a/media/engine/webrtcvoiceengine_unittest.cc b/media/engine/webrtcvoiceengine_unittest.cc
index f9a631c..75b6320 100644
--- a/media/engine/webrtcvoiceengine_unittest.cc
+++ b/media/engine/webrtcvoiceengine_unittest.cc
@@ -1238,6 +1238,43 @@
EXPECT_EQ(initial_params, channel_->GetRtpReceiveParameters(kSsrcX));
}
+// Test that GetRtpReceiveParameters returns parameters correctly when SSRCs
+// aren't signaled. It should return an empty "RtpEncodingParameters" when
+// configured to receive an unsignaled stream and no packets have been received
+// yet, and start returning the SSRC once a packet has been received.
+TEST_F(WebRtcVoiceEngineTestFake, GetRtpReceiveParametersWithUnsignaledSsrc) {
+ ASSERT_TRUE(SetupChannel());
+ // Call necessary methods to configure receiving a default stream as
+ // soon as it arrives.
+ cricket::AudioRecvParameters parameters;
+ parameters.codecs.push_back(kIsacCodec);
+ parameters.codecs.push_back(kPcmuCodec);
+ EXPECT_TRUE(channel_->SetRecvParameters(parameters));
+
+ // Call GetRtpReceiveParameters before configured to receive an unsignaled
+ // stream. Should return nothing.
+ EXPECT_EQ(webrtc::RtpParameters(), channel_->GetRtpReceiveParameters(0));
+
+ // Set a sink for an unsignaled stream.
+ std::unique_ptr<FakeAudioSink> fake_sink(new FakeAudioSink());
+ // Value of "0" means "unsignaled stream".
+ channel_->SetRawAudioSink(0, std::move(fake_sink));
+
+ // Call GetRtpReceiveParameters before the SSRC is known. Value of "0"
+ // in this method means "unsignaled stream".
+ webrtc::RtpParameters rtp_parameters = channel_->GetRtpReceiveParameters(0);
+ ASSERT_EQ(1u, rtp_parameters.encodings.size());
+ EXPECT_FALSE(rtp_parameters.encodings[0].ssrc);
+
+ // Receive PCMU packet (SSRC=1).
+ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+
+ // The |ssrc| member should still be unset.
+ rtp_parameters = channel_->GetRtpReceiveParameters(0);
+ ASSERT_EQ(1u, rtp_parameters.encodings.size());
+ EXPECT_FALSE(rtp_parameters.encodings[0].ssrc);
+}
+
// Test that we apply codecs properly.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecs) {
EXPECT_TRUE(SetupSendStream());