Ashiedu's picture
Sync unified workbench
0490201 verified

A newer version of the Gradio SDK is available: 6.14.0

Upgrade

T-013: Audio + Camera Device Enumeration IPC β€” Hot-Plug Detection, device_list_updated Event

Type: Task | Phase: 0 | Autonomy: agent:autonomous | Stack: stack:rust
Version: v0.1 | Iteration: iter-1 | Effort: XS (1 hour)

⚠️ Scope: T-004 implemented device_list for audio devices only. T-013 extends it to include cameras and adds a background watcher that emits device_list_updated when devices are plugged or unplugged. Camera enumeration uses Windows Media Foundation (MSMF) via the nokhwa crate.


Prerequisites

  • T-002 merged β€” DeviceInfo, DeviceKind, DeviceListResult types exist
  • T-004 merged β€” audio device_list command exists in kansas/src/commands/devices.rs

New Workspace Dependency

nokhwa = { version = "*", features = ["input-msmf"] }  # Windows camera enumeration

Acceptance Criteria

  • device_list returns cameras alongside audio devices (kind: "camera")
  • Plugging in a USB camera within 3 seconds emits device_list_updated event to frontend
  • Unplugging emits device_list_updated
  • No panic if zero cameras present
  • cargo check --workspace β€” zero errors

Changes to kansas/src/commands/devices.rs

Extend the existing device_list command to append camera devices:

use nokhwa::{query, utils::ApiBackend};

// After audio device collection, add:
if let Ok(cameras) = query(ApiBackend::MediaFoundation) {
    for (idx, info) in cameras.iter().enumerate() {
        devices.push(DeviceInfo {
            id: id,
            name: info.human_name().to_string(),
            kind: DeviceKind::Camera,
            is_default: idx == 0,  // first camera is default
        });
        id += 1;
    }
}

Add Hot-Plug Watcher

In kansas/src/devices.rs (new file):

use std::{sync::Arc, time::Duration, thread};
use tauri::AppHandle;
use crate::ipc::types::DeviceListResult;

/// Polls device list every 2s; emits `device_list_updated` on change.
/// Real hot-plug via WM_DEVICECHANGE is a T-013 iter-2 enhancement.
pub fn watch_devices(app: AppHandle) {
    thread::Builder::new()
        .name("synesthesia-device-watcher".into())
        .spawn(move || {
            let mut last_count = 0usize;
            loop {
                thread::sleep(Duration::from_secs(2));
                if let Ok(result) = crate::commands::devices::enumerate_all() {
                    let count = result.devices.len();
                    if count != last_count {
                        last_count = count;
                        app.emit("device_list_updated", &result).ok();
                        tracing::info!("[devices] Device list changed β€” {} devices", count);
                    }
                }
            }
        })
        .ok();
}

Register in main.rs: devices::watch_devices(app_handle.clone());


GitHub CLI

gh issue create \
  --title "T-013: Audio + camera device enumeration IPC β€” hot-plug detection, device_list_updated" \
  --label "type:task,stack:rust,agent:autonomous,priority:high,status:ready,day:1" \
  --body-file T-013.md

Parent: GENESIS | Blocks: T-031 (camera config uses device IDs) | Blocked By: T-002, T-004