Spaces:
Runtime error
Runtime error
| # 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 | |
| ```toml | |
| 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: | |
| ```rust | |
| 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): | |
| ```rust | |
| 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 | |
| ```bash | |
| 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 | |