MoqtUniStream expects that MoqtTrackPublisher will not deliver empty object fragments. Fix MoqtRelayTrackPublisher (the only child class that can deliver fragments) to not do that, thus avoiding the QUICHE_BUG OutgoingSubgroupStream_empty_payload. PiperOrigin-RevId: 955873210
diff --git a/quiche/quic/moqt/moqt_publisher.h b/quiche/quic/moqt/moqt_publisher.h index f978df2..059bf9f 100644 --- a/quiche/quic/moqt/moqt_publisher.h +++ b/quiche/quic/moqt/moqt_publisher.h
@@ -83,7 +83,8 @@ // whenever they are sent. Once an object is not available via the cache, it // can no longer be sent; this ensures that objects are not buffered forever. // - // This method returns nullopt if the object is not currently available. + // This method returns nullopt if the object is not available, or a fragment + // at |offset| > 0 is not available. // If |subgroup| is nullopt, the object is a datagram. virtual std::optional<PublishedObject> GetCachedObject( uint64_t group, std::optional<uint64_t> subgroup, uint64_t min_object,
diff --git a/quiche/quic/moqt/moqt_relay_track_publisher.cc b/quiche/quic/moqt/moqt_relay_track_publisher.cc index 797febe..07dc72d 100644 --- a/quiche/quic/moqt/moqt_relay_track_publisher.cc +++ b/quiche/quic/moqt/moqt_relay_track_publisher.cc
@@ -331,6 +331,10 @@ // No object after the last one received. return std::nullopt; } + if (offset > 0 && object_it->second.payload_received() <= offset) { + // No new data. + return std::nullopt; + } return object_it->second.ToPublishedObject(offset); }
diff --git a/quiche/quic/moqt/moqt_relay_track_publisher_test.cc b/quiche/quic/moqt/moqt_relay_track_publisher_test.cc index e12227d..b2ebd8c 100644 --- a/quiche/quic/moqt/moqt_relay_track_publisher_test.cc +++ b/quiche/quic/moqt/moqt_relay_track_publisher_test.cc
@@ -575,6 +575,27 @@ EXPECT_EQ(payload, "0123456789"); } +// Repro for b/539633547. +TEST_F(MoqtRelayTrackPublisherTest, + GetCachedObjectWithOffsetReturnsNulloptAtEnd) { + SubscribeAndOk(); + Location location = kLargestLocation.Next(); + uint64_t subgroup = 0; + PublishedObjectMetadata metadata = {location, subgroup, + "", MoqtObjectStatus::kNormal, + 128, location.object == 0, + 1000}; + EXPECT_CALL(listener_, + OnNewObjectAvailable(location, Optional(subgroup), 128)); + publisher_.OnObjectFragment(kTrackName, metadata, std::string(900, 'a'), 0); + std::optional<PublishedObject> object = + publisher_.GetCachedObject(location.group, subgroup, location.object, 0); + ASSERT_TRUE(object.has_value()); + object = publisher_.GetCachedObject(location.group, subgroup, location.object, + 900); + EXPECT_FALSE(object.has_value()); +} + } // namespace } // namespace moqt::test