Skip to content

Commit e1ea400

Browse files
committed
Change the backends so that they support the diffrent sample rates
1 parent 3bcf549 commit e1ea400

10 files changed

Lines changed: 391 additions & 401 deletions

File tree

playback/src/audio_backend/alsa.rs

Lines changed: 299 additions & 324 deletions
Large diffs are not rendered by default.

playback/src/audio_backend/gstreamer.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::sync::Arc;
1414
use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
1515

1616
use crate::{
17-
config::AudioFormat, convert::Converter, decoder::AudioPacket, NUM_CHANNELS, SAMPLE_RATE,
17+
config::AudioFormat, convert::Converter, decoder::AudioPacket, NUM_CHANNELS,
1818
};
1919

2020
pub struct GstreamerSink {
@@ -26,8 +26,8 @@ pub struct GstreamerSink {
2626
}
2727

2828
impl Open for GstreamerSink {
29-
fn open(device: Option<String>, format: AudioFormat) -> Self {
30-
info!("Using GStreamer sink with format: {format:?}");
29+
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
30+
info!("Using GStreamer sink with format: {format:?}, sample rate: {sample_rate}");
3131
gst::init().expect("failed to init GStreamer!");
3232

3333
let gst_format = match format {
@@ -39,7 +39,7 @@ impl Open for GstreamerSink {
3939
AudioFormat::S16 => gst_audio::AUDIO_FORMAT_S16,
4040
};
4141

42-
let gst_info = gst_audio::AudioInfo::builder(gst_format, SAMPLE_RATE, NUM_CHANNELS as u32)
42+
let gst_info = gst_audio::AudioInfo::builder(gst_format, sample_rate, NUM_CHANNELS as u32)
4343
.build()
4444
.expect("Failed to create GStreamer audio format");
4545
let gst_caps = gst_info.to_caps().expect("Failed to create GStreamer caps");

playback/src/audio_backend/jackaudio.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ impl ProcessHandler for JackData {
3838
}
3939

4040
impl Open for JackSink {
41-
fn open(client_name: Option<String>, format: AudioFormat) -> Self {
41+
fn open(client_name: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
4242
if format != AudioFormat::F32 {
4343
warn!("JACK currently does not support {format:?} output");
4444
}
45-
info!("Using JACK sink with format {:?}", AudioFormat::F32);
45+
info!("Using JACK sink with format {:?}, sample rate: {sample_rate}", AudioFormat::F32);
4646

4747
let client_name = client_name.unwrap_or_else(|| "librespot".to_string());
4848
let (client, _status) =

playback/src/audio_backend/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub enum SinkError {
2020
pub type SinkResult<T> = Result<T, SinkError>;
2121

2222
pub trait Open {
23-
fn open(_: Option<String>, format: AudioFormat) -> Self;
23+
fn open(_: Option<String>, format: AudioFormat, sample_rate: u32) -> Self;
2424
}
2525

2626
pub trait Sink {
@@ -36,14 +36,18 @@ pub trait Sink {
3636
fn write(&mut self, packet: AudioPacket, converter: &mut Converter) -> SinkResult<()>;
3737
}
3838

39-
pub type SinkBuilder = fn(Option<String>, AudioFormat) -> Box<dyn Sink>;
39+
pub type SinkBuilder = fn(Option<String>, AudioFormat, u32) -> Box<dyn Sink>;
4040

4141
pub trait SinkAsBytes {
4242
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()>;
4343
}
4444

45-
fn mk_sink<S: Sink + Open + 'static>(device: Option<String>, format: AudioFormat) -> Box<dyn Sink> {
46-
Box::new(S::open(device, format))
45+
fn mk_sink<S: Sink + Open + 'static>(
46+
device: Option<String>,
47+
format: AudioFormat,
48+
sample_rate: u32,
49+
) -> Box<dyn Sink> {
50+
Box::new(S::open(device, format, sample_rate))
4751
}
4852

4953
// reuse code for various backends

playback/src/audio_backend/pipe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ pub struct StdoutSink {
4242
}
4343

4444
impl Open for StdoutSink {
45-
fn open(file: Option<String>, format: AudioFormat) -> Self {
45+
fn open(file: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
4646
if let Some("?") = file.as_deref() {
4747
println!("\nUsage:\n\nOutput to stdout:\n\n\t--backend pipe\n\nOutput to file:\n\n\t--backend pipe --device {{filename}}\n");
4848
exit(0);
4949
}
5050

51-
info!("Using StdoutSink (pipe) with format: {:?}", format);
51+
info!("Using StdoutSink (pipe) with format: {format:?}, sample rate: {sample_rate}");
5252

5353
Self {
5454
output: None,

playback/src/audio_backend/portaudio.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ pub enum PortAudioSink<'a> {
1212
F32(
1313
Option<portaudio_rs::stream::Stream<'a, f32, f32>>,
1414
StreamParameters<f32>,
15+
f64,
1516
),
1617
S32(
1718
Option<portaudio_rs::stream::Stream<'a, i32, i32>>,
1819
StreamParameters<i32>,
20+
f64,
1921
),
2022
S16(
2123
Option<portaudio_rs::stream::Stream<'a, i16, i16>>,
2224
StreamParameters<i16>,
25+
f64,
2326
),
2427
}
2528

@@ -51,8 +54,8 @@ fn find_output(device: &str) -> Option<DeviceIndex> {
5154
}
5255

5356
impl<'a> Open for PortAudioSink<'a> {
54-
fn open(device: Option<String>, format: AudioFormat) -> PortAudioSink<'a> {
55-
info!("Using PortAudio sink with format: {format:?}");
57+
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> PortAudioSink<'a> {
58+
info!("Using PortAudio sink with format: {format:?}, sample rate: {sample_rate}");
5659

5760
portaudio_rs::initialize().unwrap();
5861

@@ -80,13 +83,13 @@ impl<'a> Open for PortAudioSink<'a> {
8083
suggested_latency: latency,
8184
data: 0.0 as $type,
8285
};
83-
$sink(None, params)
86+
$sink(None, params, sample_rate)
8487
}};
8588
}
8689
match format {
87-
AudioFormat::F32 => open_sink!(Self::F32, f32),
88-
AudioFormat::S32 => open_sink!(Self::S32, i32),
89-
AudioFormat::S16 => open_sink!(Self::S16, i16),
90+
AudioFormat::F32 => open_sink!(Self::F32, f32, sample_rate as f64),
91+
AudioFormat::S32 => open_sink!(Self::S32, i32, sample_rate as f64),
92+
AudioFormat::S16 => open_sink!(Self::S16, i16, sample_rate as f64),
9093
_ => {
9194
unimplemented!("PortAudio currently does not support {format:?} output")
9295
}
@@ -97,13 +100,13 @@ impl<'a> Open for PortAudioSink<'a> {
97100
impl<'a> Sink for PortAudioSink<'a> {
98101
fn start(&mut self) -> SinkResult<()> {
99102
macro_rules! start_sink {
100-
(ref mut $stream: ident, ref $parameters: ident) => {{
103+
(ref mut $stream: ident, ref $parameters: ident, ref $sample_rate: ident ) => {{
101104
if $stream.is_none() {
102105
*$stream = Some(
103106
Stream::open(
104107
None,
105108
Some(*$parameters),
106-
SAMPLE_RATE as f64,
109+
*$sample_rate,
107110
FRAMES_PER_BUFFER_UNSPECIFIED,
108111
StreamFlags::DITHER_OFF, // no need to dither twice; use librespot dithering instead
109112
None,
@@ -116,9 +119,9 @@ impl<'a> Sink for PortAudioSink<'a> {
116119
}
117120

118121
match self {
119-
Self::F32(stream, parameters) => start_sink!(ref mut stream, ref parameters),
120-
Self::S32(stream, parameters) => start_sink!(ref mut stream, ref parameters),
121-
Self::S16(stream, parameters) => start_sink!(ref mut stream, ref parameters),
122+
Self::F32(stream, parameters, sample_rate) => start_sink!(ref mut stream, ref parameters, ref sample_rate),
123+
Self::S32(stream, parameters, sample_rate) => start_sink!(ref mut stream, ref parameters, ref sample_rate),
124+
Self::S16(stream, parameters, sample_rate) => start_sink!(ref mut stream, ref parameters, ref sample_rate),
122125
};
123126

124127
Ok(())

playback/src/audio_backend/pulseaudio.rs

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
22
use crate::config::AudioFormat;
33
use crate::convert::Converter;
44
use crate::decoder::AudioPacket;
5-
use crate::{NUM_CHANNELS, SAMPLE_RATE};
5+
use crate::{NUM_CHANNELS, SAMPLE_RATE as DECODER_SAMPLE_RATE};
66
use libpulse_binding::{self as pulse, error::PAErr, stream::Direction};
77
use libpulse_simple_binding::Simple;
88
use std::env;
@@ -24,9 +24,6 @@ enum PulseError {
2424
#[error("<PulseAudioSink> Failed to Drain Pulseaudio Buffer, {0}")]
2525
DrainFailure(PAErr),
2626

27-
#[error("<PulseAudioSink>")]
28-
NotConnected,
29-
3027
#[error("<PulseAudioSink> {0}")]
3128
OnWrite(PAErr),
3229
}
@@ -38,72 +35,79 @@ impl From<PulseError> for SinkError {
3835
match e {
3936
DrainFailure(_) | OnWrite(_) => SinkError::OnWrite(es),
4037
ConnectionRefused(_) => SinkError::ConnectionRefused(es),
41-
NotConnected => SinkError::NotConnected(es),
4238
InvalidSampleSpec { .. } => SinkError::InvalidParams(es),
4339
}
4440
}
4541
}
4642

43+
impl From<AudioFormat> for pulse::sample::Format {
44+
fn from(f: AudioFormat) -> pulse::sample::Format {
45+
use AudioFormat::*;
46+
match f {
47+
F64 | F32 => pulse::sample::Format::FLOAT32NE,
48+
S32 => pulse::sample::Format::S32NE,
49+
S24 => pulse::sample::Format::S24_32NE,
50+
S24_3 => pulse::sample::Format::S24NE,
51+
S16 => pulse::sample::Format::S16NE,
52+
}
53+
}
54+
}
55+
4756
pub struct PulseAudioSink {
4857
sink: Option<Simple>,
4958
device: Option<String>,
5059
app_name: String,
5160
stream_desc: String,
5261
format: AudioFormat,
62+
sample_rate: u32,
63+
64+
sample_spec: pulse::sample::Spec,
5365
}
5466

5567
impl Open for PulseAudioSink {
56-
fn open(device: Option<String>, format: AudioFormat) -> Self {
68+
fn open(device: Option<String>, format: AudioFormat, sample_rate: u32) -> Self {
5769
let app_name = env::var("PULSE_PROP_application.name").unwrap_or_default();
5870
let stream_desc = env::var("PULSE_PROP_stream.description").unwrap_or_default();
5971

60-
let mut actual_format = format;
61-
62-
if actual_format == AudioFormat::F64 {
72+
let format = if format == AudioFormat::F64 {
6373
warn!("PulseAudio currently does not support F64 output");
64-
actual_format = AudioFormat::F32;
65-
}
74+
AudioFormat::F32
75+
} else {
76+
format
77+
};
78+
79+
info!("Using PulseAudioSink with format: {format:?}, sample rate: {sample_rate}");
6680

67-
info!("Using PulseAudioSink with format: {actual_format:?}");
81+
let sample_spec = pulse::sample::Spec {
82+
format: format.into(),
83+
channels: NUM_CHANNELS,
84+
rate: sample_rate,
85+
};
6886

6987
Self {
7088
sink: None,
7189
device,
7290
app_name,
7391
stream_desc,
74-
format: actual_format,
92+
format,
93+
sample_rate,
94+
sample_spec,
7595
}
7696
}
7797
}
7898

7999
impl Sink for PulseAudioSink {
80100
fn start(&mut self) -> SinkResult<()> {
81101
if self.sink.is_none() {
82-
// PulseAudio calls S24 and S24_3 different from the rest of the world
83-
let pulse_format = match self.format {
84-
AudioFormat::F32 => pulse::sample::Format::FLOAT32NE,
85-
AudioFormat::S32 => pulse::sample::Format::S32NE,
86-
AudioFormat::S24 => pulse::sample::Format::S24_32NE,
87-
AudioFormat::S24_3 => pulse::sample::Format::S24NE,
88-
AudioFormat::S16 => pulse::sample::Format::S16NE,
89-
_ => unreachable!(),
90-
};
91-
92-
let sample_spec = pulse::sample::Spec {
93-
format: pulse_format,
94-
channels: NUM_CHANNELS,
95-
rate: SAMPLE_RATE,
96-
};
97-
98-
if !sample_spec.is_valid() {
102+
if !self.sample_spec.is_valid() {
99103
let pulse_error = PulseError::InvalidSampleSpec {
100-
pulse_format,
104+
pulse_format: self.sample_spec.format,
101105
format: self.format,
102106
channels: NUM_CHANNELS,
103-
rate: SAMPLE_RATE,
107+
rate: self.sample_rate,
104108
};
105109

106-
return Err(SinkError::from(pulse_error));
110+
return Err(pulse_error.into());
107111
}
108112

109113
let sink = Simple::new(
@@ -112,7 +116,7 @@ impl Sink for PulseAudioSink {
112116
Direction::Playback, // Direction.
113117
self.device.as_deref(), // Our device (sink) name.
114118
&self.stream_desc, // Description of our stream.
115-
&sample_spec, // Our sample format.
119+
&self.sample_spec, // Our sample format.
116120
None, // Use default channel map.
117121
None, // Use default buffering attributes.
118122
)
@@ -125,19 +129,20 @@ impl Sink for PulseAudioSink {
125129
}
126130

127131
fn stop(&mut self) -> SinkResult<()> {
128-
let sink = self.sink.take().ok_or(PulseError::NotConnected)?;
132+
if let Some(sink) = self.sink.take() {
133+
sink.drain().map_err(PulseError::DrainFailure)?;
134+
}
129135

130-
sink.drain().map_err(PulseError::DrainFailure)?;
131136
Ok(())
132137
}
133138

134139
fn get_latency_pcm(&mut self) -> u64 {
135140
self.sink
136141
.as_mut()
137142
.and_then(|sink| {
138-
sink.get_latency()
139-
.ok()
140-
.map(|micro_sec| (micro_sec.as_secs_f64() * SAMPLE_RATE as f64) as u64)
143+
sink.get_latency().ok().map(|micro_sec| {
144+
(micro_sec.as_secs_f64() * DECODER_SAMPLE_RATE as f64).round() as u64
145+
})
141146
})
142147
.unwrap_or(0)
143148
}
@@ -147,9 +152,9 @@ impl Sink for PulseAudioSink {
147152

148153
impl SinkAsBytes for PulseAudioSink {
149154
fn write_bytes(&mut self, data: &[u8]) -> SinkResult<()> {
150-
let sink = self.sink.as_mut().ok_or(PulseError::NotConnected)?;
151-
152-
sink.write(data).map_err(PulseError::OnWrite)?;
155+
if let Some(sink) = self.sink.as_mut() {
156+
sink.write(data).map_err(PulseError::OnWrite)?;
157+
}
153158

154159
Ok(())
155160
}

0 commit comments

Comments
 (0)