#[cfg(coverage)] #[tonic::async_trait] impl Relay for Handler { type StreamKeyboardStream = ReceiverStream>; type StreamMouseStream = ReceiverStream>; type CaptureVideoStream = VideoStream; type CaptureAudioStream = AudioStream; type StreamMicrophoneStream = ReceiverStream>; type StreamCameraStream = ReceiverStream>; async fn stream_keyboard( &self, req: Request>, ) -> Result, Status> { let (tx, rx) = tokio::sync::mpsc::channel(32); let kb = self.kb.clone(); let report_delay = live_keyboard_report_delay(); tokio::spawn(async move { let mut s = req.into_inner(); while let Some(pkt) = s.next().await.transpose()? { let _ = runtime_support::write_hid_report(&kb, &hid_endpoint(0), &pkt.data).await; tx.send(Ok(pkt)).await.ok(); if !report_delay.is_zero() { #[cfg(not(coverage))] tokio::time::sleep(report_delay).await; } } Ok::<(), Status>(()) }); Ok(Response::new(ReceiverStream::new(rx))) } async fn stream_mouse( &self, req: Request>, ) -> Result, Status> { let (tx, rx) = tokio::sync::mpsc::channel(32); let ms = self.ms.clone(); tokio::spawn(async move { let mut s = req.into_inner(); while let Some(pkt) = s.next().await.transpose()? { let _ = runtime_support::write_hid_report(&ms, &hid_endpoint(1), &pkt.data).await; tx.send(Ok(pkt)).await.ok(); } Ok::<(), Status>(()) }); Ok(Response::new(ReceiverStream::new(rx))) } async fn stream_microphone( &self, req: Request>, ) -> Result, Status> { let uac_dev = std::env::var("LESAVKA_UAC_DEV").unwrap_or_else(|_| "hw:UAC2Gadget,0".into()); let mut sink = runtime_support::open_voice_with_retry(&uac_dev) .await .map_err(|e| Status::internal(format!("{e:#}")))?; let (tx, rx) = tokio::sync::mpsc::channel(1); tokio::spawn(async move { let mut inbound = req.into_inner(); while let Some(pkt) = inbound.next().await.transpose()? { sink.push(&pkt); } sink.finish(); let _ = tx.send(Ok(Empty {})).await; Ok::<(), Status>(()) }); Ok(Response::new(ReceiverStream::new(rx))) } async fn stream_camera( &self, req: Request>, ) -> Result, Status> { let cfg = camera::current_camera_config(); let (session_id, relay) = self.camera_rt.activate(&cfg).await?; let camera_rt = self.camera_rt.clone(); let (tx, rx) = tokio::sync::mpsc::channel(1); tokio::spawn(async move { let mut s = req.into_inner(); while let Some(pkt) = s.next().await.transpose()? { if !camera_rt.is_active(session_id) { break; } relay.feed(pkt); } tx.send(Ok(Empty {})).await.ok(); Ok::<(), Status>(()) }); Ok(Response::new(ReceiverStream::new(rx))) } async fn capture_video( &self, req: Request, ) -> Result, Status> { self.capture_video_reply(req.into_inner()).await } async fn capture_audio( &self, _req: Request, ) -> Result, Status> { Err(Status::internal( "audio capture unavailable in coverage harness", )) } async fn paste_text(&self, req: Request) -> Result, Status> { self.paste_text_reply(req).await } async fn reset_usb(&self, _req: Request) -> Result, Status> { self.reset_usb_reply().await } async fn get_capture_power( &self, _req: Request, ) -> Result, Status> { self.get_capture_power_reply().await } async fn set_capture_power( &self, req: Request, ) -> Result, Status> { self.set_capture_power_reply(req).await } }