active_call/media/
loader.rs1use crate::media::cache;
2use anyhow::{Result, anyhow};
3use audio_codec::Resampler;
4use hound::WavReader;
5use reqwest::Client;
6use std::fs::File;
7use std::io::{BufReader, Read, Seek, SeekFrom, Write};
8use std::time::Instant;
9use tracing::{info, warn};
10use url::Url;
11
12pub async fn download_from_url(url: &str, use_cache: bool) -> Result<File> {
13 let cache_key = cache::generate_cache_key(url, 0, None, None);
15 if use_cache && cache::is_cached(&cache_key).await? {
16 match cache::get_cache_path(&cache_key) {
17 Ok(path) => return File::open(&path).map_err(|e| anyhow!(e)),
18 Err(e) => {
19 warn!("loader: Error getting cache path: {}", e);
20 return Err(e);
21 }
22 }
23 }
24
25 let start_time = Instant::now();
27 let client = Client::new();
28 let response = client.get(url).send().await?;
29 let bytes = response.bytes().await?;
30 let data = bytes.to_vec();
31 let duration = start_time.elapsed();
32
33 info!(
34 "loader: Downloaded {} bytes in {:?} for {}",
35 data.len(),
36 duration,
37 url,
38 );
39
40 if use_cache {
42 cache::store_in_cache(&cache_key, &data).await?;
43 match cache::get_cache_path(&cache_key) {
44 Ok(path) => return File::open(path).map_err(|e| anyhow!(e)),
45 Err(e) => {
46 warn!("loader: Error getting cache path: {}", e);
47 return Err(e);
48 }
49 }
50 }
51
52 let mut temp_file = tempfile::tempfile()?;
54 temp_file.write_all(&data)?;
55 temp_file.seek(SeekFrom::Start(0))?;
56 Ok(temp_file)
57}
58
59pub fn decode_wav(file: File, target_sample_rate: u32) -> Result<Vec<i16>> {
60 let reader = BufReader::new(file);
61 let mut wav_reader = WavReader::new(reader)?;
62 let spec = wav_reader.spec();
63 let sample_rate = spec.sample_rate;
64 let is_stereo = spec.channels == 2;
65
66 info!(
67 "WAV file detected with sample rate: {} Hz, channels: {}, bits: {}",
68 sample_rate, spec.channels, spec.bits_per_sample
69 );
70
71 let mut all_samples = Vec::new();
72
73 match spec.sample_format {
75 hound::SampleFormat::Int => match spec.bits_per_sample {
76 16 => {
77 for sample in wav_reader.samples::<i16>() {
78 if let Ok(s) = sample {
79 all_samples.push(s);
80 } else {
81 break;
82 }
83 }
84 }
85 8 => {
86 for sample in wav_reader.samples::<i8>() {
87 if let Ok(s) = sample {
88 all_samples.push((s as i16) * 256); } else {
90 break;
91 }
92 }
93 }
94 24 | 32 => {
95 for sample in wav_reader.samples::<i32>() {
96 if let Ok(s) = sample {
97 all_samples.push((s >> 16) as i16); } else {
99 break;
100 }
101 }
102 }
103 _ => {
104 return Err(anyhow!(
105 "Unsupported bits per sample: {}",
106 spec.bits_per_sample
107 ));
108 }
109 },
110 hound::SampleFormat::Float => {
111 for sample in wav_reader.samples::<f32>() {
112 if let Ok(s) = sample {
113 all_samples.push((s * 32767.0) as i16); } else {
115 break;
116 }
117 }
118 }
119 }
120
121 if is_stereo {
123 let mono_samples = all_samples
124 .chunks(2)
125 .map(|chunk| {
126 if chunk.len() == 2 {
127 ((chunk[0] as i32 + chunk[1] as i32) / 2) as i16
128 } else {
129 chunk[0]
130 }
131 })
132 .collect();
133 all_samples = mono_samples;
134 }
135
136 if sample_rate != target_sample_rate && sample_rate > 0 {
137 let mut resampler = Resampler::new(sample_rate as usize, target_sample_rate as usize);
138 all_samples = resampler.resample(&all_samples);
139 }
140
141 Ok(all_samples)
142}
143
144pub fn decode_mp3(file: File, target_sample_rate: u32) -> Result<Vec<i16>> {
145 let mut reader = BufReader::new(file);
146 let mut file_data = Vec::new();
147 reader.read_to_end(&mut file_data)?;
148
149 let mut decoder = rmp3::Decoder::new(&file_data);
150 let mut all_samples = Vec::new();
151 let mut sample_rate = 0;
152
153 while let Some(frame) = decoder.next() {
154 match frame {
155 rmp3::Frame::Audio(audio) => {
156 if sample_rate == 0 {
157 sample_rate = audio.sample_rate();
158 info!("MP3 file detected with sample rate: {} Hz", sample_rate);
159 }
160 all_samples.extend_from_slice(audio.samples());
161 }
162 rmp3::Frame::Other(_) => {}
163 }
164 }
165
166 if sample_rate != target_sample_rate && sample_rate > 0 {
167 let mut resampler = Resampler::new(sample_rate as usize, target_sample_rate as usize);
168 all_samples = resampler.resample(&all_samples);
169 }
170
171 Ok(all_samples)
172}
173
174pub async fn load_audio_as_pcm(
175 path: &str,
176 target_sample_rate: u32,
177 use_cache: bool,
178) -> Result<Vec<i16>> {
179 let extension = if path.starts_with("http://") || path.starts_with("https://") {
180 path.parse::<Url>()?
181 .path()
182 .split(".")
183 .last()
184 .unwrap_or("")
185 .to_string()
186 } else {
187 path.split('.').last().unwrap_or("").to_string()
188 };
189
190 let file = if path.starts_with("http://") || path.starts_with("https://") {
191 download_from_url(path, use_cache).await?
192 } else {
193 File::open(path).map_err(|e| anyhow!("loader: {} {}", path, e))?
194 };
195
196 match extension.to_lowercase().as_str() {
197 "wav" => decode_wav(file, target_sample_rate),
198 "mp3" => decode_mp3(file, target_sample_rate),
199 _ => Err(anyhow!("loader: Unsupported file extension: {}", extension)),
200 }
201}