audio_roundtrip_test_lib/
test_suite.rs1use audio_encoder_test_lib::pcm_audio::*;
6use fidl_fuchsia_media::*;
7use log::info;
8use std::rc::Rc;
9use stream_processor_decoder_factory::*;
10use stream_processor_encoder_factory::*;
11use stream_processor_test::*;
12
13#[derive(Clone, Debug)]
14pub struct EncoderStream {
15 pub pcm_data: Vec<i16>,
16 pub pcm_framelength: usize,
18 pub frames_per_second: u32,
19 pub channel_count: usize,
20}
21
22pub struct Expectations {
23 pub encoded_output_data_size: usize,
24 pub decoded_output_data_size: usize,
25 pub format_details: FormatDetails,
26}
27
28#[allow(unused)]
29pub struct RoundTripTestSuite {
30 encoder_settings: EncoderSettings,
33 encoder_stream: EncoderStream,
34 decoder_stream: fn(Vec<u8>) -> Rc<dyn ElementaryStream>,
35
36 encoded_golden: Vec<u8>,
37
38 expectations: Expectations,
39 target_rmse: f64,
40 rmse_diff_tolerance: f64,
41}
42
43fn output_packet_data(output: Vec<Output>) -> Vec<u8> {
46 output
47 .into_iter()
48 .filter_map(|output| match output {
49 Output::Packet(packet) => Some(packet),
50 _ => None,
51 })
52 .flat_map(|packet| packet.data)
53 .collect()
54}
55
56#[allow(unused)]
57impl RoundTripTestSuite {
58 pub fn new(
59 encoder_settings: EncoderSettings,
60 encoder_stream: EncoderStream,
61 decoder_stream: fn(Vec<u8>) -> Rc<dyn ElementaryStream>,
62 encoded_golden: Vec<u8>,
63 decoded_golden: Vec<i16>,
64 expectations: Expectations,
65 rmse_diff_tolerance: f64,
66 ) -> Result<Self> {
67 let target_rmse = calculate_rmse(
68 encoder_stream.pcm_data.as_slice(),
69 decoded_golden.as_slice(),
70 encoder_stream.frames_per_second,
71 )?;
72 info!(
73 "Target RMSE calculated from input PCM and golden transcoded PCM is: {target_rmse}. RMSE difference tolerance is: {rmse_diff_tolerance}"
74 );
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}