Files
wz-phone/crates/wzp-proto/src/codec_id.rs
Siavash Sameni a8c2011445
Some checks failed
Mirror to GitHub / mirror (push) Failing after 36s
Build Release Binaries / build-amd64 (push) Has been cancelled
feat: add Opus 32k/48k/64k studio quality tiers
Adds three new codec IDs (Opus32k=6, Opus48k=7, Opus64k=8) and
corresponding STUDIO_32K, STUDIO_48K, STUDIO_64K quality profiles.
All use 20ms frames with minimal FEC (10%) for maximum quality on
good networks.

Updated across: wire protocol (codec_id.rs), encoder/decoder
(opus_enc/dec.rs), adaptive codec switch (call.rs), CLI
(--profile studio-64k), desktop engine + UI slider (8 quality
levels from Studio 64k green to Codec2 1.2k red).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 18:31:05 +04:00

162 lines
4.8 KiB
Rust

use serde::{Deserialize, Serialize};
/// Identifies the audio codec and bitrate configuration.
///
/// Encoded as 4 bits in the media packet header.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum CodecId {
/// Opus at 24kbps (good conditions)
Opus24k = 0,
/// Opus at 16kbps (moderate conditions)
Opus16k = 1,
/// Opus at 6kbps (degraded conditions)
Opus6k = 2,
/// Codec2 at 3200bps (poor conditions)
Codec2_3200 = 3,
/// Codec2 at 1200bps (catastrophic conditions)
Codec2_1200 = 4,
/// Comfort noise descriptor (silence suppression)
ComfortNoise = 5,
/// Opus at 32kbps (studio low)
Opus32k = 6,
/// Opus at 48kbps (studio)
Opus48k = 7,
/// Opus at 64kbps (studio high)
Opus64k = 8,
}
impl CodecId {
/// Nominal bitrate in bits per second.
pub const fn bitrate_bps(self) -> u32 {
match self {
Self::Opus24k => 24_000,
Self::Opus16k => 16_000,
Self::Opus6k => 6_000,
Self::Opus32k => 32_000,
Self::Opus48k => 48_000,
Self::Opus64k => 64_000,
Self::Codec2_3200 => 3_200,
Self::Codec2_1200 => 1_200,
Self::ComfortNoise => 0,
}
}
/// Preferred frame duration in milliseconds.
pub const fn frame_duration_ms(self) -> u8 {
match self {
Self::Opus24k | Self::Opus16k | Self::Opus32k | Self::Opus48k | Self::Opus64k => 20,
Self::Opus6k => 40,
Self::Codec2_3200 => 20,
Self::Codec2_1200 => 40,
Self::ComfortNoise => 20,
}
}
/// Sample rate expected by this codec.
pub const fn sample_rate_hz(self) -> u32 {
match self {
Self::Opus24k | Self::Opus16k | Self::Opus6k
| Self::Opus32k | Self::Opus48k | Self::Opus64k => 48_000,
Self::Codec2_3200 | Self::Codec2_1200 => 8_000,
Self::ComfortNoise => 48_000,
}
}
/// Try to decode from the 4-bit wire representation.
pub const fn from_wire(val: u8) -> Option<Self> {
match val {
0 => Some(Self::Opus24k),
1 => Some(Self::Opus16k),
2 => Some(Self::Opus6k),
3 => Some(Self::Codec2_3200),
4 => Some(Self::Codec2_1200),
5 => Some(Self::ComfortNoise),
6 => Some(Self::Opus32k),
7 => Some(Self::Opus48k),
8 => Some(Self::Opus64k),
_ => None,
}
}
/// Encode to the 4-bit wire representation.
pub const fn to_wire(self) -> u8 {
self as u8
}
/// Returns true if this is an Opus variant.
pub const fn is_opus(self) -> bool {
matches!(self, Self::Opus6k | Self::Opus16k | Self::Opus24k
| Self::Opus32k | Self::Opus48k | Self::Opus64k)
}
}
/// Describes the complete quality configuration for a call session.
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct QualityProfile {
/// Active codec.
pub codec: CodecId,
/// FEC repair ratio (0.0 = no FEC, 1.0 = 100% overhead, 2.0 = 200% overhead).
pub fec_ratio: f32,
/// Audio frame duration in ms (20 or 40).
pub frame_duration_ms: u8,
/// Number of source frames per FEC block.
pub frames_per_block: u8,
}
impl QualityProfile {
/// Good conditions: Opus 24kbps, light FEC.
pub const GOOD: Self = Self {
codec: CodecId::Opus24k,
fec_ratio: 0.2,
frame_duration_ms: 20,
frames_per_block: 5,
};
/// Degraded conditions: Opus 6kbps, moderate FEC.
pub const DEGRADED: Self = Self {
codec: CodecId::Opus6k,
fec_ratio: 0.5,
frame_duration_ms: 40,
frames_per_block: 10,
};
/// Catastrophic conditions: Codec2 1.2kbps, heavy FEC.
pub const CATASTROPHIC: Self = Self {
codec: CodecId::Codec2_1200,
fec_ratio: 1.0,
frame_duration_ms: 40,
frames_per_block: 8,
};
/// Studio low: Opus 32kbps, minimal FEC.
pub const STUDIO_32K: Self = Self {
codec: CodecId::Opus32k,
fec_ratio: 0.1,
frame_duration_ms: 20,
frames_per_block: 5,
};
/// Studio: Opus 48kbps, minimal FEC.
pub const STUDIO_48K: Self = Self {
codec: CodecId::Opus48k,
fec_ratio: 0.1,
frame_duration_ms: 20,
frames_per_block: 5,
};
/// Studio high: Opus 64kbps, minimal FEC.
pub const STUDIO_64K: Self = Self {
codec: CodecId::Opus64k,
fec_ratio: 0.1,
frame_duration_ms: 20,
frames_per_block: 5,
};
/// Estimated total bandwidth in kbps including FEC overhead.
pub fn total_bitrate_kbps(&self) -> f32 {
let base = self.codec.bitrate_bps() as f32 / 1000.0;
base * (1.0 + self.fec_ratio)
}
}