1use crate::pcm_audio::*;
6use crate::timestamp_validator::*;
7use fidl_fuchsia_media::*;
8use fidl_fuchsia_sysmem2::*;
9
10use rand::prelude::*;
11use std::rc::Rc;
12use stream_processor_encoder_factory::*;
13use stream_processor_test::*;
14
15pub const TEST_PCM_FRAME_COUNT: usize = 3000;
16
17pub struct AudioEncoderTestCase {
18 pub settings: EncoderSettings,
20 pub input_framelength: usize,
22 pub input_frames_per_second: u32,
24 pub channel_count: usize,
25 pub output_tests: Vec<AudioEncoderOutputTest>,
26}
27
28pub struct AudioEncoderOutputTest {
32 pub output_file: Option<&'static str>,
35 pub input_audio: PcmAudio,
36 pub expected_output_size: OutputSize,
37 pub expected_digests: Option<Vec<ExpectedDigest>>,
38}
39
40impl AudioEncoderOutputTest {
41 pub fn saw_wave_test(
42 frames_per_second: u32,
43 expected_output_size: OutputSize,
44 expected_digests: Vec<ExpectedDigest>,
45 ) -> Self {
46 Self {
47 output_file: None,
48 input_audio: PcmAudio::create_saw_wave(
49 PcmFormat {
50 pcm_mode: AudioPcmMode::Linear,
51 bits_per_sample: 16,
52 frames_per_second,
53 channel_map: vec![AudioChannelId::Cf],
54 },
55 TEST_PCM_FRAME_COUNT,
56 ),
57 expected_output_size,
58 expected_digests: Some(expected_digests),
59 }
60 }
61}
62
63impl AudioEncoderTestCase {
64 pub async fn run(self) -> Result<()> {
65 self.test_termination().await?;
66 self.test_early_termination().await?;
67 self.test_timestamps().await?;
68 self.test_outputs().await
69 }
70
71 async fn test_outputs(self) -> Result<()> {
72 let mut cases = vec![];
73 let easy_framelength = self.input_framelength;
74 for (output_test, stream_lifetime_ordinal) in
75 self.output_tests.into_iter().zip(OrdinalPattern::Odd.into_iter())
76 {
77 let settings = self.settings.clone();
78 let pcm_audio = output_test.input_audio;
79 let stream = Rc::new(PcmAudioStream {
80 pcm_audio,
81 encoder_settings: settings.clone(),
82 frames_per_packet: (0..).map(move |_| easy_framelength),
83 timebase: None,
84 });
85 let mut validators: Vec<Rc<dyn OutputValidator>> =
86 vec![Rc::new(TerminatesWithValidator {
87 expected_terminal_output: Output::Eos { stream_lifetime_ordinal },
88 })];
89 match output_test.expected_output_size {
90 OutputSize::PacketCount(v) => {
91 validators.push(Rc::new(OutputPacketCountValidator {
92 expected_output_packet_count: v,
93 }));
94 }
95 OutputSize::RawBytesCount(v) => {
96 validators
97 .push(Rc::new(OutputDataSizeValidator { expected_output_data_size: v }));
98 }
99 }
100
101 if let Some(expected_digests) = output_test.expected_digests {
102 validators.push(Rc::new(BytesValidator {
103 output_file: output_test.output_file,
104 expected_digests,
105 }));
106 }
107 cases.push(TestCase {
108 name: "Audio encoder output test",
109 stream,
110 validators,
111 stream_options: Some(StreamOptions {
112 queue_format_details: false,
113 ..StreamOptions::default()
114 }),
115 });
116 }
117
118 let spec = TestSpec {
119 cases,
120 relation: CaseRelation::Serial,
121 stream_processor_factory: Rc::new(EncoderFactory),
122 };
123
124 spec.run().await.map(|_| ())
125 }
126
127 async fn test_termination(&self) -> Result<()> {
128 let easy_framelength = self.input_framelength;
129 let stream = self.create_test_stream((0..).map(move |_| easy_framelength));
130 let eos_validator = Rc::new(TerminatesWithValidator {
131 expected_terminal_output: Output::Eos { stream_lifetime_ordinal: 1 },
132 });
133
134 let case = TestCase {
135 name: "Terminates with EOS test",
136 stream,
137 validators: vec![eos_validator],
138 stream_options: None,
139 };
140
141 let spec = TestSpec {
142 cases: vec![case],
143 relation: CaseRelation::Concurrent,
144 stream_processor_factory: Rc::new(EncoderFactory),
145 };
146
147 spec.run().await.map(|_| ())
148 }
149
150 async fn test_early_termination(&self) -> Result<()> {
151 let easy_framelength = self.input_framelength;
152 let stream = self.create_test_stream((0..).map(move |_| easy_framelength));
153 let count_validator =
154 Rc::new(OutputPacketCountValidator { expected_output_packet_count: 1 });
155
156 const ODD_OUTPUT_PACKET_SIZE: u64 = 4096 - 1;
160
161 let stream_options = Some(StreamOptions {
162 output_buffer_collection_constraints: Some(BufferCollectionConstraints {
163 buffer_memory_constraints: Some(BufferMemoryConstraints {
164 min_size_bytes: Some(ODD_OUTPUT_PACKET_SIZE),
165 ..buffer_memory_constraints_default()
166 }),
167 ..buffer_collection_constraints_default()
168 }),
169 stop_after_first_output: true,
170 ..StreamOptions::default()
171 });
172 let case = TestCase {
173 name: "Early termination test",
174 stream,
175 validators: vec![count_validator],
176 stream_options,
177 };
178
179 let spec = TestSpec {
180 cases: vec![case],
181 relation: CaseRelation::Concurrent,
182 stream_processor_factory: Rc::new(EncoderFactory),
183 };
184
185 spec.run().await.map(|_| ())
186 }
187
188 async fn test_timestamps(&self) -> Result<()> {
189 let max_framelength = self.input_framelength * 5;
190
191 let fixed_framelength = self.input_framelength + 1;
192 let fixed_framelength_stream =
193 self.create_test_stream((0..).map(move |_| fixed_framelength));
194 let pcm_frame_size = fixed_framelength_stream.pcm_audio.frame_size();
195
196 let stream_options = Some(StreamOptions {
197 input_buffer_collection_constraints: Some(BufferCollectionConstraints {
198 buffer_memory_constraints: Some(BufferMemoryConstraints {
199 min_size_bytes: Some((max_framelength * pcm_frame_size) as u64),
200 ..buffer_memory_constraints_default()
201 }),
202 ..buffer_collection_constraints_default()
203 }),
204 ..StreamOptions::default()
205 });
206
207 let fixed_framelength_case = TestCase {
208 name: "Timestamp extrapolation test - fixed framelength",
209 validators: vec![Rc::new(TimestampValidator::new(
210 self.input_framelength,
211 pcm_frame_size,
212 fixed_framelength_stream.timestamp_generator(),
213 fixed_framelength_stream.as_ref(),
214 ))],
215 stream: fixed_framelength_stream,
216 stream_options: stream_options.clone(),
217 };
218
219 let variable_framelength_stream = self.create_test_stream((0..).map(move |i| {
220 let mut rng = StdRng::seed_from_u64(i as u64);
221 rng.random_range(1..=max_framelength)
222 }));
223 let variable_framelength_case = TestCase {
224 name: "Timestamp extrapolation test - variable framelength",
225 validators: vec![Rc::new(TimestampValidator::new(
226 self.input_framelength,
227 pcm_frame_size,
228 variable_framelength_stream.timestamp_generator(),
229 variable_framelength_stream.as_ref(),
230 ))],
231 stream: variable_framelength_stream,
232 stream_options,
233 };
234
235 let spec = TestSpec {
236 cases: vec![fixed_framelength_case, variable_framelength_case],
237 relation: CaseRelation::Concurrent,
238 stream_processor_factory: Rc::new(EncoderFactory),
239 };
240
241 spec.run().await.map(|_| ())
242 }
243
244 fn create_test_stream<I>(&self, frames_per_packet: I) -> Rc<PcmAudioStream<I>> {
245 let pcm_format = PcmFormat {
246 pcm_mode: AudioPcmMode::Linear,
247 bits_per_sample: 16,
248 frames_per_second: self.input_frames_per_second,
249 channel_map: match self.channel_count {
250 1 => vec![AudioChannelId::Cf],
251 2 => vec![AudioChannelId::Lf, AudioChannelId::Rf],
252 c => panic!("{} is not a valid channel count", c),
253 },
254 };
255 let pcm_audio = PcmAudio::create_saw_wave(pcm_format.clone(), TEST_PCM_FRAME_COUNT);
256 let settings = self.settings.clone();
257 Rc::new(PcmAudioStream {
258 pcm_audio,
259 encoder_settings: settings.clone(),
260 frames_per_packet: frames_per_packet,
261 timebase: Some(zx::MonotonicDuration::from_seconds(1).into_nanos() as u64),
262 })
263 }
264}