blob: 56aa3688a866276907e3b6d5949740414e654592 [file] [log] [blame]
Markus Handell9c27ed22019-12-04 12:57:58 +01001/*
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
19using ::testing::_;
Tommi4ccdf932021-05-17 14:50:10 +020020using ::testing::AnyNumber;
Markus Handell9c27ed22019-12-04 12:57:58 +010021using ::testing::InSequence;
22using ::testing::Mock;
Tommi4ccdf932021-05-17 14:50:10 +020023using ::testing::NiceMock;
Markus Handell9c27ed22019-12-04 12:57:58 +010024using ::testing::SaveArg;
25using ::testing::StrictMock;
26
27namespace webrtc {
28namespace {
29
30class VideoRtpReceiverTest : public testing::Test {
31 protected:
32 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
33 public:
Tommic9625f02021-05-06 22:03:19 +020034 MockVideoMediaChannel(
35 cricket::FakeVideoEngine* engine,
36 const cricket::VideoOptions& options,
37 TaskQueueBase* network_thread = rtc::Thread::Current())
38 : FakeVideoMediaChannel(engine, options, network_thread) {}
Danil Chapovalov3a353122020-05-15 11:16:53 +020039 MOCK_METHOD(void,
40 SetRecordableEncodedFrameCallback,
41 (uint32_t, std::function<void(const RecordableEncodedFrame&)>),
42 (override));
43 MOCK_METHOD(void,
44 ClearRecordableEncodedFrameCallback,
45 (uint32_t),
46 (override));
47 MOCK_METHOD(void, GenerateKeyFrame, (uint32_t), (override));
Markus Handell9c27ed22019-12-04 12:57:58 +010048 };
49
50 class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
51 public:
Danil Chapovalov3a353122020-05-15 11:16:53 +020052 MOCK_METHOD(void, OnFrame, (const RecordableEncodedFrame&), (override));
Markus Handell9c27ed22019-12-04 12:57:58 +010053 };
54
55 VideoRtpReceiverTest()
56 : worker_thread_(rtc::Thread::Create()),
57 channel_(nullptr, cricket::VideoOptions()),
Tommi4ccdf932021-05-17 14:50:10 +020058 receiver_(rtc::make_ref_counted<VideoRtpReceiver>(
59 worker_thread_.get(),
60 std::string("receiver"),
61 std::vector<std::string>({"stream"}))) {
Markus Handell9c27ed22019-12-04 12:57:58 +010062 worker_thread_->Start();
Tommi6589def2022-02-17 23:36:47 +010063 SetMediaChannel(&channel_);
Markus Handell9c27ed22019-12-04 12:57:58 +010064 }
65
Tommi4ccdf932021-05-17 14:50:10 +020066 ~VideoRtpReceiverTest() override {
Tommi6589def2022-02-17 23:36:47 +010067 // Clear expectations that tests may have set up before calling
68 // SetMediaChannel(nullptr).
Tommi4ccdf932021-05-17 14:50:10 +020069 Mock::VerifyAndClearExpectations(&channel_);
70 receiver_->Stop();
Tommi6589def2022-02-17 23:36:47 +010071 SetMediaChannel(nullptr);
72 }
73
74 void SetMediaChannel(cricket::MediaChannel* media_channel) {
75 worker_thread_->Invoke<void>(
76 RTC_FROM_HERE, [&]() { receiver_->SetMediaChannel(media_channel); });
Tommi4ccdf932021-05-17 14:50:10 +020077 }
78
Markus Handell9c27ed22019-12-04 12:57:58 +010079 webrtc::VideoTrackSourceInterface* Source() {
80 return receiver_->streams()[0]->FindVideoTrack("receiver")->GetSource();
81 }
82
83 std::unique_ptr<rtc::Thread> worker_thread_;
Tommi4ccdf932021-05-17 14:50:10 +020084 NiceMock<MockVideoMediaChannel> channel_;
Markus Handell9c27ed22019-12-04 12:57:58 +010085 rtc::scoped_refptr<VideoRtpReceiver> receiver_;
86};
87
88TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
89 EXPECT_TRUE(Source()->SupportsEncodedOutput());
90}
91
92TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
93 EXPECT_CALL(channel_, GenerateKeyFrame(0));
94 Source()->GenerateKeyFrame();
95}
96
97TEST_F(VideoRtpReceiverTest,
98 GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled) {
99 // A channel switch without previous call to GenerateKeyFrame shouldn't
100 // cause a call to happen on the new channel.
101 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
102 EXPECT_CALL(channel_, GenerateKeyFrame).Times(0);
103 EXPECT_CALL(channel2, GenerateKeyFrame).Times(0);
Tommi6589def2022-02-17 23:36:47 +0100104 SetMediaChannel(&channel2);
Markus Handell9c27ed22019-12-04 12:57:58 +0100105 Mock::VerifyAndClearExpectations(&channel2);
106
107 // Generate a key frame. When we switch channel next time, we will have to
108 // re-generate it as we don't know if it was eventually received
Tommi6589def2022-02-17 23:36:47 +0100109 EXPECT_CALL(channel2, GenerateKeyFrame).Times(1);
Markus Handell9c27ed22019-12-04 12:57:58 +0100110 Source()->GenerateKeyFrame();
111 MockVideoMediaChannel channel3(nullptr, cricket::VideoOptions());
112 EXPECT_CALL(channel3, GenerateKeyFrame);
Tommi6589def2022-02-17 23:36:47 +0100113 SetMediaChannel(&channel3);
Markus Handell9c27ed22019-12-04 12:57:58 +0100114
115 // Switching to a new channel should now not cause calls to GenerateKeyFrame.
116 StrictMock<MockVideoMediaChannel> channel4(nullptr, cricket::VideoOptions());
Tommi6589def2022-02-17 23:36:47 +0100117 SetMediaChannel(&channel4);
Tommi4ccdf932021-05-17 14:50:10 +0200118
Tommi6589def2022-02-17 23:36:47 +0100119 // We must call SetMediaChannel(nullptr) here since the mock media channels
120 // live on the stack and `receiver_` still has a pointer to those objects.
121 SetMediaChannel(nullptr);
Markus Handell9c27ed22019-12-04 12:57:58 +0100122}
123
124TEST_F(VideoRtpReceiverTest, EnablesEncodedOutput) {
125 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(/*ssrc=*/0, _));
126 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback).Times(0);
127 MockVideoSink sink;
128 Source()->AddEncodedSink(&sink);
129}
130
131TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
132 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
133 MockVideoSink sink;
134 Source()->AddEncodedSink(&sink);
135 Source()->RemoveEncodedSink(&sink);
136}
137
138TEST_F(VideoRtpReceiverTest, DisablesEnablesEncodedOutputOnChannelSwitch) {
139 InSequence s;
140 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback);
141 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback);
142 MockVideoSink sink;
143 Source()->AddEncodedSink(&sink);
144 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
145 EXPECT_CALL(channel2, SetRecordableEncodedFrameCallback);
Tommi6589def2022-02-17 23:36:47 +0100146 SetMediaChannel(&channel2);
Markus Handell9c27ed22019-12-04 12:57:58 +0100147 Mock::VerifyAndClearExpectations(&channel2);
148
149 // When clearing encoded frame buffer function, we need channel switches
150 // to NOT set the callback again.
151 EXPECT_CALL(channel2, ClearRecordableEncodedFrameCallback);
152 Source()->RemoveEncodedSink(&sink);
153 StrictMock<MockVideoMediaChannel> channel3(nullptr, cricket::VideoOptions());
Tommi6589def2022-02-17 23:36:47 +0100154 SetMediaChannel(&channel3);
Tommi4ccdf932021-05-17 14:50:10 +0200155
Tommi6589def2022-02-17 23:36:47 +0100156 // We must call SetMediaChannel(nullptr) here since the mock media channels
157 // live on the stack and `receiver_` still has a pointer to those objects.
158 SetMediaChannel(nullptr);
Markus Handell9c27ed22019-12-04 12:57:58 +0100159}
160
161TEST_F(VideoRtpReceiverTest, BroadcastsEncodedFramesWhenEnabled) {
162 std::function<void(const RecordableEncodedFrame&)> broadcast;
163 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(_, _))
164 .WillRepeatedly(SaveArg<1>(&broadcast));
165 MockVideoSink sink;
166 Source()->AddEncodedSink(&sink);
167
168 // Make sure SetEncodedFrameBufferFunction completes.
169 Mock::VerifyAndClearExpectations(&channel_);
170
171 // Pass two frames on different contexts.
172 EXPECT_CALL(sink, OnFrame).Times(2);
173 MockRecordableEncodedFrame frame;
174 broadcast(frame);
175 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] { broadcast(frame); });
176}
177
178TEST_F(VideoRtpReceiverTest, EnablesEncodedOutputOnChannelRestart) {
179 InSequence s;
Markus Handell9c27ed22019-12-04 12:57:58 +0100180 MockVideoSink sink;
181 Source()->AddEncodedSink(&sink);
182 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(4711, _));
183 receiver_->SetupMediaChannel(4711);
184 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(4711));
185 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(0, _));
186 receiver_->SetupUnsignaledMediaChannel();
187}
188
189} // namespace
190} // namespace webrtc