@moqtap/codec 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-5XZKO2U5.js → chunk-2XH6PHXR.js} +62 -51
- package/dist/{chunk-APTV6F72.js → chunk-3YAR3I3S.js} +67 -51
- package/dist/{chunk-BQHLUT37.cjs → chunk-7ENEWAMZ.cjs} +2 -6
- package/dist/{chunk-MD2OA7SE.js → chunk-BV6MITLO.js} +15 -8
- package/dist/{chunk-B56AG5HU.cjs → chunk-EVCPBFSR.cjs} +6 -4
- package/dist/{chunk-KNLPX3YA.js → chunk-H6DTAIWM.js} +6 -4
- package/dist/{chunk-J3ASFPCX.cjs → chunk-IADVBKEJ.cjs} +15 -8
- package/dist/{chunk-I55J3KXD.js → chunk-NH4L6NIY.js} +48 -33
- package/dist/{chunk-EQAYMCXO.cjs → chunk-PU2KV7VP.cjs} +48 -33
- package/dist/{chunk-HEO2JG6C.js → chunk-TMXRYOBS.js} +100 -92
- package/dist/{chunk-IEJULBKB.cjs → chunk-UA5XFP4O.cjs} +100 -92
- package/dist/{chunk-KTVN4P6J.cjs → chunk-UZO5Z2XT.cjs} +62 -51
- package/dist/{chunk-MH7537FB.cjs → chunk-VWXUT5R2.cjs} +67 -51
- package/dist/{chunk-JJEN2VG5.js → chunk-XQGEOFGE.js} +2 -6
- package/dist/{codec-BnamSx7L.d.cts → codec-N3g1lxQQ.d.cts} +1 -1
- package/dist/{codec-CFhUGTu2.d.ts → codec-v6Vloc7H.d.ts} +1 -1
- package/dist/draft12.cjs +2 -2
- package/dist/draft12.js +1 -1
- package/dist/draft14-session.d.cts +1 -1
- package/dist/draft14-session.d.ts +1 -1
- package/dist/draft14.cjs +2 -2
- package/dist/draft14.d.cts +3 -3
- package/dist/draft14.d.ts +3 -3
- package/dist/draft14.js +1 -1
- package/dist/draft15.cjs +2 -2
- package/dist/draft15.js +1 -1
- package/dist/draft16.cjs +2 -2
- package/dist/draft16.js +1 -1
- package/dist/draft17.cjs +2 -2
- package/dist/draft17.js +1 -1
- package/dist/draft18.cjs +2 -2
- package/dist/draft18.js +1 -1
- package/dist/draft19.cjs +2 -2
- package/dist/draft19.js +1 -1
- package/dist/index.cjs +14 -14
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -7
- package/dist/session.d.cts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/{types-CVeKIk7A.d.cts → types-HI_bbXka.d.cts} +0 -2
- package/dist/{types-CVeKIk7A.d.ts → types-HI_bbXka.d.ts} +0 -2
- package/package.json +2 -2
- package/src/drafts/draft12/data-streams.ts +13 -4
- package/src/drafts/draft14/codec.ts +2 -6
- package/src/drafts/draft14/types.ts +0 -2
- package/src/drafts/draft15/data-streams.ts +30 -16
- package/src/drafts/draft16/codec.ts +116 -93
- package/src/drafts/draft17/codec.ts +72 -35
- package/src/drafts/draft18/codec.ts +89 -53
- package/src/drafts/draft19/codec.ts +94 -53
|
@@ -264,6 +264,47 @@ const PARAM_GROUP_ORDER = 0x22n
|
|
|
264
264
|
const PARAM_NEW_GROUP_REQUEST = 0x32n
|
|
265
265
|
const PARAM_TRACK_NAMESPACE_PREFIX = 0x34n
|
|
266
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Which messages each Message Parameter's own definition names.
|
|
269
|
+
*
|
|
270
|
+
* Section 10.2.1: "Each Message Parameter definition indicates the message types in
|
|
271
|
+
* which it can appear. If it appears in some other type of message, the
|
|
272
|
+
* receiving endpoint MUST close the connection with a PROTOCOL_VIOLATION."
|
|
273
|
+
* Drafts up to and including 16 end that sentence "it MUST be ignored", so this
|
|
274
|
+
* table has no counterpart there.
|
|
275
|
+
*
|
|
276
|
+
* A parameter type absent from this table is one no definition restricts. A
|
|
277
|
+
* type this draft does not define at all never reaches here: it is refused as
|
|
278
|
+
* unknown while its scope is still undecidable.
|
|
279
|
+
*/
|
|
280
|
+
const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
|
|
281
|
+
[0x02n, new Set(['request_ok', 'subscribe', 'request_update'])],
|
|
282
|
+
[
|
|
283
|
+
0x03n,
|
|
284
|
+
new Set([
|
|
285
|
+
'publish',
|
|
286
|
+
'subscribe',
|
|
287
|
+
'request_update',
|
|
288
|
+
'subscribe_namespace',
|
|
289
|
+
'subscribe_tracks',
|
|
290
|
+
'publish_namespace',
|
|
291
|
+
'track_status',
|
|
292
|
+
'fetch',
|
|
293
|
+
]),
|
|
294
|
+
],
|
|
295
|
+
[0x04n, new Set(['subscribe'])],
|
|
296
|
+
[0x06n, new Set(['request_ok', 'subscribe', 'request_update'])],
|
|
297
|
+
[0x08n, new Set(['subscribe_ok', 'publish', 'request_ok'])],
|
|
298
|
+
[0x09n, new Set(['subscribe_ok', 'publish', 'request_ok'])],
|
|
299
|
+
[0x0an, new Set(['fetch'])],
|
|
300
|
+
[0x10n, new Set(['subscribe', 'request_update', 'publish', 'request_ok', 'subscribe_tracks'])],
|
|
301
|
+
[0x20n, new Set(['subscribe', 'fetch', 'request_update', 'request_ok'])],
|
|
302
|
+
[0x21n, new Set(['subscribe', 'request_ok', 'request_update'])],
|
|
303
|
+
[0x22n, new Set(['subscribe', 'request_ok', 'fetch'])],
|
|
304
|
+
[0x32n, new Set(['request_ok', 'subscribe', 'request_update'])],
|
|
305
|
+
[0x34n, new Set(['request_update'])],
|
|
306
|
+
])
|
|
307
|
+
|
|
267
308
|
function encodeParams(params: Draft18Params, writer: BufferWriter): void {
|
|
268
309
|
// Collect and sort params by type
|
|
269
310
|
const entries: Array<{ type: bigint; encode: (w: BufferWriter) => void }> = []
|
|
@@ -307,13 +348,12 @@ function encodeParams(params: Draft18Params, writer: BufferWriter): void {
|
|
|
307
348
|
if (params.largest_object !== undefined) {
|
|
308
349
|
entries.push({
|
|
309
350
|
type: PARAM_LARGEST_OBJECT,
|
|
351
|
+
// A Location is "Two consecutive varints (Group, Object)", which is a
|
|
352
|
+
// different value encoding from "Length-prefixed". Nothing states the
|
|
353
|
+
// length, so nothing writes one.
|
|
310
354
|
encode: (w) => {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
tmpW.writeVarInt(params.largest_object!.object)
|
|
314
|
-
const raw = tmpW.finish()
|
|
315
|
-
w.writeVarInt(BigInt(raw.byteLength))
|
|
316
|
-
w.writeBytes(raw)
|
|
355
|
+
w.writeVarInt(params.largest_object!.group)
|
|
356
|
+
w.writeVarInt(params.largest_object!.object)
|
|
317
357
|
},
|
|
318
358
|
})
|
|
319
359
|
}
|
|
@@ -370,12 +410,11 @@ function encodeParams(params: Draft18Params, writer: BufferWriter): void {
|
|
|
370
410
|
if (params.track_namespace_prefix !== undefined) {
|
|
371
411
|
entries.push({
|
|
372
412
|
type: PARAM_TRACK_NAMESPACE_PREFIX,
|
|
413
|
+
// The parameter "uses the Track Namespace encoding", which is a tuple
|
|
414
|
+
// that states its own field count. That is not the Length-prefixed
|
|
415
|
+
// encoding, so there is no byte length ahead of it.
|
|
373
416
|
encode: (w) => {
|
|
374
|
-
|
|
375
|
-
encodeNamespaceTuple(params.track_namespace_prefix!, tmpW)
|
|
376
|
-
const raw = tmpW.finish()
|
|
377
|
-
w.writeVarInt(BigInt(raw.byteLength))
|
|
378
|
-
w.writeBytes(raw)
|
|
417
|
+
encodeNamespaceTuple(params.track_namespace_prefix!, w)
|
|
379
418
|
},
|
|
380
419
|
})
|
|
381
420
|
}
|
|
@@ -406,10 +445,9 @@ function encodeParams(params: Draft18Params, writer: BufferWriter): void {
|
|
|
406
445
|
}
|
|
407
446
|
}
|
|
408
447
|
|
|
409
|
-
function decodeParams(reader: BufferReader): Draft18Params {
|
|
448
|
+
function decodeParams(reader: BufferReader, messageType: string): Draft18Params {
|
|
410
449
|
const count = Number(reader.readVarInt())
|
|
411
450
|
const result: Draft18Params = {}
|
|
412
|
-
const unknown: UnknownParam[] = []
|
|
413
451
|
let prevType = 0n
|
|
414
452
|
|
|
415
453
|
for (let i = 0; i < count; i++) {
|
|
@@ -417,6 +455,15 @@ function decodeParams(reader: BufferReader): Draft18Params {
|
|
|
417
455
|
const paramType = prevType + delta
|
|
418
456
|
prevType = paramType
|
|
419
457
|
|
|
458
|
+
const scope = PARAMETER_SCOPE.get(paramType)
|
|
459
|
+
if (scope !== undefined && !scope.has(messageType)) {
|
|
460
|
+
throw new DecodeError(
|
|
461
|
+
'CONSTRAINT_VIOLATION',
|
|
462
|
+
`Message Parameter 0x${paramType.toString(16)} may not appear in ${messageType}`,
|
|
463
|
+
reader.offset,
|
|
464
|
+
)
|
|
465
|
+
}
|
|
466
|
+
|
|
420
467
|
if (paramType === PARAM_OBJECT_DELIVERY_TIMEOUT) {
|
|
421
468
|
result.object_delivery_timeout = reader.readVarInt()
|
|
422
469
|
} else if (paramType === PARAM_AUTHORIZATION_TOKEN) {
|
|
@@ -430,13 +477,9 @@ function decodeParams(reader: BufferReader): Draft18Params {
|
|
|
430
477
|
} else if (paramType === PARAM_EXPIRES) {
|
|
431
478
|
result.expires = reader.readVarInt()
|
|
432
479
|
} else if (paramType === PARAM_LARGEST_OBJECT) {
|
|
433
|
-
//
|
|
434
|
-
const length = Number(reader.readVarInt())
|
|
435
|
-
const startOff = reader.offset
|
|
480
|
+
// Location: 2 bare varints (not length-prefixed)
|
|
436
481
|
const group = reader.readVarInt()
|
|
437
482
|
const object = reader.readVarInt()
|
|
438
|
-
const consumed = reader.offset - startOff
|
|
439
|
-
if (consumed < length) reader.readBytes(length - consumed)
|
|
440
483
|
result.largest_object = { group, object }
|
|
441
484
|
} else if (paramType === PARAM_FILL_TIMEOUT) {
|
|
442
485
|
result.fill_timeout = reader.readVarInt()
|
|
@@ -473,34 +516,27 @@ function decodeParams(reader: BufferReader): Draft18Params {
|
|
|
473
516
|
} else if (paramType === PARAM_NEW_GROUP_REQUEST) {
|
|
474
517
|
result.new_group_request = reader.readVarInt()
|
|
475
518
|
} else if (paramType === PARAM_TRACK_NAMESPACE_PREFIX) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
result.track_namespace_prefix = decodeNamespaceTuple(
|
|
519
|
+
// Track Namespace encoding, read in place: the tuple's own field count
|
|
520
|
+
// bounds it.
|
|
521
|
+
result.track_namespace_prefix = decodeNamespaceTuple(reader)
|
|
479
522
|
} else {
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
unknown.push({
|
|
495
|
-
id: `0x${paramType.toString(16)}`,
|
|
496
|
-
length,
|
|
497
|
-
raw_hex: bytesToHex(bytes),
|
|
498
|
-
})
|
|
499
|
-
}
|
|
523
|
+
// Drafts 16 and later: "All Message Parameters MUST be defined in the
|
|
524
|
+
// negotiated version of MOQT or negotiated via Setup Options. An
|
|
525
|
+
// endpoint that receives an unknown Message Parameter MUST close the
|
|
526
|
+
// session with PROTOCOL_VIOLATION." (Section 10.2)
|
|
527
|
+
//
|
|
528
|
+
// There is no skipping an unknown one and carrying on: the value's
|
|
529
|
+
// encoding comes from its definition, so a receiver that does not know
|
|
530
|
+
// the Type does not know how many bytes it spans either. Drafts 11
|
|
531
|
+
// through 15 say the opposite and keep collecting them.
|
|
532
|
+
throw new DecodeError(
|
|
533
|
+
'INVALID_PARAMETER',
|
|
534
|
+
`Unknown Message Parameter type 0x${paramType.toString(16)}`,
|
|
535
|
+
reader.offset,
|
|
536
|
+
)
|
|
500
537
|
}
|
|
501
538
|
}
|
|
502
539
|
|
|
503
|
-
if (unknown.length > 0) result.unknown = unknown
|
|
504
540
|
return result
|
|
505
541
|
}
|
|
506
542
|
|
|
@@ -843,7 +879,7 @@ function decodeSubscribePayload(r: BufferReader): Draft18Message {
|
|
|
843
879
|
const request_id = r.readVarInt()
|
|
844
880
|
const track_namespace = r.readTuple()
|
|
845
881
|
const track_name = r.readString()
|
|
846
|
-
const parameters = decodeParams(r)
|
|
882
|
+
const parameters = decodeParams(r, 'subscribe')
|
|
847
883
|
return {
|
|
848
884
|
type: 'subscribe',
|
|
849
885
|
request_id,
|
|
@@ -855,14 +891,14 @@ function decodeSubscribePayload(r: BufferReader): Draft18Message {
|
|
|
855
891
|
|
|
856
892
|
function decodeSubscribeOkPayload(r: BufferReader, payloadEnd: number): Draft18Message {
|
|
857
893
|
const track_alias = r.readVarInt()
|
|
858
|
-
const parameters = decodeParams(r)
|
|
894
|
+
const parameters = decodeParams(r, 'subscribe_ok')
|
|
859
895
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
860
896
|
return { type: 'subscribe_ok', track_alias, parameters, track_properties }
|
|
861
897
|
}
|
|
862
898
|
|
|
863
899
|
function decodeRequestUpdatePayload(r: BufferReader): Draft18Message {
|
|
864
900
|
const request_id = r.readVarInt()
|
|
865
|
-
const parameters = decodeParams(r)
|
|
901
|
+
const parameters = decodeParams(r, 'request_update')
|
|
866
902
|
return {
|
|
867
903
|
type: 'request_update',
|
|
868
904
|
request_id,
|
|
@@ -875,7 +911,7 @@ function decodePublishPayload(r: BufferReader, payloadEnd: number): Draft18Messa
|
|
|
875
911
|
const track_namespace = r.readTuple()
|
|
876
912
|
const track_name = r.readString()
|
|
877
913
|
const track_alias = r.readVarInt()
|
|
878
|
-
const parameters = decodeParams(r)
|
|
914
|
+
const parameters = decodeParams(r, 'publish')
|
|
879
915
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
880
916
|
return {
|
|
881
917
|
type: 'publish',
|
|
@@ -898,7 +934,7 @@ function decodePublishDonePayload(r: BufferReader): Draft18Message {
|
|
|
898
934
|
function decodePublishNamespacePayload(r: BufferReader): Draft18Message {
|
|
899
935
|
const request_id = r.readVarInt()
|
|
900
936
|
const track_namespace = r.readTuple()
|
|
901
|
-
const parameters = decodeParams(r)
|
|
937
|
+
const parameters = decodeParams(r, 'publish_namespace')
|
|
902
938
|
return {
|
|
903
939
|
type: 'publish_namespace',
|
|
904
940
|
request_id,
|
|
@@ -920,7 +956,7 @@ function decodeNamespaceDonePayload(r: BufferReader): Draft18Message {
|
|
|
920
956
|
function decodeSubscribeNamespacePayload(r: BufferReader): Draft18Message {
|
|
921
957
|
const request_id = r.readVarInt()
|
|
922
958
|
const namespace_prefix = r.readTuple()
|
|
923
|
-
const parameters = decodeParams(r)
|
|
959
|
+
const parameters = decodeParams(r, 'subscribe_namespace')
|
|
924
960
|
return {
|
|
925
961
|
type: 'subscribe_namespace',
|
|
926
962
|
request_id,
|
|
@@ -932,7 +968,7 @@ function decodeSubscribeNamespacePayload(r: BufferReader): Draft18Message {
|
|
|
932
968
|
function decodeSubscribeTracksPayload(r: BufferReader): Draft18Message {
|
|
933
969
|
const request_id = r.readVarInt()
|
|
934
970
|
const namespace_prefix = r.readTuple()
|
|
935
|
-
const parameters = decodeParams(r)
|
|
971
|
+
const parameters = decodeParams(r, 'subscribe_tracks')
|
|
936
972
|
return {
|
|
937
973
|
type: 'subscribe_tracks',
|
|
938
974
|
request_id,
|
|
@@ -980,7 +1016,7 @@ function decodeFetchPayload(r: BufferReader): Draft18Message {
|
|
|
980
1016
|
joining = { joining_request_id, joining_start }
|
|
981
1017
|
}
|
|
982
1018
|
|
|
983
|
-
const parameters = decodeParams(r)
|
|
1019
|
+
const parameters = decodeParams(r, 'fetch')
|
|
984
1020
|
|
|
985
1021
|
return {
|
|
986
1022
|
type: 'fetch',
|
|
@@ -996,7 +1032,7 @@ function decodeFetchOkPayload(r: BufferReader, payloadEnd: number): Draft18Messa
|
|
|
996
1032
|
const end_of_track = r.readUint8()
|
|
997
1033
|
const end_group = r.readVarInt()
|
|
998
1034
|
const end_object = r.readVarInt()
|
|
999
|
-
const parameters = decodeParams(r)
|
|
1035
|
+
const parameters = decodeParams(r, 'fetch_ok')
|
|
1000
1036
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
1001
1037
|
return {
|
|
1002
1038
|
type: 'fetch_ok',
|
|
@@ -1012,7 +1048,7 @@ function decodeTrackStatusPayload(r: BufferReader): Draft18Message {
|
|
|
1012
1048
|
const request_id = r.readVarInt()
|
|
1013
1049
|
const track_namespace = r.readTuple()
|
|
1014
1050
|
const track_name = r.readString()
|
|
1015
|
-
const parameters = decodeParams(r)
|
|
1051
|
+
const parameters = decodeParams(r, 'track_status')
|
|
1016
1052
|
return {
|
|
1017
1053
|
type: 'track_status',
|
|
1018
1054
|
request_id,
|
|
@@ -1023,7 +1059,7 @@ function decodeTrackStatusPayload(r: BufferReader): Draft18Message {
|
|
|
1023
1059
|
}
|
|
1024
1060
|
|
|
1025
1061
|
function decodeRequestOkPayload(r: BufferReader, payloadEnd: number): Draft18Message {
|
|
1026
|
-
const parameters = decodeParams(r)
|
|
1062
|
+
const parameters = decodeParams(r, 'request_ok')
|
|
1027
1063
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
1028
1064
|
return { type: 'request_ok', parameters, track_properties }
|
|
1029
1065
|
}
|
|
@@ -347,6 +347,52 @@ function decodeRangeFilter(reader: BufferReader, hasProperty: boolean): RangeFil
|
|
|
347
347
|
return property_type !== undefined ? { set_id, property_type, ranges } : { set_id, ranges }
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Which messages each Message Parameter's own definition names.
|
|
352
|
+
*
|
|
353
|
+
* Section 10.2.1: "Each Message Parameter definition indicates the message types in
|
|
354
|
+
* which it can appear. If it appears in some other type of message, the
|
|
355
|
+
* receiving endpoint MUST close the connection with a PROTOCOL_VIOLATION."
|
|
356
|
+
* Drafts up to and including 16 end that sentence "it MUST be ignored", so this
|
|
357
|
+
* table has no counterpart there.
|
|
358
|
+
*
|
|
359
|
+
* A parameter type absent from this table is one no definition restricts. A
|
|
360
|
+
* type this draft does not define at all never reaches here: it is refused as
|
|
361
|
+
* unknown while its scope is still undecidable.
|
|
362
|
+
*/
|
|
363
|
+
const PARAMETER_SCOPE = new Map<bigint, Set<string>>([
|
|
364
|
+
[0x02n, new Set(['request_ok', 'subscribe', 'request_update', 'subscribe_tracks'])],
|
|
365
|
+
[
|
|
366
|
+
0x03n,
|
|
367
|
+
new Set([
|
|
368
|
+
'publish',
|
|
369
|
+
'subscribe',
|
|
370
|
+
'request_update',
|
|
371
|
+
'subscribe_namespace',
|
|
372
|
+
'subscribe_tracks',
|
|
373
|
+
'publish_namespace',
|
|
374
|
+
'track_status',
|
|
375
|
+
'fetch',
|
|
376
|
+
]),
|
|
377
|
+
],
|
|
378
|
+
[0x04n, new Set(['subscribe', 'subscribe_tracks'])],
|
|
379
|
+
[0x06n, new Set(['request_ok', 'subscribe', 'request_update', 'subscribe_tracks'])],
|
|
380
|
+
[0x08n, new Set(['subscribe_ok', 'publish', 'request_ok'])],
|
|
381
|
+
[0x09n, new Set(['subscribe_ok', 'publish', 'request_ok'])],
|
|
382
|
+
[0x0an, new Set(['fetch'])],
|
|
383
|
+
[0x10n, new Set(['subscribe', 'request_update', 'publish', 'request_ok', 'subscribe_tracks'])],
|
|
384
|
+
[0x20n, new Set(['subscribe', 'fetch', 'request_update', 'request_ok', 'subscribe_tracks'])],
|
|
385
|
+
[0x21n, new Set(['subscribe', 'request_ok', 'request_update', 'subscribe_tracks'])],
|
|
386
|
+
[0x22n, new Set(['subscribe', 'subscribe_tracks', 'fetch'])],
|
|
387
|
+
[0x25n, new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_ok', 'request_update'])],
|
|
388
|
+
[0x26n, new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_ok', 'request_update'])],
|
|
389
|
+
[0x27n, new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_ok', 'request_update'])],
|
|
390
|
+
[0x28n, new Set(['fetch', 'subscribe', 'subscribe_tracks', 'request_ok', 'request_update'])],
|
|
391
|
+
[0x29n, new Set(['subscribe_tracks', 'request_update'])],
|
|
392
|
+
[0x32n, new Set(['request_ok', 'subscribe', 'request_update', 'subscribe_tracks'])],
|
|
393
|
+
[0x34n, new Set(['request_update'])],
|
|
394
|
+
])
|
|
395
|
+
|
|
350
396
|
function encodeParams(params: Draft19Params, writer: BufferWriter): void {
|
|
351
397
|
// Collect and sort params by type
|
|
352
398
|
const entries: Array<{ type: bigint; encode: (w: BufferWriter) => void }> = []
|
|
@@ -390,13 +436,12 @@ function encodeParams(params: Draft19Params, writer: BufferWriter): void {
|
|
|
390
436
|
if (params.largest_object !== undefined) {
|
|
391
437
|
entries.push({
|
|
392
438
|
type: PARAM_LARGEST_OBJECT,
|
|
439
|
+
// A Location is "Two consecutive varints (Group, Object)", which is a
|
|
440
|
+
// different value encoding from "Length-prefixed". Nothing states the
|
|
441
|
+
// length, so nothing writes one.
|
|
393
442
|
encode: (w) => {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
tmpW.writeVarInt(params.largest_object!.object)
|
|
397
|
-
const raw = tmpW.finish()
|
|
398
|
-
w.writeVarInt(BigInt(raw.byteLength))
|
|
399
|
-
w.writeBytes(raw)
|
|
443
|
+
w.writeVarInt(params.largest_object!.group)
|
|
444
|
+
w.writeVarInt(params.largest_object!.object)
|
|
400
445
|
},
|
|
401
446
|
})
|
|
402
447
|
}
|
|
@@ -483,12 +528,11 @@ function encodeParams(params: Draft19Params, writer: BufferWriter): void {
|
|
|
483
528
|
if (params.track_namespace_prefix !== undefined) {
|
|
484
529
|
entries.push({
|
|
485
530
|
type: PARAM_TRACK_NAMESPACE_PREFIX,
|
|
531
|
+
// The parameter "uses the Track Namespace encoding", which is a tuple
|
|
532
|
+
// that states its own field count. That is not the Length-prefixed
|
|
533
|
+
// encoding, so there is no byte length ahead of it.
|
|
486
534
|
encode: (w) => {
|
|
487
|
-
|
|
488
|
-
encodeNamespaceTuple(params.track_namespace_prefix!, tmpW)
|
|
489
|
-
const raw = tmpW.finish()
|
|
490
|
-
w.writeVarInt(BigInt(raw.byteLength))
|
|
491
|
-
w.writeBytes(raw)
|
|
535
|
+
encodeNamespaceTuple(params.track_namespace_prefix!, w)
|
|
492
536
|
},
|
|
493
537
|
})
|
|
494
538
|
}
|
|
@@ -519,10 +563,9 @@ function encodeParams(params: Draft19Params, writer: BufferWriter): void {
|
|
|
519
563
|
}
|
|
520
564
|
}
|
|
521
565
|
|
|
522
|
-
function decodeParams(reader: BufferReader): Draft19Params {
|
|
566
|
+
function decodeParams(reader: BufferReader, messageType: string): Draft19Params {
|
|
523
567
|
const count = Number(reader.readVarInt())
|
|
524
568
|
const result: Draft19Params = {}
|
|
525
|
-
const unknown: UnknownParam[] = []
|
|
526
569
|
let prevType = 0n
|
|
527
570
|
|
|
528
571
|
for (let i = 0; i < count; i++) {
|
|
@@ -530,6 +573,15 @@ function decodeParams(reader: BufferReader): Draft19Params {
|
|
|
530
573
|
const paramType = prevType + delta
|
|
531
574
|
prevType = paramType
|
|
532
575
|
|
|
576
|
+
const scope = PARAMETER_SCOPE.get(paramType)
|
|
577
|
+
if (scope !== undefined && !scope.has(messageType)) {
|
|
578
|
+
throw new DecodeError(
|
|
579
|
+
'CONSTRAINT_VIOLATION',
|
|
580
|
+
`Message Parameter 0x${paramType.toString(16)} may not appear in ${messageType}`,
|
|
581
|
+
reader.offset,
|
|
582
|
+
)
|
|
583
|
+
}
|
|
584
|
+
|
|
533
585
|
if (paramType === PARAM_OBJECT_DELIVERY_TIMEOUT) {
|
|
534
586
|
result.object_delivery_timeout = reader.readVarInt()
|
|
535
587
|
} else if (paramType === PARAM_AUTHORIZATION_TOKEN) {
|
|
@@ -543,13 +595,9 @@ function decodeParams(reader: BufferReader): Draft19Params {
|
|
|
543
595
|
} else if (paramType === PARAM_EXPIRES) {
|
|
544
596
|
result.expires = reader.readVarInt()
|
|
545
597
|
} else if (paramType === PARAM_LARGEST_OBJECT) {
|
|
546
|
-
//
|
|
547
|
-
const length = Number(reader.readVarInt())
|
|
548
|
-
const startOff = reader.offset
|
|
598
|
+
// Location: 2 bare varints (not length-prefixed)
|
|
549
599
|
const group = reader.readVarInt()
|
|
550
600
|
const object = reader.readVarInt()
|
|
551
|
-
const consumed = reader.offset - startOff
|
|
552
|
-
if (consumed < length) reader.readBytes(length - consumed)
|
|
553
601
|
result.largest_object = { group, object }
|
|
554
602
|
} else if (paramType === PARAM_FILL_TIMEOUT) {
|
|
555
603
|
result.fill_timeout = reader.readVarInt()
|
|
@@ -596,34 +644,27 @@ function decodeParams(reader: BufferReader): Draft19Params {
|
|
|
596
644
|
} else if (paramType === PARAM_NEW_GROUP_REQUEST) {
|
|
597
645
|
result.new_group_request = reader.readVarInt()
|
|
598
646
|
} else if (paramType === PARAM_TRACK_NAMESPACE_PREFIX) {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
result.track_namespace_prefix = decodeNamespaceTuple(
|
|
647
|
+
// Track Namespace encoding, read in place: the tuple's own field count
|
|
648
|
+
// bounds it.
|
|
649
|
+
result.track_namespace_prefix = decodeNamespaceTuple(reader)
|
|
602
650
|
} else {
|
|
603
|
-
//
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
unknown.push({
|
|
618
|
-
id: `0x${paramType.toString(16)}`,
|
|
619
|
-
length,
|
|
620
|
-
raw_hex: bytesToHex(bytes),
|
|
621
|
-
})
|
|
622
|
-
}
|
|
651
|
+
// Drafts 16 and later: "All Message Parameters MUST be defined in the
|
|
652
|
+
// negotiated version of MOQT or negotiated via Setup Options. An
|
|
653
|
+
// endpoint that receives an unknown Message Parameter MUST close the
|
|
654
|
+
// session with PROTOCOL_VIOLATION." (Section 10.2)
|
|
655
|
+
//
|
|
656
|
+
// There is no skipping an unknown one and carrying on: the value's
|
|
657
|
+
// encoding comes from its definition, so a receiver that does not know
|
|
658
|
+
// the Type does not know how many bytes it spans either. Drafts 11
|
|
659
|
+
// through 15 say the opposite and keep collecting them.
|
|
660
|
+
throw new DecodeError(
|
|
661
|
+
'INVALID_PARAMETER',
|
|
662
|
+
`Unknown Message Parameter type 0x${paramType.toString(16)}`,
|
|
663
|
+
reader.offset,
|
|
664
|
+
)
|
|
623
665
|
}
|
|
624
666
|
}
|
|
625
667
|
|
|
626
|
-
if (unknown.length > 0) result.unknown = unknown
|
|
627
668
|
return result
|
|
628
669
|
}
|
|
629
670
|
|
|
@@ -964,7 +1005,7 @@ function decodeSubscribePayload(r: BufferReader): Draft19Message {
|
|
|
964
1005
|
const request_id = r.readVarInt()
|
|
965
1006
|
const track_namespace = r.readTuple()
|
|
966
1007
|
const track_name = r.readString()
|
|
967
|
-
const parameters = decodeParams(r)
|
|
1008
|
+
const parameters = decodeParams(r, 'subscribe')
|
|
968
1009
|
return {
|
|
969
1010
|
type: 'subscribe',
|
|
970
1011
|
request_id,
|
|
@@ -976,14 +1017,14 @@ function decodeSubscribePayload(r: BufferReader): Draft19Message {
|
|
|
976
1017
|
|
|
977
1018
|
function decodeSubscribeOkPayload(r: BufferReader, payloadEnd: number): Draft19Message {
|
|
978
1019
|
const track_alias = r.readVarInt()
|
|
979
|
-
const parameters = decodeParams(r)
|
|
1020
|
+
const parameters = decodeParams(r, 'subscribe_ok')
|
|
980
1021
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
981
1022
|
return { type: 'subscribe_ok', track_alias, parameters, track_properties }
|
|
982
1023
|
}
|
|
983
1024
|
|
|
984
1025
|
function decodeRequestUpdatePayload(r: BufferReader): Draft19Message {
|
|
985
1026
|
const request_id = r.readVarInt()
|
|
986
|
-
const parameters = decodeParams(r)
|
|
1027
|
+
const parameters = decodeParams(r, 'request_update')
|
|
987
1028
|
return {
|
|
988
1029
|
type: 'request_update',
|
|
989
1030
|
request_id,
|
|
@@ -996,7 +1037,7 @@ function decodePublishPayload(r: BufferReader, payloadEnd: number): Draft19Messa
|
|
|
996
1037
|
const track_namespace = r.readTuple()
|
|
997
1038
|
const track_name = r.readString()
|
|
998
1039
|
const track_alias = r.readVarInt()
|
|
999
|
-
const parameters = decodeParams(r)
|
|
1040
|
+
const parameters = decodeParams(r, 'publish')
|
|
1000
1041
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
1001
1042
|
return {
|
|
1002
1043
|
type: 'publish',
|
|
@@ -1019,7 +1060,7 @@ function decodePublishDonePayload(r: BufferReader): Draft19Message {
|
|
|
1019
1060
|
function decodePublishNamespacePayload(r: BufferReader): Draft19Message {
|
|
1020
1061
|
const request_id = r.readVarInt()
|
|
1021
1062
|
const track_namespace = r.readTuple()
|
|
1022
|
-
const parameters = decodeParams(r)
|
|
1063
|
+
const parameters = decodeParams(r, 'publish_namespace')
|
|
1023
1064
|
return {
|
|
1024
1065
|
type: 'publish_namespace',
|
|
1025
1066
|
request_id,
|
|
@@ -1041,7 +1082,7 @@ function decodeNamespaceDonePayload(r: BufferReader): Draft19Message {
|
|
|
1041
1082
|
function decodeSubscribeNamespacePayload(r: BufferReader): Draft19Message {
|
|
1042
1083
|
const request_id = r.readVarInt()
|
|
1043
1084
|
const namespace_prefix = r.readTuple()
|
|
1044
|
-
const parameters = decodeParams(r)
|
|
1085
|
+
const parameters = decodeParams(r, 'subscribe_namespace')
|
|
1045
1086
|
return {
|
|
1046
1087
|
type: 'subscribe_namespace',
|
|
1047
1088
|
request_id,
|
|
@@ -1053,7 +1094,7 @@ function decodeSubscribeNamespacePayload(r: BufferReader): Draft19Message {
|
|
|
1053
1094
|
function decodeSubscribeTracksPayload(r: BufferReader): Draft19Message {
|
|
1054
1095
|
const request_id = r.readVarInt()
|
|
1055
1096
|
const namespace_prefix = r.readTuple()
|
|
1056
|
-
const parameters = decodeParams(r)
|
|
1097
|
+
const parameters = decodeParams(r, 'subscribe_tracks')
|
|
1057
1098
|
return {
|
|
1058
1099
|
type: 'subscribe_tracks',
|
|
1059
1100
|
request_id,
|
|
@@ -1101,7 +1142,7 @@ function decodeFetchPayload(r: BufferReader): Draft19Message {
|
|
|
1101
1142
|
joining = { joining_request_id, joining_start }
|
|
1102
1143
|
}
|
|
1103
1144
|
|
|
1104
|
-
const parameters = decodeParams(r)
|
|
1145
|
+
const parameters = decodeParams(r, 'fetch')
|
|
1105
1146
|
|
|
1106
1147
|
return {
|
|
1107
1148
|
type: 'fetch',
|
|
@@ -1117,7 +1158,7 @@ function decodeFetchOkPayload(r: BufferReader, payloadEnd: number): Draft19Messa
|
|
|
1117
1158
|
const end_of_track = r.readUint8()
|
|
1118
1159
|
const end_group = r.readVarInt()
|
|
1119
1160
|
const end_object = r.readVarInt()
|
|
1120
|
-
const parameters = decodeParams(r)
|
|
1161
|
+
const parameters = decodeParams(r, 'fetch_ok')
|
|
1121
1162
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
1122
1163
|
return {
|
|
1123
1164
|
type: 'fetch_ok',
|
|
@@ -1133,7 +1174,7 @@ function decodeTrackStatusPayload(r: BufferReader): Draft19Message {
|
|
|
1133
1174
|
const request_id = r.readVarInt()
|
|
1134
1175
|
const track_namespace = r.readTuple()
|
|
1135
1176
|
const track_name = r.readString()
|
|
1136
|
-
const parameters = decodeParams(r)
|
|
1177
|
+
const parameters = decodeParams(r, 'track_status')
|
|
1137
1178
|
return {
|
|
1138
1179
|
type: 'track_status',
|
|
1139
1180
|
request_id,
|
|
@@ -1144,7 +1185,7 @@ function decodeTrackStatusPayload(r: BufferReader): Draft19Message {
|
|
|
1144
1185
|
}
|
|
1145
1186
|
|
|
1146
1187
|
function decodeRequestOkPayload(r: BufferReader, payloadEnd: number): Draft19Message {
|
|
1147
|
-
const parameters = decodeParams(r)
|
|
1188
|
+
const parameters = decodeParams(r, 'request_ok')
|
|
1148
1189
|
const track_properties = decodeTrackProperties(r, payloadEnd)
|
|
1149
1190
|
return { type: 'request_ok', parameters, track_properties }
|
|
1150
1191
|
}
|