use crate::error::Error; use crate::FlvReader; use std::io::Seek; #[repr(u8)] #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum SoundFormat { LinearPCMPlatformEndian = 0, Adpcm = 1, MP3 = 2, LinearPCMLittleEndian = 3, Nellymoser16kHz = 4, Nellymoser8kHz = 5, Nellymoser = 6, G711ALawPCM = 7, G711MuLawPCM = 8, Aac = 10, Speex = 11, MP38kHz = 14, DeviceSpecific = 15, } impl TryFrom for SoundFormat { type Error = Error; fn try_from(value: u8) -> Result { match value { 0 => Ok(Self::LinearPCMPlatformEndian), 1 => Ok(Self::Adpcm), 2 => Ok(Self::MP3), 3 => Ok(Self::LinearPCMLittleEndian), 4 => Ok(Self::Nellymoser16kHz), 5 => Ok(Self::Nellymoser8kHz), 6 => Ok(Self::Nellymoser), 7 => Ok(Self::G711ALawPCM), 8 => Ok(Self::G711MuLawPCM), 10 => Ok(Self::Aac), 11 => Ok(Self::Speex), 14 => Ok(Self::MP38kHz), 15 => Ok(Self::DeviceSpecific), unk => Err(Error::UnknownAudioFormatType(unk)), } } } #[repr(u8)] #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum SoundRate { R5_500 = 0, R11_000 = 1, R22_000 = 2, R44_000 = 3, } impl TryFrom for SoundRate { type Error = Error; fn try_from(value: u8) -> Result { match value { 0 => Ok(Self::R5_500), 1 => Ok(Self::R11_000), 2 => Ok(Self::R22_000), 3 => Ok(Self::R44_000), unk => Err(Error::UnknownAudioRate(unk)), //probably unreachable } } } #[repr(u8)] #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum SoundSize { Bits8 = 0, Bits16 = 1, } impl TryFrom for SoundSize { type Error = Error; fn try_from(value: u8) -> Result { match value { 0 => Ok(Self::Bits8), 1 => Ok(Self::Bits16), unk => Err(Error::UnknownAudioSampleSize(unk)), //probably unreachable } } } #[repr(u8)] #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub enum SoundType { Mono = 0, Stereo = 1, } impl TryFrom for SoundType { type Error = Error; fn try_from(value: u8) -> Result { match value { 0 => Ok(Self::Mono), 1 => Ok(Self::Stereo), unk => Err(Error::UnknownAudioChannelCount(unk)), //probably unreachable } } } #[derive(PartialEq, Eq, Debug, Clone)] pub enum AudioDataType<'a> { Raw(&'a [u8]), AacSequenceHeader(&'a [u8]), AacRaw(&'a [u8]), } #[derive(PartialEq, Eq, Debug, Clone)] pub struct AudioData<'a> { pub format: SoundFormat, pub rate: SoundRate, pub size: SoundSize, pub sound_type: SoundType, pub data: AudioDataType<'a>, } impl<'a> AudioData<'a> { /// Parse an audio data structure. /// /// This does not parse the actual audio data itself, which is instead /// returned as an array that must be provided to your audio decoder. /// /// `data_size` is the size of the entire audio data structure, *including* /// the header. Errors are yielded if the `data_size` is too small for the /// audio data present in the tag. This should not be confused for /// `EndOfData` which indicates that we've read past the end of the whole /// data stream. pub fn parse(reader: &mut FlvReader<'a>, data_size: u32) -> Result { let start = reader.stream_position().expect("current position") as usize; let format_spec = reader.read_u8()?; let format = SoundFormat::try_from(format_spec >> 4)?; let rate = SoundRate::try_from((format_spec >> 2) & 0x03)?; let size = SoundSize::try_from((format_spec >> 1) & 0x01)?; let sound_type = SoundType::try_from(format_spec & 0x01)?; let header_size = reader.stream_position().expect("current position") as usize - start; if (data_size as usize) < header_size { return Err(Error::ShortAudioBlock); } let data = reader.read(data_size as usize - header_size)?; let data = match format { SoundFormat::Aac => { let aac_packet_type = data.first().ok_or(Error::ShortAudioBlock)?; match aac_packet_type { //TODO: The FLV spec says this is explained in ISO 14496-3. 0 => AudioDataType::AacSequenceHeader(&data[1..]), 1 => AudioDataType::AacRaw(&data[1..]), unk => return Err(Error::UnknownAacPacketType(*unk)), } } _ => AudioDataType::Raw(data), }; Ok(AudioData { format, rate, size, sound_type, data, }) } } #[cfg(test)] mod tests { use crate::error::Error; use crate::reader::FlvReader; use crate::sound::{AudioData, AudioDataType, SoundFormat, SoundRate, SoundSize, SoundType}; #[test] fn read_audiodata() { let data = [0xBF, 0x12, 0x34, 0x56, 0x78]; let mut reader = FlvReader::from_source(&data); assert_eq!( AudioData::parse(&mut reader, data.len() as u32), Ok(AudioData { format: SoundFormat::Speex, rate: SoundRate::R44_000, size: SoundSize::Bits16, sound_type: SoundType::Stereo, data: AudioDataType::Raw(&[0x12, 0x34, 0x56, 0x78]) }) ); } #[test] fn read_audiodata_invalid_len() { let data = [0xBF, 0x12, 0x34, 0x56, 0x78]; let mut reader = FlvReader::from_source(&data); assert_eq!( AudioData::parse(&mut reader, 0), Err(Error::ShortAudioBlock) ); } #[test] fn read_audiodata_short_len() { let data = [0xBF, 0x12, 0x34, 0x56, 0x78]; let mut reader = FlvReader::from_source(&data); assert_eq!( AudioData::parse(&mut reader, 2), Ok(AudioData { format: SoundFormat::Speex, rate: SoundRate::R44_000, size: SoundSize::Bits16, sound_type: SoundType::Stereo, data: AudioDataType::Raw(&[0x12]) }) ); } #[test] fn read_audiodata_aac() { let data = [0xAD, 0x01, 0x12, 0x34, 0x56, 0x78]; let mut reader = FlvReader::from_source(&data); assert_eq!( AudioData::parse(&mut reader, data.len() as u32), Ok(AudioData { format: SoundFormat::Aac, rate: SoundRate::R44_000, size: SoundSize::Bits8, sound_type: SoundType::Stereo, data: AudioDataType::AacRaw(&[0x12, 0x34, 0x56, 0x78]) }) ); } #[test] fn read_audiodata_aac_invalid() { let data = [0xAD, 0x02, 0x12, 0x34, 0x56, 0x78]; let mut reader = FlvReader::from_source(&data); assert_eq!( AudioData::parse(&mut reader, data.len() as u32), Err(Error::UnknownAacPacketType(2)) ); } }