- commit
- 8b95efdae1c2500238fe857368b145fe1984d34c
- parent
- c948dc88beba773d85fa6e2a17f83e58df966419
- author
- Dami <dami.etoile@gmail.com>
| M | src-tauri/ | 94 | +------------------------- |
| A | src-tauri/ | 108 | ++++++++++++++++++++++++++++++ |
| M | src-tauri/ | 1 | + |
@@ -22,6 +22,9 @@ use crate::media::input_delivery::{
2222 };2323 2424 pub use crate::media::input_delivery::{PointerFeedbackPayload, PointerFeedbackTerminalReason};25+use crate::media::media_control::{26+ request_keyframe, run_media_control_writer_v3, try_queue_media_keyframe_request,27+};2528 use crate::media::metrics::{ClientMediaMetrics, lock_client_media_metrics};2629 use crate::media::moq_receiver::{2730 MoqMediaReadOutcome, open_upstream_moq_media, retire_upstream_moq_generation,@@ -43,8 +46,7 @@ use openh264::{formats::YUVSource, nal_units};
4346 use serde::Serialize;4447 use sigil_protocol::{4548 FrameFlags, InputEvent, InvitationGrants, KeyframeRequestReasonV3, MediaCodec,46- MediaControlRequestV3, PointerSurfaceDimensions, read_media_frame,47- write_media_control_request_v3,49+ PointerSurfaceDimensions, read_media_frame,4850 };4951 use std::io::Cursor;5052 @@ -114,61 +116,6 @@ pub struct ConnectResult {
114116 pub error: Option<String>,115117 }116118 117-async fn run_media_control_writer_v3(118- mut stream: iroh::endpoint::SendStream,119- mut requests: tokio::sync::mpsc::Receiver<(KeyframeRequestReasonV3, Option<u64>)>,120-) {121- let mut request_id = 0_u64;122- while let Some((reason, last_sequence)) = requests.recv().await {123- let Some(next_request_id) = request_id.checked_add(1) else {124- eprintln!("[client] media v3 keyframe request id overflowed");125- break;126- };127- request_id = next_request_id;128- let request = MediaControlRequestV3::request_keyframe(request_id, last_sequence, reason);129- match tokio::time::timeout(130- Duration::from_secs(1),131- write_media_control_request_v3(&mut stream, &request),132- )133- .await134- {135- Ok(Ok(())) => {}136- Ok(Err(error)) => {137- eprintln!("[client] media v3 keyframe request failed: {error}");138- break;139- }140- Err(_) => {141- eprintln!("[client] media v3 keyframe request timed out");142- break;143- }144- }145- }146- let _ = stream.finish();147-}148-149-fn parse_keyframe_request_reason(reason: &str) -> Result<KeyframeRequestReasonV3, String> {150- match reason {151- "join" => Ok(KeyframeRequestReasonV3::Join),152- "transport-gap" => Ok(KeyframeRequestReasonV3::TransportGap),153- "delivery-timeout" => Ok(KeyframeRequestReasonV3::DeliveryTimeout),154- "discontinuity" | "decoder-reset" | "decoder-error" => {155- Ok(KeyframeRequestReasonV3::DecoderReset)156- }157- "frontend-backpressure" => Ok(KeyframeRequestReasonV3::FrontendBackpressure),158- _ => Err(format!("Unsupported keyframe request reason: {reason}")),159- }160-}161-162-fn try_queue_media_keyframe_request(163- sender: Option<&tokio::sync::mpsc::Sender<(KeyframeRequestReasonV3, Option<u64>)>>,164- reason: KeyframeRequestReasonV3,165- last_sequence: Option<u64>,166-) {167- if let Some(sender) = sender {168- let _ = sender.try_send((reason, last_sequence));169- }170-}171-172119 173120 pub async fn iroh_client_connect(174121 app: AppHandle,@@ -1095,23 +1042,6 @@ fn sequence_gap(previous: u64, current: u64) -> Result<u64, String> {
10951042 mod tests {10961043 use super::*;10971044 1098- 1099- fn keyframe_request_reason_mapping_is_strict_and_coalesces_decoder_reasons() {1100- assert_eq!(1101- parse_keyframe_request_reason("transport-gap").unwrap(),1102- KeyframeRequestReasonV3::TransportGap1103- );1104- assert_eq!(1105- parse_keyframe_request_reason("discontinuity").unwrap(),1106- KeyframeRequestReasonV3::DecoderReset1107- );1108- assert_eq!(1109- parse_keyframe_request_reason("decoder-error").unwrap(),1110- KeyframeRequestReasonV3::DecoderReset1111- );1112- assert!(parse_keyframe_request_reason("please").is_err());1113- }1114-11151045 11161046 fn media_generations_are_nonzero_monotonic_and_checked_for_overflow() {11171047 let counter = AtomicU64::new(0);@@ -1162,21 +1092,7 @@ pub async fn iroh_client_request_keyframe(
11621092 generation: u64,11631093 reason: String,11641094 ) -> Result<bool, String> {1165- let reason = parse_keyframe_request_reason(&reason)?;1166- let control = state.media_control.lock().await;1167- let Some((current_generation, sender)) = control.as_ref() else {1168- return Ok(false);1169- };1170- if *current_generation != generation {1171- return Ok(false);1172- }1173- match sender.try_send((reason, None)) {1174- Ok(()) => Ok(true),1175- Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Ok(false),1176- Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {1177- Err("Media control channel closed".to_string())1178- }1179- }1095+ request_keyframe(&state, generation, reason).await11801096 }11811097 11821098 @@ -0,0 +1,108 @@
1+use std::time::Duration;2+3+use sigil_protocol::{4+ KeyframeRequestReasonV3, MediaControlRequestV3, write_media_control_request_v3,5+};6+7+use crate::commands::state::{AppState, MediaControlRequestSender};8+9+const MEDIA_CONTROL_WRITE_TIMEOUT: Duration = Duration::from_secs(1);10+11+pub(crate) async fn run_media_control_writer_v3(12+ mut stream: iroh::endpoint::SendStream,13+ mut requests: tokio::sync::mpsc::Receiver<(KeyframeRequestReasonV3, Option<u64>)>,14+) {15+ let mut request_id = 0_u64;16+ while let Some((reason, last_sequence)) = requests.recv().await {17+ let Some(next_request_id) = request_id.checked_add(1) else {18+ eprintln!("[client] media v3 keyframe request id overflowed");19+ break;20+ };21+ request_id = next_request_id;22+ let request = MediaControlRequestV3::request_keyframe(request_id, last_sequence, reason);23+ match tokio::time::timeout(24+ MEDIA_CONTROL_WRITE_TIMEOUT,25+ write_media_control_request_v3(&mut stream, &request),26+ )27+ .await28+ {29+ Ok(Ok(())) => {}30+ Ok(Err(error)) => {31+ eprintln!("[client] media v3 keyframe request failed: {error}");32+ break;33+ }34+ Err(_) => {35+ eprintln!("[client] media v3 keyframe request timed out");36+ break;37+ }38+ }39+ }40+ let _ = stream.finish();41+}42+43+fn parse_keyframe_request_reason(reason: &str) -> Result<KeyframeRequestReasonV3, String> {44+ match reason {45+ "join" => Ok(KeyframeRequestReasonV3::Join),46+ "transport-gap" => Ok(KeyframeRequestReasonV3::TransportGap),47+ "delivery-timeout" => Ok(KeyframeRequestReasonV3::DeliveryTimeout),48+ "discontinuity" | "decoder-reset" | "decoder-error" => {49+ Ok(KeyframeRequestReasonV3::DecoderReset)50+ }51+ "frontend-backpressure" => Ok(KeyframeRequestReasonV3::FrontendBackpressure),52+ _ => Err(format!("Unsupported keyframe request reason: {reason}")),53+ }54+}55+56+pub(crate) fn try_queue_media_keyframe_request(57+ sender: Option<&MediaControlRequestSender>,58+ reason: KeyframeRequestReasonV3,59+ last_sequence: Option<u64>,60+) {61+ if let Some(sender) = sender {62+ let _ = sender.try_send((reason, last_sequence));63+ }64+}65+66+pub(crate) async fn request_keyframe(67+ state: &AppState,68+ generation: u64,69+ reason: String,70+) -> Result<bool, String> {71+ let reason = parse_keyframe_request_reason(&reason)?;72+ let control = state.media_control.lock().await;73+ let Some((current_generation, sender)) = control.as_ref() else {74+ return Ok(false);75+ };76+ if *current_generation != generation {77+ return Ok(false);78+ }79+ match sender.try_send((reason, None)) {80+ Ok(()) => Ok(true),81+ Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Ok(false),82+ Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {83+ Err("Media control channel closed".to_string())84+ }85+ }86+}87+88+89+mod tests {90+ use super::*;91+92+ 93+ fn keyframe_request_reason_mapping_is_strict_and_coalesces_decoder_reasons() {94+ assert_eq!(95+ parse_keyframe_request_reason("transport-gap").unwrap(),96+ KeyframeRequestReasonV3::TransportGap97+ );98+ assert_eq!(99+ parse_keyframe_request_reason("discontinuity").unwrap(),100+ KeyframeRequestReasonV3::DecoderReset101+ );102+ assert_eq!(103+ parse_keyframe_request_reason("decoder-error").unwrap(),104+ KeyframeRequestReasonV3::DecoderReset105+ );106+ assert!(parse_keyframe_request_reason("please").is_err());107+ }108+}