tirtc-devtools-cli 0.0.5 → 0.0.6
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/README.md +3 -1
- package/USAGE.md +151 -366
- package/dist/devtools/cli/src/config.d.ts +4 -13
- package/dist/devtools/cli/src/config.js +7 -19
- package/dist/devtools/cli/src/facade.d.ts +39 -154
- package/dist/devtools/cli/src/facade.js +9 -23
- package/dist/devtools/cli/src/guide.js +7 -9
- package/dist/devtools/cli/src/index.js +135 -255
- package/dist/devtools/cli/src/token_command.d.ts +7 -0
- package/dist/devtools/cli/src/token_command.js +139 -0
- package/package.json +1 -1
- package/vendor/app-server/bin/native/macos-arm64/credential_napi.node +0 -0
- package/vendor/app-server/bin/native/macos-arm64/runtime_host_napi.node +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/include/tirtc/trp.h +30 -17
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_audio.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_credential.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_facade.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_http.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_media.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_transport.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_video.a +0 -0
- package/vendor/app-server/bin/runtime/macos-arm64/manifest.txt +10 -10
- package/vendor/app-server/dist/host/HostProtocol.d.ts +7 -5
- package/vendor/app-server/dist/host/HostProtocol.js +21 -10
- package/vendor/app-server/dist/host/HostServer.d.ts +2 -2
- package/vendor/app-server/dist/host/HostServer.js +93 -35
- package/vendor/app-server/dist/host/HostState.d.ts +0 -5
- package/vendor/app-server/dist/host/HostState.js +0 -1
- package/vendor/app-server/dist/host/RuntimeAdapter.d.ts +12 -0
- package/vendor/app-server/dist/host/RuntimeAdapter.js +42 -3
- package/vendor/app-server/dist/host/RuntimeSendWorker.d.ts +4 -0
- package/vendor/app-server/dist/host/RuntimeSendWorker.js +17 -0
- package/vendor/app-server/dist/protocol/contract.d.ts +72 -14
- package/vendor/app-server/dist/protocol/contract.js +11 -8
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -154,6 +154,20 @@ typedef struct TirtcConnConnectOptions {
|
|
|
154
154
|
const char* token;
|
|
155
155
|
} TirtcConnConnectOptions;
|
|
156
156
|
|
|
157
|
+
/**
|
|
158
|
+
* @brief Optional observer bound when a connection object is created.
|
|
159
|
+
*
|
|
160
|
+
* The implementation copies the observer structure and stores the supplied
|
|
161
|
+
* user_data pointer with the created connection handle.
|
|
162
|
+
*/
|
|
163
|
+
typedef struct TirtcConnCreateOptions {
|
|
164
|
+
/** @brief Optional observer copied into the new connection object. */
|
|
165
|
+
const struct TirtcConnObserver* observer;
|
|
166
|
+
|
|
167
|
+
/** @brief Opaque pointer returned to observer callbacks. */
|
|
168
|
+
void* user_data;
|
|
169
|
+
} TirtcConnCreateOptions;
|
|
170
|
+
|
|
157
171
|
/** @brief Opaque handle returned by ::tirtc_conn_service_start. */
|
|
158
172
|
typedef struct TirtcConnService TirtcConnService;
|
|
159
173
|
|
|
@@ -376,17 +390,12 @@ typedef struct TirtcConnServiceObserver {
|
|
|
376
390
|
/**
|
|
377
391
|
* @brief Optional observer for connection lifecycle and control-plane events.
|
|
378
392
|
*
|
|
379
|
-
* The implementation stores a copy of this structure
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
* Replay contract:
|
|
383
|
-
* - Installing or replacing an observer immediately replays the current state.
|
|
384
|
-
* - If the connection has already disconnected, the terminal disconnected
|
|
385
|
-
* callback is replayed as part of observer installation.
|
|
393
|
+
* The implementation stores a copy of this structure inside the owning
|
|
394
|
+
* connection object.
|
|
386
395
|
*
|
|
387
396
|
* Callback threading is not restricted to a single caller thread. Some
|
|
388
|
-
* callbacks may be replayed synchronously
|
|
389
|
-
*
|
|
397
|
+
* callbacks may be replayed synchronously when a connection object becomes
|
|
398
|
+
* visible to the caller, while others may arrive asynchronously from the
|
|
390
399
|
* internal transport layer.
|
|
391
400
|
*/
|
|
392
401
|
typedef struct TirtcConnObserver {
|
|
@@ -475,25 +484,29 @@ TirtcError tirtc_conn_service_stop(TirtcConnService* service);
|
|
|
475
484
|
* The runtime must already be initialized. The returned handle starts in
|
|
476
485
|
* ::TIRTC_CONN_STATE_IDLE and must be released with ::tirtc_conn_destroy.
|
|
477
486
|
*
|
|
487
|
+
* The observer, when provided, becomes part of the connection object's stable
|
|
488
|
+
* lifecycle contract. After creation succeeds, reconnects on the same handle
|
|
489
|
+
* keep using that observer.
|
|
490
|
+
*
|
|
491
|
+
* @param options Optional creation options. Pass NULL to create a connection
|
|
492
|
+
* without an observer.
|
|
478
493
|
* @param out_connection Receives the created connection handle on success.
|
|
479
494
|
* @return ::TIRTC_ERROR_OK on success.
|
|
480
495
|
*/
|
|
481
|
-
TirtcError tirtc_conn_create(TirtcConn** out_connection);
|
|
496
|
+
TirtcError tirtc_conn_create(const TirtcConnCreateOptions* options, TirtcConn** out_connection);
|
|
482
497
|
|
|
483
498
|
/**
|
|
484
499
|
* @brief Install, replace, or clear the connection observer.
|
|
485
500
|
*
|
|
501
|
+
* This legacy API remains available for accepted service connections and
|
|
502
|
+
* existing consumers that still bind observers after handle creation.
|
|
503
|
+
* New standalone-connection callers should prefer binding the observer through
|
|
504
|
+
* ::TirtcConnCreateOptions.
|
|
505
|
+
*
|
|
486
506
|
* Passing NULL for ::observer clears the current observer and its user data.
|
|
487
|
-
* The implementation stores a copy of the observer structure and does not
|
|
488
|
-
* require it to outlive this call.
|
|
489
507
|
* After a non-NULL observer is installed, the implementation immediately
|
|
490
508
|
* replays the current state and, when applicable, the terminal disconnected
|
|
491
509
|
* callback.
|
|
492
|
-
*
|
|
493
|
-
* @param connection Target connection.
|
|
494
|
-
* @param observer Observer to install, or NULL to clear.
|
|
495
|
-
* @param user_data Opaque pointer returned to observer callbacks.
|
|
496
|
-
* @return ::TIRTC_ERROR_OK on success.
|
|
497
510
|
*/
|
|
498
511
|
TirtcError tirtc_conn_set_observer(TirtcConn* connection, const TirtcConnObserver* observer,
|
|
499
512
|
void* user_data);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vendor/app-server/bin/runtime/macos-arm64/lib/libmatrix_runtime_foundation_logging.a
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
platform=macos-arm64
|
|
2
|
-
staged_at_utc=2026-04-
|
|
2
|
+
staged_at_utc=2026-04-09T14:57:31Z
|
|
3
3
|
source_sdk=/Users/allenfeng/Development/Repositories/tirtc-nexus/tirtc-matrix/.build/sdk/macos-arm64
|
|
4
4
|
|
|
5
5
|
dcca0b7ab8055d84e5bcfab7f1dde56df9037c40ddb99e9ca924ef2e867d8309 include/tirtc/audio.h
|
|
@@ -25,7 +25,7 @@ ae805545a9515edc9b94262e72ad2c7b7d649288166f4daeb450d8a55e82ae0b include/tirtc/
|
|
|
25
25
|
a4f8ab44c1a20ad37f250363a403a9d4d007e61ddb2426c7966dbc05f6a04b4f include/tirtc/media_live_source.h
|
|
26
26
|
1b3be6954e547f91a047866438bff1820c8406afaf91cef68ddee29a6ac70234 include/tirtc/media_uplink.h
|
|
27
27
|
1e12daf9c5fc2e2f848444688081c9be0cb738245f0155327e8003b49308058f include/tirtc/transport.h
|
|
28
|
-
|
|
28
|
+
137729c534213cb161c0853a8d4d38fcdc397c41a7fd8c813fbe0e80083ec931 include/tirtc/trp.h
|
|
29
29
|
dff5b0a0ac4a40ad17c93e1e56b3c416371c81ab365e287ea8cd6ce37ccbed3b include/tirtc/video_codec.h
|
|
30
30
|
e51379666c199588cc33279ccf52248035d1cae3d1d468b1615ebf29f0b39c9c include/tirtc/video_frame.h
|
|
31
31
|
d920afad955b9f206b02b19ca152315190fa84ab6f24e895a5b24c3ab9ffd701 include/tirtc/video_io.h
|
|
@@ -36,14 +36,14 @@ cae0bbeb884e5466a56da15182c78cc22baab6c743f349a58d3595f623333585 include/tirtc/
|
|
|
36
36
|
8cd6b66bea14890a665cc317f8572429b2c3e4463773f8b77c1e4dc30a4a8747 include/tirtc/video_processing.h
|
|
37
37
|
b39daee6a3d39bf0ca20c45084601133c4198de8dca848dcff6dd9c70ae99016 lib/libcrypto.a
|
|
38
38
|
c052857ef315e3d61db9c862cad10709a3a6b2487dc41799cbe4d74a805de875 lib/libcrypto.dylib
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
240fb613f79b39ce4ed74ebd2e56c714141a0ef858f106e1121c7d540cea7e64 lib/libmatrix_runtime_audio.a
|
|
40
|
+
e1070b1e7b262ad8a8e1dbec1ac9d524fbf4a7fdcc855bb84f69bdd13f31ae9d lib/libmatrix_runtime_credential.a
|
|
41
|
+
7081b1021d32939a1cbf399bbfa2b4f72a74e7eb48f111f34c80450f8d8a4bfe lib/libmatrix_runtime_facade.a
|
|
42
|
+
d268be4f9309c1af33f7734a692e0bf89402c96a6fe689f6d7df691d5563b391 lib/libmatrix_runtime_foundation_http.a
|
|
43
|
+
d7c51d52995b0c1be194fafb3d922b98f8c87eccbfb3a240bad1d4b7b27de1b2 lib/libmatrix_runtime_foundation_logging.a
|
|
44
|
+
37332652b4cb75f1d6a0a3a7209013d05ec55874b5103b89fd37ecd3b4601702 lib/libmatrix_runtime_media.a
|
|
45
|
+
e0ed1c103c4e2392c423aacdbf314bf13848281318c6f57496136756664c4275 lib/libmatrix_runtime_transport.a
|
|
46
|
+
f00064a09bc2c03963518e05c659becc0a24e2ec6b696ce13ca03fa1ec576f22 lib/libmatrix_runtime_video.a
|
|
47
47
|
c11c65d373a127028350c41fa58cd2d1223f2b5d70a84e13b115d90daaba25ca lib/libssl.a
|
|
48
48
|
ef1c1104bbdd2528ed7b958fb7252bd6249875f92300b0c9577d6c4bd6c0d88a lib/libssl.dylib
|
|
49
49
|
dc3e0e6ded26e90fd59c166933a5289d57f4cf25fbe6246b6b83c86fe898e63d lib/libwebrtc_apm.a
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StreamSource } from './HostState';
|
|
2
2
|
export type JsonRpcId = string | number;
|
|
3
3
|
export type JsonRpcRequest = {
|
|
4
4
|
id?: JsonRpcId;
|
|
@@ -22,6 +22,7 @@ export type ServiceStartParams = {
|
|
|
22
22
|
serviceEntry?: string;
|
|
23
23
|
license: string;
|
|
24
24
|
timeoutMs: number;
|
|
25
|
+
bootstrapSendStreams?: StreamSendStartParams[];
|
|
25
26
|
};
|
|
26
27
|
export type ConnectionAutoTokenConfig = {
|
|
27
28
|
openapiEntry?: string;
|
|
@@ -47,6 +48,10 @@ export type StreamSendStartParams = {
|
|
|
47
48
|
export type StreamStopParams = {
|
|
48
49
|
streamId: number;
|
|
49
50
|
};
|
|
51
|
+
export type StreamMessageSendParams = {
|
|
52
|
+
streamId: number;
|
|
53
|
+
payload: string;
|
|
54
|
+
};
|
|
50
55
|
export type StreamReceiveStartParams = {
|
|
51
56
|
streamId: number;
|
|
52
57
|
media: 'audio' | 'video';
|
|
@@ -78,9 +83,6 @@ export type EventsSubscribeParams = {
|
|
|
78
83
|
export type ArtifactExportParams = {
|
|
79
84
|
outputPath: string;
|
|
80
85
|
};
|
|
81
|
-
export type StreamRequestPolicySetParams = {
|
|
82
|
-
mode: StreamRequestPolicyMode;
|
|
83
|
-
};
|
|
84
86
|
export type DebugTokenQrcodeParams = {
|
|
85
87
|
payload: string;
|
|
86
88
|
outputStem?: string;
|
|
@@ -96,12 +98,12 @@ export declare function parseServiceStartParams(params: Record<string, unknown>)
|
|
|
96
98
|
export declare function parseConnectionConnectParams(params: Record<string, unknown>): ConnectionConnectParams;
|
|
97
99
|
export declare function parseStreamSendStartParams(params: Record<string, unknown>): StreamSendStartParams;
|
|
98
100
|
export declare function parseStreamStopParams(params: Record<string, unknown>): StreamStopParams;
|
|
101
|
+
export declare function parseStreamMessageSendParams(params: Record<string, unknown>): StreamMessageSendParams;
|
|
99
102
|
export declare function parseStreamReceiveStartParams(params: Record<string, unknown>): StreamReceiveStartParams;
|
|
100
103
|
export declare function parseOutputAttachParams(params: Record<string, unknown>): OutputAttachParams;
|
|
101
104
|
export declare function parseOutputDetachParams(params: Record<string, unknown>): OutputDetachParams;
|
|
102
105
|
export declare function parseCommandSendParams(params: Record<string, unknown>): CommandSendParams;
|
|
103
106
|
export declare function parseEventsSubscribeParams(params: Record<string, unknown>): EventsSubscribeParams;
|
|
104
107
|
export declare function parseArtifactExportParams(params: Record<string, unknown>): ArtifactExportParams;
|
|
105
|
-
export declare function parseStreamRequestPolicySetParams(params: Record<string, unknown>): StreamRequestPolicySetParams;
|
|
106
108
|
export declare function parseDebugTokenQrcodeParams(params: Record<string, unknown>): DebugTokenQrcodeParams;
|
|
107
109
|
export declare function normalizeError(error: unknown): HostProtocolError;
|
|
@@ -7,13 +7,13 @@ exports.parseServiceStartParams = parseServiceStartParams;
|
|
|
7
7
|
exports.parseConnectionConnectParams = parseConnectionConnectParams;
|
|
8
8
|
exports.parseStreamSendStartParams = parseStreamSendStartParams;
|
|
9
9
|
exports.parseStreamStopParams = parseStreamStopParams;
|
|
10
|
+
exports.parseStreamMessageSendParams = parseStreamMessageSendParams;
|
|
10
11
|
exports.parseStreamReceiveStartParams = parseStreamReceiveStartParams;
|
|
11
12
|
exports.parseOutputAttachParams = parseOutputAttachParams;
|
|
12
13
|
exports.parseOutputDetachParams = parseOutputDetachParams;
|
|
13
14
|
exports.parseCommandSendParams = parseCommandSendParams;
|
|
14
15
|
exports.parseEventsSubscribeParams = parseEventsSubscribeParams;
|
|
15
16
|
exports.parseArtifactExportParams = parseArtifactExportParams;
|
|
16
|
-
exports.parseStreamRequestPolicySetParams = parseStreamRequestPolicySetParams;
|
|
17
17
|
exports.parseDebugTokenQrcodeParams = parseDebugTokenQrcodeParams;
|
|
18
18
|
exports.normalizeError = normalizeError;
|
|
19
19
|
class HostProtocolError extends Error {
|
|
@@ -122,10 +122,24 @@ function parseStreamSource(source) {
|
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
function parseServiceStartParams(params) {
|
|
125
|
+
const bootstrapSendStreamsRaw = params.bootstrapSendStreams;
|
|
126
|
+
let bootstrapSendStreams;
|
|
127
|
+
if (bootstrapSendStreamsRaw !== undefined) {
|
|
128
|
+
if (!Array.isArray(bootstrapSendStreamsRaw)) {
|
|
129
|
+
throw new HostProtocolError('invalid_request', 'Invalid bootstrapSendStreams', false);
|
|
130
|
+
}
|
|
131
|
+
bootstrapSendStreams = bootstrapSendStreamsRaw.map((entry) => {
|
|
132
|
+
if (!isRecord(entry)) {
|
|
133
|
+
throw new HostProtocolError('invalid_request', 'Invalid bootstrapSendStreams item', false);
|
|
134
|
+
}
|
|
135
|
+
return parseStreamSendStartParams(entry);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
125
138
|
return {
|
|
126
139
|
serviceEntry: getOptionalString(params, 'serviceEntry'),
|
|
127
140
|
license: getString(params, 'license'),
|
|
128
141
|
timeoutMs: getNumber(params, 'timeoutMs'),
|
|
142
|
+
bootstrapSendStreams,
|
|
129
143
|
};
|
|
130
144
|
}
|
|
131
145
|
function parseConnectionConnectParams(params) {
|
|
@@ -178,6 +192,12 @@ function parseStreamSendStartParams(params) {
|
|
|
178
192
|
function parseStreamStopParams(params) {
|
|
179
193
|
return { streamId: getNumber(params, 'streamId') };
|
|
180
194
|
}
|
|
195
|
+
function parseStreamMessageSendParams(params) {
|
|
196
|
+
return {
|
|
197
|
+
streamId: getNumber(params, 'streamId'),
|
|
198
|
+
payload: getString(params, 'payload'),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
181
201
|
function parseStreamReceiveStartParams(params) {
|
|
182
202
|
const media = getString(params, 'media');
|
|
183
203
|
if (media !== 'audio' && media !== 'video') {
|
|
@@ -230,15 +250,6 @@ function parseArtifactExportParams(params) {
|
|
|
230
250
|
outputPath: getString(params, 'outputPath'),
|
|
231
251
|
};
|
|
232
252
|
}
|
|
233
|
-
function parseStreamRequestPolicySetParams(params) {
|
|
234
|
-
const mode = getString(params, 'mode');
|
|
235
|
-
if (mode !== 'manual' && mode !== 'auto-if-bound') {
|
|
236
|
-
throw new HostProtocolError('invalid_request', 'Invalid mode', false);
|
|
237
|
-
}
|
|
238
|
-
return {
|
|
239
|
-
mode,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
253
|
function parseDebugTokenQrcodeParams(params) {
|
|
243
254
|
return {
|
|
244
255
|
payload: getString(params, 'payload'),
|
|
@@ -18,6 +18,7 @@ export declare class HostServer {
|
|
|
18
18
|
removeEventSink(sink: (event: Record<string, unknown>) => void): void;
|
|
19
19
|
appendHostLog(line: string): void;
|
|
20
20
|
private handleRuntimeEvent;
|
|
21
|
+
private noteIncomingConnection;
|
|
21
22
|
private maybeAutoStartStreamFromRemoteDemand;
|
|
22
23
|
private dispatch;
|
|
23
24
|
private handleInitialize;
|
|
@@ -34,10 +35,9 @@ export declare class HostServer {
|
|
|
34
35
|
private handleStreamList;
|
|
35
36
|
private handleStreamSendStart;
|
|
36
37
|
private handleStreamSendStop;
|
|
38
|
+
private handleStreamMessageSend;
|
|
37
39
|
private handleStreamReceiveStart;
|
|
38
40
|
private handleStreamReceiveStop;
|
|
39
|
-
private handleStreamRequestPolicyGet;
|
|
40
|
-
private handleStreamRequestPolicySet;
|
|
41
41
|
private handleOutputAttach;
|
|
42
42
|
private handleOutputDetach;
|
|
43
43
|
private handleCommandSend;
|
|
@@ -175,18 +175,30 @@ class HostServer {
|
|
|
175
175
|
if (family !== 'runtime') {
|
|
176
176
|
return;
|
|
177
177
|
}
|
|
178
|
-
if (kind === 'transport.remote.
|
|
178
|
+
if (kind === 'transport.remote.request_audio' ||
|
|
179
|
+
kind === 'transport.remote.request_video' ||
|
|
180
|
+
kind === 'transport.remote.request_iframe') {
|
|
179
181
|
const streamId = Number(payload.streamId);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
this.maybeAutoStartStreamFromRemoteDemand(streamId, mediaRaw, payload);
|
|
182
|
+
if (!Number.isFinite(streamId)) {
|
|
183
|
+
return;
|
|
183
184
|
}
|
|
185
|
+
const media = kind === 'transport.remote.request_audio' ? 'audio' : 'video';
|
|
186
|
+
this.noteIncomingConnection(payload);
|
|
187
|
+
this.maybeAutoStartStreamFromRemoteDemand(streamId, media, payload);
|
|
184
188
|
}
|
|
185
189
|
}
|
|
186
|
-
|
|
187
|
-
if (this.state.
|
|
190
|
+
noteIncomingConnection(payload) {
|
|
191
|
+
if (this.state.connection.state === 'connected') {
|
|
188
192
|
return;
|
|
189
193
|
}
|
|
194
|
+
this.state.connection = {
|
|
195
|
+
state: 'connected',
|
|
196
|
+
direction: 'incoming',
|
|
197
|
+
peerId: typeof payload.peerId === 'string' && payload.peerId.length > 0 ? payload.peerId : undefined,
|
|
198
|
+
connectedAt: new Date().toISOString(),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
maybeAutoStartStreamFromRemoteDemand(streamId, media, payload) {
|
|
190
202
|
const key = streamBindingKey(streamId, media);
|
|
191
203
|
const bound = this.state.streamSourceBindings.get(key);
|
|
192
204
|
if (!bound) {
|
|
@@ -248,14 +260,12 @@ class HostServer {
|
|
|
248
260
|
return this.handleStreamSendStart((0, HostProtocol_1.parseStreamSendStartParams)(params));
|
|
249
261
|
case 'stream/sendStop':
|
|
250
262
|
return this.handleStreamSendStop((0, HostProtocol_1.parseStreamStopParams)(params));
|
|
263
|
+
case 'stream/message/send':
|
|
264
|
+
return this.handleStreamMessageSend((0, HostProtocol_1.parseStreamMessageSendParams)(params));
|
|
251
265
|
case 'stream/receiveStart':
|
|
252
266
|
return this.handleStreamReceiveStart((0, HostProtocol_1.parseStreamReceiveStartParams)(params));
|
|
253
267
|
case 'stream/receiveStop':
|
|
254
268
|
return this.handleStreamReceiveStop((0, HostProtocol_1.parseStreamStopParams)(params));
|
|
255
|
-
case 'stream/requestPolicy/get':
|
|
256
|
-
return this.handleStreamRequestPolicyGet();
|
|
257
|
-
case 'stream/requestPolicy/set':
|
|
258
|
-
return this.handleStreamRequestPolicySet((0, HostProtocol_1.parseStreamRequestPolicySetParams)(params));
|
|
259
269
|
case 'output/attach':
|
|
260
270
|
return this.handleOutputAttach((0, HostProtocol_1.parseOutputAttachParams)(params));
|
|
261
271
|
case 'output/detach':
|
|
@@ -285,11 +295,7 @@ class HostServer {
|
|
|
285
295
|
protocolVersion: this.state.protocolVersion,
|
|
286
296
|
runtimeTarget: this.state.runtimeTarget,
|
|
287
297
|
hostEndpoint: this.state.hostEndpoint,
|
|
288
|
-
capabilities: {
|
|
289
|
-
streamRequestPolicy: {
|
|
290
|
-
mode: this.state.streamRequestPolicy.mode,
|
|
291
|
-
},
|
|
292
|
-
},
|
|
298
|
+
capabilities: {},
|
|
293
299
|
};
|
|
294
300
|
}
|
|
295
301
|
async handleHostStatus() {
|
|
@@ -301,7 +307,6 @@ class HostServer {
|
|
|
301
307
|
startedAt: this.state.startedAt,
|
|
302
308
|
service: this.state.service,
|
|
303
309
|
connection: this.state.connection,
|
|
304
|
-
streamRequestPolicy: this.state.streamRequestPolicy,
|
|
305
310
|
artifactPaths: this.artifactManager.getPaths(),
|
|
306
311
|
};
|
|
307
312
|
}
|
|
@@ -327,6 +332,44 @@ class HostServer {
|
|
|
327
332
|
serviceEntry: resolvedServiceEntry,
|
|
328
333
|
startedAt: new Date().toISOString(),
|
|
329
334
|
};
|
|
335
|
+
if (params.bootstrapSendStreams && params.bootstrapSendStreams.length > 0) {
|
|
336
|
+
const bootstrapStreams = params.bootstrapSendStreams.map((streamParams) => ({
|
|
337
|
+
streamId: streamParams.streamId,
|
|
338
|
+
media: streamParams.media,
|
|
339
|
+
source: streamParams.source,
|
|
340
|
+
}));
|
|
341
|
+
const sendResults = this.runtimeAdapter.startSendStreams
|
|
342
|
+
? await this.runtimeAdapter.startSendStreams(bootstrapStreams)
|
|
343
|
+
: await Promise.all(bootstrapStreams.map(async (streamParams) => await this.runtimeAdapter.startSendStream(streamParams.streamId, streamParams.media, streamParams.source)));
|
|
344
|
+
const updatedAt = new Date().toISOString();
|
|
345
|
+
bootstrapStreams.forEach((streamParams, index) => {
|
|
346
|
+
const stream = {
|
|
347
|
+
streamId: streamParams.streamId,
|
|
348
|
+
media: streamParams.media,
|
|
349
|
+
direction: 'send',
|
|
350
|
+
state: this.state.connection.state === 'connected' ? 'active' : 'pending_on_connection',
|
|
351
|
+
source: streamParams.source,
|
|
352
|
+
updatedAt,
|
|
353
|
+
};
|
|
354
|
+
this.state.streams.set(streamParams.streamId, stream);
|
|
355
|
+
this.state.streamSourceBindings.set(streamBindingKey(streamParams.streamId, streamParams.media), {
|
|
356
|
+
streamId: streamParams.streamId,
|
|
357
|
+
media: streamParams.media,
|
|
358
|
+
source: streamParams.source,
|
|
359
|
+
updatedAt,
|
|
360
|
+
});
|
|
361
|
+
this.writeEvent('stream', 'send.bootstrap.bound', {
|
|
362
|
+
streamId: streamParams.streamId,
|
|
363
|
+
media: streamParams.media,
|
|
364
|
+
sourceMode: streamParams.source.mode,
|
|
365
|
+
assetsDir: streamParams.source.local_assets.assets_dir,
|
|
366
|
+
autoStarted: sendResults[index]?.autoStarted ?? false,
|
|
367
|
+
workerPid: sendResults[index]?.workerPid,
|
|
368
|
+
state: stream.state,
|
|
369
|
+
at: updatedAt,
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
}
|
|
330
373
|
return this.state.service;
|
|
331
374
|
}
|
|
332
375
|
async handleServiceStop() {
|
|
@@ -510,6 +553,40 @@ class HostServer {
|
|
|
510
553
|
stream.updatedAt = new Date().toISOString();
|
|
511
554
|
return stream;
|
|
512
555
|
}
|
|
556
|
+
async handleStreamMessageSend(params) {
|
|
557
|
+
const acceptedAt = new Date().toISOString();
|
|
558
|
+
this.writeEvent('stream', 'message.send.requested', {
|
|
559
|
+
streamId: params.streamId,
|
|
560
|
+
payloadPreview: params.payload.slice(0, 120),
|
|
561
|
+
payloadLength: params.payload.length,
|
|
562
|
+
at: acceptedAt,
|
|
563
|
+
});
|
|
564
|
+
try {
|
|
565
|
+
await this.runtimeAdapter.sendStreamMessage(params.streamId, params.payload);
|
|
566
|
+
}
|
|
567
|
+
catch (error) {
|
|
568
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
569
|
+
this.writeEvent('stream', 'message.send.failed', {
|
|
570
|
+
streamId: params.streamId,
|
|
571
|
+
payloadPreview: params.payload.slice(0, 120),
|
|
572
|
+
payloadLength: params.payload.length,
|
|
573
|
+
message,
|
|
574
|
+
at: new Date().toISOString(),
|
|
575
|
+
});
|
|
576
|
+
throw error;
|
|
577
|
+
}
|
|
578
|
+
this.writeEvent('stream', 'message.send.completed', {
|
|
579
|
+
streamId: params.streamId,
|
|
580
|
+
payloadPreview: params.payload.slice(0, 120),
|
|
581
|
+
payloadLength: params.payload.length,
|
|
582
|
+
at: new Date().toISOString(),
|
|
583
|
+
});
|
|
584
|
+
return {
|
|
585
|
+
streamId: params.streamId,
|
|
586
|
+
payloadLength: params.payload.length,
|
|
587
|
+
acceptedAt,
|
|
588
|
+
};
|
|
589
|
+
}
|
|
513
590
|
async handleStreamReceiveStart(params) {
|
|
514
591
|
await this.runtimeAdapter.startReceiveStream(params.streamId, params.media);
|
|
515
592
|
const stream = {
|
|
@@ -532,24 +609,6 @@ class HostServer {
|
|
|
532
609
|
stream.updatedAt = new Date().toISOString();
|
|
533
610
|
return stream;
|
|
534
611
|
}
|
|
535
|
-
async handleStreamRequestPolicyGet() {
|
|
536
|
-
return {
|
|
537
|
-
mode: this.state.streamRequestPolicy.mode,
|
|
538
|
-
updatedAt: new Date().toISOString(),
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
async handleStreamRequestPolicySet(params) {
|
|
542
|
-
this.state.streamRequestPolicy.mode = params.mode;
|
|
543
|
-
const updatedAt = new Date().toISOString();
|
|
544
|
-
this.writeEvent('stream', 'request_policy.updated', {
|
|
545
|
-
mode: params.mode,
|
|
546
|
-
at: updatedAt,
|
|
547
|
-
});
|
|
548
|
-
return {
|
|
549
|
-
mode: this.state.streamRequestPolicy.mode,
|
|
550
|
-
updatedAt,
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
612
|
async handleOutputAttach(params) {
|
|
554
613
|
const attachment = await this.runtimeAdapter.attachOutput(params.streamId, params.consumer, params.mediaView, params.format, params.delivery, params.targetPath, params.maxFiles);
|
|
555
614
|
return {
|
|
@@ -600,7 +659,6 @@ class HostServer {
|
|
|
600
659
|
service: this.state.service,
|
|
601
660
|
connection: this.state.connection,
|
|
602
661
|
streams: Array.from(this.state.streams.values()),
|
|
603
|
-
streamRequestPolicy: this.state.streamRequestPolicy,
|
|
604
662
|
artifacts: this.artifactManager.getPaths(),
|
|
605
663
|
lastError: this.state.lastError,
|
|
606
664
|
};
|
|
@@ -29,10 +29,6 @@ export interface StreamLocalAssetsSource {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
export type StreamSource = StreamLocalAssetsSource;
|
|
32
|
-
export type StreamRequestPolicyMode = 'manual' | 'auto-if-bound';
|
|
33
|
-
export interface StreamRequestPolicy {
|
|
34
|
-
mode: StreamRequestPolicyMode;
|
|
35
|
-
}
|
|
36
32
|
export interface StreamSourceBinding {
|
|
37
33
|
streamId: number;
|
|
38
34
|
media: 'audio' | 'video';
|
|
@@ -45,7 +41,6 @@ export declare class HostState {
|
|
|
45
41
|
streams: Map<number, StreamSnapshot>;
|
|
46
42
|
subscriptions: Set<string>;
|
|
47
43
|
internalConnections: Set<string>;
|
|
48
|
-
streamRequestPolicy: StreamRequestPolicy;
|
|
49
44
|
streamSourceBindings: Map<string, StreamSourceBinding>;
|
|
50
45
|
protocolVersion: string;
|
|
51
46
|
serverVersion: string;
|
|
@@ -28,7 +28,13 @@ export interface RuntimeAdapter {
|
|
|
28
28
|
connect(serviceEntry: string | undefined, peerId: string, token: string, timeoutMs: number): Promise<string>;
|
|
29
29
|
disconnect(): Promise<void>;
|
|
30
30
|
startSendStream(streamId: number, media: string, source: StreamSource): Promise<RuntimeSendStartResult>;
|
|
31
|
+
startSendStreams?(streams: Array<{
|
|
32
|
+
streamId: number;
|
|
33
|
+
media: string;
|
|
34
|
+
source: StreamSource;
|
|
35
|
+
}>): Promise<RuntimeSendStartResult[]>;
|
|
31
36
|
stopSendStream(streamId: number): Promise<void>;
|
|
37
|
+
sendStreamMessage(streamId: number, payload: string): Promise<void>;
|
|
32
38
|
startReceiveStream(streamId: number, media: string): Promise<void>;
|
|
33
39
|
stopReceiveStream(streamId: number): Promise<void>;
|
|
34
40
|
attachOutput(streamId: number, consumer: string, mediaView: string, format: string, delivery: string, targetPath?: string, maxFiles?: number): Promise<OutputAttachResult>;
|
|
@@ -71,7 +77,13 @@ export declare class RuntimeBackedAdapter implements RuntimeAdapter {
|
|
|
71
77
|
connect(serviceEntry: string | undefined, peerId: string, token: string, timeoutMs: number): Promise<string>;
|
|
72
78
|
disconnect(): Promise<void>;
|
|
73
79
|
startSendStream(streamId: number, media: string, source: StreamSource): Promise<RuntimeSendStartResult>;
|
|
80
|
+
startSendStreams(streams: Array<{
|
|
81
|
+
streamId: number;
|
|
82
|
+
media: string;
|
|
83
|
+
source: StreamSource;
|
|
84
|
+
}>): Promise<RuntimeSendStartResult[]>;
|
|
74
85
|
stopSendStream(streamId: number): Promise<void>;
|
|
86
|
+
sendStreamMessage(streamId: number, payload: string): Promise<void>;
|
|
75
87
|
startReceiveStream(streamId: number, media: string): Promise<void>;
|
|
76
88
|
stopReceiveStream(streamId: number): Promise<void>;
|
|
77
89
|
attachOutput(streamId: number, consumer: string, mediaView: string, format: string, delivery: string, targetPath?: string, maxFiles?: number): Promise<OutputAttachResult>;
|
|
@@ -262,7 +262,6 @@ class RuntimeBackedAdapter {
|
|
|
262
262
|
async startService(serviceEntry, license, timeoutMs) {
|
|
263
263
|
this.assertRuntimeBundleReady();
|
|
264
264
|
const resolvedServiceEntry = this.resolveServiceEntry(serviceEntry);
|
|
265
|
-
const senderBootstrap = await this.sendWorker.ensureServiceSession(resolvedServiceEntry, license);
|
|
266
265
|
this.activeService = {
|
|
267
266
|
serviceEntry: resolvedServiceEntry,
|
|
268
267
|
license,
|
|
@@ -272,8 +271,7 @@ class RuntimeBackedAdapter {
|
|
|
272
271
|
serviceEntry: resolvedServiceEntry,
|
|
273
272
|
licensePresent: license.length > 0,
|
|
274
273
|
timeoutMs,
|
|
275
|
-
senderBootstrapStarted:
|
|
276
|
-
senderWorkerPid: senderBootstrap.pid,
|
|
274
|
+
senderBootstrapStarted: false,
|
|
277
275
|
at: nowIsoString(),
|
|
278
276
|
});
|
|
279
277
|
return resolvedServiceEntry;
|
|
@@ -365,6 +363,36 @@ class RuntimeBackedAdapter {
|
|
|
365
363
|
});
|
|
366
364
|
return { autoStarted, workerPid };
|
|
367
365
|
}
|
|
366
|
+
async startSendStreams(streams) {
|
|
367
|
+
const activeService = this.activeService;
|
|
368
|
+
if (!activeService || streams.length === 0) {
|
|
369
|
+
return streams.map(() => ({ autoStarted: false }));
|
|
370
|
+
}
|
|
371
|
+
const bindings = streams.map((stream) => ({
|
|
372
|
+
key: String(stream.streamId) + '/' + stream.media,
|
|
373
|
+
serviceEntry: activeService.serviceEntry,
|
|
374
|
+
license: activeService.license,
|
|
375
|
+
assetsDir: resolveStreamAssetsDir(stream.source),
|
|
376
|
+
streamId: stream.streamId,
|
|
377
|
+
media: stream.media === 'audio' ? 'audio' : 'video',
|
|
378
|
+
}));
|
|
379
|
+
const startResult = await this.sendWorker.startDeviceStreams(bindings);
|
|
380
|
+
const startedAt = nowIsoString();
|
|
381
|
+
for (const binding of bindings) {
|
|
382
|
+
this.emit('stream', 'send.start.requested', {
|
|
383
|
+
streamId: binding.streamId,
|
|
384
|
+
media: binding.media,
|
|
385
|
+
sourceMode: 'local_assets',
|
|
386
|
+
assetsDir: binding.assetsDir,
|
|
387
|
+
connected: this.connected,
|
|
388
|
+
workerPid: startResult.pid,
|
|
389
|
+
autoStarted: startResult.started,
|
|
390
|
+
deferred: false,
|
|
391
|
+
at: startedAt,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return bindings.map(() => ({ autoStarted: startResult.started, workerPid: startResult.pid }));
|
|
395
|
+
}
|
|
368
396
|
async stopSendStream(streamId) {
|
|
369
397
|
const keys = [String(streamId) + '/audio', String(streamId) + '/video'];
|
|
370
398
|
for (const key of keys) {
|
|
@@ -372,6 +400,17 @@ class RuntimeBackedAdapter {
|
|
|
372
400
|
}
|
|
373
401
|
this.emit('stream', 'send.stop.requested', { streamId, at: nowIsoString() });
|
|
374
402
|
}
|
|
403
|
+
async sendStreamMessage(streamId, payload) {
|
|
404
|
+
if (!this.connected) {
|
|
405
|
+
throw new Error('connection is not established');
|
|
406
|
+
}
|
|
407
|
+
this.emit('stream', 'message.runtime.send', {
|
|
408
|
+
streamId,
|
|
409
|
+
payloadPreview: payload.slice(0, 120),
|
|
410
|
+
payloadLength: payload.length,
|
|
411
|
+
at: nowIsoString(),
|
|
412
|
+
});
|
|
413
|
+
}
|
|
375
414
|
async startReceiveStream(streamId, media) {
|
|
376
415
|
if (!this.connected) {
|
|
377
416
|
throw new Error('connection is not established');
|
|
@@ -36,6 +36,10 @@ export declare class RuntimeSendWorkerManager {
|
|
|
36
36
|
started: boolean;
|
|
37
37
|
pid?: number;
|
|
38
38
|
}>;
|
|
39
|
+
startDeviceStreams(optionsList: SendWorkerStartOptions[]): Promise<{
|
|
40
|
+
started: boolean;
|
|
41
|
+
pid?: number;
|
|
42
|
+
}>;
|
|
39
43
|
stopStream(key: string): Promise<void>;
|
|
40
44
|
stopAll(): Promise<void>;
|
|
41
45
|
}
|
|
@@ -258,6 +258,23 @@ class RuntimeSendWorkerManager {
|
|
|
258
258
|
});
|
|
259
259
|
return await this.ensureSharedSession(options.serviceEntry, options.license, true);
|
|
260
260
|
}
|
|
261
|
+
async startDeviceStreams(optionsList) {
|
|
262
|
+
if (optionsList.length === 0) {
|
|
263
|
+
return { started: false };
|
|
264
|
+
}
|
|
265
|
+
for (const options of optionsList) {
|
|
266
|
+
this.bindings.set(options.key, {
|
|
267
|
+
key: options.key,
|
|
268
|
+
serviceEntry: options.serviceEntry,
|
|
269
|
+
license: options.license,
|
|
270
|
+
assetsDir: ensureValidAssetsDir(options.assetsDir),
|
|
271
|
+
streamId: options.streamId,
|
|
272
|
+
media: options.media,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
const first = optionsList[0];
|
|
276
|
+
return await this.ensureSharedSession(first.serviceEntry, first.license, true);
|
|
277
|
+
}
|
|
261
278
|
async stopStream(key) {
|
|
262
279
|
this.bindings.delete(key);
|
|
263
280
|
const current = this.sharedSession;
|