@@ -2,7 +2,7 @@ use super::{Open, Sink, SinkAsBytes, SinkError, SinkResult};
22use crate :: config:: AudioFormat ;
33use crate :: convert:: Converter ;
44use crate :: decoder:: AudioPacket ;
5- use crate :: { NUM_CHANNELS , SAMPLE_RATE } ;
5+ use crate :: { NUM_CHANNELS , SAMPLE_RATE as DECODER_SAMPLE_RATE } ;
66use libpulse_binding:: { self as pulse, error:: PAErr , stream:: Direction } ;
77use libpulse_simple_binding:: Simple ;
88use 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+
4756pub 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
5567impl 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
7999impl 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
148153impl 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