1#![allow(clippy::cast_possible_truncation)]
4#![allow(clippy::cast_possible_wrap)]
5#![cfg_attr(not(opus_codec_rust_packet_ops), allow(dead_code))]
6
7use crate::bindings::{
8 OPUS_BANDWIDTH_FULLBAND, OPUS_BANDWIDTH_MEDIUMBAND, OPUS_BANDWIDTH_NARROWBAND,
9 OPUS_BANDWIDTH_SUPERWIDEBAND, OPUS_BANDWIDTH_WIDEBAND, opus_multistream_packet_unpad,
10 opus_packet_get_bandwidth, opus_packet_get_nb_channels, opus_packet_get_nb_frames,
11 opus_packet_get_nb_samples, opus_packet_get_samples_per_frame, opus_packet_has_lbrr,
12 opus_packet_parse, opus_packet_unpad, opus_pcm_soft_clip,
13};
14#[cfg(not(opus_codec_rust_packet_ops))]
15use crate::bindings::{opus_multistream_packet_pad, opus_packet_pad};
16use crate::error::{Error, Result};
17use crate::types::{Bandwidth, Channels, SampleRate};
18
19mod layout;
20
21pub(crate) use layout::MAX_FRAMES_PER_PACKET;
22#[cfg(opus_codec_rust_packet_ops)]
23pub(crate) use layout::{
24 PacketPadding, PacketRepacketizerLayout, packet_repacketizer_layout, repacketize_frames,
25 repacketize_frames_range,
26};
27#[cfg(opus_codec_rust_packet_ops)]
28use layout::{multistream_last_stream_offset, pad_single_packet};
29
30pub fn packet_bandwidth(packet: &[u8]) -> Result<Bandwidth> {
35 if packet.is_empty() {
36 return Err(Error::BadArg);
37 }
38 let bw = unsafe { opus_packet_get_bandwidth(packet.as_ptr()) };
39 match bw {
40 x if x == OPUS_BANDWIDTH_NARROWBAND as i32 => Ok(Bandwidth::Narrowband),
41 x if x == OPUS_BANDWIDTH_MEDIUMBAND as i32 => Ok(Bandwidth::Mediumband),
42 x if x == OPUS_BANDWIDTH_WIDEBAND as i32 => Ok(Bandwidth::Wideband),
43 x if x == OPUS_BANDWIDTH_SUPERWIDEBAND as i32 => Ok(Bandwidth::SuperWideband),
44 x if x == OPUS_BANDWIDTH_FULLBAND as i32 => Ok(Bandwidth::Fullband),
45 _ => Err(Error::InvalidPacket),
46 }
47}
48
49pub fn packet_channels(packet: &[u8]) -> Result<Channels> {
54 if packet.is_empty() {
55 return Err(Error::BadArg);
56 }
57 let ch = unsafe { opus_packet_get_nb_channels(packet.as_ptr()) };
58 match ch {
59 1 => Ok(Channels::Mono),
60 2 => Ok(Channels::Stereo),
61 _ => Err(Error::InvalidPacket),
62 }
63}
64
65pub fn packet_frame_count(packet: &[u8]) -> Result<usize> {
70 if packet.is_empty() {
71 return Err(Error::BadArg);
72 }
73 let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
74 let n = unsafe { opus_packet_get_nb_frames(packet.as_ptr(), len_i32) };
75 if n < 0 {
76 return Err(Error::from_code(n));
77 }
78 usize::try_from(n).map_err(|_| Error::InternalError)
79}
80
81pub fn packet_sample_count(packet: &[u8], sample_rate: SampleRate) -> Result<usize> {
86 if packet.is_empty() {
87 return Err(Error::BadArg);
88 }
89 let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
90 let n = unsafe { opus_packet_get_nb_samples(packet.as_ptr(), len_i32, sample_rate.as_i32()) };
91 if n < 0 {
92 return Err(Error::from_code(n));
93 }
94 usize::try_from(n).map_err(|_| Error::InternalError)
95}
96
97pub fn packet_samples_per_frame(packet: &[u8], sample_rate: SampleRate) -> Result<usize> {
102 if packet.is_empty() {
103 return Err(Error::BadArg);
104 }
105 let n = unsafe { opus_packet_get_samples_per_frame(packet.as_ptr(), sample_rate.as_i32()) };
106 if n <= 0 {
107 return Err(Error::InvalidPacket);
108 }
109 usize::try_from(n).map_err(|_| Error::InternalError)
110}
111
112pub fn packet_has_lbrr(packet: &[u8]) -> Result<bool> {
117 if packet.is_empty() {
118 return Err(Error::BadArg);
119 }
120 let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
121 let v = unsafe { opus_packet_has_lbrr(packet.as_ptr(), len_i32) };
122 if v < 0 {
123 return Err(Error::from_code(v));
124 }
125 Ok(v != 0)
126}
127
128pub fn soft_clip(
137 pcm: &mut [f32],
138 frame_size_per_ch: usize,
139 channels: i32,
140 softclip_mem: &mut [f32],
141) -> Result<()> {
142 if frame_size_per_ch == 0 {
143 return Err(Error::BadArg);
144 }
145 let channels_usize = usize::try_from(channels).map_err(|_| Error::BadArg)?;
146 if channels_usize == 0 {
147 return Err(Error::BadArg);
148 }
149 if softclip_mem.len() < channels_usize {
150 return Err(Error::BadArg);
151 }
152 let needed_samples = checked_soft_clip_sample_count(frame_size_per_ch, channels_usize)?;
153 if pcm.len() < needed_samples {
154 return Err(Error::BadArg);
155 }
156 let frame_i32 = i32::try_from(frame_size_per_ch).map_err(|_| Error::BadArg)?;
157 unsafe {
158 opus_pcm_soft_clip(
159 pcm.as_mut_ptr(),
160 frame_i32,
161 channels,
162 softclip_mem.as_mut_ptr(),
163 );
164 }
165 Ok(())
166}
167
168fn checked_soft_clip_sample_count(frame_size_per_ch: usize, channels: usize) -> Result<usize> {
169 let needed_samples = frame_size_per_ch
170 .checked_mul(channels)
171 .ok_or(Error::BadArg)?;
172 if needed_samples > i32::MAX as usize {
176 return Err(Error::BadArg);
177 }
178 Ok(needed_samples)
179}
180
181pub fn packet_parse_into<'packet>(
190 packet: &'packet [u8],
191 frames: &mut [&'packet [u8]],
192) -> Result<(u8, usize, usize)> {
193 if packet.is_empty() {
194 return Err(Error::BadArg);
195 }
196 let mut out_toc: u8 = 0;
197 let mut payload_offset: i32 = 0;
198 let mut frames_ptrs: [*const u8; MAX_FRAMES_PER_PACKET] =
200 [std::ptr::null(); MAX_FRAMES_PER_PACKET];
201 let mut sizes: [i16; MAX_FRAMES_PER_PACKET] = [0; MAX_FRAMES_PER_PACKET];
202 let len_i32 = i32::try_from(packet.len()).map_err(|_| Error::BadArg)?;
203 let n = unsafe {
204 opus_packet_parse(
205 packet.as_ptr(),
206 len_i32,
207 &raw mut out_toc,
208 frames_ptrs.as_mut_ptr().cast::<*const u8>(),
209 sizes.as_mut_ptr(),
210 &raw mut payload_offset,
211 )
212 };
213 if n < 0 {
214 return Err(Error::from_code(n));
215 }
216 let count = usize::try_from(n).map_err(|_| Error::InternalError)?;
217 if count > MAX_FRAMES_PER_PACKET {
218 return Err(Error::InternalError);
219 }
220 if count > frames.len() {
221 return Err(Error::BufferTooSmall);
222 }
223 let mut starts = [0usize; MAX_FRAMES_PER_PACKET];
224 let mut lengths = [0usize; MAX_FRAMES_PER_PACKET];
225 for i in 0..count {
226 let size = usize::try_from(sizes[i]).map_err(|_| Error::InternalError)?;
227 let ptr = frames_ptrs[i];
228 if ptr.is_null() {
229 return Err(Error::InvalidPacket);
230 }
231 let ptr_addr = ptr as usize;
232 let base_addr = packet.as_ptr() as usize;
233 if ptr_addr < base_addr {
234 return Err(Error::InvalidPacket);
235 }
236 let start = ptr_addr - base_addr;
238 let end = start.checked_add(size).ok_or(Error::InternalError)?;
239 if end > packet.len() {
240 return Err(Error::InvalidPacket);
241 }
242 starts[i] = start;
243 lengths[i] = size;
244 }
245 let payload_offset = usize::try_from(payload_offset).map_err(|_| Error::InternalError)?;
246 if payload_offset > packet.len() {
247 return Err(Error::InvalidPacket);
248 }
249 for i in 0..count {
250 frames[i] = &packet[starts[i]..starts[i] + lengths[i]];
251 }
252 Ok((out_toc, payload_offset, count))
253}
254
255pub fn packet_parse(packet: &[u8]) -> Result<(u8, usize, Vec<&[u8]>)> {
264 let mut frames = [&[][..]; MAX_FRAMES_PER_PACKET];
265 let (toc, payload_offset, frame_count) = packet_parse_into(packet, &mut frames)?;
266 Ok((toc, payload_offset, frames[..frame_count].to_vec()))
267}
268
269#[cfg(opus_codec_rust_packet_ops)]
274pub fn packet_pad(packet: &mut [u8], len: usize, new_len: usize) -> Result<()> {
275 if new_len < len || new_len > packet.len() {
276 return Err(Error::BadArg);
277 }
278 if len == 0 {
279 return Err(Error::BadArg);
280 }
281 if len == new_len {
282 return Ok(());
283 }
284 pad_single_packet(packet, len, new_len)
285}
286
287#[cfg(not(opus_codec_rust_packet_ops))]
292pub fn packet_pad(packet: &mut [u8], len: usize, new_len: usize) -> Result<()> {
293 if new_len < len || new_len > packet.len() {
294 return Err(Error::BadArg);
295 }
296 if len == 0 {
297 return Err(Error::BadArg);
298 }
299 let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
300 let new_len_i32 = i32::try_from(new_len).map_err(|_| Error::BadArg)?;
301 let r = unsafe { opus_packet_pad(packet.as_mut_ptr(), len_i32, new_len_i32) };
302 if r != 0 {
303 return Err(Error::from_code(r));
304 }
305 Ok(())
306}
307
308pub fn packet_unpad(packet: &mut [u8], len: usize) -> Result<usize> {
313 if len > packet.len() {
314 return Err(Error::BadArg);
315 }
316 if len == 0 {
317 return Err(Error::BadArg);
318 }
319 let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
320 let n = unsafe { opus_packet_unpad(packet.as_mut_ptr(), len_i32) };
321 if n < 0 {
322 return Err(Error::from_code(n));
323 }
324 usize::try_from(n).map_err(|_| Error::InternalError)
325}
326
327#[cfg(opus_codec_rust_packet_ops)]
332pub fn multistream_packet_pad(
333 packet: &mut [u8],
334 len: usize,
335 new_len: usize,
336 nb_streams: i32,
337) -> Result<()> {
338 if new_len < len || new_len > packet.len() {
339 return Err(Error::BadArg);
340 }
341 if len == 0 {
342 return Err(Error::BadArg);
343 }
344 if nb_streams < 1 {
347 return Err(Error::BadArg);
348 }
349 if len == new_len {
350 return Ok(());
351 }
352 let nb_streams = usize::try_from(nb_streams).map_err(|_| Error::BadArg)?;
353 let last_stream_offset = multistream_last_stream_offset(&packet[..len], nb_streams)?;
354 if last_stream_offset == len {
355 return Err(Error::BadArg);
356 }
357 let amount = new_len - len;
358 let last_len = len - last_stream_offset;
359 let last_new_len = last_len.checked_add(amount).ok_or(Error::BadArg)?;
360 pad_single_packet(&mut packet[last_stream_offset..], last_len, last_new_len)
361}
362
363#[cfg(not(opus_codec_rust_packet_ops))]
368pub fn multistream_packet_pad(
369 packet: &mut [u8],
370 len: usize,
371 new_len: usize,
372 nb_streams: i32,
373) -> Result<()> {
374 if new_len < len || new_len > packet.len() {
375 return Err(Error::BadArg);
376 }
377 if len == 0 {
378 return Err(Error::BadArg);
379 }
380 if nb_streams < 1 {
381 return Err(Error::BadArg);
382 }
383 let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
384 let new_len_i32 = i32::try_from(new_len).map_err(|_| Error::BadArg)?;
385 let r = unsafe {
386 opus_multistream_packet_pad(packet.as_mut_ptr(), len_i32, new_len_i32, nb_streams)
387 };
388 if r != 0 {
389 return Err(Error::from_code(r));
390 }
391 Ok(())
392}
393
394pub fn multistream_packet_unpad(packet: &mut [u8], len: usize, nb_streams: i32) -> Result<usize> {
399 if len > packet.len() {
400 return Err(Error::BadArg);
401 }
402 if len == 0 {
403 return Err(Error::BadArg);
404 }
405 if nb_streams < 1 {
408 return Err(Error::BadArg);
409 }
410 let len_i32 = i32::try_from(len).map_err(|_| Error::BadArg)?;
411 let n = unsafe { opus_multistream_packet_unpad(packet.as_mut_ptr(), len_i32, nb_streams) };
412 if n < 0 {
413 return Err(Error::from_code(n));
414 }
415 usize::try_from(n).map_err(|_| Error::InternalError)
416}
417
418#[cfg(test)]
419mod tests {
420 use super::*;
421
422 #[test]
423 fn soft_clip_rejects_sample_products_that_overflow_c_int() {
424 let frame_size = i32::MAX as usize / 2 + 1;
425 assert_eq!(
426 checked_soft_clip_sample_count(frame_size, 2),
427 Err(Error::BadArg)
428 );
429 assert_eq!(
430 checked_soft_clip_sample_count(i32::MAX as usize, 1),
431 Ok(i32::MAX as usize)
432 );
433 }
434}