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