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 <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
19 using ::testing::_;
20 using ::testing::InSequence;
21 using ::testing::Mock;
22 using ::testing::SaveArg;
23 using ::testing::StrictMock;
24
25 namespace webrtc {
26 namespace {
27
28 class VideoRtpReceiverTest : public testing::Test {
29 protected:
30 class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
31 public:
MockVideoMediaChannel(cricket::FakeVideoEngine * engine,const cricket::VideoOptions & options)32 MockVideoMediaChannel(cricket::FakeVideoEngine* engine,
33 const cricket::VideoOptions& options)
34 : FakeVideoMediaChannel(engine, options) {}
35 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));
44 };
45
46 class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
47 public:
48 MOCK_METHOD(void, OnFrame, (const RecordableEncodedFrame&), (override));
49 };
50
VideoRtpReceiverTest()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
Source()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
TEST_F(VideoRtpReceiverTest,SupportsEncodedOutput)70 TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
71 EXPECT_TRUE(Source()->SupportsEncodedOutput());
72 }
73
TEST_F(VideoRtpReceiverTest,GeneratesKeyFrame)74 TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
75 EXPECT_CALL(channel_, GenerateKeyFrame(0));
76 Source()->GenerateKeyFrame();
77 }
78
TEST_F(VideoRtpReceiverTest,GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled)79 TEST_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
TEST_F(VideoRtpReceiverTest,EnablesEncodedOutput)101 TEST_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
TEST_F(VideoRtpReceiverTest,DisablesEncodedOutput)108 TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
109 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
110 MockVideoSink sink;
111 Source()->AddEncodedSink(&sink);
112 Source()->RemoveEncodedSink(&sink);
113 }
114
TEST_F(VideoRtpReceiverTest,DisablesEnablesEncodedOutputOnChannelSwitch)115 TEST_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
TEST_F(VideoRtpReceiverTest,BroadcastsEncodedFramesWhenEnabled)134 TEST_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
TEST_F(VideoRtpReceiverTest,EnablesEncodedOutputOnChannelRestart)151 TEST_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
165