mirror of
https://github.com/librespot-org/librespot.git
synced 2025-01-07 17:24:04 +00:00
8d70fd910e
* Make error messages more consistent and concise. * `impl From<AlsaError> for io::Error` so `AlsaErrors` can be thrown to player as `io::Errors`. This little bit of boilerplate goes a long way to simplifying things further down in the code. And will make any needed future changes easier. * Bonus: handle ALSA backend buffer sizing a little better.
79 lines
2.2 KiB
Rust
79 lines
2.2 KiB
Rust
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
|
|
use crate::config::AudioFormat;
|
|
use crate::convert::Converter;
|
|
use crate::decoder::AudioPacket;
|
|
use shell_words::split;
|
|
|
|
use std::io::Write;
|
|
use std::process::{Child, Command, Stdio};
|
|
|
|
pub struct SubprocessSink {
|
|
shell_command: String,
|
|
child: Option<Child>,
|
|
format: AudioFormat,
|
|
}
|
|
|
|
impl Open for SubprocessSink {
|
|
fn open(shell_command: Option<String>, format: AudioFormat) -> Self {
|
|
info!("Using subprocess sink with format: {:?}", format);
|
|
|
|
if let Some(shell_command) = shell_command {
|
|
SubprocessSink {
|
|
shell_command,
|
|
child: None,
|
|
format,
|
|
}
|
|
} else {
|
|
panic!("subprocess sink requires specifying a shell command");
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Sink for SubprocessSink {
|
|
fn start(&mut self) -> SinkResult<()> {
|
|
let args = split(&self.shell_command).unwrap();
|
|
let child = Command::new(&args[0])
|
|
.args(&args[1..])
|
|
.stdin(Stdio::piped())
|
|
.spawn()
|
|
.map_err(|e| SinkError::ConnectionRefused(e.to_string()))?;
|
|
self.child = Some(child);
|
|
Ok(())
|
|
}
|
|
|
|
fn stop(&mut self) -> SinkResult<()> {
|
|
if let Some(child) = &mut self.child.take() {
|
|
child
|
|
.kill()
|
|
.map_err(|e| SinkError::OnWrite(e.to_string()))?;
|
|
child
|
|
.wait()
|
|
.map_err(|e| SinkError::OnWrite(e.to_string()))?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
sink_as_bytes!();
|
|
}
|
|
|
|
impl SinkAsBytes for SubprocessSink {
|
|
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
|
|
if let Some(child) = &mut self.child {
|
|
let child_stdin = child
|
|
.stdin
|
|
.as_mut()
|
|
.ok_or_else(|| SinkError::NotConnected("Child is None".to_string()))?;
|
|
child_stdin
|
|
.write_all(data)
|
|
.map_err(|e| SinkError::OnWrite(e.to_string()))?;
|
|
child_stdin
|
|
.flush()
|
|
.map_err(|e| SinkError::OnWrite(e.to_string()))?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl SubprocessSink {
|
|
pub const NAME: &'static str = "subprocess";
|
|
}
|