xref: /aosp_15_r20/external/webrtc/media/base/video_broadcaster_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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