1 /*
2  *  Copyright 2019 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "pc/video_rtp_receiver.h"
12 
13 #include <memory>
14 
15 #include "api/video/test/mock_recordable_encoded_frame.h"
16 #include "media/base/fake_media_engine.h"
17 #include "test/gmock.h"
18 
19 using ::testing::_;
20 using ::testing::InSequence;
21 using ::testing::Mock;
22 using ::testing::SaveArg;
23 using ::testing::StrictMock;
24 
25 namespace webrtc {
26 namespace {
27 
28 class VideoRtpReceiverTest : public testing::Test {
29  protected:
30   class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
31    public:
MockVideoMediaChannel(cricket::FakeVideoEngine * engine,const cricket::VideoOptions & options)32     MockVideoMediaChannel(cricket::FakeVideoEngine* engine,
33                           const cricket::VideoOptions& options)
34         : FakeVideoMediaChannel(engine, options) {}
35     MOCK_METHOD(void,
36                 SetRecordableEncodedFrameCallback,
37                 (uint32_t, std::function<void(const RecordableEncodedFrame&)>),
38                 (override));
39     MOCK_METHOD(void,
40                 ClearRecordableEncodedFrameCallback,
41                 (uint32_t),
42                 (override));
43     MOCK_METHOD(void, GenerateKeyFrame, (uint32_t), (override));
44   };
45 
46   class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
47    public:
48     MOCK_METHOD(void, OnFrame, (const RecordableEncodedFrame&), (override));
49   };
50 
VideoRtpReceiverTest()51   VideoRtpReceiverTest()
52       : worker_thread_(rtc::Thread::Create()),
53         channel_(nullptr, cricket::VideoOptions()),
54         receiver_(new VideoRtpReceiver(worker_thread_.get(),
55                                        "receiver",
56                                        {"stream"})) {
57     worker_thread_->Start();
58     receiver_->SetMediaChannel(&channel_);
59   }
60 
Source()61   webrtc::VideoTrackSourceInterface* Source() {
62     return receiver_->streams()[0]->FindVideoTrack("receiver")->GetSource();
63   }
64 
65   std::unique_ptr<rtc::Thread> worker_thread_;
66   MockVideoMediaChannel channel_;
67   rtc::scoped_refptr<VideoRtpReceiver> receiver_;
68 };
69 
TEST_F(VideoRtpReceiverTest,SupportsEncodedOutput)70 TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
71   EXPECT_TRUE(Source()->SupportsEncodedOutput());
72 }
73 
TEST_F(VideoRtpReceiverTest,GeneratesKeyFrame)74 TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
75   EXPECT_CALL(channel_, GenerateKeyFrame(0));
76   Source()->GenerateKeyFrame();
77 }
78 
TEST_F(VideoRtpReceiverTest,GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled)79 TEST_F(VideoRtpReceiverTest,
80        GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled) {
81   // A channel switch without previous call to GenerateKeyFrame shouldn't
82   // cause a call to happen on the new channel.
83   MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
84   EXPECT_CALL(channel_, GenerateKeyFrame).Times(0);
85   EXPECT_CALL(channel2, GenerateKeyFrame).Times(0);
86   receiver_->SetMediaChannel(&channel2);
87   Mock::VerifyAndClearExpectations(&channel2);
88 
89   // Generate a key frame. When we switch channel next time, we will have to
90   // re-generate it as we don't know if it was eventually received
91   Source()->GenerateKeyFrame();
92   MockVideoMediaChannel channel3(nullptr, cricket::VideoOptions());
93   EXPECT_CALL(channel3, GenerateKeyFrame);
94   receiver_->SetMediaChannel(&channel3);
95 
96   // Switching to a new channel should now not cause calls to GenerateKeyFrame.
97   StrictMock<MockVideoMediaChannel> channel4(nullptr, cricket::VideoOptions());
98   receiver_->SetMediaChannel(&channel4);
99 }
100 
TEST_F(VideoRtpReceiverTest,EnablesEncodedOutput)101 TEST_F(VideoRtpReceiverTest, EnablesEncodedOutput) {
102   EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(/*ssrc=*/0, _));
103   EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback).Times(0);
104   MockVideoSink sink;
105   Source()->AddEncodedSink(&sink);
106 }
107 
TEST_F(VideoRtpReceiverTest,DisablesEncodedOutput)108 TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
109   EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
110   MockVideoSink sink;
111   Source()->AddEncodedSink(&sink);
112   Source()->RemoveEncodedSink(&sink);
113 }
114 
TEST_F(VideoRtpReceiverTest,DisablesEnablesEncodedOutputOnChannelSwitch)115 TEST_F(VideoRtpReceiverTest, DisablesEnablesEncodedOutputOnChannelSwitch) {
116   InSequence s;
117   EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback);
118   EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback);
119   MockVideoSink sink;
120   Source()->AddEncodedSink(&sink);
121   MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
122   EXPECT_CALL(channel2, SetRecordableEncodedFrameCallback);
123   receiver_->SetMediaChannel(&channel2);
124   Mock::VerifyAndClearExpectations(&channel2);
125 
126   // When clearing encoded frame buffer function, we need channel switches
127   // to NOT set the callback again.
128   EXPECT_CALL(channel2, ClearRecordableEncodedFrameCallback);
129   Source()->RemoveEncodedSink(&sink);
130   StrictMock<MockVideoMediaChannel> channel3(nullptr, cricket::VideoOptions());
131   receiver_->SetMediaChannel(&channel3);
132 }
133 
TEST_F(VideoRtpReceiverTest,BroadcastsEncodedFramesWhenEnabled)134 TEST_F(VideoRtpReceiverTest, BroadcastsEncodedFramesWhenEnabled) {
135   std::function<void(const RecordableEncodedFrame&)> broadcast;
136   EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(_, _))
137       .WillRepeatedly(SaveArg<1>(&broadcast));
138   MockVideoSink sink;
139   Source()->AddEncodedSink(&sink);
140 
141   // Make sure SetEncodedFrameBufferFunction completes.
142   Mock::VerifyAndClearExpectations(&channel_);
143 
144   // Pass two frames on different contexts.
145   EXPECT_CALL(sink, OnFrame).Times(2);
146   MockRecordableEncodedFrame frame;
147   broadcast(frame);
148   worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] { broadcast(frame); });
149 }
150 
TEST_F(VideoRtpReceiverTest,EnablesEncodedOutputOnChannelRestart)151 TEST_F(VideoRtpReceiverTest, EnablesEncodedOutputOnChannelRestart) {
152   InSequence s;
153   EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(0));
154   MockVideoSink sink;
155   Source()->AddEncodedSink(&sink);
156   EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(4711, _));
157   receiver_->SetupMediaChannel(4711);
158   EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(4711));
159   EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(0, _));
160   receiver_->SetupUnsignaledMediaChannel();
161 }
162 
163 }  // namespace
164 }  // namespace webrtc
165