livekit-server-sdk 2.2.0 → 2.4.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/README.md +80 -95
- package/dist/AccessToken.d.ts +1 -0
- package/dist/AccessToken.d.ts.map +1 -0
- package/dist/AccessToken.js +3 -0
- package/dist/AccessToken.js.map +1 -1
- package/dist/EgressClient.d.ts +1 -0
- package/dist/EgressClient.d.ts.map +1 -0
- package/dist/EgressClient.js +4 -1
- package/dist/EgressClient.js.map +1 -1
- package/dist/IngressClient.d.ts +1 -0
- package/dist/IngressClient.d.ts.map +1 -0
- package/dist/IngressClient.js +3 -0
- package/dist/IngressClient.js.map +1 -1
- package/dist/RoomServiceClient.d.ts +1 -0
- package/dist/RoomServiceClient.d.ts.map +1 -0
- package/dist/RoomServiceClient.js.map +1 -1
- package/dist/ServiceBase.d.ts +1 -0
- package/dist/ServiceBase.d.ts.map +1 -0
- package/dist/ServiceBase.js +3 -0
- package/dist/ServiceBase.js.map +1 -1
- package/dist/SipClient.d.ts +76 -0
- package/dist/SipClient.d.ts.map +1 -0
- package/dist/SipClient.js +168 -0
- package/dist/SipClient.js.map +1 -0
- package/dist/TwirpRPC.d.ts +1 -0
- package/dist/TwirpRPC.d.ts.map +1 -0
- package/dist/TwirpRPC.js.map +1 -1
- package/dist/WebhookReceiver.d.ts +2 -1
- package/dist/WebhookReceiver.d.ts.map +1 -0
- package/dist/WebhookReceiver.js.map +1 -1
- package/dist/grants.d.ts +2 -1
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +3 -0
- package/dist/grants.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
- package/src/AccessToken.test.ts +96 -0
- package/src/AccessToken.ts +151 -0
- package/src/EgressClient.ts +617 -0
- package/src/IngressClient.ts +257 -0
- package/src/RoomServiceClient.ts +358 -0
- package/src/ServiceBase.ts +35 -0
- package/src/SipClient.ts +277 -0
- package/src/TwirpRPC.ts +54 -0
- package/src/WebhookReceiver.test.ts +44 -0
- package/src/WebhookReceiver.ts +85 -0
- package/src/grants.test.ts +30 -0
- package/src/grants.ts +96 -0
- package/src/index.ts +53 -0
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.eslintrc.cjs +0 -17
- package/.github/banner_dark.png +0 -0
- package/.github/banner_light.png +0 -0
- package/.github/workflows/release.yaml +0 -46
- package/.github/workflows/test.yaml +0 -46
- package/.gitmodules +0 -3
- package/.prettierignore +0 -8
- package/CHANGELOG.md +0 -81
- package/LICENSE +0 -201
- package/NOTICE +0 -13
- package/renovate.json +0 -18
- package/tsconfig.eslint.json +0 -5
- package/vite.config.js +0 -8
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import {
|
|
5
|
+
DirectFileOutput,
|
|
6
|
+
EgressInfo,
|
|
7
|
+
EncodedFileOutput,
|
|
8
|
+
EncodingOptions,
|
|
9
|
+
EncodingOptionsPreset,
|
|
10
|
+
ImageOutput,
|
|
11
|
+
ListEgressRequest,
|
|
12
|
+
ListEgressResponse,
|
|
13
|
+
ParticipantEgressRequest,
|
|
14
|
+
RoomCompositeEgressRequest,
|
|
15
|
+
SegmentedFileOutput,
|
|
16
|
+
StopEgressRequest,
|
|
17
|
+
StreamOutput,
|
|
18
|
+
TrackCompositeEgressRequest,
|
|
19
|
+
TrackEgressRequest,
|
|
20
|
+
UpdateLayoutRequest,
|
|
21
|
+
UpdateStreamRequest,
|
|
22
|
+
WebEgressRequest,
|
|
23
|
+
} from '@livekit/protocol';
|
|
24
|
+
import ServiceBase from './ServiceBase.js';
|
|
25
|
+
import { Rpc, TwirpRpc, livekitPackage } from './TwirpRPC.js';
|
|
26
|
+
|
|
27
|
+
const svc = 'Egress';
|
|
28
|
+
|
|
29
|
+
export interface RoomCompositeOptions {
|
|
30
|
+
/**
|
|
31
|
+
* egress layout. optional
|
|
32
|
+
*/
|
|
33
|
+
layout?: string;
|
|
34
|
+
/**
|
|
35
|
+
* encoding options or preset. optional
|
|
36
|
+
*/
|
|
37
|
+
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
|
|
38
|
+
/**
|
|
39
|
+
* record audio only. optional
|
|
40
|
+
*/
|
|
41
|
+
audioOnly?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* record video only. optional
|
|
44
|
+
*/
|
|
45
|
+
videoOnly?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* custom template url. optional
|
|
48
|
+
*/
|
|
49
|
+
customBaseUrl?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface WebOptions {
|
|
53
|
+
/**
|
|
54
|
+
* encoding options or preset. optional
|
|
55
|
+
*/
|
|
56
|
+
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
|
|
57
|
+
/**
|
|
58
|
+
* record audio only. optional
|
|
59
|
+
*/
|
|
60
|
+
audioOnly?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* record video only. optional
|
|
63
|
+
*/
|
|
64
|
+
videoOnly?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* await START_RECORDING chrome log
|
|
67
|
+
*/
|
|
68
|
+
awaitStartSignal?: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface ParticipantEgressOptions {
|
|
72
|
+
/**
|
|
73
|
+
* true to capture source screenshare and screenshare_audio
|
|
74
|
+
* false to capture camera and microphone
|
|
75
|
+
*/
|
|
76
|
+
screenShare?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* encoding options or preset. optional
|
|
79
|
+
*/
|
|
80
|
+
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface TrackCompositeOptions {
|
|
84
|
+
/**
|
|
85
|
+
* audio track ID
|
|
86
|
+
*/
|
|
87
|
+
audioTrackId?: string;
|
|
88
|
+
/**
|
|
89
|
+
* video track ID
|
|
90
|
+
*/
|
|
91
|
+
videoTrackId?: string;
|
|
92
|
+
/**
|
|
93
|
+
* encoding options or preset. optional
|
|
94
|
+
*/
|
|
95
|
+
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Used to supply multiple outputs with an egress request
|
|
100
|
+
*/
|
|
101
|
+
export interface EncodedOutputs {
|
|
102
|
+
file?: EncodedFileOutput | undefined;
|
|
103
|
+
stream?: StreamOutput | undefined;
|
|
104
|
+
segments?: SegmentedFileOutput | undefined;
|
|
105
|
+
images?: ImageOutput | undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface ListEgressOptions {
|
|
109
|
+
roomName?: string;
|
|
110
|
+
egressId?: string;
|
|
111
|
+
active?: boolean;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Client to access Egress APIs
|
|
116
|
+
*/
|
|
117
|
+
export class EgressClient extends ServiceBase {
|
|
118
|
+
private readonly rpc: Rpc;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @param host hostname including protocol. i.e. 'https://cluster.livekit.io'
|
|
122
|
+
* @param apiKey API Key, can be set in env var LIVEKIT_API_KEY
|
|
123
|
+
* @param secret API Secret, can be set in env var LIVEKIT_API_SECRET
|
|
124
|
+
*/
|
|
125
|
+
constructor(host: string, apiKey?: string, secret?: string) {
|
|
126
|
+
super(apiKey, secret);
|
|
127
|
+
this.rpc = new TwirpRpc(host, livekitPackage);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param roomName room name
|
|
132
|
+
* @param output file or stream output
|
|
133
|
+
* @param opts RoomCompositeOptions
|
|
134
|
+
*/
|
|
135
|
+
async startRoomCompositeEgress(
|
|
136
|
+
roomName: string,
|
|
137
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
138
|
+
opts?: RoomCompositeOptions,
|
|
139
|
+
): Promise<EgressInfo>;
|
|
140
|
+
/**
|
|
141
|
+
* @deprecated use RoomCompositeOptions instead
|
|
142
|
+
*/
|
|
143
|
+
async startRoomCompositeEgress(
|
|
144
|
+
roomName: string,
|
|
145
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
146
|
+
layout?: string,
|
|
147
|
+
options?: EncodingOptionsPreset | EncodingOptions,
|
|
148
|
+
audioOnly?: boolean,
|
|
149
|
+
videoOnly?: boolean,
|
|
150
|
+
customBaseUrl?: string,
|
|
151
|
+
): Promise<EgressInfo>;
|
|
152
|
+
async startRoomCompositeEgress(
|
|
153
|
+
roomName: string,
|
|
154
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
155
|
+
optsOrLayout?: RoomCompositeOptions | string,
|
|
156
|
+
options?: EncodingOptionsPreset | EncodingOptions,
|
|
157
|
+
audioOnly?: boolean,
|
|
158
|
+
videoOnly?: boolean,
|
|
159
|
+
customBaseUrl?: string,
|
|
160
|
+
): Promise<EgressInfo> {
|
|
161
|
+
let layout: string | undefined;
|
|
162
|
+
if (optsOrLayout !== undefined) {
|
|
163
|
+
if (typeof optsOrLayout === 'string') {
|
|
164
|
+
layout = optsOrLayout;
|
|
165
|
+
} else {
|
|
166
|
+
const opts = <RoomCompositeOptions>optsOrLayout;
|
|
167
|
+
layout = opts.layout;
|
|
168
|
+
options = opts.encodingOptions;
|
|
169
|
+
audioOnly = opts.audioOnly;
|
|
170
|
+
videoOnly = opts.videoOnly;
|
|
171
|
+
customBaseUrl = opts.customBaseUrl;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
layout ??= '';
|
|
176
|
+
audioOnly ??= false;
|
|
177
|
+
videoOnly ??= false;
|
|
178
|
+
customBaseUrl ??= '';
|
|
179
|
+
|
|
180
|
+
const {
|
|
181
|
+
output: legacyOutput,
|
|
182
|
+
options: egressOptions,
|
|
183
|
+
fileOutputs,
|
|
184
|
+
streamOutputs,
|
|
185
|
+
segmentOutputs,
|
|
186
|
+
imageOutputs,
|
|
187
|
+
} = this.getOutputParams(output, options);
|
|
188
|
+
|
|
189
|
+
const req = new RoomCompositeEgressRequest({
|
|
190
|
+
roomName,
|
|
191
|
+
layout,
|
|
192
|
+
audioOnly,
|
|
193
|
+
videoOnly,
|
|
194
|
+
customBaseUrl,
|
|
195
|
+
output: legacyOutput,
|
|
196
|
+
options: egressOptions,
|
|
197
|
+
fileOutputs,
|
|
198
|
+
streamOutputs,
|
|
199
|
+
segmentOutputs,
|
|
200
|
+
imageOutputs,
|
|
201
|
+
}).toJson();
|
|
202
|
+
|
|
203
|
+
const data = await this.rpc.request(
|
|
204
|
+
svc,
|
|
205
|
+
'StartRoomCompositeEgress',
|
|
206
|
+
req,
|
|
207
|
+
await this.authHeader({ roomRecord: true }),
|
|
208
|
+
);
|
|
209
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @param url url
|
|
214
|
+
* @param output file or stream output
|
|
215
|
+
* @param opts WebOptions
|
|
216
|
+
*/
|
|
217
|
+
async startWebEgress(
|
|
218
|
+
url: string,
|
|
219
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
220
|
+
opts?: WebOptions,
|
|
221
|
+
): Promise<EgressInfo> {
|
|
222
|
+
const audioOnly = opts?.audioOnly || false;
|
|
223
|
+
const videoOnly = opts?.videoOnly || false;
|
|
224
|
+
const awaitStartSignal = opts?.awaitStartSignal || false;
|
|
225
|
+
const {
|
|
226
|
+
output: legacyOutput,
|
|
227
|
+
options,
|
|
228
|
+
fileOutputs,
|
|
229
|
+
streamOutputs,
|
|
230
|
+
segmentOutputs,
|
|
231
|
+
imageOutputs,
|
|
232
|
+
} = this.getOutputParams(output, opts?.encodingOptions);
|
|
233
|
+
|
|
234
|
+
const req = new WebEgressRequest({
|
|
235
|
+
url,
|
|
236
|
+
audioOnly,
|
|
237
|
+
videoOnly,
|
|
238
|
+
awaitStartSignal,
|
|
239
|
+
output: legacyOutput,
|
|
240
|
+
options,
|
|
241
|
+
fileOutputs,
|
|
242
|
+
streamOutputs,
|
|
243
|
+
segmentOutputs,
|
|
244
|
+
imageOutputs,
|
|
245
|
+
}).toJson();
|
|
246
|
+
|
|
247
|
+
const data = await this.rpc.request(
|
|
248
|
+
svc,
|
|
249
|
+
'StartWebEgress',
|
|
250
|
+
req,
|
|
251
|
+
await this.authHeader({ roomRecord: true }),
|
|
252
|
+
);
|
|
253
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Export a participant's audio and video tracks,
|
|
258
|
+
*
|
|
259
|
+
* @param roomName room name
|
|
260
|
+
* @param output one or more outputs
|
|
261
|
+
* @param opts ParticipantEgressOptions
|
|
262
|
+
*/
|
|
263
|
+
async startParticipantEgress(
|
|
264
|
+
roomName: string,
|
|
265
|
+
identity: string,
|
|
266
|
+
output: EncodedOutputs,
|
|
267
|
+
opts?: ParticipantEgressOptions,
|
|
268
|
+
): Promise<EgressInfo> {
|
|
269
|
+
const { options, fileOutputs, streamOutputs, segmentOutputs, imageOutputs } =
|
|
270
|
+
this.getOutputParams(output, opts?.encodingOptions);
|
|
271
|
+
const req = new ParticipantEgressRequest({
|
|
272
|
+
roomName,
|
|
273
|
+
identity,
|
|
274
|
+
options,
|
|
275
|
+
fileOutputs,
|
|
276
|
+
streamOutputs,
|
|
277
|
+
segmentOutputs,
|
|
278
|
+
imageOutputs,
|
|
279
|
+
}).toJson();
|
|
280
|
+
|
|
281
|
+
const data = await this.rpc.request(
|
|
282
|
+
svc,
|
|
283
|
+
'StartParticipantEgress',
|
|
284
|
+
req,
|
|
285
|
+
this.authHeader({ roomRecord: true }),
|
|
286
|
+
);
|
|
287
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* @param roomName room name
|
|
292
|
+
* @param output file or stream output
|
|
293
|
+
* @param opts TrackCompositeOptions
|
|
294
|
+
*/
|
|
295
|
+
async startTrackCompositeEgress(
|
|
296
|
+
roomName: string,
|
|
297
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
298
|
+
opts?: TrackCompositeOptions,
|
|
299
|
+
): Promise<EgressInfo>;
|
|
300
|
+
/**
|
|
301
|
+
* @deprecated use TrackCompositeOptions instead
|
|
302
|
+
*/
|
|
303
|
+
async startTrackCompositeEgress(
|
|
304
|
+
roomName: string,
|
|
305
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
306
|
+
audioTrackId?: string,
|
|
307
|
+
videoTrackId?: string,
|
|
308
|
+
options?: EncodingOptionsPreset | EncodingOptions,
|
|
309
|
+
): Promise<EgressInfo>;
|
|
310
|
+
async startTrackCompositeEgress(
|
|
311
|
+
roomName: string,
|
|
312
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
313
|
+
optsOrAudioTrackId?: TrackCompositeOptions | string,
|
|
314
|
+
videoTrackId?: string,
|
|
315
|
+
options?: EncodingOptionsPreset | EncodingOptions,
|
|
316
|
+
): Promise<EgressInfo> {
|
|
317
|
+
let audioTrackId: string | undefined;
|
|
318
|
+
if (optsOrAudioTrackId !== undefined) {
|
|
319
|
+
if (typeof optsOrAudioTrackId === 'string') {
|
|
320
|
+
audioTrackId = optsOrAudioTrackId;
|
|
321
|
+
} else {
|
|
322
|
+
const opts = <TrackCompositeOptions>optsOrAudioTrackId;
|
|
323
|
+
audioTrackId = opts.audioTrackId;
|
|
324
|
+
videoTrackId = opts.videoTrackId;
|
|
325
|
+
options = opts.encodingOptions;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
audioTrackId ??= '';
|
|
330
|
+
videoTrackId ??= '';
|
|
331
|
+
|
|
332
|
+
const {
|
|
333
|
+
output: legacyOutput,
|
|
334
|
+
options: egressOptions,
|
|
335
|
+
fileOutputs,
|
|
336
|
+
streamOutputs,
|
|
337
|
+
segmentOutputs,
|
|
338
|
+
imageOutputs,
|
|
339
|
+
} = this.getOutputParams(output, options);
|
|
340
|
+
const req = new TrackCompositeEgressRequest({
|
|
341
|
+
roomName,
|
|
342
|
+
audioTrackId,
|
|
343
|
+
videoTrackId,
|
|
344
|
+
output: legacyOutput,
|
|
345
|
+
options: egressOptions,
|
|
346
|
+
fileOutputs,
|
|
347
|
+
streamOutputs,
|
|
348
|
+
segmentOutputs,
|
|
349
|
+
imageOutputs,
|
|
350
|
+
}).toJson();
|
|
351
|
+
|
|
352
|
+
const data = await this.rpc.request(
|
|
353
|
+
svc,
|
|
354
|
+
'StartTrackCompositeEgress',
|
|
355
|
+
req,
|
|
356
|
+
await this.authHeader({ roomRecord: true }),
|
|
357
|
+
);
|
|
358
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
private isEncodedOutputs(output: any): output is EncodedOutputs {
|
|
362
|
+
return (
|
|
363
|
+
(<EncodedOutputs>output).file !== undefined ||
|
|
364
|
+
(<EncodedOutputs>output).stream !== undefined ||
|
|
365
|
+
(<EncodedOutputs>output).segments !== undefined
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private isEncodedFileOutput(output: any): output is EncodedFileOutput {
|
|
370
|
+
return (
|
|
371
|
+
(<EncodedFileOutput>output).filepath !== undefined ||
|
|
372
|
+
(<EncodedFileOutput>output).fileType !== undefined
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
private isSegmentedFileOutput(output: any): output is SegmentedFileOutput {
|
|
377
|
+
return (
|
|
378
|
+
(<SegmentedFileOutput>output).filenamePrefix !== undefined ||
|
|
379
|
+
(<SegmentedFileOutput>output).playlistName !== undefined ||
|
|
380
|
+
(<SegmentedFileOutput>output).filenameSuffix !== undefined
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private isStreamOutput(output: any): output is StreamOutput {
|
|
385
|
+
return (
|
|
386
|
+
(<StreamOutput>output).protocol !== undefined || (<StreamOutput>output).urls !== undefined
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
private getOutputParams(
|
|
391
|
+
output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput,
|
|
392
|
+
opts?: EncodingOptionsPreset | EncodingOptions,
|
|
393
|
+
) {
|
|
394
|
+
let file: EncodedFileOutput | undefined;
|
|
395
|
+
let fileOutputs: Array<EncodedFileOutput> | undefined;
|
|
396
|
+
let stream: StreamOutput | undefined;
|
|
397
|
+
let streamOutputs: Array<StreamOutput> | undefined;
|
|
398
|
+
let segments: SegmentedFileOutput | undefined;
|
|
399
|
+
let segmentOutputs: Array<SegmentedFileOutput> | undefined;
|
|
400
|
+
let imageOutputs: Array<ImageOutput> | undefined;
|
|
401
|
+
|
|
402
|
+
if (this.isEncodedOutputs(output)) {
|
|
403
|
+
if (output.file !== undefined) {
|
|
404
|
+
fileOutputs = [output.file];
|
|
405
|
+
}
|
|
406
|
+
if (output.stream !== undefined) {
|
|
407
|
+
streamOutputs = [output.stream];
|
|
408
|
+
}
|
|
409
|
+
if (output.segments !== undefined) {
|
|
410
|
+
segmentOutputs = [output.segments];
|
|
411
|
+
}
|
|
412
|
+
if (output.images !== undefined) {
|
|
413
|
+
imageOutputs = [output.images];
|
|
414
|
+
}
|
|
415
|
+
} else if (this.isEncodedFileOutput(output)) {
|
|
416
|
+
file = output;
|
|
417
|
+
fileOutputs = [file];
|
|
418
|
+
} else if (this.isSegmentedFileOutput(output)) {
|
|
419
|
+
segments = output;
|
|
420
|
+
segmentOutputs = [segments];
|
|
421
|
+
} else if (this.isStreamOutput(output)) {
|
|
422
|
+
stream = output;
|
|
423
|
+
streamOutputs = [stream];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
let legacyOutput:
|
|
427
|
+
| {
|
|
428
|
+
value: EncodedFileOutput;
|
|
429
|
+
case: 'file';
|
|
430
|
+
}
|
|
431
|
+
| {
|
|
432
|
+
value: StreamOutput;
|
|
433
|
+
case: 'stream';
|
|
434
|
+
}
|
|
435
|
+
| {
|
|
436
|
+
value: SegmentedFileOutput;
|
|
437
|
+
case: 'segments';
|
|
438
|
+
}
|
|
439
|
+
| undefined;
|
|
440
|
+
|
|
441
|
+
if (file) {
|
|
442
|
+
legacyOutput = {
|
|
443
|
+
case: 'file',
|
|
444
|
+
value: file,
|
|
445
|
+
};
|
|
446
|
+
} else if (stream) {
|
|
447
|
+
legacyOutput = {
|
|
448
|
+
case: 'stream',
|
|
449
|
+
value: stream,
|
|
450
|
+
};
|
|
451
|
+
} else if (segments) {
|
|
452
|
+
legacyOutput = {
|
|
453
|
+
case: 'segments',
|
|
454
|
+
value: segments,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
let egressOptions:
|
|
458
|
+
| {
|
|
459
|
+
value: EncodingOptionsPreset;
|
|
460
|
+
case: 'preset';
|
|
461
|
+
}
|
|
462
|
+
| {
|
|
463
|
+
value: EncodingOptions;
|
|
464
|
+
case: 'advanced';
|
|
465
|
+
}
|
|
466
|
+
| undefined;
|
|
467
|
+
if (opts) {
|
|
468
|
+
if (typeof opts === 'number') {
|
|
469
|
+
egressOptions = {
|
|
470
|
+
case: 'preset',
|
|
471
|
+
value: opts,
|
|
472
|
+
};
|
|
473
|
+
} else {
|
|
474
|
+
egressOptions = {
|
|
475
|
+
case: 'advanced',
|
|
476
|
+
value: <EncodingOptions>opts,
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return {
|
|
482
|
+
output: legacyOutput,
|
|
483
|
+
options: egressOptions,
|
|
484
|
+
fileOutputs,
|
|
485
|
+
streamOutputs,
|
|
486
|
+
segmentOutputs,
|
|
487
|
+
imageOutputs,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* @param roomName room name
|
|
493
|
+
* @param output file or websocket output
|
|
494
|
+
* @param trackId track Id
|
|
495
|
+
*/
|
|
496
|
+
async startTrackEgress(
|
|
497
|
+
roomName: string,
|
|
498
|
+
output: DirectFileOutput | string,
|
|
499
|
+
trackId: string,
|
|
500
|
+
): Promise<EgressInfo> {
|
|
501
|
+
let legacyOutput:
|
|
502
|
+
| {
|
|
503
|
+
value: DirectFileOutput;
|
|
504
|
+
case: 'file';
|
|
505
|
+
}
|
|
506
|
+
| {
|
|
507
|
+
value: string;
|
|
508
|
+
case: 'websocketUrl';
|
|
509
|
+
}
|
|
510
|
+
| undefined;
|
|
511
|
+
|
|
512
|
+
if (typeof output === 'string') {
|
|
513
|
+
legacyOutput = {
|
|
514
|
+
case: 'websocketUrl',
|
|
515
|
+
value: output,
|
|
516
|
+
};
|
|
517
|
+
} else {
|
|
518
|
+
legacyOutput = {
|
|
519
|
+
case: 'file',
|
|
520
|
+
value: output,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const req = new TrackEgressRequest({
|
|
525
|
+
roomName,
|
|
526
|
+
trackId,
|
|
527
|
+
output: legacyOutput,
|
|
528
|
+
}).toJson();
|
|
529
|
+
|
|
530
|
+
const data = await this.rpc.request(
|
|
531
|
+
svc,
|
|
532
|
+
'StartTrackEgress',
|
|
533
|
+
req,
|
|
534
|
+
await this.authHeader({ roomRecord: true }),
|
|
535
|
+
);
|
|
536
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* @param egressId
|
|
541
|
+
* @param layout
|
|
542
|
+
*/
|
|
543
|
+
async updateLayout(egressId: string, layout: string): Promise<EgressInfo> {
|
|
544
|
+
const data = await this.rpc.request(
|
|
545
|
+
svc,
|
|
546
|
+
'UpdateLayout',
|
|
547
|
+
new UpdateLayoutRequest({ egressId, layout }).toJson(),
|
|
548
|
+
await this.authHeader({ roomRecord: true }),
|
|
549
|
+
);
|
|
550
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* @param egressId
|
|
555
|
+
* @param addOutputUrls
|
|
556
|
+
* @param removeOutputUrls
|
|
557
|
+
*/
|
|
558
|
+
async updateStream(
|
|
559
|
+
egressId: string,
|
|
560
|
+
addOutputUrls?: string[],
|
|
561
|
+
removeOutputUrls?: string[],
|
|
562
|
+
): Promise<EgressInfo> {
|
|
563
|
+
addOutputUrls ??= [];
|
|
564
|
+
removeOutputUrls ??= [];
|
|
565
|
+
|
|
566
|
+
const data = await this.rpc.request(
|
|
567
|
+
svc,
|
|
568
|
+
'UpdateStream',
|
|
569
|
+
new UpdateStreamRequest({ egressId, addOutputUrls, removeOutputUrls }).toJson(),
|
|
570
|
+
await this.authHeader({ roomRecord: true }),
|
|
571
|
+
);
|
|
572
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* @param options options to filter listed Egresses, by default returns all
|
|
577
|
+
* Egress instances
|
|
578
|
+
*/
|
|
579
|
+
async listEgress(options?: ListEgressOptions): Promise<Array<EgressInfo>>;
|
|
580
|
+
/**
|
|
581
|
+
* @deprecated
|
|
582
|
+
* @param roomName list egress for one room only
|
|
583
|
+
*/
|
|
584
|
+
async listEgress(roomName?: string): Promise<Array<EgressInfo>>;
|
|
585
|
+
/**
|
|
586
|
+
* @param roomName list egress for one room only
|
|
587
|
+
*/
|
|
588
|
+
async listEgress(options?: string | ListEgressOptions): Promise<Array<EgressInfo>> {
|
|
589
|
+
let req: Partial<ListEgressRequest> = {};
|
|
590
|
+
if (typeof options === 'string') {
|
|
591
|
+
req.roomName = options;
|
|
592
|
+
} else if (options !== undefined) {
|
|
593
|
+
req = options;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const data = await this.rpc.request(
|
|
597
|
+
svc,
|
|
598
|
+
'ListEgress',
|
|
599
|
+
new ListEgressRequest(req).toJson(),
|
|
600
|
+
await this.authHeader({ roomRecord: true }),
|
|
601
|
+
);
|
|
602
|
+
return ListEgressResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* @param egressId
|
|
607
|
+
*/
|
|
608
|
+
async stopEgress(egressId: string): Promise<EgressInfo> {
|
|
609
|
+
const data = await this.rpc.request(
|
|
610
|
+
svc,
|
|
611
|
+
'StopEgress',
|
|
612
|
+
new StopEgressRequest({ egressId }).toJson(),
|
|
613
|
+
await this.authHeader({ roomRecord: true }),
|
|
614
|
+
);
|
|
615
|
+
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
616
|
+
}
|
|
617
|
+
}
|