1 /*
2 * Copyright (c) 2024, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12
13 #include "iamf/cli/obu_processor.h"
14
15 #include <array>
16 #include <cstddef>
17 #include <cstdint>
18 #include <filesystem>
19 #include <iterator>
20 #include <list>
21 #include <memory>
22 #include <optional>
23 #include <string>
24 #include <system_error>
25 #include <utility>
26 #include <vector>
27
28 #include "absl/container/flat_hash_map.h"
29 #include "absl/status/status_matchers.h"
30 #include "absl/strings/string_view.h"
31 #include "absl/types/span.h"
32 #include "gmock/gmock.h"
33 #include "gtest/gtest.h"
34 #include "iamf/cli/audio_element_with_data.h"
35 #include "iamf/cli/audio_frame_with_data.h"
36 #include "iamf/cli/global_timing_module.h"
37 #include "iamf/cli/parameter_block_with_data.h"
38 #include "iamf/cli/parameters_manager.h"
39 #include "iamf/cli/rendering_mix_presentation_finalizer.h"
40 #include "iamf/cli/sample_processor_base.h"
41 #include "iamf/cli/tests/cli_test_utils.h"
42 #include "iamf/cli/user_metadata_builder/iamf_input_layout.h"
43 #include "iamf/cli/wav_reader.h"
44 #include "iamf/cli/wav_writer.h"
45 #include "iamf/common/read_bit_buffer.h"
46 #include "iamf/obu/arbitrary_obu.h"
47 #include "iamf/obu/audio_frame.h"
48 #include "iamf/obu/codec_config.h"
49 #include "iamf/obu/ia_sequence_header.h"
50 #include "iamf/obu/mix_gain_parameter_data.h"
51 #include "iamf/obu/mix_presentation.h"
52 #include "iamf/obu/obu_base.h"
53 #include "iamf/obu/obu_header.h"
54 #include "iamf/obu/param_definition_variant.h"
55 #include "iamf/obu/param_definitions.h"
56 #include "iamf/obu/parameter_block.h"
57 #include "iamf/obu/temporal_delimiter.h"
58 #include "iamf/obu/types.h"
59
60 namespace iamf_tools {
61 namespace {
62
63 using ::absl_testing::IsOk;
64 using ::absl_testing::IsOkAndHolds;
65 using ::testing::IsNull;
66 using ::testing::Not;
67 using ::testing::NotNull;
68
69 constexpr DecodedUleb128 kFirstCodecConfigId = 1;
70 constexpr DecodedUleb128 kSecondCodecConfigId = 2;
71 constexpr DecodedUleb128 kFirstAudioElementId = 2;
72 constexpr DecodedUleb128 kSecondAudioElementId = 3;
73 constexpr DecodedUleb128 kThirdAudioElementId = 4;
74 constexpr DecodedUleb128 kFirstSubstreamId = 18;
75 constexpr DecodedUleb128 kSecondSubstreamId = 19;
76 constexpr DecodedUleb128 kThirdSubstreamId = 20;
77 constexpr DecodedUleb128 kFourthSubstreamId = 21;
78 constexpr DecodedUleb128 kFirstMixPresentationId = 3;
79 constexpr DecodedUleb128 kSecondMixPresentationId = 4;
80 constexpr DecodedUleb128 kThirdMixPresentationId = 5;
81 constexpr DecodedUleb128 kCommonMixGainParameterId = 999;
82 constexpr uint32_t kFrameSize = 1024;
83 constexpr uint32_t kBitDepth = 16;
84 constexpr DecodedUleb128 kSampleRate = 48000;
85 constexpr DecodedUleb128 kCommonParameterRate = kSampleRate;
86
87 constexpr DecodedUleb128 kImplicitSubstreamId = 0;
88
89 constexpr int kObuTypeBitShift = 3;
90 constexpr int64_t kBufferCapacity = 1024;
91
92 constexpr std::optional<uint8_t> kNoOutputFileBitDepthOverride = std::nullopt;
93 constexpr std::array<uint8_t, 16> kArbitraryAudioFrame = {
94 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
95
AddSequenceHeaderAndSerializeObusExpectOk(const std::list<const ObuBase * > & input_ia_sequence_without_header)96 std::vector<uint8_t> AddSequenceHeaderAndSerializeObusExpectOk(
97 const std::list<const ObuBase*>& input_ia_sequence_without_header) {
98 const IASequenceHeaderObu ia_sequence_header(
99 ObuHeader(), IASequenceHeaderObu::kIaCode,
100 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
101 std::list<const ObuBase*> input_ia_sequence(input_ia_sequence_without_header);
102 input_ia_sequence.push_front(&ia_sequence_header);
103 return SerializeObusExpectOk(input_ia_sequence);
104 }
105
CreateAllWavWriters(const std::string output_filename_string,bool write_wav_header)106 auto CreateAllWavWriters(const std::string output_filename_string,
107 bool write_wav_header) {
108 return [output_filename_string, write_wav_header](
109 DecodedUleb128 /*mix_presentation_id*/, int /*sub_mix_index*/,
110 int /*layout_index*/, const Layout& /*layout*/, int num_channels,
111 int sample_rate, int bit_depth, size_t max_input_samples_per_frame)
112 -> std::unique_ptr<SampleProcessorBase> {
113 return WavWriter::Create(output_filename_string, num_channels, sample_rate,
114 bit_depth, max_input_samples_per_frame,
115 write_wav_header);
116 };
117 }
118
TEST(ProcessDescriptorObus,FailsWithEmptyBitstream)119 TEST(ProcessDescriptorObus, FailsWithEmptyBitstream) {
120 const std::vector<uint8_t> bitstream_without_ia_sequence_header =
121 SerializeObusExpectOk({});
122 IASequenceHeaderObu ia_sequence_header;
123 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obu;
124 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
125 audio_elements_with_data;
126 std::list<MixPresentationObu> mix_presentation_obus;
127
128 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
129 kBufferCapacity,
130 absl::MakeConstSpan(bitstream_without_ia_sequence_header));
131 bool insufficient_data;
132 EXPECT_FALSE(ObuProcessor::ProcessDescriptorObus(
133 /*is_exhaustive_and_exact=*/false, *read_bit_buffer,
134 ia_sequence_header, codec_config_obu,
135 audio_elements_with_data, mix_presentation_obus,
136 insufficient_data)
137 .ok());
138 // There's no data (and `is_exhaustive_and_exact` is false), so we need more
139 // data to proceed.
140 EXPECT_TRUE(insufficient_data);
141 }
142
TEST(ProcessDescriptorObus,CollectsCodecConfigsBeforeATemporalUnit)143 TEST(ProcessDescriptorObus, CollectsCodecConfigsBeforeATemporalUnit) {
144 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> input_codec_configs;
145 AddOpusCodecConfigWithId(kFirstCodecConfigId, input_codec_configs);
146 AddOpusCodecConfigWithId(kSecondCodecConfigId, input_codec_configs);
147 AudioFrameObu input_audio_frame(
148 ObuHeader(), kFirstSubstreamId, /*audio_frame=*/
149 {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16});
150 const auto two_codec_configs_and_audio_frame =
151 AddSequenceHeaderAndSerializeObusExpectOk(
152 {&input_codec_configs.at(kFirstCodecConfigId),
153 &input_codec_configs.at(kSecondCodecConfigId), &input_audio_frame});
154 IASequenceHeaderObu unused_ia_sequence_header;
155 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> output_codec_config_obus;
156 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
157 audio_elements_with_data;
158 std::list<MixPresentationObu> mix_presentation_obus;
159
160 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
161 kBufferCapacity, absl::MakeConstSpan(two_codec_configs_and_audio_frame));
162 bool insufficient_data;
163 EXPECT_THAT(
164 ObuProcessor::ProcessDescriptorObus(
165 /*is_exhaustive_and_exact=*/false, *read_bit_buffer,
166 unused_ia_sequence_header, output_codec_config_obus,
167 audio_elements_with_data, mix_presentation_obus, insufficient_data),
168 IsOk());
169
170 EXPECT_EQ(output_codec_config_obus.size(), 2);
171 EXPECT_TRUE(output_codec_config_obus.contains(kFirstCodecConfigId));
172 EXPECT_TRUE(output_codec_config_obus.contains(kSecondCodecConfigId));
173 // `insufficient_data` is false because we have successfully read all provided
174 // descriptor obus AND `is_exhaustive_and_exact` is true, meaning that the
175 // caller has indicated that there are no future Descriptor OBUs coming.
176 EXPECT_FALSE(insufficient_data);
177 }
178
TEST(ProcessDescriptorObus,CollectsCodecConfigsAtEndOfBitstream)179 TEST(ProcessDescriptorObus, CollectsCodecConfigsAtEndOfBitstream) {
180 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> input_codec_configs;
181 AddOpusCodecConfigWithId(kFirstCodecConfigId, input_codec_configs);
182 AddOpusCodecConfigWithId(kSecondCodecConfigId, input_codec_configs);
183 const auto two_codec_configs_at_end_of_bitstream =
184 AddSequenceHeaderAndSerializeObusExpectOk(
185 {&input_codec_configs.at(kFirstCodecConfigId),
186 &input_codec_configs.at(kSecondCodecConfigId)});
187 IASequenceHeaderObu ia_sequence_header;
188 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
189 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
190 audio_elements_with_data;
191 std::list<MixPresentationObu> mix_presentation_obus;
192
193 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
194 kBufferCapacity,
195 absl::MakeConstSpan(two_codec_configs_at_end_of_bitstream));
196 bool insufficient_data;
197 EXPECT_THAT(
198 ObuProcessor::ProcessDescriptorObus(
199 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
200 ia_sequence_header, codec_config_obus, audio_elements_with_data,
201 mix_presentation_obus, insufficient_data),
202 IsOk());
203 // `is_exhaustive_and_exact` is true so it could not be a more-data situation.
204 EXPECT_FALSE(insufficient_data);
205
206 EXPECT_EQ(codec_config_obus.size(), 2);
207 EXPECT_TRUE(codec_config_obus.contains(kFirstCodecConfigId));
208 EXPECT_TRUE(codec_config_obus.contains(kSecondCodecConfigId));
209 }
210
TEST(ProcessDescriptorObus,DoesNotCollectCodecConfigsAtEndOfBitstreamWithoutIsExhaustiveAndExact)211 TEST(ProcessDescriptorObus,
212 DoesNotCollectCodecConfigsAtEndOfBitstreamWithoutIsExhaustiveAndExact) {
213 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> input_codec_configs;
214 AddOpusCodecConfigWithId(kFirstCodecConfigId, input_codec_configs);
215 AddOpusCodecConfigWithId(kSecondCodecConfigId, input_codec_configs);
216 const auto two_codec_configs_at_end_of_bitstream =
217 AddSequenceHeaderAndSerializeObusExpectOk(
218 {&input_codec_configs.at(kFirstCodecConfigId),
219 &input_codec_configs.at(kSecondCodecConfigId)});
220 IASequenceHeaderObu ia_sequence_header;
221 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
222 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
223 audio_elements_with_data;
224 std::list<MixPresentationObu> mix_presentation_obus;
225
226 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
227 kBufferCapacity,
228 absl::MakeConstSpan(two_codec_configs_at_end_of_bitstream));
229 auto start_position = read_bit_buffer->Tell();
230 bool insufficient_data;
231 EXPECT_THAT(
232 ObuProcessor::ProcessDescriptorObus(
233 /*is_exhaustive_and_exact=*/false, *read_bit_buffer,
234 ia_sequence_header, codec_config_obus, audio_elements_with_data,
235 mix_presentation_obus, insufficient_data),
236 Not(IsOk()));
237 // `is_exhaustive_and_exact` is false so we won't know it's the end of the
238 // bitstream until we see a temporal unit. Need more data to know we're done.
239 EXPECT_TRUE(insufficient_data);
240 EXPECT_EQ(codec_config_obus.size(), 0);
241 EXPECT_EQ(read_bit_buffer->Tell(), start_position);
242 }
243
TEST(ProcessDescriptorObus,CollectsIaSequenceHeaderWithoutOtherObus)244 TEST(ProcessDescriptorObus, CollectsIaSequenceHeaderWithoutOtherObus) {
245 const auto only_ia_sequence_header =
246 AddSequenceHeaderAndSerializeObusExpectOk({});
247 IASequenceHeaderObu ia_sequence_header;
248 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
249 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
250 audio_elements_with_data;
251 std::list<MixPresentationObu> mix_presentation_obus;
252
253 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
254 kBufferCapacity, absl::MakeConstSpan(only_ia_sequence_header));
255 bool insufficient_data;
256 EXPECT_THAT(
257 ObuProcessor::ProcessDescriptorObus(
258 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
259 ia_sequence_header, codec_config_obus, audio_elements_with_data,
260 mix_presentation_obus, insufficient_data),
261 IsOk());
262
263 EXPECT_EQ(ia_sequence_header.GetPrimaryProfile(),
264 ProfileVersion::kIamfSimpleProfile);
265 EXPECT_EQ(ia_sequence_header.GetAdditionalProfile(),
266 ProfileVersion::kIamfBaseProfile);
267 EXPECT_FALSE(insufficient_data);
268 }
269
TEST(ProcessDescriptorObus,DescriptorObusMustStartWithIaSequenceHeader)270 TEST(ProcessDescriptorObus, DescriptorObusMustStartWithIaSequenceHeader) {
271 const IASequenceHeaderObu input_ia_sequence_header(
272 ObuHeader(), IASequenceHeaderObu::kIaCode,
273 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
274 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> input_codec_configs;
275 AddOpusCodecConfigWithId(kFirstCodecConfigId, input_codec_configs);
276
277 IASequenceHeaderObu unused_ia_sequence_header;
278 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> unused_codec_config_obus;
279 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
280 unused_audio_elements_with_data;
281 std::list<MixPresentationObu> unused_mix_presentation_obus;
282
283 // Descriptor OBUs must start with IA Sequence Header.
284 const auto ia_sequence_header_then_codec_config =
285 SerializeObusExpectOk({&input_ia_sequence_header,
286 &input_codec_configs.at(kFirstCodecConfigId)});
287
288 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
289 kBufferCapacity,
290 absl::MakeConstSpan(ia_sequence_header_then_codec_config));
291 bool insufficient_data;
292 EXPECT_THAT(ObuProcessor::ProcessDescriptorObus(
293 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
294 unused_ia_sequence_header, unused_codec_config_obus,
295 unused_audio_elements_with_data, unused_mix_presentation_obus,
296 insufficient_data),
297 IsOk());
298 EXPECT_FALSE(insufficient_data);
299 // The reverse order is not valid according to
300 // https://aomediacodec.github.io/iamf/#standalone-descriptor-obus
301 const auto codec_config_then_ia_sequence_header =
302 SerializeObusExpectOk({&input_codec_configs.at(kFirstCodecConfigId),
303 &input_ia_sequence_header});
304
305 read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
306 kBufferCapacity,
307 absl::MakeConstSpan(codec_config_then_ia_sequence_header));
308 EXPECT_FALSE(ObuProcessor::ProcessDescriptorObus(
309 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
310 unused_ia_sequence_header, unused_codec_config_obus,
311 unused_audio_elements_with_data,
312 unused_mix_presentation_obus, insufficient_data)
313 .ok());
314 // `insufficient_data` is false as the error was due to an invalid ordering of
315 // OBUs, rather than not having enough data.
316 EXPECT_FALSE(insufficient_data);
317 }
318
TEST(ProcessDescriptorObus,SucceedsWithSuccessiveRedundantSequenceHeaders)319 TEST(ProcessDescriptorObus, SucceedsWithSuccessiveRedundantSequenceHeaders) {
320 const IASequenceHeaderObu input_redundant_ia_sequence_header(
321 ObuHeader{.obu_redundant_copy = true}, IASequenceHeaderObu::kIaCode,
322 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
323 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
324 {&input_redundant_ia_sequence_header});
325 IASequenceHeaderObu ia_sequence_header;
326 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
327 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
328 audio_elements_with_data;
329 std::list<MixPresentationObu> mix_presentation_obus;
330
331 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
332 kBufferCapacity, absl::MakeConstSpan(bitstream));
333 bool insufficient_data;
334 EXPECT_THAT(
335 ObuProcessor::ProcessDescriptorObus(
336 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
337 ia_sequence_header, codec_config_obus, audio_elements_with_data,
338 mix_presentation_obus, insufficient_data),
339 IsOk());
340 EXPECT_FALSE(insufficient_data);
341 }
342
TEST(ProcessDescriptorObus,ConsumesUpToNextNonRedundantSequenceHeader)343 TEST(ProcessDescriptorObus, ConsumesUpToNextNonRedundantSequenceHeader) {
344 const IASequenceHeaderObu input_non_redundant_ia_sequence_header(
345 ObuHeader(), IASequenceHeaderObu::kIaCode,
346 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
347 auto buffer =
348 SerializeObusExpectOk({&input_non_redundant_ia_sequence_header});
349 const int64_t first_ia_sequence_size = buffer.size();
350
351 // Add a second non-redundant sequence header.
352 const auto second_non_redundant_ia_sequence =
353 SerializeObusExpectOk({&input_non_redundant_ia_sequence_header});
354 buffer.insert(buffer.end(), second_non_redundant_ia_sequence.begin(),
355 second_non_redundant_ia_sequence.end());
356
357 IASequenceHeaderObu ia_sequence_header;
358 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
359 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
360 audio_elements_with_data;
361 std::list<MixPresentationObu> mix_presentation_obus;
362
363 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
364 kBufferCapacity, absl::MakeConstSpan(buffer));
365 bool insufficient_data;
366 EXPECT_THAT(
367 ObuProcessor::ProcessDescriptorObus(
368 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
369 ia_sequence_header, codec_config_obus, audio_elements_with_data,
370 mix_presentation_obus, insufficient_data),
371 IsOk());
372 EXPECT_FALSE(insufficient_data);
373
374 // Expect the reader position to be right next to the end of the first IA
375 // sequence.
376 EXPECT_EQ(read_bit_buffer->Tell(), first_ia_sequence_size * 8);
377 }
378
TEST(ProcessDescriptorObus,CollectsIaSequenceHeaderWithCodecConfigs)379 TEST(ProcessDescriptorObus, CollectsIaSequenceHeaderWithCodecConfigs) {
380 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> input_codec_configs;
381 const DecodedUleb128 kFirstCodecConfigId = 123;
382 AddOpusCodecConfigWithId(kFirstCodecConfigId, input_codec_configs);
383 const DecodedUleb128 kSecondCodecConfigId = 124;
384 AddOpusCodecConfigWithId(kSecondCodecConfigId, input_codec_configs);
385 const auto ia_sequence_header_with_codec_configs =
386 AddSequenceHeaderAndSerializeObusExpectOk(
387 {&input_codec_configs.at(kFirstCodecConfigId),
388 &input_codec_configs.at(kSecondCodecConfigId)});
389 IASequenceHeaderObu ia_sequence_header;
390 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
391 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
392 audio_elements_with_data;
393 std::list<MixPresentationObu> mix_presentation_obus;
394
395 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
396 kBufferCapacity,
397 absl::MakeConstSpan(ia_sequence_header_with_codec_configs));
398 bool insufficient_data;
399 EXPECT_THAT(
400 ObuProcessor::ProcessDescriptorObus(
401 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
402 ia_sequence_header, codec_config_obus, audio_elements_with_data,
403 mix_presentation_obus, insufficient_data),
404 IsOk());
405
406 EXPECT_FALSE(insufficient_data);
407 EXPECT_EQ(ia_sequence_header.GetPrimaryProfile(),
408 ProfileVersion::kIamfSimpleProfile);
409 EXPECT_EQ(codec_config_obus.size(), 2);
410 EXPECT_TRUE(codec_config_obus.contains(kFirstCodecConfigId));
411 EXPECT_TRUE(codec_config_obus.contains(kSecondCodecConfigId));
412 }
413
414 // Returns a bitstream with all the descriptor obus for a zeroth order
415 // ambisonics stream.
InitAllDescriptorsForZerothOrderAmbisonics()416 std::vector<uint8_t> InitAllDescriptorsForZerothOrderAmbisonics() {
417 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> input_codec_configs;
418 AddOpusCodecConfigWithId(kFirstCodecConfigId, input_codec_configs);
419 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
420 audio_elements_with_data;
421 AddAmbisonicsMonoAudioElementWithSubstreamIds(
422 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
423 input_codec_configs, audio_elements_with_data);
424 std::list<MixPresentationObu> mix_presentation_obus;
425 AddMixPresentationObuWithAudioElementIds(
426 kFirstMixPresentationId, {kFirstAudioElementId},
427 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
428
429 return AddSequenceHeaderAndSerializeObusExpectOk(
430 {&input_codec_configs.at(kFirstCodecConfigId),
431 &audio_elements_with_data.at(kFirstAudioElementId).obu,
432 &mix_presentation_obus.front()});
433 }
434
435 // Descriptor obus only, is_exhaustive_and_exact = true.
TEST(ProcessDescriptorObus,SucceedsWithoutTemporalUnitFollowing)436 TEST(ProcessDescriptorObus, SucceedsWithoutTemporalUnitFollowing) {
437 auto zeroth_order_ambisonics_descriptor_obus =
438 InitAllDescriptorsForZerothOrderAmbisonics();
439
440 IASequenceHeaderObu ia_sequence_header;
441 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
442 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
443 audio_elements_with_data;
444 std::list<MixPresentationObu> mix_presentation_obus;
445
446 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
447 kBufferCapacity,
448 absl::MakeConstSpan(zeroth_order_ambisonics_descriptor_obus));
449 bool insufficient_data;
450
451 EXPECT_THAT(
452 ObuProcessor::ProcessDescriptorObus(
453 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
454 ia_sequence_header, codec_config_obus, audio_elements_with_data,
455 mix_presentation_obus, insufficient_data),
456 IsOk());
457
458 EXPECT_FALSE(insufficient_data);
459 EXPECT_EQ(ia_sequence_header.GetPrimaryProfile(),
460 ProfileVersion::kIamfSimpleProfile);
461 EXPECT_EQ(codec_config_obus.size(), 1);
462 EXPECT_TRUE(codec_config_obus.contains(kFirstCodecConfigId));
463 EXPECT_EQ(audio_elements_with_data.size(), 1);
464 EXPECT_TRUE(audio_elements_with_data.contains(kFirstAudioElementId));
465 EXPECT_EQ(mix_presentation_obus.size(), 1);
466 EXPECT_EQ(mix_presentation_obus.front().GetMixPresentationId(),
467 kFirstMixPresentationId);
468 }
469
470 // Descriptor obus only, is_exhaustive_and_exact = false.
TEST(ProcessDescriptorObus,RejectsWithoutTemporalUnitFollowingAndNotExhaustive)471 TEST(ProcessDescriptorObus,
472 RejectsWithoutTemporalUnitFollowingAndNotExhaustive) {
473 auto zeroth_order_ambisonics_descriptor_obus =
474 InitAllDescriptorsForZerothOrderAmbisonics();
475
476 IASequenceHeaderObu ia_sequence_header;
477 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
478 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
479 audio_elements_with_data;
480 std::list<MixPresentationObu> mix_presentation_obus;
481
482 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
483 kBufferCapacity,
484 absl::MakeConstSpan(zeroth_order_ambisonics_descriptor_obus));
485 auto start_position = read_bit_buffer->Tell();
486 bool insufficient_data;
487
488 EXPECT_THAT(
489 ObuProcessor::ProcessDescriptorObus(
490 /*is_exhaustive_and_exact=*/false, *read_bit_buffer,
491 ia_sequence_header, codec_config_obus, audio_elements_with_data,
492 mix_presentation_obus, insufficient_data),
493 Not(IsOk()));
494
495 // We've received a valid bitstream so far but not complete.
496 EXPECT_TRUE(insufficient_data);
497 EXPECT_EQ(codec_config_obus.size(), 0);
498 EXPECT_EQ(audio_elements_with_data.size(), 0);
499 EXPECT_EQ(mix_presentation_obus.size(), 0);
500 // Expect the reader position to be unchanged since we returned an error.
501 EXPECT_EQ(read_bit_buffer->Tell(), start_position);
502 }
503
504 // Descriptor obus + temporal unit header following, is_exhaustive_and_exact =
505 // true
TEST(ProcessDescriptorObusTest,RejectDescriptorObusWithTemporalUnitFollowingAndIsExhaustiveAndExact)506 TEST(ProcessDescriptorObusTest,
507 RejectDescriptorObusWithTemporalUnitFollowingAndIsExhaustiveAndExact) {
508 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
509
510 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
511 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
512 const auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
513 bitstream.insert(bitstream.end(), temporal_unit_obus.begin(),
514 temporal_unit_obus.end());
515
516 IASequenceHeaderObu ia_sequence_header;
517 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
518 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
519 audio_elements_with_data;
520 std::list<MixPresentationObu> mix_presentation_obus;
521
522 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
523 kBufferCapacity, absl::MakeConstSpan(bitstream));
524 auto start_position = read_bit_buffer->Tell();
525 bool insufficient_data;
526
527 EXPECT_THAT(
528 ObuProcessor::ProcessDescriptorObus(
529 /*is_exhaustive_and_exact=*/true, *read_bit_buffer,
530 ia_sequence_header, codec_config_obus, audio_elements_with_data,
531 mix_presentation_obus, insufficient_data),
532 Not(IsOk()));
533
534 // We failed with sufficient data.
535 EXPECT_FALSE(insufficient_data);
536
537 // Expect the reader position to be unchanged since we returned an error.
538 EXPECT_EQ(read_bit_buffer->Tell(), start_position);
539 }
540
541 // Descriptor obus + temporal unit header following, is_exhaustive_and_exact =
542 // false.
TEST(ProcessDescriptorObusTest,SucceedsWithTemporalUnitFollowing)543 TEST(ProcessDescriptorObusTest, SucceedsWithTemporalUnitFollowing) {
544 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
545 const int64_t descriptors_size = bitstream.size();
546
547 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
548 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
549 const auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
550 bitstream.insert(bitstream.end(), temporal_unit_obus.begin(),
551 temporal_unit_obus.end());
552
553 IASequenceHeaderObu ia_sequence_header;
554 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
555 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
556 audio_elements_with_data;
557 std::list<MixPresentationObu> mix_presentation_obus;
558
559 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
560 kBufferCapacity, absl::MakeConstSpan(bitstream));
561 bool insufficient_data;
562
563 EXPECT_THAT(
564 ObuProcessor::ProcessDescriptorObus(
565 /*is_exhaustive_and_exact=*/false, *read_bit_buffer,
566 ia_sequence_header, codec_config_obus, audio_elements_with_data,
567 mix_presentation_obus, insufficient_data),
568 IsOk());
569
570 EXPECT_FALSE(insufficient_data);
571 EXPECT_EQ(ia_sequence_header.GetPrimaryProfile(),
572 ProfileVersion::kIamfSimpleProfile);
573 EXPECT_EQ(codec_config_obus.size(), 1);
574 EXPECT_TRUE(codec_config_obus.contains(kFirstCodecConfigId));
575 EXPECT_EQ(audio_elements_with_data.size(), 1);
576 EXPECT_TRUE(audio_elements_with_data.contains(kFirstAudioElementId));
577 EXPECT_EQ(mix_presentation_obus.size(), 1);
578 EXPECT_EQ(mix_presentation_obus.front().GetMixPresentationId(),
579 kFirstMixPresentationId);
580
581 // Expect the reader position to be right next to the end of the descriptors.
582 // sequence.
583 EXPECT_EQ(read_bit_buffer->Tell(), descriptors_size * 8);
584 }
585
586 // Descriptor obus + non_temporal_unit_header following but not enough data to
587 // read last obu.
TEST(ProcessDescriptorObusTest,RejectDescriptorObusWithNonTemporalUnitHeaderFollowingAndNotEnoughData)588 TEST(ProcessDescriptorObusTest,
589 RejectDescriptorObusWithNonTemporalUnitHeaderFollowingAndNotEnoughData) {
590 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
591
592 std::vector<uint8_t> extra_descriptor_obu_header_bytes = {
593 kObuIaCodecConfig << kObuTypeBitShift,
594 // `obu_size`. -> Non-zero size, but we have no bytes following.
595 0x7f};
596
597 bitstream.insert(bitstream.end(), extra_descriptor_obu_header_bytes.begin(),
598 extra_descriptor_obu_header_bytes.end());
599
600 IASequenceHeaderObu ia_sequence_header;
601 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
602 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
603 audio_elements_with_data;
604 std::list<MixPresentationObu> mix_presentation_obus;
605
606 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
607 kBufferCapacity, absl::MakeConstSpan(bitstream));
608 auto start_position = read_bit_buffer->Tell();
609 bool insufficient_data;
610
611 EXPECT_THAT(
612 ObuProcessor::ProcessDescriptorObus(
613 /*is_exhaustive_and_exact=*/false, *read_bit_buffer,
614 ia_sequence_header, codec_config_obus, audio_elements_with_data,
615 mix_presentation_obus, insufficient_data),
616 Not(IsOk()));
617
618 // We've received a valid bitstream so far but not complete.
619 EXPECT_TRUE(insufficient_data);
620 // Expect the reader position to be unchanged since we returned an error.
621 EXPECT_EQ(read_bit_buffer->Tell(), start_position);
622 }
623
624 // Descriptor obus + partial header following.
TEST(ProcessDescriptorObus,RejectsDescriptorObusWithPartialHeaderFollowing)625 TEST(ProcessDescriptorObus, RejectsDescriptorObusWithPartialHeaderFollowing) {
626 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
627
628 std::vector<uint8_t> partial_header_obu = {0x80};
629 bitstream.insert(bitstream.end(), partial_header_obu.begin(),
630 partial_header_obu.end());
631
632 IASequenceHeaderObu ia_sequence_header;
633 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
634 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
635 audio_elements_with_data;
636 std::list<MixPresentationObu> mix_presentation_obus;
637
638 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
639 kBufferCapacity, absl::MakeConstSpan(bitstream));
640 auto start_position = read_bit_buffer->Tell();
641 bool insufficient_data;
642
643 EXPECT_THAT(
644 ObuProcessor::ProcessDescriptorObus(
645 /*is_exhaustive_and_exact=*/false, *read_bit_buffer,
646 ia_sequence_header, codec_config_obus, audio_elements_with_data,
647 mix_presentation_obus, insufficient_data),
648 Not(IsOk()));
649
650 // We've received a valid bitstream so far but not complete.
651 EXPECT_TRUE(insufficient_data);
652 EXPECT_EQ(codec_config_obus.size(), 0);
653 EXPECT_EQ(audio_elements_with_data.size(), 0);
654 EXPECT_EQ(mix_presentation_obus.size(), 0);
655 // Expect the reader position to be unchanged since we returned an error.
656 EXPECT_EQ(read_bit_buffer->Tell(), start_position);
657 }
658
TEST(ProcessTemporalUnitObus,OkAndProducesNoObusIfEmpty)659 TEST(ProcessTemporalUnitObus, OkAndProducesNoObusIfEmpty) {
660 const auto empty_temporal_unit = SerializeObusExpectOk({});
661 auto empty_read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
662 kBufferCapacity, absl::MakeConstSpan(empty_temporal_unit));
663 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu> kNoCodecConfigs =
664 {};
665 const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
666 kNoAudioElementsWithData = {};
667 auto global_timing_module =
668 GlobalTimingModule::Create(kNoAudioElementsWithData,
669 /*param_definitions=*/{});
670 ASSERT_THAT(global_timing_module, NotNull());
671 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
672
673 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
674 substream_id_to_audio_element = {};
675 ParametersManager parameters_manager(kNoAudioElementsWithData);
676 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
677 bool continue_processing = true;
678 std::optional<AudioFrameWithData> audio_frame_with_data;
679 std::optional<ParameterBlockWithData> parameter_block_with_data;
680 std::optional<TemporalDelimiterObu> temporal_delimiter;
681 EXPECT_THAT(
682 ObuProcessor::ProcessTemporalUnitObu(
683 kNoAudioElementsWithData, kNoCodecConfigs,
684 substream_id_to_audio_element, param_definitions, parameters_manager,
685 *empty_read_bit_buffer, *global_timing_module, audio_frame_with_data,
686 parameter_block_with_data, temporal_delimiter, continue_processing),
687 IsOk());
688
689 EXPECT_FALSE(audio_frame_with_data.has_value());
690 EXPECT_FALSE(parameter_block_with_data.has_value());
691 EXPECT_FALSE(temporal_delimiter.has_value());
692 EXPECT_FALSE(continue_processing);
693 }
694
TEST(ProcessTemporalUnitObus,ConsumesAllTemporalUnits)695 TEST(ProcessTemporalUnitObus, ConsumesAllTemporalUnits) {
696 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
697 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
698
699 const auto one_temporal_unit = SerializeObusExpectOk({&audio_frame_obu});
700
701 // Set up inputs.
702 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
703 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
704 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
705 audio_elements_with_data;
706 AddAmbisonicsMonoAudioElementWithSubstreamIds(
707 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
708 codec_config_obus, audio_elements_with_data);
709 auto global_timing_module =
710 GlobalTimingModule::Create(audio_elements_with_data,
711 /*param_definitions=*/{});
712 ASSERT_THAT(global_timing_module, NotNull());
713
714 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
715 substream_id_to_audio_element = {
716 {kFirstSubstreamId,
717 &audio_elements_with_data.at(kFirstAudioElementId)}};
718 ParametersManager parameters_manager(audio_elements_with_data);
719 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
720 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
721 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
722 kBufferCapacity, absl::MakeConstSpan(one_temporal_unit));
723
724 bool continue_processing = true;
725 std::optional<AudioFrameWithData> audio_frame_with_data;
726 std::optional<ParameterBlockWithData> parameter_block_with_data;
727 std::optional<TemporalDelimiterObu> temporal_delimiter;
728 EXPECT_THAT(
729 ObuProcessor::ProcessTemporalUnitObu(
730 audio_elements_with_data, codec_config_obus,
731 substream_id_to_audio_element, param_definitions, parameters_manager,
732 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
733 parameter_block_with_data, temporal_delimiter, continue_processing),
734 IsOk());
735 EXPECT_TRUE(audio_frame_with_data.has_value());
736 EXPECT_FALSE(parameter_block_with_data.has_value());
737 EXPECT_FALSE(temporal_delimiter.has_value());
738
739 // Reaching the end of the stream.
740 EXPECT_FALSE(read_bit_buffer->IsDataAvailable());
741 }
742
TEST(ProcessTemporalUnitObus,ReadsAllTemporalUnitsBeforeNewIaSequence)743 TEST(ProcessTemporalUnitObus, ReadsAllTemporalUnitsBeforeNewIaSequence) {
744 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
745 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
746 const IASequenceHeaderObu non_redundant_ia_sequence_header(
747 ObuHeader{.obu_redundant_copy = false}, IASequenceHeaderObu::kIaCode,
748 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
749
750 const auto one_temporal_unit_before_non_redundant_descriptor_obu =
751 SerializeObusExpectOk(
752 {&audio_frame_obu, &non_redundant_ia_sequence_header});
753
754 // Set up inputs.
755 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
756 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
757 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
758 audio_elements_with_data;
759 AddAmbisonicsMonoAudioElementWithSubstreamIds(
760 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
761 codec_config_obus, audio_elements_with_data);
762 auto global_timing_module =
763 GlobalTimingModule::Create(audio_elements_with_data,
764 /*param_definitions=*/{});
765 ASSERT_THAT(global_timing_module, NotNull());
766
767 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
768 substream_id_to_audio_element = {
769 {kFirstSubstreamId,
770 &audio_elements_with_data.at(kFirstAudioElementId)}};
771 ParametersManager parameters_manager(audio_elements_with_data);
772 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
773 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
774 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
775 kBufferCapacity,
776 absl::MakeConstSpan(
777 one_temporal_unit_before_non_redundant_descriptor_obu));
778
779 bool continue_processing = true;
780 std::optional<AudioFrameWithData> audio_frame_with_data;
781 std::optional<ParameterBlockWithData> parameter_block_with_data;
782 std::optional<TemporalDelimiterObu> temporal_delimiter;
783 EXPECT_THAT(
784 ObuProcessor::ProcessTemporalUnitObu(
785 audio_elements_with_data, codec_config_obus,
786 substream_id_to_audio_element, param_definitions, parameters_manager,
787 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
788 parameter_block_with_data, temporal_delimiter, continue_processing),
789 IsOk());
790 EXPECT_TRUE(audio_frame_with_data.has_value());
791 EXPECT_FALSE(parameter_block_with_data.has_value());
792 EXPECT_FALSE(temporal_delimiter.has_value());
793 EXPECT_TRUE(continue_processing);
794
795 // Process again, this time a new IA sequence is encountred, empty OBUs
796 // are returned, and `continue_processing` is set to false.
797 EXPECT_THAT(
798 ObuProcessor::ProcessTemporalUnitObu(
799 audio_elements_with_data, codec_config_obus,
800 substream_id_to_audio_element, param_definitions, parameters_manager,
801 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
802 parameter_block_with_data, temporal_delimiter, continue_processing),
803 IsOk());
804 EXPECT_FALSE(audio_frame_with_data.has_value());
805 EXPECT_FALSE(parameter_block_with_data.has_value());
806 EXPECT_FALSE(temporal_delimiter.has_value());
807 EXPECT_FALSE(continue_processing);
808
809 // NOT reaching the end of the stream because we haven't consumed the
810 // next IA sequence header.
811 EXPECT_TRUE(read_bit_buffer->IsDataAvailable());
812 }
813
TEST(ProcessTemporalUnitObus,ConsumesAllTemporalUnitsAndRedundantDescriptorObus)814 TEST(ProcessTemporalUnitObus,
815 ConsumesAllTemporalUnitsAndRedundantDescriptorObus) {
816 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
817 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
818 const IASequenceHeaderObu redundant_ia_sequence_header(
819 ObuHeader{.obu_redundant_copy = true}, IASequenceHeaderObu::kIaCode,
820 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
821 // Set up inputs.
822 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
823 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
824 auto& redundant_codec_config = codec_config_obus.at(kFirstCodecConfigId);
825 redundant_codec_config.header_.obu_redundant_copy = true;
826
827 const auto one_temporal_unit_before_redundant_descriptor_obu =
828 SerializeObusExpectOk({&audio_frame_obu, &redundant_ia_sequence_header,
829 &redundant_codec_config});
830
831 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
832 audio_elements_with_data;
833 AddAmbisonicsMonoAudioElementWithSubstreamIds(
834 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
835 codec_config_obus, audio_elements_with_data);
836 auto global_timing_module =
837 GlobalTimingModule::Create(audio_elements_with_data,
838 /*param_definitions=*/{});
839 ASSERT_THAT(global_timing_module, NotNull());
840 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
841 substream_id_to_audio_element = {
842 {kFirstSubstreamId,
843 &audio_elements_with_data.at(kFirstAudioElementId)}};
844 ParametersManager parameters_manager(audio_elements_with_data);
845 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
846 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
847 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
848 kBufferCapacity,
849 absl::MakeConstSpan(one_temporal_unit_before_redundant_descriptor_obu));
850
851 bool continue_processing = true;
852 std::optional<AudioFrameWithData> audio_frame_with_data;
853 std::optional<ParameterBlockWithData> parameter_block_with_data;
854 std::optional<TemporalDelimiterObu> temporal_delimiter;
855 EXPECT_THAT(
856 ObuProcessor::ProcessTemporalUnitObu(
857 audio_elements_with_data, codec_config_obus,
858 substream_id_to_audio_element, param_definitions, parameters_manager,
859 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
860 parameter_block_with_data, temporal_delimiter, continue_processing),
861 IsOk());
862 EXPECT_TRUE(audio_frame_with_data.has_value());
863 EXPECT_FALSE(parameter_block_with_data.has_value());
864 EXPECT_FALSE(temporal_delimiter.has_value());
865 EXPECT_TRUE(continue_processing);
866
867 // Process again, this time the redundant IA sequence header is read and
868 // outputs are empty.
869 EXPECT_THAT(
870 ObuProcessor::ProcessTemporalUnitObu(
871 audio_elements_with_data, codec_config_obus,
872 substream_id_to_audio_element, param_definitions, parameters_manager,
873 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
874 parameter_block_with_data, temporal_delimiter, continue_processing),
875 IsOk());
876 EXPECT_FALSE(audio_frame_with_data.has_value());
877 EXPECT_FALSE(parameter_block_with_data.has_value());
878 EXPECT_FALSE(temporal_delimiter.has_value());
879 EXPECT_TRUE(continue_processing);
880
881 // Process again, this time the redundant Codec Config is read and outputs
882 // are empty.
883 EXPECT_THAT(
884 ObuProcessor::ProcessTemporalUnitObu(
885 audio_elements_with_data, codec_config_obus,
886 substream_id_to_audio_element, param_definitions, parameters_manager,
887 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
888 parameter_block_with_data, temporal_delimiter, continue_processing),
889 IsOk());
890 EXPECT_FALSE(audio_frame_with_data.has_value());
891 EXPECT_FALSE(parameter_block_with_data.has_value());
892 EXPECT_FALSE(temporal_delimiter.has_value());
893
894 // Reaching the end of the stream.
895 EXPECT_FALSE(read_bit_buffer->IsDataAvailable());
896 }
897
TEST(ProcessTemporalUnitObus,FailsOnNonRedundantAndNonIaSequenceHeaderDescriptorObu)898 TEST(ProcessTemporalUnitObus,
899 FailsOnNonRedundantAndNonIaSequenceHeaderDescriptorObu) {
900 // Set up inputs.
901 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
902 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
903 auto& non_redundant_codec_config = codec_config_obus.at(kFirstCodecConfigId);
904 non_redundant_codec_config.header_.obu_redundant_copy = false;
905
906 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
907 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
908
909 const auto temporal_unit_with_non_redundant_codec_config_obu =
910 SerializeObusExpectOk({&audio_frame_obu, &non_redundant_codec_config});
911
912 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
913 audio_elements_with_data;
914 AddAmbisonicsMonoAudioElementWithSubstreamIds(
915 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
916 codec_config_obus, audio_elements_with_data);
917 auto global_timing_module =
918 GlobalTimingModule::Create(audio_elements_with_data,
919 /*param_definitions=*/{});
920 ASSERT_THAT(global_timing_module, NotNull());
921 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
922 substream_id_to_audio_element = {
923 {kFirstSubstreamId,
924 &audio_elements_with_data.at(kFirstAudioElementId)}};
925 ParametersManager parameters_manager(audio_elements_with_data);
926 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
927 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
928 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
929 kBufferCapacity,
930 absl::MakeConstSpan(temporal_unit_with_non_redundant_codec_config_obu));
931
932 bool continue_processing = true;
933 std::optional<AudioFrameWithData> audio_frame_with_data;
934 std::optional<ParameterBlockWithData> parameter_block_with_data;
935 std::optional<TemporalDelimiterObu> temporal_delimiter;
936 EXPECT_THAT(
937 ObuProcessor::ProcessTemporalUnitObu(
938 audio_elements_with_data, codec_config_obus,
939 substream_id_to_audio_element, param_definitions, parameters_manager,
940 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
941 parameter_block_with_data, temporal_delimiter, continue_processing),
942 IsOk());
943 EXPECT_TRUE(audio_frame_with_data.has_value());
944 EXPECT_FALSE(parameter_block_with_data.has_value());
945 EXPECT_FALSE(temporal_delimiter.has_value());
946 EXPECT_TRUE(continue_processing);
947
948 // Process again, this time the non-redundant Codec Config OBU is read and
949 // the function fails.
950 EXPECT_FALSE(ObuProcessor::ProcessTemporalUnitObu(
951 audio_elements_with_data, codec_config_obus,
952 substream_id_to_audio_element, param_definitions,
953 parameters_manager, *read_bit_buffer, *global_timing_module,
954 audio_frame_with_data, parameter_block_with_data,
955 temporal_delimiter, continue_processing)
956 .ok());
957 }
958
TEST(ProcessTemporalUnitObus,ConsumesAllTemporalUnitsAndReservedObus)959 TEST(ProcessTemporalUnitObus, ConsumesAllTemporalUnitsAndReservedObus) {
960 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
961 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
962 ArbitraryObu reserved_obu_before_audio_frame(
963 kObuIaReserved25, ObuHeader(), /*payload=*/{0, 99},
964 ArbitraryObu::kInsertionHookAfterDescriptors);
965 ArbitraryObu reserved_obu_after_audio_frame(
966 kObuIaReserved29, ObuHeader{.obu_redundant_copy = true},
967 /*payload=*/{0, 99}, ArbitraryObu::kInsertionHookAfterDescriptors);
968
969 const auto temporal_unit_with_reserved_obus =
970 SerializeObusExpectOk({&reserved_obu_before_audio_frame, &audio_frame_obu,
971 &reserved_obu_after_audio_frame});
972 // Set up inputs.
973 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
974 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
975 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
976 audio_elements_with_data;
977 AddAmbisonicsMonoAudioElementWithSubstreamIds(
978 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
979 codec_config_obus, audio_elements_with_data);
980 auto global_timing_module =
981 GlobalTimingModule::Create(audio_elements_with_data,
982 /*param_definitions=*/{});
983 ASSERT_THAT(global_timing_module, NotNull());
984 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
985 substream_id_to_audio_element = {
986 {kFirstSubstreamId,
987 &audio_elements_with_data.at(kFirstAudioElementId)}};
988 ParametersManager parameters_manager(audio_elements_with_data);
989 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
990 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
991 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
992 kBufferCapacity, absl::MakeConstSpan(temporal_unit_with_reserved_obus));
993
994 bool continue_processing = true;
995 std::optional<AudioFrameWithData> audio_frame_with_data;
996 std::optional<ParameterBlockWithData> parameter_block_with_data;
997 std::optional<TemporalDelimiterObu> temporal_delimiter;
998
999 // First call: reading and discarding the reserved OBU.
1000 EXPECT_THAT(
1001 ObuProcessor::ProcessTemporalUnitObu(
1002 audio_elements_with_data, codec_config_obus,
1003 substream_id_to_audio_element, param_definitions, parameters_manager,
1004 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1005 parameter_block_with_data, temporal_delimiter, continue_processing),
1006 IsOk());
1007 EXPECT_FALSE(audio_frame_with_data.has_value());
1008 EXPECT_FALSE(parameter_block_with_data.has_value());
1009 EXPECT_FALSE(temporal_delimiter.has_value());
1010 EXPECT_TRUE(continue_processing);
1011
1012 // Second call: reading the Audio Frame OBU.
1013 EXPECT_THAT(
1014 ObuProcessor::ProcessTemporalUnitObu(
1015 audio_elements_with_data, codec_config_obus,
1016 substream_id_to_audio_element, param_definitions, parameters_manager,
1017 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1018 parameter_block_with_data, temporal_delimiter, continue_processing),
1019 IsOk());
1020 EXPECT_TRUE(audio_frame_with_data.has_value());
1021 EXPECT_FALSE(parameter_block_with_data.has_value());
1022 EXPECT_FALSE(temporal_delimiter.has_value());
1023 EXPECT_TRUE(continue_processing);
1024
1025 // Third call: reading and discarding the reserved OBU.
1026 EXPECT_THAT(
1027 ObuProcessor::ProcessTemporalUnitObu(
1028 audio_elements_with_data, codec_config_obus,
1029 substream_id_to_audio_element, param_definitions, parameters_manager,
1030 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1031 parameter_block_with_data, temporal_delimiter, continue_processing),
1032 IsOk());
1033 EXPECT_FALSE(audio_frame_with_data.has_value());
1034 EXPECT_FALSE(parameter_block_with_data.has_value());
1035 EXPECT_FALSE(temporal_delimiter.has_value());
1036 EXPECT_TRUE(continue_processing);
1037
1038 // Reaching the end of the stream.
1039 EXPECT_FALSE(read_bit_buffer->IsDataAvailable());
1040 }
1041
TEST(ProcessTemporalUnitObusTest,ProcessMultipleAudioSubstreams)1042 TEST(ProcessTemporalUnitObusTest, ProcessMultipleAudioSubstreams) {
1043 std::vector<AudioFrameObu> audio_frame_obus;
1044 audio_frame_obus.push_back(AudioFrameObu(
1045 ObuHeader(), kFirstSubstreamId, /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1046 audio_frame_obus.push_back(
1047 AudioFrameObu(ObuHeader(), kSecondSubstreamId,
1048 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}));
1049 audio_frame_obus.push_back(
1050 AudioFrameObu(ObuHeader(), kImplicitSubstreamId,
1051 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8, 9}));
1052 const auto multiple_audio_substreams = SerializeObusExpectOk(
1053 {&audio_frame_obus[0], &audio_frame_obus[1], &audio_frame_obus[2]});
1054 // Set up inputs.
1055 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1056 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
1057 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
1058 audio_elements_with_data;
1059 AddAmbisonicsMonoAudioElementWithSubstreamIds(
1060 kFirstAudioElementId, kFirstCodecConfigId,
1061 {kFirstSubstreamId, kSecondSubstreamId, kImplicitSubstreamId},
1062 codec_config_obus, audio_elements_with_data);
1063 auto global_timing_module =
1064 GlobalTimingModule::Create(audio_elements_with_data,
1065 /*param_definitions=*/{});
1066 ASSERT_THAT(global_timing_module, NotNull());
1067 const auto* first_audio_element =
1068 &audio_elements_with_data.at(kFirstAudioElementId);
1069 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
1070 substream_id_to_audio_element = {
1071 {kFirstSubstreamId, first_audio_element},
1072 {kSecondSubstreamId, first_audio_element},
1073 {kImplicitSubstreamId, first_audio_element}};
1074 ParametersManager parameters_manager(audio_elements_with_data);
1075 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
1076 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
1077 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1078 kBufferCapacity, absl::MakeConstSpan(multiple_audio_substreams));
1079
1080 bool continue_processing = true;
1081 std::optional<AudioFrameWithData> audio_frame_with_data;
1082 std::optional<ParameterBlockWithData> parameter_block_with_data;
1083 std::optional<TemporalDelimiterObu> temporal_delimiter;
1084
1085 // Call three times, each outputing an audio frame.
1086 for (int i = 0; i < 3; i++) {
1087 EXPECT_THAT(ObuProcessor::ProcessTemporalUnitObu(
1088 audio_elements_with_data, codec_config_obus,
1089 substream_id_to_audio_element, param_definitions,
1090 parameters_manager, *read_bit_buffer, *global_timing_module,
1091 audio_frame_with_data, parameter_block_with_data,
1092 temporal_delimiter, continue_processing),
1093 IsOk());
1094 EXPECT_TRUE(audio_frame_with_data.has_value());
1095 EXPECT_FALSE(parameter_block_with_data.has_value());
1096 EXPECT_FALSE(temporal_delimiter.has_value());
1097 EXPECT_TRUE(continue_processing);
1098 }
1099 }
1100
TEST(ProcessTemporalUnitObusTest,ProcessesSubstreamWithMultipleFrames)1101 TEST(ProcessTemporalUnitObusTest, ProcessesSubstreamWithMultipleFrames) {
1102 std::vector<AudioFrameObu> audio_frame_obus;
1103 audio_frame_obus.push_back(AudioFrameObu(
1104 ObuHeader(), kFirstSubstreamId, /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1105 audio_frame_obus.push_back(
1106 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1107 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}));
1108 const auto audio_substream_with_two_frames =
1109 SerializeObusExpectOk({&audio_frame_obus[0], &audio_frame_obus[1]});
1110 // Set up inputs.
1111 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1112 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
1113 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
1114 audio_elements_with_data;
1115 AddAmbisonicsMonoAudioElementWithSubstreamIds(
1116 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
1117 codec_config_obus, audio_elements_with_data);
1118 auto global_timing_module =
1119 GlobalTimingModule::Create(audio_elements_with_data,
1120 /*param_definitions=*/{});
1121 ASSERT_THAT(global_timing_module, NotNull());
1122 const auto* first_audio_element =
1123 &audio_elements_with_data.at(kFirstAudioElementId);
1124 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
1125 substream_id_to_audio_element = {
1126 {kFirstSubstreamId, first_audio_element}};
1127 ParametersManager parameters_manager(audio_elements_with_data);
1128 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
1129 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
1130 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1131 kBufferCapacity, absl::MakeConstSpan(audio_substream_with_two_frames));
1132
1133 bool continue_processing = true;
1134 std::optional<AudioFrameWithData> audio_frame_with_data;
1135 std::optional<ParameterBlockWithData> parameter_block_with_data;
1136 std::optional<TemporalDelimiterObu> temporal_delimiter;
1137
1138 // Call two times, each outputing an audio frame.
1139 for (int i = 0; i < 2; i++) {
1140 EXPECT_THAT(ObuProcessor::ProcessTemporalUnitObu(
1141 audio_elements_with_data, codec_config_obus,
1142 substream_id_to_audio_element, param_definitions,
1143 parameters_manager, *read_bit_buffer, *global_timing_module,
1144 audio_frame_with_data, parameter_block_with_data,
1145 temporal_delimiter, continue_processing),
1146 IsOk());
1147 EXPECT_TRUE(audio_frame_with_data.has_value());
1148 EXPECT_FALSE(parameter_block_with_data.has_value());
1149 EXPECT_FALSE(temporal_delimiter.has_value());
1150 EXPECT_TRUE(continue_processing);
1151 }
1152 }
1153
TEST(ProcessTemporalUnitObusTest,ProcessesTemporalDelimiterObu)1154 TEST(ProcessTemporalUnitObusTest, ProcessesTemporalDelimiterObu) {
1155 auto temporal_delimiter_obu = TemporalDelimiterObu(ObuHeader());
1156 std::vector<AudioFrameObu> audio_frame_obus;
1157 audio_frame_obus.push_back(
1158 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1159 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1160 audio_frame_obus.push_back(
1161 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1162 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1163
1164 const auto two_temporal_units_with_delimiter_obu =
1165 SerializeObusExpectOk({&audio_frame_obus[0], &temporal_delimiter_obu,
1166 &audio_frame_obus[1], &temporal_delimiter_obu});
1167 // Set up inputs.
1168 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1169 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
1170 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
1171 audio_elements_with_data;
1172 AddAmbisonicsMonoAudioElementWithSubstreamIds(
1173 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
1174 codec_config_obus, audio_elements_with_data);
1175 auto global_timing_module =
1176 GlobalTimingModule::Create(audio_elements_with_data,
1177 /*param_definitions=*/{});
1178 ASSERT_THAT(global_timing_module, NotNull());
1179 const auto* first_audio_element =
1180 &audio_elements_with_data.at(kFirstAudioElementId);
1181 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
1182 substream_id_to_audio_element = {
1183 {kFirstSubstreamId, first_audio_element}};
1184 ParametersManager parameters_manager(audio_elements_with_data);
1185 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
1186 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
1187 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1188 kBufferCapacity,
1189 absl::MakeConstSpan(two_temporal_units_with_delimiter_obu));
1190
1191 bool continue_processing = true;
1192 std::optional<AudioFrameWithData> audio_frame_with_data;
1193 std::optional<ParameterBlockWithData> parameter_block_with_data;
1194 std::optional<TemporalDelimiterObu> temporal_delimiter;
1195
1196 // Call four times, outputing two audio frames and two temporal delimiters.
1197 const std::vector<bool> expecting_audio_frame = {true, false, true, false};
1198 const std::vector<bool> expecting_temporal_delimiter = {false, true, false,
1199 true};
1200 for (int i = 0; i < 4; i++) {
1201 EXPECT_THAT(ObuProcessor::ProcessTemporalUnitObu(
1202 audio_elements_with_data, codec_config_obus,
1203 substream_id_to_audio_element, param_definitions,
1204 parameters_manager, *read_bit_buffer, *global_timing_module,
1205 audio_frame_with_data, parameter_block_with_data,
1206 temporal_delimiter, continue_processing),
1207 IsOk());
1208 EXPECT_EQ(audio_frame_with_data.has_value(), expecting_audio_frame[i]);
1209 EXPECT_FALSE(parameter_block_with_data.has_value());
1210 EXPECT_EQ(temporal_delimiter.has_value(), expecting_temporal_delimiter[i]);
1211 EXPECT_TRUE(continue_processing);
1212 }
1213 }
1214
TEST(ProcessTemporalUnitObusTest,FillsMetadataAndTimestampsForParameterBlocks)1215 TEST(ProcessTemporalUnitObusTest,
1216 FillsMetadataAndTimestampsForParameterBlocks) {
1217 constexpr DecodedUleb128 kParameterBlockId = 1;
1218 constexpr DecodedUleb128 kParameterBlockDuration = 10;
1219 // Set up inputs.
1220 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1221 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
1222 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
1223 audio_elements_with_data;
1224 AddAmbisonicsMonoAudioElementWithSubstreamIds(
1225 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
1226 codec_config_obus, audio_elements_with_data);
1227
1228 // Param definition.
1229 MixGainParamDefinition param_definition;
1230 param_definition.parameter_id_ = kParameterBlockId;
1231 param_definition.parameter_rate_ = 1;
1232 param_definition.param_definition_mode_ = 0;
1233 param_definition.duration_ = kParameterBlockDuration;
1234 param_definition.constant_subblock_duration_ = kParameterBlockDuration;
1235 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
1236 param_definitions.emplace(kParameterBlockId, param_definition);
1237 ParameterBlockObu parameter_block_obu(ObuHeader(), kParameterBlockId,
1238 param_definition);
1239 EXPECT_THAT(parameter_block_obu.InitializeSubblocks(), IsOk());
1240 parameter_block_obu.subblocks_[0].param_data =
1241 std::make_unique<MixGainParameterData>(
1242 MixGainParameterData::kAnimateStep,
1243 AnimationStepInt16{.start_point_value = 99});
1244
1245 // Initialize the sequence with a single parameter block.
1246 const auto one_parameter_block_obu =
1247 SerializeObusExpectOk({¶meter_block_obu});
1248 auto global_timing_module =
1249 GlobalTimingModule::Create(audio_elements_with_data, param_definitions);
1250 ASSERT_THAT(global_timing_module, NotNull());
1251 const auto* first_audio_element =
1252 &audio_elements_with_data.at(kFirstAudioElementId);
1253 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
1254 substream_id_to_audio_element = {
1255 {kFirstSubstreamId, first_audio_element}};
1256 ParametersManager parameters_manager(audio_elements_with_data);
1257 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
1258 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1259 kBufferCapacity, absl::MakeConstSpan(one_parameter_block_obu));
1260
1261 bool continue_processing = true;
1262 std::optional<AudioFrameWithData> audio_frame_with_data;
1263 std::optional<ParameterBlockWithData> parameter_block_with_data;
1264 std::optional<TemporalDelimiterObu> temporal_delimiter;
1265 EXPECT_THAT(
1266 ObuProcessor::ProcessTemporalUnitObu(
1267 audio_elements_with_data, codec_config_obus,
1268 substream_id_to_audio_element, param_definitions, parameters_manager,
1269 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1270 parameter_block_with_data, temporal_delimiter, continue_processing),
1271 IsOk());
1272 EXPECT_FALSE(audio_frame_with_data.has_value());
1273 EXPECT_TRUE(parameter_block_with_data.has_value());
1274 EXPECT_FALSE(temporal_delimiter.has_value());
1275 EXPECT_TRUE(continue_processing);
1276
1277 const int32_t kObuRelativeTime = 0;
1278 float unused_mix_gain;
1279 EXPECT_THAT(parameter_block_with_data->obu->GetLinearMixGain(kObuRelativeTime,
1280 unused_mix_gain),
1281 IsOk());
1282 EXPECT_EQ(parameter_block_with_data->start_timestamp, 0);
1283 EXPECT_EQ(parameter_block_with_data->end_timestamp, kParameterBlockDuration);
1284 }
1285
TEST(ProcessTemporalUnitObus,ConsumesAllTemporalUnitsWithAnIncompleteHeaderAtEnd)1286 TEST(ProcessTemporalUnitObus,
1287 ConsumesAllTemporalUnitsWithAnIncompleteHeaderAtEnd) {
1288 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
1289 kArbitraryAudioFrame);
1290
1291 auto one_temporal_unit = SerializeObusExpectOk({&audio_frame_obu});
1292
1293 // Set up inputs with descriptors, one audio frame, and one incomplete header.
1294 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1295 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
1296 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
1297 audio_elements_with_data;
1298 AddAmbisonicsMonoAudioElementWithSubstreamIds(
1299 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
1300 codec_config_obus, audio_elements_with_data);
1301 auto global_timing_module =
1302 GlobalTimingModule::Create(audio_elements_with_data,
1303 /*param_definitions=*/{});
1304 ASSERT_THAT(global_timing_module, NotNull());
1305
1306 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
1307 substream_id_to_audio_element = {
1308 {kFirstSubstreamId,
1309 &audio_elements_with_data.at(kFirstAudioElementId)}};
1310 ParametersManager parameters_manager(audio_elements_with_data);
1311 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
1312 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
1313 // Add a single byte to the end of the temporal unit to represent an
1314 // incomplete header (A header requires at least 2 bytes).
1315 one_temporal_unit.push_back(0);
1316 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1317 kBufferCapacity, absl::MakeConstSpan(one_temporal_unit));
1318
1319 // Confirm that the first temporal unit is processed successfully.
1320 bool continue_processing = true;
1321 std::optional<AudioFrameWithData> audio_frame_with_data;
1322 std::optional<ParameterBlockWithData> parameter_block_with_data;
1323 std::optional<TemporalDelimiterObu> temporal_delimiter;
1324 EXPECT_THAT(
1325 ObuProcessor::ProcessTemporalUnitObu(
1326 audio_elements_with_data, codec_config_obus,
1327 substream_id_to_audio_element, param_definitions, parameters_manager,
1328 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1329 parameter_block_with_data, temporal_delimiter, continue_processing),
1330 IsOk());
1331 EXPECT_TRUE(audio_frame_with_data.has_value());
1332
1333 // Confirm that the second temporal unit it is incomplete.
1334 auto start_position = read_bit_buffer->Tell();
1335 EXPECT_THAT(
1336 ObuProcessor::ProcessTemporalUnitObu(
1337 audio_elements_with_data, codec_config_obus,
1338 substream_id_to_audio_element, param_definitions, parameters_manager,
1339 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1340 parameter_block_with_data, temporal_delimiter, continue_processing),
1341 IsOk());
1342 EXPECT_FALSE(audio_frame_with_data.has_value());
1343 EXPECT_FALSE(parameter_block_with_data.has_value());
1344 EXPECT_FALSE(temporal_delimiter.has_value());
1345 EXPECT_FALSE(continue_processing);
1346 EXPECT_EQ(read_bit_buffer->Tell(), start_position);
1347 }
1348
TEST(ProcessTemporalUnitObus,ConsumesAllTemporalUnitsWithAnIncompleteObuAtEnd)1349 TEST(ProcessTemporalUnitObus,
1350 ConsumesAllTemporalUnitsWithAnIncompleteObuAtEnd) {
1351 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
1352 kArbitraryAudioFrame);
1353
1354 auto ia_sequence = SerializeObusExpectOk({&audio_frame_obu});
1355
1356 // Set up inputs with descriptors, one audio frame, and one incomplete obu
1357 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1358 AddOpusCodecConfigWithId(kFirstCodecConfigId, codec_config_obus);
1359 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
1360 audio_elements_with_data;
1361 AddAmbisonicsMonoAudioElementWithSubstreamIds(
1362 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
1363 codec_config_obus, audio_elements_with_data);
1364 auto global_timing_module =
1365 GlobalTimingModule::Create(audio_elements_with_data,
1366 /*param_definitions=*/{});
1367 ASSERT_THAT(global_timing_module, NotNull());
1368
1369 const absl::flat_hash_map<DecodedUleb128, const AudioElementWithData*>
1370 substream_id_to_audio_element = {
1371 {kFirstSubstreamId,
1372 &audio_elements_with_data.at(kFirstAudioElementId)}};
1373 ParametersManager parameters_manager(audio_elements_with_data);
1374 ASSERT_THAT(parameters_manager.Initialize(), IsOk());
1375 absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant> param_definitions;
1376 std::vector<uint8_t> extra_audio_frame_obu_header_bytes = {
1377 kObuIaAudioFrameId0 << kObuTypeBitShift,
1378 // `obu_size`. -> Non-zero size, but we have no bytes following.
1379 0x7f};
1380 ia_sequence.insert(ia_sequence.end(),
1381 extra_audio_frame_obu_header_bytes.begin(),
1382 extra_audio_frame_obu_header_bytes.end());
1383 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1384 kBufferCapacity, absl::MakeConstSpan(ia_sequence));
1385
1386 // Confirm that the first temporal unit is processed successfully.
1387 bool continue_processing = true;
1388 std::optional<AudioFrameWithData> audio_frame_with_data;
1389 std::optional<ParameterBlockWithData> parameter_block_with_data;
1390 std::optional<TemporalDelimiterObu> temporal_delimiter;
1391 EXPECT_THAT(
1392 ObuProcessor::ProcessTemporalUnitObu(
1393 audio_elements_with_data, codec_config_obus,
1394 substream_id_to_audio_element, param_definitions, parameters_manager,
1395 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1396 parameter_block_with_data, temporal_delimiter, continue_processing),
1397 IsOk());
1398 EXPECT_TRUE(audio_frame_with_data.has_value());
1399
1400 // Confirm that the second temporal unit it is incomplete.
1401 auto start_position = read_bit_buffer->Tell();
1402 EXPECT_THAT(
1403 ObuProcessor::ProcessTemporalUnitObu(
1404 audio_elements_with_data, codec_config_obus,
1405 substream_id_to_audio_element, param_definitions, parameters_manager,
1406 *read_bit_buffer, *global_timing_module, audio_frame_with_data,
1407 parameter_block_with_data, temporal_delimiter, continue_processing),
1408 IsOk());
1409 EXPECT_FALSE(audio_frame_with_data.has_value());
1410 EXPECT_FALSE(parameter_block_with_data.has_value());
1411 EXPECT_FALSE(temporal_delimiter.has_value());
1412 EXPECT_FALSE(continue_processing);
1413 EXPECT_EQ(read_bit_buffer->Tell(), start_position);
1414 }
1415
1416 using OutputTemporalUnit = ObuProcessor::OutputTemporalUnit;
1417
TEST(ProcessTemporalUnit,ConsumesOneAudioFrameAsTemporalUnit)1418 TEST(ProcessTemporalUnit, ConsumesOneAudioFrameAsTemporalUnit) {
1419 // Set up inputs with a single audio frame.
1420 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1421 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
1422 kArbitraryAudioFrame);
1423 auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
1424 bitstream.insert(bitstream.end(), temporal_unit_obus.begin(),
1425 temporal_unit_obus.end());
1426 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1427 kBufferCapacity, absl::MakeConstSpan(bitstream));
1428 bool insufficient_data;
1429 auto obu_processor =
1430 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1431 read_bit_buffer.get(), insufficient_data);
1432 ASSERT_THAT(obu_processor, NotNull());
1433 ASSERT_FALSE(insufficient_data);
1434
1435 // Call `ProcessTemporalUnit()` with `eos_is_end_of_sequence` set to true.
1436 // This means that we can assume that the end of the stream implies the end of
1437 // the temporal unit.
1438 std::optional<OutputTemporalUnit> output_temporal_unit;
1439 bool continue_processing = true;
1440 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1441 /*eos_is_end_of_sequence=*/true, output_temporal_unit,
1442 continue_processing),
1443 IsOk());
1444
1445 EXPECT_FALSE(continue_processing);
1446 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1447 }
1448
TEST(ProcessTemporalUnit,DoesNotConsumeOneAudioFrameAsTemporalUnit)1449 TEST(ProcessTemporalUnit, DoesNotConsumeOneAudioFrameAsTemporalUnit) {
1450 // Set up inputs with a single audio frame.
1451 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1452 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
1453 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8});
1454 auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
1455 bitstream.insert(bitstream.end(), temporal_unit_obus.begin(),
1456 temporal_unit_obus.end());
1457 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1458 kBufferCapacity, absl::MakeConstSpan(bitstream));
1459 bool insufficient_data;
1460 auto obu_processor =
1461 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1462 read_bit_buffer.get(), insufficient_data);
1463 ASSERT_THAT(obu_processor, NotNull());
1464 ASSERT_FALSE(insufficient_data);
1465
1466 std::optional<OutputTemporalUnit> output_temporal_unit;
1467 bool continue_processing = true;
1468 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1469 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1470 continue_processing),
1471 IsOk());
1472
1473 EXPECT_FALSE(continue_processing);
1474 EXPECT_FALSE(output_temporal_unit.has_value());
1475 }
1476
TEST(ProcessTemporalUnit,ConsumesMultipleTemporalUnitsWithTemporalDelimiters)1477 TEST(ProcessTemporalUnit, ConsumesMultipleTemporalUnitsWithTemporalDelimiters) {
1478 // Set up inputs with two audio frames and temporal delimiters.
1479 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1480 auto temporal_delimiter_obu = TemporalDelimiterObu(ObuHeader());
1481 std::vector<AudioFrameObu> audio_frame_obus;
1482 audio_frame_obus.push_back(
1483 AudioFrameObu(ObuHeader(), kFirstSubstreamId, kArbitraryAudioFrame));
1484 audio_frame_obus.push_back(
1485 AudioFrameObu(ObuHeader(), kFirstSubstreamId, kArbitraryAudioFrame));
1486 const auto two_temporal_units_with_delimiter_obu =
1487 SerializeObusExpectOk({&audio_frame_obus[0], &temporal_delimiter_obu,
1488 &audio_frame_obus[1], &temporal_delimiter_obu});
1489 bitstream.insert(bitstream.end(),
1490 two_temporal_units_with_delimiter_obu.begin(),
1491 two_temporal_units_with_delimiter_obu.end());
1492 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1493 kBufferCapacity, absl::MakeConstSpan(bitstream));
1494 bool insufficient_data;
1495 auto obu_processor =
1496 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1497 read_bit_buffer.get(), insufficient_data);
1498 ASSERT_THAT(obu_processor, NotNull());
1499 ASSERT_FALSE(insufficient_data);
1500
1501 std::optional<OutputTemporalUnit> output_temporal_unit;
1502 bool continue_processing = true;
1503 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1504 /*eos_is_end_of_sequence=*/true, output_temporal_unit,
1505 continue_processing),
1506 IsOk());
1507
1508 // The first temporal unit is consumed; it should only contain the first
1509 // audio frame.
1510 EXPECT_TRUE(continue_processing);
1511 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1512
1513 output_temporal_unit.reset();
1514 continue_processing = true;
1515 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1516 /*eos_is_end_of_sequence=*/true, output_temporal_unit,
1517 continue_processing),
1518 IsOk());
1519 // Seeing a temporal delimiter at the end of the stream implies that the
1520 // stream is incomplete.
1521 EXPECT_TRUE(continue_processing);
1522 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1523 }
1524
TEST(ProcessTemporalUnit,ConsumesMultipleTemporalUnitsWithoutTemporalDelimiters)1525 TEST(ProcessTemporalUnit,
1526 ConsumesMultipleTemporalUnitsWithoutTemporalDelimiters) {
1527 // Set up inputs with two audio frames. Two audio frames are known to be in a
1528 // separate temporal unit if they have the same substream ID. Their underlying
1529 // timestamps are different.
1530 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1531 std::vector<AudioFrameObu> audio_frame_obus;
1532 audio_frame_obus.push_back(
1533 AudioFrameObu(ObuHeader(), kFirstSubstreamId, kArbitraryAudioFrame));
1534 audio_frame_obus.push_back(
1535 AudioFrameObu(ObuHeader(), kFirstSubstreamId, kArbitraryAudioFrame));
1536 const auto two_temporal_units =
1537 SerializeObusExpectOk({&audio_frame_obus[0], &audio_frame_obus[1]});
1538 bitstream.insert(bitstream.end(), two_temporal_units.begin(),
1539 two_temporal_units.end());
1540 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1541 kBufferCapacity, absl::MakeConstSpan(bitstream));
1542 bool insufficient_data;
1543 auto obu_processor =
1544 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1545 read_bit_buffer.get(), insufficient_data);
1546 ASSERT_THAT(obu_processor, NotNull());
1547 ASSERT_FALSE(insufficient_data);
1548
1549 std::optional<OutputTemporalUnit> output_temporal_unit;
1550 bool continue_processing = true;
1551 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1552 /*eos_is_end_of_sequence=*/true, output_temporal_unit,
1553 continue_processing),
1554 IsOk());
1555
1556 // The first temporal unit is consumed; it should only contain the first
1557 // audio frame.
1558 EXPECT_TRUE(continue_processing);
1559 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1560
1561 output_temporal_unit.reset();
1562 continue_processing = true;
1563 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1564 /*eos_is_end_of_sequence=*/true, output_temporal_unit,
1565 continue_processing),
1566 IsOk());
1567
1568 EXPECT_FALSE(continue_processing);
1569 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1570 }
1571
TEST(ProcessTemporalUnit,ConsumesOnlyOneTemporalUnitFromTwoAudioFrames)1572 TEST(ProcessTemporalUnit, ConsumesOnlyOneTemporalUnitFromTwoAudioFrames) {
1573 // eos_is_end_of_sequence is false. Only one temporal unit is consumed because
1574 // we don't know that the second temporal unit is finished.
1575
1576 // Set up inputs with two audio frames. Two audio
1577 // frames are known to be in a separate temporal unit if they have the same
1578 // substream ID. Their underlying timestamps are different.
1579 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1580 std::vector<AudioFrameObu> audio_frame_obus;
1581 audio_frame_obus.push_back(
1582 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1583 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1584 audio_frame_obus.push_back(
1585 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1586 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1587 const auto two_temporal_units =
1588 SerializeObusExpectOk({&audio_frame_obus[0], &audio_frame_obus[1]});
1589 bitstream.insert(bitstream.end(), two_temporal_units.begin(),
1590 two_temporal_units.end());
1591 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1592 kBufferCapacity, absl::MakeConstSpan(bitstream));
1593 bool insufficient_data;
1594 auto obu_processor =
1595 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1596 read_bit_buffer.get(), insufficient_data);
1597 ASSERT_THAT(obu_processor, NotNull());
1598 ASSERT_FALSE(insufficient_data);
1599
1600 std::optional<OutputTemporalUnit> output_temporal_unit;
1601 bool continue_processing = true;
1602 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1603 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1604 continue_processing),
1605 IsOk());
1606
1607 // The first temporal unit is consumed; it should only contain the first
1608 // audio frame.
1609 EXPECT_TRUE(continue_processing);
1610 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1611
1612 output_temporal_unit.reset();
1613 continue_processing = true;
1614 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1615 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1616 continue_processing),
1617 IsOk());
1618
1619 EXPECT_FALSE(continue_processing);
1620 EXPECT_FALSE(output_temporal_unit.has_value());
1621 }
1622
TEST(ProcessTemporalUnit,ConsumesOnlyOneTemporalUnitFromTwoAudioFramesAndIncompleteObuAtEnd)1623 TEST(ProcessTemporalUnit,
1624 ConsumesOnlyOneTemporalUnitFromTwoAudioFramesAndIncompleteObuAtEnd) {
1625 // eos_is_end_of_sequence is false. Only one temporal unit is consumed because
1626 // we don't know that the second temporal unit is finished.
1627
1628 // Set up inputs with two audio frames. Two audio
1629 // frames are known to be in a separate temporal unit if they have the same
1630 // substream ID. Their underlying timestamps are different.
1631 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1632 std::vector<AudioFrameObu> audio_frame_obus;
1633 audio_frame_obus.push_back(
1634 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1635 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1636 audio_frame_obus.push_back(
1637 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1638 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1639 auto two_temporal_units =
1640 SerializeObusExpectOk({&audio_frame_obus[0], &audio_frame_obus[1]});
1641 std::vector<uint8_t> extra_audio_frame_obu_header_bytes = {
1642 kObuIaAudioFrameId0 << kObuTypeBitShift,
1643 // `obu_size`. -> Non-zero size, but we have no bytes following.
1644 0x7f};
1645 two_temporal_units.insert(two_temporal_units.end(),
1646 extra_audio_frame_obu_header_bytes.begin(),
1647 extra_audio_frame_obu_header_bytes.end());
1648 bitstream.insert(bitstream.end(), two_temporal_units.begin(),
1649 two_temporal_units.end());
1650 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1651 kBufferCapacity, absl::MakeConstSpan(bitstream));
1652 bool insufficient_data;
1653 auto obu_processor =
1654 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1655 read_bit_buffer.get(), insufficient_data);
1656 ASSERT_THAT(obu_processor, NotNull());
1657 ASSERT_FALSE(insufficient_data);
1658
1659 std::optional<OutputTemporalUnit> output_temporal_unit;
1660 bool continue_processing = false;
1661 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1662 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1663 continue_processing),
1664 IsOk());
1665
1666 // The first temporal unit is consumed; it should only contain the first
1667 // audio frame.
1668 EXPECT_TRUE(continue_processing);
1669 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1670
1671 output_temporal_unit.reset();
1672 continue_processing = true;
1673 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1674 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1675 continue_processing),
1676 IsOk());
1677
1678 // The second temporal unit is not consumed since we don't know that it is
1679 // complete.
1680 EXPECT_FALSE(continue_processing);
1681 EXPECT_FALSE(output_temporal_unit.has_value());
1682 }
1683
TEST(ProcessTemporalUnit,ConsumesMultipleTemporalUnitsChunkedArbitrarily)1684 TEST(ProcessTemporalUnit, ConsumesMultipleTemporalUnitsChunkedArbitrarily) {
1685 // Set up inputs with two audio frames. Two audio frames are known to be in a
1686 // separate temporal unit if they have the same substream ID. Their underlying
1687 // timestamps are different.
1688 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1689 auto read_bit_buffer = StreamBasedReadBitBuffer::Create(kBufferCapacity);
1690 // Push descriptors.
1691 ASSERT_THAT(read_bit_buffer->PushBytes(bitstream), IsOk());
1692 bool insufficient_data;
1693 auto obu_processor =
1694 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
1695 read_bit_buffer.get(), insufficient_data);
1696 ASSERT_THAT(obu_processor, NotNull());
1697 ASSERT_FALSE(insufficient_data);
1698
1699 std::vector<AudioFrameObu> audio_frame_obus;
1700 audio_frame_obus.push_back(
1701 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1702 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1703 audio_frame_obus.push_back(
1704 AudioFrameObu(ObuHeader(), kFirstSubstreamId,
1705 /*audio_frame=*/{2, 3, 4, 5, 6, 7, 8}));
1706 const auto two_temporal_units =
1707 SerializeObusExpectOk({&audio_frame_obus[0], &audio_frame_obus[1]});
1708
1709 // Split the temporal units into three chunks.
1710 const int64_t chunk_size = two_temporal_units.size() / 3;
1711 std::vector<uint8_t> chunk_1(two_temporal_units.begin(),
1712 two_temporal_units.begin() + chunk_size);
1713 std::vector<uint8_t> chunk_2(two_temporal_units.begin() + chunk_size,
1714 two_temporal_units.begin() + 2 * chunk_size);
1715 std::vector<uint8_t> chunk_3(two_temporal_units.begin() + 2 * chunk_size,
1716 two_temporal_units.end());
1717
1718 // Chunk 1.
1719 ASSERT_THAT(read_bit_buffer->PushBytes(chunk_1), IsOk());
1720 std::optional<OutputTemporalUnit> output_temporal_unit;
1721 bool continue_processing = true;
1722 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1723 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1724 continue_processing),
1725 IsOk());
1726
1727 // Chunk 1 is not enough to finish reading the first audio frame, so the
1728 // first temporal unit is not finished.
1729 EXPECT_FALSE(continue_processing);
1730 EXPECT_FALSE(output_temporal_unit.has_value());
1731
1732 // Chunk 2.
1733 ASSERT_THAT(read_bit_buffer->PushBytes(chunk_2), IsOk());
1734 continue_processing = true;
1735 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1736 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1737 continue_processing),
1738 IsOk());
1739
1740 // Chunk 2 is enough to finish reading the first audio frame, but not the
1741 // second. Since we haven't finished reading the second audio frame, we cannot
1742 // know that the first temporal unit is complete. Therefore we still do not
1743 // have a temporal unit.
1744 EXPECT_FALSE(continue_processing);
1745 EXPECT_FALSE(output_temporal_unit.has_value());
1746
1747 // Chunk 3.
1748 ASSERT_THAT(read_bit_buffer->PushBytes(chunk_3), IsOk());
1749 continue_processing = true;
1750 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1751 /*eos_is_end_of_sequence=*/false, output_temporal_unit,
1752 continue_processing),
1753 IsOk());
1754
1755 // Chunk 3 is enough to finish reading the second audio frame, so the first
1756 // temporal unit is now complete. But we don't know that the second temporal
1757 // unit is complete since more data could be coming behind it.
1758 EXPECT_TRUE(continue_processing);
1759 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1760
1761 // To get the second temporal unit, we make one final call with
1762 // `eos_is_end_of_sequence` set to true. At this point, the bitstream is
1763 // exhausted, but we can get the second temporal unit that we previously
1764 // processed since we now know that the sequence is complete.
1765 continue_processing = true;
1766 output_temporal_unit.reset();
1767 EXPECT_THAT(obu_processor->ProcessTemporalUnit(
1768 /*eos_is_end_of_sequence=*/true, output_temporal_unit,
1769 continue_processing),
1770 IsOk());
1771
1772 EXPECT_FALSE(continue_processing);
1773 EXPECT_EQ(output_temporal_unit->output_audio_frames.size(), 1);
1774 }
1775
1776 // TODO(b/377772983): Test rejecting processing temporal units with mismatching
1777 // durations from parameter blocks and audio frames.
1778 // TODO(b/377772983): Test rejecting processing temporal units where the
1779 // required descriptors (audio elements, codec configs, etc.)
1780 // are not present.
1781
1782 constexpr bool kWriteWavHeader = true;
1783 constexpr bool kDontWriteWavHeader = false;
1784 constexpr Layout kStereoLayout = {
1785 .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
1786 .specific_layout = LoudspeakersSsConventionLayout{
1787 .sound_system = LoudspeakersSsConventionLayout::kSoundSystemA_0_2_0}};
1788
TEST(CollectObusFromIaSequence,ConsumesIaSequenceAndCollectsAllObus)1789 TEST(CollectObusFromIaSequence, ConsumesIaSequenceAndCollectsAllObus) {
1790 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1791 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
1792 kArbitraryAudioFrame);
1793 const auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
1794 bitstream.insert(bitstream.end(), temporal_unit_obus.begin(),
1795 temporal_unit_obus.end());
1796 const int64_t ia_sequence_size = bitstream.size();
1797
1798 IASequenceHeaderObu ia_sequence_header;
1799 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1800 absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
1801 std::list<MixPresentationObu> mix_presentation_obus;
1802 std::list<AudioFrameWithData> audio_frames;
1803 std::list<ParameterBlockWithData> parameter_blocks;
1804 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1805 kBufferCapacity, absl::MakeConstSpan(bitstream));
1806 EXPECT_THAT(CollectObusFromIaSequence(*read_bit_buffer, ia_sequence_header,
1807 codec_config_obus, audio_elements,
1808 mix_presentation_obus, audio_frames,
1809 parameter_blocks),
1810 IsOk());
1811 EXPECT_EQ(read_bit_buffer->Tell(), ia_sequence_size * 8);
1812
1813 // Reaching the end of the stream.
1814 EXPECT_FALSE(read_bit_buffer->IsDataAvailable());
1815 EXPECT_TRUE(codec_config_obus.contains(kFirstCodecConfigId));
1816 EXPECT_TRUE(audio_elements.contains(kFirstAudioElementId));
1817 EXPECT_FALSE(mix_presentation_obus.empty());
1818 EXPECT_EQ(mix_presentation_obus.front().GetMixPresentationId(),
1819 kFirstMixPresentationId);
1820 EXPECT_FALSE(audio_frames.empty());
1821 EXPECT_EQ(audio_frames.front().obu.GetSubstreamId(), kFirstSubstreamId);
1822 EXPECT_TRUE(parameter_blocks.empty());
1823 }
1824
TEST(CollectObusFromIaSequence,ConsumesTrivialIaSequence)1825 TEST(CollectObusFromIaSequence, ConsumesTrivialIaSequence) {
1826 const IASequenceHeaderObu input_non_redundant_ia_sequence_header(
1827 ObuHeader(), IASequenceHeaderObu::kIaCode,
1828 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1829 const auto trivial_ia_sequence =
1830 SerializeObusExpectOk({&input_non_redundant_ia_sequence_header});
1831 auto non_trivial_ia_sequence = InitAllDescriptorsForZerothOrderAmbisonics();
1832 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
1833 kArbitraryAudioFrame);
1834 const auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
1835 non_trivial_ia_sequence.insert(non_trivial_ia_sequence.end(),
1836 temporal_unit_obus.begin(),
1837 temporal_unit_obus.end());
1838 std::vector<uint8_t> two_ia_sequences(trivial_ia_sequence);
1839 const int64_t trivial_ia_sequence_size = trivial_ia_sequence.size();
1840
1841 two_ia_sequences.insert(two_ia_sequences.end(),
1842 non_trivial_ia_sequence.begin(),
1843 non_trivial_ia_sequence.end());
1844 const int64_t two_ia_sequences_size = two_ia_sequences.size();
1845
1846 IASequenceHeaderObu ia_sequence_header;
1847 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1848 absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
1849 std::list<MixPresentationObu> mix_presentation_obus;
1850 std::list<AudioFrameWithData> audio_frames;
1851 std::list<ParameterBlockWithData> parameter_blocks;
1852 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1853 kBufferCapacity, absl::MakeConstSpan(two_ia_sequences));
1854 EXPECT_THAT(CollectObusFromIaSequence(*read_bit_buffer, ia_sequence_header,
1855 codec_config_obus, audio_elements,
1856 mix_presentation_obus, audio_frames,
1857 parameter_blocks),
1858 IsOk());
1859 EXPECT_EQ(read_bit_buffer->Tell(), trivial_ia_sequence_size * 8);
1860
1861 // The first IA sequence is trivial and should be consumed.
1862 EXPECT_TRUE(codec_config_obus.empty());
1863 EXPECT_TRUE(audio_elements.empty());
1864 EXPECT_TRUE(mix_presentation_obus.empty());
1865 EXPECT_TRUE(audio_frames.empty());
1866 EXPECT_TRUE(parameter_blocks.empty());
1867
1868 // A second call retrieves the next IA sequence, which has an audio frame.
1869 EXPECT_THAT(CollectObusFromIaSequence(*read_bit_buffer, ia_sequence_header,
1870 codec_config_obus, audio_elements,
1871 mix_presentation_obus, audio_frames,
1872 parameter_blocks),
1873 IsOk());
1874 EXPECT_FALSE(audio_frames.empty());
1875 EXPECT_EQ(read_bit_buffer->Tell(), two_ia_sequences_size * 8);
1876 }
1877
TEST(CollectObusFromIaSequence,ConsumesUpToNextIaSequence)1878 TEST(CollectObusFromIaSequence, ConsumesUpToNextIaSequence) {
1879 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1880 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
1881 kArbitraryAudioFrame);
1882 const auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
1883 bitstream.insert(bitstream.end(), temporal_unit_obus.begin(),
1884 temporal_unit_obus.end());
1885 const int64_t first_ia_sequence_size = bitstream.size();
1886 const IASequenceHeaderObu non_redundant_ia_sequence_header(
1887 ObuHeader{.obu_redundant_copy = false}, IASequenceHeaderObu::kIaCode,
1888 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1889 const auto start_of_second_ia_sequence =
1890 SerializeObusExpectOk({&non_redundant_ia_sequence_header});
1891 bitstream.insert(bitstream.end(), start_of_second_ia_sequence.begin(),
1892 start_of_second_ia_sequence.end());
1893
1894 IASequenceHeaderObu ia_sequence_header;
1895 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1896 absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
1897 std::list<MixPresentationObu> mix_presentation_obus;
1898 std::list<AudioFrameWithData> audio_frames;
1899 std::list<ParameterBlockWithData> parameter_blocks;
1900 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1901 kBufferCapacity, absl::MakeConstSpan(bitstream));
1902 EXPECT_THAT(CollectObusFromIaSequence(*read_bit_buffer, ia_sequence_header,
1903 codec_config_obus, audio_elements,
1904 mix_presentation_obus, audio_frames,
1905 parameter_blocks),
1906 IsOk());
1907
1908 // Expect the reader position to be right next to the end of the first IA
1909 // sequence.
1910 EXPECT_EQ(read_bit_buffer->Tell(), first_ia_sequence_size * 8);
1911 }
1912
TEST(Create,Succeeds)1913 TEST(Create, Succeeds) {
1914 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1915 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1916 kBufferCapacity, absl::MakeConstSpan(bitstream));
1917 bool insufficient_data;
1918
1919 auto obu_processor =
1920 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
1921 read_bit_buffer.get(), insufficient_data);
1922
1923 EXPECT_THAT(obu_processor, NotNull());
1924 EXPECT_FALSE(insufficient_data);
1925 EXPECT_EQ(obu_processor->audio_elements_.size(), 1);
1926 EXPECT_EQ(obu_processor->codec_config_obus_.size(), 1);
1927 EXPECT_EQ(obu_processor->mix_presentations_.size(), 1);
1928 }
1929
TEST(Create,SucceedsForTrivialIaSequence)1930 TEST(Create, SucceedsForTrivialIaSequence) {
1931 const IASequenceHeaderObu kIaSequenceHeader(
1932 ObuHeader(), IASequenceHeaderObu::kIaCode,
1933 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1934 auto buffer = SerializeObusExpectOk({&kIaSequenceHeader});
1935 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1936 kBufferCapacity, absl::MakeConstSpan(buffer));
1937 bool insufficient_data;
1938 auto obu_processor =
1939 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
1940 read_bit_buffer.get(), insufficient_data);
1941
1942 EXPECT_THAT(obu_processor, NotNull());
1943 EXPECT_FALSE(insufficient_data);
1944 }
1945
TEST(Create,FailsOnNullReadBitBuffer)1946 TEST(Create, FailsOnNullReadBitBuffer) {
1947 bool insufficient_data;
1948
1949 auto obu_processor = ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1950 nullptr, insufficient_data);
1951
1952 EXPECT_THAT(obu_processor, IsNull());
1953 EXPECT_FALSE(insufficient_data);
1954 }
1955
TEST(Create,FailsOnInsufficientData)1956 TEST(Create, FailsOnInsufficientData) {
1957 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
1958 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1959 kBufferCapacity, absl::MakeConstSpan(bitstream));
1960 bool insufficient_data;
1961
1962 auto obu_processor =
1963 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
1964 read_bit_buffer.get(), insufficient_data);
1965
1966 EXPECT_THAT(obu_processor, IsNull());
1967 // We've received a valid bitstream so far but not complete.
1968 EXPECT_TRUE(insufficient_data);
1969 }
1970
TEST(GetOutputSampleRate,ReturnsSampleRateBasedOnCodecConfigObu)1971 TEST(GetOutputSampleRate, ReturnsSampleRateBasedOnCodecConfigObu) {
1972 const IASequenceHeaderObu kIaSequenceHeader(
1973 ObuHeader(), IASequenceHeaderObu::kIaCode,
1974 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1975 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
1976 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
1977 codec_config_obus);
1978 const auto buffer = SerializeObusExpectOk(
1979 {&kIaSequenceHeader, &codec_config_obus.at(kFirstCodecConfigId)});
1980 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1981 kBufferCapacity, absl::MakeConstSpan(buffer));
1982 bool insufficient_data;
1983 auto obu_processor =
1984 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
1985 read_bit_buffer.get(), insufficient_data);
1986 ASSERT_THAT(obu_processor, NotNull());
1987
1988 EXPECT_THAT(obu_processor->GetOutputSampleRate(), IsOkAndHolds(kSampleRate));
1989 }
1990
TEST(GetOutputSampleRate,FailsForTrivialIaSequence)1991 TEST(GetOutputSampleRate, FailsForTrivialIaSequence) {
1992 const IASequenceHeaderObu kIaSequenceHeader(
1993 ObuHeader(), IASequenceHeaderObu::kIaCode,
1994 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
1995 const auto buffer = SerializeObusExpectOk({&kIaSequenceHeader});
1996 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
1997 kBufferCapacity, absl::MakeConstSpan(buffer));
1998 bool insufficient_data;
1999 auto obu_processor =
2000 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
2001 read_bit_buffer.get(), insufficient_data);
2002 ASSERT_THAT(obu_processor, NotNull());
2003
2004 EXPECT_THAT(obu_processor->GetOutputSampleRate(), Not(IsOk()));
2005 }
2006
TEST(GetOutputSampleRate,FailsForMultipleCodecConfigObus)2007 TEST(GetOutputSampleRate, FailsForMultipleCodecConfigObus) {
2008 const IASequenceHeaderObu kIaSequenceHeader(
2009 ObuHeader(), IASequenceHeaderObu::kIaCode,
2010 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
2011 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2012 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2013 codec_config_obus);
2014 AddLpcmCodecConfigWithIdAndSampleRate(kSecondCodecConfigId, kSampleRate,
2015 codec_config_obus);
2016 const auto buffer = SerializeObusExpectOk(
2017 {&kIaSequenceHeader, &codec_config_obus.at(kFirstCodecConfigId),
2018 &codec_config_obus.at(kSecondCodecConfigId)});
2019 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2020 kBufferCapacity, absl::MakeConstSpan(buffer));
2021 bool insufficient_data;
2022 auto obu_processor =
2023 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
2024 read_bit_buffer.get(), insufficient_data);
2025 ASSERT_THAT(obu_processor, NotNull());
2026
2027 EXPECT_THAT(obu_processor->GetOutputSampleRate(), Not(IsOk()));
2028 }
2029
TEST(GetOutputFrameSize,ReturnsSampleRateBasedOnCodecConfigObu)2030 TEST(GetOutputFrameSize, ReturnsSampleRateBasedOnCodecConfigObu) {
2031 const IASequenceHeaderObu kIaSequenceHeader(
2032 ObuHeader(), IASequenceHeaderObu::kIaCode,
2033 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
2034 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2035 AddLpcmCodecConfig(kFirstCodecConfigId, kFrameSize, kBitDepth, kSampleRate,
2036 codec_config_obus);
2037 const auto buffer = SerializeObusExpectOk(
2038 {&kIaSequenceHeader, &codec_config_obus.at(kFirstCodecConfigId)});
2039 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2040 kBufferCapacity, absl::MakeConstSpan(buffer));
2041 bool insufficient_data;
2042 auto obu_processor =
2043 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
2044 read_bit_buffer.get(), insufficient_data);
2045 ASSERT_THAT(obu_processor, NotNull());
2046
2047 EXPECT_THAT(obu_processor->GetOutputSampleRate(), IsOkAndHolds(kSampleRate));
2048 }
2049
TEST(GetOutputFrameSize,FailsForTrivialIaSequence)2050 TEST(GetOutputFrameSize, FailsForTrivialIaSequence) {
2051 const IASequenceHeaderObu kIaSequenceHeader(
2052 ObuHeader(), IASequenceHeaderObu::kIaCode,
2053 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
2054 const auto buffer = SerializeObusExpectOk({&kIaSequenceHeader});
2055 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2056 kBufferCapacity, absl::MakeConstSpan(buffer));
2057 bool insufficient_data;
2058 auto obu_processor =
2059 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
2060 read_bit_buffer.get(), insufficient_data);
2061 ASSERT_THAT(obu_processor, NotNull());
2062
2063 EXPECT_THAT(obu_processor->GetOutputFrameSize(), Not(IsOk()));
2064 }
2065
TEST(GetOutputFrameSize,FailsForMultipleCodecConfigObus)2066 TEST(GetOutputFrameSize, FailsForMultipleCodecConfigObus) {
2067 const IASequenceHeaderObu kIaSequenceHeader(
2068 ObuHeader(), IASequenceHeaderObu::kIaCode,
2069 ProfileVersion::kIamfSimpleProfile, ProfileVersion::kIamfBaseProfile);
2070 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2071 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2072 codec_config_obus);
2073 AddLpcmCodecConfigWithIdAndSampleRate(kSecondCodecConfigId, kSampleRate,
2074 codec_config_obus);
2075 const auto buffer = SerializeObusExpectOk(
2076 {&kIaSequenceHeader, &codec_config_obus.at(kFirstCodecConfigId),
2077 &codec_config_obus.at(kSecondCodecConfigId)});
2078 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2079 kBufferCapacity, absl::MakeConstSpan(buffer));
2080 bool insufficient_data;
2081 auto obu_processor =
2082 ObuProcessor::Create(/*is_exhaustive_and_exact=*/true,
2083 read_bit_buffer.get(), insufficient_data);
2084 ASSERT_THAT(obu_processor, NotNull());
2085
2086 EXPECT_THAT(obu_processor->GetOutputFrameSize(), Not(IsOk()));
2087 }
2088
TEST(NonStatic,ProcessTemporalUnitObu)2089 TEST(NonStatic, ProcessTemporalUnitObu) {
2090 auto bitstream = InitAllDescriptorsForZerothOrderAmbisonics();
2091 AudioFrameObu audio_frame_obu(ObuHeader(), kFirstSubstreamId,
2092 kArbitraryAudioFrame);
2093 const auto temporal_unit_obus = SerializeObusExpectOk({&audio_frame_obu});
2094 bitstream.insert(bitstream.end(), temporal_unit_obus.begin(),
2095 temporal_unit_obus.end());
2096
2097 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2098 kBufferCapacity, absl::MakeConstSpan(bitstream));
2099 bool insufficient_data;
2100
2101 auto obu_processor =
2102 ObuProcessor::Create(/*is_exhaustive_and_exact=*/false,
2103 read_bit_buffer.get(), insufficient_data);
2104 ASSERT_THAT(obu_processor, NotNull());
2105 ASSERT_FALSE(insufficient_data);
2106
2107 std::optional<AudioFrameWithData> audio_frame_with_data;
2108 std::optional<ParameterBlockWithData> parameter_block_with_data;
2109 std::optional<TemporalDelimiterObu> temporal_delimiter;
2110 bool continue_processing = true;
2111 EXPECT_THAT(obu_processor->ProcessTemporalUnitObu(
2112 audio_frame_with_data, parameter_block_with_data,
2113 temporal_delimiter, continue_processing),
2114 IsOk());
2115
2116 EXPECT_TRUE(audio_frame_with_data.has_value());
2117 EXPECT_FALSE(parameter_block_with_data.has_value());
2118 EXPECT_FALSE(temporal_delimiter.has_value());
2119 EXPECT_TRUE(continue_processing);
2120 }
2121
2122 // TODO(b/381068413): Add more tests for the new iterative API.
RenderUsingObuProcessorExpectOk(absl::string_view output_filename,bool write_wav_header,const std::optional<uint8_t> output_file_bit_depth_override,const std::list<AudioFrameWithData> & audio_frames,const std::list<ParameterBlockWithData> & parameter_blocks,const std::vector<uint8_t> & bitstream_of_descriptors)2123 void RenderUsingObuProcessorExpectOk(
2124 absl::string_view output_filename, bool write_wav_header,
2125 const std::optional<uint8_t> output_file_bit_depth_override,
2126 const std::list<AudioFrameWithData>& audio_frames,
2127 const std::list<ParameterBlockWithData>& parameter_blocks,
2128 const std::vector<uint8_t>& bitstream_of_descriptors) {
2129 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2130 kBufferCapacity, absl::MakeConstSpan(bitstream_of_descriptors));
2131 bool insufficient_data;
2132
2133 const std::string output_filename_string(output_filename);
2134 Layout unused_output_layout;
2135 auto obu_processor = ObuProcessor::CreateForRendering(
2136 kStereoLayout,
2137 CreateAllWavWriters(output_filename_string, write_wav_header),
2138 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2139 unused_output_layout, insufficient_data);
2140 ASSERT_THAT(obu_processor, NotNull());
2141 ASSERT_FALSE(insufficient_data);
2142 absl::Span<const std::vector<int32_t>> output_rendered_pcm_samples;
2143 EXPECT_THAT(obu_processor->RenderTemporalUnitAndMeasureLoudness(
2144 /*timestamp=*/0, audio_frames, parameter_blocks,
2145 output_rendered_pcm_samples),
2146 IsOk());
2147 EXPECT_TRUE(output_rendered_pcm_samples.empty());
2148 }
2149
RenderOneSampleFoaToStereoWavExpectOk(absl::string_view output_filename,bool write_wav_header,std::optional<uint8_t> output_file_bit_depth_override)2150 void RenderOneSampleFoaToStereoWavExpectOk(
2151 absl::string_view output_filename, bool write_wav_header,
2152 std::optional<uint8_t> output_file_bit_depth_override) {
2153 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2154 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2155 codec_config_obus);
2156 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2157 audio_elements_with_data;
2158 AddAmbisonicsMonoAudioElementWithSubstreamIds(
2159 kFirstAudioElementId, kFirstCodecConfigId, {kFirstSubstreamId},
2160 codec_config_obus, audio_elements_with_data);
2161 std::list<MixPresentationObu> mix_presentation_obus;
2162 AddMixPresentationObuWithAudioElementIds(
2163 kFirstMixPresentationId, {kFirstAudioElementId},
2164 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2165 std::list<AudioFrameWithData> audio_frames_with_data;
2166 const auto* common_audio_element_with_data =
2167 &audio_elements_with_data.at(kFirstAudioElementId);
2168 audio_frames_with_data.push_back(AudioFrameWithData{
2169 .obu =
2170 AudioFrameObu(ObuHeader(), kFirstSubstreamId, /*audio_frame=*/{0, 0}),
2171 .start_timestamp = 0,
2172 .end_timestamp = 1,
2173 .audio_element_with_data = common_audio_element_with_data,
2174 });
2175 // Create a single parameter block consistent with the mix presentation OBU.
2176 std::list<ParameterBlockWithData> parameter_blocks_with_data = {};
2177 auto parameter_block = std::make_unique<ParameterBlockObu>(
2178 ObuHeader(), kCommonMixGainParameterId,
2179 mix_presentation_obus.front().sub_mixes_[0].output_mix_gain);
2180 EXPECT_THAT(parameter_block->InitializeSubblocks(1, 1, 1), IsOk());
2181 parameter_block->subblocks_[0].param_data =
2182 std::make_unique<MixGainParameterData>(
2183 MixGainParameterData::kAnimateStep,
2184 AnimationStepInt16{.start_point_value = 99});
2185 parameter_blocks_with_data.push_back(ParameterBlockWithData{
2186 .obu = std::move(parameter_block),
2187 .start_timestamp = 0,
2188 .end_timestamp = 1,
2189 });
2190
2191 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2192 {&codec_config_obus.at(kFirstCodecConfigId),
2193 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2194 &mix_presentation_obus.front()});
2195 RenderUsingObuProcessorExpectOk(
2196 output_filename, write_wav_header, output_file_bit_depth_override,
2197 audio_frames_with_data, parameter_blocks_with_data, bitstream);
2198 }
TEST(RenderAudioFramesWithDataAndMeasureLoudness,RenderingNothingReturnsOk)2199 TEST(RenderAudioFramesWithDataAndMeasureLoudness, RenderingNothingReturnsOk) {
2200 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2201 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2202 codec_config_obus);
2203 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2204 audio_elements_with_data;
2205 AddAmbisonicsMonoAudioElementWithSubstreamIds(
2206 kFirstAudioElementId, kFirstCodecConfigId,
2207 {kFirstSubstreamId, kSecondSubstreamId, kThirdSubstreamId,
2208 kFourthSubstreamId},
2209 codec_config_obus, audio_elements_with_data);
2210 std::list<MixPresentationObu> mix_presentation_obus;
2211 AddMixPresentationObuWithAudioElementIds(
2212 kFirstMixPresentationId, {kFirstAudioElementId},
2213 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2214
2215 const std::list<AudioFrameWithData> empty_audio_frames_with_data = {};
2216 const std::list<ParameterBlockWithData> empty_parameter_blocks_with_data = {};
2217 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2218 {&codec_config_obus.at(kFirstCodecConfigId),
2219 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2220 &mix_presentation_obus.front()});
2221 RenderUsingObuProcessorExpectOk("unused_filename", kDontWriteWavHeader,
2222 kNoOutputFileBitDepthOverride,
2223 empty_audio_frames_with_data,
2224 empty_parameter_blocks_with_data, bitstream);
2225 }
2226
TEST(RenderAudioFramesWithDataAndMeasureLoudness,RendersFoaToStereoWav)2227 TEST(RenderAudioFramesWithDataAndMeasureLoudness, RendersFoaToStereoWav) {
2228 const auto output_filename = GetAndCleanupOutputFileName(".wav");
2229 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2230 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2231 codec_config_obus);
2232 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2233 audio_elements_with_data;
2234 AddAmbisonicsMonoAudioElementWithSubstreamIds(
2235 kFirstAudioElementId, kFirstCodecConfigId,
2236 {kFirstSubstreamId, kSecondSubstreamId, kThirdSubstreamId,
2237 kFourthSubstreamId},
2238 codec_config_obus, audio_elements_with_data);
2239 std::list<MixPresentationObu> mix_presentation_obus;
2240 AddMixPresentationObuWithAudioElementIds(
2241 kFirstMixPresentationId, {kFirstAudioElementId},
2242 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2243 std::list<AudioFrameWithData> audio_frames_with_data;
2244 const std::list<ParameterBlockWithData> parameter_blocks_with_data = {};
2245 const auto* common_audio_element_with_data =
2246 &audio_elements_with_data.at(kFirstAudioElementId);
2247 audio_frames_with_data.push_back(AudioFrameWithData{
2248 .obu =
2249 AudioFrameObu(ObuHeader(), kFirstSubstreamId, /*audio_frame=*/{0, 0}),
2250 .start_timestamp = 0,
2251 .end_timestamp = 1,
2252 .audio_element_with_data = common_audio_element_with_data,
2253 });
2254 audio_frames_with_data.push_back(AudioFrameWithData{
2255 .obu = AudioFrameObu(ObuHeader(), kSecondSubstreamId,
2256 /*audio_frame=*/{0, 0}),
2257 .start_timestamp = 0,
2258 .end_timestamp = 1,
2259 .audio_element_with_data = common_audio_element_with_data,
2260 });
2261 audio_frames_with_data.push_back(AudioFrameWithData{
2262 .obu =
2263 AudioFrameObu(ObuHeader(), kThirdSubstreamId, /*audio_frame=*/{0, 0}),
2264 .start_timestamp = 0,
2265 .end_timestamp = 1,
2266 .audio_element_with_data = common_audio_element_with_data,
2267 });
2268 audio_frames_with_data.push_back(AudioFrameWithData{
2269 .obu = AudioFrameObu(ObuHeader(), kFourthSubstreamId,
2270 /*audio_frame=*/{0, 0}),
2271 .start_timestamp = 0,
2272 .end_timestamp = 1,
2273 .audio_element_with_data = common_audio_element_with_data,
2274 });
2275
2276 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2277 {&codec_config_obus.at(kFirstCodecConfigId),
2278 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2279 &mix_presentation_obus.front()});
2280 RenderUsingObuProcessorExpectOk(
2281 output_filename, kWriteWavHeader, kNoOutputFileBitDepthOverride,
2282 audio_frames_with_data, parameter_blocks_with_data, bitstream);
2283
2284 const auto wav_reader = CreateWavReaderExpectOk(output_filename);
2285 EXPECT_EQ(wav_reader.num_channels(), 2);
2286 }
2287
TEST(RenderAudioFramesWithDataAndMeasureLoudness,SupportsMixGainParameterBlocks)2288 TEST(RenderAudioFramesWithDataAndMeasureLoudness,
2289 SupportsMixGainParameterBlocks) {
2290 const auto output_filename = GetAndCleanupOutputFileName(".wav");
2291
2292 RenderOneSampleFoaToStereoWavExpectOk(output_filename, kWriteWavHeader,
2293 kNoOutputFileBitDepthOverride);
2294
2295 const auto wav_reader = CreateWavReaderExpectOk(output_filename);
2296 EXPECT_EQ(wav_reader.num_channels(), 2);
2297 }
2298
TEST(RenderAudioFramesWithDataAndMeasureLoudness,CanWritePcmOrWav)2299 TEST(RenderAudioFramesWithDataAndMeasureLoudness, CanWritePcmOrWav) {
2300 const auto output_wav_filename = GetAndCleanupOutputFileName(".wav");
2301 RenderOneSampleFoaToStereoWavExpectOk(output_wav_filename, kWriteWavHeader,
2302 kNoOutputFileBitDepthOverride);
2303
2304 const auto wav_reader = CreateWavReaderExpectOk(output_wav_filename);
2305 EXPECT_EQ(wav_reader.remaining_samples(), 2);
2306
2307 const auto output_pcm_filename = GetAndCleanupOutputFileName(".pcm");
2308 RenderOneSampleFoaToStereoWavExpectOk(
2309 output_pcm_filename, kDontWriteWavHeader, kNoOutputFileBitDepthOverride);
2310
2311 EXPECT_TRUE(std::filesystem::exists(output_pcm_filename));
2312 // PCM file size excludes the header. We expect each sample to be 2 bytes.
2313 std::error_code error_code;
2314 EXPECT_EQ(std::filesystem::file_size(output_pcm_filename, error_code), 4);
2315 EXPECT_FALSE(error_code);
2316 }
2317
AddOneLayerStereoAudioElement(DecodedUleb128 codec_config_id,DecodedUleb128 audio_element_id,uint32_t substream_id,const absl::flat_hash_map<DecodedUleb128,CodecConfigObu> & codec_config_obus,absl::flat_hash_map<DecodedUleb128,AudioElementWithData> & audio_elements)2318 void AddOneLayerStereoAudioElement(
2319 DecodedUleb128 codec_config_id, DecodedUleb128 audio_element_id,
2320 uint32_t substream_id,
2321 const absl::flat_hash_map<DecodedUleb128, CodecConfigObu>&
2322 codec_config_obus,
2323 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>& audio_elements) {
2324 AddScalableAudioElementWithSubstreamIds(
2325 IamfInputLayout::kStereo, audio_element_id, codec_config_id,
2326 {substream_id}, codec_config_obus, audio_elements);
2327 }
2328
TEST(RenderTemporalUnitAndMeasureLoudness,RendersPassthroughStereoToPcm)2329 TEST(RenderTemporalUnitAndMeasureLoudness, RendersPassthroughStereoToPcm) {
2330 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2331 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2332 codec_config_obus);
2333 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2334 audio_elements_with_data;
2335 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kFirstAudioElementId,
2336 kFirstSubstreamId, codec_config_obus,
2337 audio_elements_with_data);
2338 std::list<MixPresentationObu> mix_presentation_obus;
2339 AddMixPresentationObuWithAudioElementIds(
2340 kFirstMixPresentationId, {kFirstAudioElementId},
2341 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2342 std::list<AudioFrameWithData> audio_frames_with_data;
2343 const std::list<ParameterBlockWithData> kNoParameterBlocks = {};
2344
2345 audio_frames_with_data.push_back(AudioFrameWithData{
2346 .obu = AudioFrameObu(ObuHeader(), kFirstSubstreamId,
2347 /*audio_frame=*/
2348 {// First left sample.
2349 0x11, 0x33,
2350 // First right sample.
2351 0x22, 0x44,
2352 // Second left sample.
2353 0x55, 0x77,
2354 // Second right sample.
2355 0x66, 0x08,
2356 // Third left sample.
2357 0x99, 0x0a,
2358 // Third right sample.
2359 0xbb, 0x0d}),
2360 .start_timestamp = 0,
2361 .end_timestamp = 1,
2362 .audio_element_with_data =
2363 &audio_elements_with_data.at(kFirstAudioElementId),
2364 });
2365
2366 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2367 {&codec_config_obus.at(kFirstCodecConfigId),
2368 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2369 &mix_presentation_obus.front()});
2370 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2371 kBufferCapacity, absl::MakeConstSpan(bitstream));
2372
2373 Layout unused_output_layout;
2374 bool insufficient_data;
2375 auto obu_processor = ObuProcessor::CreateForRendering(
2376 kStereoLayout,
2377 RenderingMixPresentationFinalizer::ProduceNoSampleProcessors,
2378 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2379 unused_output_layout, insufficient_data);
2380 ASSERT_THAT(obu_processor, NotNull());
2381 ASSERT_FALSE(insufficient_data);
2382 absl::Span<const std::vector<int32_t>> output_rendered_pcm_samples;
2383 EXPECT_THAT(obu_processor->RenderTemporalUnitAndMeasureLoudness(
2384 /*timestamp=*/0, audio_frames_with_data, kNoParameterBlocks,
2385 output_rendered_pcm_samples),
2386 IsOk());
2387
2388 // Outer vector is for each tick, inner vector is for each channel.
2389 std::vector<std::vector<int32_t>> expected_pcm_samples = {
2390 {0x33110000, 0x44220000},
2391 {0x77550000, 0x08660000},
2392 {0x0a990000, 0x0dbb0000},
2393 };
2394 EXPECT_EQ(output_rendered_pcm_samples, expected_pcm_samples);
2395 }
2396
TEST(RenderAudioFramesWithDataAndMeasureLoudness,RendersPassthroughStereoToWav)2397 TEST(RenderAudioFramesWithDataAndMeasureLoudness,
2398 RendersPassthroughStereoToWav) {
2399 const auto output_filename = GetAndCleanupOutputFileName(".wav");
2400 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2401 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2402 codec_config_obus);
2403 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2404 audio_elements_with_data;
2405 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kFirstAudioElementId,
2406 kFirstSubstreamId, codec_config_obus,
2407 audio_elements_with_data);
2408 std::list<MixPresentationObu> mix_presentation_obus;
2409 AddMixPresentationObuWithAudioElementIds(
2410 kFirstMixPresentationId, {kFirstAudioElementId},
2411 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2412 std::list<AudioFrameWithData> audio_frames_with_data;
2413 const std::list<ParameterBlockWithData> kNoParameterBlocks = {};
2414
2415 audio_frames_with_data.push_back(AudioFrameWithData{
2416 .obu = AudioFrameObu(ObuHeader(), kFirstSubstreamId,
2417 /*audio_frame=*/
2418 {// First left sample.
2419 0x11, 0x33,
2420 // First right sample.
2421 0x22, 0x44,
2422 // Second left sample.
2423 0x55, 0x77,
2424 // Second right sample.
2425 0x66, 0x08,
2426 // Third left sample.
2427 0x99, 0x0a,
2428 // Third right sample.
2429 0xbb, 0x0d}),
2430 .start_timestamp = 0,
2431 .end_timestamp = 1,
2432 .audio_element_with_data =
2433 &audio_elements_with_data.at(kFirstAudioElementId),
2434 });
2435
2436 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2437 {&codec_config_obus.at(kFirstCodecConfigId),
2438 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2439 &mix_presentation_obus.front()});
2440
2441 RenderUsingObuProcessorExpectOk(
2442 output_filename, kWriteWavHeader, kNoOutputFileBitDepthOverride,
2443 audio_frames_with_data, kNoParameterBlocks, bitstream);
2444
2445 auto wav_reader = CreateWavReaderExpectOk(output_filename, 4);
2446 EXPECT_EQ(wav_reader.num_channels(), 2);
2447 EXPECT_EQ(wav_reader.ReadFrame(), 6);
2448 // Validate left channel.
2449 EXPECT_EQ(wav_reader.buffers_[0][0], int32_t{0x33110000});
2450 EXPECT_EQ(wav_reader.buffers_[1][0], int32_t{0x77550000});
2451 EXPECT_EQ(wav_reader.buffers_[2][0], int32_t{0x0a990000});
2452 // Validate right channel.
2453 EXPECT_EQ(wav_reader.buffers_[0][1], int32_t{0x44220000});
2454 EXPECT_EQ(wav_reader.buffers_[1][1], int32_t{0x08660000});
2455 EXPECT_EQ(wav_reader.buffers_[2][1], int32_t{0x0dbb0000});
2456 }
2457
TEST(RenderAudioFramesWithDataAndMeasureLoudness,RendersPassthroughStereoToWav_2)2458 TEST(RenderAudioFramesWithDataAndMeasureLoudness,
2459 RendersPassthroughStereoToWav_2) {
2460 const auto output_filename = GetAndCleanupOutputFileName(".wav");
2461 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2462 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2463 codec_config_obus);
2464 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2465 audio_elements_with_data;
2466 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kFirstAudioElementId,
2467 kFirstSubstreamId, codec_config_obus,
2468 audio_elements_with_data);
2469 std::list<MixPresentationObu> mix_presentation_obus;
2470 AddMixPresentationObuWithAudioElementIds(
2471 kFirstMixPresentationId, {kFirstAudioElementId},
2472 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2473 const std::list<ParameterBlockWithData> kNoParameterBlocks = {};
2474
2475 // Render using `ObuProcessor`, which closes the output WAV file upon
2476 // going out of scope.
2477 {
2478 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2479 {&codec_config_obus.at(kFirstCodecConfigId),
2480 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2481 &mix_presentation_obus.front()});
2482 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2483 kBufferCapacity, absl::MakeConstSpan(bitstream));
2484
2485 Layout unused_output_layout;
2486 bool insufficient_data;
2487 const std::string output_filename_string(output_filename);
2488 auto obu_processor = ObuProcessor::CreateForRendering(
2489 kStereoLayout,
2490 CreateAllWavWriters(output_filename_string, kWriteWavHeader),
2491 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2492 unused_output_layout, insufficient_data);
2493 ASSERT_THAT(obu_processor, NotNull());
2494 ASSERT_FALSE(insufficient_data);
2495
2496 for (int i = 0; i < 100; ++i) {
2497 std::list<AudioFrameWithData> audio_frames_with_data;
2498 audio_frames_with_data.push_back(AudioFrameWithData{
2499 .obu = AudioFrameObu(ObuHeader(), kFirstSubstreamId,
2500 /*audio_frame=*/
2501 std::vector<uint8_t>(8, i)),
2502 .start_timestamp = i,
2503 .end_timestamp = i + 1,
2504 .audio_element_with_data =
2505 &audio_elements_with_data.at(kFirstAudioElementId),
2506 });
2507 absl::Span<const std::vector<int32_t>> unused_output_rendered_pcm_samples;
2508 EXPECT_THAT(obu_processor->RenderTemporalUnitAndMeasureLoudness(
2509 /*timestamp=*/i, audio_frames_with_data,
2510 kNoParameterBlocks, unused_output_rendered_pcm_samples),
2511 IsOk());
2512 }
2513 }
2514
2515 auto wav_reader = CreateWavReaderExpectOk(output_filename, 2);
2516 EXPECT_EQ(wav_reader.num_channels(), 2);
2517
2518 for (int i = 0; i < 100; ++i) {
2519 EXPECT_EQ(wav_reader.ReadFrame(), 4);
2520 const int32_t expected_sample = (i << 16) | (i << 24);
2521 EXPECT_THAT(wav_reader.buffers_[0],
2522 std::vector<int32_t>(2, expected_sample));
2523 EXPECT_THAT(wav_reader.buffers_[1],
2524 std::vector<int32_t>(2, expected_sample));
2525 }
2526 }
2527
TEST(RenderAudioFramesWithDataAndMeasureLoudness,SelectsFirstMixPresentationWhenSupported)2528 TEST(RenderAudioFramesWithDataAndMeasureLoudness,
2529 SelectsFirstMixPresentationWhenSupported) {
2530 const auto output_filename = GetAndCleanupOutputFileName(".wav");
2531 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2532 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2533 codec_config_obus);
2534 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2535 audio_elements_with_data;
2536 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kFirstAudioElementId,
2537 kFirstSubstreamId, codec_config_obus,
2538 audio_elements_with_data);
2539 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kSecondAudioElementId,
2540 kSecondSubstreamId, codec_config_obus,
2541 audio_elements_with_data);
2542 std::list<AudioFrameWithData> audio_frames_with_data;
2543 const std::list<ParameterBlockWithData> kNoParameterBlocks;
2544 audio_frames_with_data.push_back(AudioFrameWithData{
2545 .obu = AudioFrameObu(ObuHeader(), kFirstSubstreamId,
2546 /*audio_frame=*/{1, 0, 0, 0}),
2547 .start_timestamp = 0,
2548 .end_timestamp = 1,
2549 .audio_element_with_data =
2550 &audio_elements_with_data.at(kFirstAudioElementId),
2551 });
2552 audio_frames_with_data.push_back(AudioFrameWithData{
2553 .obu = AudioFrameObu(ObuHeader(), kSecondSubstreamId,
2554 /*audio_frame=*/{7, 0, 0, 0}),
2555 .start_timestamp = 0,
2556 .end_timestamp = 1,
2557 .audio_element_with_data =
2558 &audio_elements_with_data.at(kSecondAudioElementId),
2559 });
2560
2561 std::list<MixPresentationObu> mix_presentation_obus;
2562 constexpr int32_t kExpectedFirstSampleForFirstMixPresentation = 1 << 16;
2563 AddMixPresentationObuWithAudioElementIds(
2564 kFirstMixPresentationId, {kFirstAudioElementId},
2565 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2566 AddMixPresentationObuWithAudioElementIds(
2567 kSecondMixPresentationId, {kSecondAudioElementId},
2568 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2569
2570 auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2571 {&codec_config_obus.at(kFirstCodecConfigId),
2572 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2573 &audio_elements_with_data.at(kSecondAudioElementId).obu,
2574 &mix_presentation_obus.front(), &mix_presentation_obus.back()});
2575 RenderUsingObuProcessorExpectOk(
2576 output_filename, kWriteWavHeader, kNoOutputFileBitDepthOverride,
2577 audio_frames_with_data, kNoParameterBlocks, bitstream);
2578
2579 auto wav_reader = CreateWavReaderExpectOk(output_filename);
2580 EXPECT_EQ(wav_reader.ReadFrame(), 2);
2581 EXPECT_EQ(wav_reader.buffers_[0][0],
2582 kExpectedFirstSampleForFirstMixPresentation);
2583 }
2584
TEST(RenderAudioFramesWithDataAndMeasureLoudness,DoesNotSupportBaseEnhancedProfile)2585 TEST(RenderAudioFramesWithDataAndMeasureLoudness,
2586 DoesNotSupportBaseEnhancedProfile) {
2587 const auto output_filename = GetAndCleanupOutputFileName(".wav");
2588 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2589 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2590 codec_config_obus);
2591 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2592 audio_elements_with_data;
2593 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kFirstAudioElementId,
2594 kFirstSubstreamId, codec_config_obus,
2595 audio_elements_with_data);
2596 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kSecondAudioElementId,
2597 kSecondSubstreamId, codec_config_obus,
2598 audio_elements_with_data);
2599 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kThirdAudioElementId,
2600 kThirdSubstreamId, codec_config_obus,
2601 audio_elements_with_data);
2602 std::list<AudioFrameWithData> audio_frames_with_data;
2603 const std::list<ParameterBlockWithData> kNoParameterBlocks;
2604 audio_frames_with_data.push_back(AudioFrameWithData{
2605 .obu = AudioFrameObu(ObuHeader(), kFirstSubstreamId,
2606 /*audio_frame=*/{0, 0, 0, 0}),
2607 .start_timestamp = 0,
2608 .end_timestamp = 1,
2609 .audio_element_with_data =
2610 &audio_elements_with_data.at(kFirstAudioElementId),
2611 });
2612 audio_frames_with_data.push_back(AudioFrameWithData{
2613 .obu = AudioFrameObu(ObuHeader(), kSecondSubstreamId,
2614 /*audio_frame=*/{0, 0, 0, 0}),
2615 .start_timestamp = 0,
2616 .end_timestamp = 1,
2617 .audio_element_with_data =
2618 &audio_elements_with_data.at(kSecondAudioElementId),
2619 });
2620 audio_frames_with_data.push_back(AudioFrameWithData{
2621 .obu = AudioFrameObu(ObuHeader(), kThirdSubstreamId,
2622 /*audio_frame=*/{0, 0, 0, 0}),
2623 .start_timestamp = 0,
2624 .end_timestamp = 1,
2625 .audio_element_with_data =
2626 &audio_elements_with_data.at(kThirdAudioElementId),
2627 });
2628
2629 // The only mix presentation is not suitable for simple or base profile.
2630 std::list<MixPresentationObu> mix_presentation_obus;
2631 AddMixPresentationObuWithAudioElementIds(
2632 kFirstMixPresentationId,
2633 {kFirstAudioElementId, kSecondAudioElementId, kThirdAudioElementId},
2634 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2635
2636 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2637 {&codec_config_obus.at(kFirstCodecConfigId),
2638 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2639 &audio_elements_with_data.at(kSecondAudioElementId).obu,
2640 &audio_elements_with_data.at(kThirdAudioElementId).obu,
2641 &mix_presentation_obus.front()});
2642
2643 // Expect that the `ObuProcessor` rejects the rendering request.
2644 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2645 kBufferCapacity, absl::MakeConstSpan(bitstream));
2646 Layout unused_output_layout;
2647 bool insufficient_data;
2648 auto obu_processor = ObuProcessor::CreateForRendering(
2649 kStereoLayout,
2650 RenderingMixPresentationFinalizer::ProduceNoSampleProcessors,
2651 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2652 unused_output_layout, insufficient_data);
2653 EXPECT_FALSE(insufficient_data);
2654 EXPECT_THAT(obu_processor, IsNull());
2655 }
2656
TEST(RenderAudioFramesWithDataAndMeasureLoudness,SelectsFirstSupportedMixPresentation)2657 TEST(RenderAudioFramesWithDataAndMeasureLoudness,
2658 SelectsFirstSupportedMixPresentation) {
2659 const auto output_filename = GetAndCleanupOutputFileName(".wav");
2660 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2661 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2662 codec_config_obus);
2663 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2664 audio_elements_with_data;
2665 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kFirstAudioElementId,
2666 kFirstSubstreamId, codec_config_obus,
2667 audio_elements_with_data);
2668 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kSecondAudioElementId,
2669 kSecondSubstreamId, codec_config_obus,
2670 audio_elements_with_data);
2671 AddOneLayerStereoAudioElement(kFirstCodecConfigId, kThirdAudioElementId,
2672 kThirdSubstreamId, codec_config_obus,
2673 audio_elements_with_data);
2674 std::list<AudioFrameWithData> audio_frames_with_data;
2675 const std::list<ParameterBlockWithData> kNoParameterBlocks;
2676 audio_frames_with_data.push_back(AudioFrameWithData{
2677 .obu = AudioFrameObu(ObuHeader(), kFirstSubstreamId,
2678 /*audio_frame=*/{10, 0, 0, 0}),
2679 .start_timestamp = 0,
2680 .end_timestamp = 1,
2681 .audio_element_with_data =
2682 &audio_elements_with_data.at(kFirstAudioElementId),
2683 });
2684 audio_frames_with_data.push_back(AudioFrameWithData{
2685 .obu = AudioFrameObu(ObuHeader(), kSecondSubstreamId,
2686 /*audio_frame=*/{20, 0, 0, 0}),
2687 .start_timestamp = 0,
2688 .end_timestamp = 1,
2689 .audio_element_with_data =
2690 &audio_elements_with_data.at(kSecondAudioElementId),
2691 });
2692 audio_frames_with_data.push_back(AudioFrameWithData{
2693 .obu = AudioFrameObu(ObuHeader(), kThirdSubstreamId,
2694 /*audio_frame=*/{40, 0, 0, 0}),
2695 .start_timestamp = 0,
2696 .end_timestamp = 1,
2697 .audio_element_with_data =
2698 &audio_elements_with_data.at(kThirdAudioElementId),
2699 });
2700 // The first mix presentation is not suitable for simple or base profile.
2701 std::list<MixPresentationObu> mix_presentation_obus;
2702 AddMixPresentationObuWithAudioElementIds(
2703 kFirstMixPresentationId,
2704 {kFirstAudioElementId, kSecondAudioElementId, kThirdAudioElementId},
2705 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2706 // The second is suitable.
2707 constexpr int32_t kExpectedFirstSampleForFirstSupportedMixPresentation =
2708 30 << 16;
2709 AddMixPresentationObuWithAudioElementIds(
2710 kSecondMixPresentationId, {kFirstAudioElementId, kSecondAudioElementId},
2711 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2712 // The third is also suitable, but the will not be selected.
2713 AddMixPresentationObuWithAudioElementIds(
2714 kThirdMixPresentationId, {kFirstAudioElementId, kThirdAudioElementId},
2715 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2716
2717 auto mix_presentation_obus_iter = mix_presentation_obus.begin();
2718 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2719 {&codec_config_obus.at(kFirstCodecConfigId),
2720 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2721 &audio_elements_with_data.at(kSecondAudioElementId).obu,
2722 &audio_elements_with_data.at(kThirdAudioElementId).obu,
2723 &(*mix_presentation_obus_iter++), &(*mix_presentation_obus_iter++),
2724 &(*mix_presentation_obus_iter++)});
2725 RenderUsingObuProcessorExpectOk(
2726 output_filename, kWriteWavHeader, kNoOutputFileBitDepthOverride,
2727 audio_frames_with_data, kNoParameterBlocks, bitstream);
2728
2729 auto wav_reader = CreateWavReaderExpectOk(output_filename);
2730 EXPECT_EQ(wav_reader.ReadFrame(), 2);
2731 EXPECT_EQ(wav_reader.buffers_[0][0],
2732 kExpectedFirstSampleForFirstSupportedMixPresentation);
2733 }
2734
TEST(CreateForRendering,ForwardsArgumentsToSampleProcessorFactory)2735 TEST(CreateForRendering, ForwardsArgumentsToSampleProcessorFactory) {
2736 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2737 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2738 codec_config_obus);
2739 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2740 audio_elements_with_data;
2741 AddAmbisonicsMonoAudioElementWithSubstreamIds(
2742 kFirstAudioElementId, kFirstCodecConfigId,
2743 {kFirstSubstreamId, kSecondSubstreamId, kThirdSubstreamId,
2744 kFourthSubstreamId},
2745 codec_config_obus, audio_elements_with_data);
2746 std::list<MixPresentationObu> mix_presentation_obus;
2747 AddMixPresentationObuWithAudioElementIds(
2748 kFirstMixPresentationId, {kFirstAudioElementId},
2749 kCommonMixGainParameterId, kCommonParameterRate, mix_presentation_obus);
2750
2751 const std::list<AudioFrameWithData> empty_audio_frames_with_data = {};
2752 const std::list<ParameterBlockWithData> empty_parameter_blocks_with_data = {};
2753
2754 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2755 {&codec_config_obus.at(kFirstCodecConfigId),
2756 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2757 &mix_presentation_obus.front()});
2758 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2759 kBufferCapacity, absl::MakeConstSpan(bitstream));
2760 bool insufficient_data;
2761
2762 // We expect arguments to be forwarded from the OBUs to the sample processor
2763 // factory.
2764 constexpr int kFirstSubmixIndex = 0;
2765 constexpr int kFirstLayoutIndex = 0;
2766 const auto& forwarded_layout =
2767 mix_presentation_obus.front().sub_mixes_[0].layouts[0].loudness_layout;
2768 const int32_t forwarded_sample_rate = static_cast<int32_t>(
2769 codec_config_obus.at(kFirstCodecConfigId).GetOutputSampleRate());
2770 const int32_t forwarded_bit_depth = static_cast<int32_t>(
2771 codec_config_obus.at(kFirstCodecConfigId).GetBitDepthToMeasureLoudness());
2772 const uint32_t forwarded_num_samples_per_frame =
2773 codec_config_obus.at(kFirstCodecConfigId).GetNumSamplesPerFrame();
2774
2775 MockSampleProcessorFactory mock_sample_processor_factory;
2776 EXPECT_CALL(
2777 mock_sample_processor_factory,
2778 Call(kFirstMixPresentationId, kFirstSubmixIndex, kFirstLayoutIndex,
2779 forwarded_layout, /*num_channels=*/2, forwarded_sample_rate,
2780 forwarded_bit_depth, forwarded_num_samples_per_frame));
2781 RenderingMixPresentationFinalizer::SampleProcessorFactory
2782 sample_processor_factory = mock_sample_processor_factory.AsStdFunction();
2783
2784 Layout unused_output_layout;
2785 EXPECT_THAT(ObuProcessor::CreateForRendering(
2786 kStereoLayout, sample_processor_factory,
2787 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2788 unused_output_layout, insufficient_data),
2789 NotNull());
2790 }
2791
2792 using testing::_;
2793
2794 constexpr Layout k5_1_Layout = {
2795 .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
2796 .specific_layout = LoudspeakersSsConventionLayout{
2797 .sound_system = LoudspeakersSsConventionLayout::kSoundSystemB_0_5_0}};
2798
TEST(CreateForRendering,ForwardsChosenLayoutToSampleProcessorFactory)2799 TEST(CreateForRendering, ForwardsChosenLayoutToSampleProcessorFactory) {
2800 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2801 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2802 codec_config_obus);
2803 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2804 audio_elements_with_data;
2805 AddAmbisonicsMonoAudioElementWithSubstreamIds(
2806 kFirstAudioElementId, kFirstCodecConfigId,
2807 {kFirstSubstreamId, kSecondSubstreamId, kThirdSubstreamId,
2808 kFourthSubstreamId},
2809 codec_config_obus, audio_elements_with_data);
2810 std::list<MixPresentationObu> mix_presentation_obus;
2811 std::vector<LoudspeakersSsConventionLayout::SoundSystem>
2812 sound_system_layouts = {
2813 LoudspeakersSsConventionLayout::kSoundSystemA_0_2_0,
2814 LoudspeakersSsConventionLayout::kSoundSystemB_0_5_0};
2815 AddMixPresentationObuWithConfigurableLayouts(
2816 kFirstMixPresentationId, {kFirstAudioElementId},
2817 kCommonMixGainParameterId, kCommonParameterRate, sound_system_layouts,
2818 mix_presentation_obus);
2819
2820 const std::list<AudioFrameWithData> empty_audio_frames_with_data = {};
2821 const std::list<ParameterBlockWithData> empty_parameter_blocks_with_data = {};
2822
2823 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2824 {&codec_config_obus.at(kFirstCodecConfigId),
2825 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2826 &mix_presentation_obus.front()});
2827 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2828 kBufferCapacity, absl::MakeConstSpan(bitstream));
2829 bool insufficient_data;
2830
2831 // We expect to use the second layout, since this is the only one that matches
2832 // the desired layout.
2833 constexpr int kSubmixIndex = 0;
2834 constexpr int kLayoutIndex = 1;
2835 const auto& forwarded_layout =
2836 mix_presentation_obus.front().sub_mixes_[0].layouts[1].loudness_layout;
2837
2838 MockSampleProcessorFactory mock_sample_processor_factory;
2839 EXPECT_CALL(mock_sample_processor_factory,
2840 Call(kFirstMixPresentationId, kSubmixIndex, kLayoutIndex,
2841 forwarded_layout, /*num_channels=*/6, _, _, _));
2842 RenderingMixPresentationFinalizer::SampleProcessorFactory
2843 sample_processor_factory = mock_sample_processor_factory.AsStdFunction();
2844
2845 Layout output_layout;
2846 EXPECT_THAT(ObuProcessor::CreateForRendering(
2847 k5_1_Layout, sample_processor_factory,
2848 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2849 output_layout, insufficient_data),
2850 NotNull());
2851 EXPECT_EQ(output_layout, k5_1_Layout);
2852 }
2853
TEST(CreateForRendering,ForwardsDefaultLayoutToSampleProcessorFactory)2854 TEST(CreateForRendering, ForwardsDefaultLayoutToSampleProcessorFactory) {
2855 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2856 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2857 codec_config_obus);
2858 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2859 audio_elements_with_data;
2860 AddAmbisonicsMonoAudioElementWithSubstreamIds(
2861 kFirstAudioElementId, kFirstCodecConfigId,
2862 {kFirstSubstreamId, kSecondSubstreamId, kThirdSubstreamId,
2863 kFourthSubstreamId},
2864 codec_config_obus, audio_elements_with_data);
2865 std::list<MixPresentationObu> mix_presentation_obus;
2866 std::vector<LoudspeakersSsConventionLayout::SoundSystem>
2867 sound_system_layouts = {
2868 LoudspeakersSsConventionLayout::kSoundSystemA_0_2_0,
2869 LoudspeakersSsConventionLayout::kSoundSystemJ_4_7_0};
2870 AddMixPresentationObuWithConfigurableLayouts(
2871 kFirstMixPresentationId, {kFirstAudioElementId},
2872 kCommonMixGainParameterId, kCommonParameterRate, sound_system_layouts,
2873 mix_presentation_obus);
2874
2875 const std::list<AudioFrameWithData> empty_audio_frames_with_data = {};
2876 const std::list<ParameterBlockWithData> empty_parameter_blocks_with_data = {};
2877
2878 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2879 {&codec_config_obus.at(kFirstCodecConfigId),
2880 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2881 &mix_presentation_obus.front()});
2882 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2883 kBufferCapacity, absl::MakeConstSpan(bitstream));
2884 bool insufficient_data;
2885
2886 // We expect to use the first layout as default, since the desired layout is
2887 // not available in the mix presentation.
2888 constexpr int kSubmixIndex = 0;
2889 constexpr int kLayoutIndex = 0;
2890 const auto& forwarded_layout =
2891 mix_presentation_obus.front().sub_mixes_[0].layouts[0].loudness_layout;
2892
2893 MockSampleProcessorFactory mock_sample_processor_factory;
2894 EXPECT_CALL(mock_sample_processor_factory,
2895 Call(kFirstMixPresentationId, kSubmixIndex, kLayoutIndex,
2896 forwarded_layout, /*num_channels=*/2, _, _, _));
2897 RenderingMixPresentationFinalizer::SampleProcessorFactory
2898 sample_processor_factory = mock_sample_processor_factory.AsStdFunction();
2899
2900 Layout unused_output_layout;
2901 EXPECT_THAT(ObuProcessor::CreateForRendering(
2902 k5_1_Layout, sample_processor_factory,
2903 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2904 unused_output_layout, insufficient_data),
2905 NotNull());
2906 }
2907
TEST(CreateForRendering,ForwardsChosenLayoutToSampleProcessorFactoryWithMultipleMixPresentations)2908 TEST(CreateForRendering,
2909 ForwardsChosenLayoutToSampleProcessorFactoryWithMultipleMixPresentations) {
2910 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_config_obus;
2911 AddLpcmCodecConfigWithIdAndSampleRate(kFirstCodecConfigId, kSampleRate,
2912 codec_config_obus);
2913 absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
2914 audio_elements_with_data;
2915 AddAmbisonicsMonoAudioElementWithSubstreamIds(
2916 kFirstAudioElementId, kFirstCodecConfigId,
2917 {kFirstSubstreamId, kSecondSubstreamId, kThirdSubstreamId,
2918 kFourthSubstreamId},
2919 codec_config_obus, audio_elements_with_data);
2920 std::list<MixPresentationObu> mix_presentation_obus;
2921 std::vector<LoudspeakersSsConventionLayout::SoundSystem>
2922 sound_system_layouts_first_mix_presentation = {
2923 LoudspeakersSsConventionLayout::kSoundSystemA_0_2_0,
2924 LoudspeakersSsConventionLayout::kSoundSystem10_2_7_0};
2925 AddMixPresentationObuWithConfigurableLayouts(
2926 kFirstMixPresentationId, {kFirstAudioElementId},
2927 kCommonMixGainParameterId, kCommonParameterRate,
2928 sound_system_layouts_first_mix_presentation, mix_presentation_obus);
2929 std::vector<LoudspeakersSsConventionLayout::SoundSystem>
2930 sound_system_layouts_second_mix_presentation = {
2931 LoudspeakersSsConventionLayout::kSoundSystemA_0_2_0,
2932 LoudspeakersSsConventionLayout::kSoundSystemB_0_5_0};
2933 AddMixPresentationObuWithConfigurableLayouts(
2934 kSecondMixPresentationId, {kFirstAudioElementId},
2935 kCommonMixGainParameterId, kCommonParameterRate,
2936 sound_system_layouts_second_mix_presentation, mix_presentation_obus);
2937
2938 const std::list<AudioFrameWithData> empty_audio_frames_with_data = {};
2939 const std::list<ParameterBlockWithData> empty_parameter_blocks_with_data = {};
2940
2941 const auto bitstream = AddSequenceHeaderAndSerializeObusExpectOk(
2942 {&codec_config_obus.at(kFirstCodecConfigId),
2943 &audio_elements_with_data.at(kFirstAudioElementId).obu,
2944 &mix_presentation_obus.front(),
2945 &*(std::next(mix_presentation_obus.begin()))});
2946 auto read_bit_buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
2947 kBufferCapacity, absl::MakeConstSpan(bitstream));
2948 bool insufficient_data;
2949
2950 // We expect to use the second layout in the second mix presentation, since
2951 // this is the only one that matches the desired layout.
2952 constexpr int kSubmixIndex = 0;
2953 constexpr int kLayoutIndex = 1;
2954 const auto& forwarded_layout = (std::next(mix_presentation_obus.begin()))
2955 ->sub_mixes_[0]
2956 .layouts[1]
2957 .loudness_layout;
2958
2959 MockSampleProcessorFactory mock_sample_processor_factory;
2960 EXPECT_CALL(mock_sample_processor_factory,
2961 Call(kSecondMixPresentationId, kSubmixIndex, kLayoutIndex,
2962 forwarded_layout, /*num_channels=*/6, _, _, _));
2963 RenderingMixPresentationFinalizer::SampleProcessorFactory
2964 sample_processor_factory = mock_sample_processor_factory.AsStdFunction();
2965
2966 Layout output_layout;
2967 EXPECT_THAT(ObuProcessor::CreateForRendering(
2968 k5_1_Layout, sample_processor_factory,
2969 /*is_exhaustive_and_exact=*/true, read_bit_buffer.get(),
2970 output_layout, insufficient_data),
2971 NotNull());
2972 EXPECT_EQ(output_layout, k5_1_Layout);
2973 }
2974
TEST(CreateForRendering,NullReadBitBufferRejected)2975 TEST(CreateForRendering, NullReadBitBufferRejected) {
2976 MockSampleProcessorFactory mock_sample_processor_factory;
2977 auto sample_processor_factory = mock_sample_processor_factory.AsStdFunction();
2978 ReadBitBuffer* read_bit_buffer_nullptr = nullptr;
2979 bool insufficient_data;
2980
2981 Layout unused_output_layout;
2982 EXPECT_THAT(ObuProcessor::CreateForRendering(
2983 kStereoLayout, sample_processor_factory,
2984 /*is_exhaustive_and_exact=*/true, read_bit_buffer_nullptr,
2985 unused_output_layout, insufficient_data),
2986 IsNull());
2987 EXPECT_FALSE(insufficient_data);
2988 }
2989
2990 } // namespace
2991 } // namespace iamf_tools
2992