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 #include "iamf/cli/parameters_manager.h"
13
14 #include <cstdint>
15 #include <memory>
16 #include <utility>
17 #include <vector>
18
19 #include "absl/container/flat_hash_map.h"
20 #include "absl/status/status.h"
21 #include "absl/status/status_matchers.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "iamf/cli/audio_element_with_data.h"
25 #include "iamf/cli/parameter_block_with_data.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/obu_header.h"
32 #include "iamf/obu/param_definitions.h"
33 #include "iamf/obu/parameter_block.h"
34 #include "iamf/obu/recon_gain_info_parameter_data.h"
35 #include "iamf/obu/types.h"
36
37 namespace iamf_tools {
38 namespace {
39
40 using ::absl_testing::IsOk;
41
42 constexpr DecodedUleb128 kCodecConfigId = 1450;
43 constexpr DecodedUleb128 kSampleRate = 16000;
44 constexpr DecodedUleb128 kAudioElementId = 157;
45 constexpr DecodedUleb128 kFirstSubstreamId = 0;
46 constexpr DecodedUleb128 kSecondSubstreamId = 1;
47 constexpr DecodedUleb128 kParameterId = 995;
48 constexpr DecodedUleb128 kSecondParameterId = 996;
49 constexpr DecodedUleb128 kDuration = 8;
50 constexpr InternalTimestamp kDurationAsInternalTimestamp = 8;
51
52 constexpr DemixingInfoParameterData::DMixPMode kDMixPMode =
53 DemixingInfoParameterData::kDMixPMode3_n;
54
AppendParameterBlock(DecodedUleb128 parameter_id,InternalTimestamp start_timestamp,const ParamDefinition & param_definition,std::vector<ParameterBlockWithData> & parameter_blocks)55 absl::Status AppendParameterBlock(
56 DecodedUleb128 parameter_id, InternalTimestamp start_timestamp,
57 const ParamDefinition& param_definition,
58 std::vector<ParameterBlockWithData>& parameter_blocks) {
59 parameter_blocks.emplace_back(ParameterBlockWithData{
60 std::make_unique<ParameterBlockObu>(ObuHeader(), parameter_id,
61 param_definition),
62 start_timestamp, start_timestamp + kDurationAsInternalTimestamp});
63 ParameterBlockObu& parameter_block_obu = *parameter_blocks.back().obu;
64 absl::Status status = parameter_block_obu.InitializeSubblocks();
65 return status;
66 }
67
AddOneDemixingParameterBlock(const ParamDefinition & param_definition,InternalTimestamp start_timestamp,std::vector<ParameterBlockWithData> & parameter_blocks)68 absl::Status AddOneDemixingParameterBlock(
69 const ParamDefinition& param_definition, InternalTimestamp start_timestamp,
70 std::vector<ParameterBlockWithData>& parameter_blocks) {
71 auto status = AppendParameterBlock(kParameterId, start_timestamp,
72 param_definition, parameter_blocks);
73 auto demixing_info_param_data = std::make_unique<DemixingInfoParameterData>();
74 demixing_info_param_data->dmixp_mode = kDMixPMode;
75 ParameterBlockObu& parameter_block_obu = *parameter_blocks.back().obu;
76 parameter_block_obu.subblocks_[0].param_data =
77 std::move(demixing_info_param_data);
78
79 return status;
80 }
81
AddOneReconGainParameterBlock(const ParamDefinition & param_definition,InternalTimestamp start_timestamp,std::vector<ParameterBlockWithData> & parameter_blocks)82 absl::Status AddOneReconGainParameterBlock(
83 const ParamDefinition& param_definition, InternalTimestamp start_timestamp,
84 std::vector<ParameterBlockWithData>& parameter_blocks) {
85 auto status = AppendParameterBlock(kSecondParameterId, start_timestamp,
86 param_definition, parameter_blocks);
87
88 auto recon_gain_info_parameter_data =
89 std::make_unique<ReconGainInfoParameterData>();
90 recon_gain_info_parameter_data->recon_gain_elements.emplace_back(
91 ReconGainElement{
92 .recon_gain_flag = DecodedUleb128(1),
93 .recon_gain = {0},
94 });
95 ParameterBlockObu& parameter_block_obu = *parameter_blocks.back().obu;
96 parameter_block_obu.subblocks_[0].param_data =
97 std::move(recon_gain_info_parameter_data);
98 return status;
99 }
100
101 class ParametersManagerTest : public testing::Test {
102 public:
ParametersManagerTest()103 ParametersManagerTest() {
104 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
105 codec_config_obus_);
106 AddAmbisonicsMonoAudioElementWithSubstreamIds(
107 kAudioElementId, kCodecConfigId, {kFirstSubstreamId},
108 codec_config_obus_, audio_elements_);
109
110 auto& audio_element_obu = audio_elements_.at(kAudioElementId).obu;
111 AddDemixingParamDefinition(kParameterId, kSampleRate, kDuration,
112 audio_element_obu);
113
114 EXPECT_THAT(
115 AddOneDemixingParameterBlock(
116 std::get<DemixingParamDefinition>(
117 audio_element_obu.audio_element_params_[0].param_definition),
118 /*start_timestamp=*/0, demixing_parameter_blocks_),
119 IsOk());
120 }
121
122 protected:
123 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus_;
124 absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements_;
125 std::vector<ParameterBlockWithData> demixing_parameter_blocks_;
126 std::vector<ParameterBlockWithData> recon_gain_parameter_blocks_;
127 std::unique_ptr<ParametersManager> parameters_manager_;
128 };
129
TEST_F(ParametersManagerTest,InitializeSucceeds)130 TEST_F(ParametersManagerTest, InitializeSucceeds) {
131 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
132 EXPECT_THAT(parameters_manager_->Initialize(), IsOk());
133 }
134
TEST_F(ParametersManagerTest,InitializeWithTwoDemixingParametersFails)135 TEST_F(ParametersManagerTest, InitializeWithTwoDemixingParametersFails) {
136 // Add one more demixing parameter definition, which is disallowed.
137 AddDemixingParamDefinition(kParameterId, kSampleRate, kDuration,
138 audio_elements_.at(kAudioElementId).obu);
139
140 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
141 EXPECT_FALSE(parameters_manager_->Initialize().ok());
142 }
143
TEST_F(ParametersManagerTest,InitializeWithReconGainParameterSucceeds)144 TEST_F(ParametersManagerTest, InitializeWithReconGainParameterSucceeds) {
145 // Remove existng param definitions added in the constructor of the
146 // test fixture.
147 audio_elements_.at(kAudioElementId).obu.audio_element_params_.clear();
148 AddReconGainParamDefinition(kSecondParameterId, kSampleRate, kDuration,
149 audio_elements_.at(kAudioElementId).obu);
150 EXPECT_THAT(
151 AddOneReconGainParameterBlock(
152 std::get<ReconGainParamDefinition>(audio_elements_.at(kAudioElementId)
153 .obu.audio_element_params_[0]
154 .param_definition),
155 /*start_timestamp=*/0, recon_gain_parameter_blocks_),
156 IsOk());
157 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
158 EXPECT_THAT(parameters_manager_->Initialize(), IsOk());
159 }
160
TEST_F(ParametersManagerTest,DemixingParamDefinitionIsAvailable)161 TEST_F(ParametersManagerTest, DemixingParamDefinitionIsAvailable) {
162 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
163 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
164
165 EXPECT_TRUE(
166 parameters_manager_->DemixingParamDefinitionAvailable(kAudioElementId));
167 }
168
TEST_F(ParametersManagerTest,GetDownMixingParametersSucceeds)169 TEST_F(ParametersManagerTest, GetDownMixingParametersSucceeds) {
170 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
171 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
172 parameters_manager_->AddDemixingParameterBlock(
173 &demixing_parameter_blocks_[0]);
174
175 DownMixingParams down_mixing_params;
176 EXPECT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
177 down_mixing_params),
178 IsOk());
179
180 // Validate the values correspond to `kDMixPMode3_n`.
181 EXPECT_FLOAT_EQ(down_mixing_params.alpha, 1.0);
182 EXPECT_FLOAT_EQ(down_mixing_params.beta, 0.866);
183 EXPECT_FLOAT_EQ(down_mixing_params.gamma, 0.866);
184 EXPECT_FLOAT_EQ(down_mixing_params.delta, 0.866);
185 EXPECT_EQ(down_mixing_params.w_idx_offset, 1);
186 EXPECT_EQ(down_mixing_params.w_idx_used, 0);
187 EXPECT_FLOAT_EQ(down_mixing_params.w, 0.0);
188 }
189
TEST_F(ParametersManagerTest,GetReconGainInfoParameterDataSucceeds)190 TEST_F(ParametersManagerTest, GetReconGainInfoParameterDataSucceeds) {
191 AddReconGainParamDefinition(kSecondParameterId, kSampleRate, kDuration,
192 audio_elements_.at(kAudioElementId).obu);
193 ASSERT_THAT(
194 AddOneReconGainParameterBlock(
195 std::get<ReconGainParamDefinition>(audio_elements_.at(kAudioElementId)
196 .obu.audio_element_params_[1]
197 .param_definition),
198 /*start_timestamp=*/0, recon_gain_parameter_blocks_),
199 IsOk());
200 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
201 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
202 parameters_manager_->AddReconGainParameterBlock(
203 &recon_gain_parameter_blocks_[0]);
204
205 ReconGainInfoParameterData recon_gain_info_parameter_data;
206 EXPECT_THAT(
207 parameters_manager_->GetReconGainInfoParameterData(
208 kAudioElementId, /*num_layers=*/1, recon_gain_info_parameter_data),
209 IsOk());
210
211 EXPECT_EQ(recon_gain_info_parameter_data.recon_gain_elements.size(), 1);
212 ASSERT_TRUE(
213 recon_gain_info_parameter_data.recon_gain_elements[0].has_value());
214 EXPECT_EQ(
215 recon_gain_info_parameter_data.recon_gain_elements[0]->recon_gain_flag,
216 DecodedUleb128(1));
217 EXPECT_EQ(
218 recon_gain_info_parameter_data.recon_gain_elements[0]->recon_gain[0], 0);
219 }
220
TEST_F(ParametersManagerTest,GetReconGainInfoParameterDataSucceedsWithNoParameterBlocks)221 TEST_F(ParametersManagerTest,
222 GetReconGainInfoParameterDataSucceedsWithNoParameterBlocks) {
223 AddReconGainParamDefinition(kSecondParameterId, kSampleRate, kDuration,
224 audio_elements_.at(kAudioElementId).obu);
225 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
226 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
227
228 ReconGainInfoParameterData recon_gain_info_parameter_data;
229 EXPECT_THAT(
230 parameters_manager_->GetReconGainInfoParameterData(
231 kAudioElementId, /*num_layers=*/1, recon_gain_info_parameter_data),
232 IsOk());
233
234 EXPECT_EQ(recon_gain_info_parameter_data.recon_gain_elements.size(), 1);
235 ASSERT_TRUE(
236 recon_gain_info_parameter_data.recon_gain_elements[0].has_value());
237 EXPECT_EQ(
238 recon_gain_info_parameter_data.recon_gain_elements[0]->recon_gain_flag,
239 DecodedUleb128(0));
240 EXPECT_EQ(
241 recon_gain_info_parameter_data.recon_gain_elements[0]->recon_gain[0],
242 255);
243 }
244
TEST_F(ParametersManagerTest,GetReconGainInfoParameterDataSucceedsWithNoParamDefinition)245 TEST_F(ParametersManagerTest,
246 GetReconGainInfoParameterDataSucceedsWithNoParamDefinition) {
247 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
248 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
249
250 ReconGainInfoParameterData recon_gain_info_parameter_data;
251 EXPECT_THAT(
252 parameters_manager_->GetReconGainInfoParameterData(
253 kAudioElementId, /*num_layers=*/1, recon_gain_info_parameter_data),
254 IsOk());
255
256 EXPECT_EQ(recon_gain_info_parameter_data.recon_gain_elements.size(), 1);
257 ASSERT_TRUE(
258 recon_gain_info_parameter_data.recon_gain_elements[0].has_value());
259 EXPECT_EQ(
260 recon_gain_info_parameter_data.recon_gain_elements[0]->recon_gain_flag,
261 DecodedUleb128(0));
262 EXPECT_EQ(
263 recon_gain_info_parameter_data.recon_gain_elements[0]->recon_gain[0],
264 255);
265 }
266
TEST_F(ParametersManagerTest,GetMultipleReconGainParametersSucceeds)267 TEST_F(ParametersManagerTest, GetMultipleReconGainParametersSucceeds) {
268 // Tests that multiple recon gain parameters are returned correctly when there
269 // are multiple recon gain parameter blocks within the same substream, with
270 // consecutive timestamps.
271 AddReconGainParamDefinition(kSecondParameterId, kSampleRate, kDuration,
272 audio_elements_.at(kAudioElementId).obu);
273 ASSERT_THAT(
274 AddOneReconGainParameterBlock(
275 std::get<ReconGainParamDefinition>(audio_elements_.at(kAudioElementId)
276 .obu.audio_element_params_[1]
277 .param_definition),
278 /*start_timestamp=*/0, recon_gain_parameter_blocks_),
279 IsOk());
280 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
281 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
282 parameters_manager_->AddReconGainParameterBlock(
283 &recon_gain_parameter_blocks_[0]);
284
285 // First recon gain parameter block.
286 ReconGainInfoParameterData recon_gain_parameter_data_0;
287 EXPECT_THAT(
288 parameters_manager_->GetReconGainInfoParameterData(
289 kAudioElementId, /*num_layers=*/1, recon_gain_parameter_data_0),
290 IsOk());
291 EXPECT_EQ(recon_gain_parameter_data_0.recon_gain_elements.size(), 1);
292 ASSERT_TRUE(recon_gain_parameter_data_0.recon_gain_elements[0].has_value());
293 EXPECT_EQ(recon_gain_parameter_data_0.recon_gain_elements[0]->recon_gain_flag,
294 DecodedUleb128(1));
295 EXPECT_EQ(recon_gain_parameter_data_0.recon_gain_elements[0]->recon_gain[0],
296 0);
297
298 EXPECT_THAT(parameters_manager_->UpdateReconGainState(
299 kAudioElementId,
300 /*expected_next_timestamp=*/kDuration),
301 IsOk());
302
303 // Second recon gain parameter block.
304 ASSERT_THAT(
305 AddOneReconGainParameterBlock(
306 std::get<ReconGainParamDefinition>(audio_elements_.at(kAudioElementId)
307 .obu.audio_element_params_[1]
308 .param_definition),
309 /*start_timestamp=*/kDurationAsInternalTimestamp,
310 recon_gain_parameter_blocks_),
311 IsOk());
312 parameters_manager_->AddReconGainParameterBlock(
313 &recon_gain_parameter_blocks_[1]);
314 ReconGainInfoParameterData recon_gain_parameter_data_1;
315 EXPECT_THAT(
316 parameters_manager_->GetReconGainInfoParameterData(
317 kAudioElementId, /*num_layers=*/1, recon_gain_parameter_data_1),
318 IsOk());
319 EXPECT_EQ(recon_gain_parameter_data_1.recon_gain_elements.size(), 1);
320 ASSERT_TRUE(recon_gain_parameter_data_1.recon_gain_elements[0].has_value());
321 EXPECT_EQ(recon_gain_parameter_data_1.recon_gain_elements[0]->recon_gain_flag,
322 DecodedUleb128(1));
323 EXPECT_EQ(recon_gain_parameter_data_1.recon_gain_elements[0]->recon_gain[0],
324 0);
325 // Updating should succeed a second time with the expected timestamp now
326 // offset by the duration of the parameter block.
327 EXPECT_THAT(parameters_manager_->UpdateReconGainState(
328 kAudioElementId,
329 /*expected_next_timestamp=*/kDuration + kDuration),
330 IsOk());
331 }
332
TEST_F(ParametersManagerTest,GetMultipleReconGainParametersFailsWithoutUpdatingState)333 TEST_F(ParametersManagerTest,
334 GetMultipleReconGainParametersFailsWithoutUpdatingState) {
335 AddReconGainParamDefinition(kSecondParameterId, kSampleRate, kDuration,
336 audio_elements_.at(kAudioElementId).obu);
337 ASSERT_THAT(
338 AddOneReconGainParameterBlock(
339 std::get<ReconGainParamDefinition>(audio_elements_.at(kAudioElementId)
340 .obu.audio_element_params_[1]
341 .param_definition),
342 /*start_timestamp=*/0, recon_gain_parameter_blocks_),
343 IsOk());
344 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
345 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
346 parameters_manager_->AddReconGainParameterBlock(
347 &recon_gain_parameter_blocks_[0]);
348
349 // First recon gain parameter block.
350 ReconGainInfoParameterData recon_gain_parameter_data_0;
351 EXPECT_THAT(
352 parameters_manager_->GetReconGainInfoParameterData(
353 kAudioElementId, /*num_layers=*/1, recon_gain_parameter_data_0),
354 IsOk());
355
356 // Second recon gain parameter block.
357 ASSERT_THAT(
358 AddOneReconGainParameterBlock(
359 std::get<ReconGainParamDefinition>(audio_elements_.at(kAudioElementId)
360 .obu.audio_element_params_[1]
361 .param_definition),
362 /*start_timestamp=*/kDurationAsInternalTimestamp,
363 recon_gain_parameter_blocks_),
364 IsOk());
365 parameters_manager_->AddReconGainParameterBlock(
366 &recon_gain_parameter_blocks_[1]);
367 ReconGainInfoParameterData recon_gain_parameter_data_1;
368 EXPECT_FALSE(parameters_manager_
369 ->GetReconGainInfoParameterData(kAudioElementId,
370 /*num_layers=*/1,
371 recon_gain_parameter_data_1)
372 .ok());
373 }
374
TEST_F(ParametersManagerTest,ParameterBlocksRunOutReturnsDefault)375 TEST_F(ParametersManagerTest, ParameterBlocksRunOutReturnsDefault) {
376 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
377 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
378
379 parameters_manager_->AddDemixingParameterBlock(
380 &demixing_parameter_blocks_[0]);
381
382 DownMixingParams down_mixing_params;
383 EXPECT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
384 down_mixing_params),
385 IsOk());
386
387 EXPECT_THAT(parameters_manager_->UpdateDemixingState(
388 kAudioElementId,
389 /*expected_next_timestamp=*/kDurationAsInternalTimestamp),
390 IsOk());
391
392 // Get the parameters for the second time. Since there is only one
393 // parameter block and is already used up the previous time, the function
394 // will not find a parameter block and will return default values.
395 EXPECT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
396 down_mixing_params),
397 IsOk());
398
399 // Validate the values correspond to `kDMixPMode1` and `default_w = 10`,
400 // which are the default set in `AddDemixingParamDefinition()`.
401 EXPECT_FLOAT_EQ(down_mixing_params.alpha, 1.0);
402 EXPECT_FLOAT_EQ(down_mixing_params.beta, 1.0);
403 EXPECT_FLOAT_EQ(down_mixing_params.gamma, 0.707);
404 EXPECT_FLOAT_EQ(down_mixing_params.delta, 0.707);
405 EXPECT_EQ(down_mixing_params.w_idx_offset, -1);
406 EXPECT_EQ(down_mixing_params.w_idx_used, 10);
407 EXPECT_FLOAT_EQ(down_mixing_params.w, 0.5);
408
409 // `UpdateDemixingState()` also succeeds with some arbitrary timestamp,
410 // because technically there's nothing to update.
411 const DecodedUleb128 kArbitraryTimestamp = 972;
412 EXPECT_THAT(parameters_manager_->UpdateDemixingState(
413 kAudioElementId,
414 /*expected_next_timestamp=*/kArbitraryTimestamp),
415 IsOk());
416 }
417
TEST_F(ParametersManagerTest,ParameterIdNotFoundReturnsDefault)418 TEST_F(ParametersManagerTest, ParameterIdNotFoundReturnsDefault) {
419 // Modify the parameter definition of the audio element so it does not
420 // correspond to any parameter blocks inside `parameter_blocks_`.
421 std::get<DemixingParamDefinition>(audio_elements_.at(kAudioElementId)
422 .obu.audio_element_params_[0]
423 .param_definition)
424 .parameter_id_ = kParameterId + 1;
425
426 // Create the parameters manager and get down mixing parameters; default
427 // values are returned because the parameter ID is different from those
428 // in the `parameter_blocks_`.
429 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
430 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
431 parameters_manager_->AddDemixingParameterBlock(
432 &demixing_parameter_blocks_[0]);
433
434 DownMixingParams down_mixing_params;
435 EXPECT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
436 down_mixing_params),
437 IsOk());
438
439 // Validate the values correspond to `kDMixPMode1` and `default_w = 10`,
440 // which are the default set in `AddDemixingParamDefinition()`.
441 EXPECT_FLOAT_EQ(down_mixing_params.alpha, 1.0);
442 EXPECT_FLOAT_EQ(down_mixing_params.beta, 1.0);
443 EXPECT_FLOAT_EQ(down_mixing_params.gamma, 0.707);
444 EXPECT_FLOAT_EQ(down_mixing_params.delta, 0.707);
445 EXPECT_EQ(down_mixing_params.w_idx_offset, -1);
446 EXPECT_EQ(down_mixing_params.w_idx_used, 10);
447 EXPECT_FLOAT_EQ(down_mixing_params.w, 0.5);
448 }
449
TEST_F(ParametersManagerTest,GetDownMixingParametersTwiceDifferentW)450 TEST_F(ParametersManagerTest, GetDownMixingParametersTwiceDifferentW) {
451 // Add another parameter block, so we can get down-mix parameters twice.
452 ASSERT_THAT(
453 AddOneDemixingParameterBlock(
454 std::get<DemixingParamDefinition>(audio_elements_.at(kAudioElementId)
455 .obu.audio_element_params_[0]
456 .param_definition),
457 /*start_timestamp=*/kDuration, demixing_parameter_blocks_),
458 IsOk());
459
460 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
461 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
462 parameters_manager_->AddDemixingParameterBlock(
463 &demixing_parameter_blocks_[0]);
464
465 // Get down-mix parameters for the first time.
466 DownMixingParams down_mixing_params;
467 ASSERT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
468 down_mixing_params),
469 IsOk());
470 EXPECT_THAT(parameters_manager_->UpdateDemixingState(
471 kAudioElementId,
472 /*expected_next_timestamp=*/kDuration),
473 IsOk());
474
475 // The first time `w_idx` is 0, and the corresponding `w` is 0.
476 const double kWFirst = 0.0;
477 const double kWSecond = 0.0179;
478 EXPECT_FLOAT_EQ(down_mixing_params.w, kWFirst);
479
480 // Add and get down-mix parameters for the second time.
481 parameters_manager_->AddDemixingParameterBlock(
482 &demixing_parameter_blocks_[1]);
483 EXPECT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
484 down_mixing_params),
485 IsOk());
486
487 // Validate the values correspond to `kDMixPMode3_n`. Since `w_idx` has
488 // been updated to 1, `w` becomes 0.0179.
489 EXPECT_FLOAT_EQ(down_mixing_params.alpha, 1.0);
490 EXPECT_FLOAT_EQ(down_mixing_params.beta, 0.866);
491 EXPECT_FLOAT_EQ(down_mixing_params.gamma, 0.866);
492 EXPECT_FLOAT_EQ(down_mixing_params.delta, 0.866);
493 EXPECT_EQ(down_mixing_params.w_idx_offset, 1);
494 EXPECT_EQ(down_mixing_params.w_idx_used, 1);
495
496 // Updated `w`, different from the first time above.
497 EXPECT_FLOAT_EQ(down_mixing_params.w, kWSecond);
498 }
499
TEST_F(ParametersManagerTest,GetDownMixingParametersTwiceWithoutUpdateSameW)500 TEST_F(ParametersManagerTest, GetDownMixingParametersTwiceWithoutUpdateSameW) {
501 // Add another parameter block, so it is possible to get down-mix parameters
502 // twice.
503 ASSERT_THAT(
504 AddOneDemixingParameterBlock(
505 std::get<DemixingParamDefinition>(audio_elements_.at(kAudioElementId)
506 .obu.audio_element_params_[0]
507 .param_definition),
508 /*start_timestamp=*/kDuration, demixing_parameter_blocks_),
509 IsOk());
510
511 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
512 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
513 parameters_manager_->AddDemixingParameterBlock(
514 &demixing_parameter_blocks_[0]);
515
516 // Get down-mix parameters twice without calling
517 // `AddDemixingParameterBlock()` and `UpdateDemixngState()`; the same
518 // down-mix parameters will be returned.
519 DownMixingParams down_mixing_params;
520 ASSERT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
521 down_mixing_params),
522 IsOk());
523
524 // The first time `w_idx` is 0, and the corresponding `w` is 0.
525 EXPECT_EQ(down_mixing_params.w_idx_used, 0);
526 EXPECT_FLOAT_EQ(down_mixing_params.w, 0.0);
527
528 EXPECT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
529 down_mixing_params),
530 IsOk());
531
532 // Validate the values correspond to `kDMixPMode3_n`. Since `w_idx` has
533 // NOT been updated, `w` remains 0.0.
534 EXPECT_FLOAT_EQ(down_mixing_params.alpha, 1.0);
535 EXPECT_FLOAT_EQ(down_mixing_params.beta, 0.866);
536 EXPECT_FLOAT_EQ(down_mixing_params.gamma, 0.866);
537 EXPECT_FLOAT_EQ(down_mixing_params.delta, 0.866);
538 EXPECT_EQ(down_mixing_params.w_idx_offset, 1);
539 EXPECT_EQ(down_mixing_params.w_idx_used, 0);
540 EXPECT_FLOAT_EQ(down_mixing_params.w, 0.0);
541 }
542
TEST_F(ParametersManagerTest,TwoAudioElementGettingParameterBlocksWithDifferentTimestampsFails)543 TEST_F(ParametersManagerTest,
544 TwoAudioElementGettingParameterBlocksWithDifferentTimestampsFails) {
545 // Add another parameter block, so we can get down-mix parameters twice.
546 ASSERT_THAT(
547 AddOneDemixingParameterBlock(
548 std::get<DemixingParamDefinition>(audio_elements_.at(kAudioElementId)
549 .obu.audio_element_params_[0]
550 .param_definition),
551 /*start_timestamp=*/kDuration, demixing_parameter_blocks_),
552 IsOk());
553
554 // Add a second audio element sharing the same demixing parameter.
555 constexpr DecodedUleb128 kAudioElementId2 = kAudioElementId + 1;
556 AddAmbisonicsMonoAudioElementWithSubstreamIds(
557 kAudioElementId2, kCodecConfigId, {kSecondSubstreamId},
558 codec_config_obus_, audio_elements_);
559 auto& second_audio_element_obu = audio_elements_.at(kAudioElementId2).obu;
560 AddDemixingParamDefinition(kParameterId, kSampleRate, kDuration,
561 second_audio_element_obu);
562
563 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
564 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
565 parameters_manager_->AddDemixingParameterBlock(
566 &demixing_parameter_blocks_[0]);
567
568 // Get down-mix parameters for the first audio element corresponding to the
569 // first frame; the `w` value is 0.
570 const double kWFirst = 0.0;
571 const double kWSecond = 0.0179;
572 DownMixingParams down_mixing_params;
573 ASSERT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
574 down_mixing_params),
575 IsOk());
576 EXPECT_THAT(parameters_manager_->UpdateDemixingState(
577 kAudioElementId,
578 /*expected_next_timestamp=*/kDuration),
579 IsOk());
580 EXPECT_FLOAT_EQ(down_mixing_params.w, kWFirst);
581
582 // Add the parameter block for the first audio element corresponding to the
583 // second frame.
584 parameters_manager_->AddDemixingParameterBlock(
585 &demixing_parameter_blocks_[1]);
586 ASSERT_THAT(parameters_manager_->GetDownMixingParameters(kAudioElementId,
587 down_mixing_params),
588 IsOk());
589 EXPECT_FLOAT_EQ(down_mixing_params.w, kWSecond);
590
591 // Get down-mix parameters for the second audio element. The second audio
592 // element shares the same parameter ID, but is still expecting the
593 // parameter block for the first frame (while the manager is already
594 // holding the parameter block for the second frame). So the getter fails.
595 EXPECT_FALSE(
596 parameters_manager_
597 ->GetDownMixingParameters(kAudioElementId2, down_mixing_params)
598 .ok());
599 }
600
TEST_F(ParametersManagerTest,DemixingParamDefinitionIsNotAvailableForWrongId)601 TEST_F(ParametersManagerTest, DemixingParamDefinitionIsNotAvailableForWrongId) {
602 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
603 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
604 parameters_manager_->AddDemixingParameterBlock(
605 &demixing_parameter_blocks_[0]);
606
607 const DecodedUleb128 kWrongAudioElementId = kAudioElementId + 1;
608 EXPECT_FALSE(parameters_manager_->DemixingParamDefinitionAvailable(
609 kWrongAudioElementId));
610
611 // However, `GetDownMixingParameters()` still succeeds.
612 DownMixingParams down_mixing_params;
613 EXPECT_THAT(parameters_manager_->GetDownMixingParameters(kWrongAudioElementId,
614 down_mixing_params),
615 IsOk());
616
617 // `UpdateDemixingState()` also succeeds.
618 EXPECT_THAT(parameters_manager_->UpdateDemixingState(
619 kWrongAudioElementId,
620 /*expected_next_timestamp=*/kDuration),
621 IsOk());
622 }
623
TEST_F(ParametersManagerTest,UpdateFailsWithWrongTimestamps)624 TEST_F(ParametersManagerTest, UpdateFailsWithWrongTimestamps) {
625 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
626 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
627 parameters_manager_->AddDemixingParameterBlock(
628 &demixing_parameter_blocks_[0]);
629
630 // The second frame starts with timestamp = 8, so updating with a different
631 // timestamp fails.
632 constexpr InternalTimestamp kWrongNextTimestamp = 17;
633 EXPECT_FALSE(parameters_manager_
634 ->UpdateDemixingState(kAudioElementId, kWrongNextTimestamp)
635 .ok());
636 }
637
TEST_F(ParametersManagerTest,UpdateNotValidatingWhenParameterIdNotFound)638 TEST_F(ParametersManagerTest, UpdateNotValidatingWhenParameterIdNotFound) {
639 // Modify the parameter definition of the audio element so it does not
640 // correspond to any parameter blocks inside `parameter_blocks_`.
641 std::get<DemixingParamDefinition>(audio_elements_.at(kAudioElementId)
642 .obu.audio_element_params_[0]
643 .param_definition)
644 .parameter_id_ = kParameterId + 1;
645
646 // Create the parameters manager and get down mixing parameters; default
647 // values are returned because the parameter ID is not found.
648 parameters_manager_ = std::make_unique<ParametersManager>(audio_elements_);
649 ASSERT_THAT(parameters_manager_->Initialize(), IsOk());
650 parameters_manager_->AddDemixingParameterBlock(
651 &demixing_parameter_blocks_[0]);
652
653 // `UpdateDemixingState()` succeeds with any timestamp passed in,
654 // because no validation is performed.
655 for (const InternalTimestamp timestamp : {0, 8, -200, 61, 4772}) {
656 EXPECT_THAT(
657 parameters_manager_->UpdateDemixingState(kAudioElementId, timestamp),
658 IsOk());
659 }
660 }
661
662 } // namespace
663 } // namespace iamf_tools
664