use crate::audio::player::AudioPlayerControls;
use crate::audio::utils::extract_audio;
use crate::common::errors::MyError;
use rodio;
use std::io::{Cursor, Read};
use std::time::Duration;
pub struct RodioAudioPlayer {
sink: rodio::Sink,
_stream: rodio::OutputStream,
#[allow(dead_code)]
stream_handle: rodio::OutputStreamHandle,
content: Vec<u8>,
volume: f32,
current_speed: f64,
}
impl RodioAudioPlayer {
pub(crate) fn new(input_path: &str) -> Result<Self, MyError> {
let (_stream, stream_handle) = rodio::OutputStream::try_default().map_err(|err| {
MyError::Audio(format!("Failed to initialize audio stream: {:?}", err))
})?;
let audio_track = extract_audio(input_path)?;
let file = std::fs::File::open(audio_track.path())
.map_err(|err| MyError::Audio(format!("Failed to open audio file: {:?}", err)))?;
let mut buf = std::io::BufReader::new(file);
let mut content = Vec::new();
buf.read_to_end(&mut content)?;
let sink = rodio::Sink::try_new(&stream_handle).map_err(|err| {
MyError::Audio(format!("Failed to create audio sink: {:?}", err))
})?;
let cursor = Cursor::new(content.clone());
let decoder = rodio::decoder::Decoder::new(cursor).map_err(|err| {
MyError::Audio(format!("Failed to decode audio: {:?}", err))
})?;
sink.append(decoder);
sink.pause();
Ok(Self {
sink,
_stream,
stream_handle,
content,
volume: 1.0,
current_speed: 1.0,
})
}
fn rebuild_at_position(&mut self, target_position: Duration) -> Result<(), MyError> {
let was_paused = self.sink.is_paused();
self.sink.clear();
let cursor = Cursor::new(self.content.clone());
let decoder = rodio::decoder::Decoder::new(cursor).map_err(|err| {
MyError::Audio(format!("Failed to decode audio for rebuild: {:?}", err))
})?;
self.sink.append(decoder);
let _ = self.sink.try_seek(target_position);
self.sink.set_volume(self.volume);
if was_paused {
self.sink.pause();
} else {
self.sink.play();
}
Ok(())
}
}
impl AudioPlayerControls for RodioAudioPlayer {
fn pause(&mut self) -> Result<(), MyError> {
self.sink.pause();
Ok(())
}
fn resume(&mut self) -> Result<(), MyError> {
self.sink.play();
Ok(())
}
fn rewind(&mut self) -> Result<(), MyError> {
self.rebuild_at_position(Duration::ZERO)
}
fn toggle_play(&mut self) -> Result<(), MyError> {
if self.sink.is_paused() {
self.resume()
} else {
self.pause()
}
}
fn mute(&mut self) -> Result<(), MyError> {
self.sink.set_volume(0.0);
Ok(())
}
fn unmute(&mut self) -> Result<(), MyError> {
self.sink.set_volume(self.volume);
Ok(())
}
fn toggle_mute(&mut self) -> Result<(), MyError> {
if self.sink.volume() == 0.0 {
self.unmute()
} else {
self.mute()
}
}
fn stop(&mut self) -> Result<(), MyError> {
self.sink.stop();
Ok(())
}
fn seek(&mut self, seconds: f64) -> Result<(), MyError> {
let current_pos = self.sink.get_pos();
let target_secs = (current_pos.as_secs_f64() + seconds).max(0.0);
let target_duration = Duration::from_secs_f64(target_secs);
self.rebuild_at_position(target_duration)
}
fn cycle_subtitle(&mut self) -> Result<(), MyError> {
Ok(())
}
fn toggle_subtitle(&mut self) -> Result<(), MyError> {
Ok(())
}
fn get_subtitle_text(&self) -> Option<String> {
None
}
fn get_position(&self) -> Duration {
self.sink.get_pos()
}
fn set_speed(&mut self, speed: f64) -> Result<(), MyError> {
let clamped_speed = speed.clamp(0.5, 2.0);
self.sink.set_speed(clamped_speed as f32);
self.current_speed = clamped_speed;
Ok(())
}
fn get_speed(&self) -> f64 {
self.current_speed
}
}