blob: c4b7b8205d0a8a4e3b572a15096649a3228180d2 [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::_;
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) {}
35 MOCK_METHOD2(SetRecordableEncodedFrameCallback,
36 void(uint32_t,
37 std::function<void(const RecordableEncodedFrame&)>));
38 MOCK_METHOD1(ClearRecordableEncodedFrameCallback, void(uint32_t));
39 MOCK_METHOD1(GenerateKeyFrame, void(uint32_t));
40 };
41
42 class MockVideoSink : public rtc::VideoSinkInterface<RecordableEncodedFrame> {
43 public:
44 MOCK_METHOD1(OnFrame, void(const RecordableEncodedFrame&));
45 };
46
47 VideoRtpReceiverTest()
48 : worker_thread_(rtc::Thread::Create()),
49 channel_(nullptr, cricket::VideoOptions()),
50 receiver_(new VideoRtpReceiver(worker_thread_.get(),
51 "receiver",
52 {"stream"})) {
53 worker_thread_->Start();
54 receiver_->SetMediaChannel(&channel_);
55 }
56
57 webrtc::VideoTrackSourceInterface* Source() {
58 return receiver_->streams()[0]->FindVideoTrack("receiver")->GetSource();
59 }
60
61 std::unique_ptr<rtc::Thread> worker_thread_;
62 MockVideoMediaChannel channel_;
63 rtc::scoped_refptr<VideoRtpReceiver> receiver_;
64};
65
66TEST_F(VideoRtpReceiverTest, SupportsEncodedOutput) {
67 EXPECT_TRUE(Source()->SupportsEncodedOutput());
68}
69
70TEST_F(VideoRtpReceiverTest, GeneratesKeyFrame) {
71 EXPECT_CALL(channel_, GenerateKeyFrame(0));
72 Source()->GenerateKeyFrame();
73}
74
75TEST_F(VideoRtpReceiverTest,
76 GenerateKeyFrameOnChannelSwitchUnlessGenerateKeyframeCalled) {
77 // A channel switch without previous call to GenerateKeyFrame shouldn't
78 // cause a call to happen on the new channel.
79 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
80 EXPECT_CALL(channel_, GenerateKeyFrame).Times(0);
81 EXPECT_CALL(channel2, GenerateKeyFrame).Times(0);
82 receiver_->SetMediaChannel(&channel2);
83 Mock::VerifyAndClearExpectations(&channel2);
84
85 // Generate a key frame. When we switch channel next time, we will have to
86 // re-generate it as we don't know if it was eventually received
87 Source()->GenerateKeyFrame();
88 MockVideoMediaChannel channel3(nullptr, cricket::VideoOptions());
89 EXPECT_CALL(channel3, GenerateKeyFrame);
90 receiver_->SetMediaChannel(&channel3);
91
92 // Switching to a new channel should now not cause calls to GenerateKeyFrame.
93 StrictMock<MockVideoMediaChannel> channel4(nullptr, cricket::VideoOptions());
94 receiver_->SetMediaChannel(&channel4);
95}
96
97TEST_F(VideoRtpReceiverTest, EnablesEncodedOutput) {
98 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(/*ssrc=*/0, _));
99 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback).Times(0);
100 MockVideoSink sink;
101 Source()->AddEncodedSink(&sink);
102}
103
104TEST_F(VideoRtpReceiverTest, DisablesEncodedOutput) {
105 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(/*ssrc=*/0));
106 MockVideoSink sink;
107 Source()->AddEncodedSink(&sink);
108 Source()->RemoveEncodedSink(&sink);
109}
110
111TEST_F(VideoRtpReceiverTest, DisablesEnablesEncodedOutputOnChannelSwitch) {
112 InSequence s;
113 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback);
114 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback);
115 MockVideoSink sink;
116 Source()->AddEncodedSink(&sink);
117 MockVideoMediaChannel channel2(nullptr, cricket::VideoOptions());
118 EXPECT_CALL(channel2, SetRecordableEncodedFrameCallback);
119 receiver_->SetMediaChannel(&channel2);
120 Mock::VerifyAndClearExpectations(&channel2);
121
122 // When clearing encoded frame buffer function, we need channel switches
123 // to NOT set the callback again.
124 EXPECT_CALL(channel2, ClearRecordableEncodedFrameCallback);
125 Source()->RemoveEncodedSink(&sink);
126 StrictMock<MockVideoMediaChannel> channel3(nullptr, cricket::VideoOptions());
127 receiver_->SetMediaChannel(&channel3);
128}
129
130TEST_F(VideoRtpReceiverTest, BroadcastsEncodedFramesWhenEnabled) {
131 std::function<void(const RecordableEncodedFrame&)> broadcast;
132 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(_, _))
133 .WillRepeatedly(SaveArg<1>(&broadcast));
134 MockVideoSink sink;
135 Source()->AddEncodedSink(&sink);
136
137 // Make sure SetEncodedFrameBufferFunction completes.
138 Mock::VerifyAndClearExpectations(&channel_);
139
140 // Pass two frames on different contexts.
141 EXPECT_CALL(sink, OnFrame).Times(2);
142 MockRecordableEncodedFrame frame;
143 broadcast(frame);
144 worker_thread_->Invoke<void>(RTC_FROM_HERE, [&] { broadcast(frame); });
145}
146
147TEST_F(VideoRtpReceiverTest, EnablesEncodedOutputOnChannelRestart) {
148 InSequence s;
149 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(0));
150 MockVideoSink sink;
151 Source()->AddEncodedSink(&sink);
152 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(4711, _));
153 receiver_->SetupMediaChannel(4711);
154 EXPECT_CALL(channel_, ClearRecordableEncodedFrameCallback(4711));
155 EXPECT_CALL(channel_, SetRecordableEncodedFrameCallback(0, _));
156 receiver_->SetupUnsignaledMediaChannel();
157}
158
159} // namespace
160} // namespace webrtc