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,257 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import {
|
|
5
|
+
CreateIngressRequest,
|
|
6
|
+
DeleteIngressRequest,
|
|
7
|
+
IngressAudioOptions,
|
|
8
|
+
IngressInfo,
|
|
9
|
+
IngressInput,
|
|
10
|
+
IngressVideoOptions,
|
|
11
|
+
ListIngressRequest,
|
|
12
|
+
ListIngressResponse,
|
|
13
|
+
UpdateIngressRequest,
|
|
14
|
+
} from '@livekit/protocol';
|
|
15
|
+
import ServiceBase from './ServiceBase.js';
|
|
16
|
+
import { Rpc, TwirpRpc, livekitPackage } from './TwirpRPC.js';
|
|
17
|
+
|
|
18
|
+
const svc = 'Ingress';
|
|
19
|
+
|
|
20
|
+
export interface CreateIngressOptions {
|
|
21
|
+
/**
|
|
22
|
+
* ingress name. optional
|
|
23
|
+
*/
|
|
24
|
+
name?: string;
|
|
25
|
+
/**
|
|
26
|
+
* name of the room to send media to. optional
|
|
27
|
+
*/
|
|
28
|
+
roomName?: string;
|
|
29
|
+
/**
|
|
30
|
+
* unique identity of the participant. optional
|
|
31
|
+
*/
|
|
32
|
+
participantIdentity?: string;
|
|
33
|
+
/**
|
|
34
|
+
* participant display name
|
|
35
|
+
*/
|
|
36
|
+
participantName?: string;
|
|
37
|
+
/**
|
|
38
|
+
* metadata to attach to the participant
|
|
39
|
+
*/
|
|
40
|
+
participantMetadata?: string;
|
|
41
|
+
/**
|
|
42
|
+
* @deprecated use `enableTranscoding` instead.
|
|
43
|
+
* whether to skip transcoding and forward the input media directly. Only supported by WHIP
|
|
44
|
+
*/
|
|
45
|
+
bypassTranscoding?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* whether to enable transcoding or forward the input media directly.
|
|
48
|
+
* Transcoding is required for all input types except WHIP. For WHIP, the default is to not transcode.
|
|
49
|
+
*/
|
|
50
|
+
enableTranscoding?: boolean | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* url of the media to pull for ingresses of type URL
|
|
53
|
+
*/
|
|
54
|
+
url?: string;
|
|
55
|
+
/**
|
|
56
|
+
* custom audio encoding parameters. optional
|
|
57
|
+
*/
|
|
58
|
+
audio?: IngressAudioOptions;
|
|
59
|
+
/**
|
|
60
|
+
* custom video encoding parameters. optional
|
|
61
|
+
*/
|
|
62
|
+
video?: IngressVideoOptions;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface UpdateIngressOptions {
|
|
66
|
+
/**
|
|
67
|
+
* ingress name. optional
|
|
68
|
+
*/
|
|
69
|
+
name: string;
|
|
70
|
+
/**
|
|
71
|
+
* name of the room to send media to. optional
|
|
72
|
+
*/
|
|
73
|
+
roomName?: string;
|
|
74
|
+
/**
|
|
75
|
+
* unique identity of the participant. optional
|
|
76
|
+
*/
|
|
77
|
+
participantIdentity?: string;
|
|
78
|
+
/**
|
|
79
|
+
* participant display name
|
|
80
|
+
*/
|
|
81
|
+
participantName?: string;
|
|
82
|
+
/**
|
|
83
|
+
* metadata to attach to the participant
|
|
84
|
+
*/
|
|
85
|
+
participantMetadata?: string;
|
|
86
|
+
/**
|
|
87
|
+
* @deprecated use `enableTranscoding` instead
|
|
88
|
+
* whether to skip transcoding and forward the input media directly. Only supported by WHIP
|
|
89
|
+
*/
|
|
90
|
+
bypassTranscoding?: boolean | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* whether to enable transcoding or forward the input media directly.
|
|
93
|
+
* Transcoding is required for all input types except WHIP. For WHIP, the default is to not transcode.
|
|
94
|
+
*/
|
|
95
|
+
enableTranscoding?: boolean | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* custom audio encoding parameters. optional
|
|
98
|
+
*/
|
|
99
|
+
audio?: IngressAudioOptions;
|
|
100
|
+
/**
|
|
101
|
+
* custom video encoding parameters. optional
|
|
102
|
+
*/
|
|
103
|
+
video?: IngressVideoOptions;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface ListIngressOptions {
|
|
107
|
+
/**
|
|
108
|
+
* list ingress for one room only
|
|
109
|
+
*/
|
|
110
|
+
roomName?: string;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* list ingress by ID
|
|
114
|
+
*/
|
|
115
|
+
ingressId?: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Client to access Ingress APIs
|
|
120
|
+
*/
|
|
121
|
+
export class IngressClient extends ServiceBase {
|
|
122
|
+
private readonly rpc: Rpc;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @param host hostname including protocol. i.e. 'https://cluster.livekit.io'
|
|
126
|
+
* @param apiKey API Key, can be set in env var LIVEKIT_API_KEY
|
|
127
|
+
* @param secret API Secret, can be set in env var LIVEKIT_API_SECRET
|
|
128
|
+
*/
|
|
129
|
+
constructor(host: string, apiKey?: string, secret?: string) {
|
|
130
|
+
super(apiKey, secret);
|
|
131
|
+
this.rpc = new TwirpRpc(host, livekitPackage);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @param inputType protocol for the ingress
|
|
136
|
+
* @param opts CreateIngressOptions
|
|
137
|
+
*/
|
|
138
|
+
async createIngress(inputType: IngressInput, opts?: CreateIngressOptions): Promise<IngressInfo> {
|
|
139
|
+
let name: string = '';
|
|
140
|
+
let roomName: string = '';
|
|
141
|
+
let participantName: string = '';
|
|
142
|
+
let participantIdentity: string = '';
|
|
143
|
+
let participantMetadata: string | undefined;
|
|
144
|
+
let bypassTranscoding: boolean = false;
|
|
145
|
+
let enableTranscoding: boolean | undefined;
|
|
146
|
+
let url: string = '';
|
|
147
|
+
let audio: IngressAudioOptions | undefined;
|
|
148
|
+
let video: IngressVideoOptions | undefined;
|
|
149
|
+
|
|
150
|
+
if (opts !== undefined) {
|
|
151
|
+
name = opts.name || '';
|
|
152
|
+
roomName = opts.roomName || '';
|
|
153
|
+
participantName = opts.participantName || '';
|
|
154
|
+
participantIdentity = opts.participantIdentity || '';
|
|
155
|
+
bypassTranscoding = opts.bypassTranscoding || false;
|
|
156
|
+
enableTranscoding = opts.enableTranscoding;
|
|
157
|
+
url = opts.url || '';
|
|
158
|
+
audio = opts.audio;
|
|
159
|
+
video = opts.video;
|
|
160
|
+
participantMetadata = opts.participantMetadata;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const req = new CreateIngressRequest({
|
|
164
|
+
inputType,
|
|
165
|
+
name,
|
|
166
|
+
roomName,
|
|
167
|
+
participantIdentity,
|
|
168
|
+
participantMetadata,
|
|
169
|
+
participantName,
|
|
170
|
+
bypassTranscoding,
|
|
171
|
+
enableTranscoding,
|
|
172
|
+
url,
|
|
173
|
+
audio,
|
|
174
|
+
video,
|
|
175
|
+
}).toJson();
|
|
176
|
+
|
|
177
|
+
const data = await this.rpc.request(
|
|
178
|
+
svc,
|
|
179
|
+
'CreateIngress',
|
|
180
|
+
req,
|
|
181
|
+
await this.authHeader({ ingressAdmin: true }),
|
|
182
|
+
);
|
|
183
|
+
return IngressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @param ingressId ID of the ingress to update
|
|
188
|
+
* @param opts UpdateIngressOptions
|
|
189
|
+
*/
|
|
190
|
+
async updateIngress(ingressId: string, opts: UpdateIngressOptions): Promise<IngressInfo> {
|
|
191
|
+
const name: string = opts.name || '';
|
|
192
|
+
const roomName: string = opts.roomName || '';
|
|
193
|
+
const participantName: string = opts.participantName || '';
|
|
194
|
+
const participantIdentity: string = opts.participantIdentity || '';
|
|
195
|
+
const { participantMetadata } = opts;
|
|
196
|
+
const { audio, video, bypassTranscoding, enableTranscoding } = opts;
|
|
197
|
+
|
|
198
|
+
const req = new UpdateIngressRequest({
|
|
199
|
+
ingressId,
|
|
200
|
+
name,
|
|
201
|
+
roomName,
|
|
202
|
+
participantIdentity,
|
|
203
|
+
participantName,
|
|
204
|
+
participantMetadata,
|
|
205
|
+
bypassTranscoding,
|
|
206
|
+
enableTranscoding,
|
|
207
|
+
audio,
|
|
208
|
+
video,
|
|
209
|
+
}).toJson();
|
|
210
|
+
|
|
211
|
+
const data = await this.rpc.request(
|
|
212
|
+
svc,
|
|
213
|
+
'UpdateIngress',
|
|
214
|
+
req,
|
|
215
|
+
await this.authHeader({ ingressAdmin: true }),
|
|
216
|
+
);
|
|
217
|
+
return IngressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @deprecated use listIngress(opts) instead
|
|
222
|
+
* @param roomName list ingress for one room only
|
|
223
|
+
*/
|
|
224
|
+
async listIngress(roomName?: string): Promise<Array<IngressInfo>>;
|
|
225
|
+
/**
|
|
226
|
+
* @param opts list options
|
|
227
|
+
*/
|
|
228
|
+
async listIngress(opts?: ListIngressOptions): Promise<Array<IngressInfo>>;
|
|
229
|
+
async listIngress(arg?: string | ListIngressOptions): Promise<Array<IngressInfo>> {
|
|
230
|
+
let req: Partial<ListIngressRequest> = {};
|
|
231
|
+
if (typeof arg === 'string') {
|
|
232
|
+
req.roomName = arg;
|
|
233
|
+
} else if (arg) {
|
|
234
|
+
req = arg;
|
|
235
|
+
}
|
|
236
|
+
const data = await this.rpc.request(
|
|
237
|
+
svc,
|
|
238
|
+
'ListIngress',
|
|
239
|
+
new ListIngressRequest(req).toJson(),
|
|
240
|
+
await this.authHeader({ ingressAdmin: true }),
|
|
241
|
+
);
|
|
242
|
+
return ListIngressResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* @param ingressId ingress to delete
|
|
247
|
+
*/
|
|
248
|
+
async deleteIngress(ingressId: string): Promise<IngressInfo> {
|
|
249
|
+
const data = await this.rpc.request(
|
|
250
|
+
svc,
|
|
251
|
+
'DeleteIngress',
|
|
252
|
+
new DeleteIngressRequest({ ingressId }).toJson(),
|
|
253
|
+
await this.authHeader({ ingressAdmin: true }),
|
|
254
|
+
);
|
|
255
|
+
return IngressInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import type { DataPacket_Kind, TrackInfo } from '@livekit/protocol';
|
|
5
|
+
import {
|
|
6
|
+
CreateRoomRequest,
|
|
7
|
+
DeleteRoomRequest,
|
|
8
|
+
ListParticipantsRequest,
|
|
9
|
+
ListParticipantsResponse,
|
|
10
|
+
ListRoomsRequest,
|
|
11
|
+
ListRoomsResponse,
|
|
12
|
+
MuteRoomTrackRequest,
|
|
13
|
+
MuteRoomTrackResponse,
|
|
14
|
+
ParticipantInfo,
|
|
15
|
+
ParticipantPermission,
|
|
16
|
+
Room,
|
|
17
|
+
RoomEgress,
|
|
18
|
+
RoomParticipantIdentity,
|
|
19
|
+
SendDataRequest,
|
|
20
|
+
UpdateParticipantRequest,
|
|
21
|
+
UpdateRoomMetadataRequest,
|
|
22
|
+
UpdateSubscriptionsRequest,
|
|
23
|
+
} from '@livekit/protocol';
|
|
24
|
+
import ServiceBase from './ServiceBase.js';
|
|
25
|
+
import { Rpc, TwirpRpc, livekitPackage } from './TwirpRPC.js';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Options for when creating a room
|
|
29
|
+
*/
|
|
30
|
+
export interface CreateOptions {
|
|
31
|
+
/**
|
|
32
|
+
* name of the room. required
|
|
33
|
+
*/
|
|
34
|
+
name: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* number of seconds to keep the room open before any participant joins
|
|
38
|
+
*/
|
|
39
|
+
emptyTimeout?: number;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* number of seconds to keep the room open after the last participant leaves
|
|
43
|
+
*/
|
|
44
|
+
departureTimeout?: number;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* limit to the number of participants in a room at a time
|
|
48
|
+
*/
|
|
49
|
+
maxParticipants?: number;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* initial room metadata
|
|
53
|
+
*/
|
|
54
|
+
metadata?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* add egress options
|
|
58
|
+
*/
|
|
59
|
+
egress?: RoomEgress;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* minimum playout delay in milliseconds
|
|
63
|
+
*/
|
|
64
|
+
minPlayoutDelay?: number;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* maximum playout delay in milliseconds
|
|
68
|
+
*/
|
|
69
|
+
maxPlayoutDelay?: number;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* improves A/V sync when min_playout_delay set to a value larger than 200ms.
|
|
73
|
+
* It will disables transceiver re-use -- this option is not recommended
|
|
74
|
+
* for rooms with frequent subscription changes
|
|
75
|
+
*/
|
|
76
|
+
syncStreams?: boolean;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* override the node room is allocated to, for debugging
|
|
80
|
+
* does not work with Cloud
|
|
81
|
+
*/
|
|
82
|
+
nodeId?: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type SendDataOptions = {
|
|
86
|
+
/** If set, only deliver to listed participant identities */
|
|
87
|
+
destinationIdentities?: string[];
|
|
88
|
+
destinationSids?: string[];
|
|
89
|
+
topic?: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const svc = 'RoomService';
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Client to access Room APIs
|
|
96
|
+
*/
|
|
97
|
+
export class RoomServiceClient extends ServiceBase {
|
|
98
|
+
private readonly rpc: Rpc;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
*
|
|
102
|
+
* @param host hostname including protocol. i.e. 'https://cluster.livekit.io'
|
|
103
|
+
* @param apiKey API Key, can be set in env var LIVEKIT_API_KEY
|
|
104
|
+
* @param secret API Secret, can be set in env var LIVEKIT_API_SECRET
|
|
105
|
+
*/
|
|
106
|
+
constructor(host: string, apiKey?: string, secret?: string) {
|
|
107
|
+
super(apiKey, secret);
|
|
108
|
+
this.rpc = new TwirpRpc(host, livekitPackage);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Creates a new room. Explicit room creation is not required, since rooms will
|
|
113
|
+
* be automatically created when the first participant joins. This method can be
|
|
114
|
+
* used to customize room settings.
|
|
115
|
+
* @param options
|
|
116
|
+
*/
|
|
117
|
+
async createRoom(options: CreateOptions): Promise<Room> {
|
|
118
|
+
const data = await this.rpc.request(
|
|
119
|
+
svc,
|
|
120
|
+
'CreateRoom',
|
|
121
|
+
new CreateRoomRequest(options).toJson(),
|
|
122
|
+
await this.authHeader({ roomCreate: true }),
|
|
123
|
+
);
|
|
124
|
+
return Room.fromJson(data, { ignoreUnknownFields: true });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* List active rooms
|
|
129
|
+
* @param names when undefined or empty, list all rooms.
|
|
130
|
+
* otherwise returns rooms with matching names
|
|
131
|
+
* @returns
|
|
132
|
+
*/
|
|
133
|
+
async listRooms(names?: string[]): Promise<Room[]> {
|
|
134
|
+
const data = await this.rpc.request(
|
|
135
|
+
svc,
|
|
136
|
+
'ListRooms',
|
|
137
|
+
new ListRoomsRequest({ names: names ?? [] }).toJson(),
|
|
138
|
+
await this.authHeader({ roomList: true }),
|
|
139
|
+
);
|
|
140
|
+
const res = ListRoomsResponse.fromJson(data, { ignoreUnknownFields: true });
|
|
141
|
+
return res.rooms ?? [];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async deleteRoom(room: string): Promise<void> {
|
|
145
|
+
await this.rpc.request(
|
|
146
|
+
svc,
|
|
147
|
+
'DeleteRoom',
|
|
148
|
+
new DeleteRoomRequest({ room }).toJson(),
|
|
149
|
+
await this.authHeader({ roomCreate: true }),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Update metadata of a room
|
|
155
|
+
* @param room name of the room
|
|
156
|
+
* @param metadata the new metadata for the room
|
|
157
|
+
*/
|
|
158
|
+
async updateRoomMetadata(room: string, metadata: string) {
|
|
159
|
+
const data = await this.rpc.request(
|
|
160
|
+
svc,
|
|
161
|
+
'UpdateRoomMetadata',
|
|
162
|
+
new UpdateRoomMetadataRequest({ room, metadata }).toJson(),
|
|
163
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
164
|
+
);
|
|
165
|
+
return Room.fromJson(data, { ignoreUnknownFields: true });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* List participants in a room
|
|
170
|
+
* @param room name of the room
|
|
171
|
+
*/
|
|
172
|
+
async listParticipants(room: string): Promise<ParticipantInfo[]> {
|
|
173
|
+
const data = await this.rpc.request(
|
|
174
|
+
svc,
|
|
175
|
+
'ListParticipants',
|
|
176
|
+
new ListParticipantsRequest({ room }).toJson(),
|
|
177
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
178
|
+
);
|
|
179
|
+
const res = ListParticipantsResponse.fromJson(data, { ignoreUnknownFields: true });
|
|
180
|
+
return res.participants ?? [];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get information on a specific participant, including the tracks that participant
|
|
185
|
+
* has published
|
|
186
|
+
* @param room name of the room
|
|
187
|
+
* @param identity identity of the participant to return
|
|
188
|
+
*/
|
|
189
|
+
async getParticipant(room: string, identity: string): Promise<ParticipantInfo> {
|
|
190
|
+
const data = await this.rpc.request(
|
|
191
|
+
svc,
|
|
192
|
+
'GetParticipant',
|
|
193
|
+
new RoomParticipantIdentity({ room, identity }).toJson(),
|
|
194
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
return ParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Removes a participant in the room. This will disconnect the participant
|
|
202
|
+
* and will emit a Disconnected event for that participant.
|
|
203
|
+
* Even after being removed, the participant can still re-join the room.
|
|
204
|
+
* @param room
|
|
205
|
+
* @param identity
|
|
206
|
+
*/
|
|
207
|
+
async removeParticipant(room: string, identity: string): Promise<void> {
|
|
208
|
+
await this.rpc.request(
|
|
209
|
+
svc,
|
|
210
|
+
'RemoveParticipant',
|
|
211
|
+
new RoomParticipantIdentity({ room, identity }).toJson(),
|
|
212
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Mutes a track that the participant has published.
|
|
218
|
+
* @param room
|
|
219
|
+
* @param identity
|
|
220
|
+
* @param trackSid sid of the track to be muted
|
|
221
|
+
* @param muted true to mute, false to unmute
|
|
222
|
+
*/
|
|
223
|
+
async mutePublishedTrack(
|
|
224
|
+
room: string,
|
|
225
|
+
identity: string,
|
|
226
|
+
trackSid: string,
|
|
227
|
+
muted: boolean,
|
|
228
|
+
): Promise<TrackInfo> {
|
|
229
|
+
const req = new MuteRoomTrackRequest({
|
|
230
|
+
room,
|
|
231
|
+
identity,
|
|
232
|
+
trackSid,
|
|
233
|
+
muted,
|
|
234
|
+
}).toJson();
|
|
235
|
+
const data = await this.rpc.request(
|
|
236
|
+
svc,
|
|
237
|
+
'MutePublishedTrack',
|
|
238
|
+
req,
|
|
239
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
240
|
+
);
|
|
241
|
+
const res = MuteRoomTrackResponse.fromJson(data, { ignoreUnknownFields: true });
|
|
242
|
+
return res.track!;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Updates a participant's metadata or permissions
|
|
247
|
+
* @param room
|
|
248
|
+
* @param identity
|
|
249
|
+
* @param metadata optional, metadata to update
|
|
250
|
+
* @param permission optional, new permissions to assign to participant
|
|
251
|
+
* @param name optional, new name for participant
|
|
252
|
+
*/
|
|
253
|
+
async updateParticipant(
|
|
254
|
+
room: string,
|
|
255
|
+
identity: string,
|
|
256
|
+
metadata?: string,
|
|
257
|
+
permission?: Partial<ParticipantPermission>,
|
|
258
|
+
name?: string,
|
|
259
|
+
): Promise<ParticipantInfo> {
|
|
260
|
+
const req = new UpdateParticipantRequest({
|
|
261
|
+
room,
|
|
262
|
+
identity,
|
|
263
|
+
metadata: metadata || '',
|
|
264
|
+
name: name || '',
|
|
265
|
+
});
|
|
266
|
+
if (permission) {
|
|
267
|
+
req.permission = new ParticipantPermission(permission);
|
|
268
|
+
}
|
|
269
|
+
const data = await this.rpc.request(
|
|
270
|
+
svc,
|
|
271
|
+
'UpdateParticipant',
|
|
272
|
+
req.toJson(),
|
|
273
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
274
|
+
);
|
|
275
|
+
return ParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Updates a participant's subscription to tracks
|
|
280
|
+
* @param room
|
|
281
|
+
* @param identity
|
|
282
|
+
* @param trackSids
|
|
283
|
+
* @param subscribe true to subscribe, false to unsubscribe
|
|
284
|
+
*/
|
|
285
|
+
async updateSubscriptions(
|
|
286
|
+
room: string,
|
|
287
|
+
identity: string,
|
|
288
|
+
trackSids: string[],
|
|
289
|
+
subscribe: boolean,
|
|
290
|
+
): Promise<void> {
|
|
291
|
+
const req = new UpdateSubscriptionsRequest({
|
|
292
|
+
room,
|
|
293
|
+
identity,
|
|
294
|
+
trackSids,
|
|
295
|
+
subscribe,
|
|
296
|
+
participantTracks: [],
|
|
297
|
+
}).toJson();
|
|
298
|
+
await this.rpc.request(
|
|
299
|
+
svc,
|
|
300
|
+
'UpdateSubscriptions',
|
|
301
|
+
req,
|
|
302
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Sends data message to participants in the room
|
|
308
|
+
* @param room
|
|
309
|
+
* @param data opaque payload to send
|
|
310
|
+
* @param kind delivery reliability
|
|
311
|
+
* @param options optionally specify a topic and destinationSids (when destinationSids is empty, message is sent to everyone)
|
|
312
|
+
*/
|
|
313
|
+
async sendData(
|
|
314
|
+
room: string,
|
|
315
|
+
data: Uint8Array,
|
|
316
|
+
kind: DataPacket_Kind,
|
|
317
|
+
options: SendDataOptions,
|
|
318
|
+
): Promise<void>;
|
|
319
|
+
/**
|
|
320
|
+
* Sends data message to participants in the room
|
|
321
|
+
* @deprecated use sendData(room, data, kind, options) instead
|
|
322
|
+
* @param room
|
|
323
|
+
* @param data opaque payload to send
|
|
324
|
+
* @param kind delivery reliability
|
|
325
|
+
* @param destinationSids optional. when empty, message is sent to everyone
|
|
326
|
+
*/
|
|
327
|
+
async sendData(
|
|
328
|
+
room: string,
|
|
329
|
+
data: Uint8Array,
|
|
330
|
+
kind: DataPacket_Kind,
|
|
331
|
+
destinationSids?: string[],
|
|
332
|
+
): Promise<void>;
|
|
333
|
+
async sendData(
|
|
334
|
+
room: string,
|
|
335
|
+
data: Uint8Array,
|
|
336
|
+
kind: DataPacket_Kind,
|
|
337
|
+
options: SendDataOptions | string[] = {},
|
|
338
|
+
): Promise<void> {
|
|
339
|
+
const destinationSids = Array.isArray(options) ? options : options.destinationSids;
|
|
340
|
+
const topic = Array.isArray(options) ? undefined : options.topic;
|
|
341
|
+
const req = new SendDataRequest({
|
|
342
|
+
room,
|
|
343
|
+
data,
|
|
344
|
+
kind,
|
|
345
|
+
destinationSids: destinationSids ?? [],
|
|
346
|
+
topic,
|
|
347
|
+
});
|
|
348
|
+
if (!Array.isArray(options) && options.destinationIdentities) {
|
|
349
|
+
req.destinationIdentities = options.destinationIdentities;
|
|
350
|
+
}
|
|
351
|
+
await this.rpc.request(
|
|
352
|
+
svc,
|
|
353
|
+
'SendData',
|
|
354
|
+
req.toJson(),
|
|
355
|
+
await this.authHeader({ roomAdmin: true, room }),
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import { AccessToken } from './AccessToken.js';
|
|
5
|
+
import { VideoGrant } from './grants.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Utilities to handle authentication
|
|
9
|
+
*/
|
|
10
|
+
export default class ServiceBase {
|
|
11
|
+
private readonly apiKey?: string;
|
|
12
|
+
|
|
13
|
+
private readonly secret?: string;
|
|
14
|
+
|
|
15
|
+
private readonly ttl: string;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param apiKey API Key.
|
|
19
|
+
* @param secret API Secret.
|
|
20
|
+
* @param ttl token TTL
|
|
21
|
+
*/
|
|
22
|
+
constructor(apiKey?: string, secret?: string, ttl?: string) {
|
|
23
|
+
this.apiKey = apiKey;
|
|
24
|
+
this.secret = secret;
|
|
25
|
+
this.ttl = ttl || '10m';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async authHeader(grant: VideoGrant): Promise<any> {
|
|
29
|
+
const at = new AccessToken(this.apiKey, this.secret, { ttl: this.ttl });
|
|
30
|
+
at.addGrant(grant);
|
|
31
|
+
return {
|
|
32
|
+
Authorization: `Bearer ${await at.toJwt()}`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|