use anyhow::Result;
use std::path::Path;
#[allow(dead_code)]
pub struct AudioData {
pub data: String, pub filename: String,
pub mime_type: String,
}
pub fn process_audio_file(file_path: &Path) -> Result<String> {
let audio_bytes = std::fs::read(file_path)?;
use base64::{engine::general_purpose, Engine as _};
let base64_data = general_purpose::STANDARD.encode(&audio_bytes);
let extension = file_path
.extension()
.and_then(|ext| ext.to_str())
.unwrap_or("")
.to_lowercase();
let mime_type = match extension.as_str() {
"mp3" => "audio/mpeg",
"wav" => "audio/wav",
"flac" => "audio/flac",
"ogg" => "audio/ogg",
"m4a" | "mp4" => "audio/mp4",
"webm" => "audio/webm",
_ => "audio/wav", };
Ok(format!("data:{};base64,{}", mime_type, base64_data))
}
pub fn process_audio_url(url: &str) -> Result<String> {
Ok(url.to_string())
}
pub fn generate_wav_header(
data_size: u32,
sample_rate: u32,
channels: u16,
bits_per_sample: u16,
) -> Vec<u8> {
let mut header = Vec::with_capacity(44);
header.extend_from_slice(b"RIFF");
let file_size = 36 + data_size;
header.extend_from_slice(&file_size.to_le_bytes());
header.extend_from_slice(b"WAVE");
header.extend_from_slice(b"fmt ");
header.extend_from_slice(&16u32.to_le_bytes());
header.extend_from_slice(&1u16.to_le_bytes());
header.extend_from_slice(&channels.to_le_bytes());
header.extend_from_slice(&sample_rate.to_le_bytes());
let byte_rate = sample_rate * channels as u32 * bits_per_sample as u32 / 8;
header.extend_from_slice(&byte_rate.to_le_bytes());
let block_align = channels * bits_per_sample / 8;
header.extend_from_slice(&block_align.to_le_bytes());
header.extend_from_slice(&bits_per_sample.to_le_bytes());
header.extend_from_slice(b"data");
header.extend_from_slice(&data_size.to_le_bytes());
header
}
pub fn pcm_to_wav(
pcm_data: &[u8],
sample_rate: Option<u32>,
channels: Option<u16>,
bits_per_sample: Option<u16>,
) -> Vec<u8> {
let sample_rate = sample_rate.unwrap_or(24000); let channels = channels.unwrap_or(1); let bits_per_sample = bits_per_sample.unwrap_or(16);
let data_size = pcm_data.len() as u32;
let header = generate_wav_header(data_size, sample_rate, channels, bits_per_sample);
let mut wav_data = Vec::with_capacity(header.len() + pcm_data.len());
wav_data.extend_from_slice(&header);
wav_data.extend_from_slice(pcm_data);
wav_data
}
pub fn is_likely_pcm(data: &[u8]) -> bool {
if data.len() < 4 {
return false;
}
let header = &data[0..4];
if header == b"RIFF" {
return false;
}
if header[0..3] == [0x49, 0x44, 0x33] || (header[0] == 0xFF && (header[1] & 0xE0) == 0xE0)
{
return false;
}
if header == b"fLaC" {
return false;
}
if header == b"OggS" {
return false;
}
true
}
pub fn get_audio_file_extension(data: &[u8], requested_format: Option<&str>) -> &'static str {
if let Some(format) = requested_format {
return match format.to_lowercase().as_str() {
"mp3" => "mp3",
"wav" => "wav",
"flac" => "flac",
"ogg" => "ogg",
"aac" => "aac",
"opus" => "opus",
"pcm" => "wav", _ => "wav", };
}
if is_likely_pcm(data) {
"wav" } else {
if data.len() >= 4 {
let header = &data[0..4];
if header == b"RIFF" {
"wav"
} else if header[0..3] == [0x49, 0x44, 0x33]
|| (header[0] == 0xFF && (header[1] & 0xE0) == 0xE0)
{
"mp3"
} else if header == b"fLaC" {
"flac"
} else if header == b"OggS" {
"ogg"
} else {
"wav" }
} else {
"wav" }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wav_header_generation() {
let header = generate_wav_header(1000, 44100, 2, 16);
assert_eq!(header.len(), 44);
assert_eq!(&header[0..4], b"RIFF");
assert_eq!(&header[8..12], b"WAVE");
assert_eq!(&header[12..16], b"fmt ");
}
#[test]
fn test_pcm_to_wav_conversion() {
let pcm_data = vec![0u8; 1000]; let wav_data = pcm_to_wav(&pcm_data, Some(44100), Some(2), Some(16));
assert_eq!(wav_data.len(), 44 + 1000);
assert_eq!(&wav_data[0..4], b"RIFF");
assert_eq!(&wav_data[8..12], b"WAVE");
}
#[test]
fn test_pcm_detection() {
let wav_header = b"RIFF\x24\x08\x00\x00WAVE";
assert!(!is_likely_pcm(wav_header));
let pcm_data = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC];
assert!(is_likely_pcm(&pcm_data));
}
#[test]
fn test_file_extension_detection() {
let pcm_data = vec![0x12, 0x34, 0x56, 0x78];
assert_eq!(get_audio_file_extension(&pcm_data, None), "wav");
let wav_data = b"RIFF\x24\x08\x00\x00WAVE";
assert_eq!(get_audio_file_extension(wav_data, None), "wav");
assert_eq!(get_audio_file_extension(&pcm_data, Some("mp3")), "mp3");
assert_eq!(get_audio_file_extension(&pcm_data, Some("pcm")), "wav");
}
}