• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 3-Clause Clear License
5  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6  * License was not distributed with this source code in the LICENSE file, you
7  * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8  * Alliance for Open Media Patent License 1.0 was not distributed with this
9  * source code in the PATENTS file, you can obtain it at
10  * www.aomedia.org/license/patent.
11  */
12 
13 #include "iamf/cli/renderer/audio_element_renderer_passthrough.h"
14 
15 #include <cstddef>
16 #include <functional>
17 #include <memory>
18 #include <numeric>
19 #include <thread>
20 #include <vector>
21 
22 #include "absl/status/status_matchers.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "iamf/cli/channel_label.h"
26 #include "iamf/cli/demixing_module.h"
27 #include "iamf/cli/tests/cli_test_utils.h"
28 #include "iamf/obu/audio_element.h"
29 #include "iamf/obu/mix_presentation.h"
30 #include "iamf/obu/types.h"
31 
32 namespace iamf_tools {
33 namespace {
34 
35 using ::absl_testing::IsOk;
36 using enum ChannelAudioLayerConfig::LoudspeakerLayout;
37 using enum ChannelAudioLayerConfig::ExpandedLoudspeakerLayout;
38 using enum ChannelLabel::Label;
39 using enum LoudspeakersSsConventionLayout::SoundSystem;
40 using testing::DoubleEq;
41 using testing::Pointwise;
42 
GetScalableLayoutForSoundSystem(LoudspeakersSsConventionLayout::SoundSystem sound_system)43 Layout GetScalableLayoutForSoundSystem(
44     LoudspeakersSsConventionLayout::SoundSystem sound_system) {
45   return {.layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
46           .specific_layout =
47               LoudspeakersSsConventionLayout{.sound_system = sound_system}};
48 }
49 
50 ScalableChannelLayoutConfig
GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(ChannelAudioLayerConfig::ExpandedLoudspeakerLayout expanded_layout)51 GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
52     ChannelAudioLayerConfig::ExpandedLoudspeakerLayout expanded_layout) {
53   return {.num_layers = 1,
54           .channel_audio_layer_configs = {
55               {.loudspeaker_layout = kLayoutExpanded,
56                .expanded_loudspeaker_layout = expanded_layout}}};
57 }
58 
59 const Layout kMonoLayout =
60     GetScalableLayoutForSoundSystem(kSoundSystem12_0_1_0);
61 const Layout kStereoLayout =
62     GetScalableLayoutForSoundSystem(kSoundSystemA_0_2_0);
63 const Layout kBinauralLayout = {.layout_type = Layout::kLayoutTypeBinaural};
64 const Layout k7_1_4Layout =
65     GetScalableLayoutForSoundSystem(kSoundSystemJ_4_7_0);
66 const Layout k5_1_4Layout =
67     GetScalableLayoutForSoundSystem(kSoundSystemD_4_5_0);
68 
69 const ScalableChannelLayoutConfig kBinauralScalableChannelLayoutConfig = {
70     .num_layers = 1,
71     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayoutBinaural}}};
72 const ScalableChannelLayoutConfig kStereoScalableChannelLayoutConfig = {
73     .num_layers = 1,
74     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayoutStereo}}};
75 const ScalableChannelLayoutConfig kStereoChannelConfigWithTwoLayers = {
76     .num_layers = 2,
77     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayoutMono},
78                                     {.loudspeaker_layout = kLayoutStereo}}};
79 const ScalableChannelLayoutConfig k7_1_4ScalableChannelLayoutConfig = {
80     .num_layers = 1,
81     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayout7_1_4_ch}}};
82 const ScalableChannelLayoutConfig kMonoScalableChannelLayoutConfig = {
83     .num_layers = 1,
84     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayoutMono}}};
85 
86 constexpr size_t kFourSamplesPerFrame = 4;
87 
TEST(CreateFromScalableChannelLayoutConfig,SupportsPassThroughBinaural)88 TEST(CreateFromScalableChannelLayoutConfig, SupportsPassThroughBinaural) {
89   EXPECT_NE(
90       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
91           kBinauralScalableChannelLayoutConfig, kBinauralLayout,
92           kFourSamplesPerFrame),
93       nullptr);
94 }
95 
TEST(CreateFromScalableChannelLayoutConfig,SupportsPassThroughStereo)96 TEST(CreateFromScalableChannelLayoutConfig, SupportsPassThroughStereo) {
97   EXPECT_NE(
98       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
99           kStereoScalableChannelLayoutConfig, kStereoLayout,
100           kFourSamplesPerFrame),
101       nullptr);
102 }
103 
TEST(CreateFromScalableChannelLayoutConfig,SupportsPassThroughIfAnyLayerMatches)104 TEST(CreateFromScalableChannelLayoutConfig,
105      SupportsPassThroughIfAnyLayerMatches) {
106   EXPECT_NE(
107       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
108           kStereoScalableChannelLayoutConfig, kStereoLayout,
109           kFourSamplesPerFrame),
110       nullptr);
111 }
112 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportBinauralToStereo)113 TEST(CreateFromScalableChannelLayoutConfig, DoesNotSupportBinauralToStereo) {
114   EXPECT_EQ(
115       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
116           kBinauralScalableChannelLayoutConfig, kStereoLayout,
117           kFourSamplesPerFrame),
118       nullptr);
119 }
120 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportStereoToBinaural)121 TEST(CreateFromScalableChannelLayoutConfig, DoesNotSupportStereoToBinaural) {
122   EXPECT_EQ(
123       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
124           kStereoScalableChannelLayoutConfig, kBinauralLayout,
125           kFourSamplesPerFrame),
126       nullptr);
127 }
128 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportIfNoLayerMatches)129 TEST(CreateFromScalableChannelLayoutConfig, DoesNotSupportIfNoLayerMatches) {
130   EXPECT_EQ(
131       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
132           kStereoScalableChannelLayoutConfig, kMonoLayout,
133           kFourSamplesPerFrame),
134       nullptr);
135 }
136 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportReservedLayout)137 TEST(CreateFromScalableChannelLayoutConfig, DoesNotSupportReservedLayout) {
138   const Layout kReservedLayout = {
139       .layout_type = Layout::kLayoutTypeReserved0,
140       .specific_layout = LoudspeakersReservedOrBinauralLayout{.reserved = 0}};
141 
142   EXPECT_EQ(
143       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
144           kStereoScalableChannelLayoutConfig, kReservedLayout,
145           kFourSamplesPerFrame),
146       nullptr);
147 }
148 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportReservedLayoutWithNoEquivalentSoundSystem)149 TEST(CreateFromScalableChannelLayoutConfig,
150      DoesNotSupportReservedLayoutWithNoEquivalentSoundSystem) {
151   const Layout kLayoutWithNoEquivalentSoundSystem = {
152       .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
153       .specific_layout =
154           LoudspeakersSsConventionLayout{.sound_system = kSoundSystemG_4_9_0}};
155 
156   EXPECT_EQ(
157       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
158           kStereoScalableChannelLayoutConfig,
159           kLayoutWithNoEquivalentSoundSystem, kFourSamplesPerFrame),
160       nullptr);
161 }
162 
TEST(CreateFromScalableChannelLayoutConfig,SupportsPassThroughFromExpandedLFETo7_1_4)163 TEST(CreateFromScalableChannelLayoutConfig,
164      SupportsPassThroughFromExpandedLFETo7_1_4) {
165   EXPECT_NE(
166       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
167           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
168               kExpandedLayoutLFE),
169           k7_1_4Layout, kFourSamplesPerFrame),
170       nullptr);
171 }
172 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportPassThroughFromExpandedLFETo7_1_2)173 TEST(CreateFromScalableChannelLayoutConfig,
174      DoesNotSupportPassThroughFromExpandedLFETo7_1_2) {
175   EXPECT_EQ(
176       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
177           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
178               kExpandedLayoutLFE),
179           GetScalableLayoutForSoundSystem(kSoundSystem10_2_7_0),
180           kFourSamplesPerFrame),
181       nullptr);
182 }
183 
TEST(CreateFromScalableChannelLayoutConfig,SupportsPassThroughFromStereoSTo5_1_4)184 TEST(CreateFromScalableChannelLayoutConfig,
185      SupportsPassThroughFromStereoSTo5_1_4) {
186   EXPECT_NE(
187       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
188           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
189               kExpandedLayoutStereoS),
190           k5_1_4Layout, kFourSamplesPerFrame),
191       nullptr);
192 }
193 
TEST(CreateFromScalableChannelLayoutConfig,SupportsPassThroughFor9_1_6)194 TEST(CreateFromScalableChannelLayoutConfig, SupportsPassThroughFor9_1_6) {
195   EXPECT_NE(
196       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
197           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
198               kExpandedLayout9_1_6_ch),
199           GetScalableLayoutForSoundSystem(kSoundSystem13_6_9_0),
200           kFourSamplesPerFrame),
201       nullptr);
202 }
203 
TEST(CreateFromScalableChannelLayoutConfig,SupportsPassThroughFromTop6ChTo9_1_6)204 TEST(CreateFromScalableChannelLayoutConfig,
205      SupportsPassThroughFromTop6ChTo9_1_6) {
206   EXPECT_NE(
207       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
208           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
209               kExpandedLayoutTop6Ch),
210           GetScalableLayoutForSoundSystem(kSoundSystem13_6_9_0),
211           kFourSamplesPerFrame),
212       nullptr);
213 }
214 
215 const LabeledFrame kLabeledFrameWithL2AndR2 = {
216     .label_to_samples = {{kL2, {1, 3, 5, 7}}, {kR2, {2, 4, 6, 8}}}};
217 
TEST(RenderLabeledFrame,RendersPassThroughStereo)218 TEST(RenderLabeledFrame, RendersPassThroughStereo) {
219   auto stereo_pass_through_renderer =
220       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
221           kStereoScalableChannelLayoutConfig, kStereoLayout,
222           kFourSamplesPerFrame);
223 
224   std::vector<InternalSampleType> rendered_samples;
225   RenderAndFlushExpectOk(kLabeledFrameWithL2AndR2,
226                          stereo_pass_through_renderer.get(), rendered_samples);
227 
228   const std::vector<InternalSampleType> expected_samples(
229       {1, 2, 3, 4, 5, 6, 7, 8});
230   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
231 }
232 
TEST(RenderLabeledFrame,RendersPassThroughBinaural)233 TEST(RenderLabeledFrame, RendersPassThroughBinaural) {
234   auto binaural_pass_through_renderer =
235       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
236           kBinauralScalableChannelLayoutConfig, kBinauralLayout,
237           kFourSamplesPerFrame);
238 
239   std::vector<InternalSampleType> rendered_samples;
240   RenderAndFlushExpectOk(kLabeledFrameWithL2AndR2,
241                          binaural_pass_through_renderer.get(),
242                          rendered_samples);
243 
244   const std::vector<InternalSampleType> expected_samples(
245       {1, 2, 3, 4, 5, 6, 7, 8});
246   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
247 }
248 
TEST(RenderLabeledFrame,RendersPassThrough7_1_4)249 TEST(RenderLabeledFrame, RendersPassThrough7_1_4) {
250   const LabeledFrame k7_1_4LabeledFrame = {.label_to_samples = {
251                                                {kL7, {0, 100}},
252                                                {kR7, {1, 101}},
253                                                {kCentre, {2, 102}},
254                                                {kLFE, {3, 103}},
255                                                {kLss7, {4, 104}},
256                                                {kRss7, {5, 105}},
257                                                {kLrs7, {6, 106}},
258                                                {kRrs7, {7, 107}},
259                                                {kLtf4, {8, 108}},
260                                                {kRtf4, {9, 109}},
261                                                {kLtb4, {10, 110}},
262                                                {kRtb4, {11, 111}},
263                                            }};
264   auto pass_through_renderer =
265       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
266           k7_1_4ScalableChannelLayoutConfig, k7_1_4Layout,
267           kFourSamplesPerFrame);
268 
269   std::vector<InternalSampleType> rendered_samples;
270   RenderAndFlushExpectOk(k7_1_4LabeledFrame, pass_through_renderer.get(),
271                          rendered_samples);
272 
273   const std::vector<InternalSampleType> expected_samples(
274       {0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,
275        100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111});
276   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
277 }
278 
TEST(RenderLabeledFrame,RendersPassThroughLFE)279 TEST(RenderLabeledFrame, RendersPassThroughLFE) {
280   const LabeledFrame kLFELabeledFrame = {
281       .label_to_samples = {{kLFE, {3, 103}}}};
282   auto pass_through_renderer =
283       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
284           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
285               ChannelAudioLayerConfig::kExpandedLayoutLFE),
286           GetScalableLayoutForSoundSystem(kSoundSystemJ_4_7_0),
287           kFourSamplesPerFrame);
288 
289   std::vector<InternalSampleType> rendered_samples;
290   RenderAndFlushExpectOk(kLFELabeledFrame, pass_through_renderer.get(),
291                          rendered_samples);
292 
293   const std::vector<InternalSampleType> expected_samples(
294       {0, 0, 0, 3,   0, 0, 0, 0, 0, 0, 0, 0,
295        0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0});
296   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
297 }
298 
TEST(RenderLabeledFrame,RendersPassThroughStereoS)299 TEST(RenderLabeledFrame, RendersPassThroughStereoS) {
300   const LabeledFrame kStereoSLabeledFrame = {.label_to_samples = {
301                                                  {kLs5, {4, 104}},
302                                                  {kRs5, {5, 105}},
303                                              }};
304   auto pass_through_renderer =
305       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
306           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
307               ChannelAudioLayerConfig::kExpandedLayoutStereoS),
308           GetScalableLayoutForSoundSystem(kSoundSystemD_4_5_0),
309           kFourSamplesPerFrame);
310 
311   std::vector<InternalSampleType> rendered_samples;
312   RenderAndFlushExpectOk(kStereoSLabeledFrame, pass_through_renderer.get(),
313                          rendered_samples);
314 
315   const std::vector<InternalSampleType> expected_samples(
316       {0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 104, 105, 0, 0, 0, 0});
317   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
318 }
319 
TEST(RenderLabeledFrame,RendersPassThrough3_0_Ch)320 TEST(RenderLabeledFrame, RendersPassThrough3_0_Ch) {
321   const LabeledFrame k7_1_4LabeledFrame = {.label_to_samples = {
322                                                {kL7, {0, 100}},
323                                                {kR7, {1, 101}},
324                                                {kCentre, {2, 102}},
325                                            }};
326   auto pass_through_renderer =
327       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
328           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
329               ChannelAudioLayerConfig::kExpandedLayout3_0_ch),
330           GetScalableLayoutForSoundSystem(kSoundSystemJ_4_7_0),
331           kFourSamplesPerFrame);
332 
333   std::vector<InternalSampleType> rendered_samples;
334   RenderAndFlushExpectOk(k7_1_4LabeledFrame, pass_through_renderer.get(),
335                          rendered_samples);
336 
337   const std::vector<InternalSampleType> expected_samples(
338       {0,   1,   2,   0, 0, 0, 0, 0, 0, 0, 0, 0,
339        100, 101, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0});
340   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
341 }
342 
TEST(RenderLabeledFrame,RendersPassThrough9_1_6)343 TEST(RenderLabeledFrame, RendersPassThrough9_1_6) {
344   const LabeledFrame k9_1_6LabeledFrame = {.label_to_samples = {
345                                                {kFL, {0, 100}},
346                                                {kFR, {1, 101}},
347                                                {kFC, {2, 102}},
348                                                {kLFE, {3, 103}},
349                                                {kBL, {4, 104}},
350                                                {kBR, {5, 105}},
351                                                {kFLc, {6, 106}},
352                                                {kFRc, {7, 107}},
353                                                {kSiL, {8, 108}},
354                                                {kSiR, {9, 109}},
355                                                {kTpFL, {10, 110}},
356                                                {kTpFR, {11, 111}},
357                                                {kTpBL, {12, 112}},
358                                                {kTpBR, {13, 113}},
359                                                {kTpSiL, {14, 114}},
360                                                {kTpSiR, {15, 115}},
361                                            }};
362   auto pass_through_renderer =
363       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
364           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
365               ChannelAudioLayerConfig::kExpandedLayout9_1_6_ch),
366           GetScalableLayoutForSoundSystem(kSoundSystem13_6_9_0),
367           kFourSamplesPerFrame);
368 
369   std::vector<InternalSampleType> rendered_samples;
370   RenderAndFlushExpectOk(k9_1_6LabeledFrame, pass_through_renderer.get(),
371                          rendered_samples);
372 
373   const std::vector<InternalSampleType> expected_samples(
374       {0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,
375        11,  12,  13,  14,  15,  100, 101, 102, 103, 104, 105,
376        106, 107, 108, 109, 110, 111, 112, 113, 114, 115});
377   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
378 }
379 
TEST(RenderLabeledFrame,RendersPassThroughStereoF)380 TEST(RenderLabeledFrame, RendersPassThroughStereoF) {
381   const LabeledFrame kStreoFLabeledFrame = {.label_to_samples = {
382                                                 {kFL, {0, 100}},
383                                                 {kFR, {1, 101}},
384                                             }};
385   auto pass_through_renderer =
386       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
387           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
388               ChannelAudioLayerConfig::kExpandedLayoutStereoF),
389           GetScalableLayoutForSoundSystem(kSoundSystem13_6_9_0),
390           kFourSamplesPerFrame);
391 
392   std::vector<InternalSampleType> rendered_samples;
393   RenderAndFlushExpectOk(kStreoFLabeledFrame, pass_through_renderer.get(),
394                          rendered_samples);
395 
396   const std::vector<InternalSampleType> expected_samples(
397       {0,   1,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398        100, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
399   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
400 }
401 
TEST(RenderLabeledFrame,RendersPassThroughTop6Ch)402 TEST(RenderLabeledFrame, RendersPassThroughTop6Ch) {
403   const LabeledFrame kTop6ChLabeledFrame = {.label_to_samples = {
404                                                 {kTpFL, {10, 110}},
405                                                 {kTpFR, {11, 111}},
406                                                 {kTpBL, {12, 112}},
407                                                 {kTpBR, {13, 113}},
408                                                 {kTpSiL, {14, 114}},
409                                                 {kTpSiR, {15, 115}},
410                                             }};
411   auto pass_through_renderer =
412       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
413           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
414               ChannelAudioLayerConfig::kExpandedLayoutTop6Ch),
415           GetScalableLayoutForSoundSystem(kSoundSystem13_6_9_0),
416           kFourSamplesPerFrame);
417 
418   std::vector<InternalSampleType> rendered_samples;
419   RenderAndFlushExpectOk(kTop6ChLabeledFrame, pass_through_renderer.get(),
420                          rendered_samples);
421 
422   const std::vector<InternalSampleType> expected_samples(
423       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,  11,  12,  13,  14,  15,
424        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 111, 112, 113, 114, 115});
425   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
426 }
427 
TEST(RenderLabeledFrame,RendersDemixedSamples)428 TEST(RenderLabeledFrame, RendersDemixedSamples) {
429   const LabeledFrame kTwoLayerStereo = {
430       .label_to_samples = {{kMono, {999}}, {kL2, {1}}, {kDemixedR2, {2}}}};
431 
432   auto demixed_stereo_renderer =
433       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
434           kStereoChannelConfigWithTwoLayers, kStereoLayout,
435           kFourSamplesPerFrame);
436   EXPECT_NE(demixed_stereo_renderer, nullptr);
437 
438   EXPECT_THAT(demixed_stereo_renderer->RenderLabeledFrame(kTwoLayerStereo),
439               IsOk());
440   EXPECT_THAT(demixed_stereo_renderer->Finalize(), IsOk());
441   EXPECT_TRUE(demixed_stereo_renderer->IsFinalized());
442   std::vector<InternalSampleType> rendered_samples;
443   EXPECT_THAT(demixed_stereo_renderer->Flush(rendered_samples), IsOk());
444   const std::vector<InternalSampleType> expected_samples({1, 2});
445   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
446 }
447 
TEST(RenderLabeledFrame,ReturnsNumberOfTicksToRender)448 TEST(RenderLabeledFrame, ReturnsNumberOfTicksToRender) {
449   const LabeledFrame kStereoFrameWithTwoRenderedTicks = {
450       .samples_to_trim_at_end = 1,
451       .samples_to_trim_at_start = 1,
452       .label_to_samples = {{kL2, {999, 1, 2, 999}}, {kR2, {999, 1, 2, 999}}}};
453 
454   auto stereo_pass_through_renderer =
455       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
456           kStereoScalableChannelLayoutConfig, kStereoLayout,
457           kFourSamplesPerFrame);
458   const auto result = stereo_pass_through_renderer->RenderLabeledFrame(
459       kStereoFrameWithTwoRenderedTicks);
460   EXPECT_THAT(result, IsOk());
461   EXPECT_EQ(*result, 2);
462 }
463 
TEST(RenderLabeledFrame,EdgeCaseWithAllSamplesTrimmedReturnsZero)464 TEST(RenderLabeledFrame, EdgeCaseWithAllSamplesTrimmedReturnsZero) {
465   const LabeledFrame kMonoFrame = {.samples_to_trim_at_start = 1,
466                                    .label_to_samples = {{kMono, {1}}}};
467 
468   auto mono_pass_through_renderer =
469       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
470           kMonoScalableChannelLayoutConfig, kMonoLayout, kFourSamplesPerFrame);
471   const auto result =
472       mono_pass_through_renderer->RenderLabeledFrame(kMonoFrame);
473   EXPECT_THAT(result, IsOk());
474   EXPECT_EQ(*result, 0);
475 }
476 
477 // Renders a sequence of `num_frames` frames, each with `samples_per_frame`
478 // samples. The sequence increases by one for each value in the sequence.
RenderMonoSequence(int num_frames,int samples_per_frame,AudioElementRendererPassThrough & renderer)479 void RenderMonoSequence(int num_frames, int samples_per_frame,
480                         AudioElementRendererPassThrough& renderer) {
481   int sample = 0;
482   for (int frame_index = 0; frame_index < num_frames; ++frame_index) {
483     std::vector<InternalSampleType> samples(samples_per_frame);
484     std::iota(samples.begin(), samples.end(), sample);
485     sample += samples_per_frame;
486 
487     EXPECT_THAT(
488         renderer.RenderLabeledFrame({.label_to_samples = {{kMono, samples}}}),
489         IsOk());
490   }
491   EXPECT_THAT(renderer.Finalize(), IsOk());
492 }
493 
494 // Collects all of the rendered samples from `renderer` into `rendered_samples`.
495 // This function blocks until the renderer is finalized.
CollectRenderedSamples(AudioElementRendererPassThrough & renderer,std::vector<InternalSampleType> & rendered_samples)496 void CollectRenderedSamples(AudioElementRendererPassThrough& renderer,
497                             std::vector<InternalSampleType>& rendered_samples) {
498   while (!renderer.IsFinalized()) {
499     // In practice threads would be better off sleeping between calls. But
500     // calling it very often is more likely to detect a problem.
501     EXPECT_THAT(renderer.Flush(rendered_samples), IsOk());
502   }
503   EXPECT_THAT(renderer.Flush(rendered_samples), IsOk());
504 }
505 
TEST(RenderLabeledFrame,IsThreadSafe)506 TEST(RenderLabeledFrame, IsThreadSafe) {
507   constexpr int kSamplesPerFrame = 10;
508   auto mono_pass_through_renderer =
509       AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
510           kMonoScalableChannelLayoutConfig, kMonoLayout, kSamplesPerFrame);
511   EXPECT_NE(mono_pass_through_renderer, nullptr);
512   constexpr int kNumFrames = 1000;
513 
514   // Spawn a thread to render an increasing sequence.
515   std::thread render_thread(&RenderMonoSequence, kNumFrames, kSamplesPerFrame,
516                             std::ref(*mono_pass_through_renderer));
517   // Spawn a thread to collect all of the rendered samples.
518   std::vector<InternalSampleType> rendered_samples;
519   std::thread collector_thread(&CollectRenderedSamples,
520                                std::ref(*mono_pass_through_renderer),
521                                std::ref(rendered_samples));
522   render_thread.join();
523   collector_thread.join();
524 
525   // If the render was not thread safe, then we would expect trouble, such as
526   // missing samples or samples coming back in the wrong order.
527   std::vector<InternalSampleType> expected_samples(kNumFrames *
528                                                    kSamplesPerFrame);
529   std::iota(expected_samples.begin(), expected_samples.end(), 0);
530   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), expected_samples));
531 }
532 
533 }  // namespace
534 }  // namespace iamf_tools
535