• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 3-Clause Clear
5  * License and the Alliance for Open Media Patent License 1.0. If the BSD
6  * 3-Clause Clear License was not distributed with this source code in the
7  * LICENSE file, you can obtain it at
8  * www.aomedia.org/license/software-license/bsd-3-c-c. If the Alliance for
9  * Open Media Patent License 1.0 was not distributed with this source code
10  * in the PATENTS file, you can obtain it at www.aomedia.org/license/patent.
11  */
12 #include "iamf/cli/proto_conversion/proto_to_obu/audio_element_generator.h"
13 
14 #include <cstdint>
15 #include <optional>
16 #include <variant>
17 #include <vector>
18 
19 #include "absl/container/flat_hash_map.h"
20 #include "absl/status/status_matchers.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "iamf/cli/audio_element_with_data.h"
24 #include "iamf/cli/channel_label.h"
25 #include "iamf/cli/proto/audio_element.pb.h"
26 #include "iamf/cli/tests/cli_test_utils.h"
27 #include "iamf/obu/audio_element.h"
28 #include "iamf/obu/codec_config.h"
29 #include "iamf/obu/demixing_info_parameter_data.h"
30 #include "iamf/obu/demixing_param_definition.h"
31 #include "iamf/obu/param_definitions.h"
32 #include "iamf/obu/types.h"
33 #include "src/google/protobuf/repeated_ptr_field.h"
34 #include "src/google/protobuf/text_format.h"
35 
36 // TODO(b/296171268): Add more tests for `AudioElementGenerator`.
37 
38 namespace iamf_tools {
39 namespace {
40 using ::absl_testing::IsOk;
41 using enum ChannelLabel::Label;
42 
43 typedef ::google::protobuf::RepeatedPtrField<
44     iamf_tools_cli_proto::AudioElementObuMetadata>
45     AudioElementObuMetadatas;
46 
47 constexpr DecodedUleb128 kCodecConfigId = 200;
48 constexpr DecodedUleb128 kAudioElementId = 300;
49 constexpr uint32_t kSampleRate = 48000;
50 
51 const ScalableChannelLayoutConfig kOneLayerStereoConfig{
52     .num_layers = 1,
53     .channel_audio_layer_configs = {
54         {.loudspeaker_layout = ChannelAudioLayerConfig::kLayoutStereo,
55          .output_gain_is_present_flag = false,
56          .substream_count = 1,
57          .coupled_substream_count = 1}}};
58 
GetScalableLayoutForAudioElementIdExpectOk(DecodedUleb128 audio_element_id,const absl::flat_hash_map<DecodedUleb128,AudioElementWithData> & output_obus)59 const ScalableChannelLayoutConfig& GetScalableLayoutForAudioElementIdExpectOk(
60     DecodedUleb128 audio_element_id,
61     const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>&
62         output_obus) {
63   EXPECT_TRUE(output_obus.contains(audio_element_id));
64   const auto& output_scalable_channel_layout_config =
65       output_obus.at(audio_element_id).obu.config_;
66   EXPECT_TRUE(std::holds_alternative<ScalableChannelLayoutConfig>(
67       output_scalable_channel_layout_config));
68   return std::get<ScalableChannelLayoutConfig>(
69       output_scalable_channel_layout_config);
70 }
71 
TEST(Generate,PopulatesExpandedLoudspeakerLayout)72 TEST(Generate, PopulatesExpandedLoudspeakerLayout) {
73   AudioElementObuMetadatas audio_element_metadatas;
74   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
75       R"pb(
76         audio_element_id: 300
77         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
78         codec_config_id: 200
79         num_substreams: 1
80         audio_substream_ids: [ 99 ]
81         scalable_channel_layout_config {
82           num_layers: 1
83           channel_audio_layer_configs {
84             loudspeaker_layout: LOUDSPEAKER_LAYOUT_EXPANDED
85             substream_count: 1
86             coupled_substream_count: 0
87             expanded_loudspeaker_layout: EXPANDED_LOUDSPEAKER_LAYOUT_LFE
88           }
89         }
90       )pb",
91       audio_element_metadatas.Add()));
92   absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
93   AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
94                                         codec_config_obus);
95   AudioElementGenerator generator(audio_element_metadatas);
96 
97   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> output_obus;
98   EXPECT_THAT(generator.Generate(codec_config_obus, output_obus), IsOk());
99 
100   const auto& output_first_layer =
101       GetScalableLayoutForAudioElementIdExpectOk(kAudioElementId, output_obus)
102           .channel_audio_layer_configs[0];
103   EXPECT_EQ(output_first_layer.loudspeaker_layout,
104             ChannelAudioLayerConfig::kLayoutExpanded);
105   ASSERT_TRUE(output_first_layer.expanded_loudspeaker_layout.has_value());
106   EXPECT_EQ(*output_first_layer.expanded_loudspeaker_layout,
107             ChannelAudioLayerConfig::kExpandedLayoutLFE);
108 }
109 
TEST(Generate,InvalidWhenExpandedLoudspeakerLayoutIsSignalledButNotPresent)110 TEST(Generate, InvalidWhenExpandedLoudspeakerLayoutIsSignalledButNotPresent) {
111   AudioElementObuMetadatas audio_element_metadatas;
112   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
113       R"pb(
114         audio_element_id: 300
115         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
116         codec_config_id: 200
117         num_substreams: 1
118         audio_substream_ids: [ 99 ]
119         scalable_channel_layout_config {
120           num_layers: 1
121           channel_audio_layer_configs {
122             loudspeaker_layout: LOUDSPEAKER_LAYOUT_EXPANDED
123             substream_count: 1
124             coupled_substream_count: 0
125             # expanded_loudspeaker_layout: EXPANDED_LOUDSPEAKER_LAYOUT_LFE
126           }
127         }
128       )pb",
129       audio_element_metadatas.Add()));
130   absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
131   AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
132                                         codec_config_obus);
133   AudioElementGenerator generator(audio_element_metadatas);
134 
135   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> output_obus;
136   EXPECT_FALSE(generator.Generate(codec_config_obus, output_obus).ok());
137 }
138 
TEST(Generate,IgnoresExpandedLayoutWhenNotSignalled)139 TEST(Generate, IgnoresExpandedLayoutWhenNotSignalled) {
140   AudioElementObuMetadatas audio_element_metadatas;
141   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
142       R"pb(
143         audio_element_id: 300
144         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
145         codec_config_id: 200
146         num_substreams: 1
147         audio_substream_ids: [ 99 ]
148         scalable_channel_layout_config {
149           num_layers: 1
150           channel_audio_layer_configs {
151             loudspeaker_layout: LOUDSPEAKER_LAYOUT_STEREO
152             substream_count: 1
153             coupled_substream_count: 1
154             expanded_loudspeaker_layout: EXPANDED_LOUDSPEAKER_LAYOUT_LFE
155           }
156         }
157       )pb",
158       audio_element_metadatas.Add()));
159   absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
160   AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
161                                         codec_config_obus);
162   AudioElementGenerator generator(audio_element_metadatas);
163 
164   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> output_obus;
165   EXPECT_THAT(generator.Generate(codec_config_obus, output_obus), IsOk());
166 
167   const auto& output_first_layer =
168       GetScalableLayoutForAudioElementIdExpectOk(kAudioElementId, output_obus)
169           .channel_audio_layer_configs[0];
170   EXPECT_FALSE(output_first_layer.expanded_loudspeaker_layout.has_value());
171 }
172 
TEST(Generate,LeavesExpandedLayoutEmptyWhenNotSignalled)173 TEST(Generate, LeavesExpandedLayoutEmptyWhenNotSignalled) {
174   AudioElementObuMetadatas audio_element_metadatas;
175   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
176       R"pb(
177         audio_element_id: 300
178         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
179         codec_config_id: 200
180         num_substreams: 1
181         audio_substream_ids: [ 99 ]
182         scalable_channel_layout_config {
183           num_layers: 1
184           channel_audio_layer_configs {
185             loudspeaker_layout: LOUDSPEAKER_LAYOUT_STEREO
186             substream_count: 1
187             coupled_substream_count: 1
188           }
189         }
190       )pb",
191       audio_element_metadatas.Add()));
192   absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
193   AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
194                                         codec_config_obus);
195   AudioElementGenerator generator(audio_element_metadatas);
196 
197   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> output_obus;
198   EXPECT_THAT(generator.Generate(codec_config_obus, output_obus), IsOk());
199 
200   const auto& output_first_layer =
201       GetScalableLayoutForAudioElementIdExpectOk(kAudioElementId, output_obus)
202           .channel_audio_layer_configs[0];
203   EXPECT_FALSE(output_first_layer.expanded_loudspeaker_layout.has_value());
204 }
205 
206 class AudioElementGeneratorTest : public ::testing::Test {
207  public:
AudioElementGeneratorTest()208   AudioElementGeneratorTest() {
209     AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
210                                           codec_config_obus_);
211   }
212 
InitAndTestGenerate()213   void InitAndTestGenerate() {
214     AudioElementGenerator generator(audio_element_metadata_);
215 
216     EXPECT_THAT(generator.Generate(codec_config_obus_, output_obus_), IsOk());
217 
218     EXPECT_EQ(output_obus_, expected_obus_);
219   }
220 
221  protected:
222   AudioElementObuMetadatas audio_element_metadata_;
223 
224   absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus_;
225   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> output_obus_;
226 
227   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> expected_obus_;
228 };
229 
TEST_F(AudioElementGeneratorTest,NoAudioElementObus)230 TEST_F(AudioElementGeneratorTest, NoAudioElementObus) { InitAndTestGenerate(); }
231 
TEST_F(AudioElementGeneratorTest,FirstOrderMonoAmbisonicsNumericalOrder)232 TEST_F(AudioElementGeneratorTest, FirstOrderMonoAmbisonicsNumericalOrder) {
233   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
234       R"pb(
235         audio_element_id: 300
236         audio_element_type: AUDIO_ELEMENT_SCENE_BASED
237         reserved: 0
238         codec_config_id: 200
239         num_substreams: 4
240         audio_substream_ids: [ 0, 1, 2, 3 ]
241         num_parameters: 0
242         ambisonics_config {
243           ambisonics_mode: AMBISONICS_MODE_MONO
244           ambisonics_mono_config {
245             output_channel_count: 4
246             substream_count: 4
247             channel_mapping: [ 0, 1, 2, 3 ]
248           }
249         }
250       )pb",
251       audio_element_metadata_.Add()));
252 
253   AddAmbisonicsMonoAudioElementWithSubstreamIds(
254       kAudioElementId, kCodecConfigId, {0, 1, 2, 3}, codec_config_obus_,
255       expected_obus_);
256 
257   InitAndTestGenerate();
258 }
259 
TEST_F(AudioElementGeneratorTest,FirstOrderMonoAmbisonicsLargeSubstreamIds)260 TEST_F(AudioElementGeneratorTest, FirstOrderMonoAmbisonicsLargeSubstreamIds) {
261   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
262       R"pb(
263         audio_element_id: 300
264         audio_element_type: AUDIO_ELEMENT_SCENE_BASED
265         reserved: 0
266         codec_config_id: 200
267         num_substreams: 4
268         audio_substream_ids: [ 1000, 2000, 3000, 4000 ]
269         num_parameters: 0
270         ambisonics_config {
271           ambisonics_mode: AMBISONICS_MODE_MONO
272           ambisonics_mono_config {
273             output_channel_count: 4
274             substream_count: 4
275             channel_mapping: [ 0, 1, 2, 3 ]
276           }
277         }
278       )pb",
279       audio_element_metadata_.Add()));
280 
281   AddAmbisonicsMonoAudioElementWithSubstreamIds(
282       kAudioElementId, kCodecConfigId, {1000, 2000, 3000, 4000},
283       codec_config_obus_, expected_obus_);
284 
285   InitAndTestGenerate();
286 }
287 
TEST_F(AudioElementGeneratorTest,FirstOrderMonoAmbisonicsArbitraryOrder)288 TEST_F(AudioElementGeneratorTest, FirstOrderMonoAmbisonicsArbitraryOrder) {
289   AddAmbisonicsMonoAudioElementWithSubstreamIds(
290       kAudioElementId, kCodecConfigId, {100, 101, 102, 103}, codec_config_obus_,
291       expected_obus_);
292   auto expected_obu_iter = expected_obus_.find(kAudioElementId);
293   ASSERT_NE(expected_obu_iter, expected_obus_.end());
294 
295   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
296       R"pb(
297         audio_element_id: 300
298         audio_element_type: AUDIO_ELEMENT_SCENE_BASED
299         reserved: 0
300         codec_config_id: 200
301         num_substreams: 4
302         audio_substream_ids: [ 100, 101, 102, 103 ]
303         num_parameters: 0
304         ambisonics_config {
305           ambisonics_mode: AMBISONICS_MODE_MONO
306           ambisonics_mono_config {
307             output_channel_count: 4
308             substream_count: 4
309             channel_mapping: [ 3, 1, 0, 2 ]
310           }
311         }
312       )pb",
313       audio_element_metadata_.Add()));
314   auto& expected_obu = expected_obu_iter->second;
315   std::get<AmbisonicsMonoConfig>(
316       std::get<AmbisonicsConfig>(expected_obu.obu.config_).ambisonics_config)
317       .channel_mapping = {/*A0:*/ 3, /*A1:*/ 1, /*A2:*/ 0, /*A3:*/ 2};
318 
319   // Configures the remapped `substream_id_to_labels` correctly.
320   expected_obu.substream_id_to_labels = {
321       {103, {kA0}},
322       {101, {kA1}},
323       {100, {kA2}},
324       {102, {kA3}},
325   };
326 
327   InitAndTestGenerate();
328 }
329 
TEST_F(AudioElementGeneratorTest,SubstreamWithMultipleAmbisonicsChannelNumbers)330 TEST_F(AudioElementGeneratorTest,
331        SubstreamWithMultipleAmbisonicsChannelNumbers) {
332   AddAmbisonicsMonoAudioElementWithSubstreamIds(
333       kAudioElementId, kCodecConfigId, {100, 101, 102}, codec_config_obus_,
334       expected_obus_);
335   auto expected_obu_iter = expected_obus_.find(kAudioElementId);
336   ASSERT_NE(expected_obu_iter, expected_obus_.end());
337 
338   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
339       R"pb(
340         audio_element_id: 300
341         audio_element_type: AUDIO_ELEMENT_SCENE_BASED
342         reserved: 0
343         codec_config_id: 200
344         num_substreams: 3
345         audio_substream_ids: [ 100, 101, 102 ]
346         num_parameters: 0
347         ambisonics_config {
348           ambisonics_mode: AMBISONICS_MODE_MONO
349           ambisonics_mono_config {
350             output_channel_count: 4
351             substream_count: 3
352             channel_mapping: [ 0, 2, 1, 0 ]
353           }
354         }
355       )pb",
356       audio_element_metadata_.Add()));
357   auto& expected_obu = expected_obu_iter->second;
358   std::get<AmbisonicsMonoConfig>(
359       std::get<AmbisonicsConfig>(expected_obu.obu.config_).ambisonics_config)
360       .channel_mapping = {/*A0:*/ 0, /*A1:*/ 2, /*A2:*/ 1, /*A3:*/ 0};
361 
362   // Configures the remapped `substream_id_to_labels` correctly.
363   expected_obu.substream_id_to_labels = {
364       {100, {kA0, kA3}},
365       {101, {kA2}},
366       {102, {kA1}},
367   };
368 
369   InitAndTestGenerate();
370 }
371 
TEST_F(AudioElementGeneratorTest,MixedFirstOrderMonoAmbisonics)372 TEST_F(AudioElementGeneratorTest, MixedFirstOrderMonoAmbisonics) {
373   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
374       R"pb(
375         audio_element_id: 300
376         audio_element_type: AUDIO_ELEMENT_SCENE_BASED
377         reserved: 0
378         codec_config_id: 200
379         num_substreams: 3
380         audio_substream_ids: [ 1000, 2000, 3000 ]
381         num_parameters: 0
382         ambisonics_config {
383           ambisonics_mode: AMBISONICS_MODE_MONO
384           ambisonics_mono_config {
385             output_channel_count: 4
386             substream_count: 3
387             channel_mapping: [ 0, 1, 2, 255 ]
388           }
389         }
390       )pb",
391       audio_element_metadata_.Add()));
392 
393   AddAmbisonicsMonoAudioElementWithSubstreamIds(
394       kAudioElementId, kCodecConfigId, {1000, 2000, 3000}, codec_config_obus_,
395       expected_obus_);
396 
397   InitAndTestGenerate();
398 }
399 
TEST_F(AudioElementGeneratorTest,ThirdOrderMonoAmbisonics)400 TEST_F(AudioElementGeneratorTest, ThirdOrderMonoAmbisonics) {
401   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
402       R"pb(
403         audio_element_id: 300
404         audio_element_type: AUDIO_ELEMENT_SCENE_BASED
405         reserved: 0
406         codec_config_id: 200
407         num_substreams: 16
408         audio_substream_ids: [
409           0,
410           1,
411           2,
412           3,
413           4,
414           5,
415           6,
416           7,
417           8,
418           9,
419           10,
420           11,
421           12,
422           13,
423           14,
424           15
425         ]
426         num_parameters: 0
427         ambisonics_config {
428           ambisonics_mode: AMBISONICS_MODE_MONO
429           ambisonics_mono_config {
430             output_channel_count: 16
431             substream_count: 16
432             channel_mapping: [
433               0,
434               1,
435               2,
436               3,
437               4,
438               5,
439               6,
440               7,
441               8,
442               9,
443               10,
444               11,
445               12,
446               13,
447               14,
448               15
449             ]
450           }
451         }
452       )pb",
453       audio_element_metadata_.Add()));
454 
455   AddAmbisonicsMonoAudioElementWithSubstreamIds(
456       kAudioElementId, kCodecConfigId,
457       {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
458       codec_config_obus_, expected_obus_);
459 
460   InitAndTestGenerate();
461 }
462 
TEST_F(AudioElementGeneratorTest,FillsAudioElementWithDataFields)463 TEST_F(AudioElementGeneratorTest, FillsAudioElementWithDataFields) {
464   const SubstreamIdLabelsMap kExpectedSubstreamIdToLabels = {{99, {kMono}},
465                                                              {100, {kL2}}};
466   const std::vector<ChannelNumbers> kExpectedChannelNumbersForLayer = {
467       {.surround = 1, .lfe = 0, .height = 0},
468       {.surround = 2, .lfe = 0, .height = 0}};
469   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
470       R"pb(
471         audio_element_id: 300
472         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
473         reserved: 0
474         codec_config_id: 200
475         num_substreams: 2
476         audio_substream_ids: [ 99, 100 ]
477         num_parameters: 0
478         scalable_channel_layout_config {
479           num_layers: 2
480           reserved: 0
481           channel_audio_layer_configs {
482             loudspeaker_layout: LOUDSPEAKER_LAYOUT_MONO
483             output_gain_is_present_flag: 0
484             recon_gain_is_present_flag: 0
485             reserved_a: 0
486             substream_count: 1
487             coupled_substream_count: 0
488           }
489           channel_audio_layer_configs {
490             loudspeaker_layout: LOUDSPEAKER_LAYOUT_STEREO
491             output_gain_is_present_flag: 1
492             recon_gain_is_present_flag: 0
493             reserved_a: 0
494             substream_count: 1
495             coupled_substream_count: 0
496             output_gain_flag: 32
497             output_gain: 32767
498           }
499         }
500       )pb",
501       audio_element_metadata_.Add()));
502   AudioElementGenerator generator(audio_element_metadata_);
503 
504   EXPECT_THAT(generator.Generate(codec_config_obus_, output_obus_), IsOk());
505 
506   const auto& audio_element_with_data = output_obus_.at(kAudioElementId);
507   EXPECT_EQ(audio_element_with_data.substream_id_to_labels,
508             kExpectedSubstreamIdToLabels);
509   EXPECT_EQ(audio_element_with_data.channel_numbers_for_layers,
510             kExpectedChannelNumbersForLayer);
511   ASSERT_TRUE(audio_element_with_data.label_to_output_gain.contains(kL2));
512   EXPECT_FLOAT_EQ(audio_element_with_data.label_to_output_gain.at(kL2),
513                   128.0 - 1 / 256.0);
514 }
515 
TEST_F(AudioElementGeneratorTest,DeprecatedLoudspeakerLayoutIsNotSupported)516 TEST_F(AudioElementGeneratorTest, DeprecatedLoudspeakerLayoutIsNotSupported) {
517   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
518       R"pb(
519         audio_element_id: 300
520         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
521         reserved: 0
522         codec_config_id: 200
523         num_substreams: 1
524         audio_substream_ids: [ 99 ]
525         num_parameters: 0
526         scalable_channel_layout_config {
527           num_layers: 1
528           reserved: 0
529           channel_audio_layer_configs {
530             deprecated_loudspeaker_layout: 1  # Stereo
531             output_gain_is_present_flag: 0
532             recon_gain_is_present_flag: 0
533             reserved_a: 0
534             substream_count: 1
535             coupled_substream_count: 1
536           }
537         }
538       )pb",
539       audio_element_metadata_.Add()));
540 
541   AudioElementGenerator generator(audio_element_metadata_);
542 
543   EXPECT_FALSE(generator.Generate(codec_config_obus_, output_obus_).ok());
544 }
545 
TEST_F(AudioElementGeneratorTest,DefaultLoudspeakerLayoutIsNotSupported)546 TEST_F(AudioElementGeneratorTest, DefaultLoudspeakerLayoutIsNotSupported) {
547   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
548       R"pb(
549         audio_element_id: 300
550         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
551         reserved: 0
552         codec_config_id: 200
553         num_substreams: 1
554         audio_substream_ids: [ 99 ]
555         num_parameters: 0
556         scalable_channel_layout_config {
557           num_layers: 1
558           reserved: 0
559           channel_audio_layer_configs {
560             # loudspeaker_layout: LOUDSPEAKER_LAYOUT_STEREO
561             output_gain_is_present_flag: 0
562             recon_gain_is_present_flag: 0
563             reserved_a: 0
564             substream_count: 1
565             coupled_substream_count: 1
566           }
567         }
568       )pb",
569       audio_element_metadata_.Add()));
570 
571   AudioElementGenerator generator(audio_element_metadata_);
572 
573   EXPECT_FALSE(generator.Generate(codec_config_obus_, output_obus_).ok());
574 }
575 
AddTwoLayer7_1_0_And7_1_4(::google::protobuf::RepeatedPtrField<iamf_tools_cli_proto::AudioElementObuMetadata> & audio_element_metadata)576 void AddTwoLayer7_1_0_And7_1_4(::google::protobuf::RepeatedPtrField<
577                                iamf_tools_cli_proto::AudioElementObuMetadata>&
578                                    audio_element_metadata) {
579   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
580       R"pb(
581         audio_element_id: 300
582         audio_element_type: AUDIO_ELEMENT_CHANNEL_BASED
583         reserved: 0
584         codec_config_id: 200
585         num_substreams: 7
586         audio_substream_ids: [ 700, 701, 702, 703, 704, 740, 741 ]
587         num_parameters: 0
588         scalable_channel_layout_config {
589           num_layers: 2
590           reserved: 0
591           channel_audio_layer_configs {
592             loudspeaker_layout: LOUDSPEAKER_LAYOUT_7_1_CH
593             output_gain_is_present_flag: 0
594             recon_gain_is_present_flag: 0
595             reserved_a: 0
596             substream_count: 5
597             coupled_substream_count: 3
598           }
599           channel_audio_layer_configs {
600             loudspeaker_layout: LOUDSPEAKER_LAYOUT_7_1_4_CH
601             output_gain_is_present_flag: 0
602             recon_gain_is_present_flag: 0
603             reserved_a: 0
604             substream_count: 2
605             coupled_substream_count: 2
606           }
607         }
608       )pb",
609       audio_element_metadata.Add()));
610 }
611 
TEST_F(AudioElementGeneratorTest,GeneratesDemixingParameterDefinition)612 TEST_F(AudioElementGeneratorTest, GeneratesDemixingParameterDefinition) {
613   AddTwoLayer7_1_0_And7_1_4(audio_element_metadata_);
614   audio_element_metadata_.at(0).set_num_parameters(1);
615   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
616       R"pb(
617         param_definition_type: PARAM_DEFINITION_TYPE_DEMIXING
618         demixing_param: {
619           param_definition {
620             parameter_id: 998
621             parameter_rate: 48000
622             param_definition_mode: 0
623             reserved: 10
624             duration: 8
625             num_subblocks: 1
626             constant_subblock_duration: 8
627           }
628           default_demixing_info_parameter_data: {
629             dmixp_mode: DMIXP_MODE_2
630             reserved: 11
631           }
632           default_w: 2
633           reserved: 12
634         }
635       )pb",
636       audio_element_metadata_.at(0).add_audio_element_params()));
637 
638   // Configure matching expected values.
639   DemixingParamDefinition expected_demixing_param_definition;
640   expected_demixing_param_definition.parameter_id_ = 998;
641   expected_demixing_param_definition.parameter_rate_ = 48000;
642   expected_demixing_param_definition.param_definition_mode_ = 0;
643   expected_demixing_param_definition.duration_ = 8;
644   expected_demixing_param_definition.constant_subblock_duration_ = 8;
645   expected_demixing_param_definition.reserved_ = 10;
646 
647   auto& expected_default_demixing_info_parameter_data =
648       expected_demixing_param_definition.default_demixing_info_parameter_data_;
649   // `DemixingInfoParameterData` in the IAMF spec.
650   expected_default_demixing_info_parameter_data.dmixp_mode =
651       DemixingInfoParameterData::kDMixPMode2;
652   expected_default_demixing_info_parameter_data.reserved = 11;
653   // Extension portion of `DefaultDemixingInfoParameterData` in the IAMF spec.
654   expected_default_demixing_info_parameter_data.default_w = 2;
655   expected_default_demixing_info_parameter_data.reserved_for_future_use = 12;
656 
657   const AudioElementParam kExpectedAudioElementParam = {
658       expected_demixing_param_definition};
659 
660   // Generate and validate the parameter-related information matches expected
661   // results.
662   AudioElementGenerator generator(audio_element_metadata_);
663   EXPECT_THAT(generator.Generate(codec_config_obus_, output_obus_), IsOk());
664 
665   const auto& obu = output_obus_.at(kAudioElementId).obu;
666   EXPECT_EQ(obu.audio_element_params_.size(), 1);
667   ASSERT_FALSE(obu.audio_element_params_.empty());
668   EXPECT_EQ(output_obus_.at(kAudioElementId).obu.audio_element_params_.front(),
669             kExpectedAudioElementParam);
670 }
671 
TEST_F(AudioElementGeneratorTest,MissingParamDefinitionTypeIsNotSupported)672 TEST_F(AudioElementGeneratorTest, MissingParamDefinitionTypeIsNotSupported) {
673   AddTwoLayer7_1_0_And7_1_4(audio_element_metadata_);
674   audio_element_metadata_.at(0).set_num_parameters(1);
675   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
676       R"pb(
677         # `param_definition_type` is omitted.
678         # param_definition_type: PARAM_DEFINITION_TYPE_DEMIXING
679       )pb",
680       audio_element_metadata_.at(0).add_audio_element_params()));
681 
682   AudioElementGenerator generator(audio_element_metadata_);
683   EXPECT_FALSE(generator.Generate(codec_config_obus_, output_obus_).ok());
684 }
685 
TEST_F(AudioElementGeneratorTest,DeprecatedParamDefinitionTypeIsNotSupported)686 TEST_F(AudioElementGeneratorTest, DeprecatedParamDefinitionTypeIsNotSupported) {
687   AddTwoLayer7_1_0_And7_1_4(audio_element_metadata_);
688   audio_element_metadata_.at(0).set_num_parameters(1);
689   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
690       R"pb(
691         deprecated_param_definition_type: 1  # PARAMETER_DEFINITION_DEMIXING
692       )pb",
693       audio_element_metadata_.at(0).add_audio_element_params()));
694 
695   AudioElementGenerator generator(audio_element_metadata_);
696   EXPECT_FALSE(generator.Generate(codec_config_obus_, output_obus_).ok());
697 }
698 
TEST_F(AudioElementGeneratorTest,GeneratesReconGainParameterDefinition)699 TEST_F(AudioElementGeneratorTest, GeneratesReconGainParameterDefinition) {
700   // Recon gain requires an associated lossy codec (e.g. Opus or AAC).
701   codec_config_obus_.clear();
702   AddOpusCodecConfigWithId(kCodecConfigId, codec_config_obus_);
703 
704   AddTwoLayer7_1_0_And7_1_4(audio_element_metadata_);
705 
706   // Reconfigure the audio element to add a recon gain parameter.
707   auto& audio_element_metadata = audio_element_metadata_.at(0);
708   audio_element_metadata.set_num_parameters(1);
709   audio_element_metadata.mutable_scalable_channel_layout_config()
710       ->mutable_channel_audio_layer_configs(1)
711       ->set_recon_gain_is_present_flag(true);
712   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
713       R"pb(
714         param_definition_type: PARAM_DEFINITION_TYPE_RECON_GAIN
715         recon_gain_param: {
716           param_definition {
717             parameter_id: 998
718             parameter_rate: 48000
719             param_definition_mode: 0
720             reserved: 10
721             duration: 8
722             num_subblocks: 1
723             constant_subblock_duration: 8
724           }
725         }
726       )pb",
727       audio_element_metadata.add_audio_element_params()));
728   // Configure matching expected values.
729   ReconGainParamDefinition expected_recon_gain_param_definition(
730       kAudioElementId);
731   expected_recon_gain_param_definition.parameter_id_ = 998;
732   expected_recon_gain_param_definition.parameter_rate_ = 48000;
733   expected_recon_gain_param_definition.param_definition_mode_ = 0;
734   expected_recon_gain_param_definition.duration_ = 8;
735   expected_recon_gain_param_definition.constant_subblock_duration_ = 8;
736   expected_recon_gain_param_definition.reserved_ = 10;
737 
738   const AudioElementParam kExpectedAudioElementParam = {
739       expected_recon_gain_param_definition};
740 
741   // Generate and validate the parameter-related information matches expected
742   // results.
743   AudioElementGenerator generator(audio_element_metadata_);
744   EXPECT_THAT(generator.Generate(codec_config_obus_, output_obus_), IsOk());
745 
746   const auto& obu = output_obus_.at(kAudioElementId).obu;
747   EXPECT_EQ(obu.audio_element_params_.size(), 1);
748   ASSERT_FALSE(obu.audio_element_params_.empty());
749   EXPECT_EQ(output_obus_.at(kAudioElementId).obu.audio_element_params_.front(),
750             kExpectedAudioElementParam);
751 }
752 
753 }  // namespace
754 }  // namespace iamf_tools
755