blob: 5efd6df47103d1a18771e87caec808ad8cdc9f1b [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
Harald Alvestrandc24a2182022-02-23 13:44:59 +000013#include <functional>
Markus Handell9c27ed22019-12-04 12:57:58 +010014#include <memory>
15
Harald Alvestrandc24a2182022-02-23 13:44:59 +000016#include "api/task_queue/task_queue_base.h"
17#include "api/video/recordable_encoded_frame.h"
Markus Handell9c27ed22019-12-04 12:57:58 +010018#include "api/video/test/mock_recordable_encoded_frame.h"
19#include "media/base/fake_media_engine.h"
Danil Chapovalov2aaef452022-08-12 15:55:11 +020020#include "rtc_base/task_queue_for_test.h"
Markus Handell9c27ed22019-12-04 12:57:58 +010021#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000022#include "test/gtest.h"
Markus Handell9c27ed22019-12-04 12:57:58 +010023
24using ::testing::_;
Tommi4ccdf932021-05-17 14:50:10 +020025using ::testing::AnyNumber;
Markus Handell9c27ed22019-12-04 12:57:58 +010026using ::testing::InSequence;
27using ::testing::Mock;
Tommi4ccdf932021-05-17 14:50:10 +020028using ::testing::NiceMock;
Markus Handell9c27ed22019-12-04 12:57:58 +010029using ::testing::SaveArg;
30using ::testing::StrictMock;
31
32namespace webrtc {
33namespace {
34
35class VideoRtpReceiverTest : public testing::Test {
36 protected:
37 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
38 public:
Tommic9625f02021-05-06 22:03:19 +020039 MockVideoMediaChannel(
40 cricket::FakeVideoEngine* engine,
41 const cricket::VideoOptions& options,
42 TaskQueueBase* network_thread = rtc::Thread::Current())
Harald Alvestrand16579cc2023-02-09 13:01:24 +000043 : FakeVideoMediaChannel(cricket::MediaChannel::Role::kBoth,
44 engine,
45 options,
46 network_thread) {}
Danil Chapovalov3a353122020-05-15 11:16:53 +020047 MOCK_METHOD(void,
48 SetRecordableEncodedFrameCallback,
49 (uint32_t, std::function<void(const RecordableEncodedFrame&)>),
50 (override));
51 MOCK_METHOD(void,
52 ClearRecordableEncodedFrameCallback,
53 (uint32_t),
54 (override));
Philipp Hancked237c2b2022-10-25 09:54:28 +020055 MOCK_METHOD(void, RequestRecvKeyFrame, (uint32_t), (override));
Philipp Hanckea1b4eb22022-11-04 14:45:23 +010056 MOCK_METHOD(void,
57 GenerateSendKeyFrame,
58 (uint32_t, const std::vector<std::string>&),
59 (override));
Markus Handell9c27ed22019-12-04 12:57:58 +010060 };
61
62 class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
63 public:
Danil Chapovalov3a353122020-05-15 11:16:53 +020064 MOCK_METHOD(void, OnFrame, (const RecordableEncodedFrame&), (override));
Markus Handell9c27ed22019-12-04 12:57:58 +010065 };
66
67 VideoRtpReceiverTest()
68 : worker_thread_(rtc::Thread::Create()),
69 channel_(nullptr, cricket::VideoOptions()),
Tommi4ccdf932021-05-17 14:50:10 +020070 receiver_(rtc::make_ref_counted<VideoRtpReceiver>(
71 worker_thread_.get(),
72 std::string("receiver"),
73 std::vector<std::string>({"stream"}))) {
Markus Handell9c27ed22019-12-04 12:57:58 +010074 worker_thread_->Start();
Tommi6589def2022-02-17 23:36:47 +010075 SetMediaChannel(&channel_);
Markus Handell9c27ed22019-12-04 12:57:58 +010076 }
77
Tommi4ccdf932021-05-17 14:50:10 +020078 ~VideoRtpReceiverTest() override {
Tommi6589def2022-02-17 23:36:47 +010079 // Clear expectations that tests may have set up before calling
80 // SetMediaChannel(nullptr).
Tommi4ccdf932021-05-17 14:50:10 +020081 Mock::VerifyAndClearExpectations(&channel_);
82 receiver_->Stop();
Tommi6589def2022-02-17 23:36:47 +010083 SetMediaChannel(nullptr);
84 }
85
86 void SetMediaChannel(cricket::MediaChannel* media_channel) {
Danil Chapovalov2aaef452022-08-12 15:55:11 +020087 SendTask(worker_thread_.get(),
88 [&]() { receiver_->SetMediaChannel(media_channel); });
Tommi4ccdf932021-05-17 14:50:10 +020089 }
90
Markus Handell9c27ed22019-12-04 12:57:58 +010091 webrtc::VideoTrackSourceInterface* Source() {
92 return receiver_->streams()[0]->FindVideoTrack("receiver")->GetSource();
93 }
94
Niels Möller83830f32022-05-20 09:12:57 +020095 rtc::AutoThread main_thread_;
Markus Handell9c27ed22019-12-04 12:57:58 +010096 std::unique_ptr<rtc::Thread> worker_thread_;
Tommi4ccdf932021-05-17 14:50:10 +020097 NiceMock<MockVideoMediaChannel> channel_;
Markus Handell9c27ed22019-12-04 12:57:58 +010098 rtc::scoped_refptr<VideoRtpReceiver> receiver_;
99};
100
101TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
102 EXPECT_TRUE(Source()->SupportsEncodedOutput());
103}
104
105TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
Philipp Hancked237c2b2022-10-25 09:54:28 +0200106 EXPECT_CALL(channel_, RequestRecvKeyFrame(0));
Markus Handell9c27ed22019-12-04 12:57:58 +0100107 Source()->GenerateKeyFrame();
108}
109
110TEST_F(VideoRtpReceiverTest,
111 GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled) {
112 // A channel switch without previous call to GenerateKeyFrame shouldn't
113 // cause a call to happen on the new channel.
114 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
Philipp Hancked237c2b2022-10-25 09:54:28 +0200115 EXPECT_CALL(channel_, RequestRecvKeyFrame).Times(0);
116 EXPECT_CALL(channel2, RequestRecvKeyFrame).Times(0);
Tommi6589def2022-02-17 23:36:47 +0100117 SetMediaChannel(&channel2);
Markus Handell9c27ed22019-12-04 12:57:58 +0100118 Mock::VerifyAndClearExpectations(&channel2);
119
120 // Generate a key frame. When we switch channel next time, we will have to
121 // re-generate it as we don't know if it was eventually received
Philipp Hancked237c2b2022-10-25 09:54:28 +0200122 EXPECT_CALL(channel2, RequestRecvKeyFrame).Times(1);
Markus Handell9c27ed22019-12-04 12:57:58 +0100123 Source()->GenerateKeyFrame();
124 MockVideoMediaChannel channel3(nullptr, cricket::VideoOptions());
Philipp Hancked237c2b2022-10-25 09:54:28 +0200125 EXPECT_CALL(channel3, RequestRecvKeyFrame);
Tommi6589def2022-02-17 23:36:47 +0100126 SetMediaChannel(&channel3);
Markus Handell9c27ed22019-12-04 12:57:58 +0100127
128 // Switching to a new channel should now not cause calls to GenerateKeyFrame.
129 StrictMock<MockVideoMediaChannel> channel4(nullptr, cricket::VideoOptions());
Tommi6589def2022-02-17 23:36:47 +0100130 SetMediaChannel(&channel4);
Tommi4ccdf932021-05-17 14:50:10 +0200131
Tommi6589def2022-02-17 23:36:47 +0100132 // We must call SetMediaChannel(nullptr) here since the mock media channels
133 // live on the stack and `receiver_` still has a pointer to those objects.
134 SetMediaChannel(nullptr);
Markus Handell9c27ed22019-12-04 12:57:58 +0100135}
136
137TEST_F(VideoRtpReceiverTest, EnablesEncodedOutput) {
138 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(/*ssrc=*/0, _));
139 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback).Times(0);
140 MockVideoSink sink;
141 Source()->AddEncodedSink(&sink);
142}
143
144TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
145 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
146 MockVideoSink sink;
147 Source()->AddEncodedSink(&sink);
148 Source()->RemoveEncodedSink(&sink);
149}
150
151TEST_F(VideoRtpReceiverTest, DisablesEnablesEncodedOutputOnChannelSwitch) {
152 InSequence s;
153 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback);
154 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback);
155 MockVideoSink sink;
156 Source()->AddEncodedSink(&sink);
157 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
158 EXPECT_CALL(channel2, SetRecordableEncodedFrameCallback);
Tommi6589def2022-02-17 23:36:47 +0100159 SetMediaChannel(&channel2);
Markus Handell9c27ed22019-12-04 12:57:58 +0100160 Mock::VerifyAndClearExpectations(&channel2);
161
162 // When clearing encoded frame buffer function, we need channel switches
163 // to NOT set the callback again.
164 EXPECT_CALL(channel2, ClearRecordableEncodedFrameCallback);
165 Source()->RemoveEncodedSink(&sink);
166 StrictMock<MockVideoMediaChannel> channel3(nullptr, cricket::VideoOptions());
Tommi6589def2022-02-17 23:36:47 +0100167 SetMediaChannel(&channel3);
Tommi4ccdf932021-05-17 14:50:10 +0200168
Tommi6589def2022-02-17 23:36:47 +0100169 // We must call SetMediaChannel(nullptr) here since the mock media channels
170 // live on the stack and `receiver_` still has a pointer to those objects.
171 SetMediaChannel(nullptr);
Markus Handell9c27ed22019-12-04 12:57:58 +0100172}
173
174TEST_F(VideoRtpReceiverTest, BroadcastsEncodedFramesWhenEnabled) {
175 std::function<void(const RecordableEncodedFrame&)> broadcast;
176 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(_, _))
177 .WillRepeatedly(SaveArg<1>(&broadcast));
178 MockVideoSink sink;
179 Source()->AddEncodedSink(&sink);
180
181 // Make sure SetEncodedFrameBufferFunction completes.
182 Mock::VerifyAndClearExpectations(&channel_);
183
184 // Pass two frames on different contexts.
185 EXPECT_CALL(sink, OnFrame).Times(2);
186 MockRecordableEncodedFrame frame;
187 broadcast(frame);
Danil Chapovalov2aaef452022-08-12 15:55:11 +0200188 SendTask(worker_thread_.get(), [&] { broadcast(frame); });
Markus Handell9c27ed22019-12-04 12:57:58 +0100189}
190
191TEST_F(VideoRtpReceiverTest, EnablesEncodedOutputOnChannelRestart) {
192 InSequence s;
Markus Handell9c27ed22019-12-04 12:57:58 +0100193 MockVideoSink sink;
194 Source()->AddEncodedSink(&sink);
195 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(4711, _));
196 receiver_->SetupMediaChannel(4711);
197 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(4711));
198 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(0, _));
199 receiver_->SetupUnsignaledMediaChannel();
200}
201
202} // namespace
203} // namespace webrtc