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_channel_to_channel.h"
14 
15 #include <cstddef>
16 #include <vector>
17 
18 #include "absl/status/status_matchers.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include "iamf/cli/channel_label.h"
22 #include "iamf/cli/demixing_module.h"
23 #include "iamf/cli/tests/cli_test_utils.h"
24 #include "iamf/obu/audio_element.h"
25 #include "iamf/obu/mix_presentation.h"
26 #include "iamf/obu/types.h"
27 
28 namespace iamf_tools {
29 namespace {
30 
31 using ::absl_testing::IsOk;
32 using enum ChannelAudioLayerConfig::LoudspeakerLayout;
33 using enum ChannelLabel::Label;
34 using enum LoudspeakersSsConventionLayout::SoundSystem;
35 using testing::DoubleEq;
36 using testing::Pointwise;
37 
38 constexpr InternalSampleType kArbitrarySample1 = 12345.0;
39 constexpr InternalSampleType kArbitrarySample2 = 6789.0;
40 constexpr InternalSampleType kArbitrarySample3 = 101112.0;
41 constexpr InternalSampleType kArbitrarySample4 = 9999999.0;
42 constexpr InternalSampleType kArbitrarySample5 = 987654321.0;
43 constexpr InternalSampleType kArbitrarySample6 = 1024.0;
44 
45 constexpr int kStereoL2ChannelIndex = 0;
46 constexpr int kStereoR2ChannelIndex = 1;
47 constexpr int k3_1_2LFEChannelIndex = 3;
48 constexpr int k5_1LFEChannelIndex = 3;
49 constexpr int k9_1_6LFEChannelIndex = 3;
50 
51 constexpr size_t kOneSamplePerFrame = 1;
52 
53 const Layout kMonoLayout = {
54     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
55     .specific_layout =
56         LoudspeakersSsConventionLayout{.sound_system = kSoundSystem12_0_1_0}};
57 const Layout kStereoLayout = {
58     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
59     .specific_layout =
60         LoudspeakersSsConventionLayout{.sound_system = kSoundSystemA_0_2_0}};
61 const Layout kBinauralLayout = {.layout_type = Layout::kLayoutTypeBinaural};
62 const Layout k5_1_0Layout = {
63     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
64     .specific_layout =
65         LoudspeakersSsConventionLayout{.sound_system = kSoundSystemB_0_5_0}};
66 const Layout k5_1_4Layout = {
67     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
68     .specific_layout =
69         LoudspeakersSsConventionLayout{.sound_system = kSoundSystemD_4_5_0}};
70 const Layout k7_1_4Layout = {
71     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
72     .specific_layout =
73         LoudspeakersSsConventionLayout{.sound_system = kSoundSystemJ_4_7_0}};
74 const Layout k9_1_6Layout = {
75     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
76     .specific_layout =
77         LoudspeakersSsConventionLayout{.sound_system = kSoundSystem13_6_9_0}};
78 
79 // The IAMF spec recommends special rules for these 3.1.2 and 7.1.2 layouts.
80 const Layout k7_1_2Layout = {
81     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
82     .specific_layout =
83         LoudspeakersSsConventionLayout{.sound_system = kSoundSystem10_2_7_0}};
84 const Layout k3_1_2Layout = {
85     .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
86     .specific_layout =
87         LoudspeakersSsConventionLayout{.sound_system = kSoundSystem11_2_3_0}};
88 
89 const ScalableChannelLayoutConfig kBinauralScalableChannelLayoutConfig = {
90     .num_layers = 1,
91     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayoutBinaural}}};
92 const ScalableChannelLayoutConfig kStereoScalableChannelLayoutConfig = {
93     .num_layers = 1,
94     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayoutStereo}}};
95 const ScalableChannelLayoutConfig k5_1_0ScalableChannelLayoutConfig = {
96     .num_layers = 1,
97     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayout5_1_ch}}};
98 const ScalableChannelLayoutConfig k7_1_4ScalableChannelLayoutConfig = {
99     .num_layers = 1,
100     .channel_audio_layer_configs = {{.loudspeaker_layout = kLayout7_1_4_ch}}};
101 
102 ScalableChannelLayoutConfig
GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(ChannelAudioLayerConfig::ExpandedLoudspeakerLayout expanded_layout)103 GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
104     ChannelAudioLayerConfig::ExpandedLoudspeakerLayout expanded_layout) {
105   return {.num_layers = 1,
106           .channel_audio_layer_configs = {
107               {.loudspeaker_layout = kLayoutExpanded,
108                .expanded_loudspeaker_layout = expanded_layout}}};
109 }
110 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixingStereoToMono)111 TEST(CreateFromScalableChannelLayoutConfig, SupportsDownMixingStereoToMono) {
112   EXPECT_NE(AudioElementRendererChannelToChannel::
113                 CreateFromScalableChannelLayoutConfig(
114                     kStereoScalableChannelLayoutConfig, kMonoLayout,
115                     kOneSamplePerFrame),
116             nullptr);
117 }
118 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixing7_1_4To7_1_2)119 TEST(CreateFromScalableChannelLayoutConfig, SupportsDownMixing7_1_4To7_1_2) {
120   EXPECT_NE(AudioElementRendererChannelToChannel::
121                 CreateFromScalableChannelLayoutConfig(
122                     k7_1_4ScalableChannelLayoutConfig, k7_1_2Layout,
123                     kOneSamplePerFrame),
124             nullptr);
125 }
126 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixing7_1_4To3_1_2)127 TEST(CreateFromScalableChannelLayoutConfig, SupportsDownMixing7_1_4To3_1_2) {
128   EXPECT_NE(AudioElementRendererChannelToChannel::
129                 CreateFromScalableChannelLayoutConfig(
130                     k7_1_4ScalableChannelLayoutConfig, k3_1_2Layout,
131                     kOneSamplePerFrame),
132             nullptr);
133 }
134 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixingExpandedLFEToStereo)135 TEST(CreateFromScalableChannelLayoutConfig,
136      SupportsDownMixingExpandedLFEToStereo) {
137   EXPECT_NE(AudioElementRendererChannelToChannel::
138                 CreateFromScalableChannelLayoutConfig(
139                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
140                         ChannelAudioLayerConfig::kExpandedLayoutLFE),
141                     kStereoLayout, kOneSamplePerFrame),
142             nullptr);
143 }
144 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixingExpandedLFETo7_1_2)145 TEST(CreateFromScalableChannelLayoutConfig,
146      SupportsDownMixingExpandedLFETo7_1_2) {
147   EXPECT_NE(AudioElementRendererChannelToChannel::
148                 CreateFromScalableChannelLayoutConfig(
149                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
150                         ChannelAudioLayerConfig::kExpandedLayoutLFE),
151                     k7_1_2Layout, kOneSamplePerFrame),
152             nullptr);
153 }
154 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportPassthroughExpandedLFETo7_1_4)155 TEST(CreateFromScalableChannelLayoutConfig,
156      DoesNotSupportPassthroughExpandedLFETo7_1_4) {
157   EXPECT_EQ(AudioElementRendererChannelToChannel::
158                 CreateFromScalableChannelLayoutConfig(
159                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
160                         ChannelAudioLayerConfig::kExpandedLayoutLFE),
161                     k7_1_4Layout, kOneSamplePerFrame),
162             nullptr);
163 }
164 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixingExpandedStereoSToStereo)165 TEST(CreateFromScalableChannelLayoutConfig,
166      SupportsDownMixingExpandedStereoSToStereo) {
167   EXPECT_NE(AudioElementRendererChannelToChannel::
168                 CreateFromScalableChannelLayoutConfig(
169                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
170                         ChannelAudioLayerConfig::kExpandedLayoutStereoS),
171                     kStereoLayout, kOneSamplePerFrame),
172             nullptr);
173 }
174 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportPassthroughExpandedStereoSTo5_1_4)175 TEST(CreateFromScalableChannelLayoutConfig,
176      DoesNotSupportPassthroughExpandedStereoSTo5_1_4) {
177   EXPECT_EQ(AudioElementRendererChannelToChannel::
178                 CreateFromScalableChannelLayoutConfig(
179                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
180                         ChannelAudioLayerConfig::kExpandedLayoutStereoS),
181                     k5_1_4Layout, kOneSamplePerFrame),
182             nullptr);
183 }
184 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixingExpanded9_1_6ToStereo)185 TEST(CreateFromScalableChannelLayoutConfig,
186      SupportsDownMixingExpanded9_1_6ToStereo) {
187   EXPECT_NE(AudioElementRendererChannelToChannel::
188                 CreateFromScalableChannelLayoutConfig(
189                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
190                         ChannelAudioLayerConfig::kExpandedLayout9_1_6_ch),
191                     kStereoLayout, kOneSamplePerFrame),
192             nullptr);
193 }
194 
TEST(CreateFromScalableChannelLayoutConfig,SupportsDownMixingExpandedStereoSSToStereo)195 TEST(CreateFromScalableChannelLayoutConfig,
196      SupportsDownMixingExpandedStereoSSToStereo) {
197   EXPECT_NE(AudioElementRendererChannelToChannel::
198                 CreateFromScalableChannelLayoutConfig(
199                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
200                         ChannelAudioLayerConfig::kExpandedLayoutStereoSS),
201                     kStereoLayout, kOneSamplePerFrame),
202             nullptr);
203 }
204 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportPassthroughExpandedStereoF9_1_6)205 TEST(CreateFromScalableChannelLayoutConfig,
206      DoesNotSupportPassthroughExpandedStereoF9_1_6) {
207   EXPECT_EQ(AudioElementRendererChannelToChannel::
208                 CreateFromScalableChannelLayoutConfig(
209                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
210                         ChannelAudioLayerConfig::kExpandedLayoutStereoF),
211                     k9_1_6Layout, kOneSamplePerFrame),
212             nullptr);
213 }
214 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportExpandedLayoutReserved13ToStereo)215 TEST(CreateFromScalableChannelLayoutConfig,
216      DoesNotSupportExpandedLayoutReserved13ToStereo) {
217   EXPECT_EQ(AudioElementRendererChannelToChannel::
218                 CreateFromScalableChannelLayoutConfig(
219                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
220                         ChannelAudioLayerConfig::kExpandedLayoutReserved13),
221                     kStereoLayout, kOneSamplePerFrame),
222             nullptr);
223 }
224 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportExpandedLayoutReserved255ToStereo)225 TEST(CreateFromScalableChannelLayoutConfig,
226      DoesNotSupportExpandedLayoutReserved255ToStereo) {
227   EXPECT_EQ(AudioElementRendererChannelToChannel::
228                 CreateFromScalableChannelLayoutConfig(
229                     GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
230                         ChannelAudioLayerConfig::kExpandedLayoutReserved255),
231                     kStereoLayout, kOneSamplePerFrame),
232             nullptr);
233 }
234 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportBinaural)235 TEST(CreateFromScalableChannelLayoutConfig, DoesNotSupportBinaural) {
236   EXPECT_EQ(AudioElementRendererChannelToChannel::
237                 CreateFromScalableChannelLayoutConfig(
238                     kBinauralScalableChannelLayoutConfig, kBinauralLayout,
239                     kOneSamplePerFrame),
240             nullptr);
241   EXPECT_EQ(AudioElementRendererChannelToChannel::
242                 CreateFromScalableChannelLayoutConfig(
243                     kBinauralScalableChannelLayoutConfig, kStereoLayout,
244                     kOneSamplePerFrame),
245             nullptr);
246   EXPECT_EQ(AudioElementRendererChannelToChannel::
247                 CreateFromScalableChannelLayoutConfig(
248                     kStereoScalableChannelLayoutConfig, kBinauralLayout,
249                     kOneSamplePerFrame),
250             nullptr);
251 }
252 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportReservedLayout)253 TEST(CreateFromScalableChannelLayoutConfig, DoesNotSupportReservedLayout) {
254   const Layout kReservedLayout = {
255       .layout_type = Layout::kLayoutTypeReserved0,
256       .specific_layout = LoudspeakersReservedOrBinauralLayout{.reserved = 0}};
257 
258   EXPECT_EQ(AudioElementRendererChannelToChannel::
259                 CreateFromScalableChannelLayoutConfig(
260                     kStereoScalableChannelLayoutConfig, kReservedLayout,
261                     kOneSamplePerFrame),
262             nullptr);
263 }
264 
TEST(CreateFromScalableChannelLayoutConfig,DoesNotSupportPassThroughStereo)265 TEST(CreateFromScalableChannelLayoutConfig, DoesNotSupportPassThroughStereo) {
266   EXPECT_EQ(AudioElementRendererChannelToChannel::
267                 CreateFromScalableChannelLayoutConfig(
268                     kStereoScalableChannelLayoutConfig, kStereoLayout,
269                     kOneSamplePerFrame),
270             nullptr);
271 }
272 
TEST(CreateFromScalableChannelLayoutConfig,IsFinalizedImmediatelyAfterFinalizeCall)273 TEST(CreateFromScalableChannelLayoutConfig,
274      IsFinalizedImmediatelyAfterFinalizeCall) {
275   auto renderer = AudioElementRendererChannelToChannel::
276       CreateFromScalableChannelLayoutConfig(kStereoScalableChannelLayoutConfig,
277                                             kMonoLayout, kOneSamplePerFrame);
278   ASSERT_NE(renderer, nullptr);
279 
280   EXPECT_THAT(renderer->RenderLabeledFrame(
281                   {.label_to_samples = {{kL2, {kArbitrarySample1}},
282                                         {kR2, {kArbitrarySample2}}}}),
283               IsOk());
284   EXPECT_THAT(renderer->Finalize(), IsOk());
285   EXPECT_TRUE(renderer->IsFinalized());
286 }
287 
TEST(RenderLabeledFrame,ReturnsNumberOfTicks)288 TEST(RenderLabeledFrame, ReturnsNumberOfTicks) {
289   const int kNumTicks = 3;
290   auto renderer = AudioElementRendererChannelToChannel::
291       CreateFromScalableChannelLayoutConfig(kStereoScalableChannelLayoutConfig,
292                                             kMonoLayout, kNumTicks);
293   ASSERT_NE(renderer, nullptr);
294 
295   const auto num_ticks = renderer->RenderLabeledFrame(
296       {.label_to_samples = {
297            {kL2, std::vector<InternalSampleType>(kNumTicks, kArbitrarySample1)},
298            {kR2,
299             std::vector<InternalSampleType>(kNumTicks, kArbitrarySample2)}}});
300   ASSERT_THAT(num_ticks, IsOk());
301 
302   EXPECT_EQ(*num_ticks, kNumTicks);
303 }
304 
TEST(RenderLabeledFrame,RendersStereoToMono)305 TEST(RenderLabeledFrame, RendersStereoToMono) {
306   const std::vector<InternalSampleType> kL2Samples = {50, 100, 10000};
307   const std::vector<InternalSampleType> kR2Samples = {100, 50, 0};
308   const std::vector<InternalSampleType> kExpectedMonoSamples = {75, 75, 5000};
309 
310   auto renderer = AudioElementRendererChannelToChannel::
311       CreateFromScalableChannelLayoutConfig(kStereoScalableChannelLayoutConfig,
312                                             kMonoLayout,
313                                             kExpectedMonoSamples.size());
314 
315   std::vector<InternalSampleType> rendered_samples;
316   RenderAndFlushExpectOk(
317       {.label_to_samples = {{kL2, kL2Samples}, {kR2, kR2Samples}}},
318       renderer.get(), rendered_samples);
319 
320   EXPECT_THAT(rendered_samples, Pointwise(DoubleEq(), kExpectedMonoSamples));
321 }
322 
TEST(RenderLabeledFrame,StereoOutputIsSymmetricWhenInputIsLeftRightSymmetric7_1_4)323 TEST(RenderLabeledFrame,
324      StereoOutputIsSymmetricWhenInputIsLeftRightSymmetric7_1_4) {
325   auto renderer = AudioElementRendererChannelToChannel::
326       CreateFromScalableChannelLayoutConfig(k7_1_4ScalableChannelLayoutConfig,
327                                             kStereoLayout, kOneSamplePerFrame);
328   constexpr InternalSampleType kSymmetricL7R7Input = kArbitrarySample1;
329   constexpr InternalSampleType kSymmetricLss7Rss7Input = kArbitrarySample2;
330   constexpr InternalSampleType kSymmetricLrs7Rss7Input = kArbitrarySample3;
331   constexpr InternalSampleType kSymmetricLtf4Rtf4Input = kArbitrarySample4;
332   constexpr InternalSampleType kSymmetricLtb4Rtb4Input = kArbitrarySample5;
333   std::vector<InternalSampleType> rendered_samples;
334   RenderAndFlushExpectOk({.label_to_samples =
335                               {
336                                   {kL7, {kSymmetricL7R7Input}},
337                                   {kR7, {kSymmetricL7R7Input}},
338                                   {kCentre, {123456.0}},
339                                   {kLFE, {1234.0}},
340                                   {kLss7, {kSymmetricLss7Rss7Input}},
341                                   {kRss7, {kSymmetricLss7Rss7Input}},
342                                   {kLrs7, {kSymmetricLrs7Rss7Input}},
343                                   {kRrs7, {kSymmetricLrs7Rss7Input}},
344                                   {kLtf4, {kSymmetricLtf4Rtf4Input}},
345                                   {kRtf4, {kSymmetricLtf4Rtf4Input}},
346                                   {kLtb4, {kSymmetricLtb4Rtb4Input}},
347                                   {kRtb4, {kSymmetricLtb4Rtb4Input}},
348                               }},
349                          renderer.get(), rendered_samples);
350 
351   EXPECT_EQ(rendered_samples.size(), 2);
352   EXPECT_DOUBLE_EQ(rendered_samples[kStereoL2ChannelIndex],
353                    rendered_samples[kStereoR2ChannelIndex]);
354 }
355 
TEST(RenderLabeledFrame,PassThroughLFE)356 TEST(RenderLabeledFrame, PassThroughLFE) {
357   auto renderer = AudioElementRendererChannelToChannel::
358       CreateFromScalableChannelLayoutConfig(
359           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
360               ChannelAudioLayerConfig::kExpandedLayoutLFE),
361           k3_1_2Layout, kOneSamplePerFrame);
362 
363   std::vector<InternalSampleType> rendered_samples;
364   RenderAndFlushExpectOk({.label_to_samples = {{kLFE, {kArbitrarySample1}}}},
365                          renderer.get(), rendered_samples);
366 
367   EXPECT_DOUBLE_EQ(rendered_samples[k3_1_2LFEChannelIndex], kArbitrarySample1);
368 }
369 
TEST(RenderLabeledFrame,LFEPassesThroughFrom9_1_6)370 TEST(RenderLabeledFrame, LFEPassesThroughFrom9_1_6) {
371   constexpr InternalSampleType kLFESample = 1234.0;
372   auto renderer = AudioElementRendererChannelToChannel::
373       CreateFromScalableChannelLayoutConfig(
374           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
375               ChannelAudioLayerConfig::kExpandedLayout9_1_6_ch),
376           k5_1_0Layout, kOneSamplePerFrame);
377   ASSERT_NE(renderer, nullptr);
378 
379   std::vector<InternalSampleType> rendered_samples;
380   RenderAndFlushExpectOk({.label_to_samples = {{kFL, {kArbitrarySample1}},
381                                                {kFR, {kArbitrarySample1}},
382                                                {kFC, {kArbitrarySample1}},
383                                                {kLFE, {kLFESample}},
384                                                {kBL, {kArbitrarySample1}},
385                                                {kBR, {kArbitrarySample1}},
386                                                {kFLc, {kArbitrarySample1}},
387                                                {kFRc, {kArbitrarySample1}},
388                                                {kSiL, {kArbitrarySample1}},
389                                                {kSiR, {kArbitrarySample1}},
390                                                {kTpFL, {kArbitrarySample1}},
391                                                {kTpFR, {kArbitrarySample1}},
392                                                {kTpBL, {kArbitrarySample1}},
393                                                {kTpBR, {kArbitrarySample1}},
394                                                {kTpSiL, {kArbitrarySample1}},
395                                                {kTpSiR, {kArbitrarySample1}}}},
396                          renderer.get(), rendered_samples);
397 
398   ASSERT_GE(rendered_samples.size(), k5_1LFEChannelIndex);
399   EXPECT_DOUBLE_EQ(rendered_samples[k5_1LFEChannelIndex], kLFESample);
400 }
401 
TEST(RenderLabeledFrame,LFEPassesThroughTo9_1_6)402 TEST(RenderLabeledFrame, LFEPassesThroughTo9_1_6) {
403   constexpr InternalSampleType kLFESample = 1234.0;
404   auto renderer = AudioElementRendererChannelToChannel::
405       CreateFromScalableChannelLayoutConfig(k5_1_0ScalableChannelLayoutConfig,
406                                             k9_1_6Layout, kOneSamplePerFrame);
407   ASSERT_NE(renderer, nullptr);
408 
409   std::vector<InternalSampleType> rendered_samples;
410   RenderAndFlushExpectOk({.label_to_samples =
411                               {
412                                   {kL5, {kArbitrarySample1}},
413                                   {kR5, {kArbitrarySample1}},
414                                   {kCentre, {kArbitrarySample1}},
415                                   {kLFE, {kLFESample}},
416                                   {kLs5, {kArbitrarySample1}},
417                                   {kRs5, {kArbitrarySample1}},
418                               }},
419                          renderer.get(), rendered_samples);
420 
421   ASSERT_GE(rendered_samples.size(), k9_1_6LFEChannelIndex);
422   EXPECT_DOUBLE_EQ(rendered_samples[k9_1_6LFEChannelIndex], kLFESample);
423 }
424 
TEST(RenderLabeledFrame,PassThroughStereoS)425 TEST(RenderLabeledFrame, PassThroughStereoS) {
426   constexpr int k5_1_0Ls5ChannelIndex = 4;
427   constexpr int k5_1_0Rs5ChannelIndex = 5;
428   auto renderer = AudioElementRendererChannelToChannel::
429       CreateFromScalableChannelLayoutConfig(
430           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
431               ChannelAudioLayerConfig::kExpandedLayoutStereoS),
432           k5_1_0Layout, kOneSamplePerFrame);
433   ASSERT_NE(renderer, nullptr);
434 
435   std::vector<InternalSampleType> rendered_samples;
436   RenderAndFlushExpectOk({.label_to_samples = {{kLs5, {kArbitrarySample1}},
437                                                {kRs5, {kArbitrarySample2}}}},
438                          renderer.get(), rendered_samples);
439 
440   EXPECT_DOUBLE_EQ(rendered_samples.size(), 6);
441   EXPECT_DOUBLE_EQ(rendered_samples[k5_1_0Ls5ChannelIndex], kArbitrarySample1);
442   EXPECT_DOUBLE_EQ(rendered_samples[k5_1_0Rs5ChannelIndex], kArbitrarySample2);
443 }
444 
445 struct ExpandedLayoutAndRelatedLoudspeakerLayout {
446   const ChannelAudioLayerConfig::ExpandedLoudspeakerLayout expanded_layout;
447   const LabelSamplesMap expanded_layout_labeled_frame;
448   const ScalableChannelLayoutConfig related_scalable_layout_config;
449   const LabelSamplesMap related_loudspeaker_layout_labeled_frame;
450   const Layout output_layout;
451 };
452 
453 using ExpandedLayoutAndRelatedLoudspeakerLayoutTest =
454     ::testing::TestWithParam<ExpandedLayoutAndRelatedLoudspeakerLayout>;
TEST_P(ExpandedLayoutAndRelatedLoudspeakerLayoutTest,Equivalent)455 TEST_P(ExpandedLayoutAndRelatedLoudspeakerLayoutTest, Equivalent) {
456   auto renderer_expanded_layout = AudioElementRendererChannelToChannel::
457       CreateFromScalableChannelLayoutConfig(
458           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
459               GetParam().expanded_layout),
460           GetParam().output_layout, kOneSamplePerFrame);
461   auto renderer_related_loudspeaker_layout =
462       AudioElementRendererChannelToChannel::
463           CreateFromScalableChannelLayoutConfig(
464               GetParam().related_scalable_layout_config,
465               GetParam().output_layout, kOneSamplePerFrame);
466 
467   std::vector<InternalSampleType> expanded_layout_rendered_samples;
468   RenderAndFlushExpectOk(
469       LabeledFrame{.label_to_samples =
470                        GetParam().expanded_layout_labeled_frame},
471       renderer_expanded_layout.get(), expanded_layout_rendered_samples);
472   std::vector<InternalSampleType> related_layout_rendered_samples;
473   RenderAndFlushExpectOk(
474       {LabeledFrame{.label_to_samples =
475                         GetParam().related_loudspeaker_layout_labeled_frame}},
476       renderer_related_loudspeaker_layout.get(),
477       related_layout_rendered_samples);
478 
479   EXPECT_THAT(expanded_layout_rendered_samples,
480               Pointwise(DoubleEq(), related_layout_rendered_samples));
481 }
482 
483 INSTANTIATE_TEST_SUITE_P(
484     ExpandedLayoutStereoSEquivalentTo5_1_4,
485     ExpandedLayoutAndRelatedLoudspeakerLayoutTest,
486     ::testing::ValuesIn<ExpandedLayoutAndRelatedLoudspeakerLayout>(
487         {{.expanded_layout = ChannelAudioLayerConfig::kExpandedLayoutStereoS,
488           .expanded_layout_labeled_frame = {{kLs5, {kArbitrarySample1}},
489                                             {kRs5, {kArbitrarySample2}}},
490           .related_scalable_layout_config = k5_1_0ScalableChannelLayoutConfig,
491           .related_loudspeaker_layout_labeled_frame =
492               {{kL5, {0}},
493                {kR5, {0}},
494                {kCentre, {0}},
495                {kLFE, {0}},
496                {kLs5, {kArbitrarySample1}},
497                {kRs5, {kArbitrarySample2}}},
498           .output_layout = k3_1_2Layout}}));
499 
500 INSTANTIATE_TEST_SUITE_P(
501     ExpandedLayoutTop4ChEquivalentTo7_1_4,
502     ExpandedLayoutAndRelatedLoudspeakerLayoutTest,
503     ::testing::ValuesIn<ExpandedLayoutAndRelatedLoudspeakerLayout>(
504         {{.expanded_layout = ChannelAudioLayerConfig::kExpandedLayoutTop4Ch,
505           .expanded_layout_labeled_frame = {{kLtf4, {kArbitrarySample1}},
506                                             {kRtf4, {kArbitrarySample2}},
507                                             {kLtb4, {kArbitrarySample3}},
508                                             {kRtb4, {kArbitrarySample4}}},
509           .related_scalable_layout_config = k7_1_4ScalableChannelLayoutConfig,
510           .related_loudspeaker_layout_labeled_frame =
511               {{kL7, {0}},
512                {kR7, {0}},
513                {kCentre, {0}},
514                {kLFE, {0}},
515                {kLss7, {0}},
516                {kRss7, {0}},
517                {kLrs7, {0}},
518                {kRrs7, {0}},
519                {kLtf4, {kArbitrarySample1}},
520                {kRtf4, {kArbitrarySample2}},
521                {kLtb4, {kArbitrarySample3}},
522                {kRtb4, {kArbitrarySample4}}},
523           .output_layout = k3_1_2Layout}}));
524 
525 INSTANTIATE_TEST_SUITE_P(
526     ExpandedLayoutTop6ChEquivalentTo9_1_6,
527     ExpandedLayoutAndRelatedLoudspeakerLayoutTest,
528     ::testing::ValuesIn<ExpandedLayoutAndRelatedLoudspeakerLayout>(
529         {{.expanded_layout = ChannelAudioLayerConfig::kExpandedLayoutTop6Ch,
530           .expanded_layout_labeled_frame = {{kTpFL, {kArbitrarySample1}},
531                                             {kTpFR, {kArbitrarySample2}},
532                                             {kTpSiL, {kArbitrarySample3}},
533                                             {kTpSiR, {kArbitrarySample4}},
534                                             {kTpBL, {kArbitrarySample5}},
535                                             {kTpBR, {kArbitrarySample6}}},
536           .related_scalable_layout_config =
537               GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
538                   ChannelAudioLayerConfig::kExpandedLayout9_1_6_ch),
539           .related_loudspeaker_layout_labeled_frame =
540               {{kFL, {0}},
541                {kFR, {0}},
542                {kFC, {0}},
543                {kLFE, {0}},
544                {kBL, {0}},
545                {kBR, {0}},
546                {kFLc, {0}},
547                {kFRc, {0}},
548                {kSiL, {0}},
549                {kSiR, {0}},
550                {kTpFL, {kArbitrarySample1}},
551                {kTpFR, {kArbitrarySample2}},
552                {kTpSiL, {kArbitrarySample3}},
553                {kTpSiR, {kArbitrarySample4}},
554                {kTpBL, {kArbitrarySample5}},
555                {kTpBR, {kArbitrarySample6}}},
556           .output_layout = k3_1_2Layout}}));
557 
TEST(RenderLabeledFrame,StereoOutputIsSymmetricWhenInputIsLeftRightSymmetric9_1_6)558 TEST(RenderLabeledFrame,
559      StereoOutputIsSymmetricWhenInputIsLeftRightSymmetric9_1_6) {
560   auto renderer = AudioElementRendererChannelToChannel::
561       CreateFromScalableChannelLayoutConfig(
562           GetScalableChannelLayoutConfigForExpandedLayoutSoundSystem(
563               ChannelAudioLayerConfig::kExpandedLayout9_1_6_ch),
564           kStereoLayout, kOneSamplePerFrame);
565   constexpr InternalSampleType kSymmetricFLFRInput = kArbitrarySample1;
566   constexpr InternalSampleType kSymmetricBLBRInput = kArbitrarySample2;
567   constexpr InternalSampleType kSymmetricFLcFRcInput = kArbitrarySample3;
568   constexpr InternalSampleType kSymmetricSiLSiRInput = kArbitrarySample4;
569   constexpr InternalSampleType kSymmetricTpFLTpFRInput = kArbitrarySample5;
570   constexpr InternalSampleType kSymmetricTpBLTpBRInput = kArbitrarySample6;
571   constexpr InternalSampleType kSymmetricTpSiLTpSiRInput = 999999999.0;
572   std::vector<InternalSampleType> rendered_samples;
573   RenderAndFlushExpectOk(
574       {.label_to_samples = {{kFL, {kSymmetricFLFRInput}},
575                             {kFR, {kSymmetricFLFRInput}},
576                             {kFC, {999.0}},
577                             {kLFE, {9999.0}},
578                             {kBL, {kSymmetricBLBRInput}},
579                             {kBR, {kSymmetricBLBRInput}},
580                             {kFLc, {kSymmetricFLcFRcInput}},
581                             {kFRc, {kSymmetricFLcFRcInput}},
582                             {kSiL, {kSymmetricSiLSiRInput}},
583                             {kSiR, {kSymmetricSiLSiRInput}},
584                             {kTpFL, {kSymmetricTpFLTpFRInput}},
585                             {kTpFR, {kSymmetricTpFLTpFRInput}},
586                             {kTpBL, {kSymmetricTpBLTpBRInput}},
587                             {kTpBR, {kSymmetricTpBLTpBRInput}},
588                             {kTpSiL, {kSymmetricTpSiLTpSiRInput}},
589                             {kTpSiR, {kSymmetricTpSiLTpSiRInput}}}},
590       renderer.get(), rendered_samples);
591 
592   EXPECT_EQ(rendered_samples.size(), 2);
593   EXPECT_DOUBLE_EQ(rendered_samples[kStereoL2ChannelIndex],
594                    rendered_samples[kStereoR2ChannelIndex]);
595 }
596 
597 }  // namespace
598 }  // namespace iamf_tools
599