Skip to main content

audio_decoder_test_lib/
test_suite.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fidl_fuchsia_media::*;
6use fidl_fuchsia_sysmem2::{BufferCollectionConstraints, BufferMemoryConstraints};
7use std::rc::Rc;
8use stream_processor_decoder_factory::*;
9use stream_processor_test::*;
10
11pub struct AudioDecoderTestCase {
12    pub output_tests: Vec<AudioDecoderOutputTest>,
13}
14
15/// A hash test runs audio through the encoder and checks that all that data emitted when hashed
16/// sequentially results in the expected digest. Oob bytes are hashed first.
17pub struct AudioDecoderOutputTest {
18    /// If provided, the output will also be written to this file. Use this to verify new files
19    /// with a decoder before using their digest in tests.
20    pub output_file: Option<&'static str>,
21    pub stream: Rc<dyn ElementaryStream>,
22    pub expected_output_size: OutputSize,
23    pub expected_digests: Option<Vec<ExpectedDigest>>,
24    pub expected_output_format: FormatDetails,
25}
26
27fn test_buffer_collection_constraints() -> BufferCollectionConstraints {
28    BufferCollectionConstraints {
29        buffer_memory_constraints: Some(BufferMemoryConstraints {
30            // Chosen to be larger than most decoder tests requirements, and not particularly
31            // an even size of output frames (at 16 bits per sample, an odd number satisfies this)
32            min_size_bytes: Some(10001),
33            ..Default::default()
34        }),
35        ..buffer_collection_constraints_default()
36    }
37}
38
39impl AudioDecoderTestCase {
40    pub async fn run(self) -> Result<()> {
41        self.test_hashes().await
42    }
43
44    async fn test_hashes(self) -> Result<()> {
45        let mut cases = vec![];
46        for (output_test, stream_lifetime_ordinal) in
47            self.output_tests.into_iter().zip(OrdinalPattern::Odd.into_iter())
48        {
49            let mut validators: Vec<Rc<dyn OutputValidator>> =
50                vec![Rc::new(TerminatesWithValidator {
51                    expected_terminal_output: Output::Eos { stream_lifetime_ordinal },
52                })];
53            match output_test.expected_output_size {
54                OutputSize::PacketCount(v) => {
55                    validators.push(Rc::new(OutputPacketCountValidator {
56                        expected_output_packet_count: v,
57                    }));
58                }
59                OutputSize::RawBytesCount(v) => {
60                    validators
61                        .push(Rc::new(OutputDataSizeValidator { expected_output_data_size: v }));
62                }
63            };
64            validators.push(Rc::new(FormatValidator {
65                expected_format: output_test.expected_output_format,
66            }));
67            if let Some(digests) = output_test.expected_digests {
68                validators.push(Rc::new(BytesValidator {
69                    output_file: output_test.output_file,
70                    expected_digests: digests,
71                }));
72            }
73            cases.push(TestCase {
74                name: "Audio decoder output test",
75                stream: output_test.stream,
76                validators,
77                stream_options: Some(StreamOptions {
78                    queue_format_details: false,
79                    // Set the buffer constraints slightly off-kilter to test fenceposting
80                    output_buffer_collection_constraints: Some(test_buffer_collection_constraints()),
81                    ..StreamOptions::default()
82                }),
83            });
84        }
85
86        let spec = TestSpec {
87            cases,
88            relation: CaseRelation::Serial,
89            stream_processor_factory: Rc::new(DecoderFactory),
90        };
91
92        spec.run().await.map(|_| ())
93    }
94}