@@ -26,14 +26,21 @@ class ObjectReceiverCallback {
2626 virtual void onEndOfStream () = 0;
2727 virtual void onError (ResetStreamErrorCode) = 0;
2828 virtual void onSubscribeDone (SubscribeDone done) = 0;
29+ // Called when SUBSCRIBE_DONE has arrived AND all outstanding subgroup
30+ // streams have closed. Only fires for subscriptions, not fetches.
31+ virtual void onAllDataReceived () {}
2932};
3033
34+ class ObjectReceiver ;
35+
3136class ObjectSubgroupReceiver : public SubgroupConsumer {
3237 std::shared_ptr<ObjectReceiverCallback> callback_{nullptr };
38+ std::shared_ptr<ObjectReceiver> parent_{nullptr };
3339 StreamType streamType_;
3440 ObjectHeader header_;
3541 folly::IOBufQueue payload_{folly::IOBufQueue::cacheChainLength ()};
3642 folly::Optional<TrackAlias> trackAlias_;
43+ bool finished_{false };
3744
3845 public:
3946 explicit ObjectSubgroupReceiver (
@@ -47,6 +54,10 @@ class ObjectSubgroupReceiver : public SubgroupConsumer {
4754 header_(groupID, subgroupID, 0 , priority),
4855 trackAlias_(trackAlias) {}
4956
57+ void setParent (std::shared_ptr<ObjectReceiver> parent) {
58+ parent_ = std::move (parent);
59+ }
60+
5061 void setFetchGroupAndSubgroup (uint64_t groupID, uint64_t subgroupID) {
5162 streamType_ = StreamType::FETCH_HEADER;
5263 header_.group = groupID;
@@ -138,18 +149,29 @@ class ObjectSubgroupReceiver : public SubgroupConsumer {
138149
139150 folly::Expected<folly::Unit, MoQPublishError> endOfSubgroup () override {
140151 callback_->onEndOfStream ();
152+ notifyParentFinished ();
141153 return folly::unit;
142154 }
143155
144156 void reset (ResetStreamErrorCode error) override {
145157 callback_->onError (error);
158+ notifyParentFinished ();
146159 }
160+
161+ private:
162+ void notifyParentFinished ();
147163};
148164
149- class ObjectReceiver : public TrackConsumer , public FetchConsumer {
165+ class ObjectReceiver : public TrackConsumer ,
166+ public FetchConsumer,
167+ public std::enable_shared_from_this<ObjectReceiver> {
150168 std::shared_ptr<ObjectReceiverCallback> callback_{nullptr };
151169 folly::Optional<ObjectSubgroupReceiver> fetchPublisher_;
152170 folly::Optional<TrackAlias> trackAlias_;
171+ // Tracking for onAllDataReceived callback (subscription mode only)
172+ size_t openSubgroups_{0 };
173+ bool subscribeDoneDelivered_{false };
174+ bool allDataCallbackSent_{false };
153175
154176 public:
155177 enum Type { SUBSCRIBE, FETCH };
@@ -171,8 +193,30 @@ class ObjectReceiver : public TrackConsumer, public FetchConsumer {
171193 folly::Expected<std::shared_ptr<SubgroupConsumer>, MoQPublishError>
172194 beginSubgroup (uint64_t groupID, uint64_t subgroupID, Priority priority)
173195 override {
174- return std::make_shared<ObjectSubgroupReceiver>(
196+ ++openSubgroups_;
197+ auto receiver = std::make_shared<ObjectSubgroupReceiver>(
175198 callback_, trackAlias_, groupID, subgroupID, priority);
199+ receiver->setParent (shared_from_this ());
200+ return receiver;
201+ }
202+
203+ // Called when a subgroup stream finishes (via endOfSubgroup or reset)
204+ void onSubgroupFinished () {
205+ if (openSubgroups_ > 0 ) {
206+ --openSubgroups_;
207+ }
208+ maybeFireAllDataReceived ();
209+ }
210+
211+ // Fire onAllDataReceived callback once when both conditions are met:
212+ // 1. SUBSCRIBE_DONE has been received
213+ // 2. All subgroup streams have closed
214+ void maybeFireAllDataReceived () {
215+ if (!allDataCallbackSent_ && subscribeDoneDelivered_ &&
216+ openSubgroups_ == 0 ) {
217+ allDataCallbackSent_ = true ;
218+ callback_->onAllDataReceived ();
219+ }
176220 }
177221
178222 folly::Expected<folly::SemiFuture<folly::Unit>, MoQPublishError>
@@ -222,6 +266,8 @@ class ObjectReceiver : public TrackConsumer, public FetchConsumer {
222266 folly::Expected<folly::Unit, MoQPublishError> subscribeDone (
223267 SubscribeDone subDone) override {
224268 callback_->onSubscribeDone (std::move (subDone));
269+ subscribeDoneDelivered_ = true ;
270+ maybeFireAllDataReceived ();
225271 return folly::unit;
226272 }
227273
@@ -311,4 +357,13 @@ class ObjectReceiver : public TrackConsumer, public FetchConsumer {
311357 }
312358};
313359
360+ // Definition of ObjectSubgroupReceiver::notifyParentFinished() - needs full
361+ // ObjectReceiver definition
362+ inline void ObjectSubgroupReceiver::notifyParentFinished () {
363+ if (parent_ && !finished_) {
364+ finished_ = true ;
365+ parent_->onSubgroupFinished ();
366+ }
367+ }
368+
314369} // namespace moxygen
0 commit comments