@blockcast/mmt-container 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/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/loc.d.ts +100 -0
- package/dist/loc.d.ts.map +1 -0
- package/dist/loc.js +198 -0
- package/dist/loc.js.map +1 -0
- package/dist/mfu-reassembler.d.ts +92 -0
- package/dist/mfu-reassembler.d.ts.map +1 -0
- package/dist/mfu-reassembler.js +320 -0
- package/dist/mfu-reassembler.js.map +1 -0
- package/dist/mmtp.d.ts +73 -0
- package/dist/mmtp.d.ts.map +1 -0
- package/dist/mmtp.js +210 -0
- package/dist/mmtp.js.map +1 -0
- package/package.json +45 -0
- package/src/index.ts +44 -0
- package/src/loc.ts +218 -0
- package/src/mfu-reassembler.ts +416 -0
- package/src/mmtp.ts +277 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mmt/container - MFU Fragment Reassembler
|
|
3
|
+
*
|
|
4
|
+
* Handles out-of-order delivery of fragmented MFUs (Media Fragment Units)
|
|
5
|
+
* according to ISO/IEC 23008-1:2023 Section 9.2.3.3
|
|
6
|
+
*
|
|
7
|
+
* Fragmentation Indicator (FI) values:
|
|
8
|
+
* - 0: Complete MFU (single packet, no fragmentation)
|
|
9
|
+
* - 1: First fragment
|
|
10
|
+
* - 2: Middle fragment
|
|
11
|
+
* - 3: Last fragment
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
16
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
17
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
18
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
19
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
20
|
+
};
|
|
21
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
22
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
23
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
24
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
25
|
+
};
|
|
26
|
+
var _MFUReassembler_instances, _MFUReassembler_buffers, _MFUReassembler_timeouts, _MFUReassembler_timeoutMs, _MFUReassembler_maxBuffered, _MFUReassembler_tryReassemble, _MFUReassembler_setTimeout, _MFUReassembler_clearTimeout, _MFUReassembler_onTimeout, _MFUReassembler_enforceMemoryLimit;
|
|
27
|
+
import { unwrapMMTP, parseMPUHeader, isFecRepairPacket, MPU_HEADER_SIZE, MFU_DU_HEADER_SIZE, } from './mmtp.js';
|
|
28
|
+
/**
|
|
29
|
+
* MFU Reassembler for out-of-order fragment delivery
|
|
30
|
+
* Based on ISO/IEC 23008-1:2023 Section 9.2.3.3
|
|
31
|
+
*/
|
|
32
|
+
export class MFUReassembler {
|
|
33
|
+
constructor(options) {
|
|
34
|
+
_MFUReassembler_instances.add(this);
|
|
35
|
+
_MFUReassembler_buffers.set(this, new Map());
|
|
36
|
+
_MFUReassembler_timeouts.set(this, new Map());
|
|
37
|
+
_MFUReassembler_timeoutMs.set(this, void 0);
|
|
38
|
+
_MFUReassembler_maxBuffered.set(this, void 0);
|
|
39
|
+
/** Statistics for debugging */
|
|
40
|
+
this.stats = {
|
|
41
|
+
totalFragments: 0,
|
|
42
|
+
reassembledMFUs: 0,
|
|
43
|
+
timedOutMFUs: 0,
|
|
44
|
+
outOfOrderFragments: 0,
|
|
45
|
+
};
|
|
46
|
+
__classPrivateFieldSet(this, _MFUReassembler_timeoutMs, options?.timeoutMs ?? 1000, "f");
|
|
47
|
+
__classPrivateFieldSet(this, _MFUReassembler_maxBuffered, options?.maxBuffered ?? 100, "f");
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Add a fragment and return reassembled MFU if complete
|
|
51
|
+
*/
|
|
52
|
+
addFragment(fragment) {
|
|
53
|
+
this.stats.totalFragments++;
|
|
54
|
+
const { mpuSequenceNumber, fragmentationIndicator, fragmentCounter } = fragment;
|
|
55
|
+
// Handle complete MFU (FI=0)
|
|
56
|
+
if (fragmentationIndicator === 0) {
|
|
57
|
+
this.stats.reassembledMFUs++;
|
|
58
|
+
return {
|
|
59
|
+
mpuSequenceNumber,
|
|
60
|
+
data: fragment.data,
|
|
61
|
+
timestamp: fragment.timestamp,
|
|
62
|
+
fragmentCount: 1,
|
|
63
|
+
rapFlag: fragment.rapFlag,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// Get or create fragment buffer for this MPU
|
|
67
|
+
let fragments = __classPrivateFieldGet(this, _MFUReassembler_buffers, "f").get(mpuSequenceNumber);
|
|
68
|
+
if (!fragments) {
|
|
69
|
+
fragments = [];
|
|
70
|
+
__classPrivateFieldGet(this, _MFUReassembler_buffers, "f").set(mpuSequenceNumber, fragments);
|
|
71
|
+
__classPrivateFieldGet(this, _MFUReassembler_instances, "m", _MFUReassembler_setTimeout).call(this, mpuSequenceNumber);
|
|
72
|
+
}
|
|
73
|
+
// Check for duplicate fragment
|
|
74
|
+
const existingIdx = fragments.findIndex((f) => f.fragmentCounter === fragmentCounter);
|
|
75
|
+
if (existingIdx >= 0) {
|
|
76
|
+
fragments[existingIdx] = fragment;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
fragments.push(fragment);
|
|
80
|
+
}
|
|
81
|
+
// Track out-of-order delivery
|
|
82
|
+
if (fragments.length > 1) {
|
|
83
|
+
const lastFI = fragments[fragments.length - 2].fragmentationIndicator;
|
|
84
|
+
if (fragmentationIndicator !== lastFI + 1) {
|
|
85
|
+
this.stats.outOfOrderFragments++;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Enforce memory limits
|
|
89
|
+
__classPrivateFieldGet(this, _MFUReassembler_instances, "m", _MFUReassembler_enforceMemoryLimit).call(this);
|
|
90
|
+
// Try to reassemble
|
|
91
|
+
return __classPrivateFieldGet(this, _MFUReassembler_instances, "m", _MFUReassembler_tryReassemble).call(this, mpuSequenceNumber);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Flush all buffered fragments
|
|
95
|
+
*/
|
|
96
|
+
flush() {
|
|
97
|
+
for (const mpuSeq of __classPrivateFieldGet(this, _MFUReassembler_buffers, "f").keys()) {
|
|
98
|
+
__classPrivateFieldGet(this, _MFUReassembler_instances, "m", _MFUReassembler_clearTimeout).call(this, mpuSeq);
|
|
99
|
+
}
|
|
100
|
+
__classPrivateFieldGet(this, _MFUReassembler_buffers, "f").clear();
|
|
101
|
+
__classPrivateFieldGet(this, _MFUReassembler_timeouts, "f").clear();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get number of pending MFUs
|
|
105
|
+
*/
|
|
106
|
+
get pendingCount() {
|
|
107
|
+
return __classPrivateFieldGet(this, _MFUReassembler_buffers, "f").size;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get current buffer status
|
|
111
|
+
*/
|
|
112
|
+
getStatus() {
|
|
113
|
+
let pendingFragments = 0;
|
|
114
|
+
for (const fragments of __classPrivateFieldGet(this, _MFUReassembler_buffers, "f").values()) {
|
|
115
|
+
pendingFragments += fragments.length;
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
bufferedMFUs: __classPrivateFieldGet(this, _MFUReassembler_buffers, "f").size,
|
|
119
|
+
pendingFragments,
|
|
120
|
+
stats: { ...this.stats },
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
_MFUReassembler_buffers = new WeakMap(), _MFUReassembler_timeouts = new WeakMap(), _MFUReassembler_timeoutMs = new WeakMap(), _MFUReassembler_maxBuffered = new WeakMap(), _MFUReassembler_instances = new WeakSet(), _MFUReassembler_tryReassemble = function _MFUReassembler_tryReassemble(mpuSequenceNumber) {
|
|
125
|
+
const fragments = __classPrivateFieldGet(this, _MFUReassembler_buffers, "f").get(mpuSequenceNumber);
|
|
126
|
+
if (!fragments || fragments.length === 0) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
// Sort by fragment counter
|
|
130
|
+
fragments.sort((a, b) => a.fragmentCounter - b.fragmentCounter);
|
|
131
|
+
const firstFI = fragments[0].fragmentationIndicator;
|
|
132
|
+
const lastFI = fragments[fragments.length - 1].fragmentationIndicator;
|
|
133
|
+
// Need first (FI=1) and last (FI=3) fragments
|
|
134
|
+
if (firstFI !== 1 || lastFI !== 3) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
// Verify middle fragments have FI=2
|
|
138
|
+
for (let i = 1; i < fragments.length - 1; i++) {
|
|
139
|
+
if (fragments[i].fragmentationIndicator !== 2) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Reassemble: concatenate all fragment data
|
|
144
|
+
const totalSize = fragments.reduce((sum, f) => sum + f.data.length, 0);
|
|
145
|
+
const data = new Uint8Array(totalSize);
|
|
146
|
+
let offset = 0;
|
|
147
|
+
for (const fragment of fragments) {
|
|
148
|
+
data.set(fragment.data, offset);
|
|
149
|
+
offset += fragment.data.length;
|
|
150
|
+
}
|
|
151
|
+
// Cleanup
|
|
152
|
+
__classPrivateFieldGet(this, _MFUReassembler_instances, "m", _MFUReassembler_clearTimeout).call(this, mpuSequenceNumber);
|
|
153
|
+
__classPrivateFieldGet(this, _MFUReassembler_buffers, "f").delete(mpuSequenceNumber);
|
|
154
|
+
this.stats.reassembledMFUs++;
|
|
155
|
+
return {
|
|
156
|
+
mpuSequenceNumber,
|
|
157
|
+
data,
|
|
158
|
+
timestamp: fragments[0].timestamp,
|
|
159
|
+
fragmentCount: fragments.length,
|
|
160
|
+
rapFlag: fragments[0].rapFlag,
|
|
161
|
+
};
|
|
162
|
+
}, _MFUReassembler_setTimeout = function _MFUReassembler_setTimeout(mpuSequenceNumber) {
|
|
163
|
+
const timeoutId = setTimeout(() => {
|
|
164
|
+
__classPrivateFieldGet(this, _MFUReassembler_instances, "m", _MFUReassembler_onTimeout).call(this, mpuSequenceNumber);
|
|
165
|
+
}, __classPrivateFieldGet(this, _MFUReassembler_timeoutMs, "f"));
|
|
166
|
+
__classPrivateFieldGet(this, _MFUReassembler_timeouts, "f").set(mpuSequenceNumber, timeoutId);
|
|
167
|
+
}, _MFUReassembler_clearTimeout = function _MFUReassembler_clearTimeout(mpuSequenceNumber) {
|
|
168
|
+
const timeoutId = __classPrivateFieldGet(this, _MFUReassembler_timeouts, "f").get(mpuSequenceNumber);
|
|
169
|
+
if (timeoutId !== undefined) {
|
|
170
|
+
clearTimeout(timeoutId);
|
|
171
|
+
__classPrivateFieldGet(this, _MFUReassembler_timeouts, "f").delete(mpuSequenceNumber);
|
|
172
|
+
}
|
|
173
|
+
}, _MFUReassembler_onTimeout = function _MFUReassembler_onTimeout(mpuSequenceNumber) {
|
|
174
|
+
const fragments = __classPrivateFieldGet(this, _MFUReassembler_buffers, "f").get(mpuSequenceNumber);
|
|
175
|
+
if (!fragments)
|
|
176
|
+
return;
|
|
177
|
+
this.stats.timedOutMFUs++;
|
|
178
|
+
__classPrivateFieldGet(this, _MFUReassembler_buffers, "f").delete(mpuSequenceNumber);
|
|
179
|
+
__classPrivateFieldGet(this, _MFUReassembler_timeouts, "f").delete(mpuSequenceNumber);
|
|
180
|
+
}, _MFUReassembler_enforceMemoryLimit = function _MFUReassembler_enforceMemoryLimit() {
|
|
181
|
+
if (__classPrivateFieldGet(this, _MFUReassembler_buffers, "f").size <= __classPrivateFieldGet(this, _MFUReassembler_maxBuffered, "f"))
|
|
182
|
+
return;
|
|
183
|
+
const sequences = Array.from(__classPrivateFieldGet(this, _MFUReassembler_buffers, "f").keys()).sort((a, b) => a - b);
|
|
184
|
+
const toRemove = sequences.slice(0, sequences.length - __classPrivateFieldGet(this, _MFUReassembler_maxBuffered, "f"));
|
|
185
|
+
for (const mpuSeq of toRemove) {
|
|
186
|
+
__classPrivateFieldGet(this, _MFUReassembler_instances, "m", _MFUReassembler_clearTimeout).call(this, mpuSeq);
|
|
187
|
+
__classPrivateFieldGet(this, _MFUReassembler_buffers, "f").delete(mpuSeq);
|
|
188
|
+
this.stats.timedOutMFUs++;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Create MFU fragment from MMTP packet for reassembly
|
|
193
|
+
*/
|
|
194
|
+
export function createFragment(mmtpPacket) {
|
|
195
|
+
const { header, payload } = unwrapMMTP(mmtpPacket);
|
|
196
|
+
const mpuHeader = parseMPUHeader(payload);
|
|
197
|
+
const { mpuSequenceNumber, fragmentationIndicator, fragmentCounter } = mpuHeader;
|
|
198
|
+
// MFU DU header is present only for FI = 0 (complete) or FI = 1 (first)
|
|
199
|
+
const hasMfuHeader = fragmentationIndicator === 0 || fragmentationIndicator === 1;
|
|
200
|
+
const headerSize = MPU_HEADER_SIZE + (hasMfuHeader ? MFU_DU_HEADER_SIZE : 0);
|
|
201
|
+
if (payload.length < headerSize) {
|
|
202
|
+
throw new Error(`Payload too small for headers: ${payload.length} bytes (need ${headerSize})`);
|
|
203
|
+
}
|
|
204
|
+
const data = payload.subarray(headerSize);
|
|
205
|
+
return {
|
|
206
|
+
fragmentationIndicator,
|
|
207
|
+
mpuSequenceNumber,
|
|
208
|
+
fragmentCounter,
|
|
209
|
+
data,
|
|
210
|
+
timestamp: header.timestamp,
|
|
211
|
+
receivedAt: typeof performance !== 'undefined' ? performance.now() : Date.now(),
|
|
212
|
+
rapFlag: header.rapFlag,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Process MMTP packet with fragment reassembly
|
|
217
|
+
*/
|
|
218
|
+
export function processMMTPWithReassembly(mmtpPacket, reassembler) {
|
|
219
|
+
// Skip FEC repair packets
|
|
220
|
+
if (isFecRepairPacket(mmtpPacket)) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const fragment = createFragment(mmtpPacket);
|
|
224
|
+
return reassembler.addFragment(fragment);
|
|
225
|
+
}
|
|
226
|
+
// =============================================================================
|
|
227
|
+
// Inline Tests (vitest)
|
|
228
|
+
// =============================================================================
|
|
229
|
+
if (import.meta.vitest) {
|
|
230
|
+
const { describe, test, expect } = import.meta.vitest;
|
|
231
|
+
describe('MFUReassembler', () => {
|
|
232
|
+
test('should return complete MFU for FI=0', () => {
|
|
233
|
+
const reassembler = new MFUReassembler();
|
|
234
|
+
const result = reassembler.addFragment({
|
|
235
|
+
fragmentationIndicator: 0,
|
|
236
|
+
mpuSequenceNumber: 1,
|
|
237
|
+
fragmentCounter: 0,
|
|
238
|
+
data: new Uint8Array([1, 2, 3, 4]),
|
|
239
|
+
timestamp: 1000n,
|
|
240
|
+
receivedAt: 0,
|
|
241
|
+
rapFlag: true,
|
|
242
|
+
});
|
|
243
|
+
expect(result).not.toBeNull();
|
|
244
|
+
expect(result?.data).toEqual(new Uint8Array([1, 2, 3, 4]));
|
|
245
|
+
expect(result?.fragmentCount).toBe(1);
|
|
246
|
+
expect(result?.rapFlag).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
test('should buffer and reassemble 2 fragments', () => {
|
|
249
|
+
const reassembler = new MFUReassembler();
|
|
250
|
+
// First fragment (FI=1)
|
|
251
|
+
const result1 = reassembler.addFragment({
|
|
252
|
+
fragmentationIndicator: 1,
|
|
253
|
+
mpuSequenceNumber: 1,
|
|
254
|
+
fragmentCounter: 0,
|
|
255
|
+
data: new Uint8Array([1, 2]),
|
|
256
|
+
timestamp: 1000n,
|
|
257
|
+
receivedAt: 0,
|
|
258
|
+
rapFlag: true,
|
|
259
|
+
});
|
|
260
|
+
expect(result1).toBeNull();
|
|
261
|
+
// Last fragment (FI=3)
|
|
262
|
+
const result2 = reassembler.addFragment({
|
|
263
|
+
fragmentationIndicator: 3,
|
|
264
|
+
mpuSequenceNumber: 1,
|
|
265
|
+
fragmentCounter: 1,
|
|
266
|
+
data: new Uint8Array([3, 4]),
|
|
267
|
+
timestamp: 1000n,
|
|
268
|
+
receivedAt: 0,
|
|
269
|
+
rapFlag: false,
|
|
270
|
+
});
|
|
271
|
+
expect(result2).not.toBeNull();
|
|
272
|
+
expect(result2?.data).toEqual(new Uint8Array([1, 2, 3, 4]));
|
|
273
|
+
expect(result2?.fragmentCount).toBe(2);
|
|
274
|
+
expect(result2?.rapFlag).toBe(true); // Should use first fragment's rapFlag
|
|
275
|
+
});
|
|
276
|
+
test('should handle out-of-order fragments', () => {
|
|
277
|
+
const reassembler = new MFUReassembler();
|
|
278
|
+
// Last fragment first (FI=3)
|
|
279
|
+
reassembler.addFragment({
|
|
280
|
+
fragmentationIndicator: 3,
|
|
281
|
+
mpuSequenceNumber: 1,
|
|
282
|
+
fragmentCounter: 1,
|
|
283
|
+
data: new Uint8Array([3, 4]),
|
|
284
|
+
timestamp: 1000n,
|
|
285
|
+
receivedAt: 0,
|
|
286
|
+
rapFlag: false,
|
|
287
|
+
});
|
|
288
|
+
// Then first fragment (FI=1)
|
|
289
|
+
const result = reassembler.addFragment({
|
|
290
|
+
fragmentationIndicator: 1,
|
|
291
|
+
mpuSequenceNumber: 1,
|
|
292
|
+
fragmentCounter: 0,
|
|
293
|
+
data: new Uint8Array([1, 2]),
|
|
294
|
+
timestamp: 1000n,
|
|
295
|
+
receivedAt: 0,
|
|
296
|
+
rapFlag: true,
|
|
297
|
+
});
|
|
298
|
+
expect(result).not.toBeNull();
|
|
299
|
+
expect(result?.data).toEqual(new Uint8Array([1, 2, 3, 4]));
|
|
300
|
+
expect(result?.rapFlag).toBe(true);
|
|
301
|
+
});
|
|
302
|
+
test('should track pending count', () => {
|
|
303
|
+
const reassembler = new MFUReassembler();
|
|
304
|
+
expect(reassembler.pendingCount).toBe(0);
|
|
305
|
+
reassembler.addFragment({
|
|
306
|
+
fragmentationIndicator: 1,
|
|
307
|
+
mpuSequenceNumber: 1,
|
|
308
|
+
fragmentCounter: 0,
|
|
309
|
+
data: new Uint8Array([1]),
|
|
310
|
+
timestamp: 1000n,
|
|
311
|
+
receivedAt: 0,
|
|
312
|
+
rapFlag: false,
|
|
313
|
+
});
|
|
314
|
+
expect(reassembler.pendingCount).toBe(1);
|
|
315
|
+
reassembler.flush();
|
|
316
|
+
expect(reassembler.pendingCount).toBe(0);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=mfu-reassembler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mfu-reassembler.js","sourceRoot":"","sources":["../src/mfu-reassembler.ts"],"names":[],"mappings":"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"}
|
package/dist/mmtp.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mmt/container - MMTP Parser
|
|
3
|
+
*
|
|
4
|
+
* MMTP (MMT Protocol) packet parser based on ISO/IEC 23008-1:2023 Section 9.2
|
|
5
|
+
*
|
|
6
|
+
* MMTP header format (12 bytes):
|
|
7
|
+
* - Byte 0: V(2) | C(1) | FEC_type(2) | r(1) | X(1) | R(1)
|
|
8
|
+
* - Byte 1: packet_type(6) | reserved(2)
|
|
9
|
+
* - Bytes 2-3: packet_id (big-endian)
|
|
10
|
+
* - Bytes 4-7: timestamp (big-endian, 32-bit)
|
|
11
|
+
* - Bytes 8-11: sequence_number (big-endian)
|
|
12
|
+
*
|
|
13
|
+
* FEC_type values:
|
|
14
|
+
* - 0: No FEC / source packet
|
|
15
|
+
* - 1: FEC mode 0 (source with FEC payload ID)
|
|
16
|
+
* - 2: FEC repair packet mode 0
|
|
17
|
+
* - 3: FEC repair packet mode 1
|
|
18
|
+
*
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
export interface MMTPHeader {
|
|
22
|
+
version: number;
|
|
23
|
+
packetId: number;
|
|
24
|
+
timestamp: bigint;
|
|
25
|
+
sequenceNumber: number;
|
|
26
|
+
payloadLength: number;
|
|
27
|
+
fecType: number;
|
|
28
|
+
/** Random Access Point flag - indicates keyframe (ISO 23008-1, byte 0 bit 0) */
|
|
29
|
+
rapFlag: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface MPUHeader {
|
|
32
|
+
mpuSequenceNumber: number;
|
|
33
|
+
fragmentationIndicator: number;
|
|
34
|
+
fragmentCounter: number;
|
|
35
|
+
}
|
|
36
|
+
export interface MMTPPacket {
|
|
37
|
+
header: MMTPHeader;
|
|
38
|
+
payload: Uint8Array;
|
|
39
|
+
}
|
|
40
|
+
export declare const MMTP_HEADER_SIZE = 12;
|
|
41
|
+
export declare const MPU_HEADER_SIZE = 8;
|
|
42
|
+
export declare const MFU_DU_HEADER_SIZE = 14;
|
|
43
|
+
/**
|
|
44
|
+
* Parse MMTP header from buffer
|
|
45
|
+
*/
|
|
46
|
+
export declare function parseMMTPHeader(buffer: Uint8Array): MMTPHeader;
|
|
47
|
+
/**
|
|
48
|
+
* Unwrap MMTP packet to extract payload
|
|
49
|
+
*/
|
|
50
|
+
export declare function unwrapMMTP(buffer: Uint8Array): MMTPPacket;
|
|
51
|
+
/**
|
|
52
|
+
* Parse MPU header from payload
|
|
53
|
+
* ISO/IEC 23008-1:2023 Section 9.2.3.3
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseMPUHeader(payload: Uint8Array): MPUHeader;
|
|
56
|
+
/**
|
|
57
|
+
* Extract NAL unit payload from MMTP packet
|
|
58
|
+
*/
|
|
59
|
+
export declare function extractNALUnit(mmtpPacket: Uint8Array): Uint8Array;
|
|
60
|
+
/**
|
|
61
|
+
* Extract timestamp from MMTP packet
|
|
62
|
+
*/
|
|
63
|
+
export declare function extractTimestamp(mmtpPacket: Uint8Array): bigint;
|
|
64
|
+
/**
|
|
65
|
+
* Check if MMTP packet is an FEC repair packet
|
|
66
|
+
* FEC_type 2 and 3 are repair packets
|
|
67
|
+
*/
|
|
68
|
+
export declare function isFecRepairPacket(mmtpPacket: Uint8Array): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Check if MMTP packet has FEC payload ID (FEC_type 1 or higher)
|
|
71
|
+
*/
|
|
72
|
+
export declare function hasFecPayloadId(mmtpPacket: Uint8Array): boolean;
|
|
73
|
+
//# sourceMappingURL=mmtp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mmtp.d.ts","sourceRoot":"","sources":["../src/mmtp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,UAAU,CAAA;CACpB;AAED,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAClC,eAAO,MAAM,eAAe,IAAI,CAAA;AAChC,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAqC9D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAKzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAqB7D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU,CAmBjE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAG/D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAIjE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAI/D"}
|
package/dist/mmtp.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mmt/container - MMTP Parser
|
|
3
|
+
*
|
|
4
|
+
* MMTP (MMT Protocol) packet parser based on ISO/IEC 23008-1:2023 Section 9.2
|
|
5
|
+
*
|
|
6
|
+
* MMTP header format (12 bytes):
|
|
7
|
+
* - Byte 0: V(2) | C(1) | FEC_type(2) | r(1) | X(1) | R(1)
|
|
8
|
+
* - Byte 1: packet_type(6) | reserved(2)
|
|
9
|
+
* - Bytes 2-3: packet_id (big-endian)
|
|
10
|
+
* - Bytes 4-7: timestamp (big-endian, 32-bit)
|
|
11
|
+
* - Bytes 8-11: sequence_number (big-endian)
|
|
12
|
+
*
|
|
13
|
+
* FEC_type values:
|
|
14
|
+
* - 0: No FEC / source packet
|
|
15
|
+
* - 1: FEC mode 0 (source with FEC payload ID)
|
|
16
|
+
* - 2: FEC repair packet mode 0
|
|
17
|
+
* - 3: FEC repair packet mode 1
|
|
18
|
+
*
|
|
19
|
+
* @packageDocumentation
|
|
20
|
+
*/
|
|
21
|
+
export const MMTP_HEADER_SIZE = 12;
|
|
22
|
+
export const MPU_HEADER_SIZE = 8;
|
|
23
|
+
export const MFU_DU_HEADER_SIZE = 14;
|
|
24
|
+
/**
|
|
25
|
+
* Parse MMTP header from buffer
|
|
26
|
+
*/
|
|
27
|
+
export function parseMMTPHeader(buffer) {
|
|
28
|
+
if (buffer.length < MMTP_HEADER_SIZE) {
|
|
29
|
+
throw new Error(`MMTP packet too small: ${buffer.length} bytes`);
|
|
30
|
+
}
|
|
31
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
32
|
+
// Extract FEC type from byte 0, bits 3-4
|
|
33
|
+
const fecType = (buffer[0] >> 3) & 0x03;
|
|
34
|
+
// Extract RAP flag from byte 0, bit 0 (R bit - Random Access Point)
|
|
35
|
+
const rapFlag = (buffer[0] & 0x01) === 1;
|
|
36
|
+
// Skip bytes 0-1 (flags and packet_type)
|
|
37
|
+
let offset = 2;
|
|
38
|
+
// Packet ID (2 bytes, big-endian)
|
|
39
|
+
const packetId = view.getUint16(offset, false);
|
|
40
|
+
offset += 2;
|
|
41
|
+
// Timestamp (4 bytes, big-endian)
|
|
42
|
+
const timestamp = BigInt(view.getUint32(offset, false));
|
|
43
|
+
offset += 4;
|
|
44
|
+
// Sequence number (4 bytes, big-endian)
|
|
45
|
+
const sequenceNumber = view.getUint32(offset, false);
|
|
46
|
+
offset += 4;
|
|
47
|
+
return {
|
|
48
|
+
version: 1,
|
|
49
|
+
packetId,
|
|
50
|
+
timestamp,
|
|
51
|
+
sequenceNumber,
|
|
52
|
+
payloadLength: buffer.length - offset,
|
|
53
|
+
fecType,
|
|
54
|
+
rapFlag,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Unwrap MMTP packet to extract payload
|
|
59
|
+
*/
|
|
60
|
+
export function unwrapMMTP(buffer) {
|
|
61
|
+
const header = parseMMTPHeader(buffer);
|
|
62
|
+
const payload = buffer.subarray(MMTP_HEADER_SIZE);
|
|
63
|
+
return { header, payload };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Parse MPU header from payload
|
|
67
|
+
* ISO/IEC 23008-1:2023 Section 9.2.3.3
|
|
68
|
+
*/
|
|
69
|
+
export function parseMPUHeader(payload) {
|
|
70
|
+
if (payload.length < MPU_HEADER_SIZE) {
|
|
71
|
+
throw new Error(`Payload too small for MPU header: ${payload.length} bytes`);
|
|
72
|
+
}
|
|
73
|
+
const view = new DataView(payload.buffer, payload.byteOffset, payload.byteLength);
|
|
74
|
+
// MPU sequence number (4 bytes, big-endian)
|
|
75
|
+
const mpuSequenceNumber = view.getUint32(0, false);
|
|
76
|
+
// Fragmentation indicator (byte 5, bits 0-1)
|
|
77
|
+
const fragmentationIndicator = payload[5] & 0x03;
|
|
78
|
+
// Fragment counter (bytes 6-7, big-endian)
|
|
79
|
+
const fragmentCounter = view.getUint16(6, false);
|
|
80
|
+
return {
|
|
81
|
+
mpuSequenceNumber,
|
|
82
|
+
fragmentationIndicator,
|
|
83
|
+
fragmentCounter,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Extract NAL unit payload from MMTP packet
|
|
88
|
+
*/
|
|
89
|
+
export function extractNALUnit(mmtpPacket) {
|
|
90
|
+
const { payload } = unwrapMMTP(mmtpPacket);
|
|
91
|
+
if (payload.length < MPU_HEADER_SIZE) {
|
|
92
|
+
throw new Error(`Payload too small for MPU header: ${payload.length} bytes`);
|
|
93
|
+
}
|
|
94
|
+
// Parse MPU header to check fragmentation indicator
|
|
95
|
+
const fragmentationIndicator = payload[5] & 0x03;
|
|
96
|
+
// MFU DU header is present only for FI = 0 (complete) or FI = 1 (first)
|
|
97
|
+
const hasMfuHeader = fragmentationIndicator === 0 || fragmentationIndicator === 1;
|
|
98
|
+
const headerSize = MPU_HEADER_SIZE + (hasMfuHeader ? MFU_DU_HEADER_SIZE : 0);
|
|
99
|
+
if (payload.length < headerSize) {
|
|
100
|
+
throw new Error(`Payload too small for headers: ${payload.length} bytes (need ${headerSize})`);
|
|
101
|
+
}
|
|
102
|
+
return payload.subarray(headerSize);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Extract timestamp from MMTP packet
|
|
106
|
+
*/
|
|
107
|
+
export function extractTimestamp(mmtpPacket) {
|
|
108
|
+
const { header } = unwrapMMTP(mmtpPacket);
|
|
109
|
+
return header.timestamp;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if MMTP packet is an FEC repair packet
|
|
113
|
+
* FEC_type 2 and 3 are repair packets
|
|
114
|
+
*/
|
|
115
|
+
export function isFecRepairPacket(mmtpPacket) {
|
|
116
|
+
if (mmtpPacket.length < 1)
|
|
117
|
+
return false;
|
|
118
|
+
const fecType = (mmtpPacket[0] >> 3) & 0x03;
|
|
119
|
+
return fecType >= 2;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check if MMTP packet has FEC payload ID (FEC_type 1 or higher)
|
|
123
|
+
*/
|
|
124
|
+
export function hasFecPayloadId(mmtpPacket) {
|
|
125
|
+
if (mmtpPacket.length < 1)
|
|
126
|
+
return false;
|
|
127
|
+
const fecType = (mmtpPacket[0] >> 3) & 0x03;
|
|
128
|
+
return fecType >= 1;
|
|
129
|
+
}
|
|
130
|
+
// =============================================================================
|
|
131
|
+
// Inline Tests (vitest)
|
|
132
|
+
// =============================================================================
|
|
133
|
+
if (import.meta.vitest) {
|
|
134
|
+
const { describe, test, expect } = import.meta.vitest;
|
|
135
|
+
describe('MMTP Parser', () => {
|
|
136
|
+
// Helper to create a minimal MMTP packet
|
|
137
|
+
function createTestPacket(opts) {
|
|
138
|
+
const fecType = opts.fecType ?? 0;
|
|
139
|
+
const packetId = opts.packetId ?? 1;
|
|
140
|
+
const timestamp = opts.timestamp ?? 12345;
|
|
141
|
+
const sequenceNumber = opts.sequenceNumber ?? 1;
|
|
142
|
+
const payload = opts.payload ?? new Uint8Array([0x00, 0x00, 0x00, 0x01]);
|
|
143
|
+
const header = new Uint8Array(12);
|
|
144
|
+
const view = new DataView(header.buffer);
|
|
145
|
+
// Byte 0: V=1, C=0, FEC_type, r=0, X=0, R=0
|
|
146
|
+
header[0] = (1 << 6) | (fecType << 3);
|
|
147
|
+
// Byte 1: packet_type=0 (MPU)
|
|
148
|
+
header[1] = 0;
|
|
149
|
+
view.setUint16(2, packetId, false);
|
|
150
|
+
view.setUint32(4, timestamp, false);
|
|
151
|
+
view.setUint32(8, sequenceNumber, false);
|
|
152
|
+
const result = new Uint8Array(header.length + payload.length);
|
|
153
|
+
result.set(header, 0);
|
|
154
|
+
result.set(payload, header.length);
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
describe('parseMMTPHeader', () => {
|
|
158
|
+
test('should parse MMTP header correctly', () => {
|
|
159
|
+
const packet = createTestPacket({
|
|
160
|
+
packetId: 42,
|
|
161
|
+
timestamp: 1000000,
|
|
162
|
+
sequenceNumber: 100,
|
|
163
|
+
});
|
|
164
|
+
const header = parseMMTPHeader(packet);
|
|
165
|
+
expect(header.packetId).toBe(42);
|
|
166
|
+
expect(header.timestamp).toBe(1000000n);
|
|
167
|
+
expect(header.sequenceNumber).toBe(100);
|
|
168
|
+
expect(header.fecType).toBe(0);
|
|
169
|
+
});
|
|
170
|
+
test('should extract FEC type', () => {
|
|
171
|
+
const packet = createTestPacket({ fecType: 2 });
|
|
172
|
+
const header = parseMMTPHeader(packet);
|
|
173
|
+
expect(header.fecType).toBe(2);
|
|
174
|
+
});
|
|
175
|
+
test('should throw on too small packet', () => {
|
|
176
|
+
expect(() => parseMMTPHeader(new Uint8Array(10))).toThrow();
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
describe('isFecRepairPacket', () => {
|
|
180
|
+
test('should return false for source packets (FEC type 0)', () => {
|
|
181
|
+
const packet = createTestPacket({ fecType: 0 });
|
|
182
|
+
expect(isFecRepairPacket(packet)).toBe(false);
|
|
183
|
+
});
|
|
184
|
+
test('should return false for FEC mode 0 source (FEC type 1)', () => {
|
|
185
|
+
const packet = createTestPacket({ fecType: 1 });
|
|
186
|
+
expect(isFecRepairPacket(packet)).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
test('should return true for repair packets (FEC type 2)', () => {
|
|
189
|
+
const packet = createTestPacket({ fecType: 2 });
|
|
190
|
+
expect(isFecRepairPacket(packet)).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
test('should return true for repair packets (FEC type 3)', () => {
|
|
193
|
+
const packet = createTestPacket({ fecType: 3 });
|
|
194
|
+
expect(isFecRepairPacket(packet)).toBe(true);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('hasFecPayloadId', () => {
|
|
198
|
+
test('should return false for no FEC (type 0)', () => {
|
|
199
|
+
const packet = createTestPacket({ fecType: 0 });
|
|
200
|
+
expect(hasFecPayloadId(packet)).toBe(false);
|
|
201
|
+
});
|
|
202
|
+
test('should return true for FEC type 1+', () => {
|
|
203
|
+
expect(hasFecPayloadId(createTestPacket({ fecType: 1 }))).toBe(true);
|
|
204
|
+
expect(hasFecPayloadId(createTestPacket({ fecType: 2 }))).toBe(true);
|
|
205
|
+
expect(hasFecPayloadId(createTestPacket({ fecType: 3 }))).toBe(true);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=mmtp.js.map
|
package/dist/mmtp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mmtp.js","sourceRoot":"","sources":["../src/mmtp.ts"],"names":[],"mappings":"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"}
|