Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ repository.
- [Virtual camera](/quest/m0/vcam/README.md) - the program or a published scene exposed as a system camera on Linux, Windows, and macOS
- [Browser sources on the GPU under Mesa](/quest/m0/cef-headless.md) - shared-texture pages paint on Intel and AMD under Wayland, and a page that cannot paint fails loudly
- [Browser sources make no outside requests](/quest/m0/browser-offline.md) - no component updates, spellcheck downloads, or network time from the helper
- [Unpublishing a scene ends its broadcast cleanly](/quest/m0/unpublish-clean.md) - viewers get a clean finish, not `Unroutable`, when a scene stops publishing
- [A media file's sound plays with its pictures](/quest/m0/media-av-sync.md) - media sources write a bus latency ahead, as broadcast sources do
- [The Apple signing identity is available](/quest/m0/signing.md) - the Apple credentials packaging and the macOS camera need; Windows ships unsigned
- [Packaging](/quest/m0/packaging.md) - a signed macOS app, a Windows installer, and a Flatpak for Linux
Expand Down
24 changes: 0 additions & 24 deletions quest/m0/unpublish-clean.md

This file was deleted.

40 changes: 32 additions & 8 deletions rs/moq-studio/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3463,11 +3463,34 @@ mod tests {
(broadcast, catalogs, catalog)
}

/// Read a published scene's `video` and `catalogs` to a clean end.
async fn ended(mut catalogs: moq_mux::catalog::Consumer<()>, mut video: moq_net::track::Subscriber) {
/// A viewer of `broadcast`'s `video`, and the first group the relay
/// handed it once it answered the subscription. The relay refuses one
/// still unanswered when the scene's broadcast goes, since the program's
/// broadcast still covers its path there.
async fn served(
broadcast: &moq_net::broadcast::Consumer,
video: &str,
) -> (moq_net::track::Subscriber, moq_net::group::Consumer) {
let mut track = broadcast.track(video).unwrap().subscribe(None).await.unwrap();
let first = kio::clock::timeout(TIMEOUT, track.recv_group())
.await
.expect("the relay serves the video")
.expect("the video")
.expect("a group");
(track, first)
}

/// Read a published scene's `video`, from the first group it was served,
/// and its `catalogs` to a clean end.
async fn ended(
mut catalogs: moq_mux::catalog::Consumer<()>,
(mut video, first): (moq_net::track::Subscriber, moq_net::group::Consumer),
) {
kio::clock::timeout(TIMEOUT, async {
while let Some(mut group) = video.recv_group().await.expect("the video finishes") {
while group.read_frame().await.expect("the video finishes").is_some() {}
let mut group = Some(first);
while let Some(mut current) = group {
while current.read_frame().await.expect("the video finishes").is_some() {}
group = video.recv_group().await.expect("the video finishes");
}
while catalogs.next().await.expect("the catalog finishes").is_some() {}
})
Expand All @@ -3480,8 +3503,9 @@ mod tests {
/// more encode session.
/// What only it shows is shown but not on program. Health grades its
/// video beside the program, with its own viewers. Unpublishing
/// it, or quitting, ends its video and then its catalog cleanly, then its
/// broadcast; unpublishing gives its session back.
/// it, or quitting, ends its video and then its catalog cleanly for a
/// viewer the relay serves, then its broadcast; unpublishing gives its
/// session back.
#[tokio::test(flavor = "multi_thread")]
#[ignore = "needs a Vulkan device and an H.264 encoder; run by just rs render-sw"]
async fn a_published_scene_has_its_own_broadcast() {
Expand Down Expand Up @@ -3601,7 +3625,7 @@ mod tests {
.await
.expect("health grades the published scene");

let track = broadcast.track(&video).unwrap().subscribe(None).await.unwrap();
let track = served(&broadcast, &video).await;
{
let mut state = engine.state.lock().unwrap();
let scene = state.collection().scenes[1].clone();
Expand Down Expand Up @@ -3631,7 +3655,7 @@ mod tests {
engine.state.lock().unwrap().undo().unwrap();
let (broadcast, catalogs, catalog) = routed(&relay, "studio/tall").await;
let (video, _) = canvas_size(&catalog);
let track = broadcast.track(&video).unwrap().subscribe(None).await.unwrap();
let track = served(&broadcast, &video).await;
let stopping = engine.clone();
tokio::task::spawn_blocking(move || stopping.stop()).await.unwrap();
kio::clock::timeout(TIMEOUT, engine.close())
Expand Down