2020-01-24 00:35:24 +00:00
|
|
|
use super::{Open, Sink};
|
2021-01-07 06:42:38 +00:00
|
|
|
use crate::audio::AudioPacket;
|
2020-01-24 00:35:24 +00:00
|
|
|
use shell_words::split;
|
|
|
|
use std::io::{self, Write};
|
|
|
|
use std::mem;
|
|
|
|
use std::process::{Child, Command, Stdio};
|
|
|
|
use std::slice;
|
|
|
|
|
|
|
|
pub struct SubprocessSink {
|
|
|
|
shell_command: String,
|
|
|
|
child: Option<Child>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Open for SubprocessSink {
|
|
|
|
fn open(shell_command: Option<String>) -> SubprocessSink {
|
|
|
|
if let Some(shell_command) = shell_command {
|
|
|
|
SubprocessSink {
|
|
|
|
shell_command: shell_command,
|
|
|
|
child: None,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
panic!("subprocess sink requires specifying a shell command");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sink for SubprocessSink {
|
|
|
|
fn start(&mut self) -> io::Result<()> {
|
|
|
|
let args = split(&self.shell_command).unwrap();
|
|
|
|
self.child = Some(
|
|
|
|
Command::new(&args[0])
|
|
|
|
.args(&args[1..])
|
|
|
|
.stdin(Stdio::piped())
|
|
|
|
.spawn()?,
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn stop(&mut self) -> io::Result<()> {
|
|
|
|
if let Some(child) = &mut self.child.take() {
|
|
|
|
child.kill()?;
|
|
|
|
child.wait()?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-07 06:42:38 +00:00
|
|
|
fn write(&mut self, packet: &AudioPacket) -> io::Result<()> {
|
2020-01-24 00:35:24 +00:00
|
|
|
let data: &[u8] = unsafe {
|
|
|
|
slice::from_raw_parts(
|
2021-01-07 06:42:38 +00:00
|
|
|
packet.samples().as_ptr() as *const u8,
|
2021-02-24 20:39:42 +00:00
|
|
|
packet.samples().len() * mem::size_of::<f32>(),
|
2020-01-24 00:35:24 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
if let Some(child) = &mut self.child {
|
|
|
|
let child_stdin = child.stdin.as_mut().unwrap();
|
|
|
|
child_stdin.write_all(data)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|