1use crate::error::{CodecError, Result};
4use crate::types::{CodecType, SampleRate};
5
6pub fn validate_samples(samples: &[i16]) -> Result<()> {
8 if samples.is_empty() {
9 return Err(CodecError::invalid_format("Input samples cannot be empty"));
10 }
11
12 for (i, &sample) in samples.iter().enumerate() {
14 if sample.abs() > 32767 {
15 return Err(CodecError::invalid_format(format!(
16 "Sample at index {} out of range: {}",
17 i, sample
18 )));
19 }
20 }
21
22 Ok(())
23}
24
25pub fn validate_encoded_data(data: &[u8]) -> Result<()> {
27 if data.is_empty() {
28 return Err(CodecError::invalid_format("Encoded data cannot be empty"));
29 }
30
31 if data.len() > 1024 * 1024 {
33 return Err(CodecError::invalid_format(format!(
34 "Encoded data too large: {} bytes",
35 data.len()
36 )));
37 }
38
39 Ok(())
40}
41
42pub fn validate_frame_size(codec_type: CodecType, frame_size: usize) -> Result<()> {
44 let expected_sizes = match codec_type {
45 CodecType::G711Pcmu | CodecType::G711Pcma => {
46 vec![80, 160, 240, 320]
48 }
49
50 CodecType::G729 | CodecType::G729A | CodecType::G729BA => {
51 vec![80]
53 }
54 CodecType::Opus => {
55 vec![120, 240, 480, 960, 1920, 2880]
57 }
58 };
59
60 if !expected_sizes.contains(&frame_size) {
61 return Err(CodecError::InvalidFrameSize {
62 expected: expected_sizes[0],
63 actual: frame_size,
64 });
65 }
66
67 Ok(())
68}
69
70pub fn validate_sample_rate(codec_type: CodecType, sample_rate: SampleRate) -> Result<()> {
72 let supported_rates = codec_type.supported_sample_rates();
73 let rate_hz = sample_rate.hz();
74
75 if !supported_rates.contains(&rate_hz) {
76 return Err(CodecError::InvalidSampleRate {
77 rate: rate_hz,
78 supported: supported_rates.to_vec(),
79 });
80 }
81
82 Ok(())
83}
84
85pub fn validate_channels(codec_type: CodecType, channels: u8) -> Result<()> {
87 let supported_channels = codec_type.supported_channels();
88
89 if !supported_channels.contains(&channels) {
90 return Err(CodecError::InvalidChannelCount {
91 channels,
92 supported: supported_channels.to_vec(),
93 });
94 }
95
96 Ok(())
97}
98
99pub fn validate_bitrate(codec_type: CodecType, bitrate: u32) -> Result<()> {
101 let (min_bitrate, max_bitrate) = codec_type.bitrate_range();
102
103 if bitrate < min_bitrate || bitrate > max_bitrate {
104 return Err(CodecError::InvalidBitrate {
105 bitrate,
106 min: min_bitrate,
107 max: max_bitrate,
108 });
109 }
110
111 Ok(())
112}
113
114pub fn validate_buffer_sizes(
116 input_size: usize,
117 output_size: usize,
118 expected_ratio: f32,
119) -> Result<()> {
120 let expected_output_size = (input_size as f32 * expected_ratio) as usize;
121
122 if output_size < expected_output_size {
123 return Err(CodecError::BufferTooSmall {
124 needed: expected_output_size,
125 actual: output_size,
126 });
127 }
128
129 Ok(())
130}
131
132pub fn validate_channel_alignment(samples: &[i16], channels: u8) -> Result<()> {
134 if samples.len() % channels as usize != 0 {
135 return Err(CodecError::invalid_format(format!(
136 "Sample count {} not divisible by channel count {}",
137 samples.len(),
138 channels
139 )));
140 }
141
142 Ok(())
143}
144
145pub fn validate_g711_frame(samples: &[i16], expected_frame_size: usize) -> Result<()> {
147 validate_samples(samples)?;
148
149 if samples.len() != expected_frame_size {
150 return Err(CodecError::InvalidFrameSize {
151 expected: expected_frame_size,
152 actual: samples.len(),
153 });
154 }
155
156 Ok(())
157}
158
159pub fn validate_g722_frame(samples: &[i16], expected_frame_size: usize) -> Result<()> {
161 validate_samples(samples)?;
162
163 if samples.len() != expected_frame_size {
164 return Err(CodecError::InvalidFrameSize {
165 expected: expected_frame_size,
166 actual: samples.len(),
167 });
168 }
169
170 if samples.len() % 2 != 0 {
172 return Err(CodecError::invalid_format(
173 "G.722 requires even number of samples for QMF processing",
174 ));
175 }
176
177 Ok(())
178}
179
180pub fn validate_g729_frame(samples: &[i16]) -> Result<()> {
182 validate_samples(samples)?;
183
184 if samples.len() != 80 {
186 return Err(CodecError::InvalidFrameSize {
187 expected: 80,
188 actual: samples.len(),
189 });
190 }
191
192 Ok(())
193}
194
195pub fn validate_opus_frame(samples: &[i16], sample_rate: SampleRate) -> Result<()> {
197 validate_samples(samples)?;
198
199 let rate_hz = sample_rate.hz();
200 let frame_size = samples.len();
201
202 let valid_frame_sizes = match rate_hz {
204 8000 => vec![20, 40, 80, 160, 320, 480],
205 12000 => vec![30, 60, 120, 240, 480, 720],
206 16000 => vec![40, 80, 160, 320, 640, 960],
207 24000 => vec![60, 120, 240, 480, 960, 1440],
208 48000 => vec![120, 240, 480, 960, 1920, 2880],
209 _ => return Err(CodecError::InvalidSampleRate {
210 rate: rate_hz,
211 supported: vec![8000, 12000, 16000, 24000, 48000],
212 }),
213 };
214
215 if !valid_frame_sizes.contains(&frame_size) {
216 return Err(CodecError::InvalidFrameSize {
217 expected: valid_frame_sizes[0],
218 actual: frame_size,
219 });
220 }
221
222 Ok(())
223}
224
225pub fn validate_buffer_compatibility(
227 input: &[i16],
228 output: &[u8],
229 compression_ratio: f32,
230) -> Result<()> {
231 let expected_output_size = (input.len() as f32 * compression_ratio) as usize;
232
233 if output.len() < expected_output_size {
234 return Err(CodecError::BufferTooSmall {
235 needed: expected_output_size,
236 actual: output.len(),
237 });
238 }
239
240 Ok(())
241}
242
243pub fn validate_simd_alignment(data: &[i16]) -> Result<()> {
245 let ptr = data.as_ptr() as usize;
246
247 if ptr % 16 != 0 {
249 tracing::debug!("Data not aligned for SIMD operations, falling back to scalar");
250 }
251
252 Ok(())
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258 use crate::types::SampleRate;
259
260 #[test]
261 fn test_validate_samples() {
262 let valid_samples = vec![0, 1000, -1000, 16000, -16000];
263 assert!(validate_samples(&valid_samples).is_ok());
264
265 let empty_samples: Vec<i16> = vec![];
266 assert!(validate_samples(&empty_samples).is_err());
267 }
268
269 #[test]
270 fn test_validate_encoded_data() {
271 let valid_data = vec![0u8, 127, 255, 64, 192];
272 assert!(validate_encoded_data(&valid_data).is_ok());
273
274 let empty_data: Vec<u8> = vec![];
275 assert!(validate_encoded_data(&empty_data).is_err());
276
277 let too_large_data = vec![0u8; 2 * 1024 * 1024]; assert!(validate_encoded_data(&too_large_data).is_err());
279 }
280
281 #[test]
282 fn test_validate_frame_size() {
283 assert!(validate_frame_size(CodecType::G711Pcmu, 160).is_ok());
285 assert!(validate_frame_size(CodecType::G711Pcmu, 123).is_err());
286
287 assert!(validate_frame_size(CodecType::G729, 80).is_ok());
289 assert!(validate_frame_size(CodecType::G729, 160).is_err());
290 }
291
292 #[test]
293 fn test_validate_sample_rate() {
294 assert!(validate_sample_rate(CodecType::G711Pcmu, SampleRate::Rate8000).is_ok());
296 assert!(validate_sample_rate(CodecType::G711Pcmu, SampleRate::Rate48000).is_err());
297
298 assert!(validate_sample_rate(CodecType::Opus, SampleRate::Rate8000).is_ok());
300 assert!(validate_sample_rate(CodecType::Opus, SampleRate::Rate48000).is_ok());
301 }
302
303 #[test]
304 fn test_validate_channels() {
305 assert!(validate_channels(CodecType::G711Pcmu, 1).is_ok());
307 assert!(validate_channels(CodecType::G711Pcmu, 2).is_err());
308
309 assert!(validate_channels(CodecType::Opus, 1).is_ok());
311 assert!(validate_channels(CodecType::Opus, 2).is_ok());
312 assert!(validate_channels(CodecType::Opus, 3).is_err());
313 }
314
315 #[test]
316 fn test_validate_bitrate() {
317 assert!(validate_bitrate(CodecType::G711Pcmu, 64000).is_ok());
319 assert!(validate_bitrate(CodecType::G711Pcmu, 128000).is_err());
320
321 assert!(validate_bitrate(CodecType::Opus, 32000).is_ok());
323 assert!(validate_bitrate(CodecType::Opus, 600000).is_err());
324 }
325
326 #[test]
327 fn test_validate_buffer_sizes() {
328 assert!(validate_buffer_sizes(160, 80, 0.5).is_ok());
330 assert!(validate_buffer_sizes(160, 40, 0.5).is_err());
331 }
332
333 #[test]
334 fn test_validate_channel_alignment() {
335 let mono_samples = vec![0, 1, 2, 3, 4]; assert!(validate_channel_alignment(&mono_samples, 1).is_ok());
337 assert!(validate_channel_alignment(&mono_samples, 2).is_err());
338
339 let stereo_samples = vec![0, 1, 2, 3]; assert!(validate_channel_alignment(&stereo_samples, 2).is_ok());
341 }
342
343 #[test]
344 fn test_codec_specific_validation() {
345 let g711_frame = vec![0i16; 160];
347 assert!(validate_g711_frame(&g711_frame, 160).is_ok());
348 assert!(validate_g711_frame(&g711_frame, 80).is_err());
349
350 let g729_frame = vec![0i16; 80];
352 assert!(validate_g729_frame(&g729_frame).is_ok());
353
354 let wrong_g729_frame = vec![0i16; 160];
355 assert!(validate_g729_frame(&wrong_g729_frame).is_err());
356 }
357
358 #[test]
359 fn test_buffer_compatibility() {
360 let input = vec![0i16; 160];
361 let output = vec![0u8; 80];
362
363 assert!(validate_buffer_compatibility(&input, &output, 0.5).is_ok());
365
366 let small_output = vec![0u8; 40];
367 assert!(validate_buffer_compatibility(&input, &small_output, 0.5).is_err());
368 }
369}