ffmpeg subprocess creation, remove byte handled checking
This commit is contained in:
parent
5aa12757a0
commit
58d33b8868
7 changed files with 56 additions and 23 deletions
|
@ -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<DecoderContext, Error> {
|
||||
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<u8>) -> Result<(), Error> {
|
||||
self.encoded_in.write_all(chunk.as_slice())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<PlayerEvent>,
|
||||
sample_in: Sender<Vec<u8>>,
|
||||
pw_signal_in: pipewire::channel::Sender<Vec<u8>>,
|
||||
decoder_context: DecoderContext,
|
||||
playing: bool,
|
||||
}
|
||||
|
||||
pub fn init(
|
||||
|
|
|
@ -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) => (),
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ pub enum PlayerEvent {
|
|||
UserQuit,
|
||||
PlayNext,
|
||||
AddAudioChunk(Vec<u8>),
|
||||
AudioChunkQueued(u32),
|
||||
}
|
||||
|
||||
pub struct Player {
|
||||
|
|
|
@ -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<u8>) -> 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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<dyn std::error::Error + Send + Sync>;
|
||||
|
||||
|
|
Loading…
Reference in a new issue