diff options
Diffstat (limited to 'third_party/libwebrtc/pc/track_media_info_map_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/pc/track_media_info_map_unittest.cc | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/third_party/libwebrtc/pc/track_media_info_map_unittest.cc b/third_party/libwebrtc/pc/track_media_info_map_unittest.cc new file mode 100644 index 0000000000..affb3630f5 --- /dev/null +++ b/third_party/libwebrtc/pc/track_media_info_map_unittest.cc @@ -0,0 +1,443 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "pc/track_media_info_map.h" + +#include <stddef.h> + +#include <cstdint> +#include <initializer_list> +#include <string> +#include <type_traits> +#include <utility> +#include <vector> + +#include "api/media_types.h" +#include "api/rtp_parameters.h" +#include "api/test/mock_video_track.h" +#include "media/base/media_channel.h" +#include "pc/audio_track.h" +#include "pc/test/fake_video_track_source.h" +#include "pc/test/mock_rtp_receiver_internal.h" +#include "pc/test/mock_rtp_sender_internal.h" +#include "pc/video_track.h" +#include "rtc_base/checks.h" +#include "rtc_base/thread.h" +#include "test/gmock.h" +#include "test/gtest.h" + +using ::testing::ElementsAre; + +namespace webrtc { + +namespace { + +RtpParameters CreateRtpParametersWithSsrcs( + std::initializer_list<uint32_t> ssrcs) { + RtpParameters params; + for (uint32_t ssrc : ssrcs) { + RtpEncodingParameters encoding_params; + encoding_params.ssrc = ssrc; + params.encodings.push_back(encoding_params); + } + return params; +} + +rtc::scoped_refptr<MockRtpSenderInternal> CreateMockRtpSender( + cricket::MediaType media_type, + std::initializer_list<uint32_t> ssrcs, + rtc::scoped_refptr<MediaStreamTrackInterface> track) { + uint32_t first_ssrc; + if (ssrcs.size()) { + first_ssrc = *ssrcs.begin(); + } else { + first_ssrc = 0; + } + auto sender = rtc::make_ref_counted<MockRtpSenderInternal>(); + EXPECT_CALL(*sender, track()) + .WillRepeatedly(::testing::Return(std::move(track))); + EXPECT_CALL(*sender, ssrc()).WillRepeatedly(::testing::Return(first_ssrc)); + EXPECT_CALL(*sender, media_type()) + .WillRepeatedly(::testing::Return(media_type)); + EXPECT_CALL(*sender, GetParameters()) + .WillRepeatedly(::testing::Return(CreateRtpParametersWithSsrcs(ssrcs))); + EXPECT_CALL(*sender, AttachmentId()).WillRepeatedly(::testing::Return(1)); + return sender; +} + +rtc::scoped_refptr<MockRtpReceiverInternal> CreateMockRtpReceiver( + cricket::MediaType media_type, + std::initializer_list<uint32_t> ssrcs, + rtc::scoped_refptr<MediaStreamTrackInterface> track) { + auto receiver = rtc::make_ref_counted<MockRtpReceiverInternal>(); + EXPECT_CALL(*receiver, track()) + .WillRepeatedly(::testing::Return(std::move(track))); + EXPECT_CALL(*receiver, media_type()) + .WillRepeatedly(::testing::Return(media_type)); + EXPECT_CALL(*receiver, GetParameters()) + .WillRepeatedly(::testing::Return(CreateRtpParametersWithSsrcs(ssrcs))); + EXPECT_CALL(*receiver, AttachmentId()).WillRepeatedly(::testing::Return(1)); + return receiver; +} + +rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack( + const std::string& id) { + return VideoTrack::Create(id, FakeVideoTrackSource::Create(false), + rtc::Thread::Current()); +} + +rtc::scoped_refptr<VideoTrackInterface> CreateMockVideoTrack( + const std::string& id) { + auto track = MockVideoTrack::Create(); + EXPECT_CALL(*track, kind()) + .WillRepeatedly(::testing::Return(VideoTrack::kVideoKind)); + return track; +} + +class TrackMediaInfoMapTest : public ::testing::Test { + public: + TrackMediaInfoMapTest() : TrackMediaInfoMapTest(true) {} + + explicit TrackMediaInfoMapTest(bool use_real_video_track) + : local_audio_track_(AudioTrack::Create("LocalAudioTrack", nullptr)), + remote_audio_track_(AudioTrack::Create("RemoteAudioTrack", nullptr)), + local_video_track_(use_real_video_track + ? CreateVideoTrack("LocalVideoTrack") + : CreateMockVideoTrack("LocalVideoTrack")), + remote_video_track_(use_real_video_track + ? CreateVideoTrack("RemoteVideoTrack") + : CreateMockVideoTrack("LocalVideoTrack")) {} + + void AddRtpSenderWithSsrcs(std::initializer_list<uint32_t> ssrcs, + MediaStreamTrackInterface* local_track) { + rtc::scoped_refptr<MockRtpSenderInternal> rtp_sender = CreateMockRtpSender( + local_track->kind() == MediaStreamTrackInterface::kAudioKind + ? cricket::MEDIA_TYPE_AUDIO + : cricket::MEDIA_TYPE_VIDEO, + ssrcs, rtc::scoped_refptr<MediaStreamTrackInterface>(local_track)); + rtp_senders_.push_back(rtp_sender); + + if (local_track->kind() == MediaStreamTrackInterface::kAudioKind) { + cricket::VoiceSenderInfo voice_sender_info; + size_t i = 0; + for (uint32_t ssrc : ssrcs) { + voice_sender_info.local_stats.push_back(cricket::SsrcSenderInfo()); + voice_sender_info.local_stats[i++].ssrc = ssrc; + } + voice_media_info_.senders.push_back(voice_sender_info); + } else { + cricket::VideoSenderInfo video_sender_info; + size_t i = 0; + for (uint32_t ssrc : ssrcs) { + video_sender_info.local_stats.push_back(cricket::SsrcSenderInfo()); + video_sender_info.local_stats[i++].ssrc = ssrc; + } + video_media_info_.senders.push_back(video_sender_info); + video_media_info_.aggregated_senders.push_back(video_sender_info); + } + } + + void AddRtpReceiverWithSsrcs(std::initializer_list<uint32_t> ssrcs, + MediaStreamTrackInterface* remote_track) { + auto rtp_receiver = CreateMockRtpReceiver( + remote_track->kind() == MediaStreamTrackInterface::kAudioKind + ? cricket::MEDIA_TYPE_AUDIO + : cricket::MEDIA_TYPE_VIDEO, + ssrcs, rtc::scoped_refptr<MediaStreamTrackInterface>(remote_track)); + rtp_receivers_.push_back(rtp_receiver); + + if (remote_track->kind() == MediaStreamTrackInterface::kAudioKind) { + cricket::VoiceReceiverInfo voice_receiver_info; + size_t i = 0; + for (uint32_t ssrc : ssrcs) { + voice_receiver_info.local_stats.push_back(cricket::SsrcReceiverInfo()); + voice_receiver_info.local_stats[i++].ssrc = ssrc; + } + voice_media_info_.receivers.push_back(voice_receiver_info); + } else { + cricket::VideoReceiverInfo video_receiver_info; + size_t i = 0; + for (uint32_t ssrc : ssrcs) { + video_receiver_info.local_stats.push_back(cricket::SsrcReceiverInfo()); + video_receiver_info.local_stats[i++].ssrc = ssrc; + } + video_media_info_.receivers.push_back(video_receiver_info); + } + } + + // Copies the current state of `voice_media_info_` and `video_media_info_` + // into the map. + void InitializeMap() { + map_.Initialize(voice_media_info_, video_media_info_, rtp_senders_, + rtp_receivers_); + } + + private: + rtc::AutoThread main_thread_; + cricket::VoiceMediaInfo voice_media_info_; + cricket::VideoMediaInfo video_media_info_; + + protected: + std::vector<rtc::scoped_refptr<RtpSenderInternal>> rtp_senders_; + std::vector<rtc::scoped_refptr<RtpReceiverInternal>> rtp_receivers_; + TrackMediaInfoMap map_; + rtc::scoped_refptr<AudioTrack> local_audio_track_; + rtc::scoped_refptr<AudioTrack> remote_audio_track_; + rtc::scoped_refptr<VideoTrackInterface> local_video_track_; + rtc::scoped_refptr<VideoTrackInterface> remote_video_track_; +}; + +} // namespace + +TEST_F(TrackMediaInfoMapTest, SingleSenderReceiverPerTrackWithOneSsrc) { + AddRtpSenderWithSsrcs({1}, local_audio_track_.get()); + AddRtpReceiverWithSsrcs({2}, remote_audio_track_.get()); + AddRtpSenderWithSsrcs({3}, local_video_track_.get()); + AddRtpReceiverWithSsrcs({4}, remote_video_track_.get()); + InitializeMap(); + + // Local audio track <-> RTP audio sender + ASSERT_TRUE(map_.GetVoiceSenderInfos(*local_audio_track_)); + EXPECT_THAT(*map_.GetVoiceSenderInfos(*local_audio_track_), + ElementsAre(&map_.voice_media_info()->senders[0])); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[0]), + local_audio_track_.get()); + + // Remote audio track <-> RTP audio receiver + EXPECT_EQ(map_.GetVoiceReceiverInfo(*remote_audio_track_), + &map_.voice_media_info()->receivers[0]); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->receivers[0]), + remote_audio_track_.get()); + + // Local video track <-> RTP video sender + ASSERT_TRUE(map_.GetVideoSenderInfos(*local_video_track_)); + EXPECT_THAT(*map_.GetVideoSenderInfos(*local_video_track_), + ElementsAre(&map_.video_media_info()->senders[0])); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[0]), + local_video_track_.get()); + + // Remote video track <-> RTP video receiver + EXPECT_EQ(map_.GetVideoReceiverInfo(*remote_video_track_), + &map_.video_media_info()->receivers[0]); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->receivers[0]), + remote_video_track_.get()); +} + +TEST_F(TrackMediaInfoMapTest, SingleSenderReceiverPerTrackWithMissingSsrc) { + AddRtpSenderWithSsrcs({}, local_audio_track_.get()); + AddRtpSenderWithSsrcs({}, local_video_track_.get()); + AddRtpReceiverWithSsrcs({}, remote_audio_track_.get()); + AddRtpReceiverWithSsrcs({}, remote_video_track_.get()); + InitializeMap(); + + EXPECT_FALSE(map_.GetVoiceSenderInfos(*local_audio_track_)); + EXPECT_FALSE(map_.GetVideoSenderInfos(*local_video_track_)); + EXPECT_FALSE(map_.GetVoiceReceiverInfo(*remote_audio_track_)); + EXPECT_FALSE(map_.GetVideoReceiverInfo(*remote_video_track_)); +} + +TEST_F(TrackMediaInfoMapTest, + SingleSenderReceiverPerTrackWithAudioAndVideoUseSameSsrc) { + AddRtpSenderWithSsrcs({1}, local_audio_track_.get()); + AddRtpReceiverWithSsrcs({2}, remote_audio_track_.get()); + AddRtpSenderWithSsrcs({1}, local_video_track_.get()); + AddRtpReceiverWithSsrcs({2}, remote_video_track_.get()); + InitializeMap(); + + // Local audio track <-> RTP audio sender + ASSERT_TRUE(map_.GetVoiceSenderInfos(*local_audio_track_)); + EXPECT_THAT(*map_.GetVoiceSenderInfos(*local_audio_track_), + ElementsAre(&map_.voice_media_info()->senders[0])); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[0]), + local_audio_track_.get()); + + // Remote audio track <-> RTP audio receiver + EXPECT_EQ(map_.GetVoiceReceiverInfo(*remote_audio_track_), + &map_.voice_media_info()->receivers[0]); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->receivers[0]), + remote_audio_track_.get()); + + // Local video track <-> RTP video sender + ASSERT_TRUE(map_.GetVideoSenderInfos(*local_video_track_)); + EXPECT_THAT(*map_.GetVideoSenderInfos(*local_video_track_), + ElementsAre(&map_.video_media_info()->senders[0])); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[0]), + local_video_track_.get()); + + // Remote video track <-> RTP video receiver + EXPECT_EQ(map_.GetVideoReceiverInfo(*remote_video_track_), + &map_.video_media_info()->receivers[0]); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->receivers[0]), + remote_video_track_.get()); +} + +TEST_F(TrackMediaInfoMapTest, SingleMultiSsrcSenderPerTrack) { + AddRtpSenderWithSsrcs({1, 2}, local_audio_track_.get()); + AddRtpSenderWithSsrcs({3, 4}, local_video_track_.get()); + InitializeMap(); + + // Local audio track <-> RTP audio senders + ASSERT_TRUE(map_.GetVoiceSenderInfos(*local_audio_track_)); + EXPECT_THAT(*map_.GetVoiceSenderInfos(*local_audio_track_), + ElementsAre(&map_.voice_media_info()->senders[0])); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[0]), + local_audio_track_.get()); + + // Local video track <-> RTP video senders + ASSERT_TRUE(map_.GetVideoSenderInfos(*local_video_track_)); + EXPECT_THAT(*map_.GetVideoSenderInfos(*local_video_track_), + ElementsAre(&map_.video_media_info()->senders[0])); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[0]), + local_video_track_.get()); +} + +TEST_F(TrackMediaInfoMapTest, MultipleOneSsrcSendersPerTrack) { + AddRtpSenderWithSsrcs({1}, local_audio_track_.get()); + AddRtpSenderWithSsrcs({2}, local_audio_track_.get()); + AddRtpSenderWithSsrcs({3}, local_video_track_.get()); + AddRtpSenderWithSsrcs({4}, local_video_track_.get()); + InitializeMap(); + + // Local audio track <-> RTP audio senders + ASSERT_TRUE(map_.GetVoiceSenderInfos(*local_audio_track_)); + EXPECT_THAT(*map_.GetVoiceSenderInfos(*local_audio_track_), + ElementsAre(&map_.voice_media_info()->senders[0], + &map_.voice_media_info()->senders[1])); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[0]), + local_audio_track_.get()); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[1]), + local_audio_track_.get()); + + // Local video track <-> RTP video senders + ASSERT_TRUE(map_.GetVideoSenderInfos(*local_video_track_)); + EXPECT_THAT(*map_.GetVideoSenderInfos(*local_video_track_), + ElementsAre(&map_.video_media_info()->senders[0], + &map_.video_media_info()->senders[1])); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[0]), + local_video_track_.get()); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[1]), + local_video_track_.get()); +} + +TEST_F(TrackMediaInfoMapTest, MultipleMultiSsrcSendersPerTrack) { + AddRtpSenderWithSsrcs({1, 2}, local_audio_track_.get()); + AddRtpSenderWithSsrcs({3, 4}, local_audio_track_.get()); + AddRtpSenderWithSsrcs({5, 6}, local_video_track_.get()); + AddRtpSenderWithSsrcs({7, 8}, local_video_track_.get()); + InitializeMap(); + + // Local audio track <-> RTP audio senders + ASSERT_TRUE(map_.GetVoiceSenderInfos(*local_audio_track_)); + EXPECT_THAT(*map_.GetVoiceSenderInfos(*local_audio_track_), + ElementsAre(&map_.voice_media_info()->senders[0], + &map_.voice_media_info()->senders[1])); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[0]), + local_audio_track_.get()); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[1]), + local_audio_track_.get()); + + // Local video track <-> RTP video senders + ASSERT_TRUE(map_.GetVideoSenderInfos(*local_video_track_)); + EXPECT_THAT(*map_.GetVideoSenderInfos(*local_video_track_), + ElementsAre(&map_.video_media_info()->senders[0], + &map_.video_media_info()->senders[1])); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[0]), + local_video_track_.get()); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[1]), + local_video_track_.get()); +} + +// SSRCs can be reused for send and receive in loopback. +TEST_F(TrackMediaInfoMapTest, SingleSenderReceiverPerTrackWithSsrcNotUnique) { + AddRtpSenderWithSsrcs({1}, local_audio_track_.get()); + AddRtpReceiverWithSsrcs({1}, remote_audio_track_.get()); + AddRtpSenderWithSsrcs({2}, local_video_track_.get()); + AddRtpReceiverWithSsrcs({2}, remote_video_track_.get()); + InitializeMap(); + + // Local audio track <-> RTP audio senders + ASSERT_TRUE(map_.GetVoiceSenderInfos(*local_audio_track_)); + EXPECT_THAT(*map_.GetVoiceSenderInfos(*local_audio_track_), + ElementsAre(&map_.voice_media_info()->senders[0])); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->senders[0]), + local_audio_track_.get()); + + // Remote audio track <-> RTP audio receiver + EXPECT_EQ(map_.GetVoiceReceiverInfo(*remote_audio_track_), + &map_.voice_media_info()->receivers[0]); + EXPECT_EQ(map_.GetAudioTrack(map_.voice_media_info()->receivers[0]), + remote_audio_track_.get()); + + // Local video track <-> RTP video senders + ASSERT_TRUE(map_.GetVideoSenderInfos(*local_video_track_)); + EXPECT_THAT(*map_.GetVideoSenderInfos(*local_video_track_), + ElementsAre(&map_.video_media_info()->senders[0])); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->senders[0]), + local_video_track_.get()); + + // Remote video track <-> RTP video receiver + EXPECT_EQ(map_.GetVideoReceiverInfo(*remote_video_track_), + &map_.video_media_info()->receivers[0]); + EXPECT_EQ(map_.GetVideoTrack(map_.video_media_info()->receivers[0]), + remote_video_track_.get()); +} + +TEST_F(TrackMediaInfoMapTest, SsrcLookupFunction) { + AddRtpSenderWithSsrcs({1}, local_audio_track_.get()); + AddRtpReceiverWithSsrcs({2}, remote_audio_track_.get()); + AddRtpSenderWithSsrcs({3}, local_video_track_.get()); + AddRtpReceiverWithSsrcs({4}, remote_video_track_.get()); + InitializeMap(); + EXPECT_TRUE(map_.GetVoiceSenderInfoBySsrc(1)); + EXPECT_TRUE(map_.GetVoiceReceiverInfoBySsrc(2)); + EXPECT_TRUE(map_.GetVideoSenderInfoBySsrc(3)); + EXPECT_TRUE(map_.GetVideoReceiverInfoBySsrc(4)); + EXPECT_FALSE(map_.GetVoiceSenderInfoBySsrc(2)); + EXPECT_FALSE(map_.GetVoiceSenderInfoBySsrc(1024)); +} + +TEST_F(TrackMediaInfoMapTest, GetAttachmentIdByTrack) { + AddRtpSenderWithSsrcs({1}, local_audio_track_.get()); + InitializeMap(); + EXPECT_EQ(rtp_senders_[0]->AttachmentId(), + map_.GetAttachmentIdByTrack(local_audio_track_.get())); + EXPECT_EQ(absl::nullopt, + map_.GetAttachmentIdByTrack(local_video_track_.get())); +} + +// Death tests. +// Disabled on Android because death tests misbehave on Android, see +// base/test/gtest_util.h. +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +class TrackMediaInfoMapDeathTest : public TrackMediaInfoMapTest { + public: + TrackMediaInfoMapDeathTest() : TrackMediaInfoMapTest(false) {} +}; + +TEST_F(TrackMediaInfoMapDeathTest, MultipleOneSsrcReceiversPerTrack) { + AddRtpReceiverWithSsrcs({1}, remote_audio_track_.get()); + AddRtpReceiverWithSsrcs({2}, remote_audio_track_.get()); + AddRtpReceiverWithSsrcs({3}, remote_video_track_.get()); + AddRtpReceiverWithSsrcs({4}, remote_video_track_.get()); + EXPECT_DEATH(InitializeMap(), ""); +} + +TEST_F(TrackMediaInfoMapDeathTest, MultipleMultiSsrcReceiversPerTrack) { + AddRtpReceiverWithSsrcs({1, 2}, remote_audio_track_.get()); + AddRtpReceiverWithSsrcs({3, 4}, remote_audio_track_.get()); + AddRtpReceiverWithSsrcs({5, 6}, remote_video_track_.get()); + AddRtpReceiverWithSsrcs({7, 8}, remote_video_track_.get()); + EXPECT_DEATH(InitializeMap(), ""); +} + +#endif // RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) + +} // namespace webrtc |