use crate::packet;
use crate::{OpusDecoder, OpusError};
pub struct OpusMultistreamDecoder {
decoders: Vec<OpusDecoder>,
nb_channels: usize,
nb_streams: usize,
nb_coupled_streams: usize,
mapping: Vec<u8>,
sample_rate: u32,
}
impl OpusMultistreamDecoder {
pub fn new(
sample_rate: u32,
nb_channels: usize,
nb_streams: usize,
nb_coupled_streams: usize,
mapping: &[u8],
) -> Result<Self, OpusError> {
if nb_channels == 0 || nb_channels > 255 {
return Err(OpusError::InvalidArgument("nb_channels"));
}
if nb_streams == 0 {
return Err(OpusError::InvalidArgument("nb_streams"));
}
if nb_coupled_streams > nb_streams {
return Err(OpusError::InvalidArgument("nb_coupled_streams"));
}
if nb_streams > 255usize.saturating_sub(nb_coupled_streams) {
return Err(OpusError::InvalidArgument("nb_streams"));
}
if mapping.len() != nb_channels {
return Err(OpusError::InvalidArgument("mapping"));
}
let total_decoded_channels = (2 * nb_coupled_streams) + (nb_streams - nb_coupled_streams);
for &slot in mapping {
if slot != 255 && usize::from(slot) >= total_decoded_channels {
return Err(OpusError::InvalidArgument("mapping"));
}
}
let mut decoders = Vec::with_capacity(nb_streams);
for stream_idx in 0..nb_streams {
let channels = if stream_idx < nb_coupled_streams {
2
} else {
1
};
decoders.push(OpusDecoder::new(sample_rate, channels)?);
}
Ok(Self {
decoders,
nb_channels,
nb_streams,
nb_coupled_streams,
mapping: mapping.to_vec(),
sample_rate,
})
}
pub fn decode(
&mut self,
packet: &[u8],
pcm: &mut [i16],
fec: bool,
) -> Result<usize, OpusError> {
let sub_packets = if packet.is_empty() || fec {
vec![&[][..]; self.nb_streams]
} else {
split_multistream_packet(packet, self.nb_streams)?
};
let frame_size = self.expected_frame_size(&sub_packets, fec)?;
let needed = frame_size * self.nb_channels;
if pcm.len() < needed {
return Err(OpusError::BufferTooSmall);
}
if frame_size == 0 {
return Ok(0);
}
let mut stream_pcm = Vec::with_capacity(self.nb_streams);
for (stream_idx, sub_packet) in sub_packets.iter().enumerate() {
let channels = self.stream_channels(stream_idx);
let mut buf = vec![0i16; frame_size * channels];
let written = self.decoders[stream_idx].decode(sub_packet, &mut buf, fec)?;
if written != frame_size {
return Err(OpusError::InvalidPacket);
}
stream_pcm.push(buf);
}
for (channel_idx, &slot) in self.mapping.iter().enumerate() {
if slot == 255 {
zero_output_channel_i16(pcm, self.nb_channels, channel_idx, frame_size);
continue;
}
let (stream_idx, source_channel) = self.slot_to_stream_channel(usize::from(slot));
copy_output_channel_i16(
pcm,
self.nb_channels,
channel_idx,
&stream_pcm[stream_idx],
self.stream_channels(stream_idx),
source_channel,
frame_size,
);
}
Ok(frame_size)
}
pub fn decode_float(
&mut self,
packet: &[u8],
pcm: &mut [f32],
fec: bool,
) -> Result<usize, OpusError> {
let sub_packets = if packet.is_empty() || fec {
vec![&[][..]; self.nb_streams]
} else {
split_multistream_packet(packet, self.nb_streams)?
};
let frame_size = self.expected_frame_size(&sub_packets, fec)?;
let needed = frame_size * self.nb_channels;
if pcm.len() < needed {
return Err(OpusError::BufferTooSmall);
}
if frame_size == 0 {
return Ok(0);
}
let mut stream_pcm = Vec::with_capacity(self.nb_streams);
for (stream_idx, sub_packet) in sub_packets.iter().enumerate() {
let channels = self.stream_channels(stream_idx);
let mut buf = vec![0.0f32; frame_size * channels];
let written = self.decoders[stream_idx].decode_float(sub_packet, &mut buf, fec)?;
if written != frame_size {
return Err(OpusError::InvalidPacket);
}
stream_pcm.push(buf);
}
for (channel_idx, &slot) in self.mapping.iter().enumerate() {
if slot == 255 {
zero_output_channel_f32(pcm, self.nb_channels, channel_idx, frame_size);
continue;
}
let (stream_idx, source_channel) = self.slot_to_stream_channel(usize::from(slot));
copy_output_channel_f32(
pcm,
self.nb_channels,
channel_idx,
&stream_pcm[stream_idx],
self.stream_channels(stream_idx),
source_channel,
frame_size,
);
}
Ok(frame_size)
}
pub fn reset(&mut self) {
for decoder in &mut self.decoders {
decoder.reset();
}
}
fn expected_frame_size(&self, sub_packets: &[&[u8]], fec: bool) -> Result<usize, OpusError> {
if fec || sub_packets.iter().all(|packet| packet.is_empty()) {
return Ok(self
.decoders
.first()
.map(|decoder| decoder.last_packet_duration)
.unwrap_or(0));
}
let mut frame_size = None;
for sub_packet in sub_packets.iter().filter(|packet| !packet.is_empty()) {
let samples = packet::parse_packet(sub_packet)
.map_err(OpusError::from)?
.samples_per_channel(self.sample_rate);
if let Some(expected) = frame_size {
if expected != samples {
return Err(OpusError::InvalidPacket);
}
} else {
frame_size = Some(samples);
}
}
Ok(frame_size.unwrap_or(0))
}
fn stream_channels(&self, stream_idx: usize) -> usize {
if stream_idx < self.nb_coupled_streams {
2
} else {
1
}
}
fn slot_to_stream_channel(&self, slot: usize) -> (usize, usize) {
let coupled_slots = 2 * self.nb_coupled_streams;
if slot < coupled_slots {
(slot / 2, slot % 2)
} else {
(self.nb_coupled_streams + (slot - coupled_slots), 0)
}
}
}
fn split_multistream_packet(packet: &[u8], nb_streams: usize) -> Result<Vec<&[u8]>, OpusError> {
if nb_streams == 0 {
return Err(OpusError::InvalidArgument("nb_streams"));
}
if packet.is_empty() {
return Ok(vec![packet; nb_streams]);
}
let mut out = Vec::with_capacity(nb_streams);
let mut offset = 0usize;
for _stream_idx in 0..nb_streams.saturating_sub(1) {
let (packet_len, used) = parse_self_delimited_size(&packet[offset..])?;
offset += used;
if offset + packet_len > packet.len() {
return Err(OpusError::InvalidPacket);
}
out.push(&packet[offset..offset + packet_len]);
offset += packet_len;
}
if offset > packet.len() {
return Err(OpusError::InvalidPacket);
}
out.push(&packet[offset..]);
Ok(out)
}
fn parse_self_delimited_size(data: &[u8]) -> Result<(usize, usize), OpusError> {
if data.is_empty() {
return Err(OpusError::InvalidPacket);
}
let first = usize::from(data[0]);
if first < 252 {
Ok((first, 1))
} else {
if data.len() < 2 {
return Err(OpusError::InvalidPacket);
}
Ok((first + (4 * usize::from(data[1])), 2))
}
}
fn copy_output_channel_i16(
pcm: &mut [i16],
dst_stride: usize,
dst_channel: usize,
src: &[i16],
src_stride: usize,
src_channel: usize,
frame_size: usize,
) {
for sample_idx in 0..frame_size {
pcm[sample_idx * dst_stride + dst_channel] = src[sample_idx * src_stride + src_channel];
}
}
fn zero_output_channel_i16(
pcm: &mut [i16],
dst_stride: usize,
dst_channel: usize,
frame_size: usize,
) {
for sample_idx in 0..frame_size {
pcm[sample_idx * dst_stride + dst_channel] = 0;
}
}
fn copy_output_channel_f32(
pcm: &mut [f32],
dst_stride: usize,
dst_channel: usize,
src: &[f32],
src_stride: usize,
src_channel: usize,
frame_size: usize,
) {
for sample_idx in 0..frame_size {
pcm[sample_idx * dst_stride + dst_channel] = src[sample_idx * src_stride + src_channel];
}
}
fn zero_output_channel_f32(
pcm: &mut [f32],
dst_stride: usize,
dst_channel: usize,
frame_size: usize,
) {
for sample_idx in 0..frame_size {
pcm[sample_idx * dst_stride + dst_channel] = 0.0;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn split_two_stream_packet_with_short_prefix() {
let packet = [3u8, 10, 11, 12, 20, 21];
let sub_packets = split_multistream_packet(&packet, 2).unwrap();
assert_eq!(sub_packets, vec![&[10, 11, 12][..], &[20, 21][..]]);
}
#[test]
fn split_empty_packet_for_plc() {
let sub_packets = split_multistream_packet(&[], 3).unwrap();
assert_eq!(sub_packets, vec![&[][..], &[][..], &[][..]]);
}
}