From b8617f54a97f6660d8259332c3c51247953d4639 Mon Sep 17 00:00:00 2001 From: misuzu Date: Fri, 24 Jan 2020 02:35:24 +0200 Subject: [PATCH] Added subprocess audio backend --- Cargo.lock | 7 +++ playback/Cargo.toml | 1 + playback/src/audio_backend/mod.rs | 4 ++ playback/src/audio_backend/subprocess.rs | 59 ++++++++++++++++++++++++ playback/src/lib.rs | 1 + 5 files changed, 72 insertions(+) create mode 100644 playback/src/audio_backend/subprocess.rs diff --git a/Cargo.lock b/Cargo.lock index 594b80c8..f5d6cfe8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -908,6 +908,7 @@ dependencies = [ "portaudio-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rodio 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", + "shell-words 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1725,6 +1726,11 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "shell-words" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "signal-hook" version = "0.1.10" @@ -2540,6 +2546,7 @@ dependencies = [ "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum shannon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ea5b41c9427b56caa7b808cb548a04fb50bb5b9e98590b53f28064ff4174561" +"checksum shell-words 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39acde55a154c4cd3ae048ac78cc21c25f3a0145e44111b523279113dce0d94a" "checksum signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4f61c4d59f3aaa9f61bba6450a9b80ba48362fd7d651689e7a10c453b1f6dc68" "checksum signal-hook-registry 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "913661ac8848a61e39684a3c3e7a7a14a4deec7f54b4976d0641e70dda3939b1" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" diff --git a/playback/Cargo.toml b/playback/Cargo.toml index f414d5ec..e3aa8879 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -20,6 +20,7 @@ version = "0.1.0" futures = "0.1" log = "0.4" byteorder = "1.3" +shell-words = "0.1.0" alsa = { version = "0.2.1", optional = true } portaudio-rs = { version = "0.3.0", optional = true } diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index 441252c6..d385e61d 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -46,6 +46,9 @@ use self::sdl::SdlSink; mod pipe; use self::pipe::StdoutSink; +mod subprocess; +use self::subprocess::SubprocessSink; + pub const BACKENDS: &'static [(&'static str, fn(Option) -> Box)] = &[ #[cfg(feature = "alsa-backend")] ("alsa", mk_sink::), @@ -60,6 +63,7 @@ pub const BACKENDS: &'static [(&'static str, fn(Option) -> Box #[cfg(feature = "sdl-backend")] ("sdl", mk_sink::), ("pipe", mk_sink::), + ("subprocess", mk_sink::), ]; pub fn find(name: Option) -> Option) -> Box> { diff --git a/playback/src/audio_backend/subprocess.rs b/playback/src/audio_backend/subprocess.rs new file mode 100644 index 00000000..2af88360 --- /dev/null +++ b/playback/src/audio_backend/subprocess.rs @@ -0,0 +1,59 @@ +use super::{Open, Sink}; +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, +} + +impl Open for SubprocessSink { + fn open(shell_command: Option) -> 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(()) + } + + fn write(&mut self, data: &[i16]) -> io::Result<()> { + let data: &[u8] = unsafe { + slice::from_raw_parts( + data.as_ptr() as *const u8, + data.len() * mem::size_of::(), + ) + }; + if let Some(child) = &mut self.child { + let child_stdin = child.stdin.as_mut().unwrap(); + child_stdin.write_all(data)?; + } + Ok(()) + } +} diff --git a/playback/src/lib.rs b/playback/src/lib.rs index aeb0407f..fe00aaab 100644 --- a/playback/src/lib.rs +++ b/playback/src/lib.rs @@ -3,6 +3,7 @@ extern crate log; extern crate byteorder; extern crate futures; +extern crate shell_words; #[cfg(feature = "alsa-backend")] extern crate alsa;