diff --git a/src/audio/codec.rs b/src/audio/codec.rs index 2cd1ff1..f31e5a0 100644 --- a/src/audio/codec.rs +++ b/src/audio/codec.rs @@ -1,5 +1,35 @@ +use std::{ + io::{Read, Write}, + process::{Child, ChildStdin, ChildStdout, Command, Stdio}, +}; + use crate::utils::Error; -pub fn init() -> Result<(), Error> { - unimplemented!() +pub struct DecoderContext { + process: Child, + encoded_in: ChildStdin, + frames_out: ChildStdout, +} + +pub fn init() -> Result { + let mut decoder = Command::new("ffmpeg") + .args(["-hide_banner", "-i", "-", "-f", "s16le", "-"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn()?; + let encoded_in = decoder.stdin.take().unwrap(); + let frames_out = decoder.stdout.take().unwrap(); + Ok(DecoderContext { + process: decoder, + encoded_in, + frames_out, + }) +} + +impl DecoderContext { + pub fn append_chunk(&mut self, chunk: Vec) -> Result<(), Error> { + self.encoded_in.write_all(chunk.as_slice())?; + Ok(()) + } } diff --git a/src/audio/mod.rs b/src/audio/mod.rs index d5814cf..e933d69 100644 --- a/src/audio/mod.rs +++ b/src/audio/mod.rs @@ -8,7 +8,7 @@ use std::{ use std::sync::mpsc::Receiver; -use pipewire::spa::pod::Pod; +use codec::DecoderContext; use crate::{config::Settings, player::PlayerEvent, utils::Error}; @@ -23,6 +23,8 @@ pub struct SoundManager { player_chan: Sender, sample_in: Sender>, pw_signal_in: pipewire::channel::Sender>, + decoder_context: DecoderContext, + playing: bool, } pub fn init( diff --git a/src/audio/sound_mgr.rs b/src/audio/sound_mgr.rs index 4fe86ba..9f831c0 100644 --- a/src/audio/sound_mgr.rs +++ b/src/audio/sound_mgr.rs @@ -1,6 +1,6 @@ use std::{ sync::{ - mpsc::{channel, Receiver, Sender}, + mpsc::{channel, Receiver, Sender, TryRecvError}, Arc, }, thread, @@ -31,6 +31,7 @@ impl SoundManager { }; }); let decoder_context = codec::init()?; + Ok(SoundManager { settings, error_chan, @@ -38,14 +39,26 @@ impl SoundManager { player_chan, sample_in, pw_signal_in, + decoder_context, + playing: true, }) } pub fn begin(&mut self) -> Result<(), Error> { loop { - match self.audio_controls.recv()? { - AudioEvent::DecodeChunk(chunk) => (), - _ => unimplemented!(), - } + self.handle_events()?; } } + + fn handle_events(&mut self) -> Result<(), Error> { + let event = match self.audio_controls.try_recv() { + Err(err) if err == TryRecvError::Empty => return Ok(()), + Ok(e) => e, + Err(err) => return Err(Box::new(err)), + }; + match event { + AudioEvent::DecodeChunk(chunk) => self.decoder_context.append_chunk(chunk)?, + _ => unimplemented!(), + } + Ok(()) + } } diff --git a/src/player/current.rs b/src/player/current.rs index 2850e2e..5e0e193 100644 --- a/src/player/current.rs +++ b/src/player/current.rs @@ -12,7 +12,6 @@ pub struct Metadata { pub cover: DynamicImage, pub size: u32, pub bytes_received: u32, - pub bytes_handled: u32, } impl Metadata { @@ -27,7 +26,6 @@ impl Metadata { cover: default_cover(), size: 0, bytes_received: 0, - bytes_handled: 0, } } diff --git a/src/player/mod.rs b/src/player/mod.rs index b9ae20f..7a7d3a1 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -24,6 +24,7 @@ pub enum PlayerEvent { UserQuit, PlayNext, AddAudioChunk(Vec), + AudioChunkQueued(u32), } pub struct Player { diff --git a/src/player/player.rs b/src/player/player.rs index 1f40985..6fb2888 100644 --- a/src/player/player.rs +++ b/src/player/player.rs @@ -46,6 +46,7 @@ impl Player { PlayerEvent::PlayNext => self.play_next()?, PlayerEvent::UpdateCover(cover) => self.tui_root.update_cover(cover), PlayerEvent::AddAudioChunk(chunk) => self.recv_chunk(chunk)?, + _ => unimplemented!(), } } @@ -100,19 +101,8 @@ impl Player { } fn recv_chunk(&mut self, chunk: Vec) -> Result<(), Error> { - if self.tui_root.metadata.bytes_received - self.tui_root.metadata.bytes_handled - > AUDIO_FILE_BUFFER - { - // requeue the new chunk since we don't need it decoded just yet. Mostly for massive hr+ files - self.player_chan_in - .send(PlayerEvent::AddAudioChunk(chunk))?; - return Ok(()); - } self.tui_root.metadata.bytes_received += chunk.len() as u32; self.audio_chan.send(AudioEvent::DecodeChunk(chunk))?; - if self.tui_root.metadata.bytes_pending() { - self.fetch_audio_chunk()?; - } Ok(()) } } diff --git a/src/utils.rs b/src/utils.rs index 831b56a..90cc172 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,3 @@ -use std::io::Cursor; - use image::DynamicImage; use pipewire::spa::{ param::audio::AudioInfoRaw, @@ -7,6 +5,7 @@ use pipewire::spa::{ sys::{SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format}, }; use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use std::io::Cursor; pub type Error = Box;