1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
use crate::range_coder::RangeCoder;
use crate::silk::decode_frame::{FLAG_DECODE_NORMAL, FLAG_PACKET_LOST, silk_decode_frame};
use crate::silk::decode_indices::{
silk_decode_indices, silk_stereo_decode_mid_only, silk_stereo_decode_pred,
silk_stereo_ms_to_lr,
};
use crate::silk::decode_pulses::silk_decode_pulses;
use crate::silk::decoder_structs::SilkDecoderState;
use crate::silk::define::*;
use crate::silk::init_decoder::{silk_decoder_set_fs, silk_init_decoder};
use crate::silk::tables::{SILK_LBRR_FLAGS_2_ICDF, SILK_LBRR_FLAGS_3_ICDF};
pub struct SilkDecoder {
pub channel_state: [SilkDecoderState; 2],
pub n_channels_api: i32,
pub n_channels_internal: i32,
pub prev_decode_only_middle: i32,
// Stereo MS->LR reconstruction state (libopus stereo_dec_state).
pub s_stereo_pred_prev_q13: [i32; 2],
pub s_stereo_mid: [i16; 2],
pub s_stereo_side: [i16; 2],
// When set, a stereo decode reconstructs L/R via silk_stereo_ms_to_lr and
// publishes them (1-sample-delay-line layout, ready to resample) in l_out/
// r_out. When clear, stereo decodes emit only the mid (mono downmix) as
// before. lib.rs sets this for the pure-SILK stereo path.
pub produce_lr: bool,
pub l_out: [i16; MAX_FRAME_LENGTH],
pub r_out: [i16; MAX_FRAME_LENGTH],
}
impl Default for SilkDecoder {
fn default() -> Self {
Self::new()
}
}
impl SilkDecoder {
pub fn new() -> Self {
let mut dec = Self {
channel_state: [SilkDecoderState::default(), SilkDecoderState::default()],
n_channels_api: 1,
n_channels_internal: 1,
prev_decode_only_middle: 0,
s_stereo_pred_prev_q13: [0; 2],
s_stereo_mid: [0; 2],
s_stereo_side: [0; 2],
produce_lr: false,
l_out: [0; MAX_FRAME_LENGTH],
r_out: [0; MAX_FRAME_LENGTH],
};
silk_init_decoder(&mut dec.channel_state[0]);
silk_init_decoder(&mut dec.channel_state[1]);
dec
}
pub fn init(&mut self, sample_rate_hz: i32, channels: i32) -> i32 {
let fs_khz = sample_rate_hz / 1000;
let ret = silk_decoder_set_fs(&mut self.channel_state[0], fs_khz, sample_rate_hz);
if ret < 0 {
return ret;
}
if channels == 2 {
let ret = silk_decoder_set_fs(&mut self.channel_state[1], fs_khz, sample_rate_hz);
if ret < 0 {
return ret;
}
}
self.channel_state[0].n_frames_per_packet = 1;
self.n_channels_api = channels;
self.n_channels_internal = channels;
ret
}
pub fn decode(
&mut self,
range_dec: &mut RangeCoder,
output: &mut [i16],
lost_flag: i32,
new_packet: bool,
payload_size_ms: i32,
internal_sample_rate: i32,
) -> i32 {
if new_packet {
self.channel_state[0].n_frames_decoded = 0;
self.channel_state[1].n_frames_decoded = 0;
}
if self.channel_state[0].n_frames_decoded == 0 {
let fs_khz_dec = (internal_sample_rate >> 10) + 1;
if fs_khz_dec != 8 && fs_khz_dec != 12 && fs_khz_dec != 16 {
return -1;
}
let api_sample_rate = self.channel_state[0].fs_api_hz;
// libopus configures EVERY internal channel here, not just ch0 — the
// side channel needs its frame_length/fs set or a stereo side decode
// consumes the wrong number of bits and desyncs the range coder.
for n in 0..self.n_channels_internal as usize {
match payload_size_ms {
0 | 10 => {
self.channel_state[n].n_frames_per_packet = 1;
self.channel_state[n].nb_subfr = 2;
}
20 => {
self.channel_state[n].n_frames_per_packet = 1;
self.channel_state[n].nb_subfr = MAX_NB_SUBFR as i32;
}
40 => {
self.channel_state[n].n_frames_per_packet = 2;
self.channel_state[n].nb_subfr = MAX_NB_SUBFR as i32;
}
60 => {
self.channel_state[n].n_frames_per_packet = 3;
self.channel_state[n].nb_subfr = MAX_NB_SUBFR as i32;
}
_ => return -1,
}
let ret =
silk_decoder_set_fs(&mut self.channel_state[n], fs_khz_dec, api_sample_rate);
if ret < 0 {
return ret;
}
if payload_size_ms == 10 {
self.channel_state[n].nb_subfr = 2;
self.channel_state[n].frame_length = self.channel_state[n].subfr_length * 2;
}
}
}
if lost_flag != FLAG_PACKET_LOST && self.channel_state[0].n_frames_decoded == 0 {
let n_frames_per_packet = self.channel_state[0].n_frames_per_packet.max(1);
let n_channels = self.n_channels_internal as usize;
for n in 0..n_channels {
for i in 0..n_frames_per_packet as usize {
let vad = range_dec.decode_bit_logp(1);
self.channel_state[n].vad_flags[i] = if vad { 1 } else { 0 };
}
let lbrr = range_dec.decode_bit_logp(1);
self.channel_state[n].lbrr_flag = if lbrr { 1 } else { 0 };
}
for n in 0..n_channels {
self.channel_state[n].lbrr_flags.fill(0);
if self.channel_state[n].lbrr_flag != 0 {
if n_frames_per_packet == 1 {
self.channel_state[n].lbrr_flags[0] = 1;
} else {
let lbrr_icdf = match n_frames_per_packet {
2 => &SILK_LBRR_FLAGS_2_ICDF[..],
3 => &SILK_LBRR_FLAGS_3_ICDF[..],
_ => &SILK_LBRR_FLAGS_2_ICDF[..],
};
let lbrr_symbol = range_dec.decode_icdf(lbrr_icdf, 8) + 1;
for i in 0..n_frames_per_packet as usize {
self.channel_state[n].lbrr_flags[i] = (lbrr_symbol >> i) & 1;
}
}
}
}
// Skip LBRR data for all frames/channels
if lost_flag == FLAG_DECODE_NORMAL {
for i in 0..n_frames_per_packet as usize {
for n in 0..n_channels {
if self.channel_state[n].lbrr_flags[i] != 0 {
if n_channels == 2 && n == 0 {
let _ = silk_stereo_decode_pred(range_dec);
if self.channel_state[1].lbrr_flags[i] == 0 {
silk_stereo_decode_mid_only(range_dec);
}
}
let cond_coding =
if i > 0 && self.channel_state[n].lbrr_flags[i - 1] != 0 {
CODE_CONDITIONALLY
} else {
CODE_INDEPENDENTLY
};
silk_decode_indices(
&mut self.channel_state[n],
range_dec,
i as i32,
1,
cond_coding,
);
let mut pulses = [0i16; MAX_FRAME_LENGTH];
silk_decode_pulses(
range_dec,
&mut pulses,
self.channel_state[n].indices.signal_type as i32,
self.channel_state[n].indices.quant_offset_type as i32,
self.channel_state[n].frame_length,
);
}
}
}
}
}
let frame_index = self.channel_state[0].n_frames_decoded as usize;
let mut decode_only_middle = 0i32;
let mut ms_pred_q13 = [0i32; 2];
if self.n_channels_internal == 2 && lost_flag == FLAG_DECODE_NORMAL {
// Predictors + mid-only flag. Bits must be read to keep the range
// coder in sync.
ms_pred_q13 = silk_stereo_decode_pred(range_dec);
if self.channel_state[1].vad_flags[frame_index] == 0 {
decode_only_middle = if silk_stereo_decode_mid_only(range_dec) {
1
} else {
0
};
}
}
// Reset the side channel's prediction memory for the first frame that
// codes side after a run of mid-only frames (libopus dec_API.c:249-256).
if self.n_channels_internal == 2
&& decode_only_middle == 0
&& self.prev_decode_only_middle == 1
{
let ch1 = &mut self.channel_state[1];
ch1.out_buf.fill(0);
ch1.s_lpc_q14_buf.fill(0);
ch1.lag_prev = 100;
ch1.last_gain_index = 10;
ch1.prev_signal_type = TYPE_NO_VOICE_ACTIVITY;
ch1.first_frame_after_reset = 1;
}
let cond_coding = if frame_index == 0 {
CODE_INDEPENDENTLY
} else {
CODE_CONDITIONALLY
};
let mut n_samples_out: i32 = 0;
let ret = silk_decode_frame(
&mut self.channel_state[0],
range_dec,
output,
&mut n_samples_out,
lost_flag,
cond_coding,
);
self.channel_state[0].n_frames_decoded += 1;
let mut side_samples = [0i16; MAX_FRAME_LENGTH];
let mut side_decoded = false;
// Stereo: we output only the mid (mono downmix) for now, but the side
// frame's bits MUST still be consumed or the range coder desyncs for the
// next internal frame of a multi-frame packet (the mid of frames 2/3 then
// decodes from garbage). Decode it into a scratch buffer and discard.
if self.n_channels_internal == 2 && decode_only_middle == 0 && lost_flag == FLAG_DECODE_NORMAL
{
// libopus FrameIndex for the side (n=1) = channel_state[0].nFramesDecoded - 1,
// evaluated AFTER ch0's own increment, which equals the original
// frame_index. (Using frame_index-1 wrongly forced INDEP on the 2nd
// internal frame -> wrong bit count -> desync.)
let cond1 = if frame_index == 0 {
CODE_INDEPENDENTLY
} else if self.prev_decode_only_middle == 1 {
CODE_INDEPENDENTLY_NO_LTP_SCALING
} else {
CODE_CONDITIONALLY
};
let mut ns_side: i32 = 0;
let ret1 = silk_decode_frame(
&mut self.channel_state[1],
range_dec,
&mut side_samples,
&mut ns_side,
lost_flag,
cond1,
);
if ret1 < 0 {
return ret1;
}
side_decoded = true;
}
// Reconstruct L/R for the pure-SILK stereo path. mid is in `output`
// ([0..n]); side in side_samples ([0..n], zero if mid-only). ms_to_lr
// wants x1/x2 laid out as [hist0, hist1, samples...] and writes L to
// x1[1..1+n], R to x2[1..1+n] — exactly the 1-sample delay line the
// resampler consumes.
if self.produce_lr && self.n_channels_internal == 2 && n_samples_out > 0 {
let n = n_samples_out as usize;
let mut mid_buf = [0i16; MAX_FRAME_LENGTH + 2];
let mut side_buf = [0i16; MAX_FRAME_LENGTH + 2];
mid_buf[2..2 + n].copy_from_slice(&output[..n]);
if side_decoded {
side_buf[2..2 + n].copy_from_slice(&side_samples[..n]);
}
silk_stereo_ms_to_lr(
&mut self.s_stereo_pred_prev_q13,
&mut self.s_stereo_mid,
&mut self.s_stereo_side,
&mut mid_buf,
&mut side_buf,
&ms_pred_q13,
self.channel_state[0].fs_khz,
n,
);
self.l_out[..n].copy_from_slice(&mid_buf[1..1 + n]);
self.r_out[..n].copy_from_slice(&side_buf[1..1 + n]);
} else if n_samples_out >= 2 {
// Mono frame: buffer the last two mid samples so the NEXT stereo
// frame's ms_to_lr starts from the correct 2-sample history (libopus
// dec_API.c:312-313 — sStereo.sMid is updated even on mono frames).
// Without this the first stereo frame after a mono run reconstructs
// from stale history (~1/4-magnitude glitch at the switch).
let n = n_samples_out as usize;
self.s_stereo_mid[0] = output[n - 2];
self.s_stereo_mid[1] = output[n - 1];
}
// libopus increments channel_state[1].nFramesDecoded on EVERY internal
// frame (even mid-only). The side's silk_decode_frame keys its VAD/
// signal-type lookup off this counter; leaving it at 0 made every side
// frame read vad_flags[0] -> wrong signal type on frame 2+ -> desync.
if self.n_channels_internal == 2 {
self.channel_state[1].n_frames_decoded += 1;
}
self.prev_decode_only_middle = decode_only_middle;
if ret < 0 { ret } else { n_samples_out }
}
pub fn decode_bytes(&mut self, data: &[u8], output: &mut [i16], new_packet: bool) -> i32 {
let mut range_dec = RangeCoder::new_decoder(data);
let internal_rate = self.channel_state[0].fs_khz * 1000;
let payload_ms = if self.channel_state[0].nb_subfr == 2 {
10
} else {
20
};
self.decode(
&mut range_dec,
output,
FLAG_DECODE_NORMAL,
new_packet,
payload_ms,
internal_rate,
)
}
pub fn reset(&mut self) {
silk_init_decoder(&mut self.channel_state[0]);
silk_init_decoder(&mut self.channel_state[1]);
self.prev_decode_only_middle = 0;
}
pub fn frame_length(&self) -> i32 {
self.channel_state[0].frame_length
}
pub fn sample_rate(&self) -> i32 {
self.channel_state[0].fs_khz * 1000
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_decoder_creation() {
let dec = SilkDecoder::new();
assert_eq!(dec.n_channels_api, 1);
assert_eq!(dec.n_channels_internal, 1);
}
#[test]
fn test_decoder_init() {
let mut dec = SilkDecoder::new();
let ret = dec.init(16000, 1);
assert_eq!(ret, 0);
assert_eq!(dec.sample_rate(), 16000);
}
#[test]
fn test_decoder_16khz() {
let mut dec = SilkDecoder::new();
let ret = dec.init(16000, 1);
assert_eq!(ret, 0);
assert_eq!(dec.frame_length(), 320);
}
}