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/obu_sequencer_base.h"
13
14 #include <cstdint>
15 #include <list>
16 #include <memory>
17 #include <optional>
18 #include <utility>
19 #include <vector>
20
21 #include "absl/container/flat_hash_map.h"
22 #include "absl/status/status.h"
23 #include "absl/status/status_matchers.h"
24 #include "absl/types/span.h"
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "iamf/cli/audio_element_with_data.h"
28 #include "iamf/cli/audio_frame_with_data.h"
29 #include "iamf/cli/parameter_block_with_data.h"
30 #include "iamf/cli/temporal_unit_view.h"
31 #include "iamf/cli/tests/cli_test_utils.h"
32 #include "iamf/common/leb_generator.h"
33 #include "iamf/common/write_bit_buffer.h"
34 #include "iamf/obu/arbitrary_obu.h"
35 #include "iamf/obu/audio_frame.h"
36 #include "iamf/obu/codec_config.h"
37 #include "iamf/obu/demixing_info_parameter_data.h"
38 #include "iamf/obu/demixing_param_definition.h"
39 #include "iamf/obu/ia_sequence_header.h"
40 #include "iamf/obu/mix_presentation.h"
41 #include "iamf/obu/obu_base.h"
42 #include "iamf/obu/obu_header.h"
43 #include "iamf/obu/parameter_block.h"
44 #include "iamf/obu/temporal_delimiter.h"
45 #include "iamf/obu/types.h"
46
47 namespace iamf_tools {
48 namespace {
49
50 using ::absl_testing::IsOk;
51 using ::testing::_;
52 using ::testing::Not;
53 using ::testing::Return;
54
55 using absl::MakeConstSpan;
56
57 constexpr DecodedUleb128 kCodecConfigId = 1;
58 constexpr uint32_t kNumSamplesPerFrame = 8;
59 constexpr uint32_t kSampleRate = 48000;
60 // Some timestamps consistent with the number of samples per frame.
61 constexpr InternalTimestamp kFirstTimestamp = kNumSamplesPerFrame * 0;
62 constexpr InternalTimestamp kSecondTimestamp = kNumSamplesPerFrame * 1;
63 constexpr InternalTimestamp kThirdTimestamp = kNumSamplesPerFrame * 2;
64 constexpr DecodedUleb128 kFirstAudioElementId = 1;
65 constexpr DecodedUleb128 kSecondAudioElementId = 2;
66 constexpr DecodedUleb128 kFirstSubstreamId = 1;
67 constexpr DecodedUleb128 kSecondSubstreamId = 2;
68 constexpr DecodedUleb128 kFirstMixPresentationId = 100;
69 constexpr DecodedUleb128 kFirstDemixingParameterId = 998;
70 constexpr DecodedUleb128 kCommonMixGainParameterId = 999;
71 constexpr uint32_t kCommonMixGainParameterRate = kSampleRate;
72
73 constexpr bool kIncludeTemporalDelimiters = true;
74 constexpr bool kDoNotIncludeTemporalDelimiters = false;
75
76 constexpr bool kDelayDescriptorsUntilTrimAtStartIsKnown = true;
77 constexpr bool kDoNotDelayDescriptorsUntilTrimAtStartIsKnown = false;
78
79 constexpr std::nullopt_t kOriginalSamplesAreIrrelevant = std::nullopt;
80
81 constexpr absl::Span<ParameterBlockWithData> kNoParameterBlocks = {};
82 constexpr absl::Span<ArbitraryObu> kNoArbitraryObus = {};
83
InitializeDescriptorObusForOneMonoAmbisonicsAudioElement(absl::flat_hash_map<DecodedUleb128,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements,std::list<MixPresentationObu> & mix_presentation_obus)84 void InitializeDescriptorObusForOneMonoAmbisonicsAudioElement(
85 absl::flat_hash_map<DecodedUleb128, CodecConfigObu>& codec_config_obus,
86 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
87 std::list<MixPresentationObu>& mix_presentation_obus) {
88 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
89 codec_config_obus);
90 AddAmbisonicsMonoAudioElementWithSubstreamIds(
91 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
92 codec_config_obus, audio_elements);
93 AddMixPresentationObuWithAudioElementIds(
94 kFirstMixPresentationId, {kFirstAudioElementId},
95 kCommonMixGainParameterId, kCommonMixGainParameterRate,
96 mix_presentation_obus);
97 }
98
AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(uint32_t audio_element_id,uint32_t substream_id,InternalTimestamp start_timestamp,InternalTimestamp end_timestamp,const absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements,std::list<AudioFrameWithData> & audio_frames)99 void AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
100 uint32_t audio_element_id, uint32_t substream_id,
101 InternalTimestamp start_timestamp, InternalTimestamp end_timestamp,
102 const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
103 std::list<AudioFrameWithData>& audio_frames) {
104 ASSERT_TRUE(audio_elements.contains(audio_element_id));
105
106 audio_frames.emplace_back(AudioFrameWithData{
107 .obu = AudioFrameObu(ObuHeader(), substream_id, {}),
108 .start_timestamp = start_timestamp,
109 .end_timestamp = end_timestamp,
110 .pcm_samples = kOriginalSamplesAreIrrelevant,
111 .down_mixing_params = {.in_bitstream = false},
112 .audio_element_with_data = &audio_elements.at(audio_element_id)});
113 }
114
InitializeOneFrameIaSequence(absl::flat_hash_map<uint32_t,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements,std::list<AudioFrameWithData> & audio_frames)115 void InitializeOneFrameIaSequence(
116 absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
117 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
118 std::list<AudioFrameWithData>& audio_frames) {
119 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
120 codec_config_obus);
121 AddAmbisonicsMonoAudioElementWithSubstreamIds(
122 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
123 codec_config_obus, audio_elements);
124 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
125 kFirstAudioElementId, kFirstSubstreamId, kFirstTimestamp,
126 kSecondTimestamp, audio_elements, audio_frames);
127 }
128
InitializeOneFrameIaSequenceWithMixPresentation(absl::flat_hash_map<DecodedUleb128,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements,std::list<MixPresentationObu> & mix_presentation_obus,std::list<AudioFrameWithData> & audio_frames)129 void InitializeOneFrameIaSequenceWithMixPresentation(
130 absl::flat_hash_map<DecodedUleb128, CodecConfigObu>& codec_config_obus,
131 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
132 std::list<MixPresentationObu>& mix_presentation_obus,
133 std::list<AudioFrameWithData>& audio_frames) {
134 InitializeDescriptorObusForOneMonoAmbisonicsAudioElement(
135 codec_config_obus, audio_elements, mix_presentation_obus);
136
137 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
138 kFirstAudioElementId, kFirstSubstreamId, 0, 8, audio_elements,
139 audio_frames);
140 }
141
InitializeOneParameterBlockAndOneAudioFrame(DemixingParamDefinition & param_definition,std::list<ParameterBlockWithData> & parameter_blocks,std::list<AudioFrameWithData> & audio_frames,absl::flat_hash_map<uint32_t,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements)142 void InitializeOneParameterBlockAndOneAudioFrame(
143 DemixingParamDefinition& param_definition,
144 std::list<ParameterBlockWithData>& parameter_blocks,
145 std::list<AudioFrameWithData>& audio_frames,
146 absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
147 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements) {
148 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
149 auto data = std::make_unique<DemixingInfoParameterData>();
150 data->dmixp_mode = DemixingInfoParameterData::kDMixPMode1;
151 data->reserved = 0;
152 auto parameter_block = std::make_unique<ParameterBlockObu>(
153 ObuHeader(), param_definition.parameter_id_, param_definition);
154 ASSERT_THAT(parameter_block->InitializeSubblocks(), IsOk());
155 parameter_block->subblocks_[0].param_data = std::move(data);
156 parameter_blocks.emplace_back(ParameterBlockWithData{
157 .obu = std::move(parameter_block),
158 .start_timestamp = kFirstTimestamp,
159 .end_timestamp = kSecondTimestamp,
160 });
161 }
InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(absl::flat_hash_map<DecodedUleb128,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<uint32_t,AudioElementWithData> & audio_elements,std::list<MixPresentationObu> & mix_presentation_obus)162 void InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(
163 absl::flat_hash_map<DecodedUleb128, CodecConfigObu>& codec_config_obus,
164 absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
165 std::list<MixPresentationObu>& mix_presentation_obus) {
166 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
167 codec_config_obus);
168 AddAmbisonicsMonoAudioElementWithSubstreamIds(
169 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
170 codec_config_obus, audio_elements);
171 AddAmbisonicsMonoAudioElementWithSubstreamIds(
172 kSecondAudioElementId, kCodecConfigId, {kSecondSubstreamId},
173 codec_config_obus, audio_elements);
174 AddMixPresentationObuWithAudioElementIds(
175 kFirstMixPresentationId, {kFirstAudioElementId, kSecondAudioElementId},
176 kCommonMixGainParameterId, kCommonMixGainParameterRate,
177 mix_presentation_obus);
178 }
179
CreateDemixingParamDefinition(const DecodedUleb128 parameter_id)180 DemixingParamDefinition CreateDemixingParamDefinition(
181 const DecodedUleb128 parameter_id) {
182 DemixingParamDefinition demixing_param_definition;
183 demixing_param_definition.parameter_id_ = parameter_id;
184 demixing_param_definition.parameter_rate_ = 48000;
185 demixing_param_definition.param_definition_mode_ = 0;
186 demixing_param_definition.duration_ = 8;
187 demixing_param_definition.constant_subblock_duration_ = 8;
188 demixing_param_definition.reserved_ = 10;
189
190 return demixing_param_definition;
191 }
192
ValidateWriteTemporalUnitSequence(bool include_temporal_delimiters,const TemporalUnitView & temporal_unit,const std::list<const ObuBase * > & expected_sequence)193 void ValidateWriteTemporalUnitSequence(
194 bool include_temporal_delimiters, const TemporalUnitView& temporal_unit,
195 const std::list<const ObuBase*>& expected_sequence) {
196 WriteBitBuffer result_wb(128);
197 int unused_num_samples;
198 EXPECT_THAT(ObuSequencerBase::WriteTemporalUnit(include_temporal_delimiters,
199 temporal_unit, result_wb,
200 unused_num_samples),
201 IsOk());
202
203 EXPECT_EQ(result_wb.bit_buffer(), SerializeObusExpectOk(expected_sequence));
204 }
205
TEST(WriteTemporalUnit,WritesArbitraryObuBeforeParameterBlocksAtTime)206 TEST(WriteTemporalUnit, WritesArbitraryObuBeforeParameterBlocksAtTime) {
207 std::list<ParameterBlockWithData> parameter_blocks;
208 std::list<AudioFrameWithData> audio_frames;
209 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
210 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
211 DemixingParamDefinition param_definition =
212 CreateDemixingParamDefinition(kFirstDemixingParameterId);
213 InitializeOneParameterBlockAndOneAudioFrame(
214 param_definition, parameter_blocks, audio_frames, codec_config_obus,
215 audio_elements);
216 const std::list<ArbitraryObu> kArbitraryObuBeforeParameterBlocks(
217 {ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
218 ArbitraryObu::kInsertionHookBeforeParameterBlocksAtTick,
219 kFirstTimestamp)});
220 const auto temporal_unit = TemporalUnitView::Create(
221 parameter_blocks, audio_frames, kArbitraryObuBeforeParameterBlocks);
222 ASSERT_THAT(temporal_unit, IsOk());
223
224 const TemporalDelimiterObu temporal_delimiter_obu(ObuHeader{});
225
226 const std::list<const ObuBase*>
227 expected_arbitrary_obu_between_temporal_delimiter_and_parameter_block = {
228 &temporal_delimiter_obu, &kArbitraryObuBeforeParameterBlocks.front(),
229 parameter_blocks.front().obu.get(), &audio_frames.front().obu};
230
231 ValidateWriteTemporalUnitSequence(
232 kIncludeTemporalDelimiters, *temporal_unit,
233 expected_arbitrary_obu_between_temporal_delimiter_and_parameter_block);
234 }
235
TEST(WriteTemporalUnit,WritesArbitraryObuAfterParameterBlocksAtTime)236 TEST(WriteTemporalUnit, WritesArbitraryObuAfterParameterBlocksAtTime) {
237 std::list<ParameterBlockWithData> parameter_blocks;
238 std::list<AudioFrameWithData> audio_frames;
239 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
240 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
241 DemixingParamDefinition param_definition =
242 CreateDemixingParamDefinition(kFirstDemixingParameterId);
243 InitializeOneParameterBlockAndOneAudioFrame(
244 param_definition, parameter_blocks, audio_frames, codec_config_obus,
245 audio_elements);
246 const std::list<ArbitraryObu> kArbitraryObuAfterParameterBlocks(
247 {ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
248 ArbitraryObu::kInsertionHookAfterParameterBlocksAtTick,
249 kFirstTimestamp)});
250 const auto temporal_unit = TemporalUnitView::Create(
251 parameter_blocks, audio_frames, kArbitraryObuAfterParameterBlocks);
252 ASSERT_THAT(temporal_unit, IsOk());
253
254 const std::list<const ObuBase*>
255 expected_arbitrary_obu_between_parameter_block_and_audio_frame = {
256 parameter_blocks.front().obu.get(),
257 &kArbitraryObuAfterParameterBlocks.front(),
258 &audio_frames.front().obu,
259 };
260
261 ValidateWriteTemporalUnitSequence(
262 kDoNotIncludeTemporalDelimiters, *temporal_unit,
263 expected_arbitrary_obu_between_parameter_block_and_audio_frame);
264 }
265
TEST(WriteTemporalUnit,WritesArbitraryObuAfterAudioFramesAtTime)266 TEST(WriteTemporalUnit, WritesArbitraryObuAfterAudioFramesAtTime) {
267 std::list<ParameterBlockWithData> parameter_blocks;
268 std::list<AudioFrameWithData> audio_frames;
269 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
270 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
271 DemixingParamDefinition param_definition =
272 CreateDemixingParamDefinition(kFirstDemixingParameterId);
273 InitializeOneParameterBlockAndOneAudioFrame(
274 param_definition, parameter_blocks, audio_frames, codec_config_obus,
275 audio_elements);
276 const std::list<ArbitraryObu> kArbitraryObuAfterAudioFrames({ArbitraryObu(
277 kObuIaReserved25, ObuHeader(), {},
278 ArbitraryObu::kInsertionHookAfterAudioFramesAtTick, kFirstTimestamp)});
279 const auto temporal_unit = TemporalUnitView::Create(
280 parameter_blocks, audio_frames, kArbitraryObuAfterAudioFrames);
281 ASSERT_THAT(temporal_unit, IsOk());
282
283 const std::list<const ObuBase*> expected_arbitrary_obu_after_audio_frame = {
284 parameter_blocks.front().obu.get(),
285 &audio_frames.front().obu,
286 &kArbitraryObuAfterAudioFrames.front(),
287 };
288
289 ValidateWriteTemporalUnitSequence(kDoNotIncludeTemporalDelimiters,
290 *temporal_unit,
291 expected_arbitrary_obu_after_audio_frame);
292 }
293
TEST(WriteTemporalUnit,AccumulatesZeroSamplesForFullyTrimmedAudioFrame)294 TEST(WriteTemporalUnit, AccumulatesZeroSamplesForFullyTrimmedAudioFrame) {
295 std::list<AudioFrameWithData> audio_frames;
296 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
297 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
298 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
299 audio_frames.front().obu.header_.num_samples_to_trim_at_end = 0;
300 audio_frames.front().obu.header_.num_samples_to_trim_at_start = 8;
301 constexpr uint32_t kNumUntrimmedSamples = 0;
302 const auto temporal_unit = TemporalUnitView::Create(
303 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
304 ASSERT_THAT(temporal_unit, IsOk());
305
306 WriteBitBuffer wb(128);
307 int num_samples = 0;
308 EXPECT_THAT(
309 ObuSequencerBase::WriteTemporalUnit(kDoNotIncludeTemporalDelimiters,
310 *temporal_unit, wb, num_samples),
311 IsOk());
312
313 EXPECT_EQ(num_samples, kNumUntrimmedSamples);
314 }
315
TEST(WriteTemporalUnit,AddsNumberOfUntrimmedSamplesToNumSamples)316 TEST(WriteTemporalUnit, AddsNumberOfUntrimmedSamplesToNumSamples) {
317 std::list<AudioFrameWithData> audio_frames;
318 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
319 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
320 InitializeOneFrameIaSequence(codec_config_obus, audio_elements, audio_frames);
321 audio_frames.front().obu.header_.num_samples_to_trim_at_end = 2;
322 audio_frames.front().obu.header_.num_samples_to_trim_at_start = 1;
323 constexpr uint32_t kNumUntrimmedSamples = kNumSamplesPerFrame - 1 - 2;
324 const auto temporal_unit = TemporalUnitView::Create(
325 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
326 ASSERT_THAT(temporal_unit, IsOk());
327
328 WriteBitBuffer undefined_wb(128);
329 int num_samples = 0;
330 EXPECT_THAT(ObuSequencerBase::WriteTemporalUnit(
331 kDoNotIncludeTemporalDelimiters, *temporal_unit, undefined_wb,
332 num_samples),
333 IsOk());
334 EXPECT_EQ(num_samples, kNumUntrimmedSamples);
335 // Another write keeps adding to the number of samples.
336 EXPECT_THAT(ObuSequencerBase::WriteTemporalUnit(
337 kDoNotIncludeTemporalDelimiters, *temporal_unit, undefined_wb,
338 num_samples),
339 IsOk());
340 EXPECT_EQ(num_samples, kNumUntrimmedSamples * 2);
341 }
342
TEST(WriteTemporalUnit,WritesTemporalDelimiterObuWhenEnabled)343 TEST(WriteTemporalUnit, WritesTemporalDelimiterObuWhenEnabled) {
344 std::list<ParameterBlockWithData> parameter_blocks;
345 std::list<AudioFrameWithData> audio_frames;
346 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
347 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
348 DemixingParamDefinition param_definition =
349 CreateDemixingParamDefinition(kFirstDemixingParameterId);
350 InitializeOneParameterBlockAndOneAudioFrame(
351 param_definition, parameter_blocks, audio_frames, codec_config_obus,
352 audio_elements);
353 const auto temporal_unit = TemporalUnitView::Create(
354 parameter_blocks, audio_frames, kNoArbitraryObus);
355 ASSERT_THAT(temporal_unit, IsOk());
356
357 const TemporalDelimiterObu kTemporalDelimiterObu(ObuHeader{});
358 const std::list<const ObuBase*> expected_sequence = {
359 &kTemporalDelimiterObu,
360 parameter_blocks.front().obu.get(),
361 &audio_frames.front().obu,
362 };
363
364 ValidateWriteTemporalUnitSequence(kIncludeTemporalDelimiters, *temporal_unit,
365 expected_sequence);
366 }
367
TEST(WriteTemporalUnit,OmitsTemporalDelimiterObuWhenDisabled)368 TEST(WriteTemporalUnit, OmitsTemporalDelimiterObuWhenDisabled) {
369 std::list<ParameterBlockWithData> parameter_blocks;
370 std::list<AudioFrameWithData> audio_frames;
371 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
372 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
373 DemixingParamDefinition param_definition =
374 CreateDemixingParamDefinition(kFirstDemixingParameterId);
375 InitializeOneParameterBlockAndOneAudioFrame(
376 param_definition, parameter_blocks, audio_frames, codec_config_obus,
377 audio_elements);
378 const auto temporal_unit = TemporalUnitView::Create(
379 parameter_blocks, audio_frames, kNoArbitraryObus);
380 ASSERT_THAT(temporal_unit, IsOk());
381
382 const std::list<const ObuBase*> expected_sequence = {
383 parameter_blocks.front().obu.get(),
384 &audio_frames.front().obu,
385 };
386
387 ValidateWriteTemporalUnitSequence(kDoNotIncludeTemporalDelimiters,
388 *temporal_unit, expected_sequence);
389 }
390
391 class ObuSequencerTest : public ::testing::Test {
392 public:
InitializeDescriptorObus()393 void InitializeDescriptorObus() {
394 ia_sequence_header_obu_.emplace(ObuHeader(), IASequenceHeaderObu::kIaCode,
395 ProfileVersion::kIamfSimpleProfile,
396 ProfileVersion::kIamfSimpleProfile);
397 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
398 codec_config_obus_);
399 AddAmbisonicsMonoAudioElementWithSubstreamIds(
400 kFirstAudioElementId, kCodecConfigId, {kFirstSubstreamId},
401 codec_config_obus_, audio_elements_);
402 AddMixPresentationObuWithAudioElementIds(
403 kFirstMixPresentationId, {kFirstAudioElementId},
404 kCommonMixGainParameterId, kCommonMixGainParameterRate,
405 mix_presentation_obus_);
406
407 ASSERT_TRUE(ia_sequence_header_obu_.has_value());
408 ASSERT_TRUE(codec_config_obus_.contains(kCodecConfigId));
409 ASSERT_TRUE(audio_elements_.contains(kFirstAudioElementId));
410 ASSERT_FALSE(mix_presentation_obus_.empty());
411 }
412
InitObusForOneFrameIaSequence()413 void InitObusForOneFrameIaSequence() {
414 ia_sequence_header_obu_.emplace(ObuHeader(), IASequenceHeaderObu::kIaCode,
415 ProfileVersion::kIamfSimpleProfile,
416 ProfileVersion::kIamfSimpleProfile);
417 param_definition_ =
418 CreateDemixingParamDefinition(kFirstDemixingParameterId);
419 InitializeOneParameterBlockAndOneAudioFrame(
420 param_definition_, parameter_blocks_, audio_frames_, codec_config_obus_,
421 audio_elements_);
422 AddMixPresentationObuWithAudioElementIds(
423 kFirstMixPresentationId, {audio_elements_.begin()->first},
424 kCommonMixGainParameterId, kCommonMixGainParameterRate,
425 mix_presentation_obus_);
426 }
427
ValidateWriteDescriptorObuSequence(const std::list<const ObuBase * > & expected_sequence)428 void ValidateWriteDescriptorObuSequence(
429 const std::list<const ObuBase*>& expected_sequence) {
430 WriteBitBuffer expected_wb(128);
431 for (const auto* expected_obu : expected_sequence) {
432 ASSERT_NE(expected_obu, nullptr);
433 EXPECT_THAT(expected_obu->ValidateAndWriteObu(expected_wb), IsOk());
434 }
435
436 WriteBitBuffer result_wb(128);
437 EXPECT_THAT(ObuSequencerBase::WriteDescriptorObus(
438 ia_sequence_header_obu_.value(), codec_config_obus_,
439 audio_elements_, mix_presentation_obus_, arbitrary_obus_,
440 result_wb),
441 IsOk());
442
443 EXPECT_EQ(result_wb.bit_buffer(), expected_wb.bit_buffer());
444 }
445
446 protected:
447 std::optional<IASequenceHeaderObu> ia_sequence_header_obu_;
448 absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus_;
449 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements_;
450 std::list<MixPresentationObu> mix_presentation_obus_;
451
452 DemixingParamDefinition param_definition_;
453 std::list<ParameterBlockWithData> parameter_blocks_;
454 std::list<AudioFrameWithData> audio_frames_;
455
456 std::list<ArbitraryObu> arbitrary_obus_;
457 };
458
TEST_F(ObuSequencerTest,OrdersByAParticularObuType)459 TEST_F(ObuSequencerTest, OrdersByAParticularObuType) {
460 InitializeDescriptorObus();
461 // The IAMF spec REQUIRES descriptor OBUs to be ordered by `obu_type` in a
462 // particular order (i.e. IA Sequence Header, Codec Config Audio Element, Mix
463 // Presentation).
464 const std::list<const ObuBase*> expected_sequence = {
465 &ia_sequence_header_obu_.value(), &codec_config_obus_.at(kCodecConfigId),
466 &audio_elements_.at(kFirstAudioElementId).obu,
467 &mix_presentation_obus_.back()};
468
469 ValidateWriteDescriptorObuSequence(expected_sequence);
470 }
471
TEST_F(ObuSequencerTest,ArbitraryObuAfterIaSequenceHeader)472 TEST_F(ObuSequencerTest, ArbitraryObuAfterIaSequenceHeader) {
473 InitializeDescriptorObus();
474
475 arbitrary_obus_.emplace_back(
476 ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
477 ArbitraryObu::kInsertionHookAfterIaSequenceHeader));
478
479 const std::list<const ObuBase*> expected_sequence = {
480 &ia_sequence_header_obu_.value(),
481 &arbitrary_obus_.back(),
482 &codec_config_obus_.at(kCodecConfigId),
483 &audio_elements_.at(kFirstAudioElementId).obu,
484 &mix_presentation_obus_.back(),
485 };
486
487 ValidateWriteDescriptorObuSequence(expected_sequence);
488 }
489
TEST_F(ObuSequencerTest,ArbitraryObuAfterCodecConfigs)490 TEST_F(ObuSequencerTest, ArbitraryObuAfterCodecConfigs) {
491 InitializeDescriptorObus();
492
493 arbitrary_obus_.emplace_back(
494 ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
495 ArbitraryObu::kInsertionHookAfterCodecConfigs));
496
497 const std::list<const ObuBase*> expected_sequence = {
498 &ia_sequence_header_obu_.value(),
499 &codec_config_obus_.at(kCodecConfigId),
500 &arbitrary_obus_.back(),
501 &audio_elements_.at(kFirstAudioElementId).obu,
502 &mix_presentation_obus_.back(),
503 };
504
505 ValidateWriteDescriptorObuSequence(expected_sequence);
506 }
507
TEST_F(ObuSequencerTest,ArbitraryObuAfterAudioElements)508 TEST_F(ObuSequencerTest, ArbitraryObuAfterAudioElements) {
509 InitializeDescriptorObus();
510
511 arbitrary_obus_.emplace_back(
512 ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
513 ArbitraryObu::kInsertionHookAfterAudioElements));
514
515 const std::list<const ObuBase*> expected_sequence = {
516 &ia_sequence_header_obu_.value(),
517 &codec_config_obus_.at(kCodecConfigId),
518 &audio_elements_.at(kFirstAudioElementId).obu,
519 &arbitrary_obus_.back(),
520 &mix_presentation_obus_.back(),
521 };
522
523 ValidateWriteDescriptorObuSequence(expected_sequence);
524 }
525
TEST_F(ObuSequencerTest,ArbitraryObuAfterMixPresentations)526 TEST_F(ObuSequencerTest, ArbitraryObuAfterMixPresentations) {
527 InitializeDescriptorObus();
528
529 arbitrary_obus_.emplace_back(
530 ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
531 ArbitraryObu::kInsertionHookAfterMixPresentations));
532
533 const std::list<const ObuBase*> expected_sequence = {
534 &ia_sequence_header_obu_.value(),
535 &codec_config_obus_.at(kCodecConfigId),
536 &audio_elements_.at(kFirstAudioElementId).obu,
537 &mix_presentation_obus_.back(),
538 &arbitrary_obus_.back(),
539 };
540
541 ValidateWriteDescriptorObuSequence(expected_sequence);
542 }
543
544 // This behavior helps ensure that "after descriptors" are not written in the
545 // "IACB" box in MP4.
TEST_F(ObuSequencerTest,DoesNotWriteArbitraryObuAfterDescriptors)546 TEST_F(ObuSequencerTest, DoesNotWriteArbitraryObuAfterDescriptors) {
547 InitializeDescriptorObus();
548
549 arbitrary_obus_.emplace_back(
550 ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
551 ArbitraryObu::kInsertionHookAfterDescriptors));
552
553 const std::list<const ObuBase*> expected_sequence = {
554 &ia_sequence_header_obu_.value(), &codec_config_obus_.at(kCodecConfigId),
555 &audio_elements_.at(kFirstAudioElementId).obu,
556 &mix_presentation_obus_.back(),
557 // &arbitrary_obus_.back(),
558 };
559
560 ValidateWriteDescriptorObuSequence(expected_sequence);
561 }
562
TEST_F(ObuSequencerTest,CodecConfigAreAscendingOrderByDefault)563 TEST_F(ObuSequencerTest, CodecConfigAreAscendingOrderByDefault) {
564 InitializeDescriptorObus();
565
566 // Initialize a second Codec Config OBU.
567 const DecodedUleb128 kSecondCodecConfigId = 101;
568 AddLpcmCodecConfigWithIdAndSampleRate(kSecondCodecConfigId, kSampleRate,
569 codec_config_obus_);
570
571 // IAMF makes no recommendation for the ordering between multiple descriptor
572 // OBUs of the same type. By default `WriteDescriptorObus` orders them in
573 // ascending order.
574 ASSERT_LT(kCodecConfigId, kSecondCodecConfigId);
575 const std::list<const ObuBase*> expected_sequence = {
576 &ia_sequence_header_obu_.value(), &codec_config_obus_.at(kCodecConfigId),
577 &codec_config_obus_.at(kSecondCodecConfigId),
578 &audio_elements_.at(kFirstAudioElementId).obu,
579 &mix_presentation_obus_.back()};
580
581 ValidateWriteDescriptorObuSequence(expected_sequence);
582 }
583
TEST_F(ObuSequencerTest,AudioElementAreAscendingOrderByDefault)584 TEST_F(ObuSequencerTest, AudioElementAreAscendingOrderByDefault) {
585 InitializeDescriptorObus();
586
587 // Initialize a second Audio Element OBU.
588 const DecodedUleb128 kSecondAudioElementId = 101;
589 AddAmbisonicsMonoAudioElementWithSubstreamIds(
590 kSecondAudioElementId, kCodecConfigId, {kFirstSubstreamId},
591 codec_config_obus_, audio_elements_);
592
593 // IAMF makes no recommendation for the ordering between multiple descriptor
594 // OBUs of the same type. By default `WriteDescriptorObus` orders them in
595 // ascending order.
596 ASSERT_LT(kFirstAudioElementId, kSecondAudioElementId);
597 const std::list<const ObuBase*> expected_sequence = {
598 &ia_sequence_header_obu_.value(), &codec_config_obus_.at(kCodecConfigId),
599 &audio_elements_.at(kFirstAudioElementId).obu,
600 &audio_elements_.at(kSecondAudioElementId).obu,
601 &mix_presentation_obus_.back()};
602
603 ValidateWriteDescriptorObuSequence(expected_sequence);
604 }
605
TEST_F(ObuSequencerTest,MixPresentationsMaintainOriginalOrder)606 TEST_F(ObuSequencerTest, MixPresentationsMaintainOriginalOrder) {
607 InitializeDescriptorObus();
608 mix_presentation_obus_.clear();
609
610 // Prefix descriptor OBUs.
611 std::list<const ObuBase*> expected_sequence = {
612 &ia_sequence_header_obu_.value(),
613 &codec_config_obus_.at(kCodecConfigId),
614 &audio_elements_.at(kFirstAudioElementId).obu,
615 };
616 // Initialize three Mix Presentation OBUs, regardless of their IDs we
617 // expect them to be serialized in the same order as the input list.
618 constexpr DecodedUleb128 kFirstMixPresentationId = 100;
619 constexpr DecodedUleb128 kSecondMixPresentationId = 99;
620 constexpr DecodedUleb128 kThirdMixPresentationId = 101;
621 AddMixPresentationObuWithAudioElementIds(
622 kFirstMixPresentationId, {kFirstAudioElementId},
623 kCommonMixGainParameterId, kCommonMixGainParameterRate,
624 mix_presentation_obus_);
625 expected_sequence.push_back(&mix_presentation_obus_.back());
626 AddMixPresentationObuWithAudioElementIds(
627 kSecondMixPresentationId, {kFirstAudioElementId},
628 kCommonMixGainParameterId, kCommonMixGainParameterRate,
629 mix_presentation_obus_);
630 expected_sequence.push_back(&mix_presentation_obus_.back());
631 AddMixPresentationObuWithAudioElementIds(
632 kThirdMixPresentationId, {kFirstAudioElementId},
633 kCommonMixGainParameterId, kCommonMixGainParameterRate,
634 mix_presentation_obus_);
635 expected_sequence.push_back(&mix_presentation_obus_.back());
636
637 ValidateWriteDescriptorObuSequence(expected_sequence);
638 }
639
TEST(WriteDescriptorObus,InvalidWhenMixPresentationDoesNotComplyWithIaSequenceHeader)640 TEST(WriteDescriptorObus,
641 InvalidWhenMixPresentationDoesNotComplyWithIaSequenceHeader) {
642 IASequenceHeaderObu ia_sequence_header_obu(
643 ObuHeader(), IASequenceHeaderObu::kIaCode,
644 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfSimpleProfile);
645 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
646 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
647 std::list<MixPresentationObu> mix_presentation_obus;
648 InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(
649 codec_config_obus, audio_elements, mix_presentation_obus);
650
651 WriteBitBuffer unused_wb(0);
652 EXPECT_FALSE(ObuSequencerBase::WriteDescriptorObus(
653 ia_sequence_header_obu, codec_config_obus, audio_elements,
654 mix_presentation_obus, /*arbitrary_obus=*/{}, unused_wb)
655 .ok());
656 }
657
TEST(WriteDescriptorObus,ValidWhenMixPresentationCompliesWithIaSequenceHeader)658 TEST(WriteDescriptorObus,
659 ValidWhenMixPresentationCompliesWithIaSequenceHeader) {
660 IASequenceHeaderObu ia_sequence_header_obu(
661 ObuHeader(), IASequenceHeaderObu::kIaCode,
662 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
663 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
664 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
665 std::list<MixPresentationObu> mix_presentation_obus;
666 InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(
667 codec_config_obus, audio_elements, mix_presentation_obus);
668
669 WriteBitBuffer unused_wb(0);
670 EXPECT_THAT(ObuSequencerBase::WriteDescriptorObus(
671 ia_sequence_header_obu, codec_config_obus, audio_elements,
672 mix_presentation_obus, /*arbitrary_obus=*/{}, unused_wb),
673 IsOk());
674 }
675
TEST(PushDescriptorObus,SucceedsWithIaSequenceHeaderOnly)676 TEST(PushDescriptorObus, SucceedsWithIaSequenceHeaderOnly) {
677 const IASequenceHeaderObu kIaSequenceHeader(
678 ObuHeader(), IASequenceHeaderObu::kIaCode,
679 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
680 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
681 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
682 const std::list<MixPresentationObu> kNoMixPresentationObus;
683 const std::list<ArbitraryObu> kNoArbitraryObus;
684 MockObuSequencer mock_obu_sequencer(
685 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
686 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
687
688 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
689 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
690 kNoMixPresentationObus, kNoArbitraryObus),
691 IsOk());
692 }
693
TEST(PickAndPlace,SucceedsWithIaSequenceHeaderOnly)694 TEST(PickAndPlace, SucceedsWithIaSequenceHeaderOnly) {
695 const IASequenceHeaderObu kIaSequenceHeader(
696 ObuHeader(), IASequenceHeaderObu::kIaCode,
697 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
698 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
699 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
700 const std::list<MixPresentationObu> kNoMixPresentationObus;
701 const std::list<AudioFrameWithData> kNoAudioFrames;
702 const std::list<ParameterBlockWithData> kNoParameterBlocks;
703 const std::list<ArbitraryObu> kNoArbitraryObus;
704 MockObuSequencer mock_obu_sequencer(
705 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
706 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
707
708 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
709 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
710 kNoMixPresentationObus, kNoAudioFrames, kNoParameterBlocks,
711 kNoArbitraryObus),
712 IsOk());
713 }
714
TEST(PushDescriptorObus,FailsWhenCalledTwice)715 TEST(PushDescriptorObus, FailsWhenCalledTwice) {
716 const IASequenceHeaderObu kIaSequenceHeader(
717 ObuHeader(), IASequenceHeaderObu::kIaCode,
718 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
719 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
720 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
721 const std::list<MixPresentationObu> kNoMixPresentationObus;
722 const std::list<ArbitraryObu> kNoArbitraryObus;
723 MockObuSequencer mock_obu_sequencer(
724 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
725 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
726 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
727 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
728 kNoMixPresentationObus, kNoArbitraryObus),
729 IsOk());
730
731 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
732 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
733 kNoMixPresentationObus, kNoArbitraryObus),
734 Not(IsOk()));
735 }
736
TEST(PickAndPlace,FailsWhenCalledTwice)737 TEST(PickAndPlace, FailsWhenCalledTwice) {
738 const IASequenceHeaderObu kIaSequenceHeader(
739 ObuHeader(), IASequenceHeaderObu::kIaCode,
740 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
741 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
742 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
743 const std::list<MixPresentationObu> kNoMixPresentationObus;
744 const std::list<AudioFrameWithData> kNoAudioFrames;
745 const std::list<ParameterBlockWithData> kNoParameterBlocks;
746 const std::list<ArbitraryObu> kNoArbitraryObus;
747 MockObuSequencer mock_obu_sequencer(
748 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
749 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
750 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
751 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
752 kNoMixPresentationObus, kNoAudioFrames, kNoParameterBlocks,
753 kNoArbitraryObus),
754 IsOk());
755
756 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
757 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
758 kNoMixPresentationObus, kNoAudioFrames, kNoParameterBlocks,
759 kNoArbitraryObus),
760 Not(IsOk()));
761 }
762
TEST(PushDescriptorObus,ForwardsPropertiesToPushSerializedDescriptorObus)763 TEST(PushDescriptorObus, ForwardsPropertiesToPushSerializedDescriptorObus) {
764 const IASequenceHeaderObu kIaSequenceHeader(
765 ObuHeader(), IASequenceHeaderObu::kIaCode,
766 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
767 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
768 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
769 std::list<MixPresentationObu> mix_presentation_obus;
770 const std::list<ArbitraryObu> kNoArbitraryObus;
771 InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(
772 codec_config_obus, audio_elements, mix_presentation_obus);
773 MockObuSequencer mock_obu_sequencer(
774 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
775 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
776
777 // Several properties should match values derived from the descriptor OBUs.
778 const auto& codec_config_obu = codec_config_obus.begin()->second;
779 const uint32_t kExpectedCommonSamplesPerFrame =
780 codec_config_obu.GetNumSamplesPerFrame();
781 const uint32_t kExpectedCommonSampleRate =
782 codec_config_obu.GetOutputSampleRate();
783 const uint8_t kExpectedCommonBitDepth =
784 codec_config_obu.GetBitDepthToMeasureLoudness();
785 const std::optional<int64_t> kOmitFirstPts = std::nullopt;
786 const int kExpectedNumChannels = 2;
787 const std::vector<uint8_t> descriptor_obus = {1, 2, 3};
788 EXPECT_CALL(
789 mock_obu_sequencer,
790 PushSerializedDescriptorObus(
791 kExpectedCommonSamplesPerFrame, kExpectedCommonSampleRate,
792 kExpectedCommonBitDepth, kOmitFirstPts, kExpectedNumChannels, _));
793
794 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
795 kIaSequenceHeader, codec_config_obus, audio_elements,
796 mix_presentation_obus, kNoArbitraryObus),
797 IsOk());
798 }
799
TEST(PickAndPlace,ForwardsPropertiesToPushSerializedDescriptorObus)800 TEST(PickAndPlace, ForwardsPropertiesToPushSerializedDescriptorObus) {
801 const IASequenceHeaderObu kIaSequenceHeader(
802 ObuHeader(), IASequenceHeaderObu::kIaCode,
803 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
804 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
805 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
806 std::list<MixPresentationObu> mix_presentation_obus;
807 const std::list<AudioFrameWithData> kNoAudioFrames;
808 const std::list<ParameterBlockWithData> kNoParameterBlocks;
809 const std::list<ArbitraryObu> kNoArbitraryObus;
810 InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(
811 codec_config_obus, audio_elements, mix_presentation_obus);
812 MockObuSequencer mock_obu_sequencer(
813 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
814 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
815
816 // Several properties should match values derived from the descriptor OBUs.
817 const auto& codec_config_obu = codec_config_obus.begin()->second;
818 const uint32_t kExpectedCommonSamplesPerFrame =
819 codec_config_obu.GetNumSamplesPerFrame();
820 const uint32_t kExpectedCommonSampleRate =
821 codec_config_obu.GetOutputSampleRate();
822 const uint8_t kExpectedCommonBitDepth =
823 codec_config_obu.GetBitDepthToMeasureLoudness();
824 const std::optional<int64_t> kOmitFirstPts = std::nullopt;
825 const int kExpectedNumChannels = 2;
826 const std::vector<uint8_t> descriptor_obus = {1, 2, 3};
827 EXPECT_CALL(
828 mock_obu_sequencer,
829 PushSerializedDescriptorObus(
830 kExpectedCommonSamplesPerFrame, kExpectedCommonSampleRate,
831 kExpectedCommonBitDepth, kOmitFirstPts, kExpectedNumChannels, _));
832
833 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
834 kIaSequenceHeader, codec_config_obus, audio_elements,
835 mix_presentation_obus, kNoAudioFrames, kNoParameterBlocks,
836 kNoArbitraryObus),
837 IsOk());
838 }
839
TEST(PushDescriptorObus,WhenDescriptorsAreNotDelayedDescriptorsAreForwardedImmediately)840 TEST(PushDescriptorObus,
841 WhenDescriptorsAreNotDelayedDescriptorsAreForwardedImmediately) {
842 // Configure the OBU sequencer to not delay descriptors. This means the
843 // properties can be forwarded right away.
844 const IASequenceHeaderObu kIaSequenceHeader(
845 ObuHeader(), IASequenceHeaderObu::kIaCode,
846 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
847 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
848 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
849 const std::list<MixPresentationObu> kNoMixPresentationObus;
850 const std::list<ArbitraryObu> kNoArbitraryObus;
851 MockObuSequencer mock_obu_sequencer(
852 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
853 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
854
855 // The properties themselves are arbitrary, but "reasonable" defaults. This is
856 // to ensure certain OBU sequencers can have a file with reasonable
857 // properties, even if the IA Sequence is trivial.
858 const uint32_t kExpectedCommonSamplesPerFrame = 1024;
859 const uint32_t kExpectedCommonSampleRate = 48000;
860 const uint8_t kExpectedCommonBitDepth = 16;
861 const std::optional<int64_t> kFirstUntrimmedTimestamp = std::nullopt;
862 const int kExpectedNumChannels = 2;
863 EXPECT_CALL(mock_obu_sequencer,
864 PushSerializedDescriptorObus(
865 kExpectedCommonSamplesPerFrame, kExpectedCommonSampleRate,
866 kExpectedCommonBitDepth, kFirstUntrimmedTimestamp,
867 kExpectedNumChannels, _));
868
869 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
870 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
871 kNoMixPresentationObus, kNoArbitraryObus),
872 IsOk());
873 }
874
TEST(PushDescriptorObus,WhenDescriptorsAreDelayedPropertiesAreForwardedAfterCloseForTrivialIaSequences)875 TEST(
876 PushDescriptorObus,
877 WhenDescriptorsAreDelayedPropertiesAreForwardedAfterCloseForTrivialIaSequences) {
878 // Configure the OBU sequencer to delay descriptors until the first untrimmed
879 // sample is known. We can't detect it is a trivial IA Sequence, until the
880 // sequencer is closed.
881 const IASequenceHeaderObu kIaSequenceHeader(
882 ObuHeader(), IASequenceHeaderObu::kIaCode,
883 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
884 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
885 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
886 const std::list<MixPresentationObu> kNoMixPresentationObus;
887 const std::list<ArbitraryObu> kNoArbitraryObus;
888 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
889 kDoNotIncludeTemporalDelimiters,
890 kDelayDescriptorsUntilTrimAtStartIsKnown);
891 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
892 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
893 kNoMixPresentationObus, kNoArbitraryObus),
894 IsOk());
895
896 // The properties themselves are arbitrary, but "reasonable" defaults. This is
897 // to ensure certain OBU sequencers can have a file with reasonable
898 // properties, even if the IA Sequence is trivial.
899 const uint32_t kExpectedCommonSamplesPerFrame = 1024;
900 const uint32_t kExpectedCommonSampleRate = 48000;
901 const uint8_t kExpectedCommonBitDepth = 16;
902 const std::optional<int64_t> kFirstUntrimmedTimestamp = 0;
903 const int kExpectedNumChannels = 2;
904 EXPECT_CALL(mock_obu_sequencer,
905 PushSerializedDescriptorObus(
906 kExpectedCommonSamplesPerFrame, kExpectedCommonSampleRate,
907 kExpectedCommonBitDepth, kFirstUntrimmedTimestamp,
908 kExpectedNumChannels, _));
909 // Finally at close time, we detect that there are no audio frames. Therefore
910 // we can make up a fake first timestamp.
911 EXPECT_THAT(mock_obu_sequencer.Close(), IsOk());
912 }
913
TEST(PickAndPlace,ForwardsDefaultPropertiesForTrivialIaSequences)914 TEST(PickAndPlace, ForwardsDefaultPropertiesForTrivialIaSequences) {
915 const IASequenceHeaderObu kIaSequenceHeader(
916 ObuHeader(), IASequenceHeaderObu::kIaCode,
917 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
918 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
919 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
920 const std::list<MixPresentationObu> kNoMixPresentationObus;
921 const std::list<AudioFrameWithData> kNoAudioFrames;
922 const std::list<ParameterBlockWithData> kNoParameterBlocks;
923 const std::list<ArbitraryObu> kNoArbitraryObus;
924 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
925 kDoNotIncludeTemporalDelimiters,
926 kDelayDescriptorsUntilTrimAtStartIsKnown);
927
928 // The properties themselves are arbitrary, but "reasonable" defaults. This is
929 // to ensure certain OBU sequencers can have a file with reasonable
930 // properties, even if the IA Sequence is trivial.
931 const uint32_t kExpectedCommonSamplesPerFrame = 1024;
932 const uint32_t kExpectedCommonSampleRate = 48000;
933 const uint8_t kExpectedCommonBitDepth = 16;
934 const std::optional<int64_t> kFirstUntrimmedTimestamp = 0;
935 const int kExpectedNumChannels = 2;
936 EXPECT_CALL(mock_obu_sequencer,
937 PushSerializedDescriptorObus(
938 kExpectedCommonSamplesPerFrame, kExpectedCommonSampleRate,
939 kExpectedCommonBitDepth, kFirstUntrimmedTimestamp,
940 kExpectedNumChannels, _));
941
942 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
943 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
944 kNoMixPresentationObus, kNoAudioFrames, kNoParameterBlocks,
945 kNoArbitraryObus),
946 IsOk());
947 }
948
TEST(PushDescriptorObus,ForwardsSerializedDescriptorObusToPushDescriptorObus)949 TEST(PushDescriptorObus, ForwardsSerializedDescriptorObusToPushDescriptorObus) {
950 const IASequenceHeaderObu kIaSequenceHeader(
951 ObuHeader(), IASequenceHeaderObu::kIaCode,
952 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
953 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
954 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
955 std::list<MixPresentationObu> mix_presentation_obus;
956 const std::list<ArbitraryObu> kNoArbitraryObus;
957 InitializeDescriptorObusForOneMonoAmbisonicsAudioElement(
958 codec_config_obus, audio_elements, mix_presentation_obus);
959 MockObuSequencer mock_obu_sequencer(
960 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
961 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
962
963 // The spec prescribes an order among different types of descriptor OBUs.
964 const auto descriptor_obus = SerializeObusExpectOk(std::list<const ObuBase*>{
965 &kIaSequenceHeader, &codec_config_obus.begin()->second,
966 &audio_elements.begin()->second.obu, &mix_presentation_obus.front()});
967 EXPECT_CALL(mock_obu_sequencer,
968 PushSerializedDescriptorObus(_, _, _, _, _,
969 MakeConstSpan(descriptor_obus)));
970
971 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
972 kIaSequenceHeader, codec_config_obus, audio_elements,
973 mix_presentation_obus, kNoArbitraryObus),
974 IsOk());
975 }
976
TEST(PickAndPlace,ForwardsSerializedDescriptorObusToPushDescriptorObus)977 TEST(PickAndPlace, ForwardsSerializedDescriptorObusToPushDescriptorObus) {
978 const IASequenceHeaderObu kIaSequenceHeader(
979 ObuHeader(), IASequenceHeaderObu::kIaCode,
980 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
981 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
982 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
983 std::list<MixPresentationObu> mix_presentation_obus;
984 const std::list<AudioFrameWithData> kNoAudioFrames;
985 const std::list<ParameterBlockWithData> kNoParameterBlocks;
986 const std::list<ArbitraryObu> kNoArbitraryObus;
987 InitializeDescriptorObusForOneMonoAmbisonicsAudioElement(
988 codec_config_obus, audio_elements, mix_presentation_obus);
989 MockObuSequencer mock_obu_sequencer(
990 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
991 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
992
993 // The spec prescribes an order among different types of descriptor OBUs.
994 const auto descriptor_obus = SerializeObusExpectOk(std::list<const ObuBase*>{
995 &kIaSequenceHeader, &codec_config_obus.begin()->second,
996 &audio_elements.begin()->second.obu, &mix_presentation_obus.front()});
997 EXPECT_CALL(mock_obu_sequencer,
998 PushSerializedDescriptorObus(_, _, _, _, _,
999 MakeConstSpan(descriptor_obus)));
1000
1001 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1002 kIaSequenceHeader, codec_config_obus, audio_elements,
1003 mix_presentation_obus, kNoAudioFrames, kNoParameterBlocks,
1004 kNoArbitraryObus),
1005 IsOk());
1006 }
1007
TEST(PushDescriptorObus,ForwardsArbitraryObusToPushSerializedDescriptorObus)1008 TEST(PushDescriptorObus, ForwardsArbitraryObusToPushSerializedDescriptorObus) {
1009 const IASequenceHeaderObu kIaSequenceHeader(
1010 ObuHeader(), IASequenceHeaderObu::kIaCode,
1011 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1012 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1013 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1014 const std::list<MixPresentationObu> kNoMixPresentationObus;
1015 const std::list<ArbitraryObu> kArbitraryObuAfterIaSequenceHeader(
1016 {ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
1017 ArbitraryObu::kInsertionHookAfterIaSequenceHeader)});
1018 MockObuSequencer mock_obu_sequencer(
1019 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1020 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1021
1022 // Custom arbitrary OBUs can be placed according to their hook.
1023 const auto descriptor_obus = SerializeObusExpectOk(std::list<const ObuBase*>{
1024 &kIaSequenceHeader, &kArbitraryObuAfterIaSequenceHeader.front()});
1025 EXPECT_CALL(mock_obu_sequencer,
1026 PushSerializedDescriptorObus(_, _, _, _, _,
1027 MakeConstSpan(descriptor_obus)));
1028
1029 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1030 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
1031 kNoMixPresentationObus, kArbitraryObuAfterIaSequenceHeader),
1032 IsOk());
1033 }
1034
TEST(PickAndPlace,ForwardsArbitraryObusToPushSerializedDescriptorObus)1035 TEST(PickAndPlace, ForwardsArbitraryObusToPushSerializedDescriptorObus) {
1036 const IASequenceHeaderObu kIaSequenceHeader(
1037 ObuHeader(), IASequenceHeaderObu::kIaCode,
1038 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1039 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1040 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1041 const std::list<MixPresentationObu> kNoMixPresentationObus;
1042 const std::list<AudioFrameWithData> kNoAudioFrames;
1043 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1044 const std::list<ArbitraryObu> kArbitraryObuAfterIaSequenceHeader(
1045 {ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
1046 ArbitraryObu::kInsertionHookAfterIaSequenceHeader)});
1047 MockObuSequencer mock_obu_sequencer(
1048 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1049 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1050
1051 // Custom arbitrary OBUs can be placed according to their hook.
1052 const auto descriptor_obus = SerializeObusExpectOk(std::list<const ObuBase*>{
1053 &kIaSequenceHeader, &kArbitraryObuAfterIaSequenceHeader.front()});
1054 EXPECT_CALL(mock_obu_sequencer,
1055 PushSerializedDescriptorObus(_, _, _, _, _,
1056 MakeConstSpan(descriptor_obus)));
1057
1058 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1059 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
1060 kNoMixPresentationObus, kNoAudioFrames, kNoParameterBlocks,
1061 kArbitraryObuAfterIaSequenceHeader),
1062 IsOk());
1063 }
1064
TEST(PushTemporalUnit,ForwardsPropertiesToPushAllTemporalUnits)1065 TEST(PushTemporalUnit, ForwardsPropertiesToPushAllTemporalUnits) {
1066 const IASequenceHeaderObu kIaSequenceHeader(
1067 ObuHeader(), IASequenceHeaderObu::kIaCode,
1068 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1069 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1070 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1071 std::list<MixPresentationObu> mix_presentation_obus;
1072 std::list<AudioFrameWithData> audio_frames;
1073 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1074 const std::list<ArbitraryObu> kNoArbitraryObus;
1075 InitializeOneFrameIaSequenceWithMixPresentation(
1076 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1077 audio_frames.front().obu.header_.num_samples_to_trim_at_start = 2;
1078 audio_frames.front().obu.header_.num_samples_to_trim_at_end = 1;
1079 const auto temporal_unit = TemporalUnitView::Create(
1080 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
1081 ASSERT_THAT(temporal_unit, IsOk());
1082 // We expect eight samples per frame, less the trimmed samples.
1083 constexpr int kExpectedTimestamp = 0;
1084 constexpr int kExpectedNumSamples = 5;
1085 MockObuSequencer mock_obu_sequencer(
1086 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1087 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1088 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1089 kIaSequenceHeader, codec_config_obus, audio_elements,
1090 mix_presentation_obus, kNoArbitraryObus),
1091 IsOk());
1092
1093 EXPECT_CALL(
1094 mock_obu_sequencer,
1095 PushSerializedTemporalUnit(kExpectedTimestamp, kExpectedNumSamples, _));
1096
1097 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*temporal_unit), IsOk());
1098 }
1099
TEST(PickAndPlace,ForwardsPropertiesToPushAllTemporalUnits)1100 TEST(PickAndPlace, ForwardsPropertiesToPushAllTemporalUnits) {
1101 const IASequenceHeaderObu kIaSequenceHeader(
1102 ObuHeader(), IASequenceHeaderObu::kIaCode,
1103 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1104 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1105 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1106 std::list<MixPresentationObu> mix_presentation_obus;
1107 std::list<AudioFrameWithData> audio_frames;
1108 InitializeOneFrameIaSequenceWithMixPresentation(
1109 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1110 audio_frames.front().obu.header_.num_samples_to_trim_at_start = 2;
1111 audio_frames.front().obu.header_.num_samples_to_trim_at_end = 1;
1112 // We expect eight samples per frame, less the trimmed samples.
1113 constexpr int kExpectedTimestamp = 0;
1114 constexpr int kExpectedNumSamples = 5;
1115 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1116 const std::list<ArbitraryObu> kNoArbitraryObus;
1117 MockObuSequencer mock_obu_sequencer(
1118 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1119 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1120
1121 EXPECT_CALL(
1122 mock_obu_sequencer,
1123 PushSerializedTemporalUnit(kExpectedTimestamp, kExpectedNumSamples, _));
1124
1125 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1126 kIaSequenceHeader, codec_config_obus, audio_elements,
1127 mix_presentation_obus, audio_frames, kNoParameterBlocks,
1128 kNoArbitraryObus),
1129 IsOk());
1130 }
1131
TEST(PickAndPlace,OrdersTemporalUnitsByTimestamp)1132 TEST(PickAndPlace, OrdersTemporalUnitsByTimestamp) {
1133 const IASequenceHeaderObu kIaSequenceHeader(
1134 ObuHeader(), IASequenceHeaderObu::kIaCode,
1135 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1136 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1137 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1138 std::list<MixPresentationObu> mix_presentation_obus;
1139 std::list<AudioFrameWithData> two_audio_frames;
1140 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1141 const std::list<ArbitraryObu> kNoArbitraryObus;
1142 InitializeOneFrameIaSequenceWithMixPresentation(
1143 codec_config_obus, audio_elements, mix_presentation_obus,
1144 two_audio_frames);
1145 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
1146 kFirstAudioElementId, kFirstSubstreamId, kSecondTimestamp,
1147 kThirdTimestamp, audio_elements, two_audio_frames);
1148 // Ok, it is strange, to have audio frames in the wrong order. But the
1149 // sequencer handles this and arranges as per the timestamp.
1150 std::swap(two_audio_frames.front(), two_audio_frames.back());
1151 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
1152 kDoNotIncludeTemporalDelimiters,
1153 kDelayDescriptorsUntilTrimAtStartIsKnown);
1154
1155 // The cumulative number of samples to trim at the start of the IA Sequence
1156 // for the initial audio frane(s).
1157 EXPECT_CALL(mock_obu_sequencer,
1158 PushSerializedTemporalUnit(kFirstTimestamp, _, _));
1159 EXPECT_CALL(mock_obu_sequencer,
1160 PushSerializedTemporalUnit(kSecondTimestamp, _, _));
1161
1162 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1163 kIaSequenceHeader, codec_config_obus, audio_elements,
1164 mix_presentation_obus, two_audio_frames, kNoParameterBlocks,
1165 kNoArbitraryObus),
1166 IsOk());
1167 }
1168
TEST(PushTemporalUnit,ForwardsNumUntrimmedSamplesToPushSerializedTemporalUnitWhenConfigured)1169 TEST(PushTemporalUnit,
1170 ForwardsNumUntrimmedSamplesToPushSerializedTemporalUnitWhenConfigured) {
1171 const IASequenceHeaderObu kIaSequenceHeader(
1172 ObuHeader(), IASequenceHeaderObu::kIaCode,
1173 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1174 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1175 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1176 std::list<MixPresentationObu> mix_presentation_obus;
1177 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1178 const std::list<ArbitraryObu> kNoArbitraryObus;
1179 std::list<AudioFrameWithData> first_audio_frame;
1180 InitializeOneFrameIaSequenceWithMixPresentation(
1181 codec_config_obus, audio_elements, mix_presentation_obus,
1182 first_audio_frame);
1183 first_audio_frame.back().obu.header_.num_samples_to_trim_at_start = 8;
1184 const auto first_temporal_unit = TemporalUnitView::Create(
1185 kNoParameterBlocks, first_audio_frame, kNoArbitraryObus);
1186 ASSERT_THAT(first_temporal_unit, IsOk());
1187 std::list<AudioFrameWithData> second_audio_frame;
1188 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
1189 kFirstAudioElementId, kFirstSubstreamId, kSecondTimestamp,
1190 kThirdTimestamp, audio_elements, second_audio_frame);
1191 second_audio_frame.back().obu.header_.num_samples_to_trim_at_start = 3;
1192 const auto second_temporal_unit = TemporalUnitView::Create(
1193 kNoParameterBlocks, second_audio_frame, kNoArbitraryObus);
1194 ASSERT_THAT(second_temporal_unit, IsOk());
1195 // The first frame is fully trimmed. The second frame is partially trimmed.
1196 constexpr std::optional<int64_t> kExpectedFirstUntrimmedTimestamp = 11;
1197 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
1198 kDoNotIncludeTemporalDelimiters,
1199 kDelayDescriptorsUntilTrimAtStartIsKnown);
1200 // Neither the initial descriptors, nor the first temporal unit have enough
1201 // information to determine the first untrimmed timestamp.
1202 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1203 kIaSequenceHeader, codec_config_obus, audio_elements,
1204 mix_presentation_obus, kNoArbitraryObus),
1205 IsOk());
1206 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*first_temporal_unit),
1207 IsOk());
1208
1209 // But by the second temporal unit, we can see the cumulative number of
1210 // samples to trim at the start for this IA Sequence.
1211 EXPECT_CALL(mock_obu_sequencer,
1212 PushSerializedDescriptorObus(
1213 _, _, _, kExpectedFirstUntrimmedTimestamp, _, _));
1214 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*second_temporal_unit),
1215 IsOk());
1216 }
1217
TEST(PickAndPlace,ForwardsNumUntrimmedSamplesToPushAllTemporalUnitsWhenConfigured)1218 TEST(PickAndPlace,
1219 ForwardsNumUntrimmedSamplesToPushAllTemporalUnitsWhenConfigured) {
1220 const IASequenceHeaderObu kIaSequenceHeader(
1221 ObuHeader(), IASequenceHeaderObu::kIaCode,
1222 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1223 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1224 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1225 std::list<MixPresentationObu> mix_presentation_obus;
1226 std::list<AudioFrameWithData> audio_frames;
1227 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1228 const std::list<ArbitraryObu> kNoArbitraryObus;
1229 InitializeOneFrameIaSequenceWithMixPresentation(
1230 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1231 audio_frames.back().obu.header_.num_samples_to_trim_at_start = 8;
1232 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
1233 kFirstAudioElementId, kFirstSubstreamId, kSecondTimestamp,
1234 kThirdTimestamp, audio_elements, audio_frames);
1235 audio_frames.back().obu.header_.num_samples_to_trim_at_start = 3;
1236 // The first frame is fully trimmed. The second frame is partially trimmed.
1237 constexpr std::optional<int64_t> kExpectedFirstUntrimmedTimestamp = 11;
1238 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
1239 kDoNotIncludeTemporalDelimiters,
1240 kDelayDescriptorsUntilTrimAtStartIsKnown);
1241
1242 // The cumulative number of samples to trim at the start of the IA Sequence
1243 // for the initial audio frane(s).
1244 EXPECT_CALL(mock_obu_sequencer,
1245 PushSerializedDescriptorObus(
1246 _, _, _, kExpectedFirstUntrimmedTimestamp, _, _));
1247
1248 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1249 kIaSequenceHeader, codec_config_obus, audio_elements,
1250 mix_presentation_obus, audio_frames, kNoParameterBlocks,
1251 kNoArbitraryObus),
1252 IsOk());
1253 }
1254
TEST(PushDescriptorObus,ReturnsErrorWhenResamplingWouldBeRequired)1255 TEST(PushDescriptorObus, ReturnsErrorWhenResamplingWouldBeRequired) {
1256 const IASequenceHeaderObu kIaSequenceHeader(
1257 ObuHeader(), IASequenceHeaderObu::kIaCode,
1258 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1259 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1260 // Theoretically, a future profile may support multiple codec config OBUs with
1261 // different sample rates. The underlying code is written to only support IAMF
1262 // v1.1.0 profiles, which all only support a single codec config OBU.
1263 constexpr uint32_t kCodecConfigId = 1;
1264 constexpr uint32_t kSecondCodecConfigId = 2;
1265 constexpr uint32_t kSampleRate = 48000;
1266 constexpr uint32_t kSecondSampleRate = 44100;
1267 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
1268 codec_config_obus);
1269 AddLpcmCodecConfigWithIdAndSampleRate(kSecondCodecConfigId, kSecondSampleRate,
1270 codec_config_obus);
1271 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1272 const std::list<MixPresentationObu> kNoMixPresentationObus;
1273 const std::list<ArbitraryObu> kNoArbitraryObus;
1274 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
1275 kDoNotIncludeTemporalDelimiters,
1276 kDelayDescriptorsUntilTrimAtStartIsKnown);
1277
1278 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1279 kIaSequenceHeader, codec_config_obus, kNoAudioElements,
1280 kNoMixPresentationObus, kNoArbitraryObus),
1281 Not(IsOk()));
1282 }
1283
TEST(PickAndPlace,ReturnsErrorWhenResamplingWouldBeRequired)1284 TEST(PickAndPlace, ReturnsErrorWhenResamplingWouldBeRequired) {
1285 const IASequenceHeaderObu kIaSequenceHeader(
1286 ObuHeader(), IASequenceHeaderObu::kIaCode,
1287 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1288 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1289 // Theoretically, a future profile may support multiple codec config OBUs with
1290 // different sample rates. The underlying code is written to only support IAMF
1291 // v1.1.0 profiles, which all only support a single codec config OBU.
1292 constexpr uint32_t kCodecConfigId = 1;
1293 constexpr uint32_t kSecondCodecConfigId = 2;
1294 constexpr uint32_t kSampleRate = 48000;
1295 constexpr uint32_t kSecondSampleRate = 44100;
1296 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
1297 codec_config_obus);
1298 AddLpcmCodecConfigWithIdAndSampleRate(kSecondCodecConfigId, kSecondSampleRate,
1299 codec_config_obus);
1300 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1301 const std::list<MixPresentationObu> kNoMixPresentationObus;
1302 const std::list<AudioFrameWithData> kNoAudioFrames;
1303 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1304 const std::list<ArbitraryObu> kNoArbitraryObus;
1305 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
1306 kDoNotIncludeTemporalDelimiters,
1307 kDelayDescriptorsUntilTrimAtStartIsKnown);
1308
1309 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1310 kIaSequenceHeader, codec_config_obus, kNoAudioElements,
1311 kNoMixPresentationObus, kNoAudioFrames, kNoParameterBlocks,
1312 kNoArbitraryObus),
1313 Not(IsOk()));
1314 }
1315
TEST(PushTemporalUnit,ReturnsErrorWhenSamplesAreTrimmedFromStartAfterFirstUntrimmedSample)1316 TEST(PushTemporalUnit,
1317 ReturnsErrorWhenSamplesAreTrimmedFromStartAfterFirstUntrimmedSample) {
1318 const IASequenceHeaderObu kIaSequenceHeader(
1319 ObuHeader(), IASequenceHeaderObu::kIaCode,
1320 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1321 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1322 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1323 std::list<MixPresentationObu> mix_presentation_obus;
1324 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1325 const std::list<ArbitraryObu> kNoArbitraryObus;
1326 std::list<AudioFrameWithData> first_audio_frame;
1327 InitializeOneFrameIaSequenceWithMixPresentation(
1328 codec_config_obus, audio_elements, mix_presentation_obus,
1329 first_audio_frame);
1330 first_audio_frame.back().obu.header_.num_samples_to_trim_at_start = 0;
1331 const auto first_temporal_unit = TemporalUnitView::Create(
1332 kNoParameterBlocks, first_audio_frame, kNoArbitraryObus);
1333 ASSERT_THAT(first_temporal_unit, IsOk());
1334 // Corrupt the data by adding a second frame with samples trimmed from the
1335 // start, after the first frame had no trimmed samples.
1336 std::list<AudioFrameWithData> second_audio_frame;
1337 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
1338 kFirstAudioElementId, kFirstSubstreamId, kSecondTimestamp,
1339 kThirdTimestamp, audio_elements, second_audio_frame);
1340 second_audio_frame.back().obu.header_.num_samples_to_trim_at_start = 1;
1341 const auto second_temporal_unit = TemporalUnitView::Create(
1342 kNoParameterBlocks, second_audio_frame, kNoArbitraryObus);
1343 ASSERT_THAT(second_temporal_unit, IsOk());
1344 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
1345 kDoNotIncludeTemporalDelimiters,
1346 kDelayDescriptorsUntilTrimAtStartIsKnown);
1347 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1348 kIaSequenceHeader, codec_config_obus, audio_elements,
1349 mix_presentation_obus, kNoArbitraryObus),
1350 IsOk());
1351 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*first_temporal_unit),
1352 IsOk());
1353
1354 // The second temporal unit is corrupt, because it has samples trimmed from
1355 // the start after the first temporal unit had no trimmed samples.
1356 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*second_temporal_unit),
1357 Not(IsOk()));
1358 }
1359
TEST(PickAndPlace,ReturnsErrorWhenSamplesAreTrimmedFromStartAfterFirstUntrimmedSample)1360 TEST(PickAndPlace,
1361 ReturnsErrorWhenSamplesAreTrimmedFromStartAfterFirstUntrimmedSample) {
1362 const IASequenceHeaderObu kIaSequenceHeader(
1363 ObuHeader(), IASequenceHeaderObu::kIaCode,
1364 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1365 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1366 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1367 std::list<MixPresentationObu> mix_presentation_obus;
1368 std::list<AudioFrameWithData> audio_frames;
1369 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1370 const std::list<ArbitraryObu> kNoArbitraryObus;
1371 InitializeOneFrameIaSequenceWithMixPresentation(
1372 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1373 audio_frames.back().obu.header_.num_samples_to_trim_at_start = 0;
1374 // Corrupt the data by adding a second frame with samples trimmed from the
1375 // start, after the first frame had no trimmed samples.
1376 AddEmptyAudioFrameWithAudioElementIdSubstreamIdAndTimestamps(
1377 kFirstAudioElementId, kFirstSubstreamId, kSecondTimestamp,
1378 kThirdTimestamp, audio_elements, audio_frames);
1379 audio_frames.back().obu.header_.num_samples_to_trim_at_start = 1;
1380 MockObuSequencer mock_obu_sequencer(*LebGenerator::Create(),
1381 kDoNotIncludeTemporalDelimiters,
1382 kDelayDescriptorsUntilTrimAtStartIsKnown);
1383
1384 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1385 kIaSequenceHeader, codec_config_obus, audio_elements,
1386 mix_presentation_obus, audio_frames, kNoParameterBlocks,
1387 kNoArbitraryObus),
1388 Not(IsOk()));
1389 }
1390
TEST(PushTemporalUnit,ForwardsObusToPushSerializedTemporalUnit)1391 TEST(PushTemporalUnit, ForwardsObusToPushSerializedTemporalUnit) {
1392 const IASequenceHeaderObu kIaSequenceHeader(
1393 ObuHeader(), IASequenceHeaderObu::kIaCode,
1394 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1395 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1396 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1397 std::list<MixPresentationObu> mix_presentation_obus;
1398 std::list<AudioFrameWithData> audio_frames;
1399 DemixingParamDefinition param_definition =
1400 CreateDemixingParamDefinition(kFirstDemixingParameterId);
1401 std::list<ParameterBlockWithData> parameter_blocks;
1402 InitializeOneParameterBlockAndOneAudioFrame(
1403 param_definition, parameter_blocks, audio_frames, codec_config_obus,
1404 audio_elements);
1405 const std::list<ArbitraryObu> kNoArbitraryObus;
1406 const auto temporal_unit = TemporalUnitView::Create(
1407 parameter_blocks, audio_frames, kNoArbitraryObus);
1408 ASSERT_THAT(temporal_unit, IsOk());
1409 MockObuSequencer mock_obu_sequencer(
1410 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1411 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1412 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1413 kIaSequenceHeader, codec_config_obus, audio_elements,
1414 mix_presentation_obus, kNoArbitraryObus),
1415 IsOk());
1416
1417 // The spec prescribes an order among different types of OBUs.
1418 const std::vector<uint8_t> serialized_temporal_unit =
1419 SerializeObusExpectOk(std::list<const ObuBase*>{
1420 parameter_blocks.front().obu.get(), &audio_frames.front().obu});
1421 EXPECT_CALL(mock_obu_sequencer,
1422 PushSerializedTemporalUnit(
1423 _, _, MakeConstSpan(serialized_temporal_unit)));
1424
1425 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*temporal_unit), IsOk());
1426 }
1427
TEST(PickAndPlace,ForwardsObusToPushSerializedTemporalUnit)1428 TEST(PickAndPlace, ForwardsObusToPushSerializedTemporalUnit) {
1429 const IASequenceHeaderObu kIaSequenceHeader(
1430 ObuHeader(), IASequenceHeaderObu::kIaCode,
1431 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1432 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1433 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1434 std::list<MixPresentationObu> mix_presentation_obus;
1435 std::list<AudioFrameWithData> audio_frames;
1436 DemixingParamDefinition param_definition =
1437 CreateDemixingParamDefinition(kFirstDemixingParameterId);
1438 std::list<ParameterBlockWithData> parameter_blocks;
1439 InitializeOneParameterBlockAndOneAudioFrame(
1440 param_definition, parameter_blocks, audio_frames, codec_config_obus,
1441 audio_elements);
1442 const std::list<ArbitraryObu> kNoArbitraryObus;
1443 MockObuSequencer mock_obu_sequencer(
1444 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1445 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1446
1447 // The spec prescribes an order among different types of OBUs.
1448 const std::vector<uint8_t> serialized_temporal_unit =
1449 SerializeObusExpectOk(std::list<const ObuBase*>{
1450 parameter_blocks.front().obu.get(), &audio_frames.front().obu});
1451 EXPECT_CALL(mock_obu_sequencer,
1452 PushSerializedTemporalUnit(
1453 _, _, MakeConstSpan(serialized_temporal_unit)));
1454
1455 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1456 kIaSequenceHeader, codec_config_obus, audio_elements,
1457 mix_presentation_obus, audio_frames, parameter_blocks,
1458 kNoArbitraryObus),
1459 IsOk());
1460 }
1461
TEST(PushTemporalUnit,ForwardsArbitraryObusToPushSerializedTemporalUnit)1462 TEST(PushTemporalUnit, ForwardsArbitraryObusToPushSerializedTemporalUnit) {
1463 const IASequenceHeaderObu kIaSequenceHeader(
1464 ObuHeader(), IASequenceHeaderObu::kIaCode,
1465 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1466 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1467 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1468 std::list<MixPresentationObu> mix_presentation_obus;
1469 std::list<AudioFrameWithData> audio_frames;
1470 InitializeOneFrameIaSequenceWithMixPresentation(
1471 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1472 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1473 const std::list<ArbitraryObu> kArbitraryObuBeforeFirstAudioFrame(
1474 {ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
1475 ArbitraryObu::kInsertionHookAfterAudioFramesAtTick,
1476 kFirstTimestamp)});
1477 const auto first_temporal_unit = TemporalUnitView::Create(
1478 kNoParameterBlocks, audio_frames, kArbitraryObuBeforeFirstAudioFrame);
1479 ASSERT_THAT(first_temporal_unit, IsOk());
1480 MockObuSequencer mock_obu_sequencer(
1481 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1482 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1483 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1484 kIaSequenceHeader, codec_config_obus, audio_elements,
1485 mix_presentation_obus, kArbitraryObuBeforeFirstAudioFrame),
1486 IsOk());
1487
1488 // Custom arbitrary OBUs can be placed according to their hook.
1489 const std::vector<uint8_t> serialized_audio_frame = SerializeObusExpectOk(
1490 std::list<const ObuBase*>{&audio_frames.front().obu,
1491 &kArbitraryObuBeforeFirstAudioFrame.front()});
1492 EXPECT_CALL(
1493 mock_obu_sequencer,
1494 PushSerializedTemporalUnit(_, _, MakeConstSpan(serialized_audio_frame)));
1495
1496 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*first_temporal_unit),
1497 IsOk());
1498 }
1499
TEST(PickAndPlace,ForwardsArbitraryObusToPushSerializedTemporalUnit)1500 TEST(PickAndPlace, ForwardsArbitraryObusToPushSerializedTemporalUnit) {
1501 const IASequenceHeaderObu kIaSequenceHeader(
1502 ObuHeader(), IASequenceHeaderObu::kIaCode,
1503 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1504 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1505 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1506 std::list<MixPresentationObu> mix_presentation_obus;
1507 std::list<AudioFrameWithData> audio_frames;
1508 InitializeOneFrameIaSequenceWithMixPresentation(
1509 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1510 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1511 const std::list<ArbitraryObu> kArbitraryObuBeforeFirstAudioFrame(
1512 {ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
1513 ArbitraryObu::kInsertionHookAfterAudioFramesAtTick,
1514 kFirstTimestamp)});
1515 MockObuSequencer mock_obu_sequencer(
1516 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1517 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1518
1519 // Custom arbitrary OBUs can be placed according to their hook.
1520 const std::vector<uint8_t> serialized_audio_frame = SerializeObusExpectOk(
1521 std::list<const ObuBase*>{&audio_frames.front().obu,
1522 &kArbitraryObuBeforeFirstAudioFrame.front()});
1523 EXPECT_CALL(
1524 mock_obu_sequencer,
1525 PushSerializedTemporalUnit(_, _, MakeConstSpan(serialized_audio_frame)));
1526
1527 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1528 kIaSequenceHeader, codec_config_obus, audio_elements,
1529 mix_presentation_obus, audio_frames, kNoParameterBlocks,
1530 kArbitraryObuBeforeFirstAudioFrame),
1531 IsOk());
1532 }
1533
TEST(Close,CallsCloseDerived)1534 TEST(Close, CallsCloseDerived) {
1535 MockObuSequencer mock_obu_sequencer(
1536 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1537 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1538
1539 // `CloseDerived` is called when done, which allows concrete implementation to
1540 // finalize and optionally close their output streams.
1541 EXPECT_CALL(mock_obu_sequencer, CloseDerived());
1542
1543 EXPECT_THAT(mock_obu_sequencer.Close(), IsOk());
1544 }
1545
TEST(Close,FailsWhenCalledTwice)1546 TEST(Close, FailsWhenCalledTwice) {
1547 MockObuSequencer mock_obu_sequencer(
1548 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1549 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1550 EXPECT_THAT(mock_obu_sequencer.Close(), IsOk());
1551
1552 EXPECT_THAT(mock_obu_sequencer.Close(), Not(IsOk()));
1553 }
1554
TEST(PickAndPlace,CallsCloseDerivedWhenDone)1555 TEST(PickAndPlace, CallsCloseDerivedWhenDone) {
1556 const IASequenceHeaderObu kIaSequenceHeader(
1557 ObuHeader(), IASequenceHeaderObu::kIaCode,
1558 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1559 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1560 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1561 const std::list<MixPresentationObu> kNoMixPresentationObus;
1562 const std::list<AudioFrameWithData> kNoAudioFrames;
1563 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1564 const std::list<ArbitraryObu> kArbitraryObuAfterIaSequenceHeader(
1565 {ArbitraryObu(kObuIaReserved25, ObuHeader(), {},
1566 ArbitraryObu::kInsertionHookAfterIaSequenceHeader)});
1567 MockObuSequencer mock_obu_sequencer(
1568 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1569 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1570
1571 // `CloseDerived` is called when done, which allows concrete implementation to
1572 // finalize and optionally close their output streams.
1573 EXPECT_CALL(mock_obu_sequencer, CloseDerived());
1574
1575 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1576 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
1577 kNoMixPresentationObus, kNoAudioFrames, kNoParameterBlocks,
1578 kArbitraryObuAfterIaSequenceHeader),
1579 IsOk());
1580 }
1581
TEST(Abort,CallsAbortDerived)1582 TEST(Abort, CallsAbortDerived) {
1583 MockObuSequencer mock_obu_sequencer(
1584 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1585 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1586
1587 // `CloseDerived` is called when done, which allows concrete implementation to
1588 // finalize and optionally close their output streams.
1589 EXPECT_CALL(mock_obu_sequencer, AbortDerived());
1590
1591 mock_obu_sequencer.Abort();
1592 }
1593
TEST(PushDescriptorObus,CallsAbortDerivedWhenPushDescriptorObusFails)1594 TEST(PushDescriptorObus, CallsAbortDerivedWhenPushDescriptorObusFails) {
1595 const IASequenceHeaderObu kIaSequenceHeader(
1596 ObuHeader(), IASequenceHeaderObu::kIaCode,
1597 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1598 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1599 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1600 std::list<MixPresentationObu> mix_presentation_obus;
1601 InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(
1602 codec_config_obus, audio_elements, mix_presentation_obus);
1603 const std::list<ArbitraryObu> kNoArbitraryObus;
1604 MockObuSequencer mock_obu_sequencer(
1605 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1606 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1607
1608 // If `PushSerializedDescriptorObus` fails, `Abort` is called. This allows
1609 // concrete implementation to clean up and remove the file in one place.
1610 EXPECT_CALL(mock_obu_sequencer,
1611 PushSerializedDescriptorObus(_, _, _, _, _, _))
1612 .WillOnce(Return(absl::InternalError("")));
1613 EXPECT_CALL(mock_obu_sequencer, AbortDerived()).Times(1);
1614
1615 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1616 kIaSequenceHeader, codec_config_obus, audio_elements,
1617 mix_presentation_obus, kNoArbitraryObus),
1618 Not(IsOk()));
1619 }
1620
TEST(PickAndPlace,CallsAbortDerivedWhenPushDescriptorObusFails)1621 TEST(PickAndPlace, CallsAbortDerivedWhenPushDescriptorObusFails) {
1622 const IASequenceHeaderObu kIaSequenceHeader(
1623 ObuHeader(), IASequenceHeaderObu::kIaCode,
1624 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1625 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1626 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1627 std::list<MixPresentationObu> mix_presentation_obus;
1628 InitializeDescriptorObusForTwoMonoAmbisonicsAudioElement(
1629 codec_config_obus, audio_elements, mix_presentation_obus);
1630 const std::list<AudioFrameWithData> kNoAudioFrames;
1631 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1632 const std::list<ArbitraryObu> kNoArbitraryObus;
1633 MockObuSequencer mock_obu_sequencer(
1634 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1635 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1636
1637 // If `PushSerializedDescriptorObus` fails, `Abort` is called. This allows
1638 // concrete implementation to clean up and remove the file in one place.
1639 EXPECT_CALL(mock_obu_sequencer,
1640 PushSerializedDescriptorObus(_, _, _, _, _, _))
1641 .WillOnce(Return(absl::InternalError("")));
1642 EXPECT_CALL(mock_obu_sequencer, AbortDerived()).Times(1);
1643
1644 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1645 kIaSequenceHeader, codec_config_obus, audio_elements,
1646 mix_presentation_obus, kNoAudioFrames, kNoParameterBlocks,
1647 kNoArbitraryObus),
1648 Not(IsOk()));
1649 }
1650
TEST(PushTemporalUnit,CallsAbortDerivedWhenPushAllTemporalUnitsFails)1651 TEST(PushTemporalUnit, CallsAbortDerivedWhenPushAllTemporalUnitsFails) {
1652 const IASequenceHeaderObu kIaSequenceHeader(
1653 ObuHeader(), IASequenceHeaderObu::kIaCode,
1654 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1655 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1656 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1657 std::list<MixPresentationObu> mix_presentation_obus;
1658 std::list<AudioFrameWithData> audio_frames;
1659 InitializeOneFrameIaSequenceWithMixPresentation(
1660 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1661 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1662 const std::list<ArbitraryObu> kNoArbitraryObus;
1663 const auto temporal_unit = TemporalUnitView::Create(
1664 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
1665 ASSERT_THAT(temporal_unit, IsOk());
1666 MockObuSequencer mock_obu_sequencer(
1667 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1668 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1669 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1670 kIaSequenceHeader, codec_config_obus, audio_elements,
1671 mix_presentation_obus, kNoArbitraryObus),
1672 IsOk());
1673
1674 // If `PushSerializedTemporalUnit` fails, `AbortDerived` is called. This
1675 // allows concrete implementation to clean up and remove the file in one
1676 // place.
1677 EXPECT_CALL(mock_obu_sequencer, PushSerializedTemporalUnit(_, _, _))
1678 .WillOnce(Return(absl::InternalError("")));
1679 EXPECT_CALL(mock_obu_sequencer, AbortDerived()).Times(1);
1680
1681 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*temporal_unit), Not(IsOk()));
1682 }
1683
TEST(PickAndPlace,CallsAbortDerivedWhenPushAllTemporalUnitsFails)1684 TEST(PickAndPlace, CallsAbortDerivedWhenPushAllTemporalUnitsFails) {
1685 const IASequenceHeaderObu kIaSequenceHeader(
1686 ObuHeader(), IASequenceHeaderObu::kIaCode,
1687 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1688 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1689 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1690 std::list<MixPresentationObu> mix_presentation_obus;
1691 std::list<AudioFrameWithData> audio_frames;
1692 InitializeOneFrameIaSequenceWithMixPresentation(
1693 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1694 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1695 const std::list<ArbitraryObu> kNoArbitraryObus;
1696 MockObuSequencer mock_obu_sequencer(
1697 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1698 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1699
1700 // If `PushSerializedTemporalUnit` fails, `AbortDerived` is called. This
1701 // allows concrete implementation to clean up and remove the file in one
1702 // place.
1703 EXPECT_CALL(mock_obu_sequencer, PushSerializedTemporalUnit(_, _, _))
1704 .WillOnce(Return(absl::InternalError("")));
1705 EXPECT_CALL(mock_obu_sequencer, AbortDerived()).Times(1);
1706
1707 EXPECT_THAT(mock_obu_sequencer.PickAndPlace(
1708 kIaSequenceHeader, codec_config_obus, audio_elements,
1709 mix_presentation_obus, audio_frames, kNoParameterBlocks,
1710 kNoArbitraryObus),
1711 Not(IsOk()));
1712 }
1713
TEST(PushTemporalUnit,FailsWhenBeforePushDescriptorObus)1714 TEST(PushTemporalUnit, FailsWhenBeforePushDescriptorObus) {
1715 const IASequenceHeaderObu kIaSequenceHeader(
1716 ObuHeader(), IASequenceHeaderObu::kIaCode,
1717 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1718 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1719 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1720 std::list<MixPresentationObu> mix_presentation_obus;
1721 std::list<AudioFrameWithData> audio_frames;
1722 InitializeOneFrameIaSequenceWithMixPresentation(
1723 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1724 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1725 const std::list<ArbitraryObu> kNoArbitraryObus;
1726 const auto temporal_unit = TemporalUnitView::Create(
1727 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
1728 ASSERT_THAT(temporal_unit, IsOk());
1729 MockObuSequencer mock_obu_sequencer(
1730 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1731 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1732 // Omitted call to `PushDescriptorObus`. We can't accept temporal units yet.
1733
1734 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*temporal_unit), Not(IsOk()));
1735 }
1736
TEST(PushTemporalUnit,FailsWhenCalledAfterClose)1737 TEST(PushTemporalUnit, FailsWhenCalledAfterClose) {
1738 const IASequenceHeaderObu kIaSequenceHeader(
1739 ObuHeader(), IASequenceHeaderObu::kIaCode,
1740 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1741 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1742 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1743 std::list<MixPresentationObu> mix_presentation_obus;
1744 std::list<AudioFrameWithData> audio_frames;
1745 InitializeOneFrameIaSequenceWithMixPresentation(
1746 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1747 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1748 const std::list<ArbitraryObu> kNoArbitraryObus;
1749 const auto temporal_unit = TemporalUnitView::Create(
1750 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
1751 ASSERT_THAT(temporal_unit, IsOk());
1752 MockObuSequencer mock_obu_sequencer(
1753 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1754 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1755 EXPECT_THAT(mock_obu_sequencer.Close(), IsOk());
1756
1757 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*temporal_unit), Not(IsOk()));
1758 }
1759
TEST(PushTemporalUnit,FailsWhenCalledAfterAbort)1760 TEST(PushTemporalUnit, FailsWhenCalledAfterAbort) {
1761 const IASequenceHeaderObu kIaSequenceHeader(
1762 ObuHeader(), IASequenceHeaderObu::kIaCode,
1763 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1764 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1765 absl::flat_hash_map<uint32_t, AudioElementWithData> audio_elements;
1766 std::list<MixPresentationObu> mix_presentation_obus;
1767 std::list<AudioFrameWithData> audio_frames;
1768 InitializeOneFrameIaSequenceWithMixPresentation(
1769 codec_config_obus, audio_elements, mix_presentation_obus, audio_frames);
1770 const std::list<ParameterBlockWithData> kNoParameterBlocks;
1771 const std::list<ArbitraryObu> kNoArbitraryObus;
1772 const auto temporal_unit = TemporalUnitView::Create(
1773 kNoParameterBlocks, audio_frames, kNoArbitraryObus);
1774 ASSERT_THAT(temporal_unit, IsOk());
1775 MockObuSequencer mock_obu_sequencer(
1776 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1777 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1778 mock_obu_sequencer.Abort();
1779
1780 EXPECT_THAT(mock_obu_sequencer.PushTemporalUnit(*temporal_unit), Not(IsOk()));
1781 }
1782
TEST(UpdateDescriptorObusAndClose,ForwardsDescriptorObusToPushFinalizedDescriptorObus)1783 TEST(UpdateDescriptorObusAndClose,
1784 ForwardsDescriptorObusToPushFinalizedDescriptorObus) {
1785 const IASequenceHeaderObu kOriginalIaSequenceHeader(
1786 ObuHeader(), IASequenceHeaderObu::kIaCode,
1787 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1788 const IASequenceHeaderObu kUpdatedIaSequenceHeader(
1789 ObuHeader(), IASequenceHeaderObu::kIaCode,
1790 ProfileVersion::kIamfBaseProfile, ProfileVersion::kIamfBaseProfile);
1791 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1792 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1793 const std::list<MixPresentationObu> kNoMixPresentationObus;
1794 const std::list<ArbitraryObu> kNoArbitraryObus;
1795 MockObuSequencer mock_obu_sequencer(
1796 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1797 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1798 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1799 kOriginalIaSequenceHeader, kNoCodecConfigObus,
1800 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1801 IsOk());
1802 const auto expected_finalized_descriptor_obus = SerializeObusExpectOk(
1803 std::list<const ObuBase*>{&kUpdatedIaSequenceHeader});
1804
1805 // Several properties should match values derived from the descriptor
1806 // OBUs.
1807 EXPECT_CALL(mock_obu_sequencer, PushFinalizedDescriptorObus(MakeConstSpan(
1808 expected_finalized_descriptor_obus)));
1809
1810 EXPECT_THAT(mock_obu_sequencer.UpdateDescriptorObusAndClose(
1811 kUpdatedIaSequenceHeader, kNoCodecConfigObus,
1812 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1813 IsOk());
1814 }
1815
TEST(UpdateDescriptorObusAndClose,FailsBeforePushDescriptorObus)1816 TEST(UpdateDescriptorObusAndClose, FailsBeforePushDescriptorObus) {
1817 const IASequenceHeaderObu kIaSequenceHeader(
1818 ObuHeader(), IASequenceHeaderObu::kIaCode,
1819 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1820 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1821 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1822 const std::list<MixPresentationObu> kNoMixPresentationObus;
1823 const std::list<ArbitraryObu> kNoArbitraryObus;
1824 MockObuSequencer mock_obu_sequencer(
1825 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1826 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1827
1828 EXPECT_THAT(mock_obu_sequencer.UpdateDescriptorObusAndClose(
1829 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
1830 kNoMixPresentationObus, kNoArbitraryObus),
1831 Not(IsOk()));
1832 }
1833
TEST(UpdateDescriptorObusAndClose,SubsequentCloseCallsFails)1834 TEST(UpdateDescriptorObusAndClose, SubsequentCloseCallsFails) {
1835 const IASequenceHeaderObu kIaSequenceHeader(
1836 ObuHeader(), IASequenceHeaderObu::kIaCode,
1837 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1838 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1839 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1840 const std::list<MixPresentationObu> kNoMixPresentationObus;
1841 const std::list<ArbitraryObu> kNoArbitraryObus;
1842 MockObuSequencer mock_obu_sequencer(
1843 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1844 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1845 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1846 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
1847 kNoMixPresentationObus, kNoArbitraryObus),
1848 IsOk());
1849 EXPECT_THAT(mock_obu_sequencer.UpdateDescriptorObusAndClose(
1850 kIaSequenceHeader, kNoCodecConfigObus, kNoAudioElements,
1851 kNoMixPresentationObus, kNoArbitraryObus),
1852 IsOk());
1853
1854 EXPECT_THAT(mock_obu_sequencer.Close(), Not(IsOk()));
1855 }
1856
TEST(UpdateDescriptorObusAndClose,CallsCloseDerived)1857 TEST(UpdateDescriptorObusAndClose, CallsCloseDerived) {
1858 const IASequenceHeaderObu kOriginalIaSequenceHeader(
1859 ObuHeader(), IASequenceHeaderObu::kIaCode,
1860 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1861 const IASequenceHeaderObu kUpdatedIaSequenceHeader(
1862 ObuHeader(), IASequenceHeaderObu::kIaCode,
1863 ProfileVersion::kIamfBaseProfile, ProfileVersion::kIamfBaseProfile);
1864 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1865 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1866 const std::list<MixPresentationObu> kNoMixPresentationObus;
1867 const std::list<ArbitraryObu> kNoArbitraryObus;
1868 MockObuSequencer mock_obu_sequencer(
1869 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1870 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1871 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1872 kOriginalIaSequenceHeader, kNoCodecConfigObus,
1873 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1874 IsOk());
1875 EXPECT_CALL(mock_obu_sequencer, CloseDerived()).Times(1);
1876
1877 EXPECT_THAT(mock_obu_sequencer.UpdateDescriptorObusAndClose(
1878 kUpdatedIaSequenceHeader, kNoCodecConfigObus,
1879 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1880 IsOk());
1881 }
1882
TEST(UpdateDescriptorObusAndClose,CallsAbortDerivedWhenPushFinalizedDescriptorObusFails)1883 TEST(UpdateDescriptorObusAndClose,
1884 CallsAbortDerivedWhenPushFinalizedDescriptorObusFails) {
1885 const IASequenceHeaderObu kOriginalIaSequenceHeader(
1886 ObuHeader(), IASequenceHeaderObu::kIaCode,
1887 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1888 const IASequenceHeaderObu kUpdatedIaSequenceHeader(
1889 ObuHeader(), IASequenceHeaderObu::kIaCode,
1890 ProfileVersion::kIamfBaseProfile, ProfileVersion::kIamfBaseProfile);
1891 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1892 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1893 const std::list<MixPresentationObu> kNoMixPresentationObus;
1894 const std::list<ArbitraryObu> kNoArbitraryObus;
1895 MockObuSequencer mock_obu_sequencer(
1896 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1897 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1898 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1899 kOriginalIaSequenceHeader, kNoCodecConfigObus,
1900 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1901 IsOk());
1902 ON_CALL(mock_obu_sequencer, PushFinalizedDescriptorObus(_))
1903 .WillByDefault(Return(absl::InternalError("")));
1904 EXPECT_CALL(mock_obu_sequencer, AbortDerived()).Times(1);
1905
1906 EXPECT_THAT(mock_obu_sequencer.UpdateDescriptorObusAndClose(
1907 kUpdatedIaSequenceHeader, kNoCodecConfigObus,
1908 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1909 Not(IsOk()));
1910 }
1911
TEST(UpdateDescriptorObusAndClose,FailsWhenSerializedSizeChanges)1912 TEST(UpdateDescriptorObusAndClose, FailsWhenSerializedSizeChanges) {
1913 const IASequenceHeaderObu kOriginalIaSequenceHeader(
1914 ObuHeader(), IASequenceHeaderObu::kIaCode,
1915 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1916 const IASequenceHeaderObu kResizedIaSequenceHeader(
1917 ObuHeader{.obu_extension_flag = true, .extension_header_size = 0},
1918 IASequenceHeaderObu::kIaCode, ProfileVersion::kIamfBaseProfile,
1919 ProfileVersion::kIamfBaseProfile);
1920 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigObus;
1921 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1922 const std::list<MixPresentationObu> kNoMixPresentationObus;
1923 const std::list<ArbitraryObu> kNoArbitraryObus;
1924 MockObuSequencer mock_obu_sequencer(
1925 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1926 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1927 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1928 kOriginalIaSequenceHeader, kNoCodecConfigObus,
1929 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1930 IsOk());
1931
1932 // Derived classes may assume the descriptor OBUs are the same size, to
1933 // permit writes in place. We could lift this restriction, but it's not
1934 // clear it's worth the effort.
1935 EXPECT_THAT(mock_obu_sequencer.UpdateDescriptorObusAndClose(
1936 kResizedIaSequenceHeader, kNoCodecConfigObus,
1937 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1938 Not(IsOk()));
1939 }
1940
TEST(UpdateDescriptorObusAndClose,FailsWhenCodecConfigPropertiesChange)1941 TEST(UpdateDescriptorObusAndClose, FailsWhenCodecConfigPropertiesChange) {
1942 const IASequenceHeaderObu kIaSequenceHeader(
1943 ObuHeader(), IASequenceHeaderObu::kIaCode,
1944 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1945 absl::flat_hash_map<DecodedUleb128, CodecConfigObu>
1946 original_codec_config_obus;
1947 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, 48000,
1948 original_codec_config_obus);
1949 absl::flat_hash_map<DecodedUleb128, CodecConfigObu>
1950 modified_codec_config_obus;
1951 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, 44100,
1952 modified_codec_config_obus);
1953 const absl::flat_hash_map<uint32_t, AudioElementWithData> kNoAudioElements;
1954 const std::list<MixPresentationObu> kNoMixPresentationObus;
1955 const std::list<ArbitraryObu> kNoArbitraryObus;
1956 MockObuSequencer mock_obu_sequencer(
1957 *LebGenerator::Create(), kDoNotIncludeTemporalDelimiters,
1958 kDoNotDelayDescriptorsUntilTrimAtStartIsKnown);
1959 EXPECT_THAT(mock_obu_sequencer.PushDescriptorObus(
1960 kIaSequenceHeader, original_codec_config_obus,
1961 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1962 IsOk());
1963
1964 EXPECT_THAT(mock_obu_sequencer.UpdateDescriptorObusAndClose(
1965 kIaSequenceHeader, modified_codec_config_obus,
1966 kNoAudioElements, kNoMixPresentationObus, kNoArbitraryObus),
1967 Not(IsOk()));
1968 }
1969
1970 } // namespace
1971 } // namespace iamf_tools
1972