1 /*
2 * Copyright 2016 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 "media/base/video_broadcaster.h"
12
13 #include <limits>
14
15 #include "absl/types/optional.h"
16 #include "api/video/i420_buffer.h"
17 #include "api/video/video_frame.h"
18 #include "api/video/video_rotation.h"
19 #include "api/video/video_source_interface.h"
20 #include "media/base/fake_video_renderer.h"
21 #include "test/gmock.h"
22 #include "test/gtest.h"
23
24 using cricket::FakeVideoRenderer;
25 using rtc::VideoBroadcaster;
26 using rtc::VideoSinkWants;
27 using FrameSize = rtc::VideoSinkWants::FrameSize;
28
29 using ::testing::AllOf;
30 using ::testing::Eq;
31 using ::testing::Field;
32 using ::testing::Mock;
33 using ::testing::Optional;
34
35 class MockSink : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
36 public:
OnFrame(const webrtc::VideoFrame &)37 void OnFrame(const webrtc::VideoFrame&) override {}
38
39 MOCK_METHOD(void,
40 OnConstraintsChanged,
41 (const webrtc::VideoTrackSourceConstraints& constraints),
42 (override));
43 };
44
TEST(VideoBroadcasterTest,frame_wanted)45 TEST(VideoBroadcasterTest, frame_wanted) {
46 VideoBroadcaster broadcaster;
47 EXPECT_FALSE(broadcaster.frame_wanted());
48
49 FakeVideoRenderer sink;
50 broadcaster.AddOrUpdateSink(&sink, rtc::VideoSinkWants());
51 EXPECT_TRUE(broadcaster.frame_wanted());
52
53 broadcaster.RemoveSink(&sink);
54 EXPECT_FALSE(broadcaster.frame_wanted());
55 }
56
TEST(VideoBroadcasterTest,OnFrame)57 TEST(VideoBroadcasterTest, OnFrame) {
58 VideoBroadcaster broadcaster;
59
60 FakeVideoRenderer sink1;
61 FakeVideoRenderer sink2;
62 broadcaster.AddOrUpdateSink(&sink1, rtc::VideoSinkWants());
63 broadcaster.AddOrUpdateSink(&sink2, rtc::VideoSinkWants());
64 static int kWidth = 100;
65 static int kHeight = 50;
66
67 rtc::scoped_refptr<webrtc::I420Buffer> buffer(
68 webrtc::I420Buffer::Create(kWidth, kHeight));
69 // Initialize, to avoid warnings on use of initialized values.
70 webrtc::I420Buffer::SetBlack(buffer.get());
71
72 webrtc::VideoFrame frame = webrtc::VideoFrame::Builder()
73 .set_video_frame_buffer(buffer)
74 .set_rotation(webrtc::kVideoRotation_0)
75 .set_timestamp_us(0)
76 .build();
77
78 broadcaster.OnFrame(frame);
79 EXPECT_EQ(1, sink1.num_rendered_frames());
80 EXPECT_EQ(1, sink2.num_rendered_frames());
81
82 broadcaster.RemoveSink(&sink1);
83 broadcaster.OnFrame(frame);
84 EXPECT_EQ(1, sink1.num_rendered_frames());
85 EXPECT_EQ(2, sink2.num_rendered_frames());
86
87 broadcaster.AddOrUpdateSink(&sink1, rtc::VideoSinkWants());
88 broadcaster.OnFrame(frame);
89 EXPECT_EQ(2, sink1.num_rendered_frames());
90 EXPECT_EQ(3, sink2.num_rendered_frames());
91 }
92
TEST(VideoBroadcasterTest,AppliesRotationIfAnySinkWantsRotationApplied)93 TEST(VideoBroadcasterTest, AppliesRotationIfAnySinkWantsRotationApplied) {
94 VideoBroadcaster broadcaster;
95 EXPECT_FALSE(broadcaster.wants().rotation_applied);
96
97 FakeVideoRenderer sink1;
98 VideoSinkWants wants1;
99 wants1.rotation_applied = false;
100
101 broadcaster.AddOrUpdateSink(&sink1, wants1);
102 EXPECT_FALSE(broadcaster.wants().rotation_applied);
103
104 FakeVideoRenderer sink2;
105 VideoSinkWants wants2;
106 wants2.rotation_applied = true;
107
108 broadcaster.AddOrUpdateSink(&sink2, wants2);
109 EXPECT_TRUE(broadcaster.wants().rotation_applied);
110
111 broadcaster.RemoveSink(&sink2);
112 EXPECT_FALSE(broadcaster.wants().rotation_applied);
113 }
114
TEST(VideoBroadcasterTest,AppliesMinOfSinkWantsMaxPixelCount)115 TEST(VideoBroadcasterTest, AppliesMinOfSinkWantsMaxPixelCount) {
116 VideoBroadcaster broadcaster;
117 EXPECT_EQ(std::numeric_limits<int>::max(),
118 broadcaster.wants().max_pixel_count);
119
120 FakeVideoRenderer sink1;
121 VideoSinkWants wants1;
122 wants1.max_pixel_count = 1280 * 720;
123
124 broadcaster.AddOrUpdateSink(&sink1, wants1);
125 EXPECT_EQ(1280 * 720, broadcaster.wants().max_pixel_count);
126
127 FakeVideoRenderer sink2;
128 VideoSinkWants wants2;
129 wants2.max_pixel_count = 640 * 360;
130 broadcaster.AddOrUpdateSink(&sink2, wants2);
131 EXPECT_EQ(640 * 360, broadcaster.wants().max_pixel_count);
132
133 broadcaster.RemoveSink(&sink2);
134 EXPECT_EQ(1280 * 720, broadcaster.wants().max_pixel_count);
135 }
136
TEST(VideoBroadcasterTest,AppliesMinOfSinkWantsMaxAndTargetPixelCount)137 TEST(VideoBroadcasterTest, AppliesMinOfSinkWantsMaxAndTargetPixelCount) {
138 VideoBroadcaster broadcaster;
139 EXPECT_TRUE(!broadcaster.wants().target_pixel_count);
140
141 FakeVideoRenderer sink1;
142 VideoSinkWants wants1;
143 wants1.target_pixel_count = 1280 * 720;
144
145 broadcaster.AddOrUpdateSink(&sink1, wants1);
146 EXPECT_EQ(1280 * 720, *broadcaster.wants().target_pixel_count);
147
148 FakeVideoRenderer sink2;
149 VideoSinkWants wants2;
150 wants2.target_pixel_count = 640 * 360;
151 broadcaster.AddOrUpdateSink(&sink2, wants2);
152 EXPECT_EQ(640 * 360, *broadcaster.wants().target_pixel_count);
153
154 broadcaster.RemoveSink(&sink2);
155 EXPECT_EQ(1280 * 720, *broadcaster.wants().target_pixel_count);
156 }
157
TEST(VideoBroadcasterTest,AppliesMinOfSinkWantsMaxFramerate)158 TEST(VideoBroadcasterTest, AppliesMinOfSinkWantsMaxFramerate) {
159 VideoBroadcaster broadcaster;
160 EXPECT_EQ(std::numeric_limits<int>::max(),
161 broadcaster.wants().max_framerate_fps);
162
163 FakeVideoRenderer sink1;
164 VideoSinkWants wants1;
165 wants1.max_framerate_fps = 30;
166
167 broadcaster.AddOrUpdateSink(&sink1, wants1);
168 EXPECT_EQ(30, broadcaster.wants().max_framerate_fps);
169
170 FakeVideoRenderer sink2;
171 VideoSinkWants wants2;
172 wants2.max_framerate_fps = 15;
173 broadcaster.AddOrUpdateSink(&sink2, wants2);
174 EXPECT_EQ(15, broadcaster.wants().max_framerate_fps);
175
176 broadcaster.RemoveSink(&sink2);
177 EXPECT_EQ(30, broadcaster.wants().max_framerate_fps);
178 }
179
TEST(VideoBroadcasterTest,AppliesLeastCommonMultipleOfSinkWantsResolutionAlignment)180 TEST(VideoBroadcasterTest,
181 AppliesLeastCommonMultipleOfSinkWantsResolutionAlignment) {
182 VideoBroadcaster broadcaster;
183 EXPECT_EQ(broadcaster.wants().resolution_alignment, 1);
184
185 FakeVideoRenderer sink1;
186 VideoSinkWants wants1;
187 wants1.resolution_alignment = 2;
188 broadcaster.AddOrUpdateSink(&sink1, wants1);
189 EXPECT_EQ(broadcaster.wants().resolution_alignment, 2);
190
191 FakeVideoRenderer sink2;
192 VideoSinkWants wants2;
193 wants2.resolution_alignment = 3;
194 broadcaster.AddOrUpdateSink(&sink2, wants2);
195 EXPECT_EQ(broadcaster.wants().resolution_alignment, 6);
196
197 FakeVideoRenderer sink3;
198 VideoSinkWants wants3;
199 wants3.resolution_alignment = 4;
200 broadcaster.AddOrUpdateSink(&sink3, wants3);
201 EXPECT_EQ(broadcaster.wants().resolution_alignment, 12);
202
203 broadcaster.RemoveSink(&sink2);
204 EXPECT_EQ(broadcaster.wants().resolution_alignment, 4);
205 }
206
TEST(VideoBroadcasterTest,SinkWantsBlackFrames)207 TEST(VideoBroadcasterTest, SinkWantsBlackFrames) {
208 VideoBroadcaster broadcaster;
209 EXPECT_TRUE(!broadcaster.wants().black_frames);
210
211 FakeVideoRenderer sink1;
212 VideoSinkWants wants1;
213 wants1.black_frames = true;
214 broadcaster.AddOrUpdateSink(&sink1, wants1);
215
216 FakeVideoRenderer sink2;
217 VideoSinkWants wants2;
218 wants2.black_frames = false;
219 broadcaster.AddOrUpdateSink(&sink2, wants2);
220
221 rtc::scoped_refptr<webrtc::I420Buffer> buffer(
222 webrtc::I420Buffer::Create(100, 200));
223 // Makes it not all black.
224 buffer->InitializeData();
225
226 webrtc::VideoFrame frame1 = webrtc::VideoFrame::Builder()
227 .set_video_frame_buffer(buffer)
228 .set_rotation(webrtc::kVideoRotation_0)
229 .set_timestamp_us(10)
230 .build();
231 broadcaster.OnFrame(frame1);
232 EXPECT_TRUE(sink1.black_frame());
233 EXPECT_EQ(10, sink1.timestamp_us());
234 EXPECT_FALSE(sink2.black_frame());
235 EXPECT_EQ(10, sink2.timestamp_us());
236
237 // Switch the sink wants.
238 wants1.black_frames = false;
239 broadcaster.AddOrUpdateSink(&sink1, wants1);
240 wants2.black_frames = true;
241 broadcaster.AddOrUpdateSink(&sink2, wants2);
242
243 webrtc::VideoFrame frame2 = webrtc::VideoFrame::Builder()
244 .set_video_frame_buffer(buffer)
245 .set_rotation(webrtc::kVideoRotation_0)
246 .set_timestamp_us(30)
247 .build();
248 broadcaster.OnFrame(frame2);
249 EXPECT_FALSE(sink1.black_frame());
250 EXPECT_EQ(30, sink1.timestamp_us());
251 EXPECT_TRUE(sink2.black_frame());
252 EXPECT_EQ(30, sink2.timestamp_us());
253 }
254
TEST(VideoBroadcasterTest,ConstraintsChangedNotCalledOnSinkAddition)255 TEST(VideoBroadcasterTest, ConstraintsChangedNotCalledOnSinkAddition) {
256 MockSink sink;
257 VideoBroadcaster broadcaster;
258 EXPECT_CALL(sink, OnConstraintsChanged).Times(0);
259 broadcaster.AddOrUpdateSink(&sink, VideoSinkWants());
260 }
261
TEST(VideoBroadcasterTest,ForwardsLastConstraintsOnAdd)262 TEST(VideoBroadcasterTest, ForwardsLastConstraintsOnAdd) {
263 MockSink sink;
264 VideoBroadcaster broadcaster;
265 broadcaster.ProcessConstraints(webrtc::VideoTrackSourceConstraints{2, 3});
266 broadcaster.ProcessConstraints(webrtc::VideoTrackSourceConstraints{1, 4});
267 EXPECT_CALL(
268 sink,
269 OnConstraintsChanged(AllOf(
270 Field(&webrtc::VideoTrackSourceConstraints::min_fps, Optional(1)),
271 Field(&webrtc::VideoTrackSourceConstraints::max_fps, Optional(4)))));
272 broadcaster.AddOrUpdateSink(&sink, VideoSinkWants());
273 }
274
TEST(VideoBroadcasterTest,UpdatesOnlyNewSinksWithConstraints)275 TEST(VideoBroadcasterTest, UpdatesOnlyNewSinksWithConstraints) {
276 MockSink sink1;
277 VideoBroadcaster broadcaster;
278 broadcaster.AddOrUpdateSink(&sink1, VideoSinkWants());
279 broadcaster.ProcessConstraints(webrtc::VideoTrackSourceConstraints{1, 4});
280 Mock::VerifyAndClearExpectations(&sink1);
281 EXPECT_CALL(sink1, OnConstraintsChanged).Times(0);
282 MockSink sink2;
283 EXPECT_CALL(
284 sink2,
285 OnConstraintsChanged(AllOf(
286 Field(&webrtc::VideoTrackSourceConstraints::min_fps, Optional(1)),
287 Field(&webrtc::VideoTrackSourceConstraints::max_fps, Optional(4)))));
288 broadcaster.AddOrUpdateSink(&sink2, VideoSinkWants());
289 }
290
TEST(VideoBroadcasterTest,ForwardsConstraintsToSink)291 TEST(VideoBroadcasterTest, ForwardsConstraintsToSink) {
292 MockSink sink;
293 VideoBroadcaster broadcaster;
294 EXPECT_CALL(sink, OnConstraintsChanged).Times(0);
295 broadcaster.AddOrUpdateSink(&sink, VideoSinkWants());
296 Mock::VerifyAndClearExpectations(&sink);
297
298 EXPECT_CALL(sink, OnConstraintsChanged(AllOf(
299 Field(&webrtc::VideoTrackSourceConstraints::min_fps,
300 Eq(absl::nullopt)),
301 Field(&webrtc::VideoTrackSourceConstraints::max_fps,
302 Eq(absl::nullopt)))));
303 broadcaster.ProcessConstraints(
304 webrtc::VideoTrackSourceConstraints{absl::nullopt, absl::nullopt});
305 Mock::VerifyAndClearExpectations(&sink);
306
307 EXPECT_CALL(
308 sink,
309 OnConstraintsChanged(AllOf(
310 Field(&webrtc::VideoTrackSourceConstraints::min_fps,
311 Eq(absl::nullopt)),
312 Field(&webrtc::VideoTrackSourceConstraints::max_fps, Optional(3)))));
313 broadcaster.ProcessConstraints(
314 webrtc::VideoTrackSourceConstraints{absl::nullopt, 3});
315 Mock::VerifyAndClearExpectations(&sink);
316
317 EXPECT_CALL(
318 sink,
319 OnConstraintsChanged(AllOf(
320 Field(&webrtc::VideoTrackSourceConstraints::min_fps, Optional(2)),
321 Field(&webrtc::VideoTrackSourceConstraints::max_fps,
322 Eq(absl::nullopt)))));
323 broadcaster.ProcessConstraints(
324 webrtc::VideoTrackSourceConstraints{2, absl::nullopt});
325 Mock::VerifyAndClearExpectations(&sink);
326
327 EXPECT_CALL(
328 sink,
329 OnConstraintsChanged(AllOf(
330 Field(&webrtc::VideoTrackSourceConstraints::min_fps, Optional(2)),
331 Field(&webrtc::VideoTrackSourceConstraints::max_fps, Optional(3)))));
332 broadcaster.ProcessConstraints(webrtc::VideoTrackSourceConstraints{2, 3});
333 }
334
TEST(VideoBroadcasterTest,AppliesMaxOfSinkWantsRequestedResolution)335 TEST(VideoBroadcasterTest, AppliesMaxOfSinkWantsRequestedResolution) {
336 VideoBroadcaster broadcaster;
337
338 FakeVideoRenderer sink1;
339 VideoSinkWants wants1;
340 wants1.requested_resolution = FrameSize(640, 360);
341
342 broadcaster.AddOrUpdateSink(&sink1, wants1);
343 EXPECT_EQ(FrameSize(640, 360), *broadcaster.wants().requested_resolution);
344
345 FakeVideoRenderer sink2;
346 VideoSinkWants wants2;
347 wants2.requested_resolution = FrameSize(650, 350);
348 broadcaster.AddOrUpdateSink(&sink2, wants2);
349 EXPECT_EQ(FrameSize(650, 360), *broadcaster.wants().requested_resolution);
350
351 broadcaster.RemoveSink(&sink2);
352 EXPECT_EQ(FrameSize(640, 360), *broadcaster.wants().requested_resolution);
353 }
354
TEST(VideoBroadcasterTest,AnyActive)355 TEST(VideoBroadcasterTest, AnyActive) {
356 VideoBroadcaster broadcaster;
357
358 FakeVideoRenderer sink1;
359 VideoSinkWants wants1;
360 wants1.is_active = false;
361
362 broadcaster.AddOrUpdateSink(&sink1, wants1);
363 EXPECT_EQ(false, broadcaster.wants().is_active);
364
365 FakeVideoRenderer sink2;
366 VideoSinkWants wants2;
367 wants2.is_active = true;
368 broadcaster.AddOrUpdateSink(&sink2, wants2);
369 EXPECT_EQ(true, broadcaster.wants().is_active);
370
371 broadcaster.RemoveSink(&sink2);
372 EXPECT_EQ(false, broadcaster.wants().is_active);
373 }
374
TEST(VideoBroadcasterTest,AnyActiveWithoutRequestedResolution)375 TEST(VideoBroadcasterTest, AnyActiveWithoutRequestedResolution) {
376 VideoBroadcaster broadcaster;
377
378 FakeVideoRenderer sink1;
379 VideoSinkWants wants1;
380 wants1.is_active = true;
381 wants1.requested_resolution = FrameSize(640, 360);
382
383 broadcaster.AddOrUpdateSink(&sink1, wants1);
384 EXPECT_EQ(
385 false,
386 broadcaster.wants().aggregates->any_active_without_requested_resolution);
387
388 FakeVideoRenderer sink2;
389 VideoSinkWants wants2;
390 wants2.is_active = true;
391 broadcaster.AddOrUpdateSink(&sink2, wants2);
392 EXPECT_EQ(
393 true,
394 broadcaster.wants().aggregates->any_active_without_requested_resolution);
395
396 broadcaster.RemoveSink(&sink2);
397 EXPECT_EQ(
398 false,
399 broadcaster.wants().aggregates->any_active_without_requested_resolution);
400 }
401
402 // This verifies that the VideoSinkWants from a Sink that is_active = false
403 // is ignored IF there is an active sink using new api (Requested_Resolution).
404 // The uses resolution_alignment for verification.
TEST(VideoBroadcasterTest,IgnoreInactiveSinkIfNewApiUsed)405 TEST(VideoBroadcasterTest, IgnoreInactiveSinkIfNewApiUsed) {
406 VideoBroadcaster broadcaster;
407
408 FakeVideoRenderer sink1;
409 VideoSinkWants wants1;
410 wants1.is_active = true;
411 wants1.requested_resolution = FrameSize(640, 360);
412 wants1.resolution_alignment = 2;
413 broadcaster.AddOrUpdateSink(&sink1, wants1);
414 EXPECT_EQ(broadcaster.wants().resolution_alignment, 2);
415
416 FakeVideoRenderer sink2;
417 VideoSinkWants wants2;
418 wants2.is_active = true;
419 wants2.resolution_alignment = 8;
420 broadcaster.AddOrUpdateSink(&sink2, wants2);
421 EXPECT_EQ(broadcaster.wants().resolution_alignment, 8);
422
423 // Now wants2 will be ignored.
424 wants2.is_active = false;
425 broadcaster.AddOrUpdateSink(&sink2, wants2);
426 EXPECT_EQ(broadcaster.wants().resolution_alignment, 2);
427
428 // But when wants1 is inactive, wants2 matters again.
429 wants1.is_active = false;
430 broadcaster.AddOrUpdateSink(&sink1, wants1);
431 EXPECT_EQ(broadcaster.wants().resolution_alignment, 8);
432
433 // inactive wants1 (new api) is always ignored.
434 broadcaster.RemoveSink(&sink2);
435 EXPECT_EQ(broadcaster.wants().resolution_alignment, 1);
436 }
437