use crate::types::{AudioCodec, AudioTag, ErrorCode, Result};
pub fn parse(data: &[u8], tag: &mut AudioTag) -> Result<()> {
if data.is_empty() {
return Err(ErrorCode::Internal);
}
tag.codec = match (data[0] >> 4) & 0x0F {
0 => AudioCodec::Pcm,
1 => AudioCodec::Adpcm,
2 => AudioCodec::Mp3,
3 => AudioCodec::PcmLe,
4 => AudioCodec::Nelly16k,
5 => AudioCodec::Nelly8k,
6 => AudioCodec::Nelly,
7 => AudioCodec::G711A,
8 => AudioCodec::G711U,
10 => AudioCodec::Aac,
11 => AudioCodec::Speex,
14 => AudioCodec::Opus,
_ => AudioCodec::Aac,
};
tag.sample_rate = (data[0] >> 2) & 0x03;
tag.bit_depth = (data[0] >> 1) & 0x01;
tag.channels = data[0] & 0x01;
if tag.codec == AudioCodec::Aac && data.len() >= 2 {
tag.aac_packet_type = data[1];
}
tag.data = data.as_ptr();
tag.size = data.len();
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::AudioTag;
#[test]
fn parse_aac_sets_codec_and_packet_type() {
let payload = [0xAF, 0x00];
let mut tag = AudioTag::default();
parse(&payload, &mut tag).unwrap();
assert_eq!(tag.codec, AudioCodec::Aac);
assert_eq!(tag.aac_packet_type, 0);
}
#[test]
fn parse_mp3_codec_nibble() {
let payload = [0x2F];
let mut tag = AudioTag::default();
parse(&payload, &mut tag).unwrap();
assert_eq!(tag.codec, AudioCodec::Mp3);
}
#[test]
fn parse_extracts_sample_rate_channels() {
let payload = [0xAF, 0x01];
let mut tag = AudioTag::default();
parse(&payload, &mut tag).unwrap();
assert_eq!(tag.sample_rate, 3);
assert_eq!(tag.bit_depth, 1);
assert_eq!(tag.channels, 1);
}
#[test]
fn parse_rejects_empty_payload() {
let mut tag = AudioTag::default();
assert_eq!(parse(&[], &mut tag), Err(ErrorCode::Internal));
}
}