diff --git a/CHANGELOG.md b/CHANGELOG.md index a2be0992..0bd19240 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [contrib] Hardened security of the systemd service units - [main] Verbose logging mode (`-v`, `--verbose`) now logs all parsed environment variables and command line arguments (credentials are redacted). - [playback] `Sink`: `write()` now receives ownership of the packet (breaking). +- [playback] `pipe`: create file if it doesn't already exist ### Added - [cache] Add `disable-credential-cache` flag (breaking). diff --git a/playback/src/audio_backend/pipe.rs b/playback/src/audio_backend/pipe.rs index fd804a0e..682f8124 100644 --- a/playback/src/audio_backend/pipe.rs +++ b/playback/src/audio_backend/pipe.rs @@ -4,19 +4,27 @@ use crate::convert::Converter; use crate::decoder::AudioPacket; use std::fs::OpenOptions; use std::io::{self, Write}; +use std::process::exit; pub struct StdoutSink { output: Option>, - path: Option, + file: Option, format: AudioFormat, } impl Open for StdoutSink { - fn open(path: Option, format: AudioFormat) -> Self { + fn open(file: Option, format: AudioFormat) -> Self { + if let Some("?") = file.as_deref() { + info!("Usage:"); + println!(" Output to stdout: --backend pipe"); + println!(" Output to file: --backend pipe --device {{filename}}"); + exit(0); + } + info!("Using pipe sink with format: {:?}", format); Self { output: None, - path, + file, format, } } @@ -25,11 +33,12 @@ impl Open for StdoutSink { impl Sink for StdoutSink { fn start(&mut self) -> SinkResult<()> { if self.output.is_none() { - let output: Box = match self.path.as_deref() { - Some(path) => { + let output: Box = match self.file.as_deref() { + Some(file) => { let open_op = OpenOptions::new() .write(true) - .open(path) + .create(true) + .open(file) .map_err(|e| SinkError::ConnectionRefused(e.to_string()))?; Box::new(open_op) } diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 9f4ad059..bbc5de1a 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -135,21 +135,18 @@ fn create_sink( host: &cpal::Host, device: Option, ) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> { - let rodio_device = match device { - Some(ask) if &ask == "?" => { - let exit_code = match list_outputs(host) { - Ok(()) => 0, - Err(e) => { - error!("{}", e); - 1 - } - }; - exit(exit_code) - } + let rodio_device = match device.as_deref() { + Some("?") => match list_outputs(host) { + Ok(()) => exit(0), + Err(e) => { + error!("{}", e); + exit(1); + } + }, Some(device_name) => { host.output_devices()? .find(|d| d.name().ok().map_or(false, |name| name == device_name)) // Ignore devices for which getting name fails - .ok_or(RodioError::DeviceNotAvailable(device_name))? + .ok_or_else(|| RodioError::DeviceNotAvailable(device_name.to_string()))? } None => host .default_output_device() diff --git a/playback/src/audio_backend/subprocess.rs b/playback/src/audio_backend/subprocess.rs index c501cf83..63fc5d88 100644 --- a/playback/src/audio_backend/subprocess.rs +++ b/playback/src/audio_backend/subprocess.rs @@ -5,7 +5,7 @@ use crate::decoder::AudioPacket; use shell_words::split; use std::io::Write; -use std::process::{Child, Command, Stdio}; +use std::process::{exit, Child, Command, Stdio}; pub struct SubprocessSink { shell_command: String, @@ -15,16 +15,24 @@ pub struct SubprocessSink { impl Open for SubprocessSink { fn open(shell_command: Option, format: AudioFormat) -> Self { + let shell_command = match shell_command.as_deref() { + Some("?") => { + info!("Usage: --backend subprocess --device {{shell_command}}"); + exit(0); + } + Some(cmd) => cmd.to_owned(), + None => { + error!("subprocess sink requires specifying a shell command"); + exit(1); + } + }; + 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"); + Self { + shell_command, + child: None, + format, } } } diff --git a/src/main.rs b/src/main.rs index 6eb9d84d..9bef5184 100644 --- a/src/main.rs +++ b/src/main.rs @@ -748,18 +748,7 @@ fn get_setup() -> Setup { }) .unwrap_or_default(); - #[cfg(any( - feature = "alsa-backend", - feature = "rodio-backend", - feature = "portaudio-backend" - ))] let device = opt_str(DEVICE); - - #[cfg(any( - feature = "alsa-backend", - feature = "rodio-backend", - feature = "portaudio-backend" - ))] if let Some(ref value) = device { if value == "?" { backend(device, format); @@ -769,25 +758,6 @@ fn get_setup() -> Setup { } } - #[cfg(not(any( - feature = "alsa-backend", - feature = "rodio-backend", - feature = "portaudio-backend" - )))] - let device: Option = None; - - #[cfg(not(any( - feature = "alsa-backend", - feature = "rodio-backend", - feature = "portaudio-backend" - )))] - if opt_present(DEVICE) { - warn!( - "The `--{}` / `-{}` option is not supported by the included audio backend(s), and has no effect.", - DEVICE, DEVICE_SHORT, - ); - } - #[cfg(feature = "alsa-backend")] let mixer_type = opt_str(MIXER_TYPE); #[cfg(not(feature = "alsa-backend"))]