codec_core/lib.rs
1//! # `Codec-Core`: Audio Codec Library for `VoIP`
2//!
3//! A simple implementation of G.711 audio codec for `VoIP` applications.
4//! This library provides `ITU-T` compliant G.711 μ-law and A-law encoding/decoding
5//! with lookup table optimizations.
6//!
7//! ## Features
8//!
9//! - **ITU-T G.711 Compliant**: Passes official compliance tests
10//! - **Real Audio Tested**: Validated with actual speech samples
11//! - **Good Quality**: ~37 dB SNR with real speech
12//! - **Lookup Table Optimized**: Fast O(1) encoding/decoding
13//!
14//! ## Implementation
15//!
16//! - **Lookup Tables**: Pre-computed tables for O(1) operations
17//! - **Simple APIs**: Straightforward encoding/decoding functions
18//!
19//! ## Usage
20//!
21//! ### Quick Start
22//!
23//! ```rust
24//! # #[cfg(feature = "g711")]
25//! # {
26//! use codec_core::codecs::g711::G711Codec;
27//! use codec_core::types::{AudioCodec, CodecConfig, CodecType, SampleRate};
28//!
29//! // Create a G.711 μ-law codec
30//! let config = CodecConfig::new(CodecType::G711Pcmu)
31//! .with_sample_rate(SampleRate::Rate8000)
32//! .with_channels(1);
33//! let mut codec = G711Codec::new_pcmu(config)?;
34//!
35//! // Encode audio samples (20ms at 8kHz = 160 samples)
36//! let samples = vec![0i16; 160];
37//! let encoded = codec.encode(&samples)?;
38//!
39//! // Decode back to samples
40//! let decoded = codec.decode(&encoded)?;
41//! # }
42//! # Ok::<(), Box<dyn std::error::Error>>(())
43//! ```
44//!
45//! ## Testing & Validation
46//!
47//! The library includes comprehensive testing including real audio validation:
48//!
49//! ```bash
50//! # Run all codec tests including WAV roundtrip tests
51//! cargo test
52//!
53//! # Run only G.711 WAV roundtrip tests (downloads real speech audio)
54//! cargo test wav_roundtrip_test -- --nocapture
55//! ```
56//!
57//! The WAV roundtrip tests automatically download real speech samples and validate:
58//! - Signal-to-Noise Ratio (SNR) measurement
59//! - Round-trip audio quality preservation
60//! - Proper encoding/decoding with real audio data
61//! - Output WAV files for manual quality assessment
62//!
63//! ## Error Handling
64//!
65//! All codec operations return `Result` types with detailed error information:
66//!
67//! ```rust
68//! # #[cfg(feature = "g711")]
69//! # {
70//! use codec_core::codecs::g711::G711Codec;
71//! use codec_core::types::{CodecConfig, CodecType, SampleRate};
72//! use codec_core::error::CodecError;
73//!
74//! // Handle configuration errors
75//! let config = CodecConfig::new(CodecType::G711Pcmu)
76//! .with_sample_rate(SampleRate::Rate48000) // Invalid for G.711
77//! .with_channels(1);
78//!
79//! match G711Codec::new_pcmu(config) {
80//! Ok(codec) => println!("Codec created successfully"),
81//! Err(CodecError::InvalidSampleRate { rate, supported }) => {
82//! println!("Invalid sample rate {}, supported: {:?}", rate, supported);
83//! }
84//! Err(e) => println!("Other error: {}", e),
85//! }
86//! # }
87//! ```
88//!
89//! ## Performance Tips
90//!
91
92//! - Use appropriate frame sizes (160 samples for G.711 at 8kHz/20ms)
93//!
94//! ### Direct G.711 Functions
95//!
96//! ```rust
97//! # #[cfg(feature = "g711")]
98//! # {
99//! use codec_core::codecs::g711::{alaw_compress, alaw_expand, ulaw_compress, ulaw_expand};
100//!
101//! // Single sample processing
102//! let sample = 1024i16;
103//! let alaw_encoded = alaw_compress(sample);
104//! let alaw_decoded = alaw_expand(alaw_encoded);
105//!
106//! let ulaw_encoded = ulaw_compress(sample);
107//! let ulaw_decoded = ulaw_expand(ulaw_encoded);
108//! # }
109//! ```
110//!
111//! ### Frame-Based Processing
112//!
113//! ```rust
114//! # #[cfg(feature = "g711")]
115//! # {
116//! use codec_core::codecs::g711::{G711Codec, G711Variant};
117//!
118//! let mut codec = G711Codec::new(G711Variant::MuLaw);
119//!
120//! // Process 160 samples (20ms at 8kHz)
121//! let input_frame = vec![1000i16; 160]; // Some test samples
122//! let encoded = codec.compress(&input_frame).unwrap();
123//!
124//! // Decode back to samples (same count for G.711)
125//! let decoded = codec.expand(&encoded).unwrap();
126//! assert_eq!(input_frame.len(), decoded.len());
127//! # }
128//! # Ok::<(), Box<dyn std::error::Error>>(())
129//! ```
130//!
131//! ## Supported Codecs
132//!
133//! | Codec | Sample Rate | Channels | Bitrate | Frame Size | Status |
134//! |-------|-------------|----------|---------|------------|--------|
135//! | **G.711 μ-law (PCMU)** | 8 kHz | 1 | 64 kbps | 160 samples | ✅ Production |
136//! | **G.711 A-law (PCMA)** | 8 kHz | 1 | 64 kbps | 160 samples | ✅ Production |
137//!
138//! ## Quality Metrics
139//!
140//! Based on real audio testing with the included WAV roundtrip tests:
141//!
142//! - **G.711**: 37+ dB SNR (excellent quality, industry standard)
143//!
144//! ## Feature Flags
145//!
146//! ### Core Codecs (enabled by default)
147//! - `g711`: G.711 μ-law/A-law codecs
148
149#![deny(missing_docs)]
150#![warn(clippy::all)]
151#![warn(clippy::pedantic)]
152#![warn(clippy::nursery)]
153#![allow(clippy::module_name_repetitions)]
154
155pub mod codecs;
156pub mod error;
157pub mod types;
158pub mod utils;
159
160// Re-export commonly used types and traits
161pub use codecs::{CodecFactory, CodecRegistry};
162pub use error::{CodecError, Result};
163pub use types::{
164 AudioCodec, AudioFrame, CodecCapability, CodecConfig, CodecInfo, CodecType, SampleRate,
165};
166
167/// Version information for the codec library
168pub const VERSION: &str = env!("CARGO_PKG_VERSION");
169
170/// Supported codec types
171pub const SUPPORTED_CODECS: &[&str] = &[
172 #[cfg(feature = "g711")]
173 "PCMU",
174 #[cfg(feature = "g711")]
175 "PCMA",
176 #[cfg(feature = "g729")]
177 "G729",
178 #[cfg(feature = "g729")]
179 "G729A",
180 #[cfg(feature = "g729")]
181 "G729BA",
182 #[cfg(feature = "opus")]
183 "opus",
184];
185
186/// Initialize the codec library
187///
188/// This function should be called once at program startup to initialize
189/// any global state or lookup tables. It's safe to call multiple times.
190///
191/// # Errors
192///
193/// Returns an error if initialization fails (e.g., SIMD detection fails)
194pub fn init() -> Result<()> {
195 // Initialize logging if not already done
196 let _ = tracing_subscriber::fmt::try_init();
197
198 // Initialize lookup tables
199 #[cfg(feature = "g711")]
200 codecs::g711::init_tables();
201
202 tracing::info!("Codec-Core v{} initialized", VERSION);
203 tracing::info!("Supported codecs: {:?}", SUPPORTED_CODECS);
204
205 Ok(())
206}
207
208/// Get library information
209#[must_use]
210pub fn info() -> LibraryInfo {
211 LibraryInfo {
212 version: VERSION,
213 supported_codecs: SUPPORTED_CODECS.to_vec(),
214 }
215}
216
217/// Library information structure
218#[derive(Debug, Clone)]
219pub struct LibraryInfo {
220 /// Library version
221 pub version: &'static str,
222 /// List of supported codec names
223 pub supported_codecs: Vec<&'static str>,
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229
230 #[test]
231 fn test_init() {
232 assert!(init().is_ok());
233 }
234
235 #[test]
236 fn test_info() {
237 let info = info();
238 assert_eq!(info.version, VERSION);
239
240 #[cfg(any(feature = "g711", feature = "g729", feature = "opus"))]
241 assert!(!info.supported_codecs.is_empty());
242
243 #[cfg(not(any(feature = "g711", feature = "g729", feature = "opus")))]
244 assert!(info.supported_codecs.is_empty());
245 }
246
247 #[test]
248 fn test_supported_codecs() {
249 #[cfg(any(feature = "g711", feature = "g729", feature = "opus"))]
250 assert!(!SUPPORTED_CODECS.is_empty());
251
252 #[cfg(not(any(feature = "g711", feature = "g729", feature = "opus")))]
253 assert!(SUPPORTED_CODECS.is_empty());
254
255 #[cfg(feature = "g711")]
256 {
257 assert!(SUPPORTED_CODECS.contains(&"PCMU"));
258 assert!(SUPPORTED_CODECS.contains(&"PCMA"));
259 }
260
261 #[cfg(feature = "g729")]
262 {
263 assert!(SUPPORTED_CODECS.contains(&"G729"));
264 assert!(SUPPORTED_CODECS.contains(&"G729A"));
265 assert!(SUPPORTED_CODECS.contains(&"G729BA"));
266 }
267
268 #[cfg(feature = "opus")]
269 assert!(SUPPORTED_CODECS.contains(&"opus"));
270 }
271}