scuffle_flv/audio/header/
legacy.rs

1//! Legacy audio header types and functions.
2
3use std::io;
4
5use byteorder::ReadBytesExt;
6use bytes::Bytes;
7use nutype_enum::nutype_enum;
8
9use crate::error::FlvError;
10
11nutype_enum! {
12    /// FLV `SoundFormat`
13    ///
14    /// Denotes the type of the underlying data packet.
15    ///
16    /// Defined by:
17    /// - Legacy FLV spec, Annex E.4.2.1
18    pub enum SoundFormat(u8) {
19        /// Linear PCM, platform endian
20        LinearPcmPlatformEndian = 0,
21        /// ADPCM
22        Adpcm = 1,
23        /// MP3
24        Mp3 = 2,
25        /// Linear PCM, little endian
26        LinearPcmLittleEndian = 3,
27        /// Nellymoser 16Khz Mono
28        Nellymoser16KhzMono = 4,
29        /// Nellymoser 8Khz Mono
30        Nellymoser8KhzMono = 5,
31        /// Nellymoser
32        Nellymoser = 6,
33        /// G.711 A-Law logarithmic PCM
34        G711ALaw = 7,
35        /// G.711 Mu-Law logarithmic PCM
36        G711MuLaw = 8,
37        /// The `ExAudioTagHeader` is present
38        ///
39        /// Defined by: Enhanced RTMP v2 (Enhanced Audio section)
40        ExHeader = 9,
41        /// AAC
42        Aac = 10,
43        /// Speex
44        Speex = 11,
45        /// Mp3 8Khz
46        Mp38Khz = 14,
47        /// Device specific sound
48        DeviceSpecificSound = 15,
49    }
50}
51
52nutype_enum! {
53    /// FLV `SoundRate`
54    ///
55    /// Denotes the sampling rate of the audio data.
56    ///
57    /// Defined by:
58    /// - Legacy FLV spec, Annex E.4.2.1
59    pub enum SoundRate(u8) {
60        /// 5.5 KHz
61        Hz5500 = 0,
62        /// 11 KHz
63        Hz11000 = 1,
64        /// 22 KHz
65        Hz22000 = 2,
66        /// 44 KHz
67        Hz44000 = 3,
68    }
69}
70
71nutype_enum! {
72    /// FLV `SoundSize`
73    ///
74    /// Size of each audio sample. This parameter only pertains to
75    /// uncompressed formats. Compressed formats always decode
76    /// to 16 bits internally.
77    ///
78    /// Defined by:
79    /// - Legacy FLV spec, Annex E.4.2.1
80    pub enum SoundSize(u8) {
81        /// 8 bit
82        Bit8 = 0,
83        /// 16 bit
84        Bit16 = 1,
85    }
86}
87
88nutype_enum! {
89    /// FLV `SoundType`
90    ///
91    /// Denotes the number of channels in the audio data.
92    ///
93    /// Defined by:
94    /// - Legacy FLV spec, Annex E.4.2.1
95    pub enum SoundType(u8) {
96        /// Mono
97        Mono = 0,
98        /// Stereo
99        Stereo = 1,
100    }
101}
102
103/// FLV `AudioTagHeader`
104///
105/// Defined by:
106/// - Legacy FLV spec, Annex E.4.2.1
107#[derive(Debug, Clone, PartialEq)]
108pub struct LegacyAudioTagHeader {
109    /// The sound format of the audio data. (4 bits)
110    pub sound_format: SoundFormat,
111    /// The sound rate of the audio data. (2 bits)
112    pub sound_rate: SoundRate,
113    /// The sound size of the audio data. (1 bit)
114    pub sound_size: SoundSize,
115    /// The sound type of the audio data. (1 bit)
116    pub sound_type: SoundType,
117}
118
119impl LegacyAudioTagHeader {
120    /// Demux the audio tag header from the given reader.
121    #[allow(clippy::unusual_byte_groupings)]
122    pub fn demux(reader: &mut io::Cursor<Bytes>) -> Result<Self, FlvError> {
123        let byte = reader.read_u8()?;
124
125        // SoundFormat is the first 4 bits of the byte
126        let sound_format = SoundFormat::from(byte >> 4); // 0b1111_00_0_0
127        // SoundRate is the next 2 bits of the byte
128        let sound_rate = SoundRate::from((byte & 0b0000_11_0_0) >> 2);
129        // SoundSize is the next bit of the byte
130        let sound_size = SoundSize::from((byte & 0b0000_00_1_0) >> 1);
131        // SoundType is the last bit of the byte
132        let sound_type = SoundType::from(byte & 0b0000_00_0_1);
133
134        Ok(Self {
135            sound_format,
136            sound_rate,
137            sound_size,
138            sound_type,
139        })
140    }
141}
142
143#[cfg(test)]
144#[cfg_attr(all(test, coverage_nightly), coverage(off))]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn test_sound_format() {
150        let cases = [
151            (
152                0x00,
153                SoundFormat::LinearPcmPlatformEndian,
154                "SoundFormat::LinearPcmPlatformEndian",
155            ),
156            (0x01, SoundFormat::Adpcm, "SoundFormat::Adpcm"),
157            (0x02, SoundFormat::Mp3, "SoundFormat::Mp3"),
158            (0x03, SoundFormat::LinearPcmLittleEndian, "SoundFormat::LinearPcmLittleEndian"),
159            (0x04, SoundFormat::Nellymoser16KhzMono, "SoundFormat::Nellymoser16KhzMono"),
160            (0x05, SoundFormat::Nellymoser8KhzMono, "SoundFormat::Nellymoser8KhzMono"),
161            (0x06, SoundFormat::Nellymoser, "SoundFormat::Nellymoser"),
162            (0x07, SoundFormat::G711ALaw, "SoundFormat::G711ALaw"),
163            (0x08, SoundFormat::G711MuLaw, "SoundFormat::G711MuLaw"),
164            (0x0A, SoundFormat::Aac, "SoundFormat::Aac"),
165            (0x0B, SoundFormat::Speex, "SoundFormat::Speex"),
166            (0x0E, SoundFormat::Mp38Khz, "SoundFormat::Mp38Khz"),
167            (0x0F, SoundFormat::DeviceSpecificSound, "SoundFormat::DeviceSpecificSound"),
168        ];
169
170        for (value, expected, name) in cases {
171            let sound_format = SoundFormat::from(value);
172            assert_eq!(sound_format, expected);
173            assert_eq!(format!("{sound_format:?}"), name);
174        }
175    }
176
177    #[test]
178    fn test_sound_rate() {
179        let cases = [
180            (0x00, SoundRate::Hz5500, "SoundRate::Hz5500"),
181            (0x01, SoundRate::Hz11000, "SoundRate::Hz11000"),
182            (0x02, SoundRate::Hz22000, "SoundRate::Hz22000"),
183            (0x03, SoundRate::Hz44000, "SoundRate::Hz44000"),
184        ];
185
186        for (value, expected, name) in cases {
187            let sound_rate = SoundRate::from(value);
188            assert_eq!(sound_rate, expected);
189            assert_eq!(format!("{sound_rate:?}"), name);
190        }
191    }
192
193    #[test]
194    fn test_sound_size() {
195        let cases = [
196            (0x00, SoundSize::Bit8, "SoundSize::Bit8"),
197            (0x01, SoundSize::Bit16, "SoundSize::Bit16"),
198        ];
199
200        for (value, expected, name) in cases {
201            let sound_size = SoundSize::from(value);
202            assert_eq!(sound_size, expected);
203            assert_eq!(format!("{sound_size:?}"), name);
204        }
205    }
206
207    #[test]
208    fn test_sound_type() {
209        let cases = [
210            (0x00, SoundType::Mono, "SoundType::Mono"),
211            (0x01, SoundType::Stereo, "SoundType::Stereo"),
212        ];
213
214        for (value, expected, name) in cases {
215            let sound_type = SoundType::from(value);
216            assert_eq!(sound_type, expected);
217            assert_eq!(format!("{sound_type:?}"), name);
218        }
219    }
220}