@blockcast/mmt-transport 0.2.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/dist/abr-controller.d.ts +94 -0
- package/dist/abr-controller.d.ts.map +1 -0
- package/dist/abr-controller.js +174 -0
- package/dist/abr-controller.js.map +1 -0
- package/dist/amt-gateway.d.ts +160 -0
- package/dist/amt-gateway.d.ts.map +1 -0
- package/dist/amt-gateway.js +390 -0
- package/dist/amt-gateway.js.map +1 -0
- package/dist/clock.d.ts +104 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +183 -0
- package/dist/clock.js.map +1 -0
- package/dist/driad-discovery.d.ts +50 -0
- package/dist/driad-discovery.d.ts.map +1 -0
- package/dist/driad-discovery.js +170 -0
- package/dist/driad-discovery.js.map +1 -0
- package/dist/fec-client.d.ts +442 -0
- package/dist/fec-client.d.ts.map +1 -0
- package/dist/fec-client.js +784 -0
- package/dist/fec-client.js.map +1 -0
- package/dist/fec-client.test.d.ts +8 -0
- package/dist/fec-client.test.d.ts.map +1 -0
- package/dist/fec-client.test.js +112 -0
- package/dist/fec-client.test.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/transport-manager.d.ts +114 -0
- package/dist/transport-manager.d.ts.map +1 -0
- package/dist/transport-manager.js +396 -0
- package/dist/transport-manager.js.map +1 -0
- package/dist/types.d.ts +356 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +85 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
- package/src/abr-controller.ts +227 -0
- package/src/amt-gateway.ts +511 -0
- package/src/clock.ts +212 -0
- package/src/driad-discovery.ts +193 -0
- package/src/fec-client.test.ts +140 -0
- package/src/fec-client.ts +1097 -0
- package/src/index.ts +122 -0
- package/src/transport-manager.ts +460 -0
- package/src/types.ts +420 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @blockcast/transport - Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Shared interfaces for unified transport (WebTransport, SSM, AMT, DRIAD) and FEC.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** window.Multicast API type (from IWA/Chrome Direct Sockets) */
|
|
8
|
+
export interface MulticastAPI {
|
|
9
|
+
subscribeSSM?: (config: {
|
|
10
|
+
group: string;
|
|
11
|
+
source: string;
|
|
12
|
+
port: number;
|
|
13
|
+
protocol?: string;
|
|
14
|
+
fec?: boolean;
|
|
15
|
+
}) => Promise<MulticastSubscription>;
|
|
16
|
+
subscribe?: (config: {
|
|
17
|
+
group: string;
|
|
18
|
+
port: number;
|
|
19
|
+
protocol?: string;
|
|
20
|
+
fec?: boolean;
|
|
21
|
+
}) => Promise<MulticastSubscription>;
|
|
22
|
+
connectAMT?: (config: {
|
|
23
|
+
relay: string;
|
|
24
|
+
group: string;
|
|
25
|
+
source?: string;
|
|
26
|
+
port: number;
|
|
27
|
+
}) => Promise<{ onpacket?: (event: { data: ArrayBuffer }) => void; close: () => void }>;
|
|
28
|
+
fecDecode?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MulticastSubscription {
|
|
32
|
+
onpacket?: (event: { data: ArrayBuffer }) => void;
|
|
33
|
+
onerror?: (error: Error) => void;
|
|
34
|
+
unsubscribe: () => void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
declare global {
|
|
38
|
+
interface Window {
|
|
39
|
+
Multicast?: MulticastAPI;
|
|
40
|
+
UDPSocket?: unknown;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Transport configuration for multicast subscriptions */
|
|
45
|
+
export interface TransportConfig {
|
|
46
|
+
/** Multicast group address (232.x.x.x for SSM) */
|
|
47
|
+
group: string;
|
|
48
|
+
/** Source address for SSM filtering */
|
|
49
|
+
source: string;
|
|
50
|
+
/** UDP port */
|
|
51
|
+
port: number;
|
|
52
|
+
/** Stream type */
|
|
53
|
+
streamType: "video" | "audio";
|
|
54
|
+
/** Optional AMT relay host for unicast tunneling */
|
|
55
|
+
amtRelay?: string;
|
|
56
|
+
/** DRIAD discovery enabled */
|
|
57
|
+
driadEnabled?: boolean;
|
|
58
|
+
/** Initial bitrate quality level */
|
|
59
|
+
initialQuality?: QualityLevel;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** @deprecated Use TransportConfig instead */
|
|
63
|
+
export type SSMConfig = TransportConfig;
|
|
64
|
+
|
|
65
|
+
export interface QualityLevel {
|
|
66
|
+
name: string;
|
|
67
|
+
bitrate: number;
|
|
68
|
+
width: number;
|
|
69
|
+
height: number;
|
|
70
|
+
fps: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface TransportCapabilities {
|
|
74
|
+
nativeSSM: boolean;
|
|
75
|
+
nativeIGMP: boolean;
|
|
76
|
+
directSockets: boolean;
|
|
77
|
+
amt: boolean;
|
|
78
|
+
driad: boolean;
|
|
79
|
+
fecDecode: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type TransportMode = "ssm" | "igmp" | "amt" | "driad" | "moq" | "disconnected";
|
|
83
|
+
|
|
84
|
+
export interface TransportState {
|
|
85
|
+
mode: TransportMode;
|
|
86
|
+
connected: boolean;
|
|
87
|
+
group?: string;
|
|
88
|
+
source?: string;
|
|
89
|
+
amtRelay?: string;
|
|
90
|
+
driadRelay?: string;
|
|
91
|
+
quality?: QualityLevel;
|
|
92
|
+
packetsReceived: number;
|
|
93
|
+
bytesReceived: number;
|
|
94
|
+
lastPacketTime: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Transport subscription handle */
|
|
98
|
+
export interface TransportSubscription {
|
|
99
|
+
id: string;
|
|
100
|
+
config: TransportConfig;
|
|
101
|
+
onpacket?: (data: ArrayBuffer) => void;
|
|
102
|
+
onerror?: (error: Error) => void;
|
|
103
|
+
onqualitychange?: (quality: QualityLevel) => void;
|
|
104
|
+
close: () => void;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** @deprecated Use TransportSubscription instead */
|
|
108
|
+
export type SSMSubscription = TransportSubscription;
|
|
109
|
+
|
|
110
|
+
/** DRIAD Relay information (RFC 8777) */
|
|
111
|
+
export interface DRIADRelay {
|
|
112
|
+
host: string;
|
|
113
|
+
port: number;
|
|
114
|
+
priority: number;
|
|
115
|
+
weight: number;
|
|
116
|
+
asn: number;
|
|
117
|
+
rtt?: number;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** AMT Relay information */
|
|
121
|
+
export interface AmtRelayInfo {
|
|
122
|
+
address: string;
|
|
123
|
+
port: number;
|
|
124
|
+
discoveryMethod: "driad" | "manual";
|
|
125
|
+
discoveredAt: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Group key for multicast subscriptions */
|
|
129
|
+
export interface GroupKey {
|
|
130
|
+
group: string;
|
|
131
|
+
port: number;
|
|
132
|
+
source?: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Packet metadata */
|
|
136
|
+
export interface PacketMetadata {
|
|
137
|
+
sourceAddress: string;
|
|
138
|
+
sourcePort: number;
|
|
139
|
+
transport: "native" | "tunnel" | "websocket";
|
|
140
|
+
timestamp: number;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** MFU Fragment for reassembly */
|
|
144
|
+
export interface MfuFragment {
|
|
145
|
+
mpuSequenceNumber: number;
|
|
146
|
+
fragmentationIndicator: number; // 0=complete, 1=first, 2=middle, 3=last
|
|
147
|
+
fragmentCounter: number;
|
|
148
|
+
data: Uint8Array;
|
|
149
|
+
timestamp: bigint;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Reassembled MFU */
|
|
153
|
+
export interface ReassembledMfu {
|
|
154
|
+
mpuSequenceNumber: number;
|
|
155
|
+
data: Uint8Array;
|
|
156
|
+
timestamp: bigint;
|
|
157
|
+
fragmentCount: number;
|
|
158
|
+
recoveredViaFec: boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** FEC + MFU processing statistics */
|
|
162
|
+
export interface ProcessingStats {
|
|
163
|
+
// MFU stats
|
|
164
|
+
mfuComplete: number;
|
|
165
|
+
mfuReassembled: number;
|
|
166
|
+
mfuTimedOut: number;
|
|
167
|
+
|
|
168
|
+
// FEC stats
|
|
169
|
+
fecSourcePackets: number;
|
|
170
|
+
fecRepairPackets: number;
|
|
171
|
+
fecBlocksComplete: number;
|
|
172
|
+
fecBlocksRecovered: number;
|
|
173
|
+
fecBlocksFailed: number;
|
|
174
|
+
fecRecoveryRate: number;
|
|
175
|
+
|
|
176
|
+
// Green-fill stats
|
|
177
|
+
greenFillFrames: number;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Options for MmtFecClient */
|
|
181
|
+
export interface MmtFecClientOptions {
|
|
182
|
+
/** Interleave depth for FEC (default: 30 for ~1s at 30fps) */
|
|
183
|
+
interleaveDepth?: number;
|
|
184
|
+
|
|
185
|
+
/** Block timeout in milliseconds (default: 2000) */
|
|
186
|
+
blockTimeoutMs?: number;
|
|
187
|
+
|
|
188
|
+
/** MFU timeout in milliseconds (default: 1000) */
|
|
189
|
+
mfuTimeoutMs?: number;
|
|
190
|
+
|
|
191
|
+
/** Enable green-fill for failed frames (default: true) */
|
|
192
|
+
greenFillEnabled?: boolean;
|
|
193
|
+
|
|
194
|
+
/** Callback when MFU is ready */
|
|
195
|
+
onMfuReady?: (mfu: ReassembledMfu) => void;
|
|
196
|
+
|
|
197
|
+
/** Callback for green-fill frame */
|
|
198
|
+
onGreenFill?: (timestamp: bigint) => void;
|
|
199
|
+
|
|
200
|
+
/** Callback for stats update */
|
|
201
|
+
onStatsUpdate?: (stats: ProcessingStats) => void;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Time types (microseconds) */
|
|
205
|
+
export type Micro = number & { readonly __micro: unique symbol };
|
|
206
|
+
|
|
207
|
+
/** Sync decision for A/V synchronization */
|
|
208
|
+
export type SyncDecision = "render" | "hold" | "discard";
|
|
209
|
+
|
|
210
|
+
// ============================================================
|
|
211
|
+
// Multicast Bridge Types (consolidated from @blockcast/multicast)
|
|
212
|
+
// ============================================================
|
|
213
|
+
|
|
214
|
+
/** Transport mode for multicast subscription (auto-selection) */
|
|
215
|
+
export type MulticastTransportMode = "auto" | "native" | "tunnel";
|
|
216
|
+
|
|
217
|
+
/** Multicast subscription configuration */
|
|
218
|
+
export interface MulticastConfig {
|
|
219
|
+
group: string;
|
|
220
|
+
port: number;
|
|
221
|
+
source?: string;
|
|
222
|
+
mode?: MulticastTransportMode;
|
|
223
|
+
onPacket: (data: ArrayBuffer, source: PacketSource) => void;
|
|
224
|
+
onStateChange?: (state: SubscriptionState) => void;
|
|
225
|
+
onError?: (error: Error) => void;
|
|
226
|
+
amtRelay?: string;
|
|
227
|
+
amtRelayPort?: number;
|
|
228
|
+
nativeFallbackTimeout?: number;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Packet source information */
|
|
232
|
+
export interface PacketSource {
|
|
233
|
+
address: string;
|
|
234
|
+
port: number;
|
|
235
|
+
transport: "native" | "tunnel";
|
|
236
|
+
recovered?: boolean;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Subscription state */
|
|
240
|
+
export type SubscriptionState = "initializing" | "joining" | "active" | "suspended" | "closed" | "error";
|
|
241
|
+
|
|
242
|
+
/** Subscription statistics */
|
|
243
|
+
export interface SubscriptionStats {
|
|
244
|
+
packetsReceived: number;
|
|
245
|
+
bytesReceived: number;
|
|
246
|
+
packetsLost: number;
|
|
247
|
+
packetsRecovered: number;
|
|
248
|
+
bitrate: number;
|
|
249
|
+
uptime: number;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Multicast subscription handle */
|
|
253
|
+
export interface MulticastSubscriptionHandle {
|
|
254
|
+
readonly state: SubscriptionState;
|
|
255
|
+
readonly group: string;
|
|
256
|
+
readonly source?: string;
|
|
257
|
+
readonly port: number;
|
|
258
|
+
readonly transport: "native" | "tunnel";
|
|
259
|
+
readonly stats: SubscriptionStats;
|
|
260
|
+
close(): Promise<void>;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** FEC Configuration for MMT streams */
|
|
264
|
+
export interface FecConfig {
|
|
265
|
+
enabled?: boolean;
|
|
266
|
+
oti?: Uint8Array;
|
|
267
|
+
interleaveDepth?: number;
|
|
268
|
+
blockTimeoutMs?: number;
|
|
269
|
+
greenFillEnabled?: boolean;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** FEC Statistics */
|
|
273
|
+
export interface FecStats {
|
|
274
|
+
sourcePackets: number;
|
|
275
|
+
repairPackets: number;
|
|
276
|
+
blocksComplete: number;
|
|
277
|
+
blocksRecovered: number;
|
|
278
|
+
blocksFailed: number;
|
|
279
|
+
recoveryRate: number;
|
|
280
|
+
greenFillFrames: number;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Extended MulticastConfig with FEC support */
|
|
284
|
+
export interface MulticastConfigWithFec extends MulticastConfig {
|
|
285
|
+
fec?: FecConfig;
|
|
286
|
+
onFecStats?: (stats: FecStats) => void;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Main Multicast Bridge API */
|
|
290
|
+
export interface MulticastBridge {
|
|
291
|
+
subscribe(config: MulticastConfig | MulticastConfigWithFec): Promise<MulticastSubscriptionHandle>;
|
|
292
|
+
getSubscriptions(): Promise<MulticastSubscriptionHandle[]>;
|
|
293
|
+
isNativeSupported(): Promise<boolean>;
|
|
294
|
+
getFecStats?(): FecStats | null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ============================================================
|
|
298
|
+
// FEC Constants and Utilities per draft-ramadan-moq-fec-00
|
|
299
|
+
// ============================================================
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* FEC_CONFIG message type per draft-ramadan-moq-fec-00
|
|
303
|
+
* Used to signal FEC configuration to subscribers
|
|
304
|
+
*/
|
|
305
|
+
export const FEC_CONFIG_MESSAGE_TYPE = 0x50;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Repair track suffix per draft-ramadan-moq-fec-00 Section 5.1
|
|
309
|
+
* Repair tracks are named by appending this suffix to the source track path
|
|
310
|
+
*/
|
|
311
|
+
export const REPAIR_TRACK_SUFFIX = "repair";
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Get the repair track path for a given source track
|
|
315
|
+
*
|
|
316
|
+
* Per draft-ramadan-moq-fec-00 Section 5.1, the repair track is named
|
|
317
|
+
* by appending "repair" to the source track path.
|
|
318
|
+
*
|
|
319
|
+
* @param sourceTrack - The source track path (e.g., "live/video")
|
|
320
|
+
* @returns The repair track path (e.g., "live/video/repair")
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* repairTrackPath("live/video") // returns "live/video/repair"
|
|
324
|
+
* repairTrackPath("broadcast/video/1080p") // returns "broadcast/video/1080p/repair"
|
|
325
|
+
*/
|
|
326
|
+
export function repairTrackPath(sourceTrack: string): string {
|
|
327
|
+
if (!sourceTrack || sourceTrack.length === 0) {
|
|
328
|
+
return REPAIR_TRACK_SUFFIX;
|
|
329
|
+
}
|
|
330
|
+
return `${sourceTrack}/${REPAIR_TRACK_SUFFIX}`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Check if a track path is a repair track
|
|
335
|
+
*
|
|
336
|
+
* @param path - The track path to check
|
|
337
|
+
* @returns True if the path ends with the repair track suffix
|
|
338
|
+
*
|
|
339
|
+
* @example
|
|
340
|
+
* isRepairTrack("live/video/repair") // returns true
|
|
341
|
+
* isRepairTrack("repair") // returns true
|
|
342
|
+
* isRepairTrack("live/video") // returns false
|
|
343
|
+
*/
|
|
344
|
+
export function isRepairTrack(path: string): boolean {
|
|
345
|
+
return path === REPAIR_TRACK_SUFFIX || path.endsWith(`/${REPAIR_TRACK_SUFFIX}`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Get the source track path from a repair track path
|
|
350
|
+
*
|
|
351
|
+
* @param repairTrack - The repair track path
|
|
352
|
+
* @returns The source track path, or null if not a valid repair track
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* sourceTrackFromRepair("live/video/repair") // returns "live/video"
|
|
356
|
+
* sourceTrackFromRepair("repair") // returns ""
|
|
357
|
+
* sourceTrackFromRepair("live/video") // returns null
|
|
358
|
+
*/
|
|
359
|
+
export function sourceTrackFromRepair(repairTrack: string): string | null {
|
|
360
|
+
if (repairTrack === REPAIR_TRACK_SUFFIX) {
|
|
361
|
+
return "";
|
|
362
|
+
}
|
|
363
|
+
const suffix = `/${REPAIR_TRACK_SUFFIX}`;
|
|
364
|
+
if (repairTrack.endsWith(suffix)) {
|
|
365
|
+
return repairTrack.slice(0, -suffix.length);
|
|
366
|
+
}
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* MoQ FEC Configuration per draft-ramadan-moq-fec-00
|
|
372
|
+
*
|
|
373
|
+
* This configuration is sent via FEC_CONFIG message after SUBSCRIBE_OK
|
|
374
|
+
* to inform subscribers about FEC parameters.
|
|
375
|
+
*/
|
|
376
|
+
export interface MoqFecConfig {
|
|
377
|
+
/** Subscribe ID this config applies to */
|
|
378
|
+
subscribeId: number;
|
|
379
|
+
/** Whether FEC is enabled */
|
|
380
|
+
enabled: boolean;
|
|
381
|
+
/** FEC algorithm (0=none, 1=XOR, 2=RaptorQ) */
|
|
382
|
+
algorithm: MoqFecAlgorithm;
|
|
383
|
+
/** Number of source symbols per FEC block (K) */
|
|
384
|
+
sourceSymbolsPerBlock: number;
|
|
385
|
+
/** Number of repair symbols per FEC block (P) */
|
|
386
|
+
repairSymbolsPerBlock: number;
|
|
387
|
+
/** Interleave depth for burst loss protection */
|
|
388
|
+
interleaveDepth: number;
|
|
389
|
+
/** Symbol size in bytes */
|
|
390
|
+
symbolSize: number;
|
|
391
|
+
/** RFC 6330 Object Transmission Information (12 bytes) - only for RaptorQ */
|
|
392
|
+
oti?: Uint8Array;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* FEC algorithm identifier per draft-ramadan-moq-fec-00
|
|
397
|
+
*/
|
|
398
|
+
export enum MoqFecAlgorithm {
|
|
399
|
+
/** No FEC (disabled) */
|
|
400
|
+
None = 0,
|
|
401
|
+
/** Simple XOR parity */
|
|
402
|
+
Xor = 1,
|
|
403
|
+
/** RaptorQ (RFC 6330) - recommended for burst loss */
|
|
404
|
+
RaptorQ = 2,
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Repair object header per draft-ramadan-moq-fec-00 Section 6.1
|
|
409
|
+
*
|
|
410
|
+
* Each object on a repair track contains repair symbols for one source block.
|
|
411
|
+
* The object payload begins with this header, followed by concatenated repair symbols.
|
|
412
|
+
*/
|
|
413
|
+
export interface RepairObjectHeader {
|
|
414
|
+
/** Source block number being protected (matches group_id of source objects) */
|
|
415
|
+
sourceBlockNumber: number;
|
|
416
|
+
/** First Repair Symbol ESI (Encoding Symbol ID) - for RaptorQ, repair ESIs >= K */
|
|
417
|
+
firstRepairEsi: number;
|
|
418
|
+
/** Number of repair symbols in this object */
|
|
419
|
+
numRepairSymbols: number;
|
|
420
|
+
}
|