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 <functional>
14 #include <memory>
15
16 #include "api/task_queue/task_queue_base.h"
17 #include "api/video/recordable_encoded_frame.h"
18 #include "api/video/test/mock_recordable_encoded_frame.h"
19 #include "media/base/fake_media_engine.h"
20 #include "rtc_base/task_queue_for_test.h"
21 #include "test/gmock.h"
22 #include "test/gtest.h"
23
24 using ::testing::_;
25 using ::testing::AnyNumber;
26 using ::testing::InSequence;
27 using ::testing::Mock;
28 using ::testing::NiceMock;
29 using ::testing::SaveArg;
30 using ::testing::StrictMock;
31
32 namespace webrtc {
33 namespace {
34
35 class VideoRtpReceiverTest : public testing::Test {
36 protected:
37 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
38 public:
MockVideoMediaChannel(cricket::FakeVideoEngine * engine,const cricket::VideoOptions & options,TaskQueueBase * network_thread=rtc::Thread::Current ())39 MockVideoMediaChannel(
40 cricket::FakeVideoEngine* engine,
41 const cricket::VideoOptions& options,
42 TaskQueueBase* network_thread = rtc::Thread::Current())
43 : FakeVideoMediaChannel(engine, options, network_thread) {}
44 MOCK_METHOD(void,
45 SetRecordableEncodedFrameCallback,
46 (uint32_t, std::function<void(const RecordableEncodedFrame&)>),
47 (override));
48 MOCK_METHOD(void,
49 ClearRecordableEncodedFrameCallback,
50 (uint32_t),
51 (override));
52 MOCK_METHOD(void, RequestRecvKeyFrame, (uint32_t), (override));
53 MOCK_METHOD(void,
54 GenerateSendKeyFrame,
55 (uint32_t, const std::vector<std::string>&),
56 (override));
57 };
58
59 class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
60 public:
61 MOCK_METHOD(void, OnFrame, (const RecordableEncodedFrame&), (override));
62 };
63
VideoRtpReceiverTest()64 VideoRtpReceiverTest()
65 : worker_thread_(rtc::Thread::Create()),
66 channel_(nullptr, cricket::VideoOptions()),
67 receiver_(rtc::make_ref_counted<VideoRtpReceiver>(
68 worker_thread_.get(),
69 std::string("receiver"),
70 std::vector<std::string>({"stream"}))) {
71 worker_thread_->Start();
72 SetMediaChannel(&channel_);
73 }
74
~VideoRtpReceiverTest()75 ~VideoRtpReceiverTest() override {
76 // Clear expectations that tests may have set up before calling
77 // SetMediaChannel(nullptr).
78 Mock::VerifyAndClearExpectations(&channel_);
79 receiver_->Stop();
80 SetMediaChannel(nullptr);
81 }
82
SetMediaChannel(cricket::MediaChannel * media_channel)83 void SetMediaChannel(cricket::MediaChannel* media_channel) {
84 SendTask(worker_thread_.get(),
85 [&]() { receiver_->SetMediaChannel(media_channel); });
86 }
87
Source()88 webrtc::VideoTrackSourceInterface* Source() {
89 return receiver_->streams()[0]->FindVideoTrack("receiver")->GetSource();
90 }
91
92 rtc::AutoThread main_thread_;
93 std::unique_ptr<rtc::Thread> worker_thread_;
94 NiceMock<MockVideoMediaChannel> channel_;
95 rtc::scoped_refptr<VideoRtpReceiver> receiver_;
96 };
97
TEST_F(VideoRtpReceiverTest,SupportsEncodedOutput)98 TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
99 EXPECT_TRUE(Source()->SupportsEncodedOutput());
100 }
101
TEST_F(VideoRtpReceiverTest,GeneratesKeyFrame)102 TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
103 EXPECT_CALL(channel_, RequestRecvKeyFrame(0));
104 Source()->GenerateKeyFrame();
105 }
106
TEST_F(VideoRtpReceiverTest,GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled)107 TEST_F(VideoRtpReceiverTest,
108 GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled) {
109 // A channel switch without previous call to GenerateKeyFrame shouldn't
110 // cause a call to happen on the new channel.
111 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
112 EXPECT_CALL(channel_, RequestRecvKeyFrame).Times(0);
113 EXPECT_CALL(channel2, RequestRecvKeyFrame).Times(0);
114 SetMediaChannel(&channel2);
115 Mock::VerifyAndClearExpectations(&channel2);
116
117 // Generate a key frame. When we switch channel next time, we will have to
118 // re-generate it as we don't know if it was eventually received
119 EXPECT_CALL(channel2, RequestRecvKeyFrame).Times(1);
120 Source()->GenerateKeyFrame();
121 MockVideoMediaChannel channel3(nullptr, cricket::VideoOptions());
122 EXPECT_CALL(channel3, RequestRecvKeyFrame);
123 SetMediaChannel(&channel3);
124
125 // Switching to a new channel should now not cause calls to GenerateKeyFrame.
126 StrictMock<MockVideoMediaChannel> channel4(nullptr, cricket::VideoOptions());
127 SetMediaChannel(&channel4);
128
129 // We must call SetMediaChannel(nullptr) here since the mock media channels
130 // live on the stack and `receiver_` still has a pointer to those objects.
131 SetMediaChannel(nullptr);
132 }
133
TEST_F(VideoRtpReceiverTest,EnablesEncodedOutput)134 TEST_F(VideoRtpReceiverTest, EnablesEncodedOutput) {
135 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(/*ssrc=*/0, _));
136 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback).Times(0);
137 MockVideoSink sink;
138 Source()->AddEncodedSink(&sink);
139 }
140
TEST_F(VideoRtpReceiverTest,DisablesEncodedOutput)141 TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
142 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
143 MockVideoSink sink;
144 Source()->AddEncodedSink(&sink);
145 Source()->RemoveEncodedSink(&sink);
146 }
147
TEST_F(VideoRtpReceiverTest,DisablesEnablesEncodedOutputOnChannelSwitch)148 TEST_F(VideoRtpReceiverTest, DisablesEnablesEncodedOutputOnChannelSwitch) {
149 InSequence s;
150 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback);
151 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback);
152 MockVideoSink sink;
153 Source()->AddEncodedSink(&sink);
154 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
155 EXPECT_CALL(channel2, SetRecordableEncodedFrameCallback);
156 SetMediaChannel(&channel2);
157 Mock::VerifyAndClearExpectations(&channel2);
158
159 // When clearing encoded frame buffer function, we need channel switches
160 // to NOT set the callback again.
161 EXPECT_CALL(channel2, ClearRecordableEncodedFrameCallback);
162 Source()->RemoveEncodedSink(&sink);
163 StrictMock<MockVideoMediaChannel> channel3(nullptr, cricket::VideoOptions());
164 SetMediaChannel(&channel3);
165
166 // We must call SetMediaChannel(nullptr) here since the mock media channels
167 // live on the stack and `receiver_` still has a pointer to those objects.
168 SetMediaChannel(nullptr);
169 }
170
TEST_F(VideoRtpReceiverTest,BroadcastsEncodedFramesWhenEnabled)171 TEST_F(VideoRtpReceiverTest, BroadcastsEncodedFramesWhenEnabled) {
172 std::function<void(const RecordableEncodedFrame&)> broadcast;
173 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(_, _))
174 .WillRepeatedly(SaveArg<1>(&broadcast));
175 MockVideoSink sink;
176 Source()->AddEncodedSink(&sink);
177
178 // Make sure SetEncodedFrameBufferFunction completes.
179 Mock::VerifyAndClearExpectations(&channel_);
180
181 // Pass two frames on different contexts.
182 EXPECT_CALL(sink, OnFrame).Times(2);
183 MockRecordableEncodedFrame frame;
184 broadcast(frame);
185 SendTask(worker_thread_.get(), [&] { broadcast(frame); });
186 }
187
TEST_F(VideoRtpReceiverTest,EnablesEncodedOutputOnChannelRestart)188 TEST_F(VideoRtpReceiverTest, EnablesEncodedOutputOnChannelRestart) {
189 InSequence s;
190 MockVideoSink sink;
191 Source()->AddEncodedSink(&sink);
192 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(4711, _));
193 receiver_->SetupMediaChannel(4711);
194 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(4711));
195 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(0, _));
196 receiver_->SetupUnsignaledMediaChannel();
197 }
198
199 } // namespace
200 } // namespace webrtc
201