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
5 * License and the Alliance for Open Media Patent License 1.0. If the BSD
6 * 3-Clause Clear License was not distributed with this source code in the
7 * LICENSE file, you can obtain it at
8 * www.aomedia.org/license/software-license/bsd-3-c-c. If the Alliance for
9 * Open Media Patent License 1.0 was not distributed with this source code
10 * in the PATENTS file, you can obtain it at www.aomedia.org/license/patent.
11 */
12 #include "iamf/cli/rendering_mix_presentation_finalizer.h"
13
14 #include <array>
15 #include <cstddef>
16 #include <cstdint>
17 #include <filesystem>
18 #include <limits>
19 #include <list>
20 #include <memory>
21 #include <optional>
22 #include <string>
23 #include <utility>
24 #include <vector>
25
26 #include "absl/container/flat_hash_map.h"
27 #include "absl/log/check.h"
28 #include "absl/status/status.h"
29 #include "absl/status/status_matchers.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/string_view.h"
32 #include "absl/types/span.h"
33 #include "gmock/gmock.h"
34 #include "gtest/gtest.h"
35 #include "iamf/cli/audio_element_with_data.h"
36 #include "iamf/cli/channel_label.h"
37 #include "iamf/cli/demixing_module.h"
38 #include "iamf/cli/loudness_calculator_base.h"
39 #include "iamf/cli/loudness_calculator_factory_base.h"
40 #include "iamf/cli/parameter_block_with_data.h"
41 #include "iamf/cli/proto/codec_config.pb.h"
42 #include "iamf/cli/proto_conversion/proto_to_obu/codec_config_generator.h"
43 #include "iamf/cli/renderer/audio_element_renderer_base.h"
44 #include "iamf/cli/renderer_factory.h"
45 #include "iamf/cli/tests/cli_test_utils.h"
46 #include "iamf/cli/user_metadata_builder/codec_config_obu_metadata_builder.h"
47 #include "iamf/cli/user_metadata_builder/iamf_input_layout.h"
48 #include "iamf/cli/wav_reader.h"
49 #include "iamf/cli/wav_writer.h"
50 #include "iamf/obu/audio_element.h"
51 #include "iamf/obu/codec_config.h"
52 #include "iamf/obu/mix_presentation.h"
53 #include "iamf/obu/types.h"
54 #include "src/google/protobuf/repeated_ptr_field.h"
55
56 namespace iamf_tools {
57 namespace {
58
59 using ::absl_testing::IsOk;
60 using ::absl_testing::IsOkAndHolds;
61 using ::absl_testing::StatusIs;
62 using ::testing::_;
63 using ::testing::Eq;
64 using ::testing::IsEmpty;
65 using ::testing::Not;
66 using testing::Return;
67 using enum ChannelLabel::Label;
68
69 using absl::StatusCode::kFailedPrecondition;
70
71 constexpr int64_t kStartTime = 0;
72 constexpr int32_t kEndTime = 10;
73 constexpr bool kValidateLoudness = true;
74 constexpr bool kDontValidateLoudness = false;
75 const std::optional<uint8_t> kNoOverrideBitDepth = std::nullopt;
76 constexpr absl::string_view kSuffixAfterMixPresentationId =
77 "_first_submix_first_layout.wav";
78
79 constexpr uint32_t kMixPresentationId = 42;
80 constexpr uint32_t kCodecConfigId = 42;
81 constexpr uint32_t kAudioElementId = 42;
82 constexpr int kNumchannelsForMono = 1;
83 constexpr uint32_t kBitDepth = 16;
84 constexpr uint32_t kSampleRate = 48000;
85 constexpr uint32_t kCommonParameterRate = kSampleRate;
86 constexpr uint32_t kNumSamplesPerFrame = 8;
87 constexpr uint8_t kCodecConfigBitDepth = 16;
88 constexpr uint8_t kNoTrimFromEnd = 0;
89 constexpr std::array<DecodedUleb128, 1> kMonoSubstreamIds = {0};
90 constexpr std::array<DecodedUleb128, 1> kStereoSubstreamIds = {1};
91
92 constexpr std::array<ChannelLabel::Label, 2> kStereoLabels = {kL2, kR2};
93
94 constexpr size_t kFirstSubmixIndex = 0;
95 constexpr size_t kFirstLayoutIndex = 0;
96
97 typedef ::google::protobuf::RepeatedPtrField<
98 iamf_tools_cli_proto::CodecConfigObuMetadata>
99 CodecConfigObuMetadatas;
100
101 class MockRenderer : public AudioElementRendererBase {
102 public:
MockRenderer(absl::Span<const ChannelLabel::Label> ordered_labels,size_t num_output_channels)103 MockRenderer(absl::Span<const ChannelLabel::Label> ordered_labels,
104 size_t num_output_channels)
105 : AudioElementRendererBase(ordered_labels,
106 static_cast<size_t>(kNumSamplesPerFrame),
107 num_output_channels) {}
MockRenderer()108 MockRenderer() : MockRenderer({}, 0) {}
109
110 MOCK_METHOD(
111 absl::Status, RenderSamples,
112 (absl::Span<const std::vector<InternalSampleType>> samples_to_render,
113 std::vector<InternalSampleType>& rendered_samples),
114 (override));
115 };
116
117 class MockRendererFactory : public RendererFactoryBase {
118 public:
MockRendererFactory()119 MockRendererFactory() : RendererFactoryBase() {}
120
121 MOCK_METHOD(std::unique_ptr<AudioElementRendererBase>,
122 CreateRendererForLayout,
123 (const std::vector<DecodedUleb128>& audio_substream_ids,
124 const SubstreamIdLabelsMap& substream_id_to_labels,
125 AudioElementObu::AudioElementType audio_element_type,
126 const AudioElementObu::AudioElementConfig& audio_element_config,
127 const RenderingConfig& rendering_config,
128 const Layout& loudness_layout, size_t num_samples_per_frame),
129 (const, override));
130 };
131
132 /*!\brief A simple factory which always returns `nullptr`. */
133 class AlwaysNullRendererFactory : public RendererFactoryBase {
134 public:
135 /*!\brief Destructor. */
136 ~AlwaysNullRendererFactory() override = default;
137
CreateRendererForLayout(const std::vector<DecodedUleb128> &,const SubstreamIdLabelsMap &,AudioElementObu::AudioElementType,const AudioElementObu::AudioElementConfig &,const RenderingConfig &,const Layout &,size_t) const138 std::unique_ptr<AudioElementRendererBase> CreateRendererForLayout(
139 const std::vector<DecodedUleb128>& /*audio_substream_ids*/,
140 const SubstreamIdLabelsMap& /*substream_id_to_labels*/,
141 AudioElementObu::AudioElementType /*audio_element_type*/,
142 const AudioElementObu::AudioElementConfig& /*audio_element_config*/,
143 const RenderingConfig& /*rendering_config*/,
144 const Layout& /*loudness_layout*/,
145 size_t /*num_samples_per_frame*/) const override {
146 return nullptr;
147 }
148 };
149
150 /*!\brief A simple factory which always returns `nullptr`. */
151 class AlwaysNullLoudnessCalculatorFactory
152 : public LoudnessCalculatorFactoryBase {
153 public:
154 /*!\brief Destructor. */
155 ~AlwaysNullLoudnessCalculatorFactory() override = default;
156
CreateLoudnessCalculator(const MixPresentationLayout &,uint32_t,int32_t,int32_t) const157 std::unique_ptr<LoudnessCalculatorBase> CreateLoudnessCalculator(
158 const MixPresentationLayout& /*layout*/,
159 uint32_t /*num_samples_per_frame*/, int32_t /*rendered_sample_rate*/,
160 int32_t /*rendered_bit_depth*/) const override {
161 return nullptr;
162 }
163 };
164
GetFirstSubmixFirstLayoutExpectedPath()165 std::string GetFirstSubmixFirstLayoutExpectedPath() {
166 return absl::StrCat(GetAndCreateOutputDirectory(""), "_id_",
167 kMixPresentationId, kSuffixAfterMixPresentationId);
168 }
169
170 class FinalizerTest : public ::testing::Test {
171 public:
InitPrerequisiteObusForMonoInput(DecodedUleb128 audio_element_id)172 void InitPrerequisiteObusForMonoInput(DecodedUleb128 audio_element_id) {
173 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
174 codec_configs_);
175 AddScalableAudioElementWithSubstreamIds(
176 IamfInputLayout::kMono, audio_element_id, kCodecConfigId,
177 kMonoSubstreamIds, codec_configs_, audio_elements_);
178 }
179
InitPrerequisiteObusForStereoInput(DecodedUleb128 audio_element_id)180 void InitPrerequisiteObusForStereoInput(DecodedUleb128 audio_element_id) {
181 AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, kSampleRate,
182 codec_configs_);
183 AddScalableAudioElementWithSubstreamIds(
184 IamfInputLayout::kStereo, audio_element_id, kCodecConfigId,
185 kStereoSubstreamIds, codec_configs_, audio_elements_);
186 }
187
AddMixPresentationObuForMonoOutput(DecodedUleb128 mix_presentation_id)188 void AddMixPresentationObuForMonoOutput(DecodedUleb128 mix_presentation_id) {
189 AddMixPresentationObuWithAudioElementIds(
190 mix_presentation_id, {kAudioElementId},
191 /*common_parameter_id=*/999, kCommonParameterRate, obus_to_finalize_);
192 obus_to_finalize_.back().sub_mixes_[0].layouts[0].loudness_layout = {
193 .layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
194 .specific_layout = LoudspeakersSsConventionLayout{
195 .sound_system =
196 LoudspeakersSsConventionLayout::kSoundSystem12_0_1_0}};
197 }
198
AddMixPresentationObuForStereoOutput(DecodedUleb128 mix_presentation_id)199 void AddMixPresentationObuForStereoOutput(
200 DecodedUleb128 mix_presentation_id) {
201 AddMixPresentationObuWithAudioElementIds(
202 mix_presentation_id, {kAudioElementId},
203 /*common_parameter_id=*/999, kCommonParameterRate, obus_to_finalize_);
204 }
205
AddLabeledFrame(DecodedUleb128 audio_element_id,const LabelSamplesMap & label_to_samples,int32_t end_timestamp,uint32_t samples_to_trim_at_end=0,uint32_t samples_to_trim_at_start=0)206 void AddLabeledFrame(DecodedUleb128 audio_element_id,
207 const LabelSamplesMap& label_to_samples,
208 int32_t end_timestamp,
209 uint32_t samples_to_trim_at_end = 0,
210 uint32_t samples_to_trim_at_start = 0) {
211 IdLabeledFrameMap id_to_labeled_frame;
212 id_to_labeled_frame[audio_element_id] = {
213 .end_timestamp = end_timestamp,
214 .samples_to_trim_at_end = samples_to_trim_at_end,
215 .samples_to_trim_at_start = samples_to_trim_at_start,
216 .label_to_samples = label_to_samples};
217 ordered_labeled_frames_.push_back(id_to_labeled_frame);
218 }
219
PrepareObusForOneSamplePassThroughMono()220 void PrepareObusForOneSamplePassThroughMono() {
221 InitPrerequisiteObusForMonoInput(kAudioElementId);
222 AddMixPresentationObuForMonoOutput(kMixPresentationId);
223 const LabelSamplesMap kLabelToSamples = {{kMono, {0, 1}}};
224 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
225 }
226
CreateFinalizerExpectOk()227 RenderingMixPresentationFinalizer CreateFinalizerExpectOk() {
228 auto finalizer = RenderingMixPresentationFinalizer::Create(
229 renderer_factory_.get(), loudness_calculator_factory_.get(),
230 audio_elements_, sample_processor_factory_, obus_to_finalize_);
231 EXPECT_THAT(finalizer, IsOk());
232 return *std::move(finalizer);
233 }
234
ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout()235 void ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout() {
236 sample_processor_factory_ =
237 [output_directory = output_directory_,
238 output_wav_file_bit_depth_override =
239 output_wav_file_bit_depth_override_](
240 DecodedUleb128 mix_presentation_id, int sub_mix_index,
241 int layout_index, const Layout&, int num_channels, int sample_rate,
242 int bit_depth,
243 size_t num_samples_per_frame) -> std::unique_ptr<WavWriter> {
244 if (sub_mix_index != 0 || layout_index != 0) {
245 return nullptr;
246 }
247 // Obey the override bit depth. But if it is not set, just match the input
248 // audio.
249 const uint8_t wav_file_bit_depth =
250 output_wav_file_bit_depth_override.value_or(bit_depth);
251 const auto wav_path =
252 absl::StrCat(output_directory.string(), "_id_", mix_presentation_id,
253 kSuffixAfterMixPresentationId);
254 return WavWriter::Create(wav_path, num_channels, sample_rate,
255 wav_file_bit_depth, num_samples_per_frame);
256 };
257 }
258
IterativeRenderingExpectOk(RenderingMixPresentationFinalizer & finalizer,const std::list<ParameterBlockWithData> & parameter_blocks)259 void IterativeRenderingExpectOk(
260 RenderingMixPresentationFinalizer& finalizer,
261 const std::list<ParameterBlockWithData>& parameter_blocks) {
262 int64_t start_timestamp = 0;
263 for (const auto& id_to_labeled_frame : ordered_labeled_frames_) {
264 ASSERT_TRUE(id_to_labeled_frame.contains(kAudioElementId));
265 EXPECT_THAT(finalizer.PushTemporalUnit(
266 id_to_labeled_frame, start_timestamp,
267 id_to_labeled_frame.at(kAudioElementId).end_timestamp,
268 parameter_blocks),
269 IsOk());
270 }
271
272 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
273 auto finalized_obus =
274 finalizer.GetFinalizedMixPresentationObus(validate_loudness_);
275 ASSERT_THAT(finalized_obus, IsOk());
276 finalized_obus_ = *std::move(finalized_obus);
277 }
278
279 protected:
280 // Prerequisite OBUs.
281 absl::flat_hash_map<DecodedUleb128, CodecConfigObu> codec_configs_;
282 absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements_;
283 std::list<MixPresentationObu> obus_to_finalize_;
284 std::list<ParameterBlockWithData> parameter_blocks_;
285
286 // Finalizer create settings. Default to simplistic inputs that disable
287 // most features.
288 std::filesystem::path output_directory_ = GetAndCreateOutputDirectory("");
289 std::optional<uint8_t> output_wav_file_bit_depth_override_ =
290 kNoOverrideBitDepth;
291 bool validate_loudness_ = kDontValidateLoudness;
292 std::unique_ptr<RendererFactoryBase> renderer_factory_;
293 std::unique_ptr<LoudnessCalculatorFactoryBase> loudness_calculator_factory_;
294 // Custom `Finalize` arguments.
295 RenderingMixPresentationFinalizer::SampleProcessorFactory
296 sample_processor_factory_ =
297 RenderingMixPresentationFinalizer::ProduceNoSampleProcessors;
298
299 std::vector<IdLabeledFrameMap> ordered_labeled_frames_;
300
301 std::list<MixPresentationObu> finalized_obus_;
302 };
303
304 // =Tests that the create function does not crash with various modes disabled.=
305
TEST_F(FinalizerTest,CreateDoesNotCrashWithMockFactories)306 TEST_F(FinalizerTest, CreateDoesNotCrashWithMockFactories) {
307 renderer_factory_ = std::make_unique<MockRendererFactory>();
308 loudness_calculator_factory_ =
309 std::make_unique<MockLoudnessCalculatorFactory>();
310
311 CreateFinalizerExpectOk();
312 }
313
TEST_F(FinalizerTest,CreateDoesNotCrashWhenRendererFactoryIsNullptr)314 TEST_F(FinalizerTest, CreateDoesNotCrashWhenRendererFactoryIsNullptr) {
315 renderer_factory_ = nullptr;
316
317 CreateFinalizerExpectOk();
318 }
319
TEST_F(FinalizerTest,CreateDoesNotCrashWhenLoudnessCalculatorFactoryIsNullptr)320 TEST_F(FinalizerTest,
321 CreateDoesNotCrashWhenLoudnessCalculatorFactoryIsNullptr) {
322 renderer_factory_ = std::make_unique<AlwaysNullRendererFactory>();
323 loudness_calculator_factory_ = nullptr;
324
325 CreateFinalizerExpectOk();
326 }
327
TEST_F(FinalizerTest,CreateFailsWitMismatchingNumSamplesPerFrame)328 TEST_F(FinalizerTest, CreateFailsWitMismatchingNumSamplesPerFrame) {
329 // The first audio element references an LPCM codec config.
330 renderer_factory_ = std::make_unique<AlwaysNullRendererFactory>();
331 CodecConfigObuMetadatas metadata;
332 metadata.Add(CodecConfigObuMetadataBuilder::GetOpusCodecConfigObuMetadata(
333 kCodecConfigId, 960));
334 constexpr uint32_t kSecondCodecConfigId = kCodecConfigId + 1;
335 metadata.Add(CodecConfigObuMetadataBuilder::GetOpusCodecConfigObuMetadata(
336 kSecondCodecConfigId, 1920));
337 CodecConfigGenerator generator(metadata);
338 ASSERT_THAT(generator.Generate(codec_configs_), IsOk());
339
340 AddScalableAudioElementWithSubstreamIds(
341 IamfInputLayout::kMono, kAudioElementId, kCodecConfigId,
342 kMonoSubstreamIds, codec_configs_, audio_elements_);
343 // The second audio element references a codec Config with a different
344 // number of samples per frame.
345 constexpr DecodedUleb128 kStereoAudioElementId = kAudioElementId + 1;
346 AddScalableAudioElementWithSubstreamIds(
347 IamfInputLayout::kStereo, kStereoAudioElementId, kSecondCodecConfigId,
348 kStereoSubstreamIds, codec_configs_, audio_elements_);
349 // Mixing these is invalid because there must be only one codec config in IAMF
350 // v1.1.0.
351 AddMixPresentationObuWithAudioElementIds(
352 kMixPresentationId, {kAudioElementId, kStereoAudioElementId},
353 /*common_parameter_id=*/999, kCommonParameterRate, obus_to_finalize_);
354
355 EXPECT_FALSE(RenderingMixPresentationFinalizer::Create(
356 renderer_factory_.get(), loudness_calculator_factory_.get(),
357 audio_elements_, sample_processor_factory_,
358 obus_to_finalize_)
359 .ok());
360 }
361
362 // =========== Tests that work is delegated to the renderer factory. ===========
TEST_F(FinalizerTest,ForwardsAudioElementToRenderer)363 TEST_F(FinalizerTest, ForwardsAudioElementToRenderer) {
364 InitPrerequisiteObusForStereoInput(kAudioElementId);
365 AddMixPresentationObuForStereoOutput(kMixPresentationId);
366 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
367 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
368
369 // We expect audio-element related arguments to be forwarded from the OBUs to
370 // the renderer factory.
371 auto mock_renderer_factory = std::make_unique<MockRendererFactory>();
372 const auto& forwarded_audio_element = audio_elements_.at(kAudioElementId);
373 EXPECT_CALL(
374 *mock_renderer_factory,
375 CreateRendererForLayout(
376 forwarded_audio_element.obu.audio_substream_ids_,
377 forwarded_audio_element.substream_id_to_labels,
378 forwarded_audio_element.obu.GetAudioElementType(),
379 forwarded_audio_element.obu.config_, _, _,
380 forwarded_audio_element.codec_config->GetNumSamplesPerFrame()));
381 renderer_factory_ = std::move(mock_renderer_factory);
382
383 auto finalizer = CreateFinalizerExpectOk();
384 }
385
TEST_F(FinalizerTest,ForwardsRenderingConfigToRenderer)386 TEST_F(FinalizerTest, ForwardsRenderingConfigToRenderer) {
387 InitPrerequisiteObusForStereoInput(kAudioElementId);
388 AddMixPresentationObuForStereoOutput(kMixPresentationId);
389 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
390 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
391
392 // We expect arguments to be forwarded from the OBUs to the renderer factory.
393 auto mock_renderer_factory = std::make_unique<MockRendererFactory>();
394 const auto& forwarded_sub_mix = obus_to_finalize_.front().sub_mixes_[0];
395 const auto& forwarded_rendering_config =
396 forwarded_sub_mix.audio_elements[0].rendering_config;
397 EXPECT_CALL(
398 *mock_renderer_factory,
399 CreateRendererForLayout(_, _, _, _, forwarded_rendering_config, _, _));
400 renderer_factory_ = std::move(mock_renderer_factory);
401
402 CreateFinalizerExpectOk();
403 }
404
TEST_F(FinalizerTest,ForwardsLayoutToRenderer)405 TEST_F(FinalizerTest, ForwardsLayoutToRenderer) {
406 InitPrerequisiteObusForStereoInput(kAudioElementId);
407 AddMixPresentationObuForStereoOutput(kMixPresentationId);
408 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
409 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
410
411 // We expect arguments to be forwarded from the OBUs to the renderer factory.
412 auto mock_renderer_factory = std::make_unique<MockRendererFactory>();
413 const auto& forwarded_sub_mix = obus_to_finalize_.front().sub_mixes_[0];
414 const auto& forwarded_layout = forwarded_sub_mix.layouts[0].loudness_layout;
415 EXPECT_CALL(*mock_renderer_factory,
416 CreateRendererForLayout(_, _, _, _, _, forwarded_layout, _));
417 renderer_factory_ = std::move(mock_renderer_factory);
418
419 CreateFinalizerExpectOk();
420 }
421
TEST_F(FinalizerTest,ForwardsOrderedSamplesToRenderer)422 TEST_F(FinalizerTest, ForwardsOrderedSamplesToRenderer) {
423 InitPrerequisiteObusForStereoInput(kAudioElementId);
424 AddMixPresentationObuForStereoOutput(kMixPresentationId);
425 const LabelSamplesMap kLabelToSamples = {{kL2, {0, 1}}, {kR2, {2, 3}}};
426 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
427
428 // We expect arguments to be forwarded from the OBUs to the renderer.
429 auto mock_renderer = std::make_unique<MockRenderer>(kStereoLabels, 2);
430 std::vector<InternalSampleType> rendered_samples;
431 const std::vector<std::vector<InternalSampleType>>
432 kExpectedTimeChannelOrderedSamples = {{0, 2}, {1, 3}};
433 EXPECT_CALL(*mock_renderer,
434 RenderSamples(
435 absl::MakeConstSpan(kExpectedTimeChannelOrderedSamples), _));
436 auto mock_renderer_factory = std::make_unique<MockRendererFactory>();
437 ASSERT_NE(mock_renderer_factory, nullptr);
438 EXPECT_CALL(*mock_renderer_factory,
439 CreateRendererForLayout(_, _, _, _, _, _, _))
440 .WillOnce(Return(std::move(mock_renderer)));
441 renderer_factory_ = std::move(mock_renderer_factory);
442 std::list<ParameterBlockWithData> parameter_blocks;
443
444 auto finalizer = CreateFinalizerExpectOk();
445 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
446 }
447
TEST_F(FinalizerTest,CreatesWavFileWhenRenderingIsSupported)448 TEST_F(FinalizerTest, CreatesWavFileWhenRenderingIsSupported) {
449 InitPrerequisiteObusForStereoInput(kAudioElementId);
450 AddMixPresentationObuForStereoOutput(kMixPresentationId);
451 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
452 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
453 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
454 auto mock_renderer = std::make_unique<MockRenderer>();
455 EXPECT_CALL(*mock_renderer, RenderSamples(_, _));
456 auto mock_renderer_factory = std::make_unique<MockRendererFactory>();
457 EXPECT_CALL(*mock_renderer_factory,
458 CreateRendererForLayout(_, _, _, _, _, _, _))
459 .WillOnce(Return(std::move(mock_renderer)));
460 renderer_factory_ = std::move(mock_renderer_factory);
461 std::list<ParameterBlockWithData> parameter_blocks;
462
463 auto finalizer = CreateFinalizerExpectOk();
464 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
465
466 EXPECT_TRUE(std::filesystem::exists(GetFirstSubmixFirstLayoutExpectedPath()));
467 }
468
TEST_F(FinalizerTest,DoesNotCreateFilesWhenRenderingFactoryIsNullptr)469 TEST_F(FinalizerTest, DoesNotCreateFilesWhenRenderingFactoryIsNullptr) {
470 InitPrerequisiteObusForStereoInput(kAudioElementId);
471 AddMixPresentationObuForStereoOutput(kMixPresentationId);
472 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
473 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
474 const std::filesystem::path output_directory =
475 GetAndCreateOutputDirectory("");
476 renderer_factory_ = nullptr;
477 std::list<ParameterBlockWithData> parameter_blocks;
478
479 auto finalizer = CreateFinalizerExpectOk();
480 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
481
482 EXPECT_TRUE(std::filesystem::is_empty(output_directory));
483 }
484
TEST_F(FinalizerTest,DoesNotCreateFilesWhenRenderingFactoryReturnsNullptr)485 TEST_F(FinalizerTest, DoesNotCreateFilesWhenRenderingFactoryReturnsNullptr) {
486 InitPrerequisiteObusForStereoInput(kAudioElementId);
487 AddMixPresentationObuForStereoOutput(kMixPresentationId);
488 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
489 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
490 const std::filesystem::path output_directory =
491 GetAndCreateOutputDirectory("");
492 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
493 renderer_factory_ = std::make_unique<AlwaysNullRendererFactory>();
494 std::list<ParameterBlockWithData> parameter_blocks;
495
496 auto finalizer = CreateFinalizerExpectOk();
497 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
498
499 EXPECT_TRUE(std::filesystem::is_empty(output_directory));
500 }
501
502 // =========== Tests on output rendered wav file properties ===========
503
TEST_F(FinalizerTest,UsesCodecConfigBitDepthWhenOverrideIsNotSet)504 TEST_F(FinalizerTest, UsesCodecConfigBitDepthWhenOverrideIsNotSet) {
505 InitPrerequisiteObusForMonoInput(kAudioElementId);
506 AddMixPresentationObuForMonoOutput(kMixPresentationId);
507 const LabelSamplesMap kLabelToSamples = {{kMono, {0, 1}}};
508 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
509 renderer_factory_ = std::make_unique<RendererFactory>();
510 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
511 std::list<ParameterBlockWithData> parameter_blocks;
512 auto finalizer = CreateFinalizerExpectOk();
513
514 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
515
516 const auto wav_reader =
517 CreateWavReaderExpectOk(GetFirstSubmixFirstLayoutExpectedPath());
518 EXPECT_EQ(wav_reader.bit_depth(), kCodecConfigBitDepth);
519 }
520
TEST_F(FinalizerTest,OverridesBitDepthWhenRequested)521 TEST_F(FinalizerTest, OverridesBitDepthWhenRequested) {
522 InitPrerequisiteObusForMonoInput(kAudioElementId);
523 AddMixPresentationObuForMonoOutput(kMixPresentationId);
524 const LabelSamplesMap kLabelToSamples = {{kMono, {0, 1}}};
525 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
526 renderer_factory_ = std::make_unique<RendererFactory>();
527 output_wav_file_bit_depth_override_ = 32;
528 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
529 std::list<ParameterBlockWithData> parameter_blocks;
530 auto finalizer = CreateFinalizerExpectOk();
531
532 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
533
534 const auto wav_reader =
535 CreateWavReaderExpectOk(GetFirstSubmixFirstLayoutExpectedPath());
536
537 EXPECT_EQ(wav_reader.bit_depth(), 32);
538 }
539
TEST_F(FinalizerTest,InvalidWhenFrameIsLargerThanNumSamplesPerFrame)540 TEST_F(FinalizerTest, InvalidWhenFrameIsLargerThanNumSamplesPerFrame) {
541 const LabelSamplesMap kInvalidLabelToSamplesWithTooManySamples = {
542 {kMono, std::vector<InternalSampleType>(kNumSamplesPerFrame + 1, 0)}};
543 InitPrerequisiteObusForMonoInput(kAudioElementId);
544 AddMixPresentationObuForMonoOutput(kMixPresentationId);
545 AddLabeledFrame(kAudioElementId, kInvalidLabelToSamplesWithTooManySamples,
546 kEndTime);
547 renderer_factory_ = std::make_unique<RendererFactory>();
548 std::list<ParameterBlockWithData> parameter_blocks;
549 auto finalizer = CreateFinalizerExpectOk();
550
551 EXPECT_FALSE(
552 finalizer
553 .PushTemporalUnit(
554 ordered_labeled_frames_[0], kStartTime,
555 ordered_labeled_frames_[0].at(kAudioElementId).end_timestamp,
556 parameter_blocks)
557 .ok());
558 }
559
TEST_F(FinalizerTest,WavFileHasExpectedProperties)560 TEST_F(FinalizerTest, WavFileHasExpectedProperties) {
561 const std::vector<InternalSampleType> kFourSamples = {1, 2, 3, 4};
562 InitPrerequisiteObusForMonoInput(kAudioElementId);
563 AddMixPresentationObuForMonoOutput(kMixPresentationId);
564 const LabelSamplesMap kLabelToSamples = {{kMono, kFourSamples}};
565 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
566 renderer_factory_ = std::make_unique<RendererFactory>();
567 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
568 std::list<ParameterBlockWithData> parameter_blocks;
569 auto finalizer = CreateFinalizerExpectOk();
570
571 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
572
573 const auto wav_reader =
574 CreateWavReaderExpectOk(GetFirstSubmixFirstLayoutExpectedPath());
575 EXPECT_EQ(wav_reader.remaining_samples(), kFourSamples.size());
576 EXPECT_EQ(wav_reader.sample_rate_hz(), kSampleRate);
577 EXPECT_EQ(wav_reader.num_channels(), 1);
578 EXPECT_EQ(wav_reader.bit_depth(), kBitDepth);
579 }
580
TEST_F(FinalizerTest,SamplesAreTrimmedFromWavFile)581 TEST_F(FinalizerTest, SamplesAreTrimmedFromWavFile) {
582 constexpr int kNumSamplesToTrimFromStart = 2;
583 constexpr int kNumSamplesToTrimFromEnd = 1;
584 constexpr int kExpectedNumSamples = 1;
585 const std::vector<InternalSampleType> kFourSamples = {1, 2, 3, 4};
586 InitPrerequisiteObusForMonoInput(kAudioElementId);
587 AddMixPresentationObuForMonoOutput(kMixPresentationId);
588 const LabelSamplesMap kLabelToSamples = {{kMono, kFourSamples}};
589 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime,
590 kNumSamplesToTrimFromStart, kNumSamplesToTrimFromEnd);
591 renderer_factory_ = std::make_unique<RendererFactory>();
592 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
593 std::list<ParameterBlockWithData> parameter_blocks;
594 auto finalizer = CreateFinalizerExpectOk();
595
596 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
597
598 const auto wav_reader =
599 CreateWavReaderExpectOk(GetFirstSubmixFirstLayoutExpectedPath());
600 EXPECT_EQ(wav_reader.remaining_samples(), kExpectedNumSamples);
601 }
602
TEST_F(FinalizerTest,SupportsFullyTrimmedFrames)603 TEST_F(FinalizerTest, SupportsFullyTrimmedFrames) {
604 // Sometimes at the start of a stream frames could be fully trimmed due to
605 // codec delay.
606 constexpr int kNumSamplesToTrimFromStart = 4;
607 constexpr int kExpectedZeroSamplesAfterTrimming = 0;
608 const std::vector<InternalSampleType> kFourSamples = {1, 2, 3, 4};
609 InitPrerequisiteObusForMonoInput(kAudioElementId);
610 AddMixPresentationObuForMonoOutput(kMixPresentationId);
611 const LabelSamplesMap kLabelToSamples = {{kMono, kFourSamples}};
612 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime,
613 kNumSamplesToTrimFromStart, kNoTrimFromEnd);
614 renderer_factory_ = std::make_unique<RendererFactory>();
615 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
616 std::list<ParameterBlockWithData> parameter_blocks;
617 auto finalizer = CreateFinalizerExpectOk();
618
619 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
620
621 const auto wav_reader =
622 CreateWavReaderExpectOk(GetFirstSubmixFirstLayoutExpectedPath());
623 EXPECT_EQ(wav_reader.remaining_samples(), kExpectedZeroSamplesAfterTrimming);
624 }
625
626 // =========== Tests for finalized OBUs ===========
627
628 const LoudnessInfo kExpectedMinimumLoudnessInfo = {
629 .info_type = 0,
630 .integrated_loudness = std::numeric_limits<int16_t>::min(),
631 .digital_peak = std::numeric_limits<int16_t>::min(),
632 };
633
634 const LoudnessInfo kArbitraryLoudnessInfo = {
635 .info_type = LoudnessInfo::kTruePeak,
636 .integrated_loudness = 123,
637 .digital_peak = 456,
638 .true_peak = 789,
639 };
640
TEST_F(FinalizerTest,CreatesWavFilesBasedOnFactoryFunction)641 TEST_F(FinalizerTest, CreatesWavFilesBasedOnFactoryFunction) {
642 PrepareObusForOneSamplePassThroughMono();
643
644 // A factory can be used to omit generating wav files.
645 renderer_factory_ = std::make_unique<RendererFactory>();
646 sample_processor_factory_ =
647 RenderingMixPresentationFinalizer::ProduceNoSampleProcessors;
648 auto finalizer_without_post_processors = CreateFinalizerExpectOk();
649 EXPECT_THAT(finalizer_without_post_processors.FinalizePushingTemporalUnits(),
650 IsOk());
651 EXPECT_FALSE(
652 std::filesystem::exists(GetFirstSubmixFirstLayoutExpectedPath()));
653
654 // Or a factory can be used to create wav files.
655 renderer_factory_ = std::make_unique<RendererFactory>();
656 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
657 auto finalizer_with_wav_writers = CreateFinalizerExpectOk();
658 EXPECT_THAT(finalizer_with_wav_writers.FinalizePushingTemporalUnits(),
659 IsOk());
660 EXPECT_TRUE(std::filesystem::exists(GetFirstSubmixFirstLayoutExpectedPath()));
661 }
662
TEST_F(FinalizerTest,ForwardsArgumentsToSampleProcessorFactory)663 TEST_F(FinalizerTest, ForwardsArgumentsToSampleProcessorFactory) {
664 PrepareObusForOneSamplePassThroughMono();
665 // Rendering needs to be initialized to create wav files.
666 renderer_factory_ = std::make_unique<RendererFactory>();
667 // We expect arguments to be forwarded from the OBUs to the wav writer
668 // factory.
669 constexpr int kFirstSubmixIndex = 0;
670 constexpr int kFirstLayoutIndex = 0;
671 const auto& forwarded_layout =
672 obus_to_finalize_.front().sub_mixes_[0].layouts[0].loudness_layout;
673 const int32_t forwarded_sample_rate = static_cast<int32_t>(
674 codec_configs_.at(kCodecConfigId).GetOutputSampleRate());
675 const int32_t forwarded_bit_depth = static_cast<int32_t>(
676 codec_configs_.at(kCodecConfigId).GetBitDepthToMeasureLoudness());
677 const uint32_t forwarded_num_samples_per_frame =
678 codec_configs_.at(kCodecConfigId).GetNumSamplesPerFrame();
679
680 MockSampleProcessorFactory mock_sample_processor_factory;
681 EXPECT_CALL(mock_sample_processor_factory,
682 Call(kMixPresentationId, kFirstSubmixIndex, kFirstLayoutIndex,
683 forwarded_layout, kNumchannelsForMono, forwarded_sample_rate,
684 forwarded_bit_depth, forwarded_num_samples_per_frame));
685 sample_processor_factory_ = mock_sample_processor_factory.AsStdFunction();
686
687 auto finalizer = CreateFinalizerExpectOk();
688 }
689
TEST_F(FinalizerTest,PushTemporalUnitDelegatesToSampleProcessor)690 TEST_F(FinalizerTest, PushTemporalUnitDelegatesToSampleProcessor) {
691 // Post-processing is only possible if rendering is enabled.
692 renderer_factory_ = std::make_unique<RendererFactory>();
693 const std::vector<std::vector<int32_t>> kExpectedPassthroughSamples = {
694 {0}, {std::numeric_limits<int32_t>::max()}};
695 const std::vector<InternalSampleType> kInputSamples = {0, 1.0};
696 InitPrerequisiteObusForMonoInput(kAudioElementId);
697 AddMixPresentationObuForMonoOutput(kMixPresentationId);
698 const LabelSamplesMap kLabelToSamples = {{kMono, {0, 1}}};
699 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
700 constexpr auto kNoOutputSamples = 0;
701 auto mock_sample_processor = std::make_unique<MockSampleProcessor>(
702 codec_configs_.at(kCodecConfigId).GetNumSamplesPerFrame(),
703 kNumchannelsForMono, kNoOutputSamples);
704 // We expect the post-processor to be called with the rendered samples.
705 EXPECT_CALL(
706 *mock_sample_processor,
707 PushFrameDerived(absl::MakeConstSpan(kExpectedPassthroughSamples)));
708 MockSampleProcessorFactory mock_sample_processor_factory;
709 EXPECT_CALL(mock_sample_processor_factory, Call(_, _, _, _, _, _, _, _))
710 .WillOnce(Return(std::move(mock_sample_processor)));
711 sample_processor_factory_ = mock_sample_processor_factory.AsStdFunction();
712
713 auto finalizer = CreateFinalizerExpectOk();
714
715 EXPECT_THAT(
716 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
717 /*start_timestamp=*/0,
718 /*end_timestamp=*/10, parameter_blocks_),
719 IsOk());
720 }
721
TEST_F(FinalizerTest,FinalizePushingTemporalUnitsDelegatesToSampleProcessorFlush)722 TEST_F(FinalizerTest,
723 FinalizePushingTemporalUnitsDelegatesToSampleProcessorFlush) {
724 // Post-processing is only possible if rendering is enabled.
725 renderer_factory_ = std::make_unique<RendererFactory>();
726 InitPrerequisiteObusForMonoInput(kAudioElementId);
727 AddMixPresentationObuForMonoOutput(kMixPresentationId);
728 constexpr auto kNoOutputSamples = 0;
729 auto mock_sample_processor = std::make_unique<MockSampleProcessor>(
730 codec_configs_.at(kCodecConfigId).GetNumSamplesPerFrame(),
731 kNumchannelsForMono, kNoOutputSamples);
732 // We expect sample processors to be flushed when FinalizePushingTemporalUnits
733 // is called.
734 MockSampleProcessorFactory mock_sample_processor_factory;
735 EXPECT_CALL(*mock_sample_processor, FlushDerived());
736 EXPECT_CALL(mock_sample_processor_factory, Call(_, _, _, _, _, _, _, _))
737 .WillOnce(Return(std::move(mock_sample_processor)));
738 sample_processor_factory_ = mock_sample_processor_factory.AsStdFunction();
739
740 auto finalizer = CreateFinalizerExpectOk();
741
742 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
743 }
744
TEST_F(FinalizerTest,ForwardsArgumentsToLoudnessCalculatorFactory)745 TEST_F(FinalizerTest, ForwardsArgumentsToLoudnessCalculatorFactory) {
746 PrepareObusForOneSamplePassThroughMono();
747 // We expect arguments to be forwarded from the OBUs to the loudness
748 // calculator factory.
749 auto mock_loudness_calculator_factory =
750 std::make_unique<MockLoudnessCalculatorFactory>();
751 const auto& forwarded_layout =
752 obus_to_finalize_.front().sub_mixes_[0].layouts[0];
753 const uint32_t forwarded_num_samples_per_frame =
754 codec_configs_.at(kCodecConfigId).GetNumSamplesPerFrame();
755 const int32_t forwarded_sample_rate = static_cast<int32_t>(
756 codec_configs_.at(kCodecConfigId).GetOutputSampleRate());
757 const int32_t forwarded_bit_depth_to_measure_loudness = static_cast<int32_t>(
758 codec_configs_.at(kCodecConfigId).GetBitDepthToMeasureLoudness());
759 EXPECT_CALL(
760 *mock_loudness_calculator_factory,
761 CreateLoudnessCalculator(
762 forwarded_layout, forwarded_num_samples_per_frame,
763 forwarded_sample_rate, forwarded_bit_depth_to_measure_loudness));
764 renderer_factory_ = std::make_unique<RendererFactory>();
765 loudness_calculator_factory_ = std::move(mock_loudness_calculator_factory);
766
767 auto finalizer = CreateFinalizerExpectOk();
768 }
769
TEST_F(FinalizerTest,DelegatestoLoudnessCalculator)770 TEST_F(FinalizerTest, DelegatestoLoudnessCalculator) {
771 const LoudnessInfo kMockCalculatedLoudness = kArbitraryLoudnessInfo;
772 const LoudnessInfo kMismatchingUserLoudness = kExpectedMinimumLoudnessInfo;
773 const std::vector<std::vector<int32_t>> kExpectedPassthroughSamples = {
774 {0}, {std::numeric_limits<int32_t>::max()}};
775 const std::vector<InternalSampleType> kInputSamples = {0, 1.0};
776 InitPrerequisiteObusForMonoInput(kAudioElementId);
777 AddMixPresentationObuForMonoOutput(kMixPresentationId);
778 const LabelSamplesMap kLabelToSamples = {{kMono, {0, 1}}};
779 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
780 // We expect arguments to be forwarded from the OBUs to the loudness
781 // calculator factory.
782 auto mock_loudness_calculator_factory =
783 std::make_unique<MockLoudnessCalculatorFactory>();
784 auto mock_loudness_calculator = std::make_unique<MockLoudnessCalculator>();
785 // We expect the loudness calculator to be called with the rendered samples.
786 EXPECT_CALL(*mock_loudness_calculator,
787 AccumulateLoudnessForSamples(
788 absl::MakeConstSpan(kExpectedPassthroughSamples)))
789 .WillOnce(Return(absl::OkStatus()));
790 ON_CALL(*mock_loudness_calculator, QueryLoudness())
791 .WillByDefault(Return(kArbitraryLoudnessInfo));
792 EXPECT_CALL(*mock_loudness_calculator_factory,
793 CreateLoudnessCalculator(_, _, _, _))
794 .WillOnce(Return(std::move(mock_loudness_calculator)));
795 renderer_factory_ = std::make_unique<RendererFactory>();
796 loudness_calculator_factory_ = std::move(mock_loudness_calculator_factory);
797 auto finalizer = CreateFinalizerExpectOk();
798
799 obus_to_finalize_.front().sub_mixes_[0].layouts[0].loudness =
800 kMismatchingUserLoudness;
801 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
802
803 // Data was copied based on `QueryLoudness()`.
804 EXPECT_EQ(finalized_obus_.front().sub_mixes_[0].layouts[0].loudness,
805 kArbitraryLoudnessInfo);
806 }
807
TEST_F(FinalizerTest,ValidatesUserLoudnessWhenRequested)808 TEST_F(FinalizerTest, ValidatesUserLoudnessWhenRequested) {
809 const LoudnessInfo kMockCalculatedLoudness = kArbitraryLoudnessInfo;
810 const LoudnessInfo kMismatchingUserLoudness = kExpectedMinimumLoudnessInfo;
811 PrepareObusForOneSamplePassThroughMono();
812
813 auto mock_loudness_calculator_factory =
814 std::make_unique<MockLoudnessCalculatorFactory>();
815 auto mock_loudness_calculator = std::make_unique<MockLoudnessCalculator>();
816 EXPECT_CALL(*mock_loudness_calculator, AccumulateLoudnessForSamples(_))
817 .WillOnce(Return(absl::OkStatus()));
818 ON_CALL(*mock_loudness_calculator, QueryLoudness())
819 .WillByDefault(Return(kMockCalculatedLoudness));
820 EXPECT_CALL(*mock_loudness_calculator_factory,
821 CreateLoudnessCalculator(_, _, _, _))
822 .WillOnce(Return(std::move(mock_loudness_calculator)));
823
824 // The user provided loudness does not match what the mock "measured".
825 obus_to_finalize_.front().sub_mixes_[0].layouts[0].loudness =
826 kMismatchingUserLoudness;
827 validate_loudness_ = kValidateLoudness;
828 renderer_factory_ = std::make_unique<RendererFactory>();
829 loudness_calculator_factory_ = std::move(mock_loudness_calculator_factory);
830 std::list<ParameterBlockWithData> parameter_blocks;
831 auto finalizer = CreateFinalizerExpectOk();
832
833 EXPECT_THAT(
834 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
835 /*start_timestamp=*/0,
836 /*end_timestamp=*/10, parameter_blocks),
837 IsOk());
838
839 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
840 EXPECT_FALSE(
841 finalizer.GetFinalizedMixPresentationObus(validate_loudness_).ok());
842 }
843
844 //============== Various modes fallback to preserving loudness. ==============
845
FinalizeOneFrameAndExpectUserLoudnessIsPreserved(const std::vector<IdLabeledFrameMap> & ordered_labeled_frames_,const LoudnessInfo & kExpectedLoudness,RenderingMixPresentationFinalizer & finalizer)846 void FinalizeOneFrameAndExpectUserLoudnessIsPreserved(
847 const std::vector<IdLabeledFrameMap>& ordered_labeled_frames_,
848 const LoudnessInfo& kExpectedLoudness,
849 RenderingMixPresentationFinalizer& finalizer) {
850 std::list<ParameterBlockWithData> parameter_blocks;
851 int64_t start_timestamp = 0;
852 for (const auto& id_to_labeled_frame : ordered_labeled_frames_) {
853 ASSERT_TRUE(id_to_labeled_frame.contains(kAudioElementId));
854 EXPECT_THAT(finalizer.PushTemporalUnit(
855 id_to_labeled_frame, start_timestamp,
856 id_to_labeled_frame.at(kAudioElementId).end_timestamp,
857 parameter_blocks),
858 IsOk());
859 }
860 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
861
862 const auto finalized_obus =
863 finalizer.GetFinalizedMixPresentationObus(kDontValidateLoudness);
864 ASSERT_THAT(finalized_obus, IsOkAndHolds(Not(IsEmpty())));
865
866 EXPECT_EQ(finalized_obus->front().sub_mixes_[0].layouts[0].loudness,
867 kExpectedLoudness);
868 }
869
TEST_F(FinalizerTest,PreservesUserLoudnessWhenRenderFactoryIsNullptr)870 TEST_F(FinalizerTest, PreservesUserLoudnessWhenRenderFactoryIsNullptr) {
871 PrepareObusForOneSamplePassThroughMono();
872 obus_to_finalize_.front().sub_mixes_[0].layouts[0].loudness =
873 kArbitraryLoudnessInfo;
874 renderer_factory_ = nullptr;
875 auto finalizer = CreateFinalizerExpectOk();
876
877 FinalizeOneFrameAndExpectUserLoudnessIsPreserved(
878 ordered_labeled_frames_, kArbitraryLoudnessInfo, finalizer);
879 }
880
TEST_F(FinalizerTest,PreservesUserLoudnessWhenRenderingIsNotSupported)881 TEST_F(FinalizerTest, PreservesUserLoudnessWhenRenderingIsNotSupported) {
882 PrepareObusForOneSamplePassThroughMono();
883 obus_to_finalize_.front().sub_mixes_[0].layouts[0].loudness =
884 kArbitraryLoudnessInfo;
885 renderer_factory_ = std::make_unique<AlwaysNullRendererFactory>();
886 loudness_calculator_factory_ =
887 std::make_unique<AlwaysNullLoudnessCalculatorFactory>();
888 auto finalizer = CreateFinalizerExpectOk();
889
890 FinalizeOneFrameAndExpectUserLoudnessIsPreserved(
891 ordered_labeled_frames_, kArbitraryLoudnessInfo, finalizer);
892 }
893
TEST_F(FinalizerTest,PreservesUserLoudnessWhenLoudnessFactoryIsNullPtr)894 TEST_F(FinalizerTest, PreservesUserLoudnessWhenLoudnessFactoryIsNullPtr) {
895 PrepareObusForOneSamplePassThroughMono();
896 obus_to_finalize_.front().sub_mixes_[0].layouts[0].loudness =
897 kArbitraryLoudnessInfo;
898 renderer_factory_ = std::make_unique<RendererFactory>();
899 loudness_calculator_factory_ = nullptr;
900 auto finalizer = CreateFinalizerExpectOk();
901
902 FinalizeOneFrameAndExpectUserLoudnessIsPreserved(
903 ordered_labeled_frames_, kArbitraryLoudnessInfo, finalizer);
904 }
905
TEST_F(FinalizerTest,PreservesUserLoudnessWhenLoudnessFactoryReturnsNullPtr)906 TEST_F(FinalizerTest, PreservesUserLoudnessWhenLoudnessFactoryReturnsNullPtr) {
907 PrepareObusForOneSamplePassThroughMono();
908 obus_to_finalize_.front().sub_mixes_[0].layouts[0].loudness =
909 kArbitraryLoudnessInfo;
910 renderer_factory_ = std::make_unique<RendererFactory>();
911 loudness_calculator_factory_ =
912 std::make_unique<AlwaysNullLoudnessCalculatorFactory>();
913 auto finalizer = CreateFinalizerExpectOk();
914
915 FinalizeOneFrameAndExpectUserLoudnessIsPreserved(
916 ordered_labeled_frames_, kArbitraryLoudnessInfo, finalizer);
917 }
918
TEST_F(FinalizerTest,CreateSucceedsWithValidInput)919 TEST_F(FinalizerTest, CreateSucceedsWithValidInput) {
920 InitPrerequisiteObusForStereoInput(kAudioElementId);
921 AddMixPresentationObuForStereoOutput(kMixPresentationId);
922 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
923 renderer_factory_ = std::make_unique<RendererFactory>();
924
925 auto finalizer = CreateFinalizerExpectOk();
926 }
927
TEST_F(FinalizerTest,FinalizePushingTemporalUnitsReturnsFailedPreconditionAfterFirstCall)928 TEST_F(FinalizerTest,
929 FinalizePushingTemporalUnitsReturnsFailedPreconditionAfterFirstCall) {
930 auto finalizer = CreateFinalizerExpectOk();
931 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
932
933 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(),
934 StatusIs(kFailedPrecondition));
935 }
936
TEST_F(FinalizerTest,GetFinalizedMixPresentationObusFailsBeforeFinalizePushingTemporalUnits)937 TEST_F(FinalizerTest,
938 GetFinalizedMixPresentationObusFailsBeforeFinalizePushingTemporalUnits) {
939 auto finalizer = CreateFinalizerExpectOk();
940
941 EXPECT_FALSE(
942 finalizer.GetFinalizedMixPresentationObus(kDontValidateLoudness).ok());
943 }
944
TEST_F(FinalizerTest,PushingIsNotAllowedAnyTimeAfterFinalizePushingTemporalUnits)945 TEST_F(FinalizerTest,
946 PushingIsNotAllowedAnyTimeAfterFinalizePushingTemporalUnits) {
947 InitPrerequisiteObusForMonoInput(kAudioElementId);
948 AddMixPresentationObuForMonoOutput(kMixPresentationId);
949 const LabelSamplesMap kLabelToSamples = {
950 {kMono, Int32ToInternalSampleType({100, 900})}};
951 const std::vector<std::vector<int32_t>> kExpectedSamples = {{100}, {900}};
952 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
953 auto finalizer = CreateFinalizerExpectOk();
954 EXPECT_THAT(
955 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
956 /*start_timestamp=*/0,
957 /*end_timestamp=*/10, parameter_blocks_),
958 IsOk());
959 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
960
961 // Any time after `FinalizePushingTemporalUnits()` has been called pushing is
962 // not allowed. Even if later functions such as
963 // `GetFinalizedMixPresentationObus` are called.
964 EXPECT_THAT(
965 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
966 /*start_timestamp=*/10,
967 /*end_timestamp=*/20, parameter_blocks_),
968 Not(IsOk()));
969 EXPECT_THAT(finalizer.GetFinalizedMixPresentationObus(kDontValidateLoudness),
970 IsOk());
971 EXPECT_THAT(
972 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
973 /*start_timestamp=*/10,
974 /*end_timestamp=*/20, parameter_blocks_),
975 Not(IsOk()));
976 }
977
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanCanBeUsedBeforeOrAfterGetFinalizedMixPresentationObus)978 TEST_F(
979 FinalizerTest,
980 GetPostProcessedSamplesAsSpanCanBeUsedBeforeOrAfterGetFinalizedMixPresentationObus) {
981 InitPrerequisiteObusForStereoInput(kAudioElementId);
982 AddMixPresentationObuForStereoOutput(kMixPresentationId);
983 renderer_factory_ = std::make_unique<RendererFactory>();
984 auto finalizer = CreateFinalizerExpectOk();
985 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
986
987 // It's acceptable to retrieve the post-processed samples either before or
988 // after retrieving the finalized mix presentation OBUs.
989 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
990 kMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
991 IsOk());
992 EXPECT_THAT(finalizer.GetFinalizedMixPresentationObus(kDontValidateLoudness),
993 IsOk());
994 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
995 kMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
996 IsOk());
997 }
998
TEST_F(FinalizerTest,GetFinalizedMixPresentationObusMayNotBeCalledTwice)999 TEST_F(FinalizerTest, GetFinalizedMixPresentationObusMayNotBeCalledTwice) {
1000 InitPrerequisiteObusForStereoInput(kAudioElementId);
1001 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1002 auto finalizer = CreateFinalizerExpectOk();
1003 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
1004
1005 EXPECT_THAT(finalizer.GetFinalizedMixPresentationObus(kDontValidateLoudness),
1006 IsOk());
1007
1008 // The finalized OBUs have already been flushed out and cannot be retrieved
1009 // again.
1010 EXPECT_THAT(finalizer.GetFinalizedMixPresentationObus(kDontValidateLoudness),
1011 Not(IsOk()));
1012 }
1013
TEST_F(FinalizerTest,GetFinalizedMixPresentationObusReturnsObusInSameorder)1014 TEST_F(FinalizerTest, GetFinalizedMixPresentationObusReturnsObusInSameorder) {
1015 InitPrerequisiteObusForStereoInput(kAudioElementId);
1016 constexpr DecodedUleb128 kFirstMixPresentationId = 100;
1017 constexpr DecodedUleb128 kSecondMixPresentationId = 99;
1018 constexpr DecodedUleb128 kThirdMixPresentationId = 101;
1019 AddMixPresentationObuForStereoOutput(kFirstMixPresentationId);
1020 AddMixPresentationObuForStereoOutput(kSecondMixPresentationId);
1021 AddMixPresentationObuForStereoOutput(kThirdMixPresentationId);
1022 auto finalizer = CreateFinalizerExpectOk();
1023 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
1024
1025 // We expect the entire list to come back in the same order. List order
1026 // may affect the priority downstream when selecting the default mix to
1027 // playback.
1028 ASSERT_THAT(finalizer.GetFinalizedMixPresentationObus(kDontValidateLoudness),
1029 IsOkAndHolds(Eq(obus_to_finalize_)));
1030 }
1031
1032 // =========== Tests for PushTemporalUnit ===========
1033 // TODO(b/380110994): Add more tests for PushTemporalUnit. Check that rendered
1034 // output is written to wav file appropriately.
TEST_F(FinalizerTest,PushTemporalUnitSucceedsWithValidInput)1035 TEST_F(FinalizerTest, PushTemporalUnitSucceedsWithValidInput) {
1036 InitPrerequisiteObusForStereoInput(kAudioElementId);
1037 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1038 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
1039 AddLabeledFrame(kAudioElementId, kLabelToSamples, /*end_timestamp=*/10);
1040
1041 ASSERT_EQ(ordered_labeled_frames_.size(), 1);
1042 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
1043 renderer_factory_ = std::make_unique<RendererFactory>();
1044 auto finalizer = CreateFinalizerExpectOk();
1045 EXPECT_THAT(finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
1046 /*start_timestamp=*/0,
1047 /*end_timestamp=*/10,
1048 /*parameter_blocks=*/{}),
1049 IsOk());
1050 }
1051
TEST_F(FinalizerTest,FullIterativeRenderingSucceedsWithValidInput)1052 TEST_F(FinalizerTest, FullIterativeRenderingSucceedsWithValidInput) {
1053 InitPrerequisiteObusForStereoInput(kAudioElementId);
1054 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1055 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
1056 AddLabeledFrame(kAudioElementId, kLabelToSamples, /*end_timestamp=*/10);
1057
1058 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
1059 renderer_factory_ = std::make_unique<RendererFactory>();
1060
1061 // Prepare a mock loudness calculator that will return arbitrary loudness
1062 // information.
1063 auto mock_loudness_calculator_factory =
1064 std::make_unique<MockLoudnessCalculatorFactory>();
1065 auto mock_loudness_calculator = std::make_unique<MockLoudnessCalculator>();
1066 ON_CALL(*mock_loudness_calculator, QueryLoudness())
1067 .WillByDefault(Return(kArbitraryLoudnessInfo));
1068 EXPECT_CALL(*mock_loudness_calculator_factory,
1069 CreateLoudnessCalculator(_, _, _, _))
1070 .WillOnce(Return(std::move(mock_loudness_calculator)));
1071 loudness_calculator_factory_ = std::move(mock_loudness_calculator_factory);
1072 validate_loudness_ = false;
1073 auto finalizer = CreateFinalizerExpectOk();
1074
1075 IterativeRenderingExpectOk(finalizer, parameter_blocks_);
1076
1077 // Then we expect the loudness to be populated with the computed loudness.
1078 EXPECT_EQ(finalized_obus_.front().sub_mixes_[0].layouts[0].loudness,
1079 kArbitraryLoudnessInfo);
1080 }
1081
TEST_F(FinalizerTest,InvalidComputedLoudnessFails)1082 TEST_F(FinalizerTest, InvalidComputedLoudnessFails) {
1083 InitPrerequisiteObusForStereoInput(kAudioElementId);
1084 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1085 const LabelSamplesMap kLabelToSamples = {{kL2, {0}}, {kR2, {2}}};
1086 AddLabeledFrame(kAudioElementId, kLabelToSamples, /*end_timestamp=*/10);
1087
1088 ConfigureWavWriterFactoryToProduceFirstSubMixFirstLayout();
1089 renderer_factory_ = std::make_unique<RendererFactory>();
1090
1091 // Prepare a mock loudness calculator that will return arbitrary loudness
1092 // information.
1093 auto mock_loudness_calculator_factory =
1094 std::make_unique<MockLoudnessCalculatorFactory>();
1095 auto mock_loudness_calculator = std::make_unique<MockLoudnessCalculator>();
1096 ON_CALL(*mock_loudness_calculator, QueryLoudness())
1097 .WillByDefault(Return(kArbitraryLoudnessInfo));
1098 EXPECT_CALL(*mock_loudness_calculator_factory,
1099 CreateLoudnessCalculator(_, _, _, _))
1100 .WillOnce(Return(std::move(mock_loudness_calculator)));
1101 loudness_calculator_factory_ = std::move(mock_loudness_calculator_factory);
1102
1103 auto finalizer = CreateFinalizerExpectOk();
1104 EXPECT_THAT(finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
1105 /*start_timestamp=*/0,
1106 /*end_timestamp=*/10,
1107 /*parameter_blocks=*/{}),
1108 IsOk());
1109 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
1110 // Do validate that computed loudness matches the user provided loudness -
1111 // since kArbitraryLoudnessInfo is the `computed` loudness, it won't.
1112 validate_loudness_ = true;
1113 EXPECT_FALSE(
1114 finalizer.GetFinalizedMixPresentationObus(validate_loudness_).ok());
1115 }
1116
1117 // =========== Tests for GetPostProcessedSamplesAsSpan ===========
1118
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanReturnsEmptySpanAfterCreate)1119 TEST_F(FinalizerTest,
1120 GetPostProcessedSamplesAsSpanReturnsEmptySpanAfterCreate) {
1121 InitPrerequisiteObusForStereoInput(kAudioElementId);
1122 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1123 renderer_factory_ = std::make_unique<RendererFactory>();
1124
1125 auto finalizer = CreateFinalizerExpectOk();
1126
1127 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1128 kMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
1129 IsOkAndHolds(IsEmpty()));
1130 }
1131
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanReturnsErrorWithRenderingDisabled)1132 TEST_F(FinalizerTest,
1133 GetPostProcessedSamplesAsSpanReturnsErrorWithRenderingDisabled) {
1134 InitPrerequisiteObusForStereoInput(kAudioElementId);
1135 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1136 // Disable rendering.
1137 renderer_factory_ = nullptr;
1138
1139 auto finalizer = CreateFinalizerExpectOk();
1140
1141 // Post-processed samples are only available if rendering was enabled.
1142 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1143 kMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
1144 Not(IsOk()));
1145 }
1146
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanReturnsErrorWithUnknownMixPresentationId)1147 TEST_F(FinalizerTest,
1148 GetPostProcessedSamplesAsSpanReturnsErrorWithUnknownMixPresentationId) {
1149 InitPrerequisiteObusForStereoInput(kAudioElementId);
1150 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1151 const DecodedUleb128 kUnknownMixPresentationId = kMixPresentationId + 1;
1152 renderer_factory_ = std::make_unique<RendererFactory>();
1153
1154 auto finalizer = CreateFinalizerExpectOk();
1155
1156 EXPECT_THAT(
1157 finalizer.GetPostProcessedSamplesAsSpan(
1158 kUnknownMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
1159 Not(IsOk()));
1160 }
1161
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanReturnsErrorWithUnknownLayoutIndex)1162 TEST_F(FinalizerTest,
1163 GetPostProcessedSamplesAsSpanReturnsErrorWithUnknownLayoutIndex) {
1164 InitPrerequisiteObusForStereoInput(kAudioElementId);
1165 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1166 const int kUnknownLayoutIndex = kFirstLayoutIndex + 1;
1167 renderer_factory_ = std::make_unique<RendererFactory>();
1168
1169 auto finalizer = CreateFinalizerExpectOk();
1170
1171 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1172 kMixPresentationId, kUnknownLayoutIndex, kFirstSubmixIndex),
1173 Not(IsOk()));
1174 }
1175
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanReturnsErrorWithUnknownSubmixIndex)1176 TEST_F(FinalizerTest,
1177 GetPostProcessedSamplesAsSpanReturnsErrorWithUnknownSubmixIndex) {
1178 InitPrerequisiteObusForStereoInput(kAudioElementId);
1179 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1180 const int kUnknownSubmixIndex = kFirstSubmixIndex + 1;
1181 renderer_factory_ = std::make_unique<RendererFactory>();
1182
1183 auto finalizer = CreateFinalizerExpectOk();
1184
1185 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1186 kMixPresentationId, kFirstLayoutIndex, kUnknownSubmixIndex),
1187 Not(IsOk()));
1188 }
1189
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanReturnsEmptySpanWhenFinalizedWithNoPostProcessor)1190 TEST_F(
1191 FinalizerTest,
1192 GetPostProcessedSamplesAsSpanReturnsEmptySpanWhenFinalizedWithNoPostProcessor) {
1193 InitPrerequisiteObusForStereoInput(kAudioElementId);
1194 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1195 renderer_factory_ = std::make_unique<RendererFactory>();
1196 sample_processor_factory_ =
1197 RenderingMixPresentationFinalizer::ProduceNoSampleProcessors;
1198
1199 auto finalizer = CreateFinalizerExpectOk();
1200 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
1201
1202 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1203 kMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
1204 IsOkAndHolds(IsEmpty()));
1205 }
1206
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanPrioritizesPostProcessedSamples)1207 TEST_F(FinalizerTest,
1208 GetPostProcessedSamplesAsSpanPrioritizesPostProcessedSamples) {
1209 InitPrerequisiteObusForStereoInput(kAudioElementId);
1210 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1211 const LabelSamplesMap kLabelToSamples = {
1212 {kL2, Int32ToInternalSampleType({0, 1})},
1213 {kR2, Int32ToInternalSampleType({2, 3})}};
1214 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
1215 renderer_factory_ = std::make_unique<RendererFactory>();
1216 const std::vector<std::vector<int32_t>> kExpectedSamples = {{1, 3}};
1217 // We expect the post-processor to be called with the rendered samples.
1218 sample_processor_factory_ =
1219 [](DecodedUleb128 /*mix_presentation_id*/, int /*sub_mix_index*/,
1220 int /*layout_index*/, const Layout& /*layout*/, int num_channels,
1221 int /*sample_rate*/, int /*bit_depth*/, size_t num_samples_per_frame) {
1222 return std::make_unique<EverySecondTickResampler>(num_samples_per_frame,
1223 num_channels);
1224 };
1225 auto finalizer = CreateFinalizerExpectOk();
1226
1227 // Push a temporal unit.
1228 EXPECT_THAT(
1229 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
1230 /*start_timestamp=*/0,
1231 /*end_timestamp=*/10, parameter_blocks_),
1232 IsOk());
1233
1234 // We expect the post-processed samples, i.e. every other tick.
1235 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1236 kMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
1237 IsOkAndHolds(absl::MakeConstSpan(kExpectedSamples)));
1238 }
1239
TEST_F(FinalizerTest,GetPostProcessedSamplesAsSpanReturnsFallsBackToRenderedSamples)1240 TEST_F(FinalizerTest,
1241 GetPostProcessedSamplesAsSpanReturnsFallsBackToRenderedSamples) {
1242 InitPrerequisiteObusForStereoInput(kAudioElementId);
1243 AddMixPresentationObuForStereoOutput(kMixPresentationId);
1244 const LabelSamplesMap kLabelToSamples = {
1245 {kL2, Int32ToInternalSampleType({0, 1})},
1246 {kR2, Int32ToInternalSampleType({2, 3})}};
1247 const std::vector<std::vector<int32_t>> kExpectedSamples = {{0, 2}, {1, 3}};
1248 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
1249 renderer_factory_ = std::make_unique<RendererFactory>();
1250 sample_processor_factory_ =
1251 RenderingMixPresentationFinalizer::ProduceNoSampleProcessors;
1252 auto finalizer = CreateFinalizerExpectOk();
1253
1254 // Push a temporal unit.
1255 EXPECT_THAT(
1256 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
1257 /*start_timestamp=*/0,
1258 /*end_timestamp=*/10, parameter_blocks_),
1259 IsOk());
1260
1261 // There is no post-processor, but it safely falls back to the pass-through
1262 // rendered samples.
1263 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1264 kMixPresentationId, kFirstLayoutIndex, kFirstSubmixIndex),
1265 IsOkAndHolds(absl::MakeConstSpan(kExpectedSamples)));
1266 }
1267
TEST_F(FinalizerTest,DelayedSamplesAreAvailableAfterFinalizePushingTemporalUnits)1268 TEST_F(FinalizerTest,
1269 DelayedSamplesAreAvailableAfterFinalizePushingTemporalUnits) {
1270 InitPrerequisiteObusForMonoInput(kAudioElementId);
1271 AddMixPresentationObuForMonoOutput(kMixPresentationId);
1272 renderer_factory_ = std::make_unique<RendererFactory>();
1273 sample_processor_factory_ =
1274 [](DecodedUleb128 /*mix_presentation_id*/, int /*sub_mix_index*/,
1275 int /*layout_index*/, const Layout& /*layout*/, int num_channels,
1276 int /*sample_rate*/, int /*bit_depth*/, size_t num_samples_per_frame) {
1277 return std::make_unique<OneFrameDelayer>(num_samples_per_frame,
1278 num_channels);
1279 };
1280 const LabelSamplesMap kLabelToSamples = {
1281 {kMono, Int32ToInternalSampleType({100, 900})}};
1282 const std::vector<std::vector<int32_t>> kExpectedSamples = {{100}, {900}};
1283 AddLabeledFrame(kAudioElementId, kLabelToSamples, kEndTime);
1284 auto finalizer = CreateFinalizerExpectOk();
1285
1286 // The post-processor has delay. So samples are not available immediately.
1287 EXPECT_THAT(
1288 finalizer.PushTemporalUnit(ordered_labeled_frames_[0],
1289 /*start_timestamp=*/0,
1290 /*end_timestamp=*/10, parameter_blocks_),
1291 IsOk());
1292 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1293 kMixPresentationId, kFirstSubmixIndex, kFirstLayoutIndex),
1294 IsOkAndHolds(IsEmpty()));
1295
1296 // But finally after flushing, samples are available.
1297 EXPECT_THAT(finalizer.FinalizePushingTemporalUnits(), IsOk());
1298 EXPECT_THAT(finalizer.GetPostProcessedSamplesAsSpan(
1299 kMixPresentationId, kFirstSubmixIndex, kFirstLayoutIndex),
1300 IsOkAndHolds(absl::MakeConstSpan(kExpectedSamples)));
1301 }
1302
1303 } // namespace
1304 } // namespace iamf_tools
1305