-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaudio_decoder.rs
More file actions
120 lines (103 loc) · 4.62 KB
/
audio_decoder.rs
File metadata and controls
120 lines (103 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Shared audio decoding functionality
// Audio decoding error types
#[derive(Debug, thiserror::Error)]
pub enum AudioError {
#[error("Audio file not found: {0}")]
FileNotFound(String),
#[error("Audio decode error: {0}")]
DecodeError(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}
// Decode audio file (OGG/MP3) to PCM data
pub async fn decode_audio_file(filename: &str) -> Result<(Vec<u8>, u32, u16), AudioError> {
let file_data = tokio::fs::read(filename).await
.map_err(|_| AudioError::FileNotFound(filename.to_string()))?;
// Use symphonia for OGG files
use symphonia::core::audio::{AudioBufferRef, Signal};
use symphonia::core::codecs::DecoderOptions;
use symphonia::core::formats::FormatOptions;
use symphonia::core::io::MediaSourceStream;
use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::Hint;
let file_data_owned = file_data.to_vec();
let cursor = std::io::Cursor::new(file_data_owned);
let mss = MediaSourceStream::new(Box::new(cursor), Default::default());
let hint = Hint::new();
let meta_opts = MetadataOptions::default();
let fmt_opts = FormatOptions::default();
let probed = symphonia::default::get_probe()
.format(&hint, mss, &fmt_opts, &meta_opts)
.map_err(|e| AudioError::DecodeError(format!("Format probe failed: {:?}", e)))?;
let mut format = probed.format;
let track = format
.tracks()
.iter()
.find(|t| t.codec_params.codec != symphonia::core::codecs::CODEC_TYPE_NULL)
.ok_or_else(|| AudioError::DecodeError("No supported audio tracks found".to_string()))?;
let dec_opts = DecoderOptions::default();
let mut decoder = symphonia::default::get_codecs()
.make(&track.codec_params, &dec_opts)
.map_err(|e| AudioError::DecodeError(format!("Decoder creation failed: {:?}", e)))?;
let track_id = track.id;
let mut pcm_data = Vec::new();
let mut sample_rate = 44100;
let mut channels = 2;
// Decode with proper stereo interleaving
loop {
let packet = match format.next_packet() {
Ok(packet) => packet,
Err(symphonia::core::errors::Error::IoError(e)) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
break;
}
Err(e) => {
return Err(AudioError::DecodeError(format!("Packet read error: {:?}", e)));
}
};
if packet.track_id() != track_id {
continue;
}
match decoder.decode(&packet) {
Ok(decoded) => {
sample_rate = decoded.spec().rate;
channels = decoded.spec().channels.count() as u16;
// Proper stereo interleaving: [L,R,L,R,L,R...]
match decoded {
AudioBufferRef::F32(buf) => {
let channels_count = buf.spec().channels.count();
let frames = buf.frames();
for frame_idx in 0..frames {
for ch in 0..channels_count {
let sample = buf.chan(ch)[frame_idx];
let sample_i16 = (sample * 32767.0).clamp(-32767.0, 32767.0) as i16;
pcm_data.extend_from_slice(&sample_i16.to_le_bytes());
}
}
}
AudioBufferRef::S16(buf) => {
let channels_count = buf.spec().channels.count();
let frames = buf.frames();
for frame_idx in 0..frames {
for ch in 0..channels_count {
let sample = buf.chan(ch)[frame_idx];
pcm_data.extend_from_slice(&sample.to_le_bytes());
}
}
}
_ => {
return Err(AudioError::DecodeError("Unsupported audio format".to_string()));
}
}
}
Err(symphonia::core::errors::Error::IoError(_)) => break,
Err(symphonia::core::errors::Error::DecodeError(_)) => continue,
Err(e) => {
return Err(AudioError::DecodeError(format!("Decode error: {:?}", e)));
}
}
}
if pcm_data.is_empty() {
return Err(AudioError::DecodeError("No audio data decoded".to_string()));
}
Ok((pcm_data, sample_rate, channels))
}