@@ -274,7 +274,7 @@ struct DeviceHandles {
274274impl DeviceHandles {
275275 /// Get a mutable reference to the `Option` for a specific `stream_type`.
276276 /// If the `Option` is `None`, the `alsa::PCM` will be opened and placed in
277- /// the `Option` before returning. If `handle_mut ()` returns `Ok` the contained
277+ /// the `Option` before returning. If `try_open ()` returns `Ok` the contained
278278 /// `Option` is guaranteed to be `Some(..)`.
279279 fn try_open (
280280 & mut self ,
@@ -320,8 +320,6 @@ pub struct Device {
320320
321321impl PartialEq for Device {
322322 fn eq ( & self , other : & Self ) -> bool {
323- // Devices are equal if they have the same PCM ID.
324- // The handles field is not part of device identity.
325323 self . pcm_id == other. pcm_id
326324 }
327325}
@@ -363,19 +361,22 @@ impl Device {
363361 }
364362 }
365363
366- let handle_result = self
364+ let handle = match self
367365 . handles
368366 . lock ( )
369367 . unwrap ( )
370368 . take ( & self . pcm_id , stream_type)
371- . map_err ( |e| ( e, e. errno ( ) ) ) ;
372-
373- let handle = match handle_result {
374- Err ( ( _, libc:: EBUSY ) ) => return Err ( BuildStreamError :: DeviceNotAvailable ) ,
369+ . map_err ( |e| ( e, e. errno ( ) ) )
370+ {
371+ Err ( ( _, libc:: ENOENT ) )
372+ | Err ( ( _, libc:: EBUSY ) )
373+ | Err ( ( _, libc:: EPERM ) )
374+ | Err ( ( _, libc:: EAGAIN ) ) => return Err ( BuildStreamError :: DeviceNotAvailable ) ,
375375 Err ( ( _, libc:: EINVAL ) ) => return Err ( BuildStreamError :: InvalidArgument ) ,
376376 Err ( ( e, _) ) => return Err ( e. into ( ) ) ,
377377 Ok ( handle) => handle,
378378 } ;
379+
379380 let can_pause = set_hw_params_from_format ( & handle, conf, sample_format) ?;
380381 let period_samples = set_sw_params_from_format ( & handle, conf, stream_type) ?;
381382
@@ -462,12 +463,15 @@ impl Device {
462463 & self ,
463464 stream_t : alsa:: Direction ,
464465 ) -> Result < VecIntoIter < SupportedStreamConfigRange > , SupportedStreamConfigsError > {
466+ // Open device handle and cache it for reuse in build_stream_inner().
467+ // This avoids opening the device twice in the common workflow:
468+ // 1. Query supported configs (opens and caches handle)
469+ // 2. Build stream (takes cached handle, or opens if not cached)
465470 let mut guard = self . handles . lock ( ) . unwrap ( ) ;
466- let handle_result = guard
471+ let pcm = match guard
467472 . get_mut ( & self . pcm_id , stream_t)
468- . map_err ( |e| ( e, e. errno ( ) ) ) ;
469-
470- let handle = match handle_result {
473+ . map_err ( |e| ( e, e. errno ( ) ) )
474+ {
471475 Err ( ( _, libc:: ENOENT ) )
472476 | Err ( ( _, libc:: EBUSY ) )
473477 | Err ( ( _, libc:: EPERM ) )
@@ -476,10 +480,10 @@ impl Device {
476480 }
477481 Err ( ( _, libc:: EINVAL ) ) => return Err ( SupportedStreamConfigsError :: InvalidArgument ) ,
478482 Err ( ( e, _) ) => return Err ( e. into ( ) ) ,
479- Ok ( handle ) => handle ,
483+ Ok ( pcm ) => pcm ,
480484 } ;
481485
482- let hw_params = alsa:: pcm:: HwParams :: any ( handle ) ?;
486+ let hw_params = alsa:: pcm:: HwParams :: any ( pcm ) ?;
483487
484488 // Test both LE and BE formats to detect what the hardware actually supports.
485489 // LE is listed first as it's the common case for most audio hardware.
0 commit comments