Add GetSources to VideoRtpReceiver

BUG=webrtc:9770

Change-Id: I16143fce6eb727bbab0f6c621aa5b51bc6d28d6b
Reviewed-on: https://webrtc-review.googlesource.com/101600
Reviewed-by: Seth Hampson <shampson@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Commit-Queue: Jonas Oreland <jonaso@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24858}
This commit is contained in:
Jonas Oreland 2018-09-26 16:04:32 +02:00 committed by Commit Bot
parent 3c7694137a
commit 49ac5959c2
15 changed files with 280 additions and 16 deletions

View File

@ -19,6 +19,7 @@
#include "api/call/transport.h"
#include "api/rtp_headers.h"
#include "api/rtpparameters.h"
#include "api/rtpreceiverinterface.h"
#include "api/video/video_content_type.h"
#include "api/video/video_sink_interface.h"
#include "api/video/video_timing.h"
@ -239,6 +240,8 @@ class VideoReceiveStream {
virtual void AddSecondarySink(RtpPacketSinkInterface* sink) = 0;
virtual void RemoveSecondarySink(const RtpPacketSinkInterface* sink) = 0;
virtual std::vector<RtpSource> GetSources() const = 0;
protected:
virtual ~VideoReceiveStream() {}
};

View File

@ -487,6 +487,7 @@ if (rtc_include_tests) {
":rtc_audio_video",
":rtc_constants",
":rtc_data",
"../api/units:time_delta",
"../api/video:video_frame_i420",
"../modules/audio_processing:mocks",
"../modules/rtp_rtcp",

View File

@ -601,6 +601,10 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
void FillBitrateInfo(BandwidthEstimationInfo* bwe_info) override {}
bool GetStats(VideoMediaInfo* info) override { return false; }
std::vector<webrtc::RtpSource> GetSources(uint32_t ssrc) const override {
return {};
}
private:
bool SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
if (fail_set_recv_codecs()) {

View File

@ -784,6 +784,8 @@ class VideoMediaChannel : public MediaChannel {
virtual void FillBitrateInfo(BandwidthEstimationInfo* bwe_info) = 0;
// Gets quality stats for the channel.
virtual bool GetStats(VideoMediaInfo* info) = 0;
virtual std::vector<webrtc::RtpSource> GetSources(uint32_t ssrc) const = 0;
};
enum DataMessageType {

View File

@ -210,6 +210,10 @@ class FakeVideoReceiveStream final : public webrtc::VideoReceiveStream {
int GetNumAddedSecondarySinks() const;
int GetNumRemovedSecondarySinks() const;
std::vector<webrtc::RtpSource> GetSources() const override {
return std::vector<webrtc::RtpSource>();
}
private:
// webrtc::VideoReceiveStream implementation.
void Start() override;

View File

@ -1480,6 +1480,20 @@ absl::optional<uint32_t> WebRtcVideoChannel::GetDefaultReceiveStreamSsrc() {
return ssrc;
}
std::vector<webrtc::RtpSource> WebRtcVideoChannel::GetSources(
uint32_t ssrc) const {
rtc::CritScope stream_lock(&stream_crit_);
auto it = receive_streams_.find(ssrc);
if (it == receive_streams_.end()) {
// TODO(bugs.webrtc.org/9781): Investigate standard compliance
// with sources for streams that has been removed.
RTC_LOG(LS_ERROR) << "Attempting to get contributing sources for SSRC:"
<< ssrc << " which doesn't exist.";
return {};
}
return it->second->GetSources();
}
bool WebRtcVideoChannel::SendRtp(const uint8_t* data,
size_t len,
const webrtc::PacketOptions& options) {
@ -2202,6 +2216,12 @@ WebRtcVideoChannel::WebRtcVideoReceiveStream::GetSsrcs() const {
return stream_params_.ssrcs;
}
std::vector<webrtc::RtpSource>
WebRtcVideoChannel::WebRtcVideoReceiveStream::GetSources() {
RTC_DCHECK(stream_);
return stream_->GetSources();
}
absl::optional<uint32_t>
WebRtcVideoChannel::WebRtcVideoReceiveStream::GetFirstPrimarySsrc() const {
std::vector<uint32_t> primary_ssrcs;

View File

@ -175,6 +175,8 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
static constexpr int kDefaultQpMax = 56;
std::vector<webrtc::RtpSource> GetSources(uint32_t ssrc) const override;
private:
class WebRtcVideoReceiveStream;
struct VideoCodecSettings {
@ -357,6 +359,8 @@ class WebRtcVideoChannel : public VideoMediaChannel, public webrtc::Transport {
const std::vector<uint32_t>& GetSsrcs() const;
std::vector<webrtc::RtpSource> GetSources();
// Does not return codecs, they are filled by the owning WebRtcVideoChannel.
webrtc::RtpParameters GetRtpParameters() const;

View File

@ -17,6 +17,7 @@
#include "api/rtpparameters.h"
#include "api/test/mock_video_decoder_factory.h"
#include "api/test/mock_video_encoder_factory.h"
#include "api/units/time_delta.h"
#include "api/video_codecs/builtin_video_decoder_factory.h"
#include "api/video_codecs/builtin_video_encoder_factory.h"
#include "api/video_codecs/sdp_video_format.h"
@ -965,6 +966,25 @@ TEST_F(WebRtcVideoEngineTest, RegisterH264DecoderIfSupported) {
ASSERT_EQ(1u, decoder_factory_->decoders().size());
}
// Tests when GetSources is called with non-existing ssrc, it will return an
// empty list of RtpSource without crashing.
TEST_F(WebRtcVideoEngineTest, GetSourcesWithNonExistingSsrc) {
// Setup an recv stream with |kSsrc|.
encoder_factory_->AddSupportedVideoCodecType("VP8");
decoder_factory_->AddSupportedVideoCodecType(webrtc::SdpVideoFormat("VP8"));
cricket::VideoRecvParameters parameters;
parameters.codecs.push_back(GetEngineCodec("VP8"));
std::unique_ptr<VideoMediaChannel> channel(
SetRecvParamsWithSupportedCodecs(parameters.codecs));
EXPECT_TRUE(
channel->AddRecvStream(cricket::StreamParams::CreateLegacy(kSsrc)));
// Call GetSources with |kSsrc + 1| which doesn't exist.
std::vector<webrtc::RtpSource> sources = channel->GetSources(kSsrc + 1);
EXPECT_EQ(0u, sources.size());
}
TEST(WebRtcVideoEngineNewVideoCodecFactoryTest, NullFactories) {
std::unique_ptr<webrtc::VideoEncoderFactory> encoder_factory;
std::unique_ptr<webrtc::VideoDecoderFactory> decoder_factory;
@ -1201,11 +1221,14 @@ TEST_F(WebRtcVideoEngineTest, DISABLED_RecreatesEncoderOnContentTypeChange) {
class WebRtcVideoChannelBaseTest : public testing::Test {
protected:
WebRtcVideoChannelBaseTest()
: call_(webrtc::Call::Create(webrtc::Call::Config(&event_log_))),
engine_(webrtc::CreateBuiltinVideoEncoderFactory(),
: engine_(webrtc::CreateBuiltinVideoEncoderFactory(),
webrtc::CreateBuiltinVideoDecoderFactory()) {}
virtual void SetUp() {
// One testcase calls SetUp in a loop, only create call_ once.
if (!call_) {
call_.reset(webrtc::Call::Create(webrtc::Call::Config(&event_log_)));
}
cricket::MediaConfig media_config;
// Disabling cpu overuse detection actually disables quality scaling too; it
// implies DegradationPreference kMaintainResolution. Automatic scaling
@ -1402,7 +1425,7 @@ class WebRtcVideoChannelBaseTest : public testing::Test {
}
webrtc::RtcEventLogNullImpl event_log_;
const std::unique_ptr<webrtc::Call> call_;
std::unique_ptr<webrtc::Call> call_;
WebRtcVideoEngine engine_;
std::unique_ptr<cricket::FakeVideoCapturerWithTaskQueue> video_capturer_;
std::unique_ptr<cricket::FakeVideoCapturerWithTaskQueue> video_capturer_2_;
@ -6696,4 +6719,145 @@ TEST_F(WebRtcVideoChannelSimulcastTest,
false);
}
// The fake clock needs to be initialize before the call.
// So defer creating call in base class.
class WebRtcVideoChannelTestWithClock : public WebRtcVideoChannelBaseTest {
public:
WebRtcVideoChannelTestWithClock() {
fake_clock_.AdvanceTime(webrtc::TimeDelta::ms(1)); // avoid time=0
}
rtc::ScopedFakeClock fake_clock_;
};
TEST_F(WebRtcVideoChannelTestWithClock, GetSources) {
uint8_t data1[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
EXPECT_EQ(0u, channel_->GetSources(kSsrc).size());
rtc::CopyOnWriteBuffer packet1(data1, sizeof(data1));
rtc::SetBE32(packet1.data() + 8, kSsrc);
channel_->SetSink(kDefaultReceiveSsrc, NULL);
EXPECT_TRUE(SetDefaultCodec());
EXPECT_TRUE(SetSend(true));
EXPECT_EQ(0, renderer_.num_rendered_frames());
channel_->OnPacketReceived(&packet1, rtc::PacketTime());
std::vector<webrtc::RtpSource> sources = channel_->GetSources(kSsrc);
EXPECT_EQ(1u, sources.size());
EXPECT_EQ(webrtc::RtpSourceType::SSRC, sources[0].source_type());
int64_t timestamp1 = sources[0].timestamp_ms();
// a new packet.
int64_t timeDeltaMs = 1;
fake_clock_.AdvanceTime(webrtc::TimeDelta::ms(timeDeltaMs));
channel_->OnPacketReceived(&packet1, rtc::PacketTime());
int64_t timestamp2 = channel_->GetSources(kSsrc)[0].timestamp_ms();
EXPECT_EQ(timestamp2, timestamp1 + timeDeltaMs);
// It only keeps 10s of history.
fake_clock_.AdvanceTime(webrtc::TimeDelta::seconds(10));
fake_clock_.AdvanceTime(webrtc::TimeDelta::ms(1));
EXPECT_EQ(0u, channel_->GetSources(kSsrc).size());
}
TEST_F(WebRtcVideoChannelTestWithClock, GetContributingSources) {
uint8_t data1[] = {0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint32_t kCsrc = 4321u;
EXPECT_EQ(0u, channel_->GetSources(kSsrc).size());
EXPECT_EQ(0u, channel_->GetSources(kCsrc).size());
rtc::CopyOnWriteBuffer packet1(data1, sizeof(data1));
rtc::SetBE32(packet1.data() + 8, kSsrc);
rtc::SetBE32(packet1.data() + 12, kCsrc);
channel_->SetSink(kDefaultReceiveSsrc, NULL);
EXPECT_TRUE(SetDefaultCodec());
EXPECT_TRUE(SetSend(true));
EXPECT_EQ(0, renderer_.num_rendered_frames());
channel_->OnPacketReceived(&packet1, rtc::PacketTime());
{
ASSERT_EQ(2u, channel_->GetSources(kSsrc).size());
EXPECT_EQ(0u, channel_->GetSources(kCsrc).size());
std::vector<webrtc::RtpSource> sources = channel_->GetSources(kSsrc);
EXPECT_EQ(sources[0].timestamp_ms(), sources[1].timestamp_ms());
// 1 SSRC and 1 CSRC.
EXPECT_EQ(1, std::count_if(sources.begin(), sources.end(),
[](const webrtc::RtpSource& source) {
return source.source_type() ==
webrtc::RtpSourceType::SSRC;
}));
EXPECT_EQ(1, std::count_if(sources.begin(), sources.end(),
[](const webrtc::RtpSource& source) {
return source.source_type() ==
webrtc::RtpSourceType::CSRC;
}));
}
int64_t timestamp1 = channel_->GetSources(kSsrc)[0].timestamp_ms();
// a new packet with only ssrc (i.e no csrc).
uint8_t data2[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
rtc::CopyOnWriteBuffer packet2(data2, sizeof(data2));
rtc::SetBE32(packet2.data() + 8, kSsrc);
int64_t timeDeltaMs = 1;
fake_clock_.AdvanceTime(webrtc::TimeDelta::ms(timeDeltaMs));
channel_->OnPacketReceived(&packet2, rtc::PacketTime());
{
ASSERT_EQ(2u, channel_->GetSources(kSsrc).size());
EXPECT_EQ(0u, channel_->GetSources(kCsrc).size());
std::vector<webrtc::RtpSource> sources = channel_->GetSources(kSsrc);
EXPECT_NE(sources[0].timestamp_ms(), sources[1].timestamp_ms());
// 1 SSRC and 1 CSRC.
EXPECT_EQ(1, std::count_if(sources.begin(), sources.end(),
[](const webrtc::RtpSource& source) {
return source.source_type() ==
webrtc::RtpSourceType::SSRC;
}));
EXPECT_EQ(1, std::count_if(sources.begin(), sources.end(),
[](const webrtc::RtpSource& source) {
return source.source_type() ==
webrtc::RtpSourceType::CSRC;
}));
auto ssrcSource = std::find_if(
sources.begin(), sources.end(), [](const webrtc::RtpSource& source) {
return source.source_type() == webrtc::RtpSourceType::SSRC;
});
auto csrcSource = std::find_if(
sources.begin(), sources.end(), [](const webrtc::RtpSource& source) {
return source.source_type() == webrtc::RtpSourceType::CSRC;
});
EXPECT_EQ(ssrcSource->timestamp_ms(), timestamp1 + timeDeltaMs);
EXPECT_EQ(csrcSource->timestamp_ms(), timestamp1);
}
// It only keeps 10s of history.
fake_clock_.AdvanceTime(webrtc::TimeDelta::seconds(10));
{
ASSERT_EQ(1u, channel_->GetSources(kSsrc).size());
EXPECT_EQ(0u, channel_->GetSources(kCsrc).size());
std::vector<webrtc::RtpSource> sources = channel_->GetSources(kSsrc);
EXPECT_EQ(1, std::count_if(sources.begin(), sources.end(),
[](const webrtc::RtpSource& source) {
return source.source_type() ==
webrtc::RtpSourceType::SSRC;
}));
EXPECT_EQ(0, std::count_if(sources.begin(), sources.end(),
[](const webrtc::RtpSource& source) {
return source.source_type() ==
webrtc::RtpSourceType::CSRC;
}));
}
fake_clock_.AdvanceTime(webrtc::TimeDelta::ms(1));
EXPECT_EQ(0u, channel_->GetSources(kSsrc).size());
EXPECT_EQ(0u, channel_->GetSources(kCsrc).size());
}
} // namespace cricket

View File

@ -4308,7 +4308,7 @@ TEST_P(PeerConnectionIntegrationTest, CodecNamesAreCaseInsensitive) {
ASSERT_TRUE(ExpectNewFrames(media_expectations));
}
TEST_P(PeerConnectionIntegrationTest, GetSources) {
TEST_P(PeerConnectionIntegrationTest, GetSourcesAudio) {
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignaling();
caller()->AddAudioTrack();
@ -4318,14 +4318,34 @@ TEST_P(PeerConnectionIntegrationTest, GetSources) {
MediaExpectations media_expectations;
media_expectations.CalleeExpectsSomeAudio(1);
ASSERT_TRUE(ExpectNewFrames(media_expectations));
ASSERT_GT(callee()->pc()->GetReceivers().size(), 0u);
ASSERT_EQ(callee()->pc()->GetReceivers().size(), 1u);
auto receiver = callee()->pc()->GetReceivers()[0];
ASSERT_EQ(receiver->media_type(), cricket::MEDIA_TYPE_AUDIO);
auto contributing_sources = receiver->GetSources();
auto sources = receiver->GetSources();
ASSERT_GT(receiver->GetParameters().encodings.size(), 0u);
EXPECT_EQ(receiver->GetParameters().encodings[0].ssrc,
contributing_sources[0].source_id());
sources[0].source_id());
EXPECT_EQ(webrtc::RtpSourceType::SSRC, sources[0].source_type());
}
TEST_P(PeerConnectionIntegrationTest, GetSourcesVideo) {
ASSERT_TRUE(CreatePeerConnectionWrappers());
ConnectFakeSignaling();
caller()->AddVideoTrack();
caller()->CreateAndSetAndSignalOffer();
ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout);
// Wait for one video frame to be received by the callee.
MediaExpectations media_expectations;
media_expectations.CalleeExpectsSomeVideo(1);
ASSERT_TRUE(ExpectNewFrames(media_expectations));
ASSERT_EQ(callee()->pc()->GetReceivers().size(), 1u);
auto receiver = callee()->pc()->GetReceivers()[0];
ASSERT_EQ(receiver->media_type(), cricket::MEDIA_TYPE_VIDEO);
auto sources = receiver->GetSources();
ASSERT_GT(receiver->GetParameters().encodings.size(), 0u);
EXPECT_EQ(receiver->GetParameters().encodings[0].ssrc,
sources[0].source_id());
EXPECT_EQ(webrtc::RtpSourceType::SSRC, sources[0].source_type());
}
// Test that if a track is removed and added again with a different stream ID,

View File

@ -440,4 +440,12 @@ void VideoRtpReceiver::NotifyFirstPacketReceived() {
received_first_packet_ = true;
}
std::vector<RtpSource> VideoRtpReceiver::GetSources() const {
if (!media_channel_ || !ssrc_ || stopped_) {
return {};
}
return worker_thread_->Invoke<std::vector<RtpSource>>(
RTC_FROM_HERE, [&] { return media_channel_->GetSources(*ssrc_); });
}
} // namespace webrtc

View File

@ -227,6 +227,8 @@ class VideoRtpReceiver : public rtc::RefCountedObject<RtpReceiverInternal> {
int AttachmentId() const override { return attachment_id_; }
std::vector<RtpSource> GetSources() const override;
private:
class VideoRtpTrackSource : public VideoTrackSource {
public:

View File

@ -185,7 +185,7 @@ absl::optional<Syncable::Info> RtpVideoStreamReceiver::GetSyncInfo() const {
return absl::nullopt;
}
{
rtc::CritScope lock(&last_seq_num_cs_);
rtc::CritScope lock(&rtp_sources_lock_);
if (!last_received_rtp_timestamp_ || !last_received_rtp_system_time_ms_) {
return absl::nullopt;
}
@ -283,13 +283,15 @@ void RtpVideoStreamReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
}
if (!packet.recovered()) {
// TODO(nisse): Exclude out-of-order packets?
int64_t now_ms = clock_->TimeInMilliseconds();
{
rtc::CritScope lock(&last_seq_num_cs_);
// TODO(nisse): Exclude out-of-order packets?
rtc::CritScope cs(&rtp_sources_lock_);
last_received_rtp_timestamp_ = packet.Timestamp();
last_received_rtp_system_time_ms_ = now_ms;
std::vector<uint32_t> csrcs = packet.Csrcs();
contributing_sources_.Update(now_ms, csrcs);
}
// Periodically log the RTP header of incoming packets.
if (now_ms - last_packet_log_ms_ > kPacketLogIntervalMs) {
@ -671,4 +673,19 @@ void RtpVideoStreamReceiver::InsertSpsPpsIntoTracker(uint8_t payload_type) {
sprop_decoder.pps_nalu());
}
std::vector<webrtc::RtpSource> RtpVideoStreamReceiver::GetSources() const {
int64_t now_ms = rtc::TimeMillis();
std::vector<RtpSource> sources;
{
rtc::CritScope cs(&rtp_sources_lock_);
sources = contributing_sources_.GetSources(now_ms);
if (last_received_rtp_system_time_ms_ >=
now_ms - ContributingSources::kHistoryMs) {
sources.emplace_back(*last_received_rtp_system_time_ms_,
config_.rtp.remote_ssrc, RtpSourceType::SSRC);
}
}
return sources;
}
} // namespace webrtc

View File

@ -29,6 +29,7 @@
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/include/rtp_rtcp.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/contributing_sources.h"
#include "modules/video_coding/h264_sps_pps_tracker.h"
#include "modules/video_coding/include/video_coding_defines.h"
#include "modules/video_coding/packet_buffer.h"
@ -134,6 +135,8 @@ class RtpVideoStreamReceiver : public RtpData,
void AddSecondarySink(RtpPacketSinkInterface* sink);
void RemoveSecondarySink(const RtpPacketSinkInterface* sink);
std::vector<webrtc::RtpSource> GetSources() const;
private:
// Entry point doing non-stats work for a received packet. Called
// for the same packet both before and after RED decapsulation.
@ -177,10 +180,6 @@ class RtpVideoStreamReceiver : public RtpData,
RTC_GUARDED_BY(last_seq_num_cs_);
video_coding::H264SpsPpsTracker tracker_;
absl::optional<uint32_t> last_received_rtp_timestamp_
RTC_GUARDED_BY(last_seq_num_cs_);
absl::optional<int64_t> last_received_rtp_system_time_ms_
RTC_GUARDED_BY(last_seq_num_cs_);
std::map<uint8_t, VideoCodecType> pt_codec_type_;
// TODO(johan): Remove pt_codec_params_ once
// https://bugs.chromium.org/p/webrtc/issues/detail?id=6883 is resolved.
@ -192,6 +191,15 @@ class RtpVideoStreamReceiver : public RtpData,
std::vector<RtpPacketSinkInterface*> secondary_sinks_
RTC_GUARDED_BY(worker_task_checker_);
// Info for GetSources and GetSyncInfo is updated on network or worker thread,
// queried on the worker thread.
rtc::CriticalSection rtp_sources_lock_;
ContributingSources contributing_sources_ RTC_GUARDED_BY(&rtp_sources_lock_);
absl::optional<uint32_t> last_received_rtp_timestamp_
RTC_GUARDED_BY(rtp_sources_lock_);
absl::optional<int64_t> last_received_rtp_system_time_ms_
RTC_GUARDED_BY(rtp_sources_lock_);
};
} // namespace webrtc

View File

@ -459,5 +459,10 @@ bool VideoReceiveStream::Decode() {
}
return true;
}
std::vector<webrtc::RtpSource> VideoReceiveStream::GetSources() const {
return rtp_video_stream_receiver_.GetSources();
}
} // namespace internal
} // namespace webrtc

View File

@ -112,6 +112,8 @@ class VideoReceiveStream : public webrtc::VideoReceiveStream,
uint32_t GetPlayoutTimestamp() const override;
void SetMinimumPlayoutDelay(int delay_ms) override;
std::vector<webrtc::RtpSource> GetSources() const override;
private:
static void DecodeThreadFunction(void* ptr);
bool Decode();