11extern crate alsa;
22extern crate libc;
3+ extern crate parking_lot;
34
45use self :: alsa:: poll:: Descriptors ;
6+ use self :: parking_lot:: Mutex ;
57use crate :: {
68 BackendSpecificError , BufferSize , BuildStreamError , ChannelCount , Data ,
79 DefaultStreamConfigError , DeviceNameError , DevicesError , InputCallbackInfo , OutputCallbackInfo ,
@@ -163,8 +165,15 @@ impl Drop for TriggerReceiver {
163165 }
164166}
165167
166- #[ derive( Clone , Debug , PartialEq , Eq ) ]
167- pub struct Device ( String ) ;
168+ struct DeviceHandles {
169+ playback : Option < alsa:: PCM > ,
170+ capture : Option < alsa:: PCM > ,
171+ }
172+
173+ pub struct Device {
174+ name : String ,
175+ handles : Mutex < DeviceHandles > ,
176+ }
168177
169178impl Device {
170179 fn build_stream_inner (
@@ -173,10 +182,21 @@ impl Device {
173182 sample_format : SampleFormat ,
174183 stream_type : alsa:: Direction ,
175184 ) -> Result < StreamInner , BuildStreamError > {
176- let name = & self . 0 ;
185+ let name = & self . name ;
177186
178- let handle = match alsa:: pcm:: PCM :: new ( name, stream_type, true ) . map_err ( |e| ( e, e. errno ( ) ) )
179- {
187+ let device_handle = {
188+ let mut guard = self . handles . lock ( ) ;
189+ match stream_type {
190+ alsa:: Direction :: Playback => guard. playback . take ( ) ,
191+ alsa:: Direction :: Capture => guard. capture . take ( ) ,
192+ }
193+ } ;
194+
195+ let handle_result = Ok ( device_handle) . transpose ( ) . unwrap_or_else ( || {
196+ alsa:: pcm:: PCM :: new ( name, stream_type, true ) . map_err ( |e| ( e, e. errno ( ) ) )
197+ } ) ;
198+
199+ let handle = match handle_result {
180200 Err ( ( _, Some ( nix:: errno:: Errno :: EBUSY ) ) ) => {
181201 return Err ( BuildStreamError :: DeviceNotAvailable )
182202 }
@@ -229,16 +249,33 @@ impl Device {
229249
230250 #[ inline]
231251 fn name ( & self ) -> Result < String , DeviceNameError > {
232- Ok ( self . 0 . clone ( ) )
252+ Ok ( self . name . clone ( ) )
233253 }
234254
235255 fn supported_configs (
236256 & self ,
237257 stream_t : alsa:: Direction ,
238258 ) -> Result < VecIntoIter < SupportedStreamConfigRange > , SupportedStreamConfigsError > {
239- let name = & self . 0 ;
259+ let name = & self . name ;
260+
261+ let mut guard = self . handles . lock ( ) ;
262+
263+ let device_handle = match stream_t {
264+ alsa:: Direction :: Playback => & mut guard. playback ,
265+ alsa:: Direction :: Capture => & mut guard. capture ,
266+ } ;
267+
268+ let handle_result = match device_handle {
269+ Some ( handle) => Ok ( handle) ,
270+ None => alsa:: pcm:: PCM :: new ( name, stream_t, true )
271+ . map ( |handle| {
272+ * device_handle = Some ( handle) ;
273+ device_handle. as_mut ( ) . unwrap ( )
274+ } )
275+ . map_err ( |e| ( e, e. errno ( ) ) ) ,
276+ } ;
240277
241- let handle = match alsa :: pcm :: PCM :: new ( name , stream_t , true ) . map_err ( |e| ( e , e . errno ( ) ) ) {
278+ let handle = match handle_result {
242279 Err ( ( _, Some ( nix:: errno:: Errno :: ENOENT ) ) )
243280 | Err ( ( _, Some ( nix:: errno:: Errno :: EBUSY ) ) ) => {
244281 return Err ( SupportedStreamConfigsError :: DeviceNotAvailable )
0 commit comments