use crate::Error;
use super::layout::{ChannelLayout, MappingType};
pub const OPUS_AUTO: i32 = crate::OPUS_AUTO;
pub const OPUS_BITRATE_MAX: i32 = crate::OPUS_BITRATE_MAX;
pub const MS_FRAME_TMP: usize = 6 * crate::packet::MAX_FRAME_BYTES + 12;
pub(crate) const MAX_BITRATE_PER_CHANNEL: i32 = 750_000;
#[inline]
fn to_i32(v: i64) -> i32 {
v.clamp(i32::MIN as i64, i32::MAX as i64) as i32
}
#[inline]
fn count(v: usize) -> i64 {
v.min(i32::MAX as usize) as i64
}
#[inline]
fn check_frame(frame_size: usize, fs: i32) -> Result<(i64, i64), Error> {
if frame_size == 0 {
return Err(Error::bad_arg("multistream rate: the frame size must not be 0"));
}
if fs <= 0 {
return Err(Error::bad_arg("multistream rate: the sampling rate must be positive"));
}
Ok((count(frame_size), fs as i64))
}
#[inline]
fn check_conversion(frame_size: usize, fs: i32) -> Result<(), Error> {
let (frame_size, fs) = check_frame(frame_size, fs)?;
if 6 * fs / frame_size == 0 {
return Err(Error::bad_arg("multistream rate: the frame is longer than 6 seconds"));
}
Ok(())
}
pub fn bitrate_to_bits(bitrate: i32, fs: i32, frame_size: usize) -> Result<i32, Error> {
check_conversion(frame_size, fs)?;
Ok(crate::bitrate_to_bits(bitrate, fs, frame_size))
}
pub fn bits_to_bitrate(bits: i32, fs: i32, frame_size: usize) -> Result<i32, Error> {
check_conversion(frame_size, fs)?;
Ok(crate::bits_to_bitrate(bits, fs, frame_size))
}
pub fn clamp_user_bitrate(value: i32, channels: usize) -> Result<i32, Error> {
if channels == 0 {
return Err(Error::bad_arg("multistream rate: the channel count must not be 0"));
}
if value == OPUS_AUTO || value == OPUS_BITRATE_MAX {
return Ok(value);
}
if value <= 0 {
return Err(Error::bad_arg("multistream rate: the bitrate must be positive"));
}
let channels = count(channels);
Ok(to_i32(
(value as i64)
.max(500 * channels)
.min(i64::from(MAX_BITRATE_PER_CHANNEL) * channels),
))
}
fn check_allocation_args(
layout: &ChannelLayout,
user_bitrate: i32,
frame_size: usize,
fs: i32,
rate: &[i32],
) -> Result<(i64, i64), Error> {
if user_bitrate <= 0 && user_bitrate != OPUS_AUTO && user_bitrate != OPUS_BITRATE_MAX {
return Err(Error::bad_arg("multistream rate: the bitrate must be positive"));
}
if rate.len() < layout.streams() {
return Err(Error::bad_arg(
"multistream rate: the rate buffer has fewer entries than streams",
));
}
check_frame(frame_size, fs)
}
pub fn surround_rate_allocation(
layout: &ChannelLayout,
lfe_stream: Option<usize>,
user_bitrate: i32,
frame_size: usize,
fs: i32,
rate: &mut [i32],
) -> Result<(), Error> {
let (frame_size, fs) = check_allocation_args(layout, user_bitrate, frame_size, fs, rate)?;
let streams = layout.streams();
let coupled = layout.coupled_streams();
if lfe_stream.is_some_and(|lfe| lfe < coupled || lfe >= streams) {
return Err(Error::bad_arg(
"multistream rate: the LFE stream must be one of the mono streams",
));
}
let nb_lfe = lfe_stream.is_some() as i64;
let nb_coupled = coupled as i64;
let nb_uncoupled = streams as i64 - nb_coupled - nb_lfe;
let nb_normal = 2 * nb_coupled + nb_uncoupled;
if nb_normal == 0 {
return Err(Error::bad_arg("multistream rate: there is no stream besides the LFE stream"));
}
let channel_offset = 40 * (fs / frame_size).max(50);
let bitrate = if user_bitrate == OPUS_AUTO {
nb_normal * (channel_offset + fs + 10000) + 8000 * nb_lfe
} else if user_bitrate == OPUS_BITRATE_MAX {
nb_normal * i64::from(MAX_BITRATE_PER_CHANNEL) + nb_lfe * 128000
} else {
user_bitrate as i64
};
let lfe_offset = (bitrate / 20).min(3000) + 15 * (fs / frame_size).max(50);
let stream_offset =
((bitrate - channel_offset * nb_normal - lfe_offset * nb_lfe) / nb_normal / 2)
.clamp(0, 20000);
let coupled_ratio = 512;
let lfe_ratio = 32;
let total = (nb_uncoupled << 8) + coupled_ratio * nb_coupled + nb_lfe * lfe_ratio;
let channel_rate = 256
* (bitrate
- lfe_offset * nb_lfe
- stream_offset * (nb_coupled + nb_uncoupled)
- channel_offset * nb_normal)
/ total;
for (i, r) in rate[..streams].iter_mut().enumerate() {
let v = if i < coupled {
2 * channel_offset + (stream_offset + ((channel_rate * coupled_ratio) >> 8)).max(0)
} else if Some(i) != lfe_stream {
channel_offset + (stream_offset + channel_rate).max(0)
} else {
(lfe_offset + ((channel_rate * lfe_ratio) >> 8)).max(0)
};
*r = to_i32(v);
}
Ok(())
}
pub fn ambisonics_rate_allocation(
layout: &ChannelLayout,
user_bitrate: i32,
frame_size: usize,
fs: i32,
rate: &mut [i32],
) -> Result<(), Error> {
let (frame_size, fs) = check_allocation_args(layout, user_bitrate, frame_size, fs, rate)?;
let nb_streams = layout.streams() as i64;
let nb_coupled_streams = layout.coupled_streams() as i64;
let nb_channels = nb_streams + nb_coupled_streams;
let total_rate = if user_bitrate == OPUS_AUTO {
(nb_coupled_streams + nb_streams) * (fs + 60 * fs / frame_size) + nb_streams * 15000
} else if user_bitrate == OPUS_BITRATE_MAX {
nb_channels * i64::from(MAX_BITRATE_PER_CHANNEL)
} else {
user_bitrate as i64
};
let per_stream_rate = to_i32(total_rate / nb_streams);
rate[..layout.streams()].fill(per_stream_rate);
Ok(())
}
pub fn rate_allocation(
layout: &ChannelLayout,
mapping_type: MappingType,
lfe_stream: Option<usize>,
user_bitrate: i32,
frame_size: usize,
fs: i32,
rate: &mut [i32],
) -> Result<i32, Error> {
if mapping_type == MappingType::Ambisonics {
ambisonics_rate_allocation(layout, user_bitrate, frame_size, fs, rate)?;
} else {
let lfe_stream = if mapping_type == MappingType::Surround {
lfe_stream
} else {
None
};
surround_rate_allocation(layout, lfe_stream, user_bitrate, frame_size, fs, rate)?;
}
let mut rate_sum = 0i64;
for r in rate[..layout.streams()].iter_mut() {
*r = (*r).max(500);
rate_sum += *r as i64;
}
Ok(to_i32(rate_sum))
}
#[inline]
fn is_100_ms(frame_size: i64, fs: i64) -> bool {
fs / frame_size == 10
}
pub fn smallest_packet(streams: usize, frame_size: usize, fs: i32) -> Result<usize, Error> {
let (frame_size, fs) = check_frame(frame_size, fs)?;
if streams == 0 {
return Err(Error::bad_arg("multistream rate: at least one stream is needed"));
}
let streams = count(streams);
let mut smallest = streams * 2 - 1;
if is_100_ms(frame_size, fs) {
smallest += streams;
}
Ok(smallest as usize)
}
pub fn cbr_max_data_bytes(
user_bitrate: i32,
rate_sum: i32,
streams: usize,
frame_size: usize,
fs: i32,
max_data_bytes: usize,
) -> Result<usize, Error> {
let smallest = smallest_packet(streams, frame_size, fs)? as i64;
let max_data_bytes = count(max_data_bytes);
let limit = if user_bitrate == OPUS_AUTO {
max_data_bytes.min((bitrate_to_bits(rate_sum, fs, frame_size)? as i64 + 4) / 8)
} else if user_bitrate != OPUS_BITRATE_MAX {
max_data_bytes
.min(smallest.max((bitrate_to_bits(user_bitrate, fs, frame_size)? as i64 + 4) / 8))
} else {
max_data_bytes
};
Ok(limit.max(0) as usize)
}
pub fn stream_max_bytes(
max_data_bytes: usize,
tot_size: usize,
streams: usize,
stream: usize,
frame_size: usize,
fs: i32,
) -> Result<usize, Error> {
let (frame_size, fs) = check_frame(frame_size, fs)?;
if stream >= streams {
return Err(Error::bad_arg("multistream rate: no such stream"));
}
let streams_after = count(streams - stream - 1);
let mut curr_max = count(max_data_bytes) - count(tot_size);
curr_max -= (2 * streams_after - 1).max(0);
if is_100_ms(frame_size, fs) {
curr_max -= streams_after;
}
curr_max = curr_max.min(MS_FRAME_TMP as i64);
if streams_after != 0 {
curr_max -= if curr_max > 253 { 2 } else { 1 };
}
if curr_max < 1 {
return Err(Error::BUFFER_TOO_SMALL);
}
Ok(curr_max as usize)
}
pub fn cbr_last_stream_bitrate(
curr_max: usize,
frame_size: usize,
fs: i32,
) -> Result<i32, Error> {
bits_to_bitrate(to_i32(count(curr_max) * 8), fs, frame_size)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::multistream::layout::SILENT_CHANNEL;
fn rates(
channels: usize,
family: u8,
user_bitrate: i32,
frame_size: usize,
fs: i32,
) -> ([i32; 255], usize, i32) {
let (layout, mapping_type, lfe) = ChannelLayout::surround(channels, family).unwrap();
let mut rate = [0i32; 255];
let sum = rate_allocation(
&layout,
mapping_type,
lfe,
user_bitrate,
frame_size,
fs,
&mut rate,
)
.unwrap();
(rate, layout.streams(), sum)
}
#[test]
fn uncoupled_streams_share_the_bitrate_evenly() {
let (rate, streams, sum) = rates(3, 255, 96_000, 960, 48_000);
assert_eq!(&rate[..streams], &[32_000, 32_000, 32_000]);
assert_eq!(sum, 96_000);
}
#[test]
fn surround_5_1_matches_libopus() {
let (rate, streams, _) = rates(6, 1, 256_000, 960, 48_000);
assert_eq!(&rate[..streams], &[95_120, 95_120, 57_560, 8_195]);
let (rate, streams, _) = rates(6, 1, 48_000, 960, 48_000);
assert_eq!(&rate[..streams], &[17_005, 17_005, 10_245, 3_745]);
let (_, _, sum) = rates(6, 1, OPUS_AUTO, 960, 48_000);
assert_eq!(sum, 307_998);
let (_, _, sum) = rates(8, 1, OPUS_AUTO, 960, 48_000);
assert_eq!(sum, 427_993);
}
#[test]
fn ambisonics_gives_every_stream_the_same_rate() {
let (rate, streams, sum) = rates(6, 2, 100_000, 960, 48_000);
assert_eq!(streams, 5);
assert_eq!(&rate[..streams], &[20_000; 5]);
assert_eq!(sum, 100_000);
let (rate, _, sum) = rates(6, 2, OPUS_AUTO, 960, 48_000);
assert_eq!(rate[0], 76_200);
assert_eq!(sum, 381_000);
let (rate, _, _) = rates(6, 2, OPUS_BITRATE_MAX, 960, 48_000);
assert_eq!(rate[0], 900_000);
}
#[test]
fn every_stream_gets_at_least_500() {
for (channels, family) in [(1usize, 1u8), (6, 1), (8, 1), (5, 255), (6, 2)] {
let (rate, streams, sum) = rates(channels, family, 1, 960, 48_000);
assert!(
rate[..streams].iter().all(|&r| r >= 500),
"{channels} ch family {family}"
);
assert_eq!(sum, rate[..streams].iter().sum::<i32>());
}
let (rate, streams, sum) = rates(6, 2, 1, 960, 48_000);
assert_eq!(&rate[..streams], &[500; 5]);
assert_eq!(sum, 2_500);
}
#[test]
fn bad_arguments_are_errors() {
let (layout, mapping_type, lfe) = ChannelLayout::surround(6, 1).unwrap();
let mut rate = [0i32; 8];
let mut call = |lfe, bitrate, frame_size, fs, n: usize| {
rate_allocation(
&layout,
mapping_type,
lfe,
bitrate,
frame_size,
fs,
&mut rate[..n],
)
};
assert!(call(lfe, 64_000, 960, 48_000, 8).is_ok());
assert!(call(lfe, 64_000, 960, 48_000, 4).is_ok());
assert!(
call(lfe, 64_000, 960, 48_000, 3).is_err(),
"rate buffer too short"
);
assert!(call(lfe, 64_000, 0, 48_000, 8).is_err(), "frame size 0");
assert!(call(lfe, 64_000, 960, 0, 8).is_err(), "sampling rate 0");
assert!(
call(lfe, 64_000, 960, -48_000, 8).is_err(),
"negative sampling rate"
);
assert!(call(lfe, 0, 960, 48_000, 8).is_err(), "bitrate 0");
assert!(call(lfe, -2, 960, 48_000, 8).is_err(), "negative bitrate");
assert!(
call(Some(0), 64_000, 960, 48_000, 8).is_err(),
"LFE on a coupled stream"
);
assert!(
call(Some(4), 64_000, 960, 48_000, 8).is_err(),
"LFE stream out of range"
);
assert!(call(None, 64_000, 960, 48_000, 8).is_ok());
let (mono, _, _) = ChannelLayout::surround(1, 1).unwrap();
let mut one = [0i32; 1];
assert!(surround_rate_allocation(&mono, Some(0), 64_000, 960, 48_000, &mut one).is_err());
}
#[test]
fn lfe_stream_counts_only_in_surround_mode() {
let (layout, mapping_type, lfe) = ChannelLayout::surround(6, 1).unwrap();
assert_eq!((mapping_type, lfe), (MappingType::Surround, Some(3)));
let call = |mapping_type, lfe| {
let mut rate = [0i32; 4];
rate_allocation(&layout, mapping_type, lfe, 256_000, 960, 48_000, &mut rate).unwrap();
rate
};
let surround = [95_120, 95_120, 57_560, 8_195];
let generic = [78_666, 78_666, 49_333, 49_333];
assert_eq!(call(MappingType::Surround, lfe), surround);
assert_eq!(call(MappingType::Surround, None), generic);
assert_eq!(call(MappingType::None, lfe), generic);
assert_eq!(call(MappingType::None, None), generic);
assert_eq!(call(MappingType::Ambisonics, lfe), [64_000; 4]);
assert_eq!(call(MappingType::Ambisonics, None), [64_000; 4]);
let mut rate = [0i32; 4];
for (mapping_type, ok) in [
(MappingType::Surround, false),
(MappingType::None, true),
(MappingType::Ambisonics, true),
] {
let result = rate_allocation(
&layout,
mapping_type,
Some(9),
256_000,
960,
48_000,
&mut rate,
);
assert_eq!(result.is_ok(), ok, "{mapping_type:?}");
}
}
#[test]
fn coupled_stream_rate_does_not_wrap_at_32_bits() {
let mut map = [SILENT_CHANNEL; 12];
map[0] = 0;
map[1] = 1;
let layout = ChannelLayout::new(12, 1, 1, &map).unwrap();
let mut rate = [0i32; 1];
let sum = rate_allocation(
&layout,
MappingType::None,
None,
9_000_000,
960,
48_000,
&mut rate,
)
.unwrap();
assert_eq!((rate[0], sum), (9_000_000, 9_000_000));
}
struct Rng(u32);
impl Rng {
fn below(&mut self, n: usize) -> usize {
self.0 = self.0.wrapping_mul(1664525).wrapping_add(1013904223);
(self.0 >> 8) as usize % n
}
}
#[test]
fn no_argument_makes_a_function_panic() {
const I32S: [i32; 22] = [
i32::MIN,
i32::MIN + 1,
-1_000_000,
-1001,
OPUS_AUTO,
-999,
-2,
OPUS_BITRATE_MAX,
0,
1,
2,
499,
500,
501,
8_000,
48_000,
750_000,
4_500_000,
191_250_000,
357_913_942,
i32::MAX - 1,
i32::MAX,
];
const USIZES: [usize; 22] = [
0,
1,
2,
3,
4,
7,
10,
119,
120,
253,
254,
255,
256,
960,
2880,
4800,
5760,
48_000,
48_001,
u32::MAX as usize,
usize::MAX - 1,
usize::MAX,
];
let identity: [u8; 255] = core::array::from_fn(|i| i as u8);
let layouts = [
ChannelLayout::surround(1, 0).unwrap().0,
ChannelLayout::surround(6, 1).unwrap().0,
ChannelLayout::surround(8, 1).unwrap().0,
ChannelLayout::surround(255, 255).unwrap().0,
ChannelLayout::surround(227, 2).unwrap().0,
ChannelLayout::surround(3, 2).unwrap().0,
ChannelLayout::new(255, 128, 127, &identity).unwrap(),
];
let mut rng = Rng(77);
let mut rate = [0i32; 255];
let mut accepted = 0usize;
for _ in 0..200_000 {
let layout = &layouts[rng.below(layouts.len())];
let streams = layout.streams();
let mapping_type = [
MappingType::None,
MappingType::Surround,
MappingType::Ambisonics,
][rng.below(3)];
let lfe = match rng.below(4) {
0 => None,
1 => Some(streams - 1),
2 => Some(USIZES[rng.below(22)]),
_ => Some(rng.below(256)),
};
let n = [0usize, 1, 3, 4, 5, 254, 255][rng.below(7)];
let (a, b, c) = (
I32S[rng.below(22)],
I32S[rng.below(22)],
I32S[rng.below(22)],
);
let (x, y, z, w) = (
USIZES[rng.below(22)],
USIZES[rng.below(22)],
USIZES[rng.below(22)],
USIZES[rng.below(22)],
);
let _ = bitrate_to_bits(a, b, x);
let _ = bits_to_bitrate(a, b, x);
if let Ok(v) = clamp_user_bitrate(a, x) {
assert!(v == a || v > 0, "clamp_user_bitrate({a}, {x}) = {v}");
}
let r = &mut rate[..n];
if let Ok(sum) = rate_allocation(layout, mapping_type, lfe, a, x, b, r) {
accepted += 1;
assert!(n >= streams && sum >= 500);
assert!(r[..streams].iter().all(|&v| v >= 500));
}
if surround_rate_allocation(layout, lfe, a, x, b, r).is_ok() {
assert!(r[..streams].iter().all(|&v| v >= 0));
}
if ambisonics_rate_allocation(layout, a, x, b, r).is_ok() {
assert!(r[..streams].iter().all(|&v| v == r[0]));
}
if let Ok(v) = smallest_packet(x, y, a) {
assert!(x > 255 || (v >= x && v <= 3 * x));
}
if let Ok(v) = cbr_max_data_bytes(a, b, x, y, c, z) {
assert!(v <= z);
}
if let Ok(v) = stream_max_bytes(x, y, z, w, USIZES[rng.below(22)], a) {
accepted += 1;
assert!((1..=MS_FRAME_TMP).contains(&v) && v <= x);
}
let _ = cbr_last_stream_bitrate(x, y, a);
}
assert!(accepted > 10_000, "{accepted}");
}
#[test]
fn extreme_arguments_do_not_overflow() {
let mut map = [SILENT_CHANNEL; 255];
map[0] = 0;
map[1] = 1;
let layout = ChannelLayout::new(255, 1, 1, &map).unwrap();
let mut rate = [0i32; 1];
for bitrate in [1, 500, 191_250_000, i32::MAX, OPUS_AUTO, OPUS_BITRATE_MAX] {
for (frame_size, fs) in [
(1usize, i32::MAX),
(usize::MAX, 1),
(120, 48_000),
(5760, 48_000),
] {
for mapping_type in [
MappingType::None,
MappingType::Surround,
MappingType::Ambisonics,
] {
let sum = rate_allocation(
&layout,
mapping_type,
None,
bitrate,
frame_size,
fs,
&mut rate,
)
.unwrap();
assert!(sum >= 500);
assert_eq!(sum, rate[0]);
}
}
}
let (layout, mapping_type, lfe) = ChannelLayout::surround(255, 255).unwrap();
let mut rate = [0i32; 255];
let sum = rate_allocation(
&layout,
mapping_type,
lfe,
OPUS_BITRATE_MAX,
960,
48_000,
&mut rate,
)
.unwrap();
assert_eq!(sum, 255 * 750_000);
}
#[test]
fn user_bitrate_clamp() {
assert_eq!(clamp_user_bitrate(OPUS_AUTO, 6), Ok(OPUS_AUTO));
assert_eq!(
clamp_user_bitrate(OPUS_BITRATE_MAX, 6),
Ok(OPUS_BITRATE_MAX)
);
assert!(clamp_user_bitrate(0, 6).is_err());
assert!(clamp_user_bitrate(-2, 6).is_err());
assert_eq!(clamp_user_bitrate(1, 6), Ok(3_000));
assert_eq!(clamp_user_bitrate(256_000, 6), Ok(256_000));
assert_eq!(clamp_user_bitrate(i32::MAX, 6), Ok(4_500_000));
assert_eq!(clamp_user_bitrate(i32::MAX, 255), Ok(191_250_000));
assert_eq!(clamp_user_bitrate(i32::MAX, usize::MAX), Ok(i32::MAX));
assert!(clamp_user_bitrate(64_000, 0).is_err());
assert!(clamp_user_bitrate(OPUS_AUTO, 0).is_err());
}
#[test]
fn bits_and_bitrate_conversions() {
assert_eq!(bitrate_to_bits(64_000, 48_000, 960), Ok(1280));
assert_eq!(bits_to_bitrate(1280, 48_000, 960), Ok(64_000));
assert_eq!(bitrate_to_bits(64_000, 48_000, 2880), Ok(3840));
assert_eq!(bits_to_bitrate(3840, 48_000, 2880), Ok(64_000));
assert_eq!(bitrate_to_bits(64_000, 48_000, 120), Ok(160));
assert!(bitrate_to_bits(64_000, 48_000, 0).is_err());
assert!(bitrate_to_bits(64_000, 0, 960).is_err());
assert!(bits_to_bitrate(1280, 8_000, 48_001).is_err());
assert_eq!(bits_to_bitrate(i32::MAX, i32::MAX, 1), Ok(i32::MAX));
}
#[test]
fn smallest_packet_sizes() {
assert_eq!(smallest_packet(1, 960, 48_000), Ok(1));
assert_eq!(smallest_packet(4, 960, 48_000), Ok(7));
assert_eq!(smallest_packet(4, 4800, 48_000), Ok(11));
assert!(smallest_packet(0, 960, 48_000).is_err());
assert!(smallest_packet(4, 0, 48_000).is_err());
}
#[test]
fn cbr_packet_size() {
assert_eq!(
cbr_max_data_bytes(256_000, 0, 4, 960, 48_000, 4000),
Ok(640)
);
assert_eq!(cbr_max_data_bytes(96_000, 0, 4, 960, 48_000, 4000), Ok(240));
assert_eq!(cbr_max_data_bytes(256_000, 0, 4, 960, 48_000, 100), Ok(100));
assert_eq!(cbr_max_data_bytes(2_000, 0, 4, 960, 48_000, 4000), Ok(7));
assert_eq!(
cbr_max_data_bytes(OPUS_AUTO, 307_998, 4, 960, 48_000, 4000),
Ok(770)
);
assert_eq!(
cbr_max_data_bytes(OPUS_BITRATE_MAX, 0, 4, 960, 48_000, 4000),
Ok(4000)
);
}
#[test]
fn stream_budget_reserves_room_for_later_streams() {
assert_eq!(stream_max_bytes(640, 0, 4, 0, 960, 48_000), Ok(633));
assert_eq!(stream_max_bytes(640, 240, 4, 1, 960, 48_000), Ok(395));
assert_eq!(stream_max_bytes(640, 480, 4, 2, 960, 48_000), Ok(158));
assert_eq!(stream_max_bytes(640, 623, 4, 3, 960, 48_000), Ok(17));
assert_eq!(stream_max_bytes(255, 0, 2, 0, 960, 48_000), Ok(252));
assert_eq!(stream_max_bytes(254, 0, 2, 0, 960, 48_000), Ok(252));
assert_eq!(
stream_max_bytes(100_000, 0, 1, 0, 960, 48_000),
Ok(MS_FRAME_TMP)
);
assert_eq!(
stream_max_bytes(100_000, 0, 2, 0, 960, 48_000),
Ok(MS_FRAME_TMP - 2)
);
assert_eq!(stream_max_bytes(7, 0, 4, 0, 960, 48_000), Ok(1));
assert_eq!(stream_max_bytes(7, 2, 4, 1, 960, 48_000), Ok(1));
assert_eq!(stream_max_bytes(7, 4, 4, 2, 960, 48_000), Ok(1));
assert_eq!(stream_max_bytes(7, 6, 4, 3, 960, 48_000), Ok(1));
assert_eq!(stream_max_bytes(640, 0, 4, 0, 4800, 48_000), Ok(630));
assert!(stream_max_bytes(6, 0, 4, 0, 960, 48_000).is_err());
assert!(stream_max_bytes(640, 641, 4, 3, 960, 48_000).is_err());
assert!(stream_max_bytes(640, usize::MAX, 4, 3, 960, 48_000).is_err());
assert!(stream_max_bytes(640, 0, 4, 4, 960, 48_000).is_err());
assert!(stream_max_bytes(640, 0, 0, 0, 960, 48_000).is_err());
assert!(stream_max_bytes(640, 0, 4, 0, 0, 48_000).is_err());
}
#[test]
fn cbr_last_stream_rate() {
assert_eq!(cbr_last_stream_bitrate(17, 960, 48_000), Ok(6_800));
assert_eq!(
cbr_last_stream_bitrate(usize::MAX, 960, 48_000),
Ok(i32::MAX)
);
assert!(cbr_last_stream_bitrate(17, 0, 48_000).is_err());
}
}