@@ -103,12 +103,13 @@ void MoQCodec::onIngressEnd(
103
103
104
104
void MoQObjectStreamCodec::onIngress (
105
105
std::unique_ptr<folly::IOBuf> data,
106
- bool eom ) {
106
+ bool endOfStream ) {
107
107
onIngressStart (std::move (data));
108
108
folly::io::Cursor cursor (ingress_.front ());
109
+ bool isFetch = std::get_if<SubscribeID>(&curObjectHeader_.trackIdentifier );
109
110
while (!connError_ &&
110
111
((ingress_.chainLength () > 0 && !cursor.isAtEnd ())/* ||
111
- (eom && parseState_ == ParseState::OBJECT_PAYLOAD_NO_LENGTH)*/ )) {
112
+ (endOfStream && parseState_ == ParseState::OBJECT_PAYLOAD_NO_LENGTH)*/ )) {
112
113
switch (parseState_) {
113
114
case ParseState::STREAM_HEADER_TYPE: {
114
115
auto newCursor = cursor;
@@ -146,7 +147,12 @@ void MoQObjectStreamCodec::onIngress(
146
147
connError_ = res.error ();
147
148
break ;
148
149
}
149
- curObjectHeader_.trackIdentifier = SubscribeID (res.value ());
150
+ auto subscribeID = SubscribeID (res.value ());
151
+ curObjectHeader_.trackIdentifier = subscribeID;
152
+ isFetch = true ;
153
+ if (callback_) {
154
+ callback_->onFetchHeader (subscribeID);
155
+ }
150
156
parseState_ = ParseState::MULTI_OBJECT_HEADER;
151
157
cursor = newCursor;
152
158
break ;
@@ -160,6 +166,16 @@ void MoQObjectStreamCodec::onIngress(
160
166
break ;
161
167
}
162
168
curObjectHeader_ = res.value ();
169
+ auto trackAlias =
170
+ std::get_if<TrackAlias>(&curObjectHeader_.trackIdentifier );
171
+ XCHECK (trackAlias);
172
+ if (callback_) {
173
+ callback_->onSubgroup (
174
+ *trackAlias,
175
+ curObjectHeader_.group ,
176
+ curObjectHeader_.subgroup ,
177
+ curObjectHeader_.priority );
178
+ }
163
179
parseState_ = ParseState::MULTI_OBJECT_HEADER;
164
180
cursor = newCursor;
165
181
[[fallthrough]];
@@ -174,84 +190,102 @@ void MoQObjectStreamCodec::onIngress(
174
190
break ;
175
191
}
176
192
curObjectHeader_ = res.value ();
177
- if (callback_) {
178
- callback_->onObjectHeader (std::move (res.value ()));
179
- }
180
193
cursor = newCursor;
181
194
if (curObjectHeader_.status == ObjectStatus::NORMAL) {
182
- parseState_ = ParseState::OBJECT_PAYLOAD;
195
+ XLOG (DBG2) << " Parsing object with length, need="
196
+ << *curObjectHeader_.length
197
+ << " have=" << cursor.totalLength ();
198
+ std::unique_ptr<folly::IOBuf> payload;
199
+ auto chunkLen = cursor.cloneAtMost (payload, *curObjectHeader_.length );
200
+ auto endOfObject = chunkLen == *curObjectHeader_.length ;
201
+ if (endOfStream && !endOfObject) {
202
+ connError_ = ErrorCode::PARSE_ERROR;
203
+ XLOG (DBG4) << __func__ << " " << uint32_t (*connError_);
204
+ break ;
205
+ }
206
+ if (callback_) {
207
+ callback_->onObjectBegin (
208
+ curObjectHeader_.group ,
209
+ curObjectHeader_.subgroup ,
210
+ curObjectHeader_.id ,
211
+ *curObjectHeader_.length ,
212
+ std::move (payload),
213
+ endOfObject,
214
+ endOfStream && cursor.isAtEnd ());
215
+ }
216
+ *curObjectHeader_.length -= chunkLen;
217
+ if (endOfObject) {
218
+ if (endOfStream && cursor.isAtEnd ()) {
219
+ parseState_ = ParseState::STREAM_FIN_DELIVERED;
220
+ } else {
221
+ parseState_ = ParseState::MULTI_OBJECT_HEADER;
222
+ }
223
+ break ;
224
+ } else {
225
+ parseState_ = ParseState::OBJECT_PAYLOAD;
226
+ }
183
227
} else {
184
- parseState_ = ParseState::MULTI_OBJECT_HEADER;
228
+ if (callback_) {
229
+ callback_->onObjectStatus (
230
+ curObjectHeader_.group ,
231
+ curObjectHeader_.subgroup ,
232
+ curObjectHeader_.id ,
233
+ curObjectHeader_.status );
234
+ }
235
+ if (curObjectHeader_.status == ObjectStatus::END_OF_TRACK_AND_GROUP ||
236
+ (!isFetch &&
237
+ curObjectHeader_.status == ObjectStatus::END_OF_GROUP)) {
238
+ parseState_ = ParseState::STREAM_FIN_DELIVERED;
239
+ } else {
240
+ parseState_ = ParseState::MULTI_OBJECT_HEADER;
241
+ }
185
242
break ;
186
243
}
187
244
[[fallthrough]];
188
245
}
189
246
case ParseState::OBJECT_PAYLOAD: {
190
- auto newCursor = cursor;
191
247
// need to check for bufLen == 0?
192
248
std::unique_ptr<folly::IOBuf> payload;
193
249
// TODO: skip clone and do split
194
250
uint64_t chunkLen = 0 ;
195
251
XCHECK (curObjectHeader_.length );
196
252
XLOG (DBG2) << " Parsing object with length, need="
197
253
<< *curObjectHeader_.length ;
198
- if (ingress_.chainLength () > 0 && newCursor .canAdvance (1 )) {
199
- chunkLen = newCursor .cloneAtMost (payload, *curObjectHeader_.length );
254
+ if (ingress_.chainLength () > 0 && cursor .canAdvance (1 )) {
255
+ chunkLen = cursor .cloneAtMost (payload, *curObjectHeader_.length );
200
256
}
201
257
*curObjectHeader_.length -= chunkLen;
202
- if (eom && *curObjectHeader_.length != 0 ) {
258
+ if (endOfStream && *curObjectHeader_.length != 0 ) {
203
259
connError_ = ErrorCode::PARSE_ERROR;
204
260
XLOG (DBG4) << __func__ << " " << uint32_t (*connError_);
205
261
break ;
206
262
}
207
263
bool endOfObject = (*curObjectHeader_.length == 0 );
208
264
if (callback_ && (payload || endOfObject)) {
209
- callback_->onObjectPayload (
210
- curObjectHeader_.trackIdentifier ,
211
- curObjectHeader_.group ,
212
- curObjectHeader_.id ,
213
- std::move (payload),
214
- endOfObject);
265
+ callback_->onObjectPayload (std::move (payload), endOfObject);
215
266
}
216
267
if (endOfObject) {
217
268
parseState_ = ParseState::MULTI_OBJECT_HEADER;
218
269
}
219
- cursor = newCursor;
220
270
break ;
221
271
}
222
- #if 0
223
- // This code is no longer reachable, but I'm leaving it here in case
224
- // the wire format changes back
225
- case ParseState::OBJECT_PAYLOAD_NO_LENGTH: {
226
- auto newCursor = cursor;
227
- // need to check for bufLen == 0?
228
- std::unique_ptr<folly::IOBuf> payload;
229
- // TODO: skip clone and do split
230
- if (ingress_.chainLength() > 0 && newCursor.canAdvance(1)) {
231
- newCursor.cloneAtMost(payload, std::numeric_limits<uint64_t>::max());
232
- }
233
- XCHECK(!curObjectHeader_.length);
234
- if (callback_ && (payload || eom)) {
235
- callback_->onObjectPayload(
236
- curObjectHeader_.trackIdentifier,
237
- curObjectHeader_.group,
238
- curObjectHeader_.id,
239
- std::move(payload),
240
- eom);
241
- }
242
- if (eom) {
243
- parseState_ = ParseState::FRAME_HEADER_TYPE;
244
- }
245
- cursor = newCursor;
272
+ case ParseState::STREAM_FIN_DELIVERED: {
273
+ XLOG (DBG2) << " Bytes=" << cursor.totalLength ()
274
+ << " remaining in STREAM_FIN_DELIVERED" ;
275
+ connError_ = ErrorCode::PARSE_ERROR;
276
+ break ;
246
277
}
247
- #endif
248
278
}
249
279
}
250
280
size_t remainingLength = 0 ;
251
- if (!eom && !cursor.isAtEnd ()) {
281
+ if (!endOfStream && !cursor.isAtEnd ()) {
252
282
remainingLength = cursor.totalLength (); // must be less than 1 message
253
283
}
254
- onIngressEnd (remainingLength, eom, callback_);
284
+ if (endOfStream && parseState_ != ParseState::STREAM_FIN_DELIVERED &&
285
+ !connError_ && callback_) {
286
+ callback_->onEndOfStream ();
287
+ }
288
+ onIngressEnd (remainingLength, endOfStream, callback_);
255
289
}
256
290
257
291
folly::Expected<folly::Unit, ErrorCode> MoQControlCodec::parseFrame (
0 commit comments