use async_trait::async_trait;
use bytes::Bytes;
use tokio::sync::mpsc;
use crate::error::Result;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pcm {
pub samples: Bytes,
pub rate: u32,
pub channels: u16,
}
impl Pcm {
pub fn frames(&self) -> usize {
self.samples.len() / (2 * self.channels.max(1) as usize)
}
pub fn duration_secs(&self) -> f64 {
self.frames() as f64 / self.rate.max(1) as f64
}
}
pub struct PcmChunks {
pub rate: u32,
pub channels: u16,
pub chunks: mpsc::Receiver<Result<Bytes>>,
}
#[async_trait]
pub trait TtsSynthesizer: Send + Sync + 'static {
fn name(&self) -> &'static str;
fn model(&self) -> String;
fn supports(&self, lang: &str) -> bool;
fn pace_range(&self) -> (f32, f32) {
(1.0, 1.0)
}
async fn synthesize(&self, text: &str, lang: &str, voice: &str, pace: f32, sample_rate: u32) -> Result<Pcm>;
fn streams(&self) -> bool {
false
}
async fn synthesize_streaming(&self, text: &str, lang: &str, voice: &str, pace: f32, sample_rate: u32) -> Result<PcmChunks> {
let pcm = self.synthesize(text, lang, voice, pace, sample_rate).await?;
let (tx, rx) = mpsc::channel(1);
if !pcm.samples.is_empty() {
let _ = tx.try_send(Ok(pcm.samples));
}
Ok(PcmChunks { rate: pcm.rate, channels: pcm.channels, chunks: rx })
}
}