steam_audio_codec/
decoder.rs1use crate::{read_u16, Packet, SteamAudioError, SteamVoiceData};
2use opus::{Channels, Decoder};
3
4#[derive(Default)]
8pub struct SteamVoiceDecoder {
9 decoder: Option<Decoder>,
10 sample_rate: u16,
11 seq: u16,
12}
13
14impl SteamVoiceDecoder {
15 pub fn new() -> Self {
16 Self::default()
17 }
18
19 pub fn decode(
23 &mut self,
24 voice_data: SteamVoiceData,
25 output_buffer: &mut [i16],
26 ) -> Result<usize, SteamAudioError> {
27 let mut total = 0;
28 for packet in voice_data.packets() {
29 let packet = packet?;
30 match packet {
31 Packet::SampleRate(rate) => {
32 if self.sample_rate != rate {
33 self.decoder = Some(Decoder::new(rate as u32, Channels::Mono)?);
34 self.sample_rate = rate;
35 }
36 }
37 Packet::OpusPlc(opus) => {
38 let count = self.decode_opus(opus.data, &mut output_buffer[total..])?;
39 total += count;
40 if total >= output_buffer.len() {
41 return Err(SteamAudioError::InsufficientOutputBuffer);
42 }
43 }
44 Packet::Silence(silence) => {
45 total += silence as usize;
46 }
47 }
48 }
49 Ok(total)
50 }
51
52 fn decode_opus(
53 &mut self,
54 mut data: &[u8],
55 output_buffer: &mut [i16],
56 ) -> Result<usize, SteamAudioError> {
57 let mut total = 0;
58 let Some(decoder) = self.decoder.as_mut() else {
59 return Err(SteamAudioError::NoSampleRate);
60 };
61
62 while data.len() > 2 {
63 let (len, remainder) = read_u16(data)?;
64 data = remainder;
65 if len == u16::MAX {
66 decoder.reset_state()?;
67 self.seq = 0;
68 continue;
69 }
70 let (seq, remainder) = read_u16(data)?;
71 data = remainder;
72
73 if seq < self.seq {
74 decoder.reset_state()?;
75 } else {
76 let lost = seq - self.seq;
77 for _ in 0..lost {
78 let count = decoder.decode(&[], &mut output_buffer[total..], false)?;
79 total += count;
80 if total >= output_buffer.len() {
81 return Err(SteamAudioError::InsufficientOutputBuffer);
82 }
83 }
84 }
85 let len = len as usize;
86
87 self.seq = seq + 1;
88
89 if data.len() < len {
90 return Err(SteamAudioError::InsufficientData);
91 }
92
93 let count = decoder.decode(&data[0..len], &mut output_buffer[total..], false)?;
94 data = &data[len..];
95 total += count;
96 if total >= output_buffer.len() {
97 return Err(SteamAudioError::InsufficientOutputBuffer);
98 }
99 }
100
101 Ok(total)
102 }
103}