#![cfg_attr(not(test), allow(dead_code))]
use alloc::vec;
use alloc::vec::Vec;
use crate::celt::{CELT_SIG_SCALE, OpusRes, float2int, float2int16, isqrt32};
use crate::opus_decoder::{
OpusDecodeError, OpusDecoder, OpusDecoderCtlError, OpusDecoderCtlRequest, OpusDecoderInitError,
opus_decode_native, opus_decoder_create, opus_decoder_ctl, opus_decoder_get_size,
};
use crate::opus_encoder::{
OPUS_FRAMESIZE_ARG, OpusEncodeError, OpusEncodeOptions, OpusEncoder, OpusEncoderCtlError,
OpusEncoderCtlRequest, OpusEncoderInitError, opus_encode_with_options, opus_encoder_create,
opus_encoder_ctl, opus_encoder_get_size,
};
use crate::packet::{PacketError, opus_packet_get_nb_samples, opus_packet_parse_impl};
pub(crate) const OPUS_AUTO: i32 = -1000;
pub(crate) const OPUS_BITRATE_MAX: i32 = -1;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum MappingType {
None,
Surround,
Ambisonics,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChannelLayout {
pub nb_channels: usize,
pub nb_streams: usize,
pub nb_coupled_streams: usize,
pub mapping: [u8; 256],
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OpusMultistreamDecoderError {
BadArgument,
BufferTooSmall,
InternalError,
InvalidPacket,
Unimplemented,
DecoderInit(OpusDecoderInitError),
DecoderCtl(OpusDecoderCtlError),
DecoderDecode(OpusDecodeError),
}
impl OpusMultistreamDecoderError {
#[inline]
pub const fn code(&self) -> i32 {
match self {
Self::BadArgument => -1,
Self::BufferTooSmall => -2,
Self::InternalError => -3,
Self::InvalidPacket => -4,
Self::Unimplemented => -5,
Self::DecoderInit(OpusDecoderInitError::BadArgument) => -1,
Self::DecoderInit(_) => -3,
Self::DecoderCtl(OpusDecoderCtlError::BadArgument) => -1,
Self::DecoderCtl(OpusDecoderCtlError::Unimplemented) => -5,
Self::DecoderCtl(OpusDecoderCtlError::Silk(_)) => -3,
Self::DecoderDecode(err) => err.code(),
}
}
}
impl From<PacketError> for OpusMultistreamDecoderError {
#[inline]
fn from(value: PacketError) -> Self {
match value {
PacketError::BadArgument => Self::BadArgument,
PacketError::InvalidPacket => Self::InvalidPacket,
}
}
}
impl From<OpusDecoderInitError> for OpusMultistreamDecoderError {
#[inline]
fn from(value: OpusDecoderInitError) -> Self {
Self::DecoderInit(value)
}
}
impl From<OpusDecoderCtlError> for OpusMultistreamDecoderError {
#[inline]
fn from(value: OpusDecoderCtlError) -> Self {
Self::DecoderCtl(value)
}
}
impl From<OpusDecodeError> for OpusMultistreamDecoderError {
#[inline]
fn from(value: OpusDecodeError) -> Self {
Self::DecoderDecode(value)
}
}
#[repr(C)]
struct ChannelLayoutLayout {
nb_channels: i32,
nb_streams: i32,
nb_coupled_streams: i32,
mapping: [u8; 256],
}
#[repr(C)]
struct OpusMsDecoderLayout {
layout: ChannelLayoutLayout,
}
#[repr(C)]
struct OpusMsEncoderLayout {
layout: ChannelLayoutLayout,
}
#[inline]
fn align(value: usize) -> usize {
#[repr(C)]
struct AlignProbe {
_tag: u8,
_union: AlignUnion,
}
#[repr(C)]
union AlignUnion {
_ptr: *const (),
_i32: i32,
_f32: f32,
}
let alignment = core::mem::align_of::<AlignProbe>();
value.div_ceil(alignment) * alignment
}
#[must_use]
pub fn opus_multistream_decoder_get_size(
nb_streams: usize,
nb_coupled_streams: usize,
) -> Option<usize> {
if nb_streams == 0 || nb_coupled_streams > nb_streams {
return None;
}
let coupled_size = opus_decoder_get_size(2)?;
let mono_size = opus_decoder_get_size(1)?;
let header_size = align(core::mem::size_of::<OpusMsDecoderLayout>());
let coupled_total = nb_coupled_streams.checked_mul(align(coupled_size))?;
let mono_total = nb_streams
.checked_sub(nb_coupled_streams)?
.checked_mul(align(mono_size))?;
header_size
.checked_add(coupled_total)?
.checked_add(mono_total)
}
#[derive(Debug)]
pub struct OpusMultistreamDecoder<'mode> {
layout: ChannelLayout,
decoders: Vec<OpusDecoder<'mode>>,
}
impl<'mode> OpusMultistreamDecoder<'mode> {
#[inline]
pub fn layout(&self) -> &ChannelLayout {
&self.layout
}
#[inline]
fn sample_rate(&self) -> Option<i32> {
self.decoders.first().map(|decoder| decoder.fs)
}
pub fn init(
&mut self,
sample_rate: i32,
channels: usize,
streams: usize,
coupled_streams: usize,
mapping: &[u8],
) -> Result<(), OpusMultistreamDecoderError> {
let layout = build_layout(channels, streams, coupled_streams, mapping)?;
let decoders = build_stream_decoders(sample_rate, streams, coupled_streams)?;
self.layout = layout;
self.decoders = decoders;
Ok(())
}
pub fn decoder_state(&mut self, stream_id: usize) -> Option<&mut OpusDecoder<'mode>> {
self.decoders.get_mut(stream_id)
}
}
pub fn opus_multistream_decoder_create(
sample_rate: i32,
channels: usize,
streams: usize,
coupled_streams: usize,
mapping: &[u8],
) -> Result<OpusMultistreamDecoder<'static>, OpusMultistreamDecoderError> {
let layout = build_layout(channels, streams, coupled_streams, mapping)?;
let decoders = build_stream_decoders(sample_rate, streams, coupled_streams)?;
Ok(OpusMultistreamDecoder { layout, decoders })
}
pub fn opus_multistream_decoder_init(
decoder: &mut OpusMultistreamDecoder<'_>,
sample_rate: i32,
channels: usize,
streams: usize,
coupled_streams: usize,
mapping: &[u8],
) -> Result<(), OpusMultistreamDecoderError> {
decoder.init(sample_rate, channels, streams, coupled_streams, mapping)
}
fn build_layout(
channels: usize,
streams: usize,
coupled_streams: usize,
mapping: &[u8],
) -> Result<ChannelLayout, OpusMultistreamDecoderError> {
if channels == 0
|| channels > 255
|| coupled_streams > streams
|| streams == 0
|| streams > 255 - coupled_streams
{
return Err(OpusMultistreamDecoderError::BadArgument);
}
if mapping.len() < channels {
return Err(OpusMultistreamDecoderError::BadArgument);
}
let mut layout = ChannelLayout {
nb_channels: channels,
nb_streams: streams,
nb_coupled_streams: coupled_streams,
mapping: [u8::MAX; 256],
};
layout.mapping[..channels].copy_from_slice(&mapping[..channels]);
if !validate_layout(&layout) {
return Err(OpusMultistreamDecoderError::BadArgument);
}
Ok(layout)
}
fn build_stream_decoders(
sample_rate: i32,
streams: usize,
coupled_streams: usize,
) -> Result<Vec<OpusDecoder<'static>>, OpusMultistreamDecoderError> {
if sample_rate <= 0 {
return Err(OpusMultistreamDecoderError::BadArgument);
}
let mut decoders = Vec::with_capacity(streams);
for stream in 0..streams {
let channels: i32 = if stream < coupled_streams { 2 } else { 1 };
decoders.push(opus_decoder_create(sample_rate, channels)?);
}
Ok(decoders)
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct VorbisLayout {
nb_streams: usize,
nb_coupled_streams: usize,
mapping: [u8; 8],
}
#[allow(dead_code)]
const VORBIS_MAPPINGS: [VorbisLayout; 8] = [
VorbisLayout {
nb_streams: 1,
nb_coupled_streams: 0,
mapping: [0, 255, 255, 255, 255, 255, 255, 255],
},
VorbisLayout {
nb_streams: 1,
nb_coupled_streams: 1,
mapping: [0, 1, 255, 255, 255, 255, 255, 255],
},
VorbisLayout {
nb_streams: 2,
nb_coupled_streams: 1,
mapping: [0, 2, 1, 255, 255, 255, 255, 255],
},
VorbisLayout {
nb_streams: 2,
nb_coupled_streams: 2,
mapping: [0, 1, 2, 3, 255, 255, 255, 255],
},
VorbisLayout {
nb_streams: 3,
nb_coupled_streams: 2,
mapping: [0, 4, 1, 2, 3, 255, 255, 255],
},
VorbisLayout {
nb_streams: 4,
nb_coupled_streams: 2,
mapping: [0, 4, 1, 2, 3, 5, 255, 255],
},
VorbisLayout {
nb_streams: 4,
nb_coupled_streams: 3,
mapping: [0, 4, 1, 2, 3, 5, 6, 255],
},
VorbisLayout {
nb_streams: 5,
nb_coupled_streams: 3,
mapping: [0, 6, 1, 2, 3, 4, 5, 7],
},
];
#[must_use]
pub(crate) fn validate_layout(layout: &ChannelLayout) -> bool {
let Some(max_channel) = layout.nb_streams.checked_add(layout.nb_coupled_streams) else {
return false;
};
if max_channel > u8::MAX as usize {
return false;
}
if layout.nb_channels > layout.mapping.len() {
return false;
}
layout
.mapping
.iter()
.take(layout.nb_channels)
.all(|&value| value == u8::MAX || usize::from(value) < max_channel)
}
#[must_use]
pub(crate) fn validate_encoder_layout(layout: &ChannelLayout) -> bool {
for stream in 0..layout.nb_streams {
if stream < layout.nb_coupled_streams {
if get_left_channel(layout, stream, None).is_none() {
return false;
}
if get_right_channel(layout, stream, None).is_none() {
return false;
}
} else if get_mono_channel(layout, stream, None).is_none() {
return false;
}
}
true
}
#[must_use]
pub(crate) fn validate_ambisonics(channels: usize) -> Option<(usize, usize)> {
if !(1..=227).contains(&channels) {
return None;
}
let order_plus_one = isqrt32(channels as u32) as usize;
let acn_channels = order_plus_one.checked_mul(order_plus_one)?;
let nondiegetic_channels = channels.checked_sub(acn_channels)?;
if nondiegetic_channels != 0 && nondiegetic_channels != 2 {
return None;
}
let streams = acn_channels + usize::from(nondiegetic_channels != 0);
let coupled_streams = usize::from(nondiegetic_channels != 0);
Some((streams, coupled_streams))
}
fn surround_rate_allocation(
layout: &ChannelLayout,
bitrate_bps: i32,
lfe_stream: Option<usize>,
frame_size: usize,
sample_rate: i32,
rates: &mut [i32],
) -> Option<()> {
let nb_streams = layout.nb_streams;
let nb_coupled = layout.nb_coupled_streams;
let nb_lfe = usize::from(lfe_stream.is_some());
if nb_streams == 0 || nb_coupled > nb_streams || nb_streams < nb_coupled + nb_lfe {
return None;
}
if frame_size == 0 || sample_rate <= 0 {
return None;
}
if rates.len() < nb_streams {
return None;
}
let nb_uncoupled = nb_streams - nb_coupled - nb_lfe;
let nb_normal = 2 * nb_coupled + nb_uncoupled;
if nb_normal == 0 {
return None;
}
let frame_rate = sample_rate / frame_size as i32;
let channel_offset = 40 * frame_rate.max(50);
let bitrate = if bitrate_bps == OPUS_AUTO {
nb_normal as i32 * (channel_offset + sample_rate + 10_000) + 8000 * nb_lfe as i32
} else if bitrate_bps == OPUS_BITRATE_MAX {
nb_normal as i32 * 300_000 + nb_lfe as i32 * 128_000
} else {
bitrate_bps
};
let lfe_offset = bitrate
.checked_div(20)
.map(|value| value.min(3000))
.and_then(|value| value.checked_add(15 * frame_rate.max(50)))?;
let stream_offset =
(((bitrate - channel_offset * nb_normal as i32 - lfe_offset * nb_lfe as i32)
/ nb_normal as i32)
/ 2)
.clamp(0, 20_000);
let coupled_ratio = 512;
let lfe_ratio = 32;
let total = ((nb_uncoupled as i32) << 8)
+ coupled_ratio * nb_coupled as i32
+ lfe_ratio * nb_lfe as i32;
if total == 0 {
return None;
}
let channel_rate = 256
* (bitrate
- lfe_offset * nb_lfe as i32
- stream_offset * (nb_coupled as i32 + nb_uncoupled as i32)
- channel_offset * nb_normal as i32)
/ total;
for (stream, slot) in rates.iter_mut().take(nb_streams).enumerate() {
let value = if stream < nb_coupled {
2 * channel_offset + (stream_offset + ((channel_rate * coupled_ratio) >> 8)).max(0)
} else if lfe_stream == Some(stream) {
(lfe_offset + ((channel_rate * lfe_ratio) >> 8)).max(0)
} else {
channel_offset + (stream_offset + channel_rate).max(0)
};
*slot = value;
}
Some(())
}
fn ambisonics_rate_allocation(
layout: &ChannelLayout,
bitrate_bps: i32,
frame_size: usize,
sample_rate: i32,
rates: &mut [i32],
) -> Option<()> {
if frame_size == 0 || sample_rate <= 0 || layout.nb_streams == 0 {
return None;
}
if rates.len() < layout.nb_streams {
return None;
}
let nb_channels = layout.nb_streams + layout.nb_coupled_streams;
let total_rate = if bitrate_bps == OPUS_AUTO {
let term = sample_rate + 60 * sample_rate / frame_size as i32;
(layout.nb_coupled_streams + layout.nb_streams) as i32 * term
+ layout.nb_streams as i32 * 15_000
} else if bitrate_bps == OPUS_BITRATE_MAX {
nb_channels as i32 * 320_000
} else {
bitrate_bps
};
let per_stream_rate = total_rate / layout.nb_streams as i32;
for slot in rates.iter_mut().take(layout.nb_streams) {
*slot = per_stream_rate;
}
Some(())
}
#[must_use]
pub(crate) fn rate_allocation(
layout: &ChannelLayout,
mapping_type: MappingType,
bitrate_bps: i32,
lfe_stream: Option<usize>,
frame_size: usize,
sample_rate: i32,
rates: &mut [i32],
) -> Option<i32> {
match mapping_type {
MappingType::Ambisonics => {
ambisonics_rate_allocation(layout, bitrate_bps, frame_size, sample_rate, rates)?
}
_ => surround_rate_allocation(
layout,
bitrate_bps,
lfe_stream,
frame_size,
sample_rate,
rates,
)?,
}
let mut sum = 0i64;
for rate in rates.iter_mut().take(layout.nb_streams) {
*rate = (*rate).max(500);
sum += i64::from(*rate);
}
i32::try_from(sum).ok()
}
fn next_index(prev: Option<usize>) -> Option<usize> {
match prev {
Some(idx) => idx.checked_add(1),
None => Some(0),
}
}
fn find_channel(layout: &ChannelLayout, start: usize, target: usize) -> Option<usize> {
let limit = layout.nb_channels.min(layout.mapping.len());
(start..limit).find(|&i| usize::from(layout.mapping[i]) == target)
}
#[must_use]
pub(crate) fn get_left_channel(
layout: &ChannelLayout,
stream_id: usize,
prev: Option<usize>,
) -> Option<usize> {
let target = stream_id.checked_mul(2)?;
let start = next_index(prev)?;
find_channel(layout, start, target)
}
#[must_use]
pub(crate) fn get_right_channel(
layout: &ChannelLayout,
stream_id: usize,
prev: Option<usize>,
) -> Option<usize> {
let target = stream_id.checked_mul(2)?.checked_add(1)?;
let start = next_index(prev)?;
find_channel(layout, start, target)
}
#[must_use]
pub(crate) fn get_mono_channel(
layout: &ChannelLayout,
stream_id: usize,
prev: Option<usize>,
) -> Option<usize> {
let target = stream_id.checked_add(layout.nb_coupled_streams)?;
let start = next_index(prev)?;
find_channel(layout, start, target)
}
pub enum OpusMultistreamDecoderCtlRequest<'req> {
SetGain(i32),
GetGain(&'req mut i32),
SetComplexity(i32),
GetComplexity(&'req mut i32),
GetBandwidth(&'req mut i32),
GetSampleRate(&'req mut i32),
GetFinalRange(&'req mut u32),
ResetState,
GetLastPacketDuration(&'req mut i32),
SetPhaseInversionDisabled(bool),
GetPhaseInversionDisabled(&'req mut bool),
SetDnnBlob(&'req [u8]),
}
pub fn opus_multistream_decoder_ctl<'req>(
decoder: &mut OpusMultistreamDecoder<'_>,
request: OpusMultistreamDecoderCtlRequest<'req>,
) -> Result<(), OpusMultistreamDecoderError> {
if decoder.decoders.is_empty() {
return Err(OpusMultistreamDecoderError::InternalError);
}
match request {
OpusMultistreamDecoderCtlRequest::SetGain(value) => {
for dec in &mut decoder.decoders {
opus_decoder_ctl(dec, OpusDecoderCtlRequest::SetGain(value))?;
}
}
OpusMultistreamDecoderCtlRequest::GetGain(slot) => {
opus_decoder_ctl(
decoder
.decoders
.first_mut()
.ok_or(OpusMultistreamDecoderError::InternalError)?,
OpusDecoderCtlRequest::GetGain(slot),
)?;
}
OpusMultistreamDecoderCtlRequest::SetComplexity(value) => {
for dec in &mut decoder.decoders {
opus_decoder_ctl(dec, OpusDecoderCtlRequest::SetComplexity(value))?;
}
}
OpusMultistreamDecoderCtlRequest::GetComplexity(slot) => {
opus_decoder_ctl(
decoder
.decoders
.first_mut()
.ok_or(OpusMultistreamDecoderError::InternalError)?,
OpusDecoderCtlRequest::GetComplexity(slot),
)?;
}
OpusMultistreamDecoderCtlRequest::GetBandwidth(slot) => {
opus_decoder_ctl(
decoder
.decoders
.first_mut()
.ok_or(OpusMultistreamDecoderError::InternalError)?,
OpusDecoderCtlRequest::GetBandwidth(slot),
)?;
}
OpusMultistreamDecoderCtlRequest::GetSampleRate(slot) => {
opus_decoder_ctl(
decoder
.decoders
.first_mut()
.ok_or(OpusMultistreamDecoderError::InternalError)?,
OpusDecoderCtlRequest::GetSampleRate(slot),
)?;
}
OpusMultistreamDecoderCtlRequest::GetFinalRange(slot) => {
let mut acc = 0u32;
for dec in &mut decoder.decoders {
let mut value = 0u32;
opus_decoder_ctl(dec, OpusDecoderCtlRequest::GetFinalRange(&mut value))?;
acc ^= value;
}
*slot = acc;
}
OpusMultistreamDecoderCtlRequest::ResetState => {
for dec in &mut decoder.decoders {
opus_decoder_ctl(dec, OpusDecoderCtlRequest::ResetState)?;
}
}
OpusMultistreamDecoderCtlRequest::GetLastPacketDuration(slot) => {
opus_decoder_ctl(
decoder
.decoders
.first_mut()
.ok_or(OpusMultistreamDecoderError::InternalError)?,
OpusDecoderCtlRequest::GetLastPacketDuration(slot),
)?;
}
OpusMultistreamDecoderCtlRequest::SetPhaseInversionDisabled(value) => {
for dec in &mut decoder.decoders {
opus_decoder_ctl(dec, OpusDecoderCtlRequest::SetPhaseInversionDisabled(value))?;
}
}
OpusMultistreamDecoderCtlRequest::GetPhaseInversionDisabled(slot) => {
opus_decoder_ctl(
decoder
.decoders
.first_mut()
.ok_or(OpusMultistreamDecoderError::InternalError)?,
OpusDecoderCtlRequest::GetPhaseInversionDisabled(slot),
)?;
}
OpusMultistreamDecoderCtlRequest::SetDnnBlob(data) => {
for dec in &mut decoder.decoders {
opus_decoder_ctl(dec, OpusDecoderCtlRequest::SetDnnBlob(data))?;
}
}
}
Ok(())
}
fn opus_multistream_packet_validate(
data: &[u8],
len: usize,
nb_streams: usize,
sample_rate: i32,
) -> Result<usize, OpusMultistreamDecoderError> {
if len > data.len() || nb_streams == 0 || sample_rate <= 0 {
return Err(OpusMultistreamDecoderError::BadArgument);
}
let mut remaining = len;
let mut cursor = data;
let mut samples: Option<usize> = None;
for stream in 0..nb_streams {
if remaining == 0 {
return Err(OpusMultistreamDecoderError::InvalidPacket);
}
let parsed = opus_packet_parse_impl(cursor, remaining, stream + 1 != nb_streams)?;
let tmp_samples =
opus_packet_get_nb_samples(cursor, parsed.packet_offset, sample_rate as u32)?;
if let Some(prev) = samples {
if prev != tmp_samples {
return Err(OpusMultistreamDecoderError::InvalidPacket);
}
} else {
samples = Some(tmp_samples);
}
cursor = &cursor[parsed.packet_offset..];
remaining = remaining
.checked_sub(parsed.packet_offset)
.ok_or(OpusMultistreamDecoderError::InvalidPacket)?;
}
samples.ok_or(OpusMultistreamDecoderError::InvalidPacket)
}
#[cfg(feature = "fixed_point")]
const OPTIONAL_CLIP: bool = false;
#[cfg(not(feature = "fixed_point"))]
const OPTIONAL_CLIP: bool = true;
fn opus_multistream_decode_native<T: PcmSample>(
decoder: &mut OpusMultistreamDecoder<'_>,
data: &[u8],
len: usize,
pcm: &mut [T],
frame_size: usize,
decode_fec: bool,
soft_clip: bool,
) -> Result<usize, OpusMultistreamDecoderError> {
opus_multistream_decode_native_with_handler(
decoder,
data,
len,
pcm,
frame_size,
decode_fec,
soft_clip,
|dst, dst_stride, dst_channel, src, frame_size, src_offset| {
copy_channel_out(dst, dst_stride, dst_channel, src, frame_size, src_offset);
},
)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn opus_multistream_decode_native_with_handler<T>(
decoder: &mut OpusMultistreamDecoder<'_>,
data: &[u8],
len: usize,
pcm: &mut [T],
mut frame_size: usize,
decode_fec: bool,
soft_clip: bool,
mut handler: impl FnMut(&mut [T], usize, usize, Option<(&[OpusRes], usize)>, usize, usize),
) -> Result<usize, OpusMultistreamDecoderError> {
if frame_size == 0 {
return Err(OpusMultistreamDecoderError::BadArgument);
}
if len > data.len() {
return Err(OpusMultistreamDecoderError::BadArgument);
}
let nb_streams = decoder.layout.nb_streams;
if nb_streams == 0 {
return Err(OpusMultistreamDecoderError::BadArgument);
}
let sample_rate = decoder
.sample_rate()
.ok_or(OpusMultistreamDecoderError::InternalError)?;
let max_frame = sample_rate as usize / 25 * 3;
frame_size = frame_size.min(max_frame);
let required = frame_size
.checked_mul(decoder.layout.nb_channels)
.ok_or(OpusMultistreamDecoderError::BadArgument)?;
if pcm.len() < required {
return Err(OpusMultistreamDecoderError::BufferTooSmall);
}
let do_plc = len == 0;
if !do_plc {
let minimum = nb_streams
.checked_mul(2)
.and_then(|value| value.checked_sub(1))
.ok_or(OpusMultistreamDecoderError::BadArgument)?;
if len < minimum {
return Err(OpusMultistreamDecoderError::InvalidPacket);
}
let samples = opus_multistream_packet_validate(data, len, nb_streams, sample_rate)?;
if samples > frame_size {
return Err(OpusMultistreamDecoderError::BufferTooSmall);
}
}
let mut scratch = vec![OpusRes::default(); 2 * frame_size];
let mut cursor = data;
let mut remaining = len;
let mut decoded_frame_size = frame_size;
for stream in 0..nb_streams {
let self_delimited = stream + 1 != nb_streams;
let decoder_state = decoder
.decoders
.get_mut(stream)
.ok_or(OpusMultistreamDecoderError::InternalError)?;
let mut packet_offset = 0usize;
let decoded = if do_plc {
opus_decode_native(
decoder_state,
None,
0,
&mut scratch,
decoded_frame_size,
decode_fec,
self_delimited,
None,
soft_clip,
)?
} else {
if remaining == 0 {
return Err(OpusMultistreamDecoderError::InternalError);
}
opus_decode_native(
decoder_state,
Some(cursor),
remaining,
&mut scratch,
decoded_frame_size,
decode_fec,
self_delimited,
Some(&mut packet_offset),
soft_clip,
)?
};
if !do_plc {
if packet_offset > remaining {
return Err(OpusMultistreamDecoderError::InvalidPacket);
}
cursor = &cursor[packet_offset..];
remaining -= packet_offset;
}
if decoded == 0 {
return Err(OpusMultistreamDecoderError::InternalError);
}
decoded_frame_size = decoded;
if stream < decoder.layout.nb_coupled_streams {
let mut prev = None;
while let Some(chan) = get_left_channel(&decoder.layout, stream, prev) {
handler(
pcm,
decoder.layout.nb_channels,
chan,
Some((&scratch[..], 2)),
decoded_frame_size,
0,
);
prev = Some(chan);
}
let mut prev = None;
while let Some(chan) = get_right_channel(&decoder.layout, stream, prev) {
handler(
pcm,
decoder.layout.nb_channels,
chan,
Some((&scratch[1..], 2)),
decoded_frame_size,
0,
);
prev = Some(chan);
}
} else {
let mut prev = None;
while let Some(chan) = get_mono_channel(&decoder.layout, stream, prev) {
handler(
pcm,
decoder.layout.nb_channels,
chan,
Some((&scratch[..], 1)),
decoded_frame_size,
0,
);
prev = Some(chan);
}
}
}
for channel in 0..decoder.layout.nb_channels {
if decoder.layout.mapping[channel] == u8::MAX {
handler(
pcm,
decoder.layout.nb_channels,
channel,
None,
decoded_frame_size,
0,
);
}
}
Ok(decoded_frame_size)
}
pub fn opus_multistream_decode(
decoder: &mut OpusMultistreamDecoder<'_>,
data: &[u8],
len: usize,
pcm: &mut [i16],
frame_size: usize,
decode_fec: bool,
) -> Result<usize, OpusMultistreamDecoderError> {
opus_multistream_decode_native(
decoder,
data,
len,
pcm,
frame_size,
decode_fec,
OPTIONAL_CLIP,
)
}
pub fn opus_multistream_decode24(
decoder: &mut OpusMultistreamDecoder<'_>,
data: &[u8],
len: usize,
pcm: &mut [i32],
frame_size: usize,
decode_fec: bool,
) -> Result<usize, OpusMultistreamDecoderError> {
opus_multistream_decode_native(decoder, data, len, pcm, frame_size, decode_fec, false)
}
pub fn opus_multistream_decode_float(
decoder: &mut OpusMultistreamDecoder<'_>,
data: &[u8],
len: usize,
pcm: &mut [f32],
frame_size: usize,
decode_fec: bool,
) -> Result<usize, OpusMultistreamDecoderError> {
opus_multistream_decode_native(decoder, data, len, pcm, frame_size, decode_fec, false)
}
trait PcmSample: Copy + Default {
fn from_opus_res(value: OpusRes) -> Self;
}
#[inline]
fn res_to_int24(sample: OpusRes) -> i32 {
let scale = CELT_SIG_SCALE * 256.0;
let scaled = (sample * scale).clamp(-8_388_608.0, 8_388_607.0);
float2int(scaled)
}
impl PcmSample for i16 {
#[inline]
fn from_opus_res(value: OpusRes) -> Self {
float2int16(value)
}
}
impl PcmSample for i32 {
#[inline]
fn from_opus_res(value: OpusRes) -> Self {
res_to_int24(value)
}
}
impl PcmSample for f32 {
#[inline]
fn from_opus_res(value: OpusRes) -> Self {
value
}
}
fn copy_channel_out<T: PcmSample>(
dst: &mut [T],
dst_stride: usize,
dst_channel: usize,
src: Option<(&[OpusRes], usize)>,
frame_size: usize,
src_offset: usize,
) {
if dst_stride == 0 || frame_size == 0 {
return;
}
for i in 0..frame_size {
let dst_index = i * dst_stride + dst_channel;
if dst_index >= dst.len() {
break;
}
dst[dst_index] = match src {
Some((src_data, src_stride)) => {
let src_index = src_offset + i * src_stride;
let value = src_data.get(src_index).copied().unwrap_or_default();
T::from_opus_res(value)
}
None => T::default(),
};
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OpusMultistreamEncoderError {
BadArgument,
BufferTooSmall,
InternalError,
Unimplemented,
EncoderInit(OpusEncoderInitError),
EncoderCtl(OpusEncoderCtlError),
Encode(OpusEncodeError),
}
impl OpusMultistreamEncoderError {
#[inline]
pub const fn code(&self) -> i32 {
match self {
Self::BadArgument => -1,
Self::BufferTooSmall => -2,
Self::InternalError => -3,
Self::Unimplemented => -5,
Self::EncoderInit(err) => err.code(),
Self::EncoderCtl(err) => err.code(),
Self::Encode(err) => err.code(),
}
}
}
impl From<OpusEncoderInitError> for OpusMultistreamEncoderError {
#[inline]
fn from(value: OpusEncoderInitError) -> Self {
Self::EncoderInit(value)
}
}
impl From<OpusEncoderCtlError> for OpusMultistreamEncoderError {
#[inline]
fn from(value: OpusEncoderCtlError) -> Self {
Self::EncoderCtl(value)
}
}
impl From<OpusEncodeError> for OpusMultistreamEncoderError {
#[inline]
fn from(value: OpusEncodeError) -> Self {
match value {
OpusEncodeError::BadArgument => Self::BadArgument,
OpusEncodeError::BufferTooSmall => Self::BufferTooSmall,
OpusEncodeError::InternalError => Self::InternalError,
OpusEncodeError::Unimplemented => Self::Unimplemented,
OpusEncodeError::Silk(_) => Self::Encode(value),
}
}
}
#[derive(Debug)]
pub struct OpusMultistreamEncoder<'mode> {
layout: ChannelLayout,
encoders: Vec<OpusEncoder<'mode>>,
mapping_type: MappingType,
lfe_stream: Option<usize>,
sample_rate: i32,
application: i32,
bitrate_bps: i32,
variable_duration: i32,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct OpusMultistreamEncodeOptions<'a> {
pub stream_energy_masks: Option<&'a [Option<&'a [f32]>]>,
}
impl<'mode> OpusMultistreamEncoder<'mode> {
#[inline]
pub fn layout(&self) -> &ChannelLayout {
&self.layout
}
pub fn init(
&mut self,
sample_rate: i32,
channels: usize,
streams: usize,
coupled_streams: usize,
mapping: &[u8],
application: i32,
) -> Result<(), OpusMultistreamEncoderError> {
let layout = build_encoder_layout(channels, streams, coupled_streams, mapping)?;
let encoders = build_stream_encoders(sample_rate, streams, coupled_streams, application)?;
self.layout = layout;
self.encoders = encoders;
self.mapping_type = MappingType::None;
self.lfe_stream = None;
self.sample_rate = sample_rate;
self.application = application;
self.bitrate_bps = OPUS_AUTO;
self.variable_duration = OPUS_FRAMESIZE_ARG;
Ok(())
}
pub fn encoder_state(&mut self, stream_id: usize) -> Option<&mut OpusEncoder<'mode>> {
self.encoders.get_mut(stream_id)
}
}
pub fn opus_multistream_encoder_get_encoder_state<'a, 'mode>(
encoder: &'a mut OpusMultistreamEncoder<'mode>,
stream_id: usize,
) -> Result<&'a mut OpusEncoder<'mode>, OpusMultistreamEncoderError> {
encoder
.encoders
.get_mut(stream_id)
.ok_or(OpusMultistreamEncoderError::BadArgument)
}
#[must_use]
pub fn opus_multistream_encoder_get_size(
nb_streams: usize,
nb_coupled_streams: usize,
) -> Option<usize> {
if nb_streams == 0 || nb_coupled_streams > nb_streams {
return None;
}
let coupled_size = opus_encoder_get_size(2)?;
let mono_size = opus_encoder_get_size(1)?;
let header_size = align(core::mem::size_of::<OpusMsEncoderLayout>());
let coupled_total = nb_coupled_streams.checked_mul(align(coupled_size))?;
let mono_total = nb_streams
.checked_sub(nb_coupled_streams)?
.checked_mul(align(mono_size))?;
header_size
.checked_add(coupled_total)?
.checked_add(mono_total)
}
pub fn opus_multistream_encoder_create(
sample_rate: i32,
channels: usize,
streams: usize,
coupled_streams: usize,
mapping: &[u8],
application: i32,
) -> Result<OpusMultistreamEncoder<'static>, OpusMultistreamEncoderError> {
let layout = build_encoder_layout(channels, streams, coupled_streams, mapping)?;
let encoders = build_stream_encoders(sample_rate, streams, coupled_streams, application)?;
Ok(OpusMultistreamEncoder {
layout,
encoders,
mapping_type: MappingType::None,
lfe_stream: None,
sample_rate,
application,
bitrate_bps: OPUS_AUTO,
variable_duration: OPUS_FRAMESIZE_ARG,
})
}
fn build_encoder_layout(
channels: usize,
streams: usize,
coupled_streams: usize,
mapping: &[u8],
) -> Result<ChannelLayout, OpusMultistreamEncoderError> {
let layout =
build_layout(channels, streams, coupled_streams, mapping).map_err(|err| match err {
OpusMultistreamDecoderError::BadArgument => OpusMultistreamEncoderError::BadArgument,
_ => OpusMultistreamEncoderError::InternalError,
})?;
if streams
.checked_add(coupled_streams)
.is_none_or(|total| total > channels)
{
return Err(OpusMultistreamEncoderError::BadArgument);
}
if !validate_encoder_layout(&layout) {
return Err(OpusMultistreamEncoderError::BadArgument);
}
Ok(layout)
}
fn build_stream_encoders(
sample_rate: i32,
streams: usize,
coupled_streams: usize,
application: i32,
) -> Result<Vec<OpusEncoder<'static>>, OpusMultistreamEncoderError> {
if sample_rate <= 0 {
return Err(OpusMultistreamEncoderError::BadArgument);
}
let mut encoders = Vec::with_capacity(streams);
for stream in 0..streams {
let channels: i32 = if stream < coupled_streams { 2 } else { 1 };
encoders.push(opus_encoder_create(sample_rate, channels, application)?);
}
Ok(encoders)
}
pub enum OpusMultistreamEncoderCtlRequest<'req> {
SetApplication(i32),
GetApplication(&'req mut i32),
SetBitrate(i32),
GetBitrate(&'req mut i32),
SetForceChannels(i32),
GetForceChannels(&'req mut i32),
SetMaxBandwidth(i32),
GetMaxBandwidth(&'req mut i32),
SetBandwidth(i32),
GetBandwidth(&'req mut i32),
SetVbr(bool),
GetVbr(&'req mut bool),
SetVbrConstraint(bool),
GetVbrConstraint(&'req mut bool),
SetComplexity(i32),
GetComplexity(&'req mut i32),
SetSignal(i32),
GetSignal(&'req mut i32),
GetVoiceRatio(&'req mut i32),
SetPacketLossPerc(i32),
GetPacketLossPerc(&'req mut i32),
SetInbandFec(bool),
GetInbandFec(&'req mut bool),
SetDtx(bool),
GetDtx(&'req mut bool),
GetInDtx(&'req mut bool),
SetLsbDepth(i32),
GetLsbDepth(&'req mut i32),
SetExpertFrameDuration(i32),
GetExpertFrameDuration(&'req mut i32),
SetPredictionDisabled(bool),
GetPredictionDisabled(&'req mut bool),
SetPhaseInversionDisabled(bool),
GetPhaseInversionDisabled(&'req mut bool),
SetDredDuration(i32),
GetDredDuration(&'req mut i32),
SetDnnBlob(&'req [u8]),
SetForceMode(i32),
GetSampleRate(&'req mut i32),
GetLookahead(&'req mut i32),
GetFinalRange(&'req mut u32),
ResetState,
}
pub fn opus_multistream_encoder_ctl<'req>(
encoder: &mut OpusMultistreamEncoder<'_>,
request: OpusMultistreamEncoderCtlRequest<'req>,
) -> Result<(), OpusMultistreamEncoderError> {
if encoder.encoders.is_empty() {
return Err(OpusMultistreamEncoderError::InternalError);
}
match request {
OpusMultistreamEncoderCtlRequest::SetApplication(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetApplication(value)).map_err(
|err| match err {
OpusEncoderCtlError::BadArgument => {
OpusMultistreamEncoderError::BadArgument
}
_ => OpusMultistreamEncoderError::EncoderCtl(err),
},
)?;
}
encoder.application = value;
}
OpusMultistreamEncoderCtlRequest::GetApplication(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetApplication(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetBitrate(value) => {
if value != OPUS_AUTO && value != OPUS_BITRATE_MAX && value <= 0 {
return Err(OpusMultistreamEncoderError::BadArgument);
}
let clamped = if value == OPUS_AUTO || value == OPUS_BITRATE_MAX {
value
} else {
let channels = i32::try_from(encoder.layout.nb_channels)
.map_err(|_| OpusMultistreamEncoderError::BadArgument)?;
let min_rate = 500i32.saturating_mul(channels);
let max_rate = 300_000i32.saturating_mul(channels);
value.clamp(min_rate, max_rate)
};
encoder.bitrate_bps = clamped;
}
OpusMultistreamEncoderCtlRequest::GetBitrate(out) => {
let mut total = 0i64;
for enc in &mut encoder.encoders {
let mut rate = 0i32;
opus_encoder_ctl(enc, OpusEncoderCtlRequest::GetBitrate(&mut rate))?;
total += i64::from(rate);
}
*out = i32::try_from(total).map_err(|_| OpusMultistreamEncoderError::InternalError)?;
}
OpusMultistreamEncoderCtlRequest::SetForceChannels(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetForceChannels(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetForceChannels(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetForceChannels(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetMaxBandwidth(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetMaxBandwidth(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetMaxBandwidth(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetMaxBandwidth(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetBandwidth(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetBandwidth(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetBandwidth(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetBandwidth(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetVbr(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetVbr(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetVbr(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetVbr(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetVbrConstraint(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetVbrConstraint(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetVbrConstraint(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetVbrConstraint(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetComplexity(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetComplexity(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetComplexity(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetComplexity(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetSignal(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetSignal(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetSignal(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetSignal(out),
)?;
}
OpusMultistreamEncoderCtlRequest::GetVoiceRatio(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetVoiceRatio(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetPacketLossPerc(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetPacketLossPerc(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetPacketLossPerc(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetPacketLossPerc(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetInbandFec(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetInbandFec(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetInbandFec(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetInbandFec(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetDtx(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetDtx(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetDtx(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetDtx(out),
)?;
}
OpusMultistreamEncoderCtlRequest::GetInDtx(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetInDtx(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetLsbDepth(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetLsbDepth(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetLsbDepth(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetLsbDepth(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetExpertFrameDuration(value) => {
encoder.variable_duration = value;
}
OpusMultistreamEncoderCtlRequest::GetExpertFrameDuration(out) => {
*out = encoder.variable_duration;
}
OpusMultistreamEncoderCtlRequest::SetPredictionDisabled(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetPredictionDisabled(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetPredictionDisabled(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetPredictionDisabled(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetPhaseInversionDisabled(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetPhaseInversionDisabled(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetPhaseInversionDisabled(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetPhaseInversionDisabled(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetDredDuration(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetDredDuration(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetDredDuration(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetDredDuration(out),
)?;
}
OpusMultistreamEncoderCtlRequest::SetDnnBlob(data) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetDnnBlob(data))?;
}
}
OpusMultistreamEncoderCtlRequest::SetForceMode(value) => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::SetForceMode(value))?;
}
}
OpusMultistreamEncoderCtlRequest::GetSampleRate(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetSampleRate(out),
)?;
}
OpusMultistreamEncoderCtlRequest::GetLookahead(out) => {
opus_encoder_ctl(
encoder
.encoders
.first_mut()
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::GetLookahead(out),
)?;
}
OpusMultistreamEncoderCtlRequest::GetFinalRange(out) => {
let mut acc = 0u32;
for enc in &mut encoder.encoders {
let mut value = 0u32;
opus_encoder_ctl(enc, OpusEncoderCtlRequest::GetFinalRange(&mut value))?;
acc ^= value;
}
*out = acc;
}
OpusMultistreamEncoderCtlRequest::ResetState => {
for enc in &mut encoder.encoders {
opus_encoder_ctl(enc, OpusEncoderCtlRequest::ResetState)?;
}
}
}
Ok(())
}
fn encode_size(size: usize, data: &mut [u8]) -> Option<usize> {
if data.is_empty() {
return None;
}
if size < 252 {
data[0] = size as u8;
Some(1)
} else {
if data.len() < 2 {
return None;
}
data[0] = 252 + (size & 0x3) as u8;
data[1] = ((size - usize::from(data[0])) >> 2) as u8;
Some(2)
}
}
fn extract_i16_channel(
input: &[i16],
input_channels: usize,
channel: usize,
frame_size: usize,
output: &mut [i16],
output_stride: usize,
output_offset: usize,
) -> Result<(), OpusMultistreamEncoderError> {
for i in 0..frame_size {
let src = i
.checked_mul(input_channels)
.and_then(|base| base.checked_add(channel))
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
let dst = output_offset
.checked_add(
i.checked_mul(output_stride)
.ok_or(OpusMultistreamEncoderError::BadArgument)?,
)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
output[dst] = *input
.get(src)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
}
Ok(())
}
pub fn opus_multistream_encode_with_options(
encoder: &mut OpusMultistreamEncoder<'_>,
pcm: &[i16],
frame_size: usize,
data: &mut [u8],
options: OpusMultistreamEncodeOptions<'_>,
) -> Result<usize, OpusMultistreamEncoderError> {
let channels = encoder.layout.nb_channels;
if channels == 0 || frame_size == 0 {
return Err(OpusMultistreamEncoderError::BadArgument);
}
let required_pcm = channels
.checked_mul(frame_size)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
if pcm.len() < required_pcm {
return Err(OpusMultistreamEncoderError::BadArgument);
}
let nb_streams = encoder.layout.nb_streams;
if nb_streams == 0 {
return Err(OpusMultistreamEncoderError::BadArgument);
}
if let Some(masks) = options.stream_energy_masks
&& masks.len() != nb_streams
{
return Err(OpusMultistreamEncoderError::BadArgument);
}
let smallest_packet = nb_streams
.checked_mul(2)
.and_then(|value| value.checked_sub(1))
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
if data.len() < smallest_packet {
return Err(OpusMultistreamEncoderError::BufferTooSmall);
}
let mut rates = vec![0i32; nb_streams];
let _ = rate_allocation(
&encoder.layout,
encoder.mapping_type,
encoder.bitrate_bps,
encoder.lfe_stream,
frame_size,
encoder.sample_rate,
&mut rates,
);
let mut total_written = 0usize;
for stream in 0..nb_streams {
let self_delimited = stream + 1 != nb_streams;
let remaining_streams = nb_streams - stream - 1;
let reserve_min = remaining_streams
.checked_mul(2)
.and_then(|value| value.checked_sub(1))
.unwrap_or(0);
let available = data
.len()
.checked_sub(total_written)
.and_then(|value| value.checked_sub(reserve_min))
.ok_or(OpusMultistreamEncoderError::BufferTooSmall)?;
let size_overhead = if self_delimited { 2 } else { 0 };
if available <= size_overhead + 1 {
return Err(OpusMultistreamEncoderError::BufferTooSmall);
}
let mut tmp = vec![0u8; available - size_overhead];
if let Some(rate) = rates.get(stream).copied() {
let _ = opus_encoder_ctl(
encoder
.encoders
.get_mut(stream)
.ok_or(OpusMultistreamEncoderError::InternalError)?,
OpusEncoderCtlRequest::SetBitrate(rate),
);
}
let encode_options = OpusEncodeOptions {
energy_masking: options
.stream_energy_masks
.and_then(|masks| masks.get(stream))
.copied()
.flatten(),
};
if stream < encoder.layout.nb_coupled_streams {
let left = get_left_channel(&encoder.layout, stream, None)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
let right = get_right_channel(&encoder.layout, stream, None)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
let mut coupled_pcm = vec![0i16; frame_size * 2];
extract_i16_channel(pcm, channels, left, frame_size, &mut coupled_pcm, 2, 0)?;
extract_i16_channel(pcm, channels, right, frame_size, &mut coupled_pcm, 2, 1)?;
let len = opus_encode_with_options(
encoder
.encoders
.get_mut(stream)
.ok_or(OpusMultistreamEncoderError::InternalError)?,
&coupled_pcm,
frame_size,
&mut tmp,
encode_options,
)?;
let written =
write_stream_packet(&tmp[..len], self_delimited, &mut data[total_written..])
.ok_or(OpusMultistreamEncoderError::BufferTooSmall)?;
total_written += written;
} else {
let chan = get_mono_channel(&encoder.layout, stream, None)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
let mut mono_pcm = vec![0i16; frame_size];
extract_i16_channel(pcm, channels, chan, frame_size, &mut mono_pcm, 1, 0)?;
let len = opus_encode_with_options(
encoder
.encoders
.get_mut(stream)
.ok_or(OpusMultistreamEncoderError::InternalError)?,
&mono_pcm,
frame_size,
&mut tmp,
encode_options,
)?;
let written =
write_stream_packet(&tmp[..len], self_delimited, &mut data[total_written..])
.ok_or(OpusMultistreamEncoderError::BufferTooSmall)?;
total_written += written;
}
}
Ok(total_written)
}
pub fn opus_multistream_encode(
encoder: &mut OpusMultistreamEncoder<'_>,
pcm: &[i16],
frame_size: usize,
data: &mut [u8],
) -> Result<usize, OpusMultistreamEncoderError> {
opus_multistream_encode_with_options(
encoder,
pcm,
frame_size,
data,
OpusMultistreamEncodeOptions::default(),
)
}
fn write_stream_packet(
stream_packet: &[u8],
self_delimited: bool,
out: &mut [u8],
) -> Option<usize> {
if !self_delimited {
if out.len() < stream_packet.len() {
return None;
}
out[..stream_packet.len()].copy_from_slice(stream_packet);
return Some(stream_packet.len());
}
if stream_packet.is_empty() {
return None;
}
let toc = stream_packet[0];
let frame = &stream_packet[1..];
if out.is_empty() {
return None;
}
out[0] = toc;
let size_bytes = encode_size(frame.len(), &mut out[1..])?;
let start = 1 + size_bytes;
if out.len() < start + frame.len() {
return None;
}
out[start..start + frame.len()].copy_from_slice(frame);
Some(start + frame.len())
}
pub fn opus_multistream_encode_float_with_options(
encoder: &mut OpusMultistreamEncoder<'_>,
pcm: &[f32],
frame_size: usize,
data: &mut [u8],
options: OpusMultistreamEncodeOptions<'_>,
) -> Result<usize, OpusMultistreamEncoderError> {
let channels = encoder.layout.nb_channels;
let required_pcm = channels
.checked_mul(frame_size)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
if pcm.len() < required_pcm {
return Err(OpusMultistreamEncoderError::BadArgument);
}
let mut tmp = vec![0i16; required_pcm];
for (dst, &sample) in tmp.iter_mut().zip(pcm.iter().take(required_pcm)) {
let scaled = libm::roundf(sample * 32_768.0);
*dst = scaled.clamp(f32::from(i16::MIN), f32::from(i16::MAX)) as i16;
}
opus_multistream_encode_with_options(encoder, &tmp, frame_size, data, options)
}
pub fn opus_multistream_encode_float(
encoder: &mut OpusMultistreamEncoder<'_>,
pcm: &[f32],
frame_size: usize,
data: &mut [u8],
) -> Result<usize, OpusMultistreamEncoderError> {
opus_multistream_encode_float_with_options(
encoder,
pcm,
frame_size,
data,
OpusMultistreamEncodeOptions::default(),
)
}
pub fn opus_multistream_encode24_with_options(
encoder: &mut OpusMultistreamEncoder<'_>,
pcm: &[i32],
frame_size: usize,
data: &mut [u8],
options: OpusMultistreamEncodeOptions<'_>,
) -> Result<usize, OpusMultistreamEncoderError> {
let channels = encoder.layout.nb_channels;
let required_pcm = channels
.checked_mul(frame_size)
.ok_or(OpusMultistreamEncoderError::BadArgument)?;
if pcm.len() < required_pcm {
return Err(OpusMultistreamEncoderError::BadArgument);
}
let mut tmp = vec![0i16; required_pcm];
for (dst, &sample) in tmp.iter_mut().zip(pcm.iter().take(required_pcm)) {
let shifted = (sample >> 8).clamp(i32::from(i16::MIN), i32::from(i16::MAX));
*dst = shifted as i16;
}
opus_multistream_encode_with_options(encoder, &tmp, frame_size, data, options)
}
pub fn opus_multistream_encode24(
encoder: &mut OpusMultistreamEncoder<'_>,
pcm: &[i32],
frame_size: usize,
data: &mut [u8],
) -> Result<usize, OpusMultistreamEncoderError> {
opus_multistream_encode24_with_options(
encoder,
pcm,
frame_size,
data,
OpusMultistreamEncodeOptions::default(),
)
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpusMultistreamSurroundLayout {
pub streams: usize,
pub coupled_streams: usize,
pub mapping: Vec<u8>,
}
pub fn opus_multistream_surround_encoder_get_size(
channels: usize,
mapping_family: u8,
) -> Option<usize> {
let (streams, coupled_streams, _) = surround_layout(channels, mapping_family).ok()?;
let mut size = opus_multistream_encoder_get_size(streams, coupled_streams)?;
if channels > 2 {
size = size.checked_add(
channels.checked_mul(
120usize
.checked_mul(core::mem::size_of::<crate::celt::OpusVal32>())?
.checked_add(core::mem::size_of::<crate::celt::OpusVal32>())?,
)?,
)?;
}
Some(size)
}
pub fn opus_multistream_surround_encoder_create(
sample_rate: i32,
channels: usize,
mapping_family: u8,
application: i32,
) -> Result<
(
OpusMultistreamEncoder<'static>,
OpusMultistreamSurroundLayout,
),
OpusMultistreamEncoderError,
> {
let (streams, coupled_streams, mapping) = surround_layout(channels, mapping_family)?;
let mut encoder = opus_multistream_encoder_create(
sample_rate,
channels,
streams,
coupled_streams,
&mapping,
application,
)?;
let (mapping_type, lfe_stream) = surround_mapping_type(channels, mapping_family, streams);
encoder.mapping_type = mapping_type;
encoder.lfe_stream = lfe_stream;
Ok((
encoder,
OpusMultistreamSurroundLayout {
streams,
coupled_streams,
mapping,
},
))
}
pub fn opus_multistream_surround_encoder_init(
encoder: &mut OpusMultistreamEncoder<'_>,
sample_rate: i32,
channels: usize,
mapping_family: u8,
application: i32,
) -> Result<OpusMultistreamSurroundLayout, OpusMultistreamEncoderError> {
let (streams, coupled_streams, mapping) = surround_layout(channels, mapping_family)?;
encoder.init(
sample_rate,
channels,
streams,
coupled_streams,
&mapping,
application,
)?;
let (mapping_type, lfe_stream) = surround_mapping_type(channels, mapping_family, streams);
encoder.mapping_type = mapping_type;
encoder.lfe_stream = lfe_stream;
Ok(OpusMultistreamSurroundLayout {
streams,
coupled_streams,
mapping,
})
}
fn surround_mapping_type(
channels: usize,
mapping_family: u8,
streams: usize,
) -> (MappingType, Option<usize>) {
match mapping_family {
1 if channels > 2 => (
MappingType::Surround,
if channels >= 6 {
streams.checked_sub(1)
} else {
None
},
),
2 => (MappingType::Ambisonics, None),
_ => (MappingType::None, None),
}
}
fn surround_layout(
channels: usize,
mapping_family: u8,
) -> Result<(usize, usize, Vec<u8>), OpusMultistreamEncoderError> {
if channels == 0 || channels > 255 {
return Err(OpusMultistreamEncoderError::BadArgument);
}
let mut mapping = Vec::with_capacity(channels);
match mapping_family {
0 => match channels {
1 => {
mapping.push(0);
Ok((1, 0, mapping))
}
2 => {
mapping.extend_from_slice(&[0, 1]);
Ok((1, 1, mapping))
}
_ => Err(OpusMultistreamEncoderError::Unimplemented),
},
1 => {
if !(1..=8).contains(&channels) {
return Err(OpusMultistreamEncoderError::Unimplemented);
}
let layout = &VORBIS_MAPPINGS[channels - 1];
mapping.extend_from_slice(&layout.mapping[..channels]);
Ok((layout.nb_streams, layout.nb_coupled_streams, mapping))
}
255 => {
mapping.extend((0..channels).map(|v| v as u8));
Ok((channels, 0, mapping))
}
2 => {
let (streams, coupled_streams) =
validate_ambisonics(channels).ok_or(OpusMultistreamEncoderError::BadArgument)?;
let uncoupled_streams = streams - coupled_streams;
for i in 0..uncoupled_streams {
mapping.push((i + coupled_streams * 2) as u8);
}
for i in 0..coupled_streams * 2 {
mapping.push(i as u8);
}
Ok((streams, coupled_streams, mapping))
}
_ => Err(OpusMultistreamEncoderError::Unimplemented),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::opus_decoder::{opus_decode, opus_decoder_create};
use crate::opus_encoder::opus_encode;
use alloc::vec;
fn layout_from_mapping(
nb_channels: usize,
nb_streams: usize,
nb_coupled_streams: usize,
mapping_slice: &[u8],
) -> ChannelLayout {
let mut mapping = [u8::MAX; 256];
let count = mapping_slice.len().min(mapping.len());
mapping[..count].copy_from_slice(&mapping_slice[..count]);
ChannelLayout {
nb_channels,
nb_streams,
nb_coupled_streams,
mapping,
}
}
#[test]
fn accepts_valid_layout() {
let layout = layout_from_mapping(3, 2, 1, &[0, 1, 2]);
assert!(validate_layout(&layout));
}
#[test]
fn rejects_out_of_range_stream_indices() {
let layout = layout_from_mapping(1, 1, 0, &[1]);
assert!(!validate_layout(&layout));
}
#[test]
fn rejects_when_stream_count_exceeds_byte_limit() {
let layout = layout_from_mapping(2, 200, 60, &[0, 1]);
assert!(!validate_layout(&layout));
}
#[test]
fn iterates_all_channels_for_a_stream() {
let layout = layout_from_mapping(4, 3, 1, &[0, 0, 1, 2]);
assert_eq!(get_left_channel(&layout, 0, None), Some(0));
assert_eq!(get_left_channel(&layout, 0, Some(0)), Some(1));
assert_eq!(get_left_channel(&layout, 0, Some(1)), None);
assert_eq!(get_right_channel(&layout, 0, None), Some(2));
assert_eq!(get_right_channel(&layout, 0, Some(2)), None);
assert_eq!(get_mono_channel(&layout, 1, None), Some(3));
assert_eq!(get_mono_channel(&layout, 1, Some(3)), None);
}
#[test]
fn validate_encoder_layout_rejects_missing_channel() {
let layout = layout_from_mapping(2, 1, 1, &[0, u8::MAX]);
assert!(!validate_encoder_layout(&layout));
}
#[test]
fn validate_encoder_layout_accepts_complete_mapping() {
let layout = layout_from_mapping(2, 1, 1, &[0, 1]);
assert!(validate_encoder_layout(&layout));
}
#[test]
fn validate_ambisonics_computes_stream_and_coupling_counts() {
assert_eq!(validate_ambisonics(1), Some((1, 0)));
assert_eq!(validate_ambisonics(6), Some((5, 1)));
assert_eq!(validate_ambisonics(7), None);
assert_eq!(validate_ambisonics(228), None);
}
#[test]
fn rate_allocation_handles_stereo_surround_defaults() {
let layout = layout_from_mapping(2, 1, 1, &[0, 1]);
let mut rates = [0; 1];
let sum = rate_allocation(
&layout,
MappingType::Surround,
OPUS_AUTO,
None,
960,
48_000,
&mut rates,
)
.expect("allocation");
assert_eq!(sum, 120_000);
assert_eq!(rates, [120_000]);
}
#[test]
fn rate_allocation_accounts_for_lfe_stream() {
let layout = layout_from_mapping(6, 4, 2, &[0, 4, 1, 2, 3, 5]);
let mut rates = [0; 4];
let sum = rate_allocation(
&layout,
MappingType::Surround,
256_000,
Some(3),
960,
48_000,
&mut rates,
)
.expect("allocation");
assert_eq!(sum, 255_995);
assert_eq!(rates, [95_120, 95_120, 57_560, 8_195]);
}
#[test]
fn rate_allocation_splits_evenly_for_ambisonics() {
let layout = layout_from_mapping(4, 4, 0, &[0, 1, 2, 3]);
let mut rates = [0; 4];
let sum = rate_allocation(
&layout,
MappingType::Ambisonics,
OPUS_AUTO,
None,
960,
48_000,
&mut rates,
)
.expect("allocation");
assert_eq!(sum, 264_000);
assert_eq!(rates, [66_000; 4]);
}
#[test]
fn rate_allocation_rejects_insufficient_rate_storage() {
let layout = layout_from_mapping(2, 1, 1, &[0, 1]);
let mut rates: [i32; 0] = [];
assert!(
rate_allocation(
&layout,
MappingType::Surround,
64_000,
None,
960,
48_000,
&mut rates
)
.is_none()
);
}
#[test]
fn multistream_decoder_size_matches_aligned_components() {
let coupled = opus_decoder_get_size(2).expect("coupled size");
let mono = opus_decoder_get_size(1).expect("mono size");
let expected =
align(core::mem::size_of::<OpusMsDecoderLayout>()) + align(coupled) + align(mono);
let reported = opus_multistream_decoder_get_size(2, 1).expect("reported size");
assert_eq!(reported, expected);
assert!(opus_multistream_decoder_get_size(0, 0).is_none());
assert!(opus_multistream_decoder_get_size(2, 3).is_none());
}
#[test]
fn multistream_decoder_creation_validates_arguments() {
let mapping = [0u8, 1];
let err = opus_multistream_decoder_create(48_000, 0, 1, 0, &mapping).unwrap_err();
assert_eq!(err, OpusMultistreamDecoderError::BadArgument);
let short_map = [0u8];
let err = opus_multistream_decoder_create(48_000, 2, 1, 1, &short_map).unwrap_err();
assert_eq!(err, OpusMultistreamDecoderError::BadArgument);
}
#[test]
fn multistream_decoder_ctl_round_trips_gain_and_complexity() {
let mapping = [0u8, 1];
let mut decoder =
opus_multistream_decoder_create(48_000, 2, 1, 1, &mapping).expect("decoder");
opus_multistream_decoder_ctl(&mut decoder, OpusMultistreamDecoderCtlRequest::SetGain(-12))
.unwrap();
let mut gain = 0;
opus_multistream_decoder_ctl(
&mut decoder,
OpusMultistreamDecoderCtlRequest::GetGain(&mut gain),
)
.unwrap();
assert_eq!(gain, -12);
opus_multistream_decoder_ctl(
&mut decoder,
OpusMultistreamDecoderCtlRequest::SetComplexity(5),
)
.unwrap();
let mut complexity = 0;
opus_multistream_decoder_ctl(
&mut decoder,
OpusMultistreamDecoderCtlRequest::GetComplexity(&mut complexity),
)
.unwrap();
assert_eq!(complexity, 5);
let mut fs = 0;
opus_multistream_decoder_ctl(
&mut decoder,
OpusMultistreamDecoderCtlRequest::GetSampleRate(&mut fs),
)
.unwrap();
assert_eq!(fs, 48_000);
let err = opus_multistream_decoder_ctl(
&mut decoder,
OpusMultistreamDecoderCtlRequest::SetComplexity(11),
)
.unwrap_err();
assert_eq!(
err,
OpusMultistreamDecoderError::DecoderCtl(OpusDecoderCtlError::BadArgument)
);
}
#[test]
fn packet_validation_accepts_self_delimited_streams() {
let packet = [0x00, 0x01, 0xAA, 0x00, 0xBB];
let samples =
opus_multistream_packet_validate(&packet, packet.len(), 2, 48_000).expect("packet");
assert_eq!(samples, 480);
}
#[test]
fn packet_validation_rejects_mismatched_sample_counts() {
let packet = [0x00, 0x01, 0xAA, 0x18, 0xBB];
let err = opus_multistream_packet_validate(&packet, packet.len(), 2, 48_000).unwrap_err();
assert_eq!(err, OpusMultistreamDecoderError::InvalidPacket);
}
#[test]
fn decode_returns_unimplemented_after_validation() {
let mapping = [0u8, 1];
let mut decoder =
opus_multistream_decoder_create(48_000, 2, 1, 1, &mapping).expect("decoder");
let packet = [0x00, 0xAA];
let mut pcm = vec![0i16; 2 * 960];
let decoded =
opus_multistream_decode(&mut decoder, &packet, packet.len(), &mut pcm, 960, false)
.expect("decode");
assert!(decoded > 0);
}
#[test]
fn multistream_decode_matches_single_stream_decoder_for_stereo() {
let mapping = [0u8, 1];
let mut encoder = opus_encoder_create(48_000, 2, 2048).expect("encoder");
let pcm_in = vec![0i16; 2 * 960];
let mut packet = vec![0u8; 1500];
let len = opus_encode(&mut encoder, &pcm_in, 960, &mut packet).expect("encode");
let mut ms_decoder =
opus_multistream_decoder_create(48_000, 2, 1, 1, &mapping).expect("ms decoder");
let mut single = opus_decoder_create(48_000, 2).expect("single decoder");
let mut ms_out = vec![0i16; 2 * 960];
let mut single_out = vec![0i16; 2 * 960];
let ms_decoded =
opus_multistream_decode(&mut ms_decoder, &packet, len, &mut ms_out, 960, false)
.expect("ms decode");
let single_decoded = opus_decode(
&mut single,
Some(&packet[..len]),
len,
&mut single_out,
960,
false,
)
.expect("single decode");
assert_eq!(ms_decoded, single_decoded);
assert_eq!(ms_out[..ms_decoded * 2], single_out[..single_decoded * 2]);
}
#[test]
fn multistream_decode_routes_two_coupled_streams() {
let mapping = [0u8, 1, 2, 3];
let mut ms_encoder =
opus_multistream_encoder_create(48_000, 4, 2, 2, &mapping, 2048).expect("ms encoder");
let pcm_in = vec![0i16; 4 * 960];
let mut packet = vec![0u8; 4000];
let len =
opus_multistream_encode(&mut ms_encoder, &pcm_in, 960, &mut packet).expect("encode");
let mut ms_decoder =
opus_multistream_decoder_create(48_000, 4, 2, 2, &mapping).expect("ms decoder");
let mut ms_out = vec![0i16; 4 * 960];
let decoded =
opus_multistream_decode(&mut ms_decoder, &packet, len, &mut ms_out, 960, false)
.expect("ms decode");
assert!(decoded > 0);
let mut offset = 0usize;
let mut remaining = len;
let mut expected = vec![0i16; 4 * decoded];
for stream in 0..2 {
let self_delimited = stream == 0;
let parsed = opus_packet_parse_impl(&packet[offset..], remaining, self_delimited)
.expect("parse");
let packet_offset = parsed.packet_offset;
let mut dec = opus_decoder_create(48_000, 2).expect("decoder");
let mut stream_out = vec![0i16; 2 * decoded];
let stream_packet = if self_delimited {
let toc = packet[offset];
let payload_start = offset + parsed.payload_offset;
let payload_end = offset + parsed.packet_offset;
let mut reconstructed = vec![0u8; 1 + (payload_end - payload_start)];
reconstructed[0] = toc;
reconstructed[1..].copy_from_slice(&packet[payload_start..payload_end]);
reconstructed
} else {
packet[offset..offset + packet_offset].to_vec()
};
let stream_decoded = opus_decode(
&mut dec,
Some(&stream_packet),
stream_packet.len(),
&mut stream_out,
decoded,
false,
)
.expect("decode");
assert_eq!(stream_decoded, decoded);
for i in 0..decoded {
expected[i * 4 + stream * 2] = stream_out[i * 2];
expected[i * 4 + stream * 2 + 1] = stream_out[i * 2 + 1];
}
offset += packet_offset;
remaining -= packet_offset;
}
assert_eq!(ms_out[..decoded * 4], expected[..decoded * 4]);
}
#[test]
fn multistream_decode_zero_fills_muted_channel() {
let mapping = [0u8, 1, u8::MAX];
let mut encoder = opus_encoder_create(48_000, 2, 2048).expect("encoder");
let pcm_in = vec![0i16; 2 * 960];
let mut packet = vec![0u8; 1500];
let len = opus_encode(&mut encoder, &pcm_in, 960, &mut packet).expect("encode");
let mut ms_decoder =
opus_multistream_decoder_create(48_000, 3, 1, 1, &mapping).expect("ms decoder");
let mut out = vec![0i16; 3 * 960];
let decoded = opus_multistream_decode(&mut ms_decoder, &packet, len, &mut out, 960, false)
.expect("decode");
for i in 0..decoded {
assert_eq!(out[i * 3 + 2], 0);
}
}
#[test]
fn multistream_encode_respects_minimum_packet_size() {
let mapping = [0u8, 1];
let mut ms_encoder =
opus_multistream_encoder_create(48_000, 2, 1, 1, &mapping, 2048).expect("ms encoder");
let pcm_in = vec![0i16; 2 * 960];
let mut packet = vec![0u8; 2];
let err = opus_multistream_encode(&mut ms_encoder, &pcm_in, 960, &mut packet).unwrap_err();
assert_eq!(err, OpusMultistreamEncoderError::BufferTooSmall);
}
#[test]
fn multistream_encoder_ctl_round_trips_lsb_and_prediction() {
let mapping = [0u8, 1];
let mut encoder =
opus_multistream_encoder_create(48_000, 2, 2, 0, &mapping, 2048).expect("ms encoder");
let mut lsb = 0;
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::GetLsbDepth(&mut lsb),
)
.unwrap();
assert!(lsb >= 16);
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::SetLsbDepth(12),
)
.unwrap();
let mut updated = 0;
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::GetLsbDepth(&mut updated),
)
.unwrap();
assert_eq!(updated, 12);
let mut pred = false;
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::GetPredictionDisabled(&mut pred),
)
.unwrap();
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::SetPredictionDisabled(!pred),
)
.unwrap();
let mut pred_after = false;
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::GetPredictionDisabled(&mut pred_after),
)
.unwrap();
assert_eq!(pred_after, !pred);
{
let stream =
opus_multistream_encoder_get_encoder_state(&mut encoder, 1).expect("stream");
let mut stream_lsb = 0;
opus_encoder_ctl(stream, OpusEncoderCtlRequest::GetLsbDepth(&mut stream_lsb)).unwrap();
assert_eq!(stream_lsb, 12);
}
assert_eq!(
opus_multistream_encoder_get_encoder_state(&mut encoder, 2).unwrap_err(),
OpusMultistreamEncoderError::BadArgument
);
}
#[cfg(feature = "dred")]
#[test]
fn multistream_encoder_ctl_round_trips_dred_duration() {
let mapping = [0u8, 1];
let mut encoder =
opus_multistream_encoder_create(48_000, 2, 2, 0, &mapping, 2048).expect("ms encoder");
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::SetDredDuration(8),
)
.unwrap();
let mut duration = 0;
opus_multistream_encoder_ctl(
&mut encoder,
OpusMultistreamEncoderCtlRequest::GetDredDuration(&mut duration),
)
.unwrap();
assert_eq!(duration, 8);
}
#[test]
fn surround_encoder_layout_matches_vorbis_mapping() {
let (encoder, layout) =
opus_multistream_surround_encoder_create(48_000, 6, 1, 2048).expect("encoder");
assert_eq!(layout.streams, 4);
assert_eq!(layout.coupled_streams, 2);
assert_eq!(layout.mapping, vec![0, 4, 1, 2, 3, 5]);
assert_eq!(encoder.layout.nb_channels, 6);
assert_eq!(encoder.layout.nb_streams, 4);
assert_eq!(encoder.layout.nb_coupled_streams, 2);
assert_eq!(encoder.lfe_stream, Some(3));
assert_eq!(encoder.mapping_type, MappingType::Surround);
}
#[test]
fn surround_encoder_ambisonics_layout_matches_reference_ordering() {
let (_encoder, layout) =
opus_multistream_surround_encoder_create(48_000, 6, 2, 2048).expect("encoder");
assert_eq!(layout.streams, 5);
assert_eq!(layout.coupled_streams, 1);
assert_eq!(layout.mapping, vec![2, 3, 4, 5, 0, 1]);
}
#[test]
fn surround_encoder_get_size_matches_reference_overhead() {
let size = opus_multistream_surround_encoder_get_size(6, 1).expect("size");
let base = opus_multistream_encoder_get_size(4, 2).expect("base");
let overhead = 6
* (120 * core::mem::size_of::<crate::celt::OpusVal32>()
+ core::mem::size_of::<crate::celt::OpusVal32>());
assert_eq!(size, base + overhead);
}
}