Map V4L2 EBUSY to a distinct DeviceError::Busy #47

Open
opened 2026-07-14 15:40:03 +00:00 by p13marc · 0 comments
p13marc commented 2026-07-14 15:40:03 +00:00 (Migrated from github.com)

EBUSY is the characteristic V4L2 failure — a second open() of a camera another process (or another pipeline) already holds. It currently lands in the generic catch-all.

src/elements/device/v4l2.rs:295-303:

let dev = Device::with_path(&path).map_err(|e| {
    if e.kind() == std::io::ErrorKind::NotFound {
        DeviceError::NotFound(device_path.to_string())
    } else if e.kind() == std::io::ErrorKind::PermissionDenied {
        DeviceError::PermissionDenied(device_path.to_string())
    } else {
        DeviceError::V4l2(e)     // EBUSY lands here
    }
})?;

NotFound and PermissionDenied — the two other "the operator did something recoverable" cases — get named variants. Busy doesn't, so a caller cannot distinguish "this camera is in use, close the other stream or wait" from any other ioctl failure without string-matching the io error.

Ask

Add DeviceError::Busy(String) and map ErrorKind::ResourceBusy (or raw errno 16) to it.

Why it matters

The zensight sensor hits exactly this: opening an H.264 profile and a JPEG preview profile on the same camera opens the device twice, and most UVC cameras reject the second open. It's a documented limitation there, and the error it surfaces today is undiagnosable. (The proper fix is a single-open fan-out graph — see the head-of-line-blocking issue — but a legible error is worth having regardless, since two processes can always collide.)

`EBUSY` is *the* characteristic V4L2 failure — a second `open()` of a camera another process (or another pipeline) already holds. It currently lands in the generic catch-all. `src/elements/device/v4l2.rs:295-303`: ```rust let dev = Device::with_path(&path).map_err(|e| { if e.kind() == std::io::ErrorKind::NotFound { DeviceError::NotFound(device_path.to_string()) } else if e.kind() == std::io::ErrorKind::PermissionDenied { DeviceError::PermissionDenied(device_path.to_string()) } else { DeviceError::V4l2(e) // EBUSY lands here } })?; ``` `NotFound` and `PermissionDenied` — the two other "the operator did something recoverable" cases — get named variants. Busy doesn't, so a caller cannot distinguish "this camera is in use, close the other stream or wait" from any other ioctl failure without string-matching the io error. ## Ask Add `DeviceError::Busy(String)` and map `ErrorKind::ResourceBusy` (or raw errno 16) to it. ## Why it matters The zensight sensor hits exactly this: opening an H.264 profile and a JPEG preview profile on the same camera opens the device twice, and most UVC cameras reject the second open. It's a documented limitation there, and the error it surfaces today is undiagnosable. (The proper fix is a single-open fan-out graph — see the head-of-line-blocking issue — but a legible error is worth having regardless, since two *processes* can always collide.)
Sign in to join this conversation.
No description provided.