steam_audio_codec/
decoder.rs

1use crate::{read_u16, Packet, SteamAudioError, SteamVoiceData};
2use opus::{Channels, Decoder};
3
4/// A decoder for the steam voice data
5///
6/// This transforms the "lightly parsed" `SteamVoiceData` into 16-bit PCM voice data
7#[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    /// Decode a `SteamVoiceData` into 16-bit PCM sound data
20    ///
21    /// The raw samples are written into the provided output buffer. The number of samples written into the buffer is returned.
22    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}