1
0
Fork 0
mirror of https://github.com/librespot-org/librespot.git synced 2025-10-04 10:19:27 +02:00

Add command-line option to set F32 or S16 bit output

Usage: `--format {F32|S16}`. Default is F32.

 - Implemented for all backends, except for JACK audio which itself
 only supports 32-bit output at this time. Setting JACK audio to S16
 will panic and instruct the user to set output to F32.

 - The F32 default works fine for Rodio on macOS, but not on Raspian 10
 with Alsa as host. Therefore users on Linux systems are warned to set
 output to S16 in case of garbled sound with Rodio. This seems an issue
 with cpal incorrectly detecting the output stream format.

 - While at it, DRY up lots of code in the backends and by that virtue,
 also enable OggData passthrough on the subprocess backend.

 - I tested Rodio, ALSA, pipe and subprocess quite a bit, and call on
 others to join in and test the other backends.
This commit is contained in:
Roderick van Domburg 2021-03-12 23:05:38 +01:00
parent 1672eb87ab
commit 5257be7824
15 changed files with 504 additions and 314 deletions

View file

@ -1,46 +1,39 @@
use super::{Open, Sink};
use super::{Open, Sink, SinkAsBytes};
use crate::audio::AudioPacket;
use crate::config::AudioFormat;
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::mem;
use std::slice;
pub struct StdoutSink(Box<dyn Write>);
pub struct StdoutSink {
output: Box<dyn Write>,
format: AudioFormat,
}
impl Open for StdoutSink {
fn open(path: Option<String>) -> StdoutSink {
if let Some(path) = path {
let file = OpenOptions::new().write(true).open(path).unwrap();
StdoutSink(Box::new(file))
} else {
StdoutSink(Box::new(io::stdout()))
fn open(path: Option<String>, format: AudioFormat) -> StdoutSink {
info!("Using pipe sink with format: {:?}", format);
let output: Box<dyn Write> = match path {
Some(path) => Box::new(OpenOptions::new().write(true).open(path).unwrap()),
_ => Box::new(io::stdout()),
};
StdoutSink {
output: output,
format: format,
}
}
}
impl Sink for StdoutSink {
fn start(&mut self) -> io::Result<()> {
Ok(())
}
fn stop(&mut self) -> io::Result<()> {
Ok(())
}
fn write(&mut self, packet: &AudioPacket) -> io::Result<()> {
let data: &[u8] = match packet {
AudioPacket::Samples(data) => unsafe {
slice::from_raw_parts(
data.as_ptr() as *const u8,
data.len() * mem::size_of::<f32>(),
)
},
AudioPacket::OggData(data) => data,
};
self.0.write_all(data)?;
self.0.flush()?;
start_stop_noop!();
sink_as_bytes!();
}
impl SinkAsBytes for StdoutSink {
fn write_bytes(&mut self, data: &[u8]) -> io::Result<()> {
self.output.write_all(data)?;
self.output.flush()?;
Ok(())
}
}