ogg_opus/
lib.rs

1mod common;
2mod decode;
3mod encode;
4
5use thiserror::Error;
6
7pub use decode::decode;
8pub use encode::encode;
9
10use std::io::{Read, Seek, SeekFrom};
11pub fn is_ogg_opus<T: Read + Seek>(mut d: T) -> bool {
12    let mut buff = [0u8; 8];
13    if let Ok(_) = d.seek(SeekFrom::Start(28)) {
14        if let Ok(d) = d.read(&mut buff) {
15            if d == 8 {
16                return buff == decode::OPUS_MAGIC_HEADER;
17            }
18        }
19    }
20    // If anything fails
21    false
22}
23#[derive(Debug, Error)]
24pub enum Error {
25    #[error("Input audio was malformed")]
26    MalformedAudio,
27
28    #[error("Encoding error")]
29    OpusError(#[from] audiopus::Error),
30
31    #[error("Failed to decode ogg")]
32    OggReadError(#[from] ogg::OggReadError),
33
34    #[error("Failed to write in OGG")]
35    OggWriteError(#[from]std::io::Error),
36
37    #[error("Invalid samples per second")]
38    InvalidSps,
39}
40
41#[cfg(test)]
42mod tests {
43    use std::fs::{File};
44    use std::io::{Cursor};
45
46        fn read_file_i16(path: &str) -> Vec<i16> {
47            let mut f = File::open(path).expect("no file found");
48            let (_, b) = wav::read(&mut f).unwrap();
49            b.try_into_sixteen().unwrap()
50        }
51
52        #[test]
53        fn dec_enc_empty() {
54            let audio = Vec::new();
55            let opus = crate::encode::<16000, 1>(&audio).unwrap();
56            let enc_fin_range = crate::encode::get_final_range();
57            let (audio2, _) = crate::decode::<_,16000>(Cursor::new(opus)).unwrap();
58            let dec_fin_range = crate::decode::get_final_range();
59            assert_eq!(audio.len(), audio2.len()); // Should be the same, empty
60            assert_eq!(enc_fin_range, dec_fin_range);
61        }
62
63        #[test]
64        fn dec_enc_recording_big() {
65            let audio = read_file_i16("test_assets/big.wav");
66            let opus = crate::encode::<16000, 1>(&audio).unwrap();
67            let enc_fin_range = crate::encode::get_final_range();
68            let (a2,_) = crate::decode::<_,16000>(Cursor::new(opus)).unwrap();
69            let dec_fin_range = crate::decode::get_final_range();
70            assert_eq!(dec_fin_range, enc_fin_range);
71            assert_eq!(audio.len(), a2.len());
72        }
73
74        #[test]
75        fn dec_enc_recording_small() {
76            // This file (when added the skip) decodes to exactly 63 20ms 
77            // + a 2.5 ms packet
78            let audio = read_file_i16("test_assets/small.wav");
79            let opus = crate::encode::<16000, 1>(&audio).unwrap();
80            let enc_fin_range = crate::encode::get_final_range();
81            let (a2, _) = crate::decode::<_, 16000>(Cursor::new(opus)).unwrap();
82            let dec_fin_range = crate::decode::get_final_range();
83            assert_eq!(dec_fin_range, enc_fin_range);
84            assert_eq!(audio.len(), a2.len());
85        }
86
87        #[test]
88        // Record, encode, decode , encode and decode again, finally compare the
89        // first and second decodes, to make sure nothing is lost (can't compare
90        // raw audio as vorbis is lossy)
91        fn dec_enc_recording_whole() {
92            let audio = read_file_i16("test_assets/small.wav");
93            
94            let opus = crate::encode::<16000, 1>(&audio).unwrap();
95            let enc_fr1 = crate::encode::get_final_range();
96
97            let (audio2, _) = crate::decode::<_, 16000>(Cursor::new(opus)).unwrap();
98            let dec_fr1 = crate::decode::get_final_range();
99
100            let opus2 = crate::encode::<16000, 1>(&audio2).unwrap();
101            let enc_fr2 = crate::encode::get_final_range();
102
103            let (audio3, _) = crate::decode::<_, 16000>(Cursor::new(opus2)).unwrap();
104            let dec_fr2 = crate::decode::get_final_range();
105
106            assert_eq!(audio2.len(), audio3.len());
107            assert_eq!(enc_fr1, dec_fr1);
108            assert_eq!(enc_fr2, dec_fr2);
109        }
110}