Refactor MoQT interfaces to consistently pass FullTrackName around. This should make us well-positioned for tuple namespaces and potentially #508. PiperOrigin-RevId: 678730997
diff --git a/build/source_list.bzl b/build/source_list.bzl index e32fc09..bce0f0f 100644 --- a/build/source_list.bzl +++ b/build/source_list.bzl
@@ -1545,6 +1545,7 @@ "quic/moqt/moqt_live_relay_queue.cc", "quic/moqt/moqt_live_relay_queue_test.cc", "quic/moqt/moqt_messages.cc", + "quic/moqt/moqt_messages_test.cc", "quic/moqt/moqt_outgoing_queue.cc", "quic/moqt/moqt_outgoing_queue_test.cc", "quic/moqt/moqt_parser.cc",
diff --git a/build/source_list.gni b/build/source_list.gni index 98d1fc3..9fe8d75 100644 --- a/build/source_list.gni +++ b/build/source_list.gni
@@ -1549,6 +1549,7 @@ "src/quiche/quic/moqt/moqt_live_relay_queue.cc", "src/quiche/quic/moqt/moqt_live_relay_queue_test.cc", "src/quiche/quic/moqt/moqt_messages.cc", + "src/quiche/quic/moqt/moqt_messages_test.cc", "src/quiche/quic/moqt/moqt_outgoing_queue.cc", "src/quiche/quic/moqt/moqt_outgoing_queue_test.cc", "src/quiche/quic/moqt/moqt_parser.cc",
diff --git a/build/source_list.json b/build/source_list.json index e1ed864..e02ea5d 100644 --- a/build/source_list.json +++ b/build/source_list.json
@@ -1548,6 +1548,7 @@ "quiche/quic/moqt/moqt_live_relay_queue.cc", "quiche/quic/moqt/moqt_live_relay_queue_test.cc", "quiche/quic/moqt/moqt_messages.cc", + "quiche/quic/moqt/moqt_messages_test.cc", "quiche/quic/moqt/moqt_outgoing_queue.cc", "quiche/quic/moqt/moqt_outgoing_queue_test.cc", "quiche/quic/moqt/moqt_parser.cc",
diff --git a/quiche/quic/moqt/moqt_framer.cc b/quiche/quic/moqt/moqt_framer.cc index f4ddd7a..c4fe1e1 100644 --- a/quiche/quic/moqt/moqt_framer.cc +++ b/quiche/quic/moqt/moqt_framer.cc
@@ -112,6 +112,27 @@ const IntParameter& parameter_; }; +class WireFullTrackName { + public: + using DataType = FullTrackName; + + explicit WireFullTrackName(const FullTrackName& name) : name_(name) {} + + size_t GetLengthOnWire() { + return quiche::ComputeLengthOnWire( + WireStringWithVarInt62Length(name_.track_namespace()), + WireStringWithVarInt62Length(name_.track_name())); + } + absl::Status SerializeIntoWriter(quiche::QuicheDataWriter& writer) { + return quiche::SerializeIntoWriter( + writer, WireStringWithVarInt62Length(name_.track_namespace()), + WireStringWithVarInt62Length(name_.track_name())); + } + + private: + const FullTrackName& name_; +}; + // Serializes data into buffer using the default allocator. Invokes QUICHE_BUG // on failure. template <typename... Ts> @@ -332,8 +353,7 @@ return Serialize( WireVarInt62(MoqtMessageType::kSubscribe), WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias), - WireStringWithVarInt62Length(message.track_namespace), - WireStringWithVarInt62Length(message.track_name), + WireFullTrackName(message.full_track_name), WireUint8(message.subscriber_priority), WireDeliveryOrder(message.group_order), WireVarInt62(filter_type), WireVarInt62(string_params.size() + int_params.size()), @@ -343,8 +363,7 @@ return Serialize( WireVarInt62(MoqtMessageType::kSubscribe), WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias), - WireStringWithVarInt62Length(message.track_namespace), - WireStringWithVarInt62Length(message.track_name), + WireFullTrackName(message.full_track_name), WireUint8(message.subscriber_priority), WireDeliveryOrder(message.group_order), WireVarInt62(filter_type), WireVarInt62(*message.start_group), @@ -356,8 +375,7 @@ return Serialize( WireVarInt62(MoqtMessageType::kSubscribe), WireVarInt62(message.subscribe_id), WireVarInt62(message.track_alias), - WireStringWithVarInt62Length(message.track_namespace), - WireStringWithVarInt62Length(message.track_name), + WireFullTrackName(message.full_track_name), WireUint8(message.subscriber_priority), WireDeliveryOrder(message.group_order), WireVarInt62(filter_type), WireVarInt62(*message.start_group), @@ -482,8 +500,7 @@ quiche::QuicheBuffer MoqtFramer::SerializeTrackStatusRequest( const MoqtTrackStatusRequest& message) { return Serialize(WireVarInt62(MoqtMessageType::kTrackStatusRequest), - WireStringWithVarInt62Length(message.track_namespace), - WireStringWithVarInt62Length(message.track_name)); + WireFullTrackName(message.full_track_name)); } quiche::QuicheBuffer MoqtFramer::SerializeUnannounce( @@ -495,8 +512,7 @@ quiche::QuicheBuffer MoqtFramer::SerializeTrackStatus( const MoqtTrackStatus& message) { return Serialize(WireVarInt62(MoqtMessageType::kTrackStatus), - WireStringWithVarInt62Length(message.track_namespace), - WireStringWithVarInt62Length(message.track_name), + WireFullTrackName(message.full_track_name), WireVarInt62(message.status_code), WireVarInt62(message.last_group), WireVarInt62(message.last_object));
diff --git a/quiche/quic/moqt/moqt_framer_test.cc b/quiche/quic/moqt/moqt_framer_test.cc index bd19955..55f6944 100644 --- a/quiche/quic/moqt/moqt_framer_test.cc +++ b/quiche/quic/moqt/moqt_framer_test.cc
@@ -302,8 +302,7 @@ MoqtSubscribe subscribe = { /*subscribe_id=*/3, /*track_alias=*/4, - /*track_namespace=*/"foo", - /*track_name=*/"abcd", + /*full_track_name=*/FullTrackName({"foo", "abcd"}), /*subscriber_priority=*/0x20, /*group_order=*/std::nullopt, start_group, @@ -354,8 +353,7 @@ MoqtSubscribe subscribe = { /*subscribe_id=*/3, /*track_alias=*/4, - /*track_namespace=*/"foo", - /*track_name=*/"abcd", + /*full_track_name=*/FullTrackName({"foo", "abcd"}), /*subscriber_priority=*/0x20, /*group_order=*/std::nullopt, /*start_group=*/std::optional<uint64_t>(4), @@ -379,8 +377,7 @@ MoqtSubscribe subscribe = { /*subscribe_id=*/3, /*track_alias=*/4, - /*track_namespace=*/"foo", - /*track_name=*/"abcd", + /*full_track_name=*/FullTrackName({"foo", "abcd"}), /*subscriber_priority=*/0x20, /*group_order=*/std::nullopt, /*start_group=*/std::nullopt,
diff --git a/quiche/quic/moqt/moqt_integration_test.cc b/quiche/quic/moqt/moqt_integration_test.cc index a8a67e7..b6cb671 100644 --- a/quiche/quic/moqt/moqt_integration_test.cc +++ b/quiche/quic/moqt/moqt_integration_test.cc
@@ -158,8 +158,8 @@ std::optional<MoqtAnnounceErrorReason> error) { EXPECT_EQ(track_namespace, "foo"); EXPECT_FALSE(error.has_value()); - server_->session()->SubscribeCurrentGroup(track_namespace, "/catalog", - &server_visitor); + server_->session()->SubscribeCurrentGroup( + FullTrackName(track_namespace, "/catalog"), &server_visitor); }); EXPECT_CALL(server_visitor, OnReply(_, _)).WillOnce([&]() { matches = true; @@ -178,7 +178,7 @@ EXPECT_CALL(server_callbacks_.incoming_announce_callback, Call(_)) .WillOnce([&](absl::string_view track_namespace) { server_->session()->SubscribeAbsolute( - track_namespace, "data", /*start_group=*/0, + FullTrackName(track_namespace, "data"), /*start_group=*/0, /*start_object=*/0, &server_visitor); return std::optional<MoqtAnnounceErrorReason>(); }); @@ -204,8 +204,7 @@ MoqtObjectStatus status, MoqtForwardingPreference forwarding_preference, absl::string_view object, bool end_of_message) { - EXPECT_EQ(full_track_name.track_namespace, "test"); - EXPECT_EQ(full_track_name.track_name, "data"); + EXPECT_EQ(full_track_name, FullTrackName("test", "data")); EXPECT_EQ(group_sequence, 0u); EXPECT_EQ(object_sequence, 0u); EXPECT_EQ(status, MoqtObjectStatus::kNormal); @@ -242,7 +241,8 @@ queue->AddObject(MemSliceFromString("object 4"), /*key=*/true); queue->AddObject(MemSliceFromString("object 5"), /*key=*/false); - client_->session()->SubscribeCurrentGroup("test", name, &client_visitor); + client_->session()->SubscribeCurrentGroup(FullTrackName("test", name), + &client_visitor); int received = 0; EXPECT_CALL(client_visitor, OnObjectFragment(_, 1, 0, _, MoqtObjectStatus::kNormal, _, @@ -301,7 +301,8 @@ queue->AddObject(MemSliceFromString("object"), /*key=*/true); } - client_->session()->SubscribeAbsolute("test", name, 0, 0, &client_visitor); + client_->session()->SubscribeAbsolute(FullTrackName("test", name), 0, 0, + &client_visitor); int received = 0; // Those won't arrive since they have expired. EXPECT_CALL(client_visitor, OnObjectFragment(_, 0, 0, _, _, _, _, true)) @@ -367,9 +368,7 @@ bool received_ok = false; EXPECT_CALL(client_visitor, OnReply(full_track_name, expected_reason)) .WillOnce([&]() { received_ok = true; }); - client_->session()->SubscribeAbsolute(full_track_name.track_namespace, - full_track_name.track_name, 0, 0, - &client_visitor); + client_->session()->SubscribeAbsolute(full_track_name, 0, 0, &client_visitor); bool success = test_harness_.RunUntilWithDefaultTimeout([&]() { return received_ok; }); EXPECT_TRUE(success); @@ -389,9 +388,7 @@ bool received_ok = false; EXPECT_CALL(client_visitor, OnReply(full_track_name, expected_reason)) .WillOnce([&]() { received_ok = true; }); - client_->session()->SubscribeCurrentObject(full_track_name.track_namespace, - full_track_name.track_name, - &client_visitor); + client_->session()->SubscribeCurrentObject(full_track_name, &client_visitor); bool success = test_harness_.RunUntilWithDefaultTimeout([&]() { return received_ok; }); EXPECT_TRUE(success); @@ -411,9 +408,7 @@ bool received_ok = false; EXPECT_CALL(client_visitor, OnReply(full_track_name, expected_reason)) .WillOnce([&]() { received_ok = true; }); - client_->session()->SubscribeCurrentGroup(full_track_name.track_namespace, - full_track_name.track_name, - &client_visitor); + client_->session()->SubscribeCurrentGroup(full_track_name, &client_visitor); bool success = test_harness_.RunUntilWithDefaultTimeout([&]() { return received_ok; }); EXPECT_TRUE(success); @@ -427,9 +422,7 @@ bool received_ok = false; EXPECT_CALL(client_visitor, OnReply(full_track_name, expected_reason)) .WillOnce([&]() { received_ok = true; }); - client_->session()->SubscribeCurrentObject(full_track_name.track_namespace, - full_track_name.track_name, - &client_visitor); + client_->session()->SubscribeCurrentObject(full_track_name, &client_visitor); bool success = test_harness_.RunUntilWithDefaultTimeout([&]() { return received_ok; }); EXPECT_TRUE(success); @@ -467,9 +460,8 @@ MoqtSubscribeParameters parameters; parameters.object_ack_window = quic::QuicTimeDelta::FromMilliseconds(100); - client_->session()->SubscribeCurrentObject(full_track_name.track_namespace, - full_track_name.track_name, - &client_visitor, parameters); + client_->session()->SubscribeCurrentObject(full_track_name, &client_visitor, + parameters); EXPECT_CALL(monitoring, OnObjectAckSupportKnown(true)); EXPECT_CALL( monitoring,
diff --git a/quiche/quic/moqt/moqt_messages.cc b/quiche/quic/moqt/moqt_messages.cc index df357fe..26acbac 100644 --- a/quiche/quic/moqt/moqt_messages.cc +++ b/quiche/quic/moqt/moqt_messages.cc
@@ -5,9 +5,16 @@ #include "quiche/quic/moqt/moqt_messages.h" #include <string> +#include <vector> +#include "absl/algorithm/container.h" +#include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" #include "quiche/quic/platform/api/quic_bug_tracker.h" +#include "quiche/common/platform/api/quiche_bug_tracker.h" namespace moqt { @@ -164,4 +171,35 @@ return MoqtDataStreamType::kObjectStream; } +std::string FullTrackName::ToString() const { + std::vector<std::string> bits; + bits.reserve(tuple_.size()); + for (absl::string_view raw_bit : tuple_) { + bits.push_back(absl::StrCat("\"", absl::CHexEscape(raw_bit), "\"")); + } + return absl::StrCat("{", absl::StrJoin(bits, ", "), "}"); +} + +bool FullTrackName::operator==(const FullTrackName& other) const { + if (tuple_.size() != other.tuple_.size()) { + return false; + } + return absl::c_equal(tuple_, other.tuple_); +} +bool FullTrackName::operator<(const FullTrackName& other) const { + return absl::c_lexicographical_compare(tuple_, other.tuple_); +} +FullTrackName::FullTrackName(absl::Span<const absl::string_view> elements) + : tuple_(elements.begin(), elements.end()) { + if (tuple_.size() < 2) { + QUICHE_BUG(FullTrackName_too_short) + << "Full track name should be at least two elements long"; + // Failsafe. + while (tuple_.size() < 2) { + tuple_.push_back(""); + } + return; + } +} + } // namespace moqt
diff --git a/quiche/quic/moqt/moqt_messages.h b/quiche/quic/moqt/moqt_messages.h index aaf151d..b3db5b7 100644 --- a/quiche/quic/moqt/moqt_messages.h +++ b/quiche/quic/moqt/moqt_messages.h
@@ -9,13 +9,16 @@ #include <cstddef> #include <cstdint> +#include <initializer_list> #include <optional> #include <string> #include <utility> #include <vector> +#include "absl/container/inlined_vector.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "absl/types/span.h" #include "quiche/quic/core/quic_time.h" #include "quiche/quic/core/quic_types.h" #include "quiche/quic/core/quic_versions.h" @@ -151,39 +154,45 @@ std::string reason_phrase; }; -struct FullTrackName { - std::string track_namespace; - std::string track_name; - FullTrackName(absl::string_view ns, absl::string_view name) - : track_namespace(ns), track_name(name) {} - bool operator==(const FullTrackName& other) const { - return track_namespace == other.track_namespace && - track_name == other.track_name; +// Full track name represents a tuple of the track namespace and the the track +// name. (TODO) After draft-06, multiple elements in track namespace will be +// supported; if https://github.com/moq-wg/moq-transport/issues/508 goes +// through, the distinction between different parts will disappear. +class FullTrackName { + public: + explicit FullTrackName(absl::Span<const absl::string_view> elements); + explicit FullTrackName( + std::initializer_list<const absl::string_view> elements) + : FullTrackName(absl::Span<const absl::string_view>( + std::data(elements), std::size(elements))) {} + explicit FullTrackName(absl::string_view ns, absl::string_view name) + : FullTrackName({ns, name}) {} + FullTrackName() : FullTrackName({"", ""}) {} + + std::string ToString() const; + + absl::string_view track_namespace() const { + // TODO: turn into a tuple for draft-06. + return tuple_[0]; } - bool operator<(const FullTrackName& other) const { - return track_namespace < other.track_namespace || - (track_namespace == other.track_namespace && - track_name < other.track_name); - } - FullTrackName& operator=(const FullTrackName& other) { - track_namespace = other.track_namespace; - track_name = other.track_name; - return *this; - } + absl::string_view track_name() const { return tuple_[tuple_.size() - 1]; } + + bool operator==(const FullTrackName& other) const; + bool operator<(const FullTrackName& other) const; + template <typename H> - friend H AbslHashValue(H h, const FullTrackName& m); + friend H AbslHashValue(H h, const FullTrackName& m) { + return H::combine(std::move(h), m.tuple_); + } template <typename Sink> friend void AbslStringify(Sink& sink, const FullTrackName& track_name) { - absl::Format(&sink, "(%s; %s)", track_name.track_namespace, - track_name.track_name); + sink.Append(track_name.ToString()); } -}; -template <typename H> -H AbslHashValue(H h, const FullTrackName& m) { - return H::combine(std::move(h), m.track_namespace, m.track_name); -} + private: + absl::InlinedVector<std::string, 2> tuple_; +}; // These are absolute sequence numbers. struct FullSequence { @@ -290,8 +299,7 @@ struct QUICHE_EXPORT MoqtSubscribe { uint64_t subscribe_id; uint64_t track_alias; - std::string track_namespace; - std::string track_name; + FullTrackName full_track_name; MoqtPriority subscriber_priority; std::optional<MoqtDeliveryOrder> group_order; @@ -410,8 +418,7 @@ } struct QUICHE_EXPORT MoqtTrackStatus { - std::string track_namespace; - std::string track_name; + FullTrackName full_track_name; MoqtTrackStatusCode status_code; uint64_t last_group; uint64_t last_object; @@ -422,8 +429,7 @@ }; struct QUICHE_EXPORT MoqtTrackStatusRequest { - std::string track_namespace; - std::string track_name; + FullTrackName full_track_name; }; struct QUICHE_EXPORT MoqtGoAway {
diff --git a/quiche/quic/moqt/moqt_messages_test.cc b/quiche/quic/moqt/moqt_messages_test.cc new file mode 100644 index 0000000..bec3c4b --- /dev/null +++ b/quiche/quic/moqt/moqt_messages_test.cc
@@ -0,0 +1,42 @@ +// Copyright 2024 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "quiche/quic/moqt/moqt_messages.h" + +#include <vector> + +#include "absl/hash/hash.h" +#include "absl/strings/string_view.h" +#include "quiche/common/platform/api/quiche_test.h" + +namespace moqt::test { +namespace { + +TEST(MoqtMessagesTest, FullTrackNameConstructors) { + FullTrackName name1({"foo", "bar"}); + std::vector<absl::string_view> list = {"foo", "bar"}; + FullTrackName name2(list); + EXPECT_EQ(name1, name2); + EXPECT_EQ(absl::HashOf(name1), absl::HashOf(name2)); +} + +TEST(MoqtMessagesTest, FullTrackNameOrder) { + FullTrackName name1({"a", "b"}); + FullTrackName name2({"a", "b", "c"}); + FullTrackName name3({"b", "a"}); + EXPECT_LT(name1, name2); + EXPECT_LT(name2, name3); + EXPECT_LT(name1, name3); +} + +TEST(MoqtMessagesTest, FullTrackNameToString) { + FullTrackName name1({"a", "b"}); + EXPECT_EQ(name1.ToString(), R"({"a", "b"})"); + + FullTrackName name2({"\xff", "\x61"}); + EXPECT_EQ(name2.ToString(), R"({"\xff", "a"})"); +} + +} // namespace +} // namespace moqt::test
diff --git a/quiche/quic/moqt/moqt_parser.cc b/quiche/quic/moqt/moqt_parser.cc index 87c45b9..a00416b 100644 --- a/quiche/quic/moqt/moqt_parser.cc +++ b/quiche/quic/moqt/moqt_parser.cc
@@ -25,6 +25,16 @@ namespace { +bool ReadFullTrackName(quic::QuicDataReader& reader, FullTrackName& out) { + absl::string_view track_namespace, track_name; + if (!reader.ReadStringPieceVarInt62(&track_namespace) || + !reader.ReadStringPieceVarInt62(&track_name)) { + return false; + } + out = FullTrackName({track_namespace, track_name}); + return true; +} + bool ParseDeliveryOrder(uint8_t raw_value, std::optional<MoqtDeliveryOrder>& output) { switch (raw_value) { @@ -400,8 +410,7 @@ uint8_t group_order; if (!reader.ReadVarInt62(&subscribe_request.subscribe_id) || !reader.ReadVarInt62(&subscribe_request.track_alias) || - !reader.ReadStringVarInt62(subscribe_request.track_namespace) || - !reader.ReadStringVarInt62(subscribe_request.track_name) || + !ReadFullTrackName(reader, subscribe_request.full_track_name) || !reader.ReadUInt8(&subscribe_request.subscriber_priority) || !reader.ReadUInt8(&group_order) || !reader.ReadVarInt62(&filter)) { return 0; @@ -706,10 +715,7 @@ size_t MoqtControlParser::ProcessTrackStatusRequest( quic::QuicDataReader& reader) { MoqtTrackStatusRequest track_status_request; - if (!reader.ReadStringVarInt62(track_status_request.track_namespace)) { - return 0; - } - if (!reader.ReadStringVarInt62(track_status_request.track_name)) { + if (!ReadFullTrackName(reader, track_status_request.full_track_name)) { return 0; } visitor_.OnTrackStatusRequestMessage(track_status_request); @@ -728,8 +734,7 @@ size_t MoqtControlParser::ProcessTrackStatus(quic::QuicDataReader& reader) { MoqtTrackStatus track_status; uint64_t value; - if (!reader.ReadStringVarInt62(track_status.track_namespace) || - !reader.ReadStringVarInt62(track_status.track_name) || + if (!ReadFullTrackName(reader, track_status.full_track_name) || !reader.ReadVarInt62(&value) || !reader.ReadVarInt62(&track_status.last_group) || !reader.ReadVarInt62(&track_status.last_object)) {
diff --git a/quiche/quic/moqt/moqt_session.cc b/quiche/quic/moqt/moqt_session.cc index d11f9d2..a411269 100644 --- a/quiche/quic/moqt/moqt_session.cc +++ b/quiche/quic/moqt/moqt_session.cc
@@ -250,14 +250,12 @@ pending_outgoing_announces_[track_namespace] = std::move(announce_callback); } -bool MoqtSession::SubscribeAbsolute(absl::string_view track_namespace, - absl::string_view name, +bool MoqtSession::SubscribeAbsolute(const FullTrackName& name, uint64_t start_group, uint64_t start_object, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters) { MoqtSubscribe message; - message.track_namespace = track_namespace; - message.track_name = name; + message.full_track_name = name; message.subscriber_priority = kDefaultSubscriberPriority; message.group_order = std::nullopt; message.start_group = start_group; @@ -268,8 +266,7 @@ return Subscribe(message, visitor); } -bool MoqtSession::SubscribeAbsolute(absl::string_view track_namespace, - absl::string_view name, +bool MoqtSession::SubscribeAbsolute(const FullTrackName& name, uint64_t start_group, uint64_t start_object, uint64_t end_group, RemoteTrack::Visitor* visitor, @@ -279,8 +276,7 @@ return false; } MoqtSubscribe message; - message.track_namespace = track_namespace; - message.track_name = name; + message.full_track_name = name; message.subscriber_priority = kDefaultSubscriberPriority; message.group_order = std::nullopt; message.start_group = start_group; @@ -291,8 +287,7 @@ return Subscribe(message, visitor); } -bool MoqtSession::SubscribeAbsolute(absl::string_view track_namespace, - absl::string_view name, +bool MoqtSession::SubscribeAbsolute(const FullTrackName& name, uint64_t start_group, uint64_t start_object, uint64_t end_group, uint64_t end_object, RemoteTrack::Visitor* visitor, @@ -306,8 +301,7 @@ return false; } MoqtSubscribe message; - message.track_namespace = track_namespace; - message.track_name = name; + message.full_track_name = name; message.subscriber_priority = kDefaultSubscriberPriority; message.group_order = std::nullopt; message.start_group = start_group; @@ -318,13 +312,11 @@ return Subscribe(message, visitor); } -bool MoqtSession::SubscribeCurrentObject(absl::string_view track_namespace, - absl::string_view name, +bool MoqtSession::SubscribeCurrentObject(const FullTrackName& name, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters) { MoqtSubscribe message; - message.track_namespace = track_namespace; - message.track_name = name; + message.full_track_name = name; message.subscriber_priority = kDefaultSubscriberPriority; message.group_order = std::nullopt; message.start_group = std::nullopt; @@ -335,13 +327,11 @@ return Subscribe(message, visitor); } -bool MoqtSession::SubscribeCurrentGroup(absl::string_view track_namespace, - absl::string_view name, +bool MoqtSession::SubscribeCurrentGroup(const FullTrackName& name, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters) { MoqtSubscribe message; - message.track_namespace = track_namespace; - message.track_name = name; + message.full_track_name = name; message.subscriber_priority = kDefaultSubscriberPriority; message.group_order = std::nullopt; // First object of current group. @@ -399,9 +389,7 @@ return false; } message.subscribe_id = next_subscribe_id_++; - FullTrackName ftn(std::string(message.track_namespace), - std::string(message.track_name)); - auto it = remote_track_aliases_.find(ftn); + auto it = remote_track_aliases_.find(message.full_track_name); if (it != remote_track_aliases_.end()) { message.track_alias = it->second; if (message.track_alias >= next_remote_track_alias_) { @@ -423,7 +411,7 @@ } SendControlMessage(framer_.SerializeSubscribe(message)); QUIC_DLOG(INFO) << ENDPOINT << "Sent SUBSCRIBE message for " - << message.track_namespace << ":" << message.track_name; + << message.full_track_name; active_subscribes_.try_emplace(message.subscribe_id, message, visitor); return true; } @@ -517,7 +505,7 @@ auto subscribe_it = active_subscribes_.find(message.subscribe_id); if (subscribe_it == active_subscribes_.end()) { return std::pair<FullTrackName, RemoteTrack::Visitor*>( - {{"", ""}, nullptr}); + {FullTrackName{"", ""}, nullptr}); } ActiveSubscribe& subscribe = subscribe_it->second; visitor = subscribe.visitor; @@ -527,26 +515,22 @@ Error(MoqtError::kProtocolViolation, "Forwarding preference changes mid-track"); return std::pair<FullTrackName, RemoteTrack::Visitor*>( - {{"", ""}, nullptr}); + {FullTrackName{"", ""}, nullptr}); } } else { subscribe.forwarding_preference = message.forwarding_preference; } - return std::pair<FullTrackName, RemoteTrack::Visitor*>( - {{subscribe.message.track_namespace, subscribe.message.track_name}, - subscribe.visitor}); + return std::make_pair(subscribe.message.full_track_name, subscribe.visitor); } RemoteTrack& track = it->second; if (!track.CheckForwardingPreference(message.forwarding_preference)) { // Incorrect forwarding preference. Error(MoqtError::kProtocolViolation, "Forwarding preference changes mid-track"); - return std::pair<FullTrackName, RemoteTrack::Visitor*>({{"", ""}, nullptr}); + return std::pair<FullTrackName, RemoteTrack::Visitor*>( + {FullTrackName{"", ""}, nullptr}); } - return std::pair<FullTrackName, RemoteTrack::Visitor*>( - {{track.full_track_name().track_namespace, - track.full_track_name().track_name}, - track.visitor()}); + return std::make_pair(track.full_track_name(), track.visitor()); } template <class Parser> @@ -682,10 +666,9 @@ return; } QUIC_DLOG(INFO) << ENDPOINT << "Received a SUBSCRIBE for " - << message.track_namespace << ":" << message.track_name; + << message.full_track_name; - FullTrackName track_name = - FullTrackName{message.track_namespace, message.track_name}; + const FullTrackName& track_name = message.full_track_name; absl::StatusOr<std::shared_ptr<MoqtTrackPublisher>> track_publisher = session_->publisher_->GetTrack(track_name); if (!track_publisher.ok()) { @@ -742,13 +725,13 @@ MoqtSubscribe& subscribe = it->second.message; QUIC_DLOG(INFO) << ENDPOINT << "Received the SUBSCRIBE_OK for " << "subscribe_id = " << message.subscribe_id << " " - << subscribe.track_namespace << ":" << subscribe.track_name; + << subscribe.full_track_name; // Copy the Remote Track from session_->active_subscribes_ to // session_->remote_tracks_. - FullTrackName ftn(subscribe.track_namespace, subscribe.track_name); RemoteTrack::Visitor* visitor = it->second.visitor; auto [track_iter, new_entry] = session_->remote_tracks_.try_emplace( - subscribe.track_alias, ftn, subscribe.track_alias, visitor); + subscribe.track_alias, subscribe.full_track_name, subscribe.track_alias, + visitor); if (it->second.forwarding_preference.has_value()) { if (!track_iter->second.CheckForwardingPreference( *it->second.forwarding_preference)) { @@ -759,7 +742,7 @@ } // TODO: handle expires. if (visitor != nullptr) { - visitor->OnReply(ftn, std::nullopt); + visitor->OnReply(subscribe.full_track_name, std::nullopt); } session_->active_subscribes_.erase(it); } @@ -780,17 +763,17 @@ MoqtSubscribe& subscribe = it->second.message; QUIC_DLOG(INFO) << ENDPOINT << "Received the SUBSCRIBE_ERROR for " << "subscribe_id = " << message.subscribe_id << " (" - << subscribe.track_namespace << ":" << subscribe.track_name - << ")" << ", error = " << static_cast<int>(message.error_code) + << subscribe.full_track_name << ")" + << ", error = " << static_cast<int>(message.error_code) << " (" << message.reason_phrase << ")"; RemoteTrack::Visitor* visitor = it->second.visitor; - FullTrackName ftn(subscribe.track_namespace, subscribe.track_name); if (message.error_code == SubscribeErrorCode::kRetryTrackAlias) { // Automatically resubscribe with new alias. - session_->remote_track_aliases_[ftn] = message.track_alias; + session_->remote_track_aliases_[subscribe.full_track_name] = + message.track_alias; session_->Subscribe(subscribe, visitor); } else if (visitor != nullptr) { - visitor->OnReply(ftn, message.reason_phrase); + visitor->OnReply(subscribe.full_track_name, message.reason_phrase); } session_->active_subscribes_.erase(it); } @@ -983,7 +966,7 @@ subscribe.parameters.object_ack_window.has_value()); } QUIC_DLOG(INFO) << ENDPOINT << "Created subscription for " - << subscribe.track_namespace << ":" << subscribe.track_name; + << subscribe.full_track_name; } MoqtSession::PublishedSubscription::~PublishedSubscription() {
diff --git a/quiche/quic/moqt/moqt_session.h b/quiche/quic/moqt/moqt_session.h index 79104c6..b3124a9 100644 --- a/quiche/quic/moqt/moqt_session.h +++ b/quiche/quic/moqt/moqt_session.h
@@ -116,29 +116,24 @@ // ignored. // Subscribe from (start_group, start_object) to the end of the track. bool SubscribeAbsolute( - absl::string_view track_namespace, absl::string_view name, - uint64_t start_group, uint64_t start_object, + const FullTrackName& name, uint64_t start_group, uint64_t start_object, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters = MoqtSubscribeParameters()); // Subscribe from (start_group, start_object) to the end of end_group. bool SubscribeAbsolute( - absl::string_view track_namespace, absl::string_view name, - uint64_t start_group, uint64_t start_object, uint64_t end_group, - RemoteTrack::Visitor* visitor, + const FullTrackName& name, uint64_t start_group, uint64_t start_object, + uint64_t end_group, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters = MoqtSubscribeParameters()); // Subscribe from (start_group, start_object) to (end_group, end_object). bool SubscribeAbsolute( - absl::string_view track_namespace, absl::string_view name, - uint64_t start_group, uint64_t start_object, uint64_t end_group, - uint64_t end_object, RemoteTrack::Visitor* visitor, + const FullTrackName& name, uint64_t start_group, uint64_t start_object, + uint64_t end_group, uint64_t end_object, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters = MoqtSubscribeParameters()); bool SubscribeCurrentObject( - absl::string_view track_namespace, absl::string_view name, - RemoteTrack::Visitor* visitor, + const FullTrackName& name, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters = MoqtSubscribeParameters()); bool SubscribeCurrentGroup( - absl::string_view track_namespace, absl::string_view name, - RemoteTrack::Visitor* visitor, + const FullTrackName& name, RemoteTrack::Visitor* visitor, MoqtSubscribeParameters parameters = MoqtSubscribeParameters()); webtransport::Session* session() { return session_; }
diff --git a/quiche/quic/moqt/moqt_session_test.cc b/quiche/quic/moqt/moqt_session_test.cc index 25783a3..6c29a4b 100644 --- a/quiche/quic/moqt/moqt_session_test.cc +++ b/quiche/quic/moqt/moqt_session_test.cc
@@ -126,8 +126,7 @@ uint64_t subscribe_id, uint64_t track_alias, uint64_t start_group, uint64_t start_object) { MoqtSubscribe subscribe; - subscribe.track_namespace = publisher->GetTrackName().track_namespace; - subscribe.track_name = publisher->GetTrackName().track_name; + subscribe.full_track_name = publisher->GetTrackName(); subscribe.track_alias = track_alias; subscribe.subscribe_id = subscribe_id; subscribe.start_group = start_group; @@ -314,8 +313,7 @@ MoqtSubscribe request = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/"foo", - /*track_name=*/"bar", + /*full_track_name=*/FullTrackName({"foo", "bar"}), /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -450,8 +448,7 @@ MoqtSubscribe request = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/"foo", - /*track_name=*/"bar", + /*full_track_name=*/FullTrackName({"foo", "bar"}), /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -480,8 +477,7 @@ MoqtSubscribe request = { /*subscribe_id=*/kDefaultInitialMaxSubscribeId + 1, /*track_alias=*/2, - /*track_namespace=*/"foo", - /*track_name=*/"bar", + /*full_track_name=*/FullTrackName({"foo", "bar"}), /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -516,10 +512,10 @@ EXPECT_EQ(*ExtractMessageType(data[0]), MoqtMessageType::kSubscribe); return absl::OkStatus(); }); - EXPECT_TRUE( - session_.SubscribeCurrentGroup("foo", "bar", &remote_track_visitor)); - EXPECT_FALSE( - session_.SubscribeCurrentGroup("foo", "bar", &remote_track_visitor)); + EXPECT_TRUE(session_.SubscribeCurrentGroup(FullTrackName("foo", "bar"), + &remote_track_visitor)); + EXPECT_FALSE(session_.SubscribeCurrentGroup(FullTrackName("foo", "bar"), + &remote_track_visitor)); } TEST_F(MoqtSessionTest, SubscribeWithOk) { @@ -536,7 +532,8 @@ EXPECT_EQ(*ExtractMessageType(data[0]), MoqtMessageType::kSubscribe); return absl::OkStatus(); }); - session_.SubscribeCurrentGroup("foo", "bar", &remote_track_visitor); + session_.SubscribeCurrentGroup(FullTrackName("foo", "bar"), + &remote_track_visitor); MoqtSubscribeOk ok = { /*subscribe_id=*/0, @@ -558,8 +555,8 @@ MoqtSessionPeer::set_next_subscribe_id(&session_, kDefaultInitialMaxSubscribeId + 1); MockRemoteTrackVisitor remote_track_visitor; - EXPECT_FALSE( - session_.SubscribeCurrentGroup("foo", "bar", &remote_track_visitor)); + EXPECT_FALSE(session_.SubscribeCurrentGroup(FullTrackName("foo", "bar"), + &remote_track_visitor)); MoqtMaxSubscribeId max_subscribe_id = { /*max_subscribe_id=*/kDefaultInitialMaxSubscribeId + 1, }; @@ -576,8 +573,8 @@ EXPECT_EQ(*ExtractMessageType(data[0]), MoqtMessageType::kSubscribe); return absl::OkStatus(); }); - EXPECT_TRUE( - session_.SubscribeCurrentGroup("foo", "bar", &remote_track_visitor)); + EXPECT_TRUE(session_.SubscribeCurrentGroup(FullTrackName("foo", "bar"), + &remote_track_visitor)); EXPECT_TRUE(correct_message); } @@ -616,8 +613,7 @@ MoqtSubscribe request = { /*subscribe_id=*/kDefaultInitialMaxSubscribeId + 1, /*track_alias=*/2, - /*track_namespace=*/"foo", - /*track_name=*/"bar", + /*full_track_name=*/FullTrackName({"foo", "bar"}), /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -664,7 +660,8 @@ EXPECT_EQ(*ExtractMessageType(data[0]), MoqtMessageType::kSubscribe); return absl::OkStatus(); }); - session_.SubscribeCurrentGroup("foo", "bar", &remote_track_visitor); + session_.SubscribeCurrentGroup(FullTrackName("foo", "bar"), + &remote_track_visitor); MoqtSubscribeError error = { /*subscribe_id=*/0, @@ -793,8 +790,7 @@ MoqtSubscribe subscribe = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/ftn.track_namespace, - /*track_name=*/ftn.track_name, + /*full_track_name=*/ftn, /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -852,8 +848,7 @@ MoqtSubscribe subscribe = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/ftn.track_namespace, - /*track_name=*/ftn.track_name, + /*full_track_name=*/ftn, /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -914,8 +909,7 @@ MoqtSubscribe subscribe = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/ftn.track_namespace, - /*track_name=*/ftn.track_name, + /*full_track_name=*/ftn, /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -967,8 +961,7 @@ MoqtSubscribe subscribe = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/ftn.track_namespace, - /*track_name=*/ftn.track_name, + /*full_track_name=*/ftn, /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0, @@ -1374,8 +1367,7 @@ MoqtSubscribe request = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/"foo", - /*track_name=*/"bar", + /*full_track_name=*/FullTrackName({"foo", "bar"}), /*subscriber_priority=*/0x80, /*group_order=*/std::nullopt, /*start_group=*/0,
diff --git a/quiche/quic/moqt/test_tools/moqt_test_message.h b/quiche/quic/moqt/test_tools/moqt_test_message.h index 813d4e8..1be7b08 100644 --- a/quiche/quic/moqt/test_tools/moqt_test_message.h +++ b/quiche/quic/moqt/test_tools/moqt_test_message.h
@@ -411,11 +411,7 @@ QUIC_LOG(INFO) << "SUBSCRIBE track alias mismatch"; return false; } - if (cast.track_namespace != subscribe_.track_namespace) { - QUIC_LOG(INFO) << "SUBSCRIBE track namespace mismatch"; - return false; - } - if (cast.track_name != subscribe_.track_name) { + if (cast.full_track_name != subscribe_.full_track_name) { QUIC_LOG(INFO) << "SUBSCRIBE track name mismatch"; return false; } @@ -481,8 +477,7 @@ MoqtSubscribe subscribe_ = { /*subscribe_id=*/1, /*track_alias=*/2, - /*track_namespace=*/"foo", - /*track_name=*/"abcd", + /*full_track_name=*/FullTrackName({"foo", "abcd"}), /*subscriber_priority=*/0x20, /*group_order=*/MoqtDeliveryOrder::kDescending, /*start_group=*/4, @@ -899,11 +894,7 @@ bool EqualFieldValues(MessageStructuredData& values) const override { auto cast = std::get<MoqtTrackStatusRequest>(values); - if (cast.track_namespace != track_status_request_.track_namespace) { - QUIC_LOG(INFO) << "TRACK STATUS REQUEST track namespace mismatch"; - return false; - } - if (cast.track_name != track_status_request_.track_name) { + if (cast.full_track_name != track_status_request_.full_track_name) { QUIC_LOG(INFO) << "TRACK STATUS REQUEST track name mismatch"; return false; } @@ -923,8 +914,7 @@ }; MoqtTrackStatusRequest track_status_request_ = { - /*track_namespace=*/"foo", - /*track_name=*/"abcd", + /*full_track_name=*/FullTrackName({"foo", "abcd"}), }; }; @@ -967,11 +957,7 @@ bool EqualFieldValues(MessageStructuredData& values) const override { auto cast = std::get<MoqtTrackStatus>(values); - if (cast.track_namespace != track_status_.track_namespace) { - QUIC_LOG(INFO) << "TRACK STATUS track namespace mismatch"; - return false; - } - if (cast.track_name != track_status_.track_name) { + if (cast.full_track_name != track_status_.full_track_name) { QUIC_LOG(INFO) << "TRACK STATUS track name mismatch"; return false; } @@ -1004,8 +990,7 @@ }; MoqtTrackStatus track_status_ = { - /*track_namespace=*/"foo", - /*track_name=*/"abcd", + /*full_track_name=*/FullTrackName({"foo", "abcd"}), /*status_code=*/MoqtTrackStatusCode::kInProgress, /*last_group=*/12, /*last_object=*/20,
diff --git a/quiche/quic/moqt/tools/chat_client.cc b/quiche/quic/moqt/tools/chat_client.cc index f5bc8df..9e43485 100644 --- a/quiche/quic/moqt/tools/chat_client.cc +++ b/quiche/quic/moqt/tools/chat_client.cc
@@ -114,7 +114,7 @@ if (full_track_name == client_->chat_strings_->GetCatalogName()) { std::cout << "Subscription to catalog "; } else { - std::cout << "Subscription to user " << full_track_name.track_namespace + std::cout << "Subscription to user " << full_track_name.track_namespace() << " "; } if (reason_phrase.has_value()) { @@ -142,7 +142,7 @@ client_->ProcessCatalog(object, this, group_sequence, object_sequence); return; } - std::string username = full_track_name.track_namespace; + std::string username(full_track_name.track_namespace()); username = username.substr(username.find_last_of('/') + 1); if (!client_->other_users_.contains(username)) { std::cout << "Username " << username << "doesn't exist\n"; @@ -181,15 +181,14 @@ std::cout << "ANNOUNCE for " << track_namespace << " accepted\n"; return; }; - std::cout << "Announcing " << my_track_name.track_namespace << "\n"; - session_->Announce(my_track_name.track_namespace, + std::cout << "Announcing " << my_track_name.track_namespace() << "\n"; + session_->Announce(my_track_name.track_namespace(), std::move(announce_callback)); } remote_track_visitor_ = std::make_unique<RemoteTrackVisitor>(this); FullTrackName catalog_name = chat_strings_->GetCatalogName(); if (!session_->SubscribeCurrentGroup( - catalog_name.track_namespace, catalog_name.track_name, - remote_track_visitor_.get(), + catalog_name, remote_track_visitor_.get(), MoqtSubscribeParameters{username_, std::nullopt})) { std::cout << "Failed to get catalog\n"; return false; @@ -263,9 +262,7 @@ auto new_user = other_users_.emplace( std::make_pair(user, ChatUser(to_subscribe, group_sequence))); ChatUser& user_record = new_user.first->second; - session_->SubscribeCurrentGroup( - user_record.full_track_name.track_namespace, - user_record.full_track_name.track_name, visitor); + session_->SubscribeCurrentGroup(user_record.full_track_name, visitor); subscribes_to_make_++; } else { if (it->second.from_group == group_sequence) {
diff --git a/quiche/quic/moqt/tools/chat_server.cc b/quiche/quic/moqt/tools/chat_server.cc index b1b7b0a..c7c6ce5 100644 --- a/quiche/quic/moqt/tools/chat_server.cc +++ b/quiche/quic/moqt/tools/chat_server.cc
@@ -41,7 +41,7 @@ std::cout << "Malformed ANNOUNCE namespace\n"; return std::nullopt; } - session_->SubscribeCurrentGroup(track_namespace, "", + session_->SubscribeCurrentGroup(FullTrackName({track_namespace, ""}), server_->remote_track_visitor()); server_->AddUser(*username_); return std::nullopt; @@ -69,7 +69,7 @@ void ChatServer::RemoteTrackVisitor::OnReply( const moqt::FullTrackName& full_track_name, std::optional<absl::string_view> reason_phrase) { - std::cout << "Subscription to user " << full_track_name.track_namespace + std::cout << "Subscription to user " << full_track_name.track_namespace() << " "; if (reason_phrase.has_value()) { std::cout << "REJECTED, reason = " << *reason_phrase << "\n";
diff --git a/quiche/quic/moqt/tools/moq_chat.h b/quiche/quic/moqt/tools/moq_chat.h index e2f9041..1e6ac66 100644 --- a/quiche/quic/moqt/tools/moq_chat.h +++ b/quiche/quic/moqt/tools/moq_chat.h
@@ -47,10 +47,10 @@ std::string GetUsernameFromFullTrackName( FullTrackName full_track_name) const { // Check the full path - if (!full_track_name.track_name.empty()) { + if (!full_track_name.track_name().empty()) { return ""; } - return GetUsernameFromTrackNamespace(full_track_name.track_namespace); + return GetUsernameFromTrackNamespace(full_track_name.track_namespace()); } FullTrackName GetFullTrackNameFromUsername(absl::string_view username) const {
diff --git a/quiche/quic/moqt/tools/moqt_ingestion_server_bin.cc b/quiche/quic/moqt/tools/moqt_ingestion_server_bin.cc index a66eb8d..4e4ac10 100644 --- a/quiche/quic/moqt/tools/moqt_ingestion_server_bin.cc +++ b/quiche/quic/moqt/tools/moqt_ingestion_server_bin.cc
@@ -142,7 +142,8 @@ std::vector<absl::string_view> tracks_to_subscribe = absl::StrSplit(track_list, ',', absl::AllowEmpty()); for (absl::string_view track : tracks_to_subscribe) { - session_->SubscribeCurrentGroup(track_namespace, track, &it->second); + session_->SubscribeCurrentGroup(FullTrackName({track_namespace, track}), + &it->second); } return std::nullopt; @@ -159,9 +160,7 @@ std::optional<absl::string_view> error_reason_phrase) override { if (error_reason_phrase.has_value()) { QUICHE_LOG(ERROR) << "Failed to subscribe to the peer track " - << full_track_name.track_namespace << " " - << full_track_name.track_name << ": " - << *error_reason_phrase; + << full_track_name << ": " << *error_reason_phrase; } } @@ -175,7 +174,7 @@ absl::string_view object, bool /*end_of_message*/) override { std::string file_name = absl::StrCat(group_sequence, "-", object_sequence, - ".", full_track_name.track_name); + ".", full_track_name.track_name()); std::string file_path = quiche::JoinPath(directory_, file_name); std::ofstream output(file_path, std::ios::binary | std::ios::ate); output.write(object.data(), object.size());
diff --git a/quiche/quic/moqt/tools/moqt_simulator_bin.cc b/quiche/quic/moqt/tools/moqt_simulator_bin.cc index 9916eca..6d08147 100644 --- a/quiche/quic/moqt/tools/moqt_simulator_bin.cc +++ b/quiche/quic/moqt/tools/moqt_simulator_bin.cc
@@ -357,8 +357,7 @@ // server does not yet have an active subscription, so the client has // some catching up to do. generator_.Start(); - server_session()->SubscribeCurrentGroup(TrackName().track_namespace, - TrackName().track_name, &receiver_); + server_session()->SubscribeCurrentGroup(TrackName(), &receiver_); simulator_.RunFor(parameters_.duration); // At the end, we wait for eight RTTs until the connection settles down.