streamkit-orchestrator 0.4.0-alpha.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 +304 -0
- package/dist/controlChannel.d.ts +47 -0
- package/dist/controlChannel.d.ts.map +1 -0
- package/dist/controlChannel.js +149 -0
- package/dist/controlChannel.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +35 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +298 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/types.d.ts +116 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 StreamKit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# @streamkit/orchestrator
|
|
2
|
+
|
|
3
|
+
Lightweight stream orchestrator for coordinating multiple WebRTC streams.
|
|
4
|
+
|
|
5
|
+
## What This Package Does
|
|
6
|
+
|
|
7
|
+
The orchestrator acts as a coordination layer that:
|
|
8
|
+
|
|
9
|
+
- **Registers** multiple named streams (binary or JSON)
|
|
10
|
+
- **Enables/disables** streams dynamically
|
|
11
|
+
- **Routes** incoming data to the correct handler
|
|
12
|
+
- **Coordinates** stream state via control messages
|
|
13
|
+
|
|
14
|
+
## What This Package Does NOT Do
|
|
15
|
+
|
|
16
|
+
- ❌ WebRTC signaling (offer/answer exchange)
|
|
17
|
+
- ❌ Binary frame parsing (delegated to @streamkit/binary-stream)
|
|
18
|
+
- ❌ DataChannel management (delegated to @streamkit/webrtc)
|
|
19
|
+
- ❌ Data decoding or rendering
|
|
20
|
+
- ❌ Retry or reconnection logic
|
|
21
|
+
|
|
22
|
+
## Position in the Stack
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────────────────────┐
|
|
26
|
+
│ Your Application │
|
|
27
|
+
└──────────┬──────────┘
|
|
28
|
+
│
|
|
29
|
+
▼
|
|
30
|
+
┌─────────────────────┐
|
|
31
|
+
│ @streamkit/ │ ← THIS PACKAGE
|
|
32
|
+
│ orchestrator │ Coordinates streams
|
|
33
|
+
└──────────┬──────────┘
|
|
34
|
+
│
|
|
35
|
+
┌─────┴─────┐
|
|
36
|
+
│ │
|
|
37
|
+
▼ ▼
|
|
38
|
+
┌─────────┐ ┌─────────┐
|
|
39
|
+
│ binary │ │ json │
|
|
40
|
+
│ streams │ │ streams │
|
|
41
|
+
└────┬────┘ └────┬────┘
|
|
42
|
+
│ │
|
|
43
|
+
▼ │
|
|
44
|
+
┌─────────────┐ │
|
|
45
|
+
│ @streamkit/ │ │
|
|
46
|
+
│ webrtc │ │
|
|
47
|
+
└──────┬──────┘ │
|
|
48
|
+
│ │
|
|
49
|
+
▼ │
|
|
50
|
+
┌─────────────┐ │
|
|
51
|
+
│ @streamkit/ │ │
|
|
52
|
+
│ binary- │ │
|
|
53
|
+
│ stream │ │
|
|
54
|
+
└──────┬──────┘ │
|
|
55
|
+
│ │
|
|
56
|
+
└────┬────┘
|
|
57
|
+
│
|
|
58
|
+
▼
|
|
59
|
+
┌─────────────────────┐
|
|
60
|
+
│ RTCPeerConnection │
|
|
61
|
+
└─────────────────────┘
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install @streamkit/orchestrator
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quick Start
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { createOrchestrator } from "@streamkit/orchestrator";
|
|
74
|
+
|
|
75
|
+
// You create and configure the peer connection
|
|
76
|
+
const pc = new RTCPeerConnection();
|
|
77
|
+
|
|
78
|
+
// Create orchestrator
|
|
79
|
+
const orch = createOrchestrator({ pc });
|
|
80
|
+
|
|
81
|
+
// Register a binary stream (e.g., point cloud data)
|
|
82
|
+
orch.registerStream({
|
|
83
|
+
name: "pointcloud",
|
|
84
|
+
type: "binary",
|
|
85
|
+
onFrame(frame) {
|
|
86
|
+
console.log("PointCloud frame:", frame.id, frame.payload.byteLength);
|
|
87
|
+
// Pass to @streamkit/pointcloud decoder
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Register a JSON stream (e.g., telemetry)
|
|
92
|
+
orch.registerStream({
|
|
93
|
+
name: "telemetry",
|
|
94
|
+
type: "json",
|
|
95
|
+
onMessage(data) {
|
|
96
|
+
console.log("Telemetry:", data);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Enable streams when ready
|
|
101
|
+
orch.enable("pointcloud");
|
|
102
|
+
orch.enable("telemetry");
|
|
103
|
+
|
|
104
|
+
// Later: disable a stream
|
|
105
|
+
orch.disable("pointcloud");
|
|
106
|
+
|
|
107
|
+
// Cleanup
|
|
108
|
+
orch.dispose();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Mental Model
|
|
112
|
+
|
|
113
|
+
Think of the orchestrator as a **switchboard operator**:
|
|
114
|
+
|
|
115
|
+
1. **Registration** = Plugging in a phone line (no connection yet)
|
|
116
|
+
2. **Enable** = Connecting the call (DataChannel created)
|
|
117
|
+
3. **Disable** = Hanging up (DataChannel closed)
|
|
118
|
+
4. **Control messages** = Signaling to the remote switchboard
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Local Orchestrator Remote Orchestrator
|
|
122
|
+
│ │
|
|
123
|
+
│ ──── control: enable ───► │
|
|
124
|
+
│ │
|
|
125
|
+
│ ◄─── data frames ──────── │
|
|
126
|
+
│ │
|
|
127
|
+
│ ──── control: disable ──► │
|
|
128
|
+
│ │
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## API Reference
|
|
132
|
+
|
|
133
|
+
### `createOrchestrator(options)`
|
|
134
|
+
|
|
135
|
+
Creates a stream orchestrator.
|
|
136
|
+
|
|
137
|
+
**Options:**
|
|
138
|
+
|
|
139
|
+
| Option | Type | Description |
|
|
140
|
+
| ------------------ | ------------------------------- | --------------------------------- |
|
|
141
|
+
| `pc` | `RTCPeerConnection` | The peer connection to manage |
|
|
142
|
+
| `onError` | `(error: Error) => void` | Optional error callback |
|
|
143
|
+
| `onControlMessage` | `(msg: ControlMessage) => void` | Optional control message observer |
|
|
144
|
+
|
|
145
|
+
**Returns:** `Orchestrator`
|
|
146
|
+
|
|
147
|
+
### `Orchestrator`
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
interface Orchestrator {
|
|
151
|
+
registerStream(descriptor: StreamDescriptor): void;
|
|
152
|
+
enable(name: string): void;
|
|
153
|
+
disable(name: string): void;
|
|
154
|
+
isEnabled(name: string): boolean;
|
|
155
|
+
isRegistered(name: string): boolean;
|
|
156
|
+
getStreamNames(): string[];
|
|
157
|
+
sendControl(message: ControlMessage): void;
|
|
158
|
+
dispose(): void;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Stream Descriptors
|
|
163
|
+
|
|
164
|
+
#### Binary Stream
|
|
165
|
+
|
|
166
|
+
For frame-based binary data (point clouds, video frames, sensor data):
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
orch.registerStream({
|
|
170
|
+
name: "pointcloud",
|
|
171
|
+
type: "binary",
|
|
172
|
+
enabledByDefault: false,
|
|
173
|
+
maxFrameSize: 10_000_000, // 10MB max frame
|
|
174
|
+
maxBufferSize: 50_000_000, // 50MB buffer limit
|
|
175
|
+
onFrame(frame) {
|
|
176
|
+
// frame.id: number
|
|
177
|
+
// frame.timestamp: number
|
|
178
|
+
// frame.payload: ArrayBuffer
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### JSON Stream
|
|
184
|
+
|
|
185
|
+
For structured messages (telemetry, commands, events):
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
orch.registerStream({
|
|
189
|
+
name: "telemetry",
|
|
190
|
+
type: "json",
|
|
191
|
+
enabledByDefault: true,
|
|
192
|
+
onMessage(data) {
|
|
193
|
+
// data: unknown (parsed JSON)
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Control Messages
|
|
199
|
+
|
|
200
|
+
Control messages coordinate stream state between peers:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
interface ControlMessage {
|
|
204
|
+
type: "control";
|
|
205
|
+
stream: string;
|
|
206
|
+
enabled: boolean;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Automatic behavior:**
|
|
211
|
+
|
|
212
|
+
- `enable()` sends `{ type: 'control', stream: 'name', enabled: true }`
|
|
213
|
+
- `disable()` sends `{ type: 'control', stream: 'name', enabled: false }`
|
|
214
|
+
|
|
215
|
+
**Manual control:**
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
orch.sendControl({
|
|
219
|
+
type: "control",
|
|
220
|
+
stream: "custom",
|
|
221
|
+
enabled: true,
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Integration with @streamkit/pointcloud
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
import { createOrchestrator } from "@streamkit/orchestrator";
|
|
229
|
+
import { createPointCloudLayer, decodeDraco } from "@streamkit/pointcloud";
|
|
230
|
+
|
|
231
|
+
const scene = new THREE.Scene();
|
|
232
|
+
const layer = createPointCloudLayer({ scene });
|
|
233
|
+
|
|
234
|
+
const orch = createOrchestrator({ pc });
|
|
235
|
+
|
|
236
|
+
orch.registerStream({
|
|
237
|
+
name: "pointcloud",
|
|
238
|
+
type: "binary",
|
|
239
|
+
async onFrame(frame) {
|
|
240
|
+
// Decode Draco-compressed point cloud
|
|
241
|
+
const data = await decodeDraco(frame.payload);
|
|
242
|
+
// Update Three.js layer
|
|
243
|
+
layer.update(data, { mode: "append" });
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
orch.enable("pointcloud");
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Lifecycle
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
┌──────────────┐
|
|
254
|
+
│ registered │ ← registerStream()
|
|
255
|
+
└──────┬───────┘
|
|
256
|
+
│ enable()
|
|
257
|
+
▼
|
|
258
|
+
┌──────────────┐
|
|
259
|
+
│ enabled │ ← DataChannel open, receiving data
|
|
260
|
+
└──────┬───────┘
|
|
261
|
+
│ disable()
|
|
262
|
+
▼
|
|
263
|
+
┌──────────────┐
|
|
264
|
+
│ disabled │ ← DataChannel closed
|
|
265
|
+
└──────┬───────┘
|
|
266
|
+
│ enable() (can re-enable)
|
|
267
|
+
▼
|
|
268
|
+
...
|
|
269
|
+
│
|
|
270
|
+
│ dispose()
|
|
271
|
+
▼
|
|
272
|
+
┌──────────────┐
|
|
273
|
+
│ disposed │ ← All resources released
|
|
274
|
+
└──────────────┘
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## TypeScript
|
|
278
|
+
|
|
279
|
+
Full type exports:
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import type {
|
|
283
|
+
Orchestrator,
|
|
284
|
+
OrchestratorOptions,
|
|
285
|
+
StreamDescriptor,
|
|
286
|
+
BinaryStreamDescriptor,
|
|
287
|
+
JSONStreamDescriptor,
|
|
288
|
+
StreamType,
|
|
289
|
+
ControlMessage,
|
|
290
|
+
BinaryFrame,
|
|
291
|
+
} from "@streamkit/orchestrator";
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Design Principles
|
|
295
|
+
|
|
296
|
+
1. **Lazy initialization**: Channels created only on `enable()`
|
|
297
|
+
2. **Explicit lifecycle**: No hidden state transitions
|
|
298
|
+
3. **Delegation**: Frame parsing and channel management delegated to specialized packages
|
|
299
|
+
4. **Coordination**: Control messages keep both peers in sync
|
|
300
|
+
5. **Minimal surface**: Only what's needed for orchestration
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streamkit/orchestrator - Control Channel
|
|
3
|
+
*
|
|
4
|
+
* Dedicated channel for orchestrator control messages.
|
|
5
|
+
*/
|
|
6
|
+
import type { ControlMessage } from "./types.js";
|
|
7
|
+
/** Reserved channel name for control messages */
|
|
8
|
+
export declare const CONTROL_CHANNEL_LABEL = "__streamkit_control__";
|
|
9
|
+
/**
|
|
10
|
+
* Validates and parses a control message.
|
|
11
|
+
* @param data - Raw message data
|
|
12
|
+
* @returns Parsed ControlMessage or null if invalid
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseControlMessage(data: unknown): ControlMessage | null;
|
|
15
|
+
/**
|
|
16
|
+
* Serializes a control message to JSON string.
|
|
17
|
+
* @param message - Control message to serialize
|
|
18
|
+
*/
|
|
19
|
+
export declare function serializeControlMessage(message: ControlMessage): string;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a control message for stream state change.
|
|
22
|
+
* @param streamName - Name of the stream
|
|
23
|
+
* @param enabled - Whether stream is being enabled
|
|
24
|
+
*/
|
|
25
|
+
export declare function createControlMessage(streamName: string, enabled: boolean): ControlMessage;
|
|
26
|
+
/**
|
|
27
|
+
* Internal control channel manager.
|
|
28
|
+
*/
|
|
29
|
+
export interface ControlChannel {
|
|
30
|
+
send(message: ControlMessage): void;
|
|
31
|
+
close(): void;
|
|
32
|
+
readonly isOpen: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a control channel on the peer connection.
|
|
36
|
+
* @param pc - RTCPeerConnection
|
|
37
|
+
* @param onMessage - Callback for incoming control messages
|
|
38
|
+
* @param onError - Optional error callback
|
|
39
|
+
*/
|
|
40
|
+
export declare function createControlChannel(pc: RTCPeerConnection, onMessage: (message: ControlMessage) => void, onError?: (error: Error) => void): ControlChannel;
|
|
41
|
+
/**
|
|
42
|
+
* Sets up handler for incoming control channels from remote peer.
|
|
43
|
+
* @param pc - RTCPeerConnection
|
|
44
|
+
* @param onMessage - Callback for incoming control messages
|
|
45
|
+
*/
|
|
46
|
+
export declare function handleIncomingControlChannel(pc: RTCPeerConnection, onMessage: (message: ControlMessage) => void): void;
|
|
47
|
+
//# sourceMappingURL=controlChannel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlChannel.d.ts","sourceRoot":"","sources":["../src/controlChannel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,iDAAiD;AACjD,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAoBxE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,cAAc,CAMhB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,EAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAC/B,cAAc,CA0EhB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,GAC3C,IAAI,CA2BN"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streamkit/orchestrator - Control Channel
|
|
3
|
+
*
|
|
4
|
+
* Dedicated channel for orchestrator control messages.
|
|
5
|
+
*/
|
|
6
|
+
/** Reserved channel name for control messages */
|
|
7
|
+
export const CONTROL_CHANNEL_LABEL = "__streamkit_control__";
|
|
8
|
+
/**
|
|
9
|
+
* Validates and parses a control message.
|
|
10
|
+
* @param data - Raw message data
|
|
11
|
+
* @returns Parsed ControlMessage or null if invalid
|
|
12
|
+
*/
|
|
13
|
+
export function parseControlMessage(data) {
|
|
14
|
+
if (typeof data !== "object" || data === null) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const msg = data;
|
|
18
|
+
if (msg.type !== "control" ||
|
|
19
|
+
typeof msg.stream !== "string" ||
|
|
20
|
+
typeof msg.enabled !== "boolean") {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
type: "control",
|
|
25
|
+
stream: msg.stream,
|
|
26
|
+
enabled: msg.enabled,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Serializes a control message to JSON string.
|
|
31
|
+
* @param message - Control message to serialize
|
|
32
|
+
*/
|
|
33
|
+
export function serializeControlMessage(message) {
|
|
34
|
+
return JSON.stringify(message);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates a control message for stream state change.
|
|
38
|
+
* @param streamName - Name of the stream
|
|
39
|
+
* @param enabled - Whether stream is being enabled
|
|
40
|
+
*/
|
|
41
|
+
export function createControlMessage(streamName, enabled) {
|
|
42
|
+
return {
|
|
43
|
+
type: "control",
|
|
44
|
+
stream: streamName,
|
|
45
|
+
enabled,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Creates a control channel on the peer connection.
|
|
50
|
+
* @param pc - RTCPeerConnection
|
|
51
|
+
* @param onMessage - Callback for incoming control messages
|
|
52
|
+
* @param onError - Optional error callback
|
|
53
|
+
*/
|
|
54
|
+
export function createControlChannel(pc, onMessage, onError) {
|
|
55
|
+
const channel = pc.createDataChannel(CONTROL_CHANNEL_LABEL, {
|
|
56
|
+
ordered: true,
|
|
57
|
+
});
|
|
58
|
+
// Control channel uses string messages (JSON)
|
|
59
|
+
channel.binaryType = "arraybuffer"; // Not used, but required
|
|
60
|
+
let isOpen = false;
|
|
61
|
+
let isClosed = false;
|
|
62
|
+
channel.onopen = () => {
|
|
63
|
+
isOpen = true;
|
|
64
|
+
};
|
|
65
|
+
channel.onclose = () => {
|
|
66
|
+
isOpen = false;
|
|
67
|
+
isClosed = true;
|
|
68
|
+
};
|
|
69
|
+
channel.onerror = (event) => {
|
|
70
|
+
const error = new Error(`Control channel error: ${event}`);
|
|
71
|
+
onError?.(error);
|
|
72
|
+
console.error("Orchestrator control channel error:", event);
|
|
73
|
+
};
|
|
74
|
+
channel.onmessage = (event) => {
|
|
75
|
+
try {
|
|
76
|
+
const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
|
|
77
|
+
const message = parseControlMessage(data);
|
|
78
|
+
if (message) {
|
|
79
|
+
onMessage(message);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
console.warn("Orchestrator: invalid control message received", err);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
send(message) {
|
|
88
|
+
if (isClosed) {
|
|
89
|
+
throw new Error("Control channel is closed");
|
|
90
|
+
}
|
|
91
|
+
if (!isOpen) {
|
|
92
|
+
// Queue message until channel opens
|
|
93
|
+
const checkAndSend = () => {
|
|
94
|
+
if (isOpen && !isClosed) {
|
|
95
|
+
channel.send(serializeControlMessage(message));
|
|
96
|
+
}
|
|
97
|
+
else if (!isClosed) {
|
|
98
|
+
setTimeout(checkAndSend, 10);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
checkAndSend();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
channel.send(serializeControlMessage(message));
|
|
105
|
+
},
|
|
106
|
+
close() {
|
|
107
|
+
if (!isClosed) {
|
|
108
|
+
isClosed = true;
|
|
109
|
+
isOpen = false;
|
|
110
|
+
channel.close();
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
get isOpen() {
|
|
114
|
+
return isOpen;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Sets up handler for incoming control channels from remote peer.
|
|
120
|
+
* @param pc - RTCPeerConnection
|
|
121
|
+
* @param onMessage - Callback for incoming control messages
|
|
122
|
+
*/
|
|
123
|
+
export function handleIncomingControlChannel(pc, onMessage) {
|
|
124
|
+
const existingHandler = pc.ondatachannel;
|
|
125
|
+
pc.ondatachannel = (event) => {
|
|
126
|
+
if (event.channel.label === CONTROL_CHANNEL_LABEL) {
|
|
127
|
+
const channel = event.channel;
|
|
128
|
+
channel.onmessage = (msgEvent) => {
|
|
129
|
+
try {
|
|
130
|
+
const data = typeof msgEvent.data === "string"
|
|
131
|
+
? JSON.parse(msgEvent.data)
|
|
132
|
+
: null;
|
|
133
|
+
const message = parseControlMessage(data);
|
|
134
|
+
if (message) {
|
|
135
|
+
onMessage(message);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
console.warn("Orchestrator: invalid control message received", err);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// Pass through to existing handler if any
|
|
145
|
+
existingHandler?.call(pc, event);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=controlChannel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controlChannel.js","sourceRoot":"","sources":["../src/controlChannel.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streamkit/orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Lightweight stream orchestrator for coordinating multiple WebRTC streams.
|
|
5
|
+
*
|
|
6
|
+
* This package provides:
|
|
7
|
+
* - Multi-stream registration and management
|
|
8
|
+
* - Dynamic enable/disable of streams
|
|
9
|
+
* - Control message coordination
|
|
10
|
+
* - Automatic routing to stream handlers
|
|
11
|
+
*
|
|
12
|
+
* This package does NOT provide:
|
|
13
|
+
* - WebRTC signaling
|
|
14
|
+
* - Binary frame parsing (delegated to @streamkit/binary-stream)
|
|
15
|
+
* - DataChannel management (delegated to @streamkit/webrtc)
|
|
16
|
+
* - Data decoding or rendering
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
export type { BaseStreamDescriptor, BinaryFrame, BinaryStreamDescriptor, ControlMessage, JSONStreamDescriptor, Orchestrator, OrchestratorOptions, StreamDescriptor, StreamType, } from "./types.js";
|
|
21
|
+
export { createOrchestrator } from "./orchestrator.js";
|
|
22
|
+
export { CONTROL_CHANNEL_LABEL, createControlMessage, parseControlMessage, } from "./controlChannel.js";
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,sBAAsB,EACtB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAMvD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streamkit/orchestrator
|
|
3
|
+
*
|
|
4
|
+
* Lightweight stream orchestrator for coordinating multiple WebRTC streams.
|
|
5
|
+
*
|
|
6
|
+
* This package provides:
|
|
7
|
+
* - Multi-stream registration and management
|
|
8
|
+
* - Dynamic enable/disable of streams
|
|
9
|
+
* - Control message coordination
|
|
10
|
+
* - Automatic routing to stream handlers
|
|
11
|
+
*
|
|
12
|
+
* This package does NOT provide:
|
|
13
|
+
* - WebRTC signaling
|
|
14
|
+
* - Binary frame parsing (delegated to @streamkit/binary-stream)
|
|
15
|
+
* - DataChannel management (delegated to @streamkit/webrtc)
|
|
16
|
+
* - Data decoding or rendering
|
|
17
|
+
*
|
|
18
|
+
* @packageDocumentation
|
|
19
|
+
*/
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// Orchestrator Factory
|
|
22
|
+
// =============================================================================
|
|
23
|
+
export { createOrchestrator } from "./orchestrator.js";
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Control Channel Utilities
|
|
26
|
+
// =============================================================================
|
|
27
|
+
export { CONTROL_CHANNEL_LABEL, createControlMessage, parseControlMessage, } from "./controlChannel.js";
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAkBH,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,gFAAgF;AAChF,4BAA4B;AAC5B,gFAAgF;AAEhF,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streamkit/orchestrator - Stream Orchestrator Implementation
|
|
3
|
+
*
|
|
4
|
+
* Coordinates multiple logical streams over a single RTCPeerConnection.
|
|
5
|
+
*/
|
|
6
|
+
import type { Orchestrator, OrchestratorOptions } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Creates a stream orchestrator for coordinating multiple WebRTC streams.
|
|
9
|
+
*
|
|
10
|
+
* The orchestrator:
|
|
11
|
+
* - Registers streams by unique name
|
|
12
|
+
* - Lazily creates DataChannels on enable()
|
|
13
|
+
* - Routes incoming data to correct handlers
|
|
14
|
+
* - Sends/receives control messages for coordination
|
|
15
|
+
*
|
|
16
|
+
* @param options - Orchestrator configuration
|
|
17
|
+
* @returns Orchestrator controller
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const orch = createOrchestrator({ pc });
|
|
22
|
+
*
|
|
23
|
+
* orch.registerStream({
|
|
24
|
+
* name: 'pointcloud',
|
|
25
|
+
* type: 'binary',
|
|
26
|
+
* onFrame(frame) {
|
|
27
|
+
* console.log('Frame:', frame.id);
|
|
28
|
+
* }
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* orch.enable('pointcloud');
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function createOrchestrator(options: OrchestratorOptions): Orchestrator;
|
|
35
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,OAAO,KAAK,EAIV,YAAY,EACZ,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAepB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAgV7E"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streamkit/orchestrator - Stream Orchestrator Implementation
|
|
3
|
+
*
|
|
4
|
+
* Coordinates multiple logical streams over a single RTCPeerConnection.
|
|
5
|
+
*/
|
|
6
|
+
import { createBinaryStream } from "@streamkit/binary-stream";
|
|
7
|
+
import { createWebRTCBinaryChannel, wrapDataChannel } from "@streamkit/webrtc";
|
|
8
|
+
import { CONTROL_CHANNEL_LABEL, createControlChannel, createControlMessage, handleIncomingControlChannel, } from "./controlChannel.js";
|
|
9
|
+
/**
|
|
10
|
+
* Creates a stream orchestrator for coordinating multiple WebRTC streams.
|
|
11
|
+
*
|
|
12
|
+
* The orchestrator:
|
|
13
|
+
* - Registers streams by unique name
|
|
14
|
+
* - Lazily creates DataChannels on enable()
|
|
15
|
+
* - Routes incoming data to correct handlers
|
|
16
|
+
* - Sends/receives control messages for coordination
|
|
17
|
+
*
|
|
18
|
+
* @param options - Orchestrator configuration
|
|
19
|
+
* @returns Orchestrator controller
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const orch = createOrchestrator({ pc });
|
|
24
|
+
*
|
|
25
|
+
* orch.registerStream({
|
|
26
|
+
* name: 'pointcloud',
|
|
27
|
+
* type: 'binary',
|
|
28
|
+
* onFrame(frame) {
|
|
29
|
+
* console.log('Frame:', frame.id);
|
|
30
|
+
* }
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* orch.enable('pointcloud');
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function createOrchestrator(options) {
|
|
37
|
+
const { pc, onError, onControlMessage } = options;
|
|
38
|
+
if (!pc) {
|
|
39
|
+
throw new Error("Orchestrator: RTCPeerConnection is required");
|
|
40
|
+
}
|
|
41
|
+
// Internal state
|
|
42
|
+
const streams = new Map();
|
|
43
|
+
let controlChannel = null;
|
|
44
|
+
let disposed = false;
|
|
45
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46
|
+
// Control Channel Setup
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Handles incoming control messages.
|
|
50
|
+
*/
|
|
51
|
+
function handleControlMessage(message) {
|
|
52
|
+
// Notify application
|
|
53
|
+
onControlMessage?.(message);
|
|
54
|
+
// Handle stream enable/disable from remote
|
|
55
|
+
const stream = streams.get(message.stream);
|
|
56
|
+
if (stream) {
|
|
57
|
+
if (message.enabled && !stream.enabled) {
|
|
58
|
+
enableStreamInternal(message.stream, false); // Don't send control back
|
|
59
|
+
}
|
|
60
|
+
else if (!message.enabled && stream.enabled) {
|
|
61
|
+
disableStreamInternal(message.stream, false); // Don't send control back
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Create outgoing control channel
|
|
66
|
+
controlChannel = createControlChannel(pc, handleControlMessage, onError);
|
|
67
|
+
// Handle incoming control channel from remote peer
|
|
68
|
+
handleIncomingControlChannel(pc, handleControlMessage);
|
|
69
|
+
// Handle incoming data channels from remote peer
|
|
70
|
+
setupIncomingDataChannelHandler();
|
|
71
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
72
|
+
// Incoming Channel Handling
|
|
73
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
74
|
+
function setupIncomingDataChannelHandler() {
|
|
75
|
+
const existingHandler = pc.ondatachannel;
|
|
76
|
+
pc.ondatachannel = (event) => {
|
|
77
|
+
const channel = event.channel;
|
|
78
|
+
const label = channel.label;
|
|
79
|
+
// Skip control channel (handled separately)
|
|
80
|
+
if (label === CONTROL_CHANNEL_LABEL) {
|
|
81
|
+
existingHandler?.call(pc, event);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
// Find registered stream
|
|
85
|
+
const managed = streams.get(label);
|
|
86
|
+
if (!managed) {
|
|
87
|
+
console.warn(`Orchestrator: received channel for unknown stream '${label}'`);
|
|
88
|
+
channel.close();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Setup channel based on stream type
|
|
92
|
+
if (managed.descriptor.type === "binary") {
|
|
93
|
+
setupIncomingBinaryChannel(managed, channel);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
setupIncomingJSONChannel(managed, channel);
|
|
97
|
+
}
|
|
98
|
+
managed.enabled = true;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function setupIncomingBinaryChannel(managed, channel) {
|
|
102
|
+
const descriptor = managed.descriptor;
|
|
103
|
+
// Create binary stream for frame reassembly
|
|
104
|
+
managed.binaryStream = createBinaryStream({
|
|
105
|
+
maxFrameSize: descriptor.maxFrameSize,
|
|
106
|
+
maxBufferSize: descriptor.maxBufferSize,
|
|
107
|
+
dropStrategy: "oldest",
|
|
108
|
+
onFrame: descriptor.onFrame,
|
|
109
|
+
});
|
|
110
|
+
// Wrap incoming channel
|
|
111
|
+
managed.webrtcChannel = wrapDataChannel(channel, (chunk) => managed.binaryStream?.push(chunk));
|
|
112
|
+
}
|
|
113
|
+
function setupIncomingJSONChannel(managed, channel) {
|
|
114
|
+
const descriptor = managed.descriptor;
|
|
115
|
+
channel.binaryType = "arraybuffer";
|
|
116
|
+
managed.jsonChannel = channel;
|
|
117
|
+
channel.onmessage = (event) => {
|
|
118
|
+
try {
|
|
119
|
+
const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
|
|
120
|
+
if (data !== null) {
|
|
121
|
+
descriptor.onMessage(data);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
console.warn(`Orchestrator: invalid JSON on stream '${descriptor.name}'`, err);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
130
|
+
// Stream Management
|
|
131
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
132
|
+
function assertNotDisposed() {
|
|
133
|
+
if (disposed) {
|
|
134
|
+
throw new Error("Orchestrator has been disposed");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function enableStreamInternal(name, sendControl) {
|
|
138
|
+
const managed = streams.get(name);
|
|
139
|
+
if (!managed) {
|
|
140
|
+
throw new Error(`Orchestrator: stream '${name}' not registered`);
|
|
141
|
+
}
|
|
142
|
+
if (managed.enabled) {
|
|
143
|
+
return; // Already enabled
|
|
144
|
+
}
|
|
145
|
+
if (managed.descriptor.type === "binary") {
|
|
146
|
+
enableBinaryStream(managed);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
enableJSONStream(managed);
|
|
150
|
+
}
|
|
151
|
+
managed.enabled = true;
|
|
152
|
+
// Send control message to remote
|
|
153
|
+
if (sendControl) {
|
|
154
|
+
controlChannel?.send(createControlMessage(name, true));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function disableStreamInternal(name, sendControl) {
|
|
158
|
+
const managed = streams.get(name);
|
|
159
|
+
if (!managed) {
|
|
160
|
+
throw new Error(`Orchestrator: stream '${name}' not registered`);
|
|
161
|
+
}
|
|
162
|
+
if (!managed.enabled) {
|
|
163
|
+
return; // Already disabled
|
|
164
|
+
}
|
|
165
|
+
// Cleanup resources
|
|
166
|
+
if (managed.descriptor.type === "binary") {
|
|
167
|
+
managed.webrtcChannel?.close();
|
|
168
|
+
managed.binaryStream?.dispose();
|
|
169
|
+
managed.webrtcChannel = undefined;
|
|
170
|
+
managed.binaryStream = undefined;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
managed.jsonChannel?.close();
|
|
174
|
+
managed.jsonChannel = undefined;
|
|
175
|
+
}
|
|
176
|
+
managed.enabled = false;
|
|
177
|
+
// Send control message to remote
|
|
178
|
+
if (sendControl) {
|
|
179
|
+
controlChannel?.send(createControlMessage(name, false));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function enableBinaryStream(managed) {
|
|
183
|
+
const descriptor = managed.descriptor;
|
|
184
|
+
// Create binary stream for frame reassembly
|
|
185
|
+
managed.binaryStream = createBinaryStream({
|
|
186
|
+
maxFrameSize: descriptor.maxFrameSize,
|
|
187
|
+
maxBufferSize: descriptor.maxBufferSize,
|
|
188
|
+
dropStrategy: "oldest",
|
|
189
|
+
onFrame: descriptor.onFrame,
|
|
190
|
+
});
|
|
191
|
+
// Create WebRTC channel
|
|
192
|
+
managed.webrtcChannel = createWebRTCBinaryChannel({
|
|
193
|
+
pc,
|
|
194
|
+
label: descriptor.name,
|
|
195
|
+
ordered: true,
|
|
196
|
+
onChunk: (chunk) => managed.binaryStream?.push(chunk),
|
|
197
|
+
onStateChange: (state) => {
|
|
198
|
+
if (state === "closed") {
|
|
199
|
+
managed.enabled = false;
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function enableJSONStream(managed) {
|
|
205
|
+
const descriptor = managed.descriptor;
|
|
206
|
+
const channel = pc.createDataChannel(descriptor.name, {
|
|
207
|
+
ordered: true,
|
|
208
|
+
});
|
|
209
|
+
channel.binaryType = "arraybuffer";
|
|
210
|
+
managed.jsonChannel = channel;
|
|
211
|
+
channel.onmessage = (event) => {
|
|
212
|
+
try {
|
|
213
|
+
const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
|
|
214
|
+
if (data !== null) {
|
|
215
|
+
descriptor.onMessage(data);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
console.warn(`Orchestrator: invalid JSON on stream '${descriptor.name}'`, err);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
channel.onclose = () => {
|
|
223
|
+
managed.enabled = false;
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
227
|
+
// Public Interface
|
|
228
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
229
|
+
return {
|
|
230
|
+
registerStream(descriptor) {
|
|
231
|
+
assertNotDisposed();
|
|
232
|
+
if (!descriptor.name) {
|
|
233
|
+
throw new Error("Orchestrator: stream name is required");
|
|
234
|
+
}
|
|
235
|
+
if (streams.has(descriptor.name)) {
|
|
236
|
+
throw new Error(`Orchestrator: stream '${descriptor.name}' already registered`);
|
|
237
|
+
}
|
|
238
|
+
const streamType = descriptor.type;
|
|
239
|
+
if (streamType !== "binary" && streamType !== "json") {
|
|
240
|
+
throw new Error(`Orchestrator: invalid stream type '${streamType}'`);
|
|
241
|
+
}
|
|
242
|
+
const managed = {
|
|
243
|
+
descriptor,
|
|
244
|
+
enabled: false,
|
|
245
|
+
};
|
|
246
|
+
streams.set(descriptor.name, managed);
|
|
247
|
+
// Enable if configured
|
|
248
|
+
if (descriptor.enabledByDefault) {
|
|
249
|
+
enableStreamInternal(descriptor.name, true);
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
enable(name) {
|
|
253
|
+
assertNotDisposed();
|
|
254
|
+
enableStreamInternal(name, true);
|
|
255
|
+
},
|
|
256
|
+
disable(name) {
|
|
257
|
+
assertNotDisposed();
|
|
258
|
+
disableStreamInternal(name, true);
|
|
259
|
+
},
|
|
260
|
+
isEnabled(name) {
|
|
261
|
+
const managed = streams.get(name);
|
|
262
|
+
return managed?.enabled ?? false;
|
|
263
|
+
},
|
|
264
|
+
isRegistered(name) {
|
|
265
|
+
return streams.has(name);
|
|
266
|
+
},
|
|
267
|
+
getStreamNames() {
|
|
268
|
+
return Array.from(streams.keys());
|
|
269
|
+
},
|
|
270
|
+
sendControl(message) {
|
|
271
|
+
assertNotDisposed();
|
|
272
|
+
controlChannel?.send(message);
|
|
273
|
+
},
|
|
274
|
+
dispose() {
|
|
275
|
+
if (disposed)
|
|
276
|
+
return;
|
|
277
|
+
disposed = true;
|
|
278
|
+
// Disable all streams (without sending control)
|
|
279
|
+
for (const name of streams.keys()) {
|
|
280
|
+
const managed = streams.get(name);
|
|
281
|
+
if (managed?.enabled) {
|
|
282
|
+
if (managed.descriptor.type === "binary") {
|
|
283
|
+
managed.webrtcChannel?.close();
|
|
284
|
+
managed.binaryStream?.dispose();
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
managed.jsonChannel?.close();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
streams.clear();
|
|
292
|
+
// Close control channel
|
|
293
|
+
controlChannel?.close();
|
|
294
|
+
controlChannel = null;
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @streamkit/orchestrator - Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Types for stream orchestration and coordination.
|
|
5
|
+
*/
|
|
6
|
+
import type { BinaryFrame } from "@streamkit/binary-stream";
|
|
7
|
+
/**
|
|
8
|
+
* Stream transport type.
|
|
9
|
+
*/
|
|
10
|
+
export type StreamType = "binary" | "json";
|
|
11
|
+
/**
|
|
12
|
+
* Base descriptor for all stream types.
|
|
13
|
+
*/
|
|
14
|
+
export interface BaseStreamDescriptor {
|
|
15
|
+
/** Unique stream identifier */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Transport type */
|
|
18
|
+
type: StreamType;
|
|
19
|
+
/** Whether stream is enabled on registration (default: false) */
|
|
20
|
+
enabledByDefault?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Descriptor for binary frame streams.
|
|
24
|
+
* Uses @streamkit/binary-stream for frame reassembly.
|
|
25
|
+
*/
|
|
26
|
+
export interface BinaryStreamDescriptor extends BaseStreamDescriptor {
|
|
27
|
+
type: "binary";
|
|
28
|
+
/** Callback for complete binary frames */
|
|
29
|
+
onFrame: (frame: BinaryFrame) => void;
|
|
30
|
+
/** Maximum frame size in bytes (default: 10MB) */
|
|
31
|
+
maxFrameSize?: number;
|
|
32
|
+
/** Maximum buffer size in bytes (default: 50MB) */
|
|
33
|
+
maxBufferSize?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Descriptor for JSON message streams.
|
|
37
|
+
* Used for control messages, telemetry, and structured data.
|
|
38
|
+
*/
|
|
39
|
+
export interface JSONStreamDescriptor extends BaseStreamDescriptor {
|
|
40
|
+
type: "json";
|
|
41
|
+
/** Callback for parsed JSON messages */
|
|
42
|
+
onMessage: (data: unknown) => void;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Union type for all stream descriptors.
|
|
46
|
+
*/
|
|
47
|
+
export type StreamDescriptor = BinaryStreamDescriptor | JSONStreamDescriptor;
|
|
48
|
+
/**
|
|
49
|
+
* Control message format for stream coordination.
|
|
50
|
+
*/
|
|
51
|
+
export interface ControlMessage {
|
|
52
|
+
type: "control";
|
|
53
|
+
stream: string;
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Options for creating an orchestrator.
|
|
58
|
+
*/
|
|
59
|
+
export interface OrchestratorOptions {
|
|
60
|
+
/** RTCPeerConnection to manage streams on */
|
|
61
|
+
pc: RTCPeerConnection;
|
|
62
|
+
/** Optional callback for orchestrator-level errors */
|
|
63
|
+
onError?: (error: Error) => void;
|
|
64
|
+
/** Optional callback for control messages received */
|
|
65
|
+
onControlMessage?: (message: ControlMessage) => void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Stream orchestrator interface.
|
|
69
|
+
*/
|
|
70
|
+
export interface Orchestrator {
|
|
71
|
+
/**
|
|
72
|
+
* Register a stream descriptor.
|
|
73
|
+
* Does not open the channel until enable() is called.
|
|
74
|
+
* @param descriptor - Stream configuration
|
|
75
|
+
*/
|
|
76
|
+
registerStream(descriptor: StreamDescriptor): void;
|
|
77
|
+
/**
|
|
78
|
+
* Enable a registered stream.
|
|
79
|
+
* Creates the DataChannel and starts receiving data.
|
|
80
|
+
* Sends control message to remote peer.
|
|
81
|
+
* @param name - Stream name
|
|
82
|
+
*/
|
|
83
|
+
enable(name: string): void;
|
|
84
|
+
/**
|
|
85
|
+
* Disable an active stream.
|
|
86
|
+
* Closes the DataChannel and stops receiving data.
|
|
87
|
+
* Sends control message to remote peer.
|
|
88
|
+
* @param name - Stream name
|
|
89
|
+
*/
|
|
90
|
+
disable(name: string): void;
|
|
91
|
+
/**
|
|
92
|
+
* Check if a stream is currently enabled.
|
|
93
|
+
* @param name - Stream name
|
|
94
|
+
*/
|
|
95
|
+
isEnabled(name: string): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Check if a stream is registered.
|
|
98
|
+
* @param name - Stream name
|
|
99
|
+
*/
|
|
100
|
+
isRegistered(name: string): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Get list of all registered stream names.
|
|
103
|
+
*/
|
|
104
|
+
getStreamNames(): string[];
|
|
105
|
+
/**
|
|
106
|
+
* Send a control message to the remote peer.
|
|
107
|
+
* @param message - Control message to send
|
|
108
|
+
*/
|
|
109
|
+
sendControl(message: ControlMessage): void;
|
|
110
|
+
/**
|
|
111
|
+
* Dispose all streams and release resources.
|
|
112
|
+
*/
|
|
113
|
+
dispose(): void;
|
|
114
|
+
}
|
|
115
|
+
export type { BinaryFrame } from "@streamkit/binary-stream";
|
|
116
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,0CAA0C;IAC1C,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,6CAA6C;IAC7C,EAAE,EAAE,iBAAiB,CAAC;IACtB,sDAAsD;IACtD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACtD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEnD;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAEjC;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAEpC;;OAEG;IACH,cAAc,IAAI,MAAM,EAAE,CAAC;IAE3B;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAE3C;;OAEG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAGD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "streamkit-orchestrator",
|
|
3
|
+
"version": "0.4.0-alpha.0",
|
|
4
|
+
"description": "Lightweight stream orchestrator for coordinating multiple WebRTC binary streams",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"clean": "rimraf dist",
|
|
20
|
+
"build": "tsc -p tsconfig.build.json",
|
|
21
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"webrtc",
|
|
25
|
+
"stream",
|
|
26
|
+
"orchestrator",
|
|
27
|
+
"binary",
|
|
28
|
+
"real-time"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@jervis/streamkit-binary-stream": "^0.4.0-alpha.0",
|
|
32
|
+
"@jervis/streamkit-webrtc": "^0.4.0-alpha.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"rimraf": "^5.0.5",
|
|
36
|
+
"typescript": "^5.3.0"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|