1use crate::error::{CodecError, Result};
4use crate::types::{CodecType, SampleRate};
5
6pub fn validate_samples(samples: &[i16]) -> Result<()> {
12 if samples.is_empty() {
13 return Err(CodecError::invalid_format("Input samples cannot be empty"));
14 }
15 Ok(())
18}
19
20pub fn validate_encoded_data(data: &[u8]) -> Result<()> {
26 if data.is_empty() {
27 return Err(CodecError::invalid_format("Encoded data cannot be empty"));
28 }
29
30 if data.len() > 1024 * 1024 {
32 return Err(CodecError::invalid_format(format!(
33 "Encoded data too large: {} bytes",
34 data.len()
35 )));
36 }
37
38 Ok(())
39}
40
41pub fn validate_frame_size(codec_type: CodecType, frame_size: usize) -> Result<()> {
47 let expected_sizes = match codec_type {
48 CodecType::G711Pcmu | CodecType::G711Pcma => {
49 vec![80, 160, 240, 320]
51 }
52
53 CodecType::G729 | CodecType::G729A | CodecType::G729BA => {
54 vec![80]
56 }
57 CodecType::Opus => {
58 vec![120, 240, 480, 960, 1920, 2880]
60 }
61 };
62
63 if !expected_sizes.contains(&frame_size) {
64 return Err(CodecError::InvalidFrameSize {
65 expected: expected_sizes[0],
66 actual: frame_size,
67 });
68 }
69
70 Ok(())
71}
72
73pub fn validate_sample_rate(codec_type: CodecType, sample_rate: SampleRate) -> Result<()> {
79 let supported_rates = codec_type.supported_sample_rates();
80 let rate_hz = sample_rate.hz();
81
82 if !supported_rates.contains(&rate_hz) {
83 return Err(CodecError::InvalidSampleRate {
84 rate: rate_hz,
85 supported: supported_rates.to_vec(),
86 });
87 }
88
89 Ok(())
90}
91
92pub fn validate_channels(codec_type: CodecType, channels: u8) -> Result<()> {
98 let supported_channels = codec_type.supported_channels();
99
100 if !supported_channels.contains(&channels) {
101 return Err(CodecError::InvalidChannelCount {
102 channels,
103 supported: supported_channels.to_vec(),
104 });
105 }
106
107 Ok(())
108}
109
110pub const fn validate_bitrate(codec_type: CodecType, bitrate: u32) -> Result<()> {
116 let (min_bitrate, max_bitrate) = codec_type.bitrate_range();
117
118 if bitrate < min_bitrate || bitrate > max_bitrate {
119 return Err(CodecError::InvalidBitrate {
120 bitrate,
121 min: min_bitrate,
122 max: max_bitrate,
123 });
124 }
125
126 Ok(())
127}
128
129#[allow(
136 clippy::cast_possible_truncation,
137 clippy::cast_precision_loss,
138 clippy::cast_sign_loss
139)]
140pub fn validate_buffer_sizes(
141 input_size: usize,
142 output_size: usize,
143 expected_ratio: f32,
144) -> Result<()> {
145 let expected_output_size = (input_size as f32 * expected_ratio) as usize;
146
147 if output_size < expected_output_size {
148 return Err(CodecError::BufferTooSmall {
149 needed: expected_output_size,
150 actual: output_size,
151 });
152 }
153
154 Ok(())
155}
156
157#[allow(clippy::manual_is_multiple_of)]
163pub fn validate_channel_alignment(samples: &[i16], channels: u8) -> Result<()> {
164 if samples.len() % usize::from(channels) != 0 {
165 return Err(CodecError::invalid_format(format!(
166 "Sample count {} not divisible by channel count {}",
167 samples.len(),
168 channels
169 )));
170 }
171
172 Ok(())
173}
174
175pub fn validate_g711_frame(samples: &[i16], expected_frame_size: usize) -> Result<()> {
181 validate_samples(samples)?;
182
183 if samples.len() != expected_frame_size {
184 return Err(CodecError::InvalidFrameSize {
185 expected: expected_frame_size,
186 actual: samples.len(),
187 });
188 }
189
190 Ok(())
191}
192
193pub fn validate_g722_frame(samples: &[i16], expected_frame_size: usize) -> Result<()> {
200 validate_samples(samples)?;
201
202 if samples.len() != expected_frame_size {
203 return Err(CodecError::InvalidFrameSize {
204 expected: expected_frame_size,
205 actual: samples.len(),
206 });
207 }
208
209 if !samples.len().is_multiple_of(2) {
211 return Err(CodecError::invalid_format(
212 "G.722 requires even number of samples for QMF processing",
213 ));
214 }
215
216 Ok(())
217}
218
219pub fn validate_g729_frame(samples: &[i16]) -> Result<()> {
225 validate_samples(samples)?;
226
227 if samples.len() != 80 {
229 return Err(CodecError::InvalidFrameSize {
230 expected: 80,
231 actual: samples.len(),
232 });
233 }
234
235 Ok(())
236}
237
238pub fn validate_opus_frame(samples: &[i16], sample_rate: SampleRate) -> Result<()> {
245 validate_samples(samples)?;
246
247 let rate_hz = sample_rate.hz();
248 let frame_size = samples.len();
249
250 let valid_frame_sizes = match rate_hz {
252 8000 => vec![20, 40, 80, 160, 320, 480],
253 12000 => vec![30, 60, 120, 240, 480, 720],
254 16000 => vec![40, 80, 160, 320, 640, 960],
255 24000 => vec![60, 120, 240, 480, 960, 1440],
256 48000 => vec![120, 240, 480, 960, 1920, 2880],
257 _ => {
258 return Err(CodecError::InvalidSampleRate {
259 rate: rate_hz,
260 supported: vec![8000, 12000, 16000, 24000, 48000],
261 });
262 }
263 };
264
265 if !valid_frame_sizes.contains(&frame_size) {
266 return Err(CodecError::InvalidFrameSize {
267 expected: valid_frame_sizes[0],
268 actual: frame_size,
269 });
270 }
271
272 Ok(())
273}
274
275#[allow(
282 clippy::cast_possible_truncation,
283 clippy::cast_precision_loss,
284 clippy::cast_sign_loss
285)]
286pub fn validate_buffer_compatibility(
287 input: &[i16],
288 output: &[u8],
289 compression_ratio: f32,
290) -> Result<()> {
291 let expected_output_size = (input.len() as f32 * compression_ratio) as usize;
292
293 if output.len() < expected_output_size {
294 return Err(CodecError::BufferTooSmall {
295 needed: expected_output_size,
296 actual: output.len(),
297 });
298 }
299
300 Ok(())
301}
302
303pub fn validate_simd_alignment(data: &[i16]) -> Result<()> {
310 let ptr = data.as_ptr() as usize;
311
312 if !ptr.is_multiple_of(16) {
314 tracing::debug!("Data not aligned for SIMD operations, falling back to scalar");
315 }
316
317 Ok(())
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323 use crate::types::SampleRate;
324
325 #[test]
326 fn test_validate_samples() {
327 let valid_samples = vec![0, 1000, -1000, 16000, -16000];
328 assert!(validate_samples(&valid_samples).is_ok());
329
330 let empty_samples: Vec<i16> = vec![];
331 assert!(validate_samples(&empty_samples).is_err());
332 }
333
334 #[test]
335 fn test_validate_encoded_data() {
336 let valid_data = vec![0u8, 127, 255, 64, 192];
337 assert!(validate_encoded_data(&valid_data).is_ok());
338
339 let empty_data: Vec<u8> = vec![];
340 assert!(validate_encoded_data(&empty_data).is_err());
341
342 let too_large_data = vec![0u8; 2 * 1024 * 1024]; assert!(validate_encoded_data(&too_large_data).is_err());
344 }
345
346 #[test]
347 fn test_validate_frame_size() {
348 assert!(validate_frame_size(CodecType::G711Pcmu, 160).is_ok());
350 assert!(validate_frame_size(CodecType::G711Pcmu, 123).is_err());
351
352 assert!(validate_frame_size(CodecType::G729, 80).is_ok());
354 assert!(validate_frame_size(CodecType::G729, 160).is_err());
355 }
356
357 #[test]
358 fn test_validate_sample_rate() {
359 assert!(validate_sample_rate(CodecType::G711Pcmu, SampleRate::Rate8000).is_ok());
361 assert!(validate_sample_rate(CodecType::G711Pcmu, SampleRate::Rate48000).is_err());
362
363 assert!(validate_sample_rate(CodecType::Opus, SampleRate::Rate8000).is_ok());
365 assert!(validate_sample_rate(CodecType::Opus, SampleRate::Rate48000).is_ok());
366 }
367
368 #[test]
369 fn test_validate_channels() {
370 assert!(validate_channels(CodecType::G711Pcmu, 1).is_ok());
372 assert!(validate_channels(CodecType::G711Pcmu, 2).is_err());
373
374 assert!(validate_channels(CodecType::Opus, 1).is_ok());
376 assert!(validate_channels(CodecType::Opus, 2).is_ok());
377 assert!(validate_channels(CodecType::Opus, 3).is_err());
378 }
379
380 #[test]
381 fn test_validate_bitrate() {
382 assert!(validate_bitrate(CodecType::G711Pcmu, 64_000).is_ok());
384 assert!(validate_bitrate(CodecType::G711Pcmu, 128_000).is_err());
385
386 assert!(validate_bitrate(CodecType::Opus, 32_000).is_ok());
388 assert!(validate_bitrate(CodecType::Opus, 600_000).is_err());
389 }
390
391 #[test]
392 fn test_validate_buffer_sizes() {
393 assert!(validate_buffer_sizes(160, 80, 0.5).is_ok());
395 assert!(validate_buffer_sizes(160, 40, 0.5).is_err());
396 }
397
398 #[test]
399 fn test_validate_channel_alignment() {
400 let mono_samples = vec![0, 1, 2, 3, 4]; assert!(validate_channel_alignment(&mono_samples, 1).is_ok());
402 assert!(validate_channel_alignment(&mono_samples, 2).is_err());
403
404 let stereo_samples = vec![0, 1, 2, 3]; assert!(validate_channel_alignment(&stereo_samples, 2).is_ok());
406 }
407
408 #[test]
409 fn test_codec_specific_validation() {
410 let g711_frame = vec![0i16; 160];
412 assert!(validate_g711_frame(&g711_frame, 160).is_ok());
413 assert!(validate_g711_frame(&g711_frame, 80).is_err());
414
415 let g729_frame = vec![0i16; 80];
417 assert!(validate_g729_frame(&g729_frame).is_ok());
418
419 let wrong_g729_frame = vec![0i16; 160];
420 assert!(validate_g729_frame(&wrong_g729_frame).is_err());
421 }
422
423 #[test]
424 fn test_buffer_compatibility() {
425 let input = vec![0i16; 160];
426 let output = vec![0u8; 80];
427
428 assert!(validate_buffer_compatibility(&input, &output, 0.5).is_ok());
430
431 let small_output = vec![0u8; 40];
432 assert!(validate_buffer_compatibility(&input, &small_output, 0.5).is_err());
433 }
434}