use super::media::MediaData;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioData {
pub base64_data: String,
pub format: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub sample_rate: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub channels: Option<u8>,
}
impl MediaData for AudioData {
fn base64_data(&self) -> &str {
&self.base64_data
}
fn format_id(&self) -> &str {
&self.format
}
fn mime_type(&self) -> String {
match self.format.as_str() {
"wav" => "audio/wav",
"mp3" => "audio/mpeg",
"ogg" => "audio/ogg",
"flac" => "audio/flac",
"webm" => "audio/webm",
"m4a" | "aac" => "audio/aac",
_ => "audio/wav",
}
.to_string()
}
fn from_base64(base64_data: impl Into<String>, format: impl Into<String>) -> Self {
Self {
base64_data: base64_data.into(),
format: format.into(),
sample_rate: None,
channels: None,
}
}
fn guess_format(path: &Path) -> String {
path.extension()
.and_then(|e| e.to_str())
.unwrap_or("wav")
.to_lowercase()
}
}
impl AudioData {
pub fn from_base64(base64_data: impl Into<String>, format: impl Into<String>) -> Self {
<Self as MediaData>::from_base64(base64_data, format)
}
pub fn from_bytes(bytes: &[u8], format: impl Into<String>) -> Self {
<Self as MediaData>::from_bytes(bytes, format)
}
pub fn from_file(path: impl AsRef<Path>) -> crate::error::Result<Self> {
<Self as MediaData>::from_file(path)
}
pub async fn from_file_async(path: impl AsRef<Path> + Send) -> crate::error::Result<Self> {
<Self as MediaData>::from_file_async(path).await
}
pub fn from_url(url: impl Into<String>) -> Self {
Self {
base64_data: url.into(),
format: "url".to_string(),
sample_rate: None,
channels: None,
}
}
pub fn to_data_url(&self) -> String {
if self.format == "url" {
self.base64_data.clone()
} else {
format!("data:{};base64,{}", self.mime_type(), self.base64_data)
}
}
pub fn with_sample_rate(mut self, rate: u32) -> Self {
self.sample_rate = Some(rate);
self
}
pub fn with_channels(mut self, channels: u8) -> Self {
self.channels = Some(channels);
self
}
pub fn to_bytes(&self) -> crate::error::Result<Vec<u8>> {
Ok(BASE64.decode(&self.base64_data)?)
}
pub fn mime_type(&self) -> String {
<Self as MediaData>::mime_type(self)
}
}