Update nusb to c1380673 which allows multiple IsoEndpoint instances per address, enabling concurrent URB submission from separate threads. Change UsbInterfaceHandler trait methods from &mut self to &self and replace Arc<Mutex<Box<dyn Handler>>> with Arc<dyn Handler>. This removes the serialization bottleneck where the handler mutex was held for the entire USB transfer duration, causing ISO audio to play at ~67% speed. Handlers needing interior mutability (HID, CDC) now use Mutex on individual fields. Passthrough handlers already used Arc<Mutex<>> internally and need no changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
81 lines
2.6 KiB
Rust
81 lines
2.6 KiB
Rust
use log::info;
|
|
use std::sync::Arc;
|
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
|
|
use usbip_rs::{
|
|
ClassCode, UsbDevice, UsbEndpoint, UsbInterfaceHandler, hid::UsbHidKeyboardHandler,
|
|
usbip_protocol::UsbIpResponse,
|
|
};
|
|
|
|
use crate::transport;
|
|
|
|
/// Send handshake, spawn key simulator, and run URB loop.
|
|
async fn do_test_hid_session<S: AsyncReadExt + AsyncWriteExt + Unpin + Send + 'static>(
|
|
mut stream: S,
|
|
device: UsbDevice,
|
|
handler: Arc<UsbHidKeyboardHandler>,
|
|
) -> std::io::Result<()> {
|
|
// Send device info (simplified handshake)
|
|
let handshake = UsbIpResponse::op_rep_import_success(&device).to_bytes()?;
|
|
stream
|
|
.write_all(&handshake)
|
|
.await
|
|
.map_err(|e| std::io::Error::other(format!("Failed to send handshake: {e}")))?;
|
|
info!("Handshake sent, entering URB loop");
|
|
|
|
// Spawn key event simulator
|
|
let handler_clone = handler.clone();
|
|
tokio::spawn(async move {
|
|
loop {
|
|
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
|
match usbip_rs::hid::UsbHidKeyboardReport::from_ascii(b'1') {
|
|
Ok(report) => {
|
|
handler_clone.pending_key_events.lock().unwrap().push_back(report);
|
|
info!("Simulated key event '1'");
|
|
}
|
|
Err(e) => {
|
|
info!("Failed to create key report: {}", e);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Handle URBs
|
|
usbip_rs::handle_urb_loop(stream, Arc::new(device)).await
|
|
}
|
|
|
|
pub async fn run(addr: transport::TransportAddr) -> std::io::Result<()> {
|
|
// Create simulated HID keyboard
|
|
let handler = Arc::new(UsbHidKeyboardHandler::new_keyboard());
|
|
|
|
let device = UsbDevice::new(0)?.with_interface(
|
|
ClassCode::HID as u8,
|
|
0x00,
|
|
0x00,
|
|
Some("Test HID Keyboard"),
|
|
vec![UsbEndpoint {
|
|
address: 0x81, // IN
|
|
attributes: 0x03, // Interrupt
|
|
max_packet_size: 0x08, // 8 bytes
|
|
interval: 10,
|
|
}],
|
|
handler.clone() as Arc<dyn UsbInterfaceHandler>,
|
|
)?;
|
|
|
|
info!(
|
|
"Created simulated HID keyboard {:04x}:{:04x}",
|
|
device.vendor_id, device.product_id
|
|
);
|
|
|
|
// Connect via transport and run session
|
|
match addr {
|
|
transport::TransportAddr::Vsock(v) => {
|
|
let stream = transport::connect_vsock(v.cid, v.port).await?;
|
|
do_test_hid_session(stream, device, handler).await
|
|
}
|
|
transport::TransportAddr::Tcp(ref t) => {
|
|
let stream = transport::connect_tcp(t).await?;
|
|
do_test_hid_session(stream, device, handler).await
|
|
}
|
|
}
|
|
}
|