Skip to content

Commit b2c2981

Browse files
committed
fix: preserve DASH render startup
1 parent a417f69 commit b2c2981

4 files changed

Lines changed: 53 additions & 9 deletions

File tree

src/live_dash_ingest.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,10 +506,21 @@ LiveObject LiveDashIngestSession::build_catalog_locked() {
506506
<< "\"id\":" << track.track_id << ','
507507
<< "\"role\":\"" << role_for_handler(track.handler_type) << "\","
508508
<< "\"packaging\":\"cmaf\","
509+
<< "\"renderGroup\":1,"
509510
<< "\"isLive\":true";
510511
if (!track.codec.empty()) {
511512
catalog << ",\"codec\":\"" << json_escape(track.codec) << "\"";
512513
}
514+
if (track.handler_type == "vide") {
515+
catalog << ",\"width\":" << track.width
516+
<< ",\"height\":" << track.height;
517+
if (track.frame_rate > 0.0) {
518+
catalog << ",\"frameRate\":" << std::setprecision(6) << track.frame_rate;
519+
}
520+
} else if (track.handler_type == "soun") {
521+
catalog << ",\"sampleRate\":" << track.sample_rate
522+
<< ",\"channelCount\":" << track.channel_count;
523+
}
513524
if (!registered.init_data_base64.empty()) {
514525
catalog << ",\"initData\":\"" << registered.init_data_base64 << "\"";
515526
}

src/transport/moqt_session.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4597,6 +4597,12 @@ TransportStatus MoqtSession::publish_live_objects(const openmoq::publisher::Live
45974597
std::optional<std::chrono::steady_clock::time_point> object_pacing_start;
45984598
std::optional<std::uint64_t> object_first_media_time_us;
45994599
bool live_object_catalog_sent = !alias_by_track.contains("catalog");
4600+
const bool has_media_tracks = std::any_of(alias_by_track.begin(), alias_by_track.end(),
4601+
[](const auto& entry) { return entry.first != "catalog"; });
4602+
const auto has_media_subscription = [&]() {
4603+
return std::any_of(subscribed_tracks.begin(), subscribed_tracks.end(),
4604+
[](const std::string& track_name) { return track_name != "catalog"; });
4605+
};
46004606
const auto await_subscribe_deadline = std::chrono::steady_clock::now() + subscriber_timeout_;
46014607
while (!source_eof) {
46024608
if (stop_requested_.load(std::memory_order_acquire)) {
@@ -4611,7 +4617,11 @@ TransportStatus MoqtSession::publish_live_objects(const openmoq::publisher::Live
46114617
bool read_fin = false;
46124618
const bool waiting_for_first_subscription =
46134619
!auto_forward_ && active_subscriptions.empty() && subscribed_tracks.empty();
4614-
const auto read_timeout = waiting_for_first_subscription && !uses_request_streams(draft_version)
4620+
const bool waiting_for_media_subscription =
4621+
!auto_forward_ && live_object_catalog_sent && has_media_tracks && !has_media_subscription();
4622+
const bool waiting_for_required_subscription =
4623+
waiting_for_first_subscription || waiting_for_media_subscription;
4624+
const auto read_timeout = waiting_for_required_subscription && !uses_request_streams(draft_version)
46154625
? subscriber_timeout_
46164626
: std::chrono::milliseconds(0);
46174627
const TransportStatus read_status =
@@ -4621,7 +4631,8 @@ TransportStatus MoqtSession::publish_live_objects(const openmoq::publisher::Live
46214631
control_fin = read_fin;
46224632
} else if (read_status.message == "timed out waiting for stream data" ||
46234633
read_status.message == "no queued read for stream") {
4624-
if (waiting_for_first_subscription && std::chrono::steady_clock::now() >= await_subscribe_deadline) {
4634+
if (waiting_for_required_subscription &&
4635+
std::chrono::steady_clock::now() >= await_subscribe_deadline) {
46254636
break;
46264637
}
46274638
} else {
@@ -4643,6 +4654,9 @@ TransportStatus MoqtSession::publish_live_objects(const openmoq::publisher::Live
46434654
if (!auto_forward_ && subscribed_tracks.empty()) {
46444655
continue;
46454656
}
4657+
if (!auto_forward_ && live_object_catalog_sent && has_media_tracks && !has_media_subscription()) {
4658+
continue;
4659+
}
46464660

46474661
std::optional<openmoq::publisher::LiveObject> next = source.next_object();
46484662
if (!next.has_value()) {

tests/live_dash_ingest_test.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,14 @@ int main() {
273273
ok &= expect(catalog.has_value() && catalog->track_name == "catalog",
274274
"expected catalog object for initData test");
275275
if (catalog.has_value()) {
276-
ok &= expect(as_string(catalog->payload).find("\"initData\":\"") != std::string::npos,
276+
const std::string catalog_text = as_string(catalog->payload);
277+
ok &= expect(catalog_text.find("\"initData\":\"") != std::string::npos,
277278
"expected catalog to embed base64 initData for the track");
279+
ok &= expect(catalog_text.find("\"renderGroup\":1") != std::string::npos,
280+
"expected DASH catalog track to declare its render group");
281+
ok &= expect(catalog_text.find("\"width\":320") != std::string::npos &&
282+
catalog_text.find("\"height\":240") != std::string::npos,
283+
"expected DASH catalog video dimensions for renderer selection");
278284
}
279285
}
280286

tests/moqt_session_test.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2530,16 +2530,24 @@ int main() {
25302530
encode_publish_namespace_ok_message(DraftVersion::kDraft16, 0));
25312531
dash_live_transport.reads[0].push_back(
25322532
encode_subscribe_message(
2533-
1, kTestTrackNamespace, "video0_vide_1", 0, DraftVersion::kDraft16));
2533+
1, kTestTrackNamespace, "catalog", 0, DraftVersion::kDraft16));
2534+
dash_live_transport.reads[0].push_back({});
2535+
dash_live_transport.reads[0].push_back(
2536+
encode_subscribe_message(
2537+
3, kTestTrackNamespace, "video0_vide_1", 0, DraftVersion::kDraft16));
25342538
// Keep the mock control stream open while each queued source object is considered.
25352539
for (int i = 0; i < 4; ++i) {
25362540
dash_live_transport.reads[0].push_back({});
25372541
}
25382542

2539-
bool subscribe_read = false;
2543+
bool catalog_subscribe_read = false;
2544+
bool media_subscribe_read = false;
25402545
dash_live_transport.on_read = [&](MockTransport& transport, std::uint64_t stream_id) {
25412546
if (stream_id == 0 && transport.read_count >= 3) {
2542-
subscribe_read = true;
2547+
catalog_subscribe_read = true;
2548+
}
2549+
if (stream_id == 0 && transport.read_count >= 5) {
2550+
media_subscribe_read = true;
25432551
}
25442552
};
25452553

@@ -2551,6 +2559,7 @@ int main() {
25512559
};
25522560
std::size_t object_index = 0;
25532561
bool consumed_before_subscribe = false;
2562+
bool media_consumed_before_media_subscribe = false;
25542563
LiveObjectSource source{
25552564
.tracks = {
25562565
LiveTrack{.track_name = "catalog"},
@@ -2559,7 +2568,9 @@ int main() {
25592568
LiveTrack{.track_name = "video2_vide_3"},
25602569
},
25612570
.next_object = [&]() -> std::optional<LiveObject> {
2562-
consumed_before_subscribe = consumed_before_subscribe || !subscribe_read;
2571+
consumed_before_subscribe = consumed_before_subscribe || !catalog_subscribe_read;
2572+
media_consumed_before_media_subscribe =
2573+
media_consumed_before_media_subscribe || (object_index > 0 && !media_subscribe_read);
25632574
if (object_index >= objects.size()) {
25642575
return std::nullopt;
25652576
}
@@ -2578,11 +2589,13 @@ int main() {
25782589
ok &= expect(status.ok, "expected FFmpeg-style DASH session connect to succeed");
25792590
status = dash_live_session.publish_live_objects(source, DraftVersion::kDraft16);
25802591
ok &= expect(status.ok, "expected FFmpeg-style DASH publish to enter await-subscribe mode");
2581-
ok &= expect(subscribe_read && !consumed_before_subscribe,
2592+
ok &= expect(catalog_subscribe_read && media_subscribe_read && !consumed_before_subscribe,
25822593
"expected FFmpeg-style DASH media consumption to wait for SUBSCRIBE");
2594+
ok &= expect(!media_consumed_before_media_subscribe,
2595+
"expected catalog-first subscription to preserve queued media until media SUBSCRIBE");
25832596
ok &= expect(control_message_count(dash_live_transport, 0x1d) == 4,
25842597
"expected catalog plus three FFmpeg-style DASH tracks to be published");
2585-
ok &= expect(control_message_count(dash_live_transport, 0x04) == 1,
2598+
ok &= expect(control_message_count(dash_live_transport, 0x04) == 2,
25862599
"expected FFmpeg-style DASH subscriber to receive SUBSCRIBE_OK");
25872600
ok &= expect(dash_live_session.publish_stats().objects_published == 2,
25882601
"expected catalog and subscribed FFmpeg-style DASH representation only");

0 commit comments

Comments
 (0)