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;
|
use crate::utils::Error;
|
||||||
|
|
||||||
pub fn init() -> Result<(), Error> {
|
pub struct DecoderContext {
|
||||||
unimplemented!()
|
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 std::sync::mpsc::Receiver;
|
||||||
|
|
||||||
use pipewire::spa::pod::Pod;
|
use codec::DecoderContext;
|
||||||
|
|
||||||
use crate::{config::Settings, player::PlayerEvent, utils::Error};
|
use crate::{config::Settings, player::PlayerEvent, utils::Error};
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@ pub struct SoundManager {
|
||||||
player_chan: Sender<PlayerEvent>,
|
player_chan: Sender<PlayerEvent>,
|
||||||
sample_in: Sender<Vec<u8>>,
|
sample_in: Sender<Vec<u8>>,
|
||||||
pw_signal_in: pipewire::channel::Sender<Vec<u8>>,
|
pw_signal_in: pipewire::channel::Sender<Vec<u8>>,
|
||||||
|
decoder_context: DecoderContext,
|
||||||
|
playing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
sync::{
|
sync::{
|
||||||
mpsc::{channel, Receiver, Sender},
|
mpsc::{channel, Receiver, Sender, TryRecvError},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
thread,
|
thread,
|
||||||
|
@ -31,6 +31,7 @@ impl SoundManager {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
let decoder_context = codec::init()?;
|
let decoder_context = codec::init()?;
|
||||||
|
|
||||||
Ok(SoundManager {
|
Ok(SoundManager {
|
||||||
settings,
|
settings,
|
||||||
error_chan,
|
error_chan,
|
||||||
|
@ -38,14 +39,26 @@ impl SoundManager {
|
||||||
player_chan,
|
player_chan,
|
||||||
sample_in,
|
sample_in,
|
||||||
pw_signal_in,
|
pw_signal_in,
|
||||||
|
decoder_context,
|
||||||
|
playing: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn begin(&mut self) -> Result<(), Error> {
|
pub fn begin(&mut self) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
match self.audio_controls.recv()? {
|
self.handle_events()?;
|
||||||
AudioEvent::DecodeChunk(chunk) => (),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 cover: DynamicImage,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
pub bytes_received: u32,
|
pub bytes_received: u32,
|
||||||
pub bytes_handled: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Metadata {
|
impl Metadata {
|
||||||
|
@ -27,7 +26,6 @@ impl Metadata {
|
||||||
cover: default_cover(),
|
cover: default_cover(),
|
||||||
size: 0,
|
size: 0,
|
||||||
bytes_received: 0,
|
bytes_received: 0,
|
||||||
bytes_handled: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub enum PlayerEvent {
|
||||||
UserQuit,
|
UserQuit,
|
||||||
PlayNext,
|
PlayNext,
|
||||||
AddAudioChunk(Vec<u8>),
|
AddAudioChunk(Vec<u8>),
|
||||||
|
AudioChunkQueued(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
|
|
|
@ -46,6 +46,7 @@ impl Player {
|
||||||
PlayerEvent::PlayNext => self.play_next()?,
|
PlayerEvent::PlayNext => self.play_next()?,
|
||||||
PlayerEvent::UpdateCover(cover) => self.tui_root.update_cover(cover),
|
PlayerEvent::UpdateCover(cover) => self.tui_root.update_cover(cover),
|
||||||
PlayerEvent::AddAudioChunk(chunk) => self.recv_chunk(chunk)?,
|
PlayerEvent::AddAudioChunk(chunk) => self.recv_chunk(chunk)?,
|
||||||
|
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,19 +101,8 @@ impl Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv_chunk(&mut self, chunk: Vec<u8>) -> Result<(), Error> {
|
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.tui_root.metadata.bytes_received += chunk.len() as u32;
|
||||||
self.audio_chan.send(AudioEvent::DecodeChunk(chunk))?;
|
self.audio_chan.send(AudioEvent::DecodeChunk(chunk))?;
|
||||||
if self.tui_root.metadata.bytes_pending() {
|
|
||||||
self.fetch_audio_chunk()?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::io::Cursor;
|
|
||||||
|
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
use pipewire::spa::{
|
use pipewire::spa::{
|
||||||
param::audio::AudioInfoRaw,
|
param::audio::AudioInfoRaw,
|
||||||
|
@ -7,6 +5,7 @@ use pipewire::spa::{
|
||||||
sys::{SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format},
|
sys::{SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format},
|
||||||
};
|
};
|
||||||
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
use rand::{distributions::Alphanumeric, thread_rng, Rng};
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue