use crate::audio::{player::AudioPlayerControls, utils::extract_audio};
use crate::common::errors::MyError;
use rodio;
use std::io::{BufReader, Cursor, Read, Seek};
pub struct RodioAudioPlayer {
player: rodio::Sink,
_stream: rodio::OutputStream,
content: Vec<u8>,
}
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 = BufReader::new(file);
let mut content = Vec::new();
buf.by_ref().read_to_end(&mut content)?;
buf.rewind()?;
let player: rodio::Sink = stream_handle
.play_once(buf)
.map_err(|err| MyError::Audio(format!("Failed to start playback: {:?}", err)))?;
Ok(Self {
player,
_stream,
content,
})
}
}
impl AudioPlayerControls for RodioAudioPlayer {
fn pause(&mut self) -> Result<(), MyError> {
self.player.pause();
Ok(())
}
fn resume(&mut self) -> Result<(), MyError> {
self.player.play();
Ok(())
}
fn rewind(&mut self) -> Result<(), MyError> {
self.player.clear();
let input = Cursor::new(self.content.clone());
let input = rodio::decoder::Decoder::new(input).map_err(|err| {
MyError::Audio(format!(
"Could not set decoder on rewind content: {:?}",
err
))
})?;
self.player.append(input);
self.player.play();
Ok(())
}
fn toggle_play(&mut self) -> Result<(), MyError> {
if self.player.is_paused() {
self.resume()
} else {
self.pause()
}
}
fn mute(&mut self) -> Result<(), MyError> {
self.player.set_volume(0.0);
Ok(())
}
fn unmute(&mut self) -> Result<(), MyError> {
self.player.set_volume(1.0);
Ok(())
}
fn toggle_mute(&mut self) -> Result<(), MyError> {
if self.player.volume() == 0.0 {
self.unmute()
} else {
self.mute()
}
}
fn stop(&mut self) -> Result<(), MyError> {
self.player.stop();
Ok(())
}
}