diff --git a/rs/moq-cli/src/play/media.rs b/rs/moq-cli/src/play/media.rs index 8676e459428..2cab59293c5 100644 --- a/rs/moq-cli/src/play/media.rs +++ b/rs/moq-cli/src/play/media.rs @@ -494,11 +494,11 @@ async fn play_audio( let mut quiet = fit.pad + timing.silence.saturating_sub(fit.skip); while quiet > 0 { let part = (quiet as usize * stride).min(silence.len()); - let _ = sink.write(&silence[..part])?; + sink.write(&silence[..part])?; quiet -= (part / stride) as u64; } let skip = fit.skip.saturating_sub(timing.silence) as usize * stride; - let _ = sink.write(&frame.data[skip.min(frame.data.len())..])?; + sink.write(&frame.data[skip.min(frame.data.len())..])?; // Anchor the playout clock on where the speaker has actually reached, which // is the only half of the pipeline that cannot skip ahead. A move has to diff --git a/rs/moq-net/benches/origin.rs b/rs/moq-net/benches/origin.rs index 88263158a8b..b9d5b9d0492 100644 --- a/rs/moq-net/benches/origin.rs +++ b/rs/moq-net/benches/origin.rs @@ -327,9 +327,10 @@ fn bench_reprice_duplicate(c: &mut Criterion) { for cost in [incumbent_cost - 1, incumbent_cost + 1] { route.update(peer_route(challenger, cost)).unwrap(); for cursor in &mut cursors { + // The winner switches between epochless routes, which is another instance. let event = cursor.next().now_or_never().flatten().expect("winner changed"); - let moq_net::announce::Event::Update(update) = event else { - panic!("expected an update: got {event:?}"); + let moq_net::announce::Event::Restart(update) = event else { + panic!("expected a restart: got {event:?}"); }; assert_eq!(update.route.cost, moq_net::origin::Cost::new(cost.min(incumbent_cost))); } @@ -654,8 +655,10 @@ fn bench_pool_cursors(c: &mut Criterion) { /// Publisher handoff at one path: a subscriber is reading from one local /// source when a second announces at the same path and takes over (newest -/// wins). Measured from the standby's attach to the subscriber receiving its -/// first group, with `publishers` unrelated broadcasts in the table. +/// wins). An open subscription stays on the old instance, so the subscriber +/// re-requests the broadcast. Measured from the standby's attach to the +/// re-request receiving its first group, with `publishers` unrelated +/// broadcasts in the table. fn bench_handoff(c: &mut Criterion) { let mut group = c.benchmark_group("origin/handoff"); group.measurement_time(Duration::from_secs(5)); @@ -695,14 +698,20 @@ fn bench_handoff(c: &mut Criterion) { second.finish().unwrap(); // Announcing is what makes the standby a route the front can take. standby.announce(origin::Route::default()).unwrap(); - subscription.recv_group().await.unwrap().expect("standby group"); + let replaced = consumer.request_broadcast("room/live", None).await.unwrap(); + let mut replacement = replaced.track("video").unwrap().subscribe(None).await.unwrap(); + let group = replacement.recv_group().await.unwrap().expect("standby group"); total += started.elapsed(); + // Rejoining the incumbent would replay its cached group 0 instead. + assert_eq!(group.sequence, 1, "standby group"); drop(subscription); + drop(replacement); incumbent.close(); standby.close(); - // Wait for the front to close so the next iteration starts a fresh one. + // Wait for the fronts to close so the next iteration starts fresh ones. resolved.closed().await; + replaced.closed().await; } total }) diff --git a/rs/moq-video/src/render/dmabuf.rs b/rs/moq-video/src/render/dmabuf.rs index e149665669f..2f8bb51e552 100644 --- a/rs/moq-video/src/render/dmabuf.rs +++ b/rs/moq-video/src/render/dmabuf.rs @@ -299,29 +299,10 @@ unsafe fn adopt_plane( /// would produce, with pixels it chose itself. #[cfg(all(test, feature = "vaapi"))] pub(super) mod fixture { - use std::os::fd::OwnedFd; use std::sync::Arc; use super::*; - - /// A DMA-BUF built from an already exported descriptor. - /// - /// The export holds its own reference on the underlying allocation, so the - /// VA-API surface it came from is long gone by the time anything imports - /// this. Downloading is not implemented: the point of the fixture is the - /// zero-copy path, and a test comparing against the CPU one builds its - /// reference from the bytes it uploaded rather than reading them back. - struct Exported(OwnedFd); - - impl crate::frame::DmaBufFrame for Exported { - fn export(&self) -> std::io::Result { - self.0.try_clone() - } - - fn download_i420(&self) -> Result { - Err(err("the DMA-BUF fixture does not implement downloading")) - } - } + use crate::DmaBufLayout; /// The VA-API fourcc naming the same layout as a DRM format. /// @@ -422,16 +403,11 @@ pub(super) mod fixture { .collect(); let fd = object.fd.try_clone().expect("duplicate the exported descriptor"); - DmaBuf::new( - format, - object.drm_format_modifier, - size.width, - size.height, - planes, - None, - Arc::new(Exported(fd)), - ) - .expect("a well-formed DMA-BUF") + // The export holds its own reference on the allocation, so the VA-API + // surface it came from can go away before anything imports this. + let mut layout = DmaBufLayout::new(format, size, planes); + layout.modifier = object.drm_format_modifier; + DmaBuf::new(fd, layout, ()).expect("a well-formed DMA-BUF") } /// Copy tightly packed planes into a surface, honoring the image's own plane