blob: c13214fcbb6e33b2ed95d4051e4c90c45be94206 [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"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000020#include "rtc_base/location.h"
21#include "rtc_base/ref_counted_object.h"
Markus Handell9c27ed22019-12-04 12:57:58 +010022#include "test/gmock.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000023#include "test/gtest.h"
Markus Handell9c27ed22019-12-04 12:57:58 +010024
25using ::testing::_;
Tommi4ccdf932021-05-17 14:50:10 +020026using ::testing::AnyNumber;
Markus Handell9c27ed22019-12-04 12:57:58 +010027using ::testing::InSequence;
28using ::testing::Mock;
Tommi4ccdf932021-05-17 14:50:10 +020029using ::testing::NiceMock;
Markus Handell9c27ed22019-12-04 12:57:58 +010030using ::testing::SaveArg;
31using ::testing::StrictMock;
32
33namespace webrtc {
34namespace {
35
36class VideoRtpReceiverTest : public testing::Test {
37 protected:
38 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
39 public:
Tommic9625f02021-05-06 22:03:19 +020040 MockVideoMediaChannel(
41 cricket::FakeVideoEngine* engine,
42 const cricket::VideoOptions& options,
43 TaskQueueBase* network_thread = rtc::Thread::Current())
44 : FakeVideoMediaChannel(engine, options, network_thread) {}
Danil Chapovalov3a353122020-05-15 11:16:53 +020045 MOCK_METHOD(void,
46 SetRecordableEncodedFrameCallback,
47 (uint32_t, std::function<void(const RecordableEncodedFrame&)>),
48 (override));
49 MOCK_METHOD(void,
50 ClearRecordableEncodedFrameCallback,
51 (uint32_t),
52 (override));
53 MOCK_METHOD(void, GenerateKeyFrame, (uint32_t), (override));
Markus Handell9c27ed22019-12-04 12:57:58 +010054 };
55
56 class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
57 public:
Danil Chapovalov3a353122020-05-15 11:16:53 +020058 MOCK_METHOD(void, OnFrame, (const RecordableEncodedFrame&), (override));
Markus Handell9c27ed22019-12-04 12:57:58 +010059 };
60
61 VideoRtpReceiverTest()
62 : worker_thread_(rtc::Thread::Create()),
63 channel_(nullptr, cricket::VideoOptions()),
Tommi4ccdf932021-05-17 14:50:10 +020064 receiver_(rtc::make_ref_counted<VideoRtpReceiver>(
65 worker_thread_.get(),
66 std::string("receiver"),
67 std::vector<std::string>({"stream"}))) {
Markus Handell9c27ed22019-12-04 12:57:58 +010068 worker_thread_->Start();
Tommi6589def2022-02-17 23:36:47 +010069 SetMediaChannel(&channel_);
Markus Handell9c27ed22019-12-04 12:57:58 +010070 }
71
Tommi4ccdf932021-05-17 14:50:10 +020072 ~VideoRtpReceiverTest() override {
Tommi6589def2022-02-17 23:36:47 +010073 // Clear expectations that tests may have set up before calling
74 // SetMediaChannel(nullptr).
Tommi4ccdf932021-05-17 14:50:10 +020075 Mock::VerifyAndClearExpectations(&channel_);
76 receiver_->Stop();
Tommi6589def2022-02-17 23:36:47 +010077 SetMediaChannel(nullptr);
78 }
79
80 void SetMediaChannel(cricket::MediaChannel* media_channel) {
81 worker_thread_->Invoke<void>(
82 RTC_FROM_HERE, [&]() { receiver_->SetMediaChannel(media_channel); });
Tommi4ccdf932021-05-17 14:50:10 +020083 }
84
Markus Handell9c27ed22019-12-04 12:57:58 +010085 webrtc::VideoTrackSourceInterface* Source() {
86 return receiver_->streams()[0]->FindVideoTrack("receiver")->GetSource();
87 }
88
89 std::unique_ptr<rtc::Thread> worker_thread_;
Tommi4ccdf932021-05-17 14:50:10 +020090 NiceMock<MockVideoMediaChannel> channel_;
Markus Handell9c27ed22019-12-04 12:57:58 +010091 rtc::scoped_refptr<VideoRtpReceiver> receiver_;
92};
93
94TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
95 EXPECT_TRUE(Source()->SupportsEncodedOutput());
96}
97
98TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
99 EXPECT_CALL(channel_, GenerateKeyFrame(0));
100 Source()->GenerateKeyFrame();
101}
102
103TEST_F(VideoRtpReceiverTest,
104 GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled) {
105 // A channel switch without previous call to GenerateKeyFrame shouldn't
106 // cause a call to happen on the new channel.
107 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
108 EXPECT_CALL(channel_, GenerateKeyFrame).Times(0);
109 EXPECT_CALL(channel2, GenerateKeyFrame).Times(0);
Tommi6589def2022-02-17 23:36:47 +0100110 SetMediaChannel(&channel2);
Markus Handell9c27ed22019-12-04 12:57:58 +0100111 Mock::VerifyAndClearExpectations(&channel2);
112
113 // Generate a key frame. When we switch channel next time, we will have to
114 // re-generate it as we don't know if it was eventually received
Tommi6589def2022-02-17 23:36:47 +0100115 EXPECT_CALL(channel2, GenerateKeyFrame).Times(1);
Markus Handell9c27ed22019-12-04 12:57:58 +0100116 Source()->GenerateKeyFrame();
117 MockVideoMediaChannel channel3(nullptr, cricket::VideoOptions());
118 EXPECT_CALL(channel3, GenerateKeyFrame);
Tommi6589def2022-02-17 23:36:47 +0100119 SetMediaChannel(&channel3);
Markus Handell9c27ed22019-12-04 12:57:58 +0100120
121 // Switching to a new channel should now not cause calls to GenerateKeyFrame.
122 StrictMock<MockVideoMediaChannel> channel4(nullptr, cricket::VideoOptions());
Tommi6589def2022-02-17 23:36:47 +0100123 SetMediaChannel(&channel4);
Tommi4ccdf932021-05-17 14:50:10 +0200124
Tommi6589def2022-02-17 23:36:47 +0100125 // We must call SetMediaChannel(nullptr) here since the mock media channels
126 // live on the stack and `receiver_` still has a pointer to those objects.
127 SetMediaChannel(nullptr);
Markus Handell9c27ed22019-12-04 12:57:58 +0100128}
129
130TEST_F(VideoRtpReceiverTest, EnablesEncodedOutput) {
131 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(/*ssrc=*/0, _));
132 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback).Times(0);
133 MockVideoSink sink;
134 Source()->AddEncodedSink(&sink);
135}
136
137TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
138 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
139 MockVideoSink sink;
140 Source()->AddEncodedSink(&sink);
141 Source()->RemoveEncodedSink(&sink);
142}
143
144TEST_F(VideoRtpReceiverTest, DisablesEnablesEncodedOutputOnChannelSwitch) {
145 InSequence s;
146 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback);
147 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback);
148 MockVideoSink sink;
149 Source()->AddEncodedSink(&sink);
150 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
151 EXPECT_CALL(channel2, SetRecordableEncodedFrameCallback);
Tommi6589def2022-02-17 23:36:47 +0100152 SetMediaChannel(&channel2);
Markus Handell9c27ed22019-12-04 12:57:58 +0100153 Mock::VerifyAndClearExpectations(&channel2);
154
155 // When clearing encoded frame buffer function, we need channel switches
156 // to NOT set the callback again.
157 EXPECT_CALL(channel2, ClearRecordableEncodedFrameCallback);
158 Source()->RemoveEncodedSink(&sink);
159 StrictMock<MockVideoMediaChannel> channel3(nullptr, cricket::VideoOptions());
Tommi6589def2022-02-17 23:36:47 +0100160 SetMediaChannel(&channel3);
Tommi4ccdf932021-05-17 14:50:10 +0200161
Tommi6589def2022-02-17 23:36:47 +0100162 // We must call SetMediaChannel(nullptr) here since the mock media channels
163 // live on the stack and `receiver_` still has a pointer to those objects.
164 SetMediaChannel(nullptr);
Markus Handell9c27ed22019-12-04 12:57:58 +0100165}
166
167TEST_F(VideoRtpReceiverTest, BroadcastsEncodedFramesWhenEnabled) {
168 std::function<void(const RecordableEncodedFrame&)> broadcast;
169 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(_, _))
170 .WillRepeatedly(SaveArg<1>(&broadcast));
171 MockVideoSink sink;
172 Source()->AddEncodedSink(&sink);
173
174 // Make sure SetEncodedFrameBufferFunction completes.
175 Mock::VerifyAndClearExpectations(&channel_);
176
177 // Pass two frames on different contexts.
178 EXPECT_CALL(sink, OnFrame).Times(2);
179 MockRecordableEncodedFrame frame;
180 broadcast(frame);
181 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] { broadcast(frame); });
182}
183
184TEST_F(VideoRtpReceiverTest, EnablesEncodedOutputOnChannelRestart) {
185 InSequence s;
Markus Handell9c27ed22019-12-04 12:57:58 +0100186 MockVideoSink sink;
187 Source()->AddEncodedSink(&sink);
188 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(4711, _));
189 receiver_->SetupMediaChannel(4711);
190 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(4711));
191 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(0, _));
192 receiver_->SetupUnsignaledMediaChannel();
193}
194
195} // namespace
196} // namespace webrtc