blob: b3eb6e6e355d8bb389b5894eef55b6550ce1123d [file] [log] [blame]
Markus Handell9c27ed22019-12-04 11:57:581/*
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::_;
20using ::testing::InSequence;
21using ::testing::Mock;
22using ::testing::SaveArg;
23using ::testing::StrictMock;
24
25namespace webrtc {
26namespace {
27
28class VideoRtpReceiverTest : public testing::Test {
29 protected:
30 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
31 public:
32 MockVideoMediaChannel(cricket::FakeVideoEngine* engine,
33 const cricket::VideoOptions& options)
34 : FakeVideoMediaChannel(engine, options) {}
Danil Chapovalov3a353122020-05-15 09:16:5335 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));
Markus Handell9c27ed22019-12-04 11:57:5844 };
45
46 class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
47 public:
Danil Chapovalov3a353122020-05-15 09:16:5348 MOCK_METHOD(void, OnFrame, (const RecordableEncodedFrame&), (override));
Markus Handell9c27ed22019-12-04 11:57:5849 };
50
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
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
70TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
71 EXPECT_TRUE(Source()->SupportsEncodedOutput());
72}
73
74TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
75 EXPECT_CALL(channel_, GenerateKeyFrame(0));
76 Source()->GenerateKeyFrame();
77}
78
79TEST_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
101TEST_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
108TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
109 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
110 MockVideoSink sink;
111 Source()->AddEncodedSink(&sink);
112 Source()->RemoveEncodedSink(&sink);
113}
114
115TEST_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
134TEST_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
151TEST_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