Merge branch 'dev' into new-api

This commit is contained in:
Roderick van Domburg 2022-01-04 01:13:48 +01:00
commit 8dbcda6bc2
No known key found for this signature in database
GPG key ID: FE2585E713F9F30A
8 changed files with 61 additions and 51 deletions

View file

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [playback] `alsa`: Improve `--device ?` functionality for the alsa backend. - [playback] `alsa`: Improve `--device ?` functionality for the alsa backend.
- [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).
### Added ### Added
- [cache] Add `disable-credential-cache` flag (breaking). - [cache] Add `disable-credential-cache` flag (breaking).

View file

@ -62,8 +62,8 @@ enum AlsaError {
#[error("<AlsaSink> PCM, {0}")] #[error("<AlsaSink> PCM, {0}")]
Pcm(alsa::Error), Pcm(alsa::Error),
#[error("<AlsaSink> Could Not Parse Ouput Name(s) and/or Description(s)")] #[error("<AlsaSink> Could Not Parse Output Name(s) and/or Description(s), {0}")]
Parsing, Parsing(alsa::Error),
#[error("<AlsaSink>")] #[error("<AlsaSink>")]
NotConnected, NotConnected,
@ -107,49 +107,58 @@ pub struct AlsaSink {
} }
fn list_compatible_devices() -> SinkResult<()> { fn list_compatible_devices() -> SinkResult<()> {
let i = HintIter::new_str(None, "pcm").map_err(AlsaError::Parsing)?;
println!("\n\n\tCompatible alsa device(s):\n"); println!("\n\n\tCompatible alsa device(s):\n");
println!("\t------------------------------------------------------\n"); println!("\t------------------------------------------------------\n");
let i = HintIter::new_str(None, "pcm").map_err(|_| AlsaError::Parsing)?;
for a in i { for a in i {
if let Some(Direction::Playback) = a.direction { if let Some(Direction::Playback) = a.direction {
let name = a.name.ok_or(AlsaError::Parsing)?; if let Some(name) = a.name {
let desc = a.desc.ok_or(AlsaError::Parsing)?; if let Ok(pcm) = PCM::new(&name, Direction::Playback, false) {
if let Ok(hwp) = HwParams::any(&pcm) {
// Only show devices that support
// 2 ch 44.1 Interleaved.
if let Ok(pcm) = PCM::new(&name, Direction::Playback, false) { if hwp.set_access(Access::RWInterleaved).is_ok()
if let Ok(hwp) = HwParams::any(&pcm) { && hwp.set_rate(SAMPLE_RATE, ValueOr::Nearest).is_ok()
// Only show devices that support && hwp.set_channels(NUM_CHANNELS as u32).is_ok()
// 2 ch 44.1 Interleaved. {
if hwp.set_access(Access::RWInterleaved).is_ok() let mut supported_formats = vec![];
&& hwp.set_rate(SAMPLE_RATE, ValueOr::Nearest).is_ok()
&& hwp.set_channels(NUM_CHANNELS as u32).is_ok()
{
println!("\tDevice:\n\n\t\t{}\n", name);
println!("\tDescription:\n\n\t\t{}\n", desc.replace("\n", "\n\t\t"));
let mut supported_formats = vec![]; for f in &[
AudioFormat::S16,
AudioFormat::S24,
AudioFormat::S24_3,
AudioFormat::S32,
AudioFormat::F32,
AudioFormat::F64,
] {
if hwp.test_format(Format::from(*f)).is_ok() {
supported_formats.push(format!("{:?}", f));
}
}
for f in &[ if !supported_formats.is_empty() {
AudioFormat::S16, println!("\tDevice:\n\n\t\t{}\n", name);
AudioFormat::S24,
AudioFormat::S24_3, println!(
AudioFormat::S32, "\tDescription:\n\n\t\t{}\n",
AudioFormat::F32, a.desc.unwrap_or_default().replace("\n", "\n\t\t")
AudioFormat::F64, );
] {
if hwp.test_format(Format::from(*f)).is_ok() { println!(
supported_formats.push(format!("{:?}", f)); "\tSupported Format(s):\n\n\t\t{}\n",
supported_formats.join(" ")
);
println!(
"\t------------------------------------------------------\n"
);
} }
} }
};
println!( }
"\tSupported Format(s):\n\n\t\t{}\n",
supported_formats.join(" ")
);
println!("\t------------------------------------------------------\n");
}
};
} }
} }
} }

View file

@ -66,7 +66,7 @@ impl Open for JackSink {
} }
impl Sink for JackSink { impl Sink for JackSink {
fn write(&mut self, packet: &AudioPacket, converter: &mut Converter) -> SinkResult<()> { fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
let samples = packet let samples = packet
.samples() .samples()
.map_err(|e| SinkError::OnWrite(e.to_string()))?; .map_err(|e| SinkError::OnWrite(e.to_string()))?;

View file

@ -28,7 +28,7 @@ pub trait Sink {
fn stop(&mut self) -> SinkResult<()> { fn stop(&mut self) -> SinkResult<()> {
Ok(()) Ok(())
} }
fn write(&mut self, packet: &AudioPacket, converter: &mut Converter) -> SinkResult<()>; fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()>;
} }
pub type SinkBuilder = fn(Option<String>, AudioFormat) -> Box<dyn Sink>; pub type SinkBuilder = fn(Option<String>, AudioFormat) -> Box<dyn Sink>;
@ -44,34 +44,34 @@ fn mk_sink<S: Sink + Open + 'static>(device: Option<String>, format: AudioFormat
// reuse code for various backends // reuse code for various backends
macro_rules! sink_as_bytes { macro_rules! sink_as_bytes {
() => { () => {
fn write(&mut self, packet: &AudioPacket, converter: &mut Converter) -> SinkResult<()> { fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
use crate::convert::i24; use crate::convert::i24;
use zerocopy::AsBytes; use zerocopy::AsBytes;
match packet { match packet {
AudioPacket::Samples(samples) => match self.format { AudioPacket::Samples(samples) => match self.format {
AudioFormat::F64 => self.write_bytes(samples.as_bytes()), AudioFormat::F64 => self.write_bytes(samples.as_bytes()),
AudioFormat::F32 => { AudioFormat::F32 => {
let samples_f32: &[f32] = &converter.f64_to_f32(samples); let samples_f32: &[f32] = &converter.f64_to_f32(&samples);
self.write_bytes(samples_f32.as_bytes()) self.write_bytes(samples_f32.as_bytes())
} }
AudioFormat::S32 => { AudioFormat::S32 => {
let samples_s32: &[i32] = &converter.f64_to_s32(samples); let samples_s32: &[i32] = &converter.f64_to_s32(&samples);
self.write_bytes(samples_s32.as_bytes()) self.write_bytes(samples_s32.as_bytes())
} }
AudioFormat::S24 => { AudioFormat::S24 => {
let samples_s24: &[i32] = &converter.f64_to_s24(samples); let samples_s24: &[i32] = &converter.f64_to_s24(&samples);
self.write_bytes(samples_s24.as_bytes()) self.write_bytes(samples_s24.as_bytes())
} }
AudioFormat::S24_3 => { AudioFormat::S24_3 => {
let samples_s24_3: &[i24] = &converter.f64_to_s24_3(samples); let samples_s24_3: &[i24] = &converter.f64_to_s24_3(&samples);
self.write_bytes(samples_s24_3.as_bytes()) self.write_bytes(samples_s24_3.as_bytes())
} }
AudioFormat::S16 => { AudioFormat::S16 => {
let samples_s16: &[i16] = &converter.f64_to_s16(samples); let samples_s16: &[i16] = &converter.f64_to_s16(&samples);
self.write_bytes(samples_s16.as_bytes()) self.write_bytes(samples_s16.as_bytes())
} }
}, },
AudioPacket::Raw(samples) => self.write_bytes(samples), AudioPacket::Raw(samples) => self.write_bytes(&samples),
} }
} }
}; };

View file

@ -140,7 +140,7 @@ impl<'a> Sink for PortAudioSink<'a> {
Ok(()) Ok(())
} }
fn write(&mut self, packet: &AudioPacket, converter: &mut Converter) -> SinkResult<()> { fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
macro_rules! write_sink { macro_rules! write_sink {
(ref mut $stream: expr, $samples: expr) => { (ref mut $stream: expr, $samples: expr) => {
$stream.as_mut().unwrap().write($samples) $stream.as_mut().unwrap().write($samples)
@ -153,15 +153,15 @@ impl<'a> Sink for PortAudioSink<'a> {
let result = match self { let result = match self {
Self::F32(stream, _parameters) => { Self::F32(stream, _parameters) => {
let samples_f32: &[f32] = &converter.f64_to_f32(samples); let samples_f32: &[f32] = &converter.f64_to_f32(&samples);
write_sink!(ref mut stream, samples_f32) write_sink!(ref mut stream, samples_f32)
} }
Self::S32(stream, _parameters) => { Self::S32(stream, _parameters) => {
let samples_s32: &[i32] = &converter.f64_to_s32(samples); let samples_s32: &[i32] = &converter.f64_to_s32(&samples);
write_sink!(ref mut stream, samples_s32) write_sink!(ref mut stream, samples_s32)
} }
Self::S16(stream, _parameters) => { Self::S16(stream, _parameters) => {
let samples_s16: &[i16] = &converter.f64_to_s16(samples); let samples_s16: &[i16] = &converter.f64_to_s16(&samples);
write_sink!(ref mut stream, samples_s16) write_sink!(ref mut stream, samples_s16)
} }
}; };

View file

@ -189,7 +189,7 @@ pub fn open(host: cpal::Host, device: Option<String>, format: AudioFormat) -> Ro
} }
impl Sink for RodioSink { impl Sink for RodioSink {
fn write(&mut self, packet: &AudioPacket, converter: &mut Converter) -> SinkResult<()> { fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
let samples = packet let samples = packet
.samples() .samples()
.map_err(|e| RodioError::Samples(e.to_string()))?; .map_err(|e| RodioError::Samples(e.to_string()))?;

View file

@ -82,7 +82,7 @@ impl Sink for SdlSink {
Ok(()) Ok(())
} }
fn write(&mut self, packet: &AudioPacket, converter: &mut Converter) -> SinkResult<()> { fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()> {
macro_rules! drain_sink { macro_rules! drain_sink {
($queue: expr, $size: expr) => {{ ($queue: expr, $size: expr) => {{
// sleep and wait for sdl thread to drain the queue a bit // sleep and wait for sdl thread to drain the queue a bit

View file

@ -1477,7 +1477,7 @@ impl PlayerInternal {
} }
} }
if let Err(e) = self.sink.write(&packet, &mut self.converter) { if let Err(e) = self.sink.write(packet, &mut self.converter) {
error!("{}", e); error!("{}", e);
exit(1); exit(1);
} }