@moqtap/codec 0.1.0
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/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/chunk-23YG7F46.js +764 -0
- package/dist/chunk-2NARXGVA.cjs +194 -0
- package/dist/chunk-3BSZ55L3.cjs +307 -0
- package/dist/chunk-5WFXFLL4.cjs +1185 -0
- package/dist/chunk-DC4L6ZIT.js +307 -0
- package/dist/chunk-GDRGWFEK.cjs +498 -0
- package/dist/chunk-IQPDRQVC.js +1185 -0
- package/dist/chunk-QYG6KGOV.cjs +101 -0
- package/dist/chunk-UOBWHJA5.js +101 -0
- package/dist/chunk-WNTXF3DE.cjs +764 -0
- package/dist/chunk-YBSEOSSP.js +194 -0
- package/dist/chunk-YPXLV5YK.js +498 -0
- package/dist/codec-CTvFtQQI.d.cts +86 -0
- package/dist/codec-qPzfmLNu.d.ts +86 -0
- package/dist/draft14-session.cjs +6 -0
- package/dist/draft14-session.d.cts +8 -0
- package/dist/draft14-session.d.ts +8 -0
- package/dist/draft14-session.js +6 -0
- package/dist/draft14.cjs +121 -0
- package/dist/draft14.d.cts +96 -0
- package/dist/draft14.d.ts +96 -0
- package/dist/draft14.js +121 -0
- package/dist/draft7-session.cjs +7 -0
- package/dist/draft7-session.d.cts +7 -0
- package/dist/draft7-session.d.ts +7 -0
- package/dist/draft7-session.js +7 -0
- package/dist/draft7.cjs +60 -0
- package/dist/draft7.d.cts +72 -0
- package/dist/draft7.d.ts +72 -0
- package/dist/draft7.js +60 -0
- package/dist/index.cjs +40 -0
- package/dist/index.d.cts +40 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +40 -0
- package/dist/session-types-B9NIf7_F.d.ts +101 -0
- package/dist/session-types-CCo-oA-d.d.cts +101 -0
- package/dist/session.cjs +27 -0
- package/dist/session.d.cts +24 -0
- package/dist/session.d.ts +24 -0
- package/dist/session.js +27 -0
- package/dist/types-CIk5W10V.d.cts +249 -0
- package/dist/types-CIk5W10V.d.ts +249 -0
- package/dist/types-ClXELFGN.d.cts +241 -0
- package/dist/types-ClXELFGN.d.ts +241 -0
- package/package.json +84 -0
- package/src/core/buffer-reader.ts +107 -0
- package/src/core/buffer-writer.ts +91 -0
- package/src/core/errors.ts +1 -0
- package/src/core/session-types.ts +103 -0
- package/src/core/types.ts +363 -0
- package/src/drafts/draft07/announce-fsm.ts +2 -0
- package/src/drafts/draft07/codec.ts +874 -0
- package/src/drafts/draft07/index.ts +70 -0
- package/src/drafts/draft07/messages.ts +44 -0
- package/src/drafts/draft07/parameters.ts +12 -0
- package/src/drafts/draft07/rules.ts +75 -0
- package/src/drafts/draft07/session-fsm.ts +353 -0
- package/src/drafts/draft07/session.ts +21 -0
- package/src/drafts/draft07/subscription-fsm.ts +3 -0
- package/src/drafts/draft07/varint.ts +23 -0
- package/src/drafts/draft14/codec.ts +1330 -0
- package/src/drafts/draft14/index.ts +132 -0
- package/src/drafts/draft14/messages.ts +76 -0
- package/src/drafts/draft14/rules.ts +70 -0
- package/src/drafts/draft14/session-fsm.ts +480 -0
- package/src/drafts/draft14/session.ts +26 -0
- package/src/drafts/draft14/types.ts +365 -0
- package/src/index.ts +85 -0
- package/src/session.ts +58 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export class BufferWriter {
|
|
2
|
+
private buffer: Uint8Array;
|
|
3
|
+
private view: DataView;
|
|
4
|
+
private pos: number;
|
|
5
|
+
|
|
6
|
+
constructor(initialSize = 256) {
|
|
7
|
+
this.buffer = new Uint8Array(initialSize);
|
|
8
|
+
this.view = new DataView(this.buffer.buffer);
|
|
9
|
+
this.pos = 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get offset(): number {
|
|
13
|
+
return this.pos;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
private ensureCapacity(needed: number): void {
|
|
17
|
+
const required = this.pos + needed;
|
|
18
|
+
if (required <= this.buffer.byteLength) return;
|
|
19
|
+
|
|
20
|
+
let newSize = this.buffer.byteLength * 2;
|
|
21
|
+
while (newSize < required) newSize *= 2;
|
|
22
|
+
|
|
23
|
+
const newBuffer = new Uint8Array(newSize);
|
|
24
|
+
newBuffer.set(this.buffer);
|
|
25
|
+
this.buffer = newBuffer;
|
|
26
|
+
this.view = new DataView(this.buffer.buffer);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
writeUint8(value: number): void {
|
|
30
|
+
this.ensureCapacity(1);
|
|
31
|
+
this.view.setUint8(this.pos, value);
|
|
32
|
+
this.pos += 1;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
writeBytes(bytes: Uint8Array): void {
|
|
36
|
+
this.ensureCapacity(bytes.byteLength);
|
|
37
|
+
this.buffer.set(bytes, this.pos);
|
|
38
|
+
this.pos += bytes.byteLength;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
writeVarInt(value: number | bigint): void {
|
|
42
|
+
const v = BigInt(value);
|
|
43
|
+
if (v < 0n) throw new Error('VarInt value must be non-negative');
|
|
44
|
+
|
|
45
|
+
if (v < 0x40n) {
|
|
46
|
+
this.ensureCapacity(1);
|
|
47
|
+
this.view.setUint8(this.pos, Number(v));
|
|
48
|
+
this.pos += 1;
|
|
49
|
+
} else if (v < 0x4000n) {
|
|
50
|
+
this.ensureCapacity(2);
|
|
51
|
+
this.view.setUint16(this.pos, Number(v) | 0x4000);
|
|
52
|
+
this.pos += 2;
|
|
53
|
+
} else if (v < 0x40000000n) {
|
|
54
|
+
this.ensureCapacity(4);
|
|
55
|
+
this.view.setUint32(this.pos, Number(v) | 0x80000000);
|
|
56
|
+
this.pos += 4;
|
|
57
|
+
} else if (v < 0x4000000000000000n) {
|
|
58
|
+
this.ensureCapacity(8);
|
|
59
|
+
this.view.setBigUint64(this.pos, v | 0xc000000000000000n);
|
|
60
|
+
this.pos += 8;
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error('VarInt value exceeds 62-bit range');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
writeString(str: string): void {
|
|
67
|
+
const encoded = new TextEncoder().encode(str);
|
|
68
|
+
this.writeVarInt(encoded.byteLength);
|
|
69
|
+
this.writeBytes(encoded);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
writeTuple(values: string[]): void {
|
|
73
|
+
this.writeVarInt(values.length);
|
|
74
|
+
for (const v of values) {
|
|
75
|
+
this.writeString(v);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
writeParameters(params: Map<bigint, Uint8Array>): void {
|
|
80
|
+
this.writeVarInt(params.size);
|
|
81
|
+
for (const [key, value] of params) {
|
|
82
|
+
this.writeVarInt(key);
|
|
83
|
+
this.writeVarInt(value.byteLength);
|
|
84
|
+
this.writeBytes(value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
finish(): Uint8Array {
|
|
89
|
+
return this.buffer.slice(0, this.pos);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DecodeError, type DecodeErrorCode } from './types.js';
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { Codec, MoqtMessage, MoqtMessageType } from './types.js';
|
|
2
|
+
|
|
3
|
+
export type SessionPhase =
|
|
4
|
+
| 'idle'
|
|
5
|
+
| 'setup'
|
|
6
|
+
| 'ready'
|
|
7
|
+
| 'draining'
|
|
8
|
+
| 'closed'
|
|
9
|
+
| 'error';
|
|
10
|
+
|
|
11
|
+
export type SubscriptionPhase =
|
|
12
|
+
| 'pending'
|
|
13
|
+
| 'active'
|
|
14
|
+
| 'error'
|
|
15
|
+
| 'done';
|
|
16
|
+
|
|
17
|
+
export type AnnouncePhase =
|
|
18
|
+
| 'pending'
|
|
19
|
+
| 'active'
|
|
20
|
+
| 'error';
|
|
21
|
+
|
|
22
|
+
export type PublishPhase = 'pending' | 'active' | 'error' | 'done';
|
|
23
|
+
|
|
24
|
+
export type FetchPhase = 'pending' | 'active' | 'error' | 'cancelled';
|
|
25
|
+
|
|
26
|
+
export interface SubscriptionState {
|
|
27
|
+
readonly subscribeId: bigint;
|
|
28
|
+
readonly phase: SubscriptionPhase;
|
|
29
|
+
readonly trackNamespace: string[];
|
|
30
|
+
readonly trackName: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AnnounceState {
|
|
34
|
+
readonly namespace: string[];
|
|
35
|
+
readonly phase: AnnouncePhase;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PublishState {
|
|
39
|
+
readonly requestId: bigint;
|
|
40
|
+
readonly phase: PublishPhase;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface FetchState {
|
|
44
|
+
readonly requestId: bigint;
|
|
45
|
+
readonly phase: FetchPhase;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface SessionStateOptions {
|
|
49
|
+
codec: { draft: string };
|
|
50
|
+
role: 'client' | 'server';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface SessionState<M = MoqtMessage, T extends string = MoqtMessageType> {
|
|
54
|
+
readonly phase: SessionPhase;
|
|
55
|
+
readonly role: 'client' | 'server';
|
|
56
|
+
receive(message: M): TransitionResult<T>;
|
|
57
|
+
validateOutgoing(message: M): ValidationResult<T>;
|
|
58
|
+
send(message: M): TransitionResult<T>;
|
|
59
|
+
readonly subscriptions: ReadonlyMap<bigint, SubscriptionState>;
|
|
60
|
+
readonly announces: ReadonlyMap<string, AnnounceState>;
|
|
61
|
+
readonly legalOutgoing: ReadonlySet<T>;
|
|
62
|
+
readonly legalIncoming: ReadonlySet<T>;
|
|
63
|
+
reset(): void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type TransitionResult<T extends string = MoqtMessageType> =
|
|
67
|
+
| { ok: true; phase: SessionPhase; sideEffects: SideEffect[] }
|
|
68
|
+
| { ok: false; violation: ProtocolViolation<T> };
|
|
69
|
+
|
|
70
|
+
export type ValidationResult<T extends string = MoqtMessageType> =
|
|
71
|
+
| { ok: true }
|
|
72
|
+
| { ok: false; violation: ProtocolViolation<T> };
|
|
73
|
+
|
|
74
|
+
export interface ProtocolViolation<T extends string = MoqtMessageType> {
|
|
75
|
+
readonly code: ProtocolViolationCode;
|
|
76
|
+
readonly message: string;
|
|
77
|
+
readonly currentPhase: SessionPhase;
|
|
78
|
+
readonly offendingMessage: T;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type ProtocolViolationCode =
|
|
82
|
+
| 'MESSAGE_BEFORE_SETUP'
|
|
83
|
+
| 'UNEXPECTED_MESSAGE'
|
|
84
|
+
| 'DUPLICATE_SUBSCRIBE_ID'
|
|
85
|
+
| 'UNKNOWN_SUBSCRIBE_ID'
|
|
86
|
+
| 'DUPLICATE_REQUEST_ID'
|
|
87
|
+
| 'UNKNOWN_REQUEST_ID'
|
|
88
|
+
| 'ROLE_VIOLATION'
|
|
89
|
+
| 'STATE_VIOLATION'
|
|
90
|
+
| 'SETUP_VIOLATION';
|
|
91
|
+
|
|
92
|
+
export type SideEffect =
|
|
93
|
+
| { type: 'subscription-activated'; subscribeId: bigint }
|
|
94
|
+
| { type: 'subscription-ended'; subscribeId: bigint; reason: string }
|
|
95
|
+
| { type: 'announce-activated'; namespace: string[] }
|
|
96
|
+
| { type: 'announce-ended'; namespace: string[] }
|
|
97
|
+
| { type: 'publish-activated'; requestId: bigint }
|
|
98
|
+
| { type: 'publish-ended'; requestId: bigint; reason: string }
|
|
99
|
+
| { type: 'fetch-activated'; requestId: bigint }
|
|
100
|
+
| { type: 'fetch-ended'; requestId: bigint; reason: string }
|
|
101
|
+
| { type: 'session-ready' }
|
|
102
|
+
| { type: 'session-draining'; goAwayUri: string }
|
|
103
|
+
| { type: 'session-closed' };
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
// Draft identifiers
|
|
2
|
+
export type Draft = 'draft-ietf-moq-transport-07' | 'draft-ietf-moq-transport-14';
|
|
3
|
+
export type DraftShorthand = '07' | '14';
|
|
4
|
+
|
|
5
|
+
// All MoQT message type tags
|
|
6
|
+
export type MoqtMessageType =
|
|
7
|
+
| 'client_setup'
|
|
8
|
+
| 'server_setup'
|
|
9
|
+
| 'subscribe'
|
|
10
|
+
| 'subscribe_ok'
|
|
11
|
+
| 'subscribe_error'
|
|
12
|
+
| 'subscribe_done'
|
|
13
|
+
| 'subscribe_update'
|
|
14
|
+
| 'unsubscribe'
|
|
15
|
+
| 'announce'
|
|
16
|
+
| 'announce_ok'
|
|
17
|
+
| 'announce_error'
|
|
18
|
+
| 'announce_cancel'
|
|
19
|
+
| 'unannounce'
|
|
20
|
+
| 'track_status_request'
|
|
21
|
+
| 'track_status'
|
|
22
|
+
| 'object_stream'
|
|
23
|
+
| 'object_datagram'
|
|
24
|
+
| 'stream_header_track'
|
|
25
|
+
| 'stream_header_group'
|
|
26
|
+
| 'stream_header_subgroup'
|
|
27
|
+
| 'goaway'
|
|
28
|
+
| 'subscribe_announces'
|
|
29
|
+
| 'subscribe_announces_ok'
|
|
30
|
+
| 'subscribe_announces_error'
|
|
31
|
+
| 'unsubscribe_announces'
|
|
32
|
+
| 'max_subscribe_id'
|
|
33
|
+
| 'fetch'
|
|
34
|
+
| 'fetch_ok'
|
|
35
|
+
| 'fetch_error'
|
|
36
|
+
| 'fetch_cancel';
|
|
37
|
+
|
|
38
|
+
// Base message interface
|
|
39
|
+
export interface BaseMessage {
|
|
40
|
+
readonly type: MoqtMessageType;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Setup messages
|
|
44
|
+
export interface ClientSetup extends BaseMessage {
|
|
45
|
+
readonly type: 'client_setup';
|
|
46
|
+
readonly supportedVersions: bigint[];
|
|
47
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ServerSetup extends BaseMessage {
|
|
51
|
+
readonly type: 'server_setup';
|
|
52
|
+
readonly selectedVersion: bigint;
|
|
53
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Subscribe messages
|
|
57
|
+
export interface Subscribe extends BaseMessage {
|
|
58
|
+
readonly type: 'subscribe';
|
|
59
|
+
readonly subscribeId: bigint;
|
|
60
|
+
readonly trackAlias: bigint;
|
|
61
|
+
readonly trackNamespace: string[];
|
|
62
|
+
readonly trackName: string;
|
|
63
|
+
readonly subscriberPriority: number;
|
|
64
|
+
readonly groupOrder: GroupOrderValue;
|
|
65
|
+
readonly filterType: FilterType;
|
|
66
|
+
readonly startGroup?: bigint;
|
|
67
|
+
readonly startObject?: bigint;
|
|
68
|
+
readonly endGroup?: bigint;
|
|
69
|
+
readonly endObject?: bigint;
|
|
70
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type FilterType = 'latest_group' | 'latest_object' | 'absolute_start' | 'absolute_range';
|
|
74
|
+
|
|
75
|
+
export interface SubscribeOk extends BaseMessage {
|
|
76
|
+
readonly type: 'subscribe_ok';
|
|
77
|
+
readonly subscribeId: bigint;
|
|
78
|
+
readonly expires: bigint;
|
|
79
|
+
readonly groupOrder: GroupOrderValue;
|
|
80
|
+
readonly contentExists: boolean;
|
|
81
|
+
readonly largestGroupId?: bigint;
|
|
82
|
+
readonly largestObjectId?: bigint;
|
|
83
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type GroupOrderValue = 'ascending' | 'descending' | 'original';
|
|
87
|
+
|
|
88
|
+
export interface SubscribeError extends BaseMessage {
|
|
89
|
+
readonly type: 'subscribe_error';
|
|
90
|
+
readonly subscribeId: bigint;
|
|
91
|
+
readonly errorCode: bigint;
|
|
92
|
+
readonly reasonPhrase: string;
|
|
93
|
+
readonly trackAlias: bigint;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface SubscribeDone extends BaseMessage {
|
|
97
|
+
readonly type: 'subscribe_done';
|
|
98
|
+
readonly subscribeId: bigint;
|
|
99
|
+
readonly statusCode: bigint;
|
|
100
|
+
readonly reasonPhrase: string;
|
|
101
|
+
readonly contentExists: boolean;
|
|
102
|
+
readonly finalGroupId?: bigint;
|
|
103
|
+
readonly finalObjectId?: bigint;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface SubscribeUpdate extends BaseMessage {
|
|
107
|
+
readonly type: 'subscribe_update';
|
|
108
|
+
readonly subscribeId: bigint;
|
|
109
|
+
readonly startGroup: bigint;
|
|
110
|
+
readonly startObject: bigint;
|
|
111
|
+
readonly endGroup: bigint;
|
|
112
|
+
readonly endObject: bigint;
|
|
113
|
+
readonly subscriberPriority: number;
|
|
114
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface Unsubscribe extends BaseMessage {
|
|
118
|
+
readonly type: 'unsubscribe';
|
|
119
|
+
readonly subscribeId: bigint;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Announce messages
|
|
123
|
+
export interface Announce extends BaseMessage {
|
|
124
|
+
readonly type: 'announce';
|
|
125
|
+
readonly trackNamespace: string[];
|
|
126
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface AnnounceOk extends BaseMessage {
|
|
130
|
+
readonly type: 'announce_ok';
|
|
131
|
+
readonly trackNamespace: string[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface AnnounceError extends BaseMessage {
|
|
135
|
+
readonly type: 'announce_error';
|
|
136
|
+
readonly trackNamespace: string[];
|
|
137
|
+
readonly errorCode: bigint;
|
|
138
|
+
readonly reasonPhrase: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface AnnounceCancel extends BaseMessage {
|
|
142
|
+
readonly type: 'announce_cancel';
|
|
143
|
+
readonly trackNamespace: string[];
|
|
144
|
+
readonly errorCode: bigint;
|
|
145
|
+
readonly reasonPhrase: string;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface Unannounce extends BaseMessage {
|
|
149
|
+
readonly type: 'unannounce';
|
|
150
|
+
readonly trackNamespace: string[];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Track status
|
|
154
|
+
export interface TrackStatusRequest extends BaseMessage {
|
|
155
|
+
readonly type: 'track_status_request';
|
|
156
|
+
readonly trackNamespace: string[];
|
|
157
|
+
readonly trackName: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface TrackStatus extends BaseMessage {
|
|
161
|
+
readonly type: 'track_status';
|
|
162
|
+
readonly trackNamespace: string[];
|
|
163
|
+
readonly trackName: string;
|
|
164
|
+
readonly statusCode: bigint;
|
|
165
|
+
readonly lastGroupId: bigint;
|
|
166
|
+
readonly lastObjectId: bigint;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Object/stream messages
|
|
170
|
+
export interface ObjectStream extends BaseMessage {
|
|
171
|
+
readonly type: 'object_stream';
|
|
172
|
+
readonly subscribeId: bigint;
|
|
173
|
+
readonly trackAlias: bigint;
|
|
174
|
+
readonly groupId: bigint;
|
|
175
|
+
readonly objectId: bigint;
|
|
176
|
+
readonly publisherPriority: number;
|
|
177
|
+
readonly objectStatus?: number;
|
|
178
|
+
readonly payload: Uint8Array;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface ObjectDatagram extends BaseMessage {
|
|
182
|
+
readonly type: 'object_datagram';
|
|
183
|
+
readonly subscribeId: bigint;
|
|
184
|
+
readonly trackAlias: bigint;
|
|
185
|
+
readonly groupId: bigint;
|
|
186
|
+
readonly objectId: bigint;
|
|
187
|
+
readonly publisherPriority: number;
|
|
188
|
+
readonly objectStatus?: number;
|
|
189
|
+
readonly payload: Uint8Array;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface StreamHeaderTrack extends BaseMessage {
|
|
193
|
+
readonly type: 'stream_header_track';
|
|
194
|
+
readonly subscribeId: bigint;
|
|
195
|
+
readonly trackAlias: bigint;
|
|
196
|
+
readonly publisherPriority: number;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface StreamHeaderGroup extends BaseMessage {
|
|
200
|
+
readonly type: 'stream_header_group';
|
|
201
|
+
readonly subscribeId: bigint;
|
|
202
|
+
readonly trackAlias: bigint;
|
|
203
|
+
readonly groupId: bigint;
|
|
204
|
+
readonly publisherPriority: number;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface StreamHeaderSubgroup extends BaseMessage {
|
|
208
|
+
readonly type: 'stream_header_subgroup';
|
|
209
|
+
readonly subscribeId: bigint;
|
|
210
|
+
readonly trackAlias: bigint;
|
|
211
|
+
readonly groupId: bigint;
|
|
212
|
+
readonly subgroupId: bigint;
|
|
213
|
+
readonly publisherPriority: number;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// GoAway
|
|
217
|
+
export interface GoAway extends BaseMessage {
|
|
218
|
+
readonly type: 'goaway';
|
|
219
|
+
readonly newSessionUri: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Subscribe Announces
|
|
223
|
+
export interface SubscribeAnnounces extends BaseMessage {
|
|
224
|
+
readonly type: 'subscribe_announces';
|
|
225
|
+
readonly trackNamespace: string[];
|
|
226
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface SubscribeAnnouncesOk extends BaseMessage {
|
|
230
|
+
readonly type: 'subscribe_announces_ok';
|
|
231
|
+
readonly trackNamespace: string[];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface SubscribeAnnouncesError extends BaseMessage {
|
|
235
|
+
readonly type: 'subscribe_announces_error';
|
|
236
|
+
readonly trackNamespace: string[];
|
|
237
|
+
readonly errorCode: bigint;
|
|
238
|
+
readonly reasonPhrase: string;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Unsubscribe Announces
|
|
242
|
+
export interface UnsubscribeAnnounces extends BaseMessage {
|
|
243
|
+
readonly type: 'unsubscribe_announces';
|
|
244
|
+
readonly trackNamespace: string[];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Max Subscribe ID
|
|
248
|
+
export interface MaxSubscribeId extends BaseMessage {
|
|
249
|
+
readonly type: 'max_subscribe_id';
|
|
250
|
+
readonly subscribeId: bigint;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Fetch
|
|
254
|
+
export interface Fetch extends BaseMessage {
|
|
255
|
+
readonly type: 'fetch';
|
|
256
|
+
readonly subscribeId: bigint;
|
|
257
|
+
readonly trackNamespace: string[];
|
|
258
|
+
readonly trackName: string;
|
|
259
|
+
readonly subscriberPriority: number;
|
|
260
|
+
readonly groupOrder: GroupOrderValue;
|
|
261
|
+
readonly startGroup: bigint;
|
|
262
|
+
readonly startObject: bigint;
|
|
263
|
+
readonly endGroup: bigint;
|
|
264
|
+
readonly endObject: bigint;
|
|
265
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface FetchOk extends BaseMessage {
|
|
269
|
+
readonly type: 'fetch_ok';
|
|
270
|
+
readonly subscribeId: bigint;
|
|
271
|
+
readonly groupOrder: GroupOrderValue;
|
|
272
|
+
readonly endOfTrack: boolean;
|
|
273
|
+
readonly largestGroupId: bigint;
|
|
274
|
+
readonly largestObjectId: bigint;
|
|
275
|
+
readonly parameters: Map<bigint, Uint8Array>;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export interface FetchError extends BaseMessage {
|
|
279
|
+
readonly type: 'fetch_error';
|
|
280
|
+
readonly subscribeId: bigint;
|
|
281
|
+
readonly errorCode: bigint;
|
|
282
|
+
readonly reasonPhrase: string;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface FetchCancel extends BaseMessage {
|
|
286
|
+
readonly type: 'fetch_cancel';
|
|
287
|
+
readonly subscribeId: bigint;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Union type of all messages
|
|
291
|
+
export type MoqtMessage =
|
|
292
|
+
| ClientSetup
|
|
293
|
+
| ServerSetup
|
|
294
|
+
| Subscribe
|
|
295
|
+
| SubscribeOk
|
|
296
|
+
| SubscribeError
|
|
297
|
+
| SubscribeDone
|
|
298
|
+
| SubscribeUpdate
|
|
299
|
+
| Unsubscribe
|
|
300
|
+
| Announce
|
|
301
|
+
| AnnounceOk
|
|
302
|
+
| AnnounceError
|
|
303
|
+
| AnnounceCancel
|
|
304
|
+
| Unannounce
|
|
305
|
+
| TrackStatusRequest
|
|
306
|
+
| TrackStatus
|
|
307
|
+
| ObjectStream
|
|
308
|
+
| ObjectDatagram
|
|
309
|
+
| StreamHeaderTrack
|
|
310
|
+
| StreamHeaderGroup
|
|
311
|
+
| StreamHeaderSubgroup
|
|
312
|
+
| GoAway
|
|
313
|
+
| SubscribeAnnounces
|
|
314
|
+
| SubscribeAnnouncesOk
|
|
315
|
+
| SubscribeAnnouncesError
|
|
316
|
+
| UnsubscribeAnnounces
|
|
317
|
+
| MaxSubscribeId
|
|
318
|
+
| Fetch
|
|
319
|
+
| FetchOk
|
|
320
|
+
| FetchError
|
|
321
|
+
| FetchCancel;
|
|
322
|
+
|
|
323
|
+
// Base codec interface — draft-specific codecs extend this
|
|
324
|
+
export interface BaseCodec<M = MoqtMessage> {
|
|
325
|
+
readonly draft: Draft;
|
|
326
|
+
encodeMessage(message: M): Uint8Array;
|
|
327
|
+
decodeMessage(bytes: Uint8Array): DecodeResult<M>;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Full codec interface for drafts that support varint + stream decode
|
|
331
|
+
export interface Codec extends BaseCodec<MoqtMessage> {
|
|
332
|
+
encodeVarInt(value: number | bigint): Uint8Array;
|
|
333
|
+
decodeVarInt(bytes: Uint8Array, offset?: number): DecodeResult<bigint>;
|
|
334
|
+
createStreamDecoder(): TransformStream<Uint8Array, MoqtMessage>;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export interface CodecOptions {
|
|
338
|
+
draft: Draft | DraftShorthand;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Result types
|
|
342
|
+
export type DecodeResult<T> =
|
|
343
|
+
| { ok: true; value: T; bytesRead: number }
|
|
344
|
+
| { ok: false; error: DecodeError };
|
|
345
|
+
|
|
346
|
+
export type DecodeErrorCode =
|
|
347
|
+
| 'UNEXPECTED_END'
|
|
348
|
+
| 'INVALID_VARINT'
|
|
349
|
+
| 'UNKNOWN_MESSAGE_TYPE'
|
|
350
|
+
| 'INVALID_PARAMETER'
|
|
351
|
+
| 'CONSTRAINT_VIOLATION';
|
|
352
|
+
|
|
353
|
+
export class DecodeError extends Error {
|
|
354
|
+
readonly code: DecodeErrorCode;
|
|
355
|
+
readonly offset: number;
|
|
356
|
+
|
|
357
|
+
constructor(code: DecodeErrorCode, message: string, offset: number) {
|
|
358
|
+
super(message);
|
|
359
|
+
this.name = 'DecodeError';
|
|
360
|
+
this.code = code;
|
|
361
|
+
this.offset = offset;
|
|
362
|
+
}
|
|
363
|
+
}
|