Fix --device argument to various backends (#938)

Fix `--device` argument to various backends
This commit is contained in:
Roderick van Domburg 2022-01-14 08:20:29 +01:00 committed by GitHub
parent a605444d18
commit 1e54913523
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 57 deletions

View file

@ -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 - [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). - [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] `Sink`: `write()` now receives ownership of the packet (breaking).
- [playback] `pipe`: create file if it doesn't already exist
### Added ### Added
- [cache] Add `disable-credential-cache` flag (breaking). - [cache] Add `disable-credential-cache` flag (breaking).

View file

@ -4,19 +4,27 @@ use crate::convert::Converter;
use crate::decoder::AudioPacket; use crate::decoder::AudioPacket;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::{self, Write}; use std::io::{self, Write};
use std::process::exit;
pub struct StdoutSink { pub struct StdoutSink {
output: Option<Box<dyn Write>>, output: Option<Box<dyn Write>>,
path: Option<String>, file: Option<String>,
format: AudioFormat, format: AudioFormat,
} }
impl Open for StdoutSink { impl Open for StdoutSink {
fn open(path: Option<String>, format: AudioFormat) -> Self { fn open(file: Option<String>, 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); info!("Using pipe sink with format: {:?}", format);
Self { Self {
output: None, output: None,
path, file,
format, format,
} }
} }
@ -25,11 +33,12 @@ impl Open for StdoutSink {
impl Sink for StdoutSink { impl Sink for StdoutSink {
fn start(&mut self) -> SinkResult<()> { fn start(&mut self) -> SinkResult<()> {
if self.output.is_none() { if self.output.is_none() {
let output: Box<dyn Write> = match self.path.as_deref() { let output: Box<dyn Write> = match self.file.as_deref() {
Some(path) => { Some(file) => {
let open_op = OpenOptions::new() let open_op = OpenOptions::new()
.write(true) .write(true)
.open(path) .create(true)
.open(file)
.map_err(|e| SinkError::ConnectionRefused(e.to_string()))?; .map_err(|e| SinkError::ConnectionRefused(e.to_string()))?;
Box::new(open_op) Box::new(open_op)
} }

View file

@ -135,21 +135,18 @@ fn create_sink(
host: &cpal::Host, host: &cpal::Host,
device: Option<String>, device: Option<String>,
) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> { ) -> Result<(rodio::Sink, rodio::OutputStream), RodioError> {
let rodio_device = match device { let rodio_device = match device.as_deref() {
Some(ask) if &ask == "?" => { Some("?") => match list_outputs(host) {
let exit_code = match list_outputs(host) { Ok(()) => exit(0),
Ok(()) => 0, Err(e) => {
Err(e) => { error!("{}", e);
error!("{}", e); exit(1);
1 }
} },
};
exit(exit_code)
}
Some(device_name) => { Some(device_name) => {
host.output_devices()? host.output_devices()?
.find(|d| d.name().ok().map_or(false, |name| name == device_name)) // Ignore devices for which getting name fails .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 None => host
.default_output_device() .default_output_device()

View file

@ -5,7 +5,7 @@ use crate::decoder::AudioPacket;
use shell_words::split; use shell_words::split;
use std::io::Write; use std::io::Write;
use std::process::{Child, Command, Stdio}; use std::process::{exit, Child, Command, Stdio};
pub struct SubprocessSink { pub struct SubprocessSink {
shell_command: String, shell_command: String,
@ -15,16 +15,24 @@ pub struct SubprocessSink {
impl Open for SubprocessSink { impl Open for SubprocessSink {
fn open(shell_command: Option<String>, format: AudioFormat) -> Self { fn open(shell_command: Option<String>, 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); info!("Using subprocess sink with format: {:?}", format);
if let Some(shell_command) = shell_command { Self {
SubprocessSink { shell_command,
shell_command, child: None,
child: None, format,
format,
}
} else {
panic!("subprocess sink requires specifying a shell command");
} }
} }
} }

View file

@ -748,18 +748,7 @@ fn get_setup() -> Setup {
}) })
.unwrap_or_default(); .unwrap_or_default();
#[cfg(any(
feature = "alsa-backend",
feature = "rodio-backend",
feature = "portaudio-backend"
))]
let device = opt_str(DEVICE); let device = opt_str(DEVICE);
#[cfg(any(
feature = "alsa-backend",
feature = "rodio-backend",
feature = "portaudio-backend"
))]
if let Some(ref value) = device { if let Some(ref value) = device {
if value == "?" { if value == "?" {
backend(device, format); 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<String> = 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")] #[cfg(feature = "alsa-backend")]
let mixer_type = opt_str(MIXER_TYPE); let mixer_type = opt_str(MIXER_TYPE);
#[cfg(not(feature = "alsa-backend"))] #[cfg(not(feature = "alsa-backend"))]