audio_roundtrip_test_lib/
test_suite.rs1#![allow(clippy::large_futures)]
6
7use audio_encoder_test_lib::pcm_audio::*;
8use fidl_fuchsia_media::*;
9use log::info;
10use std::rc::Rc;
11use stream_processor_decoder_factory::*;
12use stream_processor_encoder_factory::*;
13use stream_processor_test::*;
14
15#[derive(Clone, Debug)]
16pub struct EncoderStream {
17 pub pcm_data: Vec<i16>,
18 pub pcm_framelength: usize,
20 pub frames_per_second: u32,
21 pub channel_count: usize,
22}
23
24pub struct Expectations {
25 pub encoded_output_data_size: usize,
26 pub decoded_output_data_size: usize,
27 pub format_details: FormatDetails,
28}
29
30#[allow(unused)]
31pub struct RoundTripTestSuite {
32 encoder_settings: EncoderSettings,
35 encoder_stream: EncoderStream,
36 decoder_stream: fn(Vec<u8>) -> Rc<dyn ElementaryStream>,
37
38 encoded_golden: Vec<u8>,
39
40 expectations: Expectations,
41 target_rmse: f64,
42 rmse_diff_tolerance: f64,
43}
44
45fn output_packet_data(output: Vec<Output>) -> Vec<u8> {
48 output
49 .into_iter()
50 .filter_map(|output| match output {
51 Output::Packet(packet) => Some(packet),
52 _ => None,
53 })
54 .flat_map(|packet| packet.data)
55 .collect()
56}
57
58#[allow(unused)]
59impl RoundTripTestSuite {
60 pub fn new(
61 encoder_settings: EncoderSettings,
62 encoder_stream: EncoderStream,
63 decoder_stream: fn(Vec<u8>) -> Rc<dyn ElementaryStream>,
64 encoded_golden: Vec<u8>,
65 decoded_golden: Vec<i16>,
66 expectations: Expectations,
67 rmse_diff_tolerance: f64,
68 ) -> Result<Self> {
69 let target_rmse = calculate_rmse(
70 encoder_stream.pcm_data.as_slice(),
71 decoded_golden.as_slice(),
72 encoder_stream.frames_per_second,
73 )?;
74 info!("Target RMSE calculated from input PCM and golden transcoded PCM is: {target_rmse}. RMSE difference tolerance is: {rmse_diff_tolerance}");
75 Ok(Self {
76 encoder_settings,
77 encoder_stream,
78 decoder_stream,
79 encoded_golden,
80 expectations,
81 target_rmse,
82 rmse_diff_tolerance,
83 })
84 }
85
86 pub async fn run(self) -> Result<()> {
87 self.test_roundtrip().await?;
88 self.test_oneway().await
89 }
90
91 async fn test_roundtrip(&self) -> Result<()> {
94 let encoded_output = self.run_through_encoder().await?;
95 let encoded_data = output_packet_data(encoded_output);
96 self.run_through_decoder(encoded_data).await
97 }
98
99 async fn test_oneway(mut self) -> Result<()> {
104 let encoded_data = std::mem::replace(&mut self.encoded_golden, vec![]);
107 self.run_through_decoder(encoded_data).await
108 }
109
110 async fn run_through_encoder(&self) -> Result<TestCaseOutputs> {
111 let easy_framelength = self.encoder_stream.pcm_framelength;
112 let pcm_audio = PcmAudio::create_from_data(
113 PcmFormat {
114 pcm_mode: AudioPcmMode::Linear,
115 bits_per_sample: 16,
116 frames_per_second: self.encoder_stream.frames_per_second,
117 channel_map: vec![AudioChannelId::Cf],
118 },
119 self.encoder_stream.pcm_data.as_slice(),
120 );
121 let settings = self.encoder_settings.clone();
122 let case = TestCase {
123 name: "Audio encoder test",
124 stream: Rc::new(PcmAudioStream {
125 pcm_audio,
126 encoder_settings: settings,
127 frames_per_packet: (0..).map(move |_| easy_framelength),
128 timebase: None,
129 }),
130 validators: vec![
131 Rc::new(TerminatesWithValidator {
132 expected_terminal_output: Output::Eos { stream_lifetime_ordinal: 1 },
133 }),
134 Rc::new(OutputDataSizeValidator {
135 expected_output_data_size: self.expectations.encoded_output_data_size,
136 }),
137 ],
138 stream_options: Some(StreamOptions {
139 queue_format_details: false,
140 ..StreamOptions::default()
141 }),
142 };
143 let spec = TestSpec {
144 cases: vec![case],
145 relation: CaseRelation::Serial,
146 stream_processor_factory: Rc::new(EncoderFactory),
147 };
148 let mut output_data =
149 spec.run().await?.expect("Output data should be returned from serial test");
150 assert_eq!(output_data.len(), 1);
151 Ok(output_data.swap_remove(0))
152 }
153
154 async fn run_through_decoder(&self, data: Vec<u8>) -> Result<()> {
155 let case = TestCase {
156 name: "Audio decoder RMSE test",
157 stream: (self.decoder_stream)(data),
158 validators: vec![
159 Rc::new(TerminatesWithValidator {
160 expected_terminal_output: Output::Eos { stream_lifetime_ordinal: 1 },
161 }),
162 Rc::new(OutputDataSizeValidator {
163 expected_output_data_size: self.expectations.decoded_output_data_size,
164 }),
165 Rc::new(FormatValidator {
166 expected_format: self.expectations.format_details.clone(),
167 }),
168 Rc::new(RmseValidator::<i16> {
169 output_file: None,
170 expected_data: self.encoder_stream.pcm_data.clone(),
171 expected_rmse: self.target_rmse,
172 rmse_diff_tolerance: self.rmse_diff_tolerance,
173 data_len_diff_tolerance: self.encoder_stream.frames_per_second,
174 output_converter: |data: Vec<u8>| {
175 data.chunks_exact(2)
176 .into_iter()
177 .map(|d| i16::from_ne_bytes([d[0], d[1]]))
178 .collect()
179 },
180 }),
181 ],
182 stream_options: Some(StreamOptions {
183 queue_format_details: false,
184 ..StreamOptions::default()
185 }),
186 };
187 let spec = TestSpec {
188 cases: vec![case],
189 relation: CaseRelation::Serial,
190 stream_processor_factory: Rc::new(DecoderFactory),
191 };
192
193 spec.run().await.map(|_| ())
194 }
195}