ogg_opus/
decode.rs

1use std::io::{Read, Seek};
2
3use crate::Error;
4use crate::common::*;
5use byteorder::{LittleEndian, ByteOrder};
6use ogg::{Packet, PacketReader};
7use audiopus::{coder::{Decoder as OpusDec, GenericCtl}};
8
9//--- Final range  things ------------------------------------------------------
10
11#[cfg(test)]
12use std::cell::RefCell;
13
14#[cfg(test)]
15thread_local! {
16    static LAST_FINAL_RANGE: RefCell<u32> = RefCell::new(0);
17}
18
19#[cfg(test)]
20fn set_final_range(r:u32) {
21    LAST_FINAL_RANGE.with(|f|*f.borrow_mut() = r);
22}
23
24// Just here so that it can be used in the function
25#[cfg(not(test))]
26fn set_final_range(_:u32) {}
27
28#[cfg(test)]
29pub(crate) fn get_final_range() -> u32 {
30    LAST_FINAL_RANGE.with(|f|*f.borrow())
31}
32
33//--- Code ---------------------------------------------------------------------
34
35pub struct PlayData {
36    pub channels: u16
37}
38
39pub(crate) const OPUS_MAGIC_HEADER:[u8;8] = [b'O', b'p', b'u', b's', b'H', b'e', b'a', b'd'];
40
41/**Reads audio from Ogg Opus, note: it only can read from the ones produced 
42by itself, this is not ready for anything more, third return is final range just
43available while testing, otherwise it is a 0*/
44pub fn decode<T: Read + Seek, const TARGET_SPS: u32>(data: T) -> Result<(Vec<i16>, PlayData), Error> {
45    // Data
46    const MAX_FRAME_SAMPLES: usize = 5760; // According to opus_decode docs
47    const MAX_FRAME_SIZE: usize = MAX_FRAME_SAMPLES * (MAX_NUM_CHANNELS as usize); // Our buffer will be i16 so, don't convert to bytes
48
49    let mut reader = PacketReader::new(data);
50    let fp = reader.read_packet_expected().map_err(|_| Error::MalformedAudio)?; // Header
51
52    struct DecodeData {
53        pre_skip: u16,
54        gain: i32
55    }
56
57    // Analyze first page, where all the metadata we need is contained
58    fn check_fp<const TARGET_SPS: u32>(fp: &Packet) -> Result<(PlayData, DecodeData), Error> {
59
60        // Check size
61        if fp.data.len() < 19 {
62            return Err(Error::MalformedAudio)
63        }
64
65        // Read magic header
66        if fp.data[0..8] != OPUS_MAGIC_HEADER {
67            return Err(Error::MalformedAudio)
68        }
69
70        // Read version
71        if fp.data[8] != 1 {
72            return Err(Error::MalformedAudio)
73        }
74        
75
76        Ok((
77            PlayData{
78                channels: fp.data[9] as u16, // Number of channels
79            },
80            DecodeData {
81                pre_skip: calc_sr(LittleEndian::read_u16(&fp.data[10..12]), OGG_OPUS_SPS, TARGET_SPS),
82                gain: LittleEndian::read_i16(&fp.data[16..18]) as i32
83            }
84        ))
85    }
86
87    let (play_data, dec_data) = check_fp::<TARGET_SPS>(&fp)?;
88
89    let chans = match play_data.channels {
90        1 => Ok(audiopus::Channels::Mono),
91        2 => Ok(audiopus::Channels::Stereo),
92        _ => Err(Error::MalformedAudio)
93    }?;
94
95    let opus_sr = s_ps_to_audiopus(TARGET_SPS)?;
96
97    // According to RFC7845 if a device supports 48Khz, decode at this rate
98    let mut decoder =  OpusDec::new(opus_sr, chans)?;
99    decoder.set_gain(dec_data.gain)?;
100
101    // Vendor and other tags, do a basic check
102    let sp = reader.read_packet_expected().map_err(|_| Error::MalformedAudio)?; // Tags
103    fn check_sp(sp: &Packet) -> Result<(), Error> {
104        if sp.data.len() < 12 {
105            return Err(Error::MalformedAudio)
106        }
107
108        let head = std::str::from_utf8(&sp.data[0..8]).or_else(|_| Err(Error::MalformedAudio))?;
109        if head != "OpusTags" {
110            return Err(Error::MalformedAudio)
111        }
112        
113        Ok(())
114    }
115        
116    check_sp(&sp)?;
117
118    let mut buffer: Vec<i16> = Vec::new();
119    let mut rem_skip = dec_data.pre_skip as usize;
120    let mut dec_absgsp = 0;
121    while let Some(packet) = reader.read_packet()? {
122        let mut temp_buffer = [0i16; MAX_FRAME_SIZE];
123        let out_size = decoder.decode(Some(&packet.data), &mut temp_buffer[..], false)?;
124        let absgsp = calc_sr_u64(packet.absgp_page(),OGG_OPUS_SPS, TARGET_SPS) as usize;
125        dec_absgsp += out_size;
126        let trimmed_end = if packet.last_in_stream() && dec_absgsp > absgsp {
127            (out_size as usize * play_data.channels as usize) - (dec_absgsp - absgsp)
128        }
129        else {
130            // out_size == num of samples *per channel*
131            out_size as usize * play_data.channels as usize
132        } as usize;
133
134        if rem_skip < out_size {
135            buffer.extend_from_slice(&temp_buffer[rem_skip..trimmed_end]);
136            rem_skip = 0;
137        }
138        else {
139            rem_skip -= out_size;
140        }
141
142    }
143
144    if cfg!(test) {set_final_range(decoder.final_range().unwrap())};
145
146    Ok( (buffer, play_data))
147}