1use anyhow::{ensure, Result};
4unsafe extern "C" {
5 fn aw_silk_encode(
6 pcm: *const i16,
7 samples: i32,
8 out: *mut u8,
9 capacity: i32,
10 length: *mut i32,
11 ) -> i32;
12 fn aw_silk_decode(
13 input: *const u8,
14 length: i32,
15 pcm: *mut i16,
16 capacity: i32,
17 samples: *mut i32,
18 ) -> i32;
19}
20pub const SAMPLE_RATE: u32 = 16000;
21pub const BIT_RATE: u32 = 40000;
26pub const FRAME_MS: u32 = 20;
28pub const MAX_NOTE_MS: u32 = 60_000;
30pub const MAX_SAMPLES: usize = (MAX_NOTE_MS / 1000 * SAMPLE_RATE) as usize;
31pub const MAX_STREAM_BYTES: usize = 512 * 1024;
33pub const MAX_NOTE_BYTES: usize = 10
39 + (MAX_NOTE_MS / FRAME_MS) as usize * (2 + (BIT_RATE / 8 * FRAME_MS / 1000) as usize * 3 / 2);
40const _: () = assert!(MAX_NOTE_BYTES <= MAX_STREAM_BYTES);
41pub fn encode(pcm: &[i16]) -> Result<Vec<u8>> {
42 ensure!(
43 !pcm.is_empty() && pcm.len() <= MAX_SAMPLES,
44 "voice_duration_limit"
45 );
46 let mut out = vec![0u8; MAX_STREAM_BYTES];
47 let mut length = 0i32;
48 let status = unsafe {
51 aw_silk_encode(
52 pcm.as_ptr(),
53 pcm.len() as i32,
54 out.as_mut_ptr(),
55 out.len() as i32,
56 &mut length,
57 )
58 };
59 ensure!(
60 status == 0 && length >= 12 && length as usize <= out.len(),
61 "silk_encode_failed"
62 );
63 out.truncate(length as usize);
64 validate_framing(&out)?;
65 Ok(out)
66}
67pub fn validate_framing(input: &[u8]) -> Result<u32> {
68 ensure!(
69 input.len() >= 12
70 && input.len() <= MAX_STREAM_BYTES
71 && input[0] <= 3
72 && input[1..10] == *b"#!SILK_V3",
73 "invalid_silk_stream"
74 );
75 let mut p = 10;
76 let mut packets = 0u32;
77 while p < input.len() {
78 ensure!(p + 2 <= input.len(), "invalid_silk_packet");
79 let n = i16::from_le_bytes(input[p..p + 2].try_into()?) as i32;
80 p += 2;
81 ensure!(
82 n > 0 && n <= 5120 && n as usize <= input.len() - p,
83 "invalid_silk_packet"
84 );
85 p += n as usize;
86 packets += 1;
87 ensure!(packets <= MAX_NOTE_MS / FRAME_MS, "voice_duration_limit");
88 }
89 ensure!(packets > 0, "empty_silk_stream");
90 Ok(packets * FRAME_MS)
91}
92pub fn decode(input: &[u8]) -> Result<Vec<i16>> {
93 validate_framing(input)?;
94 let mut pcm = vec![0i16; MAX_SAMPLES];
95 let mut samples = 0i32;
96 let status = unsafe {
99 aw_silk_decode(
100 input.as_ptr(),
101 input.len() as i32,
102 pcm.as_mut_ptr(),
103 pcm.len() as i32,
104 &mut samples,
105 )
106 };
107 ensure!(
108 status == 0 && samples > 0 && samples as usize <= pcm.len(),
109 "silk_decode_failed"
110 );
111 pcm.truncate(samples as usize);
112 Ok(pcm)
113}
114pub fn wav(pcm: &[i16]) -> Result<Vec<u8>> {
115 ensure!(pcm.len() <= MAX_SAMPLES, "voice_duration_limit");
116 let n = u32::try_from(pcm.len() * 2)?;
117 let mut out = Vec::with_capacity(44 + n as usize);
118 out.extend(b"RIFF");
119 out.extend((36 + n).to_le_bytes());
120 out.extend(b"WAVEfmt ");
121 out.extend(16u32.to_le_bytes());
122 out.extend(1u16.to_le_bytes());
123 out.extend(1u16.to_le_bytes());
124 out.extend(SAMPLE_RATE.to_le_bytes());
125 out.extend((SAMPLE_RATE * 2).to_le_bytes());
126 out.extend(2u16.to_le_bytes());
127 out.extend(16u16.to_le_bytes());
128 out.extend(b"data");
129 out.extend(n.to_le_bytes());
130 for s in pcm {
131 out.extend(s.to_le_bytes());
132 }
133 Ok(out)
134}
135#[cfg(test)]
136mod tests {
137 use super::*;
138 #[test]
139 fn independent_fresh_tones_encode_decode() {
140 let pcm = (0..16000)
141 .map(|i| ((i as f64 * 440.0 * std::f64::consts::TAU / 16000.0).sin() * 10000.0) as i16)
142 .collect::<Vec<_>>();
143 let encoded = encode(&pcm).unwrap();
144 assert_eq!(validate_framing(&encoded).unwrap(), 1000);
145 let decoded = decode(&encoded).unwrap();
146 assert_eq!(decoded.len(), pcm.len());
147 assert!(decoded.iter().any(|s| s.abs() > 1000));
148 assert_eq!(&wav(&decoded).unwrap()[..4], b"RIFF");
149 }
150 #[test]
151 fn maximum_note_stays_within_derived_byte_bound() {
152 assert_eq!(MAX_SAMPLES, 960_000);
153 assert_eq!(MAX_NOTE_BYTES, 456_010);
154 let mut seed = 0x9e37_79b9_7f4a_7c15u64;
157 let noise = (0..MAX_SAMPLES)
158 .map(|_| {
159 seed = seed
160 .wrapping_mul(6364136223846793005)
161 .wrapping_add(1442695040888963407);
162 (seed >> 48) as u16 as i16
163 })
164 .collect::<Vec<_>>();
165 let harmonic = (0..MAX_SAMPLES)
166 .map(|i| {
167 let t = i as f64 / SAMPLE_RATE as f64;
168 let f0 = 120.0 + 40.0 * (t * 3.0).sin();
169 let v = (1..30)
170 .map(|h| (t * f0 * h as f64 * std::f64::consts::TAU).sin() / h as f64)
171 .sum::<f64>();
172 (v * (t * 4.0).sin().abs() * 8000.0) as i16
173 })
174 .collect::<Vec<_>>();
175 for pcm in [noise, harmonic] {
176 let encoded = encode(&pcm).unwrap();
177 assert!(encoded.len() <= MAX_NOTE_BYTES, "{}", encoded.len());
178 assert_eq!(validate_framing(&encoded).unwrap(), MAX_NOTE_MS);
179 }
180 let too_long = vec![0i16; MAX_SAMPLES + 1];
181 assert!(encode(&too_long).is_err());
182 }
183 #[test]
184 fn malformed_packet_refused_before_ffi() {
185 for input in [
186 vec![],
187 [vec![2], b"#!SILK_V3".to_vec(), vec![0, 0]].concat(),
188 [vec![2], b"#!SILK_V3".to_vec(), vec![255, 255]].concat(),
189 ] {
190 assert!(decode(&input).is_err());
191 }
192 }
193}