Skip to content

Commit bab2fdd

Browse files
committed
refactor(alsa): handle more open errors
* Map ENOENT, EBUSY, EPERM and EAGAIN returned when taking a PCM handle to DeviceNotAvailable. * Add a comment to clarify reuse of cached device handles to avoid opening the device twice. * Minor documentation improvements.
1 parent 6f5ad67 commit bab2fdd

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

src/host/alsa/mod.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ struct DeviceHandles {
274274
impl 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

321321
impl 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

Comments
 (0)