@appsocom/client 0.0.0-stage → 0.5.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 +29 -2
- package/dist/adaptive.d.ts +246 -0
- package/dist/adaptive.js +389 -0
- package/dist/adaptive.js.map +1 -0
- package/dist/captions.d.ts +18 -0
- package/dist/captions.js +190 -0
- package/dist/captions.js.map +1 -0
- package/dist/e2ee.d.ts +71 -0
- package/dist/e2ee.js +268 -0
- package/dist/e2ee.js.map +1 -0
- package/dist/effects.d.ts +84 -0
- package/dist/effects.js +417 -0
- package/dist/effects.js.map +1 -0
- package/dist/emitter.d.ts +9 -0
- package/dist/emitter.js +35 -0
- package/dist/emitter.js.map +1 -0
- package/dist/index.d.ts +632 -0
- package/dist/index.js +2289 -0
- package/dist/index.js.map +1 -0
- package/dist/preflight.d.ts +67 -0
- package/dist/preflight.js +365 -0
- package/dist/preflight.js.map +1 -0
- package/dist/speaker.d.ts +62 -0
- package/dist/speaker.js +89 -0
- package/dist/speaker.js.map +1 -0
- package/package.json +64 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
import "webrtc-adapter";
|
|
2
|
+
import { PartyTracks, getCamera, getMic, getScreenshare } from "partytracks/client";
|
|
3
|
+
import { type AttendanceReport, type ChatMessage, type Device, type RoomState, type JoinClaims, type Participant, type ParticipantState, type Permissions, type RecordingStatus, type SharedFile, type Poll, type PollInput, type Question, type CaptionsState, type CaptionTranslation, type TranscriptLine, type CallSummary, type TrackKind, type TrackPermissions, type VideoQuality, type ConnectionQuality, type TranscriptSegment, type AgentState, type LessonAlert, type LessonControl, type LessonState, type AiControl, type AiFlag, type AiMinutes, type DataSaverInput, type DataSaverMode, type DataSaverSettings } from "@appsocom/protocol";
|
|
4
|
+
import { Emitter } from "./emitter.js";
|
|
5
|
+
export { SPEAKER, SpeakerTracker, VoiceActivity } from "./speaker.js";
|
|
6
|
+
import { type DataUsage, type LinkSample } from "./adaptive.js";
|
|
7
|
+
export { qualityForHeight, nextAdaptiveState, initialAdaptiveState, ADAPTIVE, connectionQualityFromSample, FALLBACK, nextFallbackState, initialFallbackState, cameraEncodings, videoAllowList, nextUsage, initialUsageMeter, bytesFromStats, } from "./adaptive.js";
|
|
8
|
+
export type { LinkSample, AdaptiveState, FallbackState, DataUsage, UsageMeter, ByteTotals } from "./adaptive.js";
|
|
9
|
+
export { DATA_SAVER_PRESETS, DATA_SAVER_MODES, resolveDataSaver, estimateDataUsage, pickLayer, TYPICAL_BITRATES } from "@appsocom/protocol";
|
|
10
|
+
import { type E2EEKey, type E2EEOptions, type EncryptionErrorType } from "./e2ee.js";
|
|
11
|
+
export { isE2EESupported, deriveE2EEKeys, createE2EEWorker, e2eeWorkerSource, type E2EEKey, type E2EEOptions, type EncryptionErrorType, } from "./e2ee.js";
|
|
12
|
+
import { type BackgroundEffectOptions, type NoiseSuppressionOptions } from "./effects.js";
|
|
13
|
+
export * from "./effects.js";
|
|
14
|
+
export type * from "@appsocom/protocol";
|
|
15
|
+
export { CloseCodes, attendanceToCsv } from "@appsocom/protocol";
|
|
16
|
+
export { runPreflight, type PreflightOptions, type PreflightReport, type PreflightStep, type Verdict } from "./preflight.js";
|
|
17
|
+
export declare const TOKEN_HEADER = "X-SfuKit-Token";
|
|
18
|
+
/** Options for `room.send()`. */
|
|
19
|
+
export interface SendOptions {
|
|
20
|
+
/** Only these userIds get it (up to 100). Default: everyone else in your group. */
|
|
21
|
+
to?: string[];
|
|
22
|
+
/** A label passed through to receivers, up to 64 characters (e.g. "whiteboard"). */
|
|
23
|
+
topic?: string;
|
|
24
|
+
}
|
|
25
|
+
/** What came with a received app message. */
|
|
26
|
+
export interface MessageInfo {
|
|
27
|
+
topic: string | null;
|
|
28
|
+
/** Sent only to some people (with `to`), not the whole room. */
|
|
29
|
+
private: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface JoinOptions {
|
|
32
|
+
/**
|
|
33
|
+
* Where the kit's Worker routes live, e.g. "https://video.client.com"
|
|
34
|
+
* or "https://api.client.com/video" if mounted under a path.
|
|
35
|
+
*/
|
|
36
|
+
url: string;
|
|
37
|
+
/** Join token from your backend (POST /tokens). */
|
|
38
|
+
token: string;
|
|
39
|
+
/** Start with the mic broadcasting. Default true. */
|
|
40
|
+
audio?: boolean;
|
|
41
|
+
/** Start with the camera broadcasting. Default true (false when mode is "audio"). */
|
|
42
|
+
video?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* "video" (default): normal video call.
|
|
45
|
+
* "audio": voice call. The camera is never opened (no camera permission prompt)
|
|
46
|
+
* and nobody's camera video is received; screen shares still work.
|
|
47
|
+
*/
|
|
48
|
+
mode?: "video" | "audio";
|
|
49
|
+
/** Play remote audio automatically through hidden <audio> elements. Default true. */
|
|
50
|
+
autoPlayAudio?: boolean;
|
|
51
|
+
/** Reconnect after network drops (Wi-Fi ↔ mobile data, sleep, blips). Default true. */
|
|
52
|
+
reconnect?: boolean;
|
|
53
|
+
/** Give up reconnecting after this long without a connection, in ms. Default 120000. */
|
|
54
|
+
reconnectTimeoutMs?: number;
|
|
55
|
+
/** Override ICE servers. By default they come from the kit (TURN if configured). */
|
|
56
|
+
iceServers?: RTCIceServer[];
|
|
57
|
+
/** Give up joining after this many ms. Default 15000. Paused while you're in a waiting room. */
|
|
58
|
+
joinTimeoutMs?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Send the camera in three sizes (720p / 360p / 180p) so each viewer gets the
|
|
61
|
+
* size it needs and the SFU can step down on weak links. Default true.
|
|
62
|
+
*/
|
|
63
|
+
simulcast?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Adapt to the connection: lower received video quality, then pause received
|
|
66
|
+
* video, and pause sending your own video when upload bandwidth collapses.
|
|
67
|
+
* Audio is never paused. Default true.
|
|
68
|
+
*/
|
|
69
|
+
adaptive?: boolean;
|
|
70
|
+
/** How often to sample WebRTC stats, in ms. Default 2000. */
|
|
71
|
+
statsIntervalMs?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Audio-first fallback: when the connection stays very bad even after the
|
|
74
|
+
* adaptive steps (heavy loss, very slow round trips, almost no upload), stop
|
|
75
|
+
* all camera video both ways and keep audio; video comes back by itself after
|
|
76
|
+
* a long good stretch. Fires "audio-fallback". Default true (false when
|
|
77
|
+
* `adaptive` is false). `{ keepScreenShare: true }` keeps receiving screen shares.
|
|
78
|
+
*/
|
|
79
|
+
audioFallback?: boolean | {
|
|
80
|
+
keepScreenShare?: boolean;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Data saver for costly or weak mobile data: "low", "minimal", "audio", or
|
|
84
|
+
* custom settings (see DATA_SAVER_PRESETS). Default: the join token's
|
|
85
|
+
* `dataSaver`, else "off". Change it any time with room.setDataSaver().
|
|
86
|
+
*/
|
|
87
|
+
dataSaver?: DataSaverInput;
|
|
88
|
+
/**
|
|
89
|
+
* Receive other people's tracks automatically. Default true. Set
|
|
90
|
+
* `{ video: false }` to pull no camera/screen video until you call
|
|
91
|
+
* room.setSubscribed() or room.observeVisibility() (large rooms, galleries).
|
|
92
|
+
*/
|
|
93
|
+
autoSubscribe?: boolean | {
|
|
94
|
+
audio?: boolean;
|
|
95
|
+
video?: boolean;
|
|
96
|
+
};
|
|
97
|
+
/** Called when you're put in the room's waiting room; joinRoom() resolves once a teacher admits you. */
|
|
98
|
+
onWaiting?: () => void;
|
|
99
|
+
/**
|
|
100
|
+
* End-to-end encryption: a passphrase or random bytes every participant shares,
|
|
101
|
+
* handed out by your app (never through the kit's Worker or the join token).
|
|
102
|
+
* Media frames and room.send() messages are then unreadable to the Worker and the SFU.
|
|
103
|
+
*/
|
|
104
|
+
e2ee?: E2EEOptions;
|
|
105
|
+
/**
|
|
106
|
+
* When a host turns captions on, transcribe your mic (only while it's on and
|
|
107
|
+
* you're speaking). Default true; false = others won't see captions of you.
|
|
108
|
+
*/
|
|
109
|
+
sendCaptions?: boolean;
|
|
110
|
+
/** Start with background blur (true) or replacement ({ backgroundImage }). See room.setBackgroundEffect(). */
|
|
111
|
+
backgroundEffect?: boolean | BackgroundEffectOptions;
|
|
112
|
+
/** Start with RNNoise noise suppression on the mic. See room.setNoiseSuppression(). */
|
|
113
|
+
noiseSuppression?: boolean | NoiseSuppressionOptions;
|
|
114
|
+
}
|
|
115
|
+
export type ConnectionState = "connecting" | "connected" | "reconnecting" | "disconnected";
|
|
116
|
+
export type RoomEvents = {
|
|
117
|
+
"participant-joined": (participant: Participant) => void;
|
|
118
|
+
"participant-updated": (participant: Participant) => void;
|
|
119
|
+
"participant-left": (participant: Participant) => void;
|
|
120
|
+
/** A remote track is ready (or was replaced). Attach it to a <video>/<audio>. */
|
|
121
|
+
track: (participant: Participant, kind: TrackKind, track: MediaStreamTrack) => void;
|
|
122
|
+
/** A remote track went away (e.g. screen share stopped, participant left). */
|
|
123
|
+
"track-removed": (participant: Participant, kind: TrackKind) => void;
|
|
124
|
+
/** Your own camera / screen preview track. */
|
|
125
|
+
"local-track": (kind: "video" | "screenVideo", track: MediaStreamTrack | null) => void;
|
|
126
|
+
/** Your mic/camera/screen state changed. */
|
|
127
|
+
"local-state": (state: ParticipantState) => void;
|
|
128
|
+
/**
|
|
129
|
+
* Your permissions changed during the call (a teacher allowed or stopped
|
|
130
|
+
* your mic/camera/screen). Devices you lost are already turned off.
|
|
131
|
+
*/
|
|
132
|
+
permissions: (permissions: Permissions, previous: Permissions) => void;
|
|
133
|
+
/**
|
|
134
|
+
* Your own participant record changed on the server: metadata or display
|
|
135
|
+
* name set by your app's backend, role, permissions, hand…
|
|
136
|
+
*/
|
|
137
|
+
self: (self: Participant) => void;
|
|
138
|
+
/** Your role changed during the call (e.g. your app's backend promoted you). */
|
|
139
|
+
role: (role: string, previous: string) => void;
|
|
140
|
+
/** A teacher/host (`by`, undefined = your app's backend) turned off these devices of yours. */
|
|
141
|
+
muted: (devices: Device[], by: Participant | undefined) => void;
|
|
142
|
+
/** A chat message arrived (or was part of the history sent when you joined). */
|
|
143
|
+
chat: (message: ChatMessage) => void;
|
|
144
|
+
/** A teacher/host deleted a chat message. */
|
|
145
|
+
"chat-deleted": (id: string) => void;
|
|
146
|
+
/** The raised-hand queue changed: everyone with a hand up (you included), first raised first. */
|
|
147
|
+
hands: (raised: Participant[]) => void;
|
|
148
|
+
/** You're in the waiting room (before joinRoom() resolves; also see JoinOptions.onWaiting). */
|
|
149
|
+
waiting: () => void;
|
|
150
|
+
/**
|
|
151
|
+
* You were moved to a breakout group (null = main room). `participants`
|
|
152
|
+
* already holds the people you see now; the usual join/leave events fired.
|
|
153
|
+
*/
|
|
154
|
+
"group-changed": (group: string | null) => void;
|
|
155
|
+
/** Teachers/hosts: the waiting room changed. */
|
|
156
|
+
"waiting-list": (waiting: Participant[]) => void;
|
|
157
|
+
/** Room-wide settings changed (e.g. a teacher locked the room). */
|
|
158
|
+
"room-state": (state: RoomState) => void;
|
|
159
|
+
/**
|
|
160
|
+
* The room started (status) or stopped (null) recording. Show an indicator
|
|
161
|
+
* while it's set: participants should know they're being recorded.
|
|
162
|
+
*/
|
|
163
|
+
recording: (recording: RecordingStatus | null) => void;
|
|
164
|
+
/** Someone reacted with an emoji. `from` is null for your own reactions. */
|
|
165
|
+
reaction: (emoji: string, from: Participant | null, at: number) => void;
|
|
166
|
+
/** A file was shared (also fired for each file already shared when you join). */
|
|
167
|
+
"file-shared": (file: SharedFile) => void;
|
|
168
|
+
"file-removed": (fileId: string) => void;
|
|
169
|
+
/** A poll started, got votes, closed (or you just joined and it exists). */
|
|
170
|
+
poll: (poll: Poll) => void;
|
|
171
|
+
"poll-removed": (pollId: string) => void;
|
|
172
|
+
/** A question was asked, upvoted or answered. */
|
|
173
|
+
question: (question: Question) => void;
|
|
174
|
+
"question-removed": (questionId: string) => void;
|
|
175
|
+
/** Captions turned on/off (or settings changed). */
|
|
176
|
+
captions: (state: CaptionsState) => void;
|
|
177
|
+
/** A new caption line from someone (you included), translated if you asked with setCaptionLanguage(). */
|
|
178
|
+
caption: (line: TranscriptLine, translation?: CaptionTranslation) => void;
|
|
179
|
+
/** A host or your backend summarized the call. */
|
|
180
|
+
summary: (summary: CallSummary) => void;
|
|
181
|
+
/** App-level message sent by another participant with room.send(). */
|
|
182
|
+
/** `info.topic` is the sender's topic (or null); `info.private` is true when it was sent only to some people. */
|
|
183
|
+
message: (data: unknown, from: Participant | undefined, info: MessageInfo) => void;
|
|
184
|
+
/**
|
|
185
|
+
* Overall call state. "reconnecting" covers both the room connection and the
|
|
186
|
+
* media connection dropping; it goes back to "connected" once both are back.
|
|
187
|
+
*/
|
|
188
|
+
connection: (state: ConnectionState) => void;
|
|
189
|
+
/** Your join token expires in about a minute: get a new one and call room.updateToken(). */
|
|
190
|
+
"token-expiring": (expiresAt: number) => void;
|
|
191
|
+
/** Media (WebRTC) connection state. */
|
|
192
|
+
"media-connection": (state: RTCPeerConnectionState) => void;
|
|
193
|
+
/** Background effect / noise suppression switched on or off. */
|
|
194
|
+
effects: (effects: {
|
|
195
|
+
background: BackgroundEffectOptions | null;
|
|
196
|
+
noiseSuppression: boolean;
|
|
197
|
+
}) => void;
|
|
198
|
+
error: (error: Error) => void;
|
|
199
|
+
/**
|
|
200
|
+
* End-to-end encryption problem: a frame or message couldn't be decrypted
|
|
201
|
+
* (wrong or missing key, or a sender that doesn't encrypt). Throttled.
|
|
202
|
+
*/
|
|
203
|
+
"encryption-error": (type: EncryptionErrorType, detail: string) => void;
|
|
204
|
+
/** You left, were removed, or the room closed. The Room can't be reused. */
|
|
205
|
+
left: (reason: string) => void;
|
|
206
|
+
/**
|
|
207
|
+
* Video was paused or resumed to save bandwidth. `participant` is whose video
|
|
208
|
+
* you stopped/started receiving, or null for your own outgoing camera.
|
|
209
|
+
*/
|
|
210
|
+
"video-paused": (participant: Participant | null, paused: boolean) => void;
|
|
211
|
+
/**
|
|
212
|
+
* Someone's connection rating changed. `participantId` is `room.self.id` for
|
|
213
|
+
* your own. Ratings come from each participant's own WebRTC stats.
|
|
214
|
+
*/
|
|
215
|
+
"connection-quality": (participantId: string, quality: ConnectionQuality) => void;
|
|
216
|
+
/** Who is talking right now, loudest first (participant ids; includes room.self.id). */
|
|
217
|
+
"active-speakers": (participantIds: string[]) => void;
|
|
218
|
+
/** The quality of video you receive from a participant changed (high/medium/low/off). */
|
|
219
|
+
"video-quality": (participant: Participant, quality: VideoQuality) => void;
|
|
220
|
+
/**
|
|
221
|
+
* Your connection fell back to audio only (true) or recovered (false). While
|
|
222
|
+
* it's on, no camera video is sent or received; tell the user why.
|
|
223
|
+
*/
|
|
224
|
+
"audio-fallback": (active: boolean) => void;
|
|
225
|
+
/** The data-saver mode changed (room.setDataSaver()). */
|
|
226
|
+
"data-saver": (mode: DataSaverMode | "custom", settings: DataSaverSettings) => void;
|
|
227
|
+
/** Media data used so far in this call; fires every statsIntervalMs. */
|
|
228
|
+
"data-usage": (usage: DataUsage) => void;
|
|
229
|
+
/** An AI agent changed state: initializing, listening, thinking or speaking. */
|
|
230
|
+
"agent-state": (agent: Participant, state: AgentState) => void;
|
|
231
|
+
/**
|
|
232
|
+
* Live transcript of a conversation with an AI agent. Partial segments are
|
|
233
|
+
* re-sent with the same segment.id as words arrive; replace, don't append.
|
|
234
|
+
*/
|
|
235
|
+
transcript: (segment: TranscriptSegment) => void;
|
|
236
|
+
/** An AI lesson started or changed: slide, whiteboard, who has the floor, quiz, timer, status. */
|
|
237
|
+
lesson: (lesson: LessonState) => void;
|
|
238
|
+
/** An AI lesson ended. */
|
|
239
|
+
"lesson-ended": (lessonId: string) => void;
|
|
240
|
+
/** Moderators only: the AI teacher raised a safeguarding or help alert. */
|
|
241
|
+
"lesson-alert": (lessonId: string, alert: LessonAlert) => void;
|
|
242
|
+
/** An AI participant flagged a point (hosts; everyone when its flags go to the room). */
|
|
243
|
+
"ai-flag": (agentId: string, flag: AiFlag) => void;
|
|
244
|
+
/** Hosts: an AI participant's minutes so far (after a "minutes" control, and when it leaves). */
|
|
245
|
+
"ai-minutes": (agentId: string, minutes: AiMinutes) => void;
|
|
246
|
+
};
|
|
247
|
+
/** Join a room. Resolves once you're in, rejects if the token is bad, the room is full, etc. */
|
|
248
|
+
export declare function joinRoom(options: JoinOptions): Promise<Room>;
|
|
249
|
+
export declare class Room extends Emitter<RoomEvents> {
|
|
250
|
+
#private;
|
|
251
|
+
readonly roomId: string;
|
|
252
|
+
readonly userId: string;
|
|
253
|
+
/** Your role: "teacher", "student", "observer", or your app's own label. */
|
|
254
|
+
/** Updated when your app's backend changes it during the call. */
|
|
255
|
+
role: string;
|
|
256
|
+
/** What you may do right now. Updated when a teacher/host changes it. */
|
|
257
|
+
permissions: Permissions;
|
|
258
|
+
/** Room-wide settings (locked, …). */
|
|
259
|
+
roomState: RoomState;
|
|
260
|
+
/** Teachers/hosts: who is in the waiting room now, first come first. */
|
|
261
|
+
waiting: Participant[];
|
|
262
|
+
/** Room metadata set by your app's backend (same as roomState.metadata). */
|
|
263
|
+
get metadata(): Record<string, unknown> | undefined;
|
|
264
|
+
/** Chat messages you've seen (public history + live, private ones to/from you), oldest first. Last 200. */
|
|
265
|
+
chat: ChatMessage[];
|
|
266
|
+
/** True if you may publish anything at all right now. */
|
|
267
|
+
get canPublish(): boolean;
|
|
268
|
+
/** Your own participant record (id changes after a reconnect). */
|
|
269
|
+
self: Participant | null;
|
|
270
|
+
/** The recording in progress, or null. See the "recording" event. */
|
|
271
|
+
recording: RecordingStatus | null;
|
|
272
|
+
connectionState: ConnectionState;
|
|
273
|
+
/** Raw partytracks objects for advanced use (device lists, transforms…). */
|
|
274
|
+
readonly media: {
|
|
275
|
+
partyTracks: PartyTracks;
|
|
276
|
+
mic: ReturnType<typeof getMic> | null;
|
|
277
|
+
camera: ReturnType<typeof getCamera> | null;
|
|
278
|
+
screen: ReturnType<typeof getScreenshare> | null;
|
|
279
|
+
};
|
|
280
|
+
/** @internal use joinRoom() */
|
|
281
|
+
constructor(options: JoinOptions);
|
|
282
|
+
/** All other participants currently in the room. */
|
|
283
|
+
get participants(): Participant[];
|
|
284
|
+
/** Current remote track for a participant, if any. */
|
|
285
|
+
getTrack(participantId: string, kind: TrackKind): MediaStreamTrack | undefined;
|
|
286
|
+
get localState(): ParticipantState;
|
|
287
|
+
toggleMic(): void;
|
|
288
|
+
setMic(on: boolean): void;
|
|
289
|
+
toggleCamera(): void;
|
|
290
|
+
setCamera(on: boolean): void;
|
|
291
|
+
/** Must be called from a click/tap handler (browser rule for screen capture). */
|
|
292
|
+
toggleScreenShare(): void;
|
|
293
|
+
/** Pick a specific mic/camera, e.g. from navigator.mediaDevices.enumerateDevices(). */
|
|
294
|
+
setMicDevice(device: MediaDeviceInfo): void;
|
|
295
|
+
setCameraDevice(device: MediaDeviceInfo): void;
|
|
296
|
+
/**
|
|
297
|
+
* Start the camera or mic again from scratch and turn it on. Use it for a
|
|
298
|
+
* "Try again" button after an "error" saying the device could not start
|
|
299
|
+
* (blocked, busy in another app, or stuck). Call it from a click/tap so the
|
|
300
|
+
* browser can ask for permission again.
|
|
301
|
+
*/
|
|
302
|
+
restartDevice(kind: "mic" | "camera"): void;
|
|
303
|
+
/** Your own camera / screen preview track right now (also sent as "local-track" events). */
|
|
304
|
+
getLocalTrack(kind: "video" | "screenVideo"): MediaStreamTrack | null;
|
|
305
|
+
/** Play remote audio through this output device (speakers/headset). Not supported in every browser. */
|
|
306
|
+
setAudioOutputDevice(deviceId: string): void;
|
|
307
|
+
get audioOutputDevice(): string | null;
|
|
308
|
+
/** Current background effect (null = off). */
|
|
309
|
+
get backgroundEffect(): BackgroundEffectOptions | null;
|
|
310
|
+
/** True while RNNoise noise suppression is on. */
|
|
311
|
+
get noiseSuppression(): boolean;
|
|
312
|
+
/**
|
|
313
|
+
* Blur your background (true / { blurRadius }), replace it
|
|
314
|
+
* ({ backgroundImage: url }), or switch the effect off (false).
|
|
315
|
+
* Runs on-device with MediaPipe; loaded on first use.
|
|
316
|
+
*/
|
|
317
|
+
setBackgroundEffect(effect: boolean | BackgroundEffectOptions): void;
|
|
318
|
+
/** Shorthand: setBackgroundEffect(on ? { blurRadius } : false). */
|
|
319
|
+
setBackgroundBlur(on: boolean, blurRadius?: number): void;
|
|
320
|
+
/** Switch RNNoise noise suppression on the mic on or off. */
|
|
321
|
+
setNoiseSuppression(on: boolean | NoiseSuppressionOptions): void;
|
|
322
|
+
/** Small app-defined state shared with everyone (hand raised, etc.). Max ~4KB. */
|
|
323
|
+
setCustomState(custom: Record<string, unknown>): void;
|
|
324
|
+
/**
|
|
325
|
+
* Teachers/hosts (permissions.moderate): allow or stop a user's mic, camera
|
|
326
|
+
* or screen share, e.g. { screen: true } to let a student present.
|
|
327
|
+
* Applies to all their connections and lasts until the room empties.
|
|
328
|
+
*/
|
|
329
|
+
setPermissions(userId: string, permissions: Partial<Omit<Permissions, "moderate">>): void;
|
|
330
|
+
/**
|
|
331
|
+
* Teachers/hosts: turn off a user's devices (default: mic). They can turn
|
|
332
|
+
* them back on, unless `lock` is true (that also takes the permission away;
|
|
333
|
+
* give it back with setPermissions).
|
|
334
|
+
*/
|
|
335
|
+
mute(userId: string, devices?: Device[], options?: {
|
|
336
|
+
lock?: boolean;
|
|
337
|
+
}): void;
|
|
338
|
+
/** Teachers/hosts: mute everyone who isn't a teacher/host (default: mics). */
|
|
339
|
+
muteAll(devices?: Device[], options?: {
|
|
340
|
+
lock?: boolean;
|
|
341
|
+
}): void;
|
|
342
|
+
/** Teachers/hosts: stop someone's screen share. */
|
|
343
|
+
stopScreenShare(userId: string): void;
|
|
344
|
+
/** Teachers/hosts: remove a user. `ban` keeps them out until the room empties. */
|
|
345
|
+
remove(userId: string, options?: {
|
|
346
|
+
ban?: boolean;
|
|
347
|
+
}): void;
|
|
348
|
+
/** Raise your hand. Raising it again keeps your place in the queue. */
|
|
349
|
+
raiseHand(): void;
|
|
350
|
+
/** Lower your own hand, or (teachers/hosts) someone else's. */
|
|
351
|
+
lowerHand(userId?: string): void;
|
|
352
|
+
/** Teachers/hosts: lower every raised hand. */
|
|
353
|
+
lowerAllHands(): void;
|
|
354
|
+
/** Everyone with a hand up (you included), first raised first. */
|
|
355
|
+
get raisedHands(): Participant[];
|
|
356
|
+
/**
|
|
357
|
+
* Send a chat message to everyone, or privately with { to: userId }.
|
|
358
|
+
* Students can only message teachers/hosts privately, and can't chat while a
|
|
359
|
+
* teacher has turned chat off (you get an `error` event).
|
|
360
|
+
*/
|
|
361
|
+
sendChat(text: string, options?: {
|
|
362
|
+
to?: string;
|
|
363
|
+
everywhere?: boolean;
|
|
364
|
+
}): void;
|
|
365
|
+
/** Teachers/hosts: delete a chat message for everyone. */
|
|
366
|
+
deleteChat(id: string): void;
|
|
367
|
+
/** Teachers/hosts: turn chat on/off for everyone who isn't a teacher/host. */
|
|
368
|
+
setChatEnabled(enabled: boolean): void;
|
|
369
|
+
/**
|
|
370
|
+
* Teachers/hosts: put users in the spotlight for everyone (up to 6, in
|
|
371
|
+
* order; [] clears). Read it from room.roomState.spotlight / "room-state".
|
|
372
|
+
*/
|
|
373
|
+
setSpotlight(userIds: string[]): void;
|
|
374
|
+
/**
|
|
375
|
+
* Teachers/hosts: start breakout rooms. Each group lists userIds; anyone not
|
|
376
|
+
* listed stays in the main room. Groups get ids "g1", "g2", … (room.roomState.breakouts).
|
|
377
|
+
*/
|
|
378
|
+
startBreakouts(groups: {
|
|
379
|
+
name: string;
|
|
380
|
+
userIds: string[];
|
|
381
|
+
}[]): void;
|
|
382
|
+
/** Teachers/hosts: move someone to a group id (null = main room). */
|
|
383
|
+
moveToGroup(userId: string, group: string | null): void;
|
|
384
|
+
/** Teachers/hosts: join a breakout group yourself (null = back to the main room). */
|
|
385
|
+
visitGroup(group: string | null): void;
|
|
386
|
+
/** Teachers/hosts: end breakouts; everyone returns to the main room. */
|
|
387
|
+
endBreakouts(): void;
|
|
388
|
+
/** Your breakout group id, or null in the main room. */
|
|
389
|
+
get group(): string | null;
|
|
390
|
+
/** Teachers/hosts: turn the waiting room on/off (off admits everyone waiting). */
|
|
391
|
+
setWaitingRoom(on: boolean): void;
|
|
392
|
+
/** Teachers/hosts: let someone in from the waiting room ("*" = everyone). */
|
|
393
|
+
admit(userId: string): void;
|
|
394
|
+
/** Teachers/hosts: turn someone in the waiting room away. */
|
|
395
|
+
deny(userId: string): void;
|
|
396
|
+
/**
|
|
397
|
+
* Teachers/hosts: who attended and for how long (this room, last 30 days).
|
|
398
|
+
* Turn it into a spreadsheet with attendanceToCsv(report).
|
|
399
|
+
*/
|
|
400
|
+
fetchAttendance(timeoutMs?: number): Promise<AttendanceReport>;
|
|
401
|
+
/** Teachers/hosts: while locked, only teachers/hosts can join. */
|
|
402
|
+
lockRoom(locked?: boolean): void;
|
|
403
|
+
/**
|
|
404
|
+
* Teachers/hosts (permissions.moderate): start recording the room to R2.
|
|
405
|
+
* Audio only by default; { video: true } records everything with the
|
|
406
|
+
* recorder bot (the kit must be deployed with it).
|
|
407
|
+
*/
|
|
408
|
+
startRecording(options?: {
|
|
409
|
+
video?: boolean;
|
|
410
|
+
}): void;
|
|
411
|
+
/** Teachers/hosts (permissions.moderate): stop the recording. */
|
|
412
|
+
stopRecording(): void;
|
|
413
|
+
/**
|
|
414
|
+
* Start or stop receiving some of a participant's tracks, e.g. stop their
|
|
415
|
+
* video while their tile is off screen. Stopping really stops the media
|
|
416
|
+
* (no bandwidth used); starting again pulls it fresh.
|
|
417
|
+
*/
|
|
418
|
+
setSubscribed(participantId: string, kinds: TrackKind | TrackKind[], on: boolean): void;
|
|
419
|
+
/** Whether you're set to receive this participant's track kind (if they publish it and you're allowed). */
|
|
420
|
+
isSubscribed(participantId: string, kind: TrackKind): boolean;
|
|
421
|
+
/**
|
|
422
|
+
* Receive a participant's video only while `el` (their tile) is on screen
|
|
423
|
+
* and the tab is visible. Video stops 1s after the tile leaves the screen
|
|
424
|
+
* (`hideDelayMs`) and comes back when it returns. Returns a function that
|
|
425
|
+
* stops watching (and leaves video on).
|
|
426
|
+
*/
|
|
427
|
+
observeVisibility(el: Element, participantId: string, options?: {
|
|
428
|
+
kinds?: TrackKind[];
|
|
429
|
+
hideDelayMs?: number;
|
|
430
|
+
}): () => void;
|
|
431
|
+
/**
|
|
432
|
+
* Choose who may receive YOUR tracks. Enforced by the server: others only
|
|
433
|
+
* see (and can only pull) what you allow; anyone who loses access stops
|
|
434
|
+
* receiving within seconds. Kept until the room empties.
|
|
435
|
+
*
|
|
436
|
+
* room.setTrackPermissions({ allowAll: true }); // default
|
|
437
|
+
* room.setTrackPermissions({ allowAll: false, allow: [{ userId: "t1" }] });
|
|
438
|
+
* room.setTrackPermissions({ allowAll: false, allow: [{ userId: "t1", kinds: ["screenVideo"] }] });
|
|
439
|
+
*/
|
|
440
|
+
setTrackPermissions(permissions: TrackPermissions): void;
|
|
441
|
+
/** AI agents currently in the room. */
|
|
442
|
+
get agents(): Participant[];
|
|
443
|
+
/** Type to an AI agent instead of speaking; it answers out loud. */
|
|
444
|
+
sendToAgent(agentId: string, text: string): void;
|
|
445
|
+
/** AI lessons running in this room (usually one). */
|
|
446
|
+
get lessons(): LessonState[];
|
|
447
|
+
/** The AI lesson running in this room, if any. */
|
|
448
|
+
get lesson(): LessonState | null;
|
|
449
|
+
/** AI participants in the room (agents with a role: contributor, scribe, co-teacher…). */
|
|
450
|
+
get aiParticipants(): Participant[];
|
|
451
|
+
/**
|
|
452
|
+
* "Ask AI": type a question to an AI participant (the alternative to asking
|
|
453
|
+
* the host or teacher). It answers in the chat, or out loud when its voice is
|
|
454
|
+
* on. `private`: only you see the answer, in chat. Needs the AI's
|
|
455
|
+
* directQuestions on unless you're a host. Saying its name in the call works too.
|
|
456
|
+
*/
|
|
457
|
+
askAI(text: string, options?: {
|
|
458
|
+
agentId?: string;
|
|
459
|
+
private?: boolean;
|
|
460
|
+
}): void;
|
|
461
|
+
/**
|
|
462
|
+
* Hosts: steer an AI participant: { action: "pause" | "resume" | "recap" | "minutes" },
|
|
463
|
+
* { action: "settings", voice, directQuestions, flags, watchPolicy, knowledge },
|
|
464
|
+
* co-teachers { action: "teach", topic | planId } and { action: "stop-teaching" }.
|
|
465
|
+
*/
|
|
466
|
+
controlAI(control: AiControl, agentId?: string | undefined): void;
|
|
467
|
+
/**
|
|
468
|
+
* Keep yourself out of what AI participants hear (true) or let them hear you
|
|
469
|
+
* again (false). Your speech and chat are then never handed to the AI.
|
|
470
|
+
* Shown to everyone as `participant.aiOptOut`.
|
|
471
|
+
*/
|
|
472
|
+
setAiOptOut(optOut: boolean): void;
|
|
473
|
+
/** Type a question to the AI teacher. Raise your hand (raiseHand) to ask out loud instead. */
|
|
474
|
+
askLesson(text: string, lessonId?: string | undefined): void;
|
|
475
|
+
/**
|
|
476
|
+
* Moderators: steer the AI lesson, e.g. { action: "pause" }, { action: "takeover" }
|
|
477
|
+
* (you speak, the AI listens and keeps notes), { action: "handback" },
|
|
478
|
+
* { action: "call-on", userId }, { action: "goto", section: 2 },
|
|
479
|
+
* { action: "scope", scope: "strict" }, { action: "note", text: "slow down" }.
|
|
480
|
+
*/
|
|
481
|
+
controlLesson(control: LessonControl, lessonId?: string | undefined): void;
|
|
482
|
+
/**
|
|
483
|
+
* Send an app-level message to everyone else in the room (chat, reactions…),
|
|
484
|
+
* or with `to` only to those userIds. `topic` travels with it so you can route
|
|
485
|
+
* messages (e.g. "whiteboard").
|
|
486
|
+
* With end-to-end encryption on, it's encrypted first (other participants
|
|
487
|
+
* receive the original `data`; the server sees ciphertext).
|
|
488
|
+
*/
|
|
489
|
+
send(data: unknown, options?: SendOptions): void;
|
|
490
|
+
/** End-to-end encryption status. `keyIndex` is the key you send with (-1 = off). */
|
|
491
|
+
get encryption(): {
|
|
492
|
+
enabled: boolean;
|
|
493
|
+
keyIndex: number;
|
|
494
|
+
};
|
|
495
|
+
/**
|
|
496
|
+
* Add or rotate the end-to-end encryption key. Give every participant the new
|
|
497
|
+
* key with a new index (0-255). With `use: false` it's only added for
|
|
498
|
+
* receiving, so you can hand it out first and switch everyone over after.
|
|
499
|
+
* The last 16 keys are kept for decrypting.
|
|
500
|
+
*/
|
|
501
|
+
setEncryptionKey(key: E2EEKey, index: number, options?: {
|
|
502
|
+
use?: boolean;
|
|
503
|
+
}): Promise<void>;
|
|
504
|
+
/** Send an emoji reaction to everyone (e.g. "👍"). Max ~10 per 5 seconds. */
|
|
505
|
+
react(emoji: string): void;
|
|
506
|
+
/** Files shared in this room, oldest first. They're deleted when the room empties. */
|
|
507
|
+
get files(): SharedFile[];
|
|
508
|
+
/**
|
|
509
|
+
* Share a file with everyone in the room (needs the Worker's STORAGE bucket).
|
|
510
|
+
* Observers can't share. Max size is the Worker's MAX_FILE_MB (default 25).
|
|
511
|
+
*/
|
|
512
|
+
shareFile(file: Blob, name?: string): Promise<SharedFile>;
|
|
513
|
+
/** Download a shared file's bytes. */
|
|
514
|
+
downloadFile(fileId: string): Promise<Blob>;
|
|
515
|
+
/**
|
|
516
|
+
* A link that downloads the file (carries your join token, so don't share it
|
|
517
|
+
* outside the room). `inline` shows PNG/JPEG/GIF/WebP images instead.
|
|
518
|
+
*/
|
|
519
|
+
fileUrl(fileId: string, inline?: boolean): string;
|
|
520
|
+
/** Remove a file you shared (moderators can remove anyone's). */
|
|
521
|
+
deleteFile(fileId: string): Promise<void>;
|
|
522
|
+
/** True if you may run polls and moderate Q&A (moderators, or everyone in rooms without roles). */
|
|
523
|
+
get isHost(): boolean;
|
|
524
|
+
/** Polls in this room, oldest first. `counts` is empty while results are hidden from you. */
|
|
525
|
+
get polls(): Poll[];
|
|
526
|
+
/** Your vote in a poll (option indexes), if you voted. */
|
|
527
|
+
myVote(pollId: string): number[] | undefined;
|
|
528
|
+
/** Hosts: start a poll. */
|
|
529
|
+
createPoll(poll: PollInput): void;
|
|
530
|
+
/** Vote, or change your vote. One option index unless the poll allows multiple. */
|
|
531
|
+
vote(pollId: string, choices: number | number[]): void;
|
|
532
|
+
closePoll(pollId: string): void;
|
|
533
|
+
deletePoll(pollId: string): void;
|
|
534
|
+
/** Q&A questions, oldest first. Sort by `upvotes` for a "top questions" view. */
|
|
535
|
+
get questions(): Question[];
|
|
536
|
+
/** Did you upvote this question? */
|
|
537
|
+
hasUpvoted(questionId: string): boolean;
|
|
538
|
+
/** `anonymous` hides your name from everyone except hosts. Max 500 characters, 5 a minute. */
|
|
539
|
+
askQuestion(text: string, anonymous?: boolean): void;
|
|
540
|
+
upvoteQuestion(questionId: string, up?: boolean): void;
|
|
541
|
+
/** Hosts. */
|
|
542
|
+
markAnswered(questionId: string, answered?: boolean): void;
|
|
543
|
+
/** Hosts, or your own question. */
|
|
544
|
+
deleteQuestion(questionId: string): void;
|
|
545
|
+
/** Are captions on in this room, and with what settings. */
|
|
546
|
+
get captions(): CaptionsState;
|
|
547
|
+
/** Recent caption lines (the last 200 you've seen). Hosts can fetch the full transcript. */
|
|
548
|
+
get recentCaptions(): TranscriptLine[];
|
|
549
|
+
/** The latest AI summary of this call, if a host made one. */
|
|
550
|
+
get summary(): CallSummary | undefined;
|
|
551
|
+
/**
|
|
552
|
+
* Hosts: turn live captions on/off (needs Workers AI on the Worker).
|
|
553
|
+
* `language` ("en", "fr", …) improves accuracy; `translate` gives English captions for any language.
|
|
554
|
+
* `server`: transcribe every mic on the server (participants on any SDK get captioned, nobody uploads clips).
|
|
555
|
+
*/
|
|
556
|
+
setCaptions(on: boolean, options?: {
|
|
557
|
+
language?: string;
|
|
558
|
+
translate?: boolean;
|
|
559
|
+
server?: boolean;
|
|
560
|
+
}): void;
|
|
561
|
+
/** The language you read captions in ("fr", "ha", …): lines arrive with a translation. null = as spoken. */
|
|
562
|
+
setCaptionLanguage(language: string | null): void;
|
|
563
|
+
/** The language you asked to read captions in (null = as spoken). */
|
|
564
|
+
get captionLanguage(): string | null;
|
|
565
|
+
/** Hosts: the whole transcript so far, as JSON lines, plain text or WebVTT. */
|
|
566
|
+
getTranscript(format?: "json" | "txt" | "vtt"): Promise<TranscriptLine[] | string>;
|
|
567
|
+
/** Hosts: summarize the transcript so far with AI. Everyone gets the `summary` event. */
|
|
568
|
+
summarize(style?: "meeting" | "lesson"): Promise<CallSummary>;
|
|
569
|
+
/** Swap in a fresh token before the current one expires. */
|
|
570
|
+
updateToken(token: string): void;
|
|
571
|
+
/**
|
|
572
|
+
* Choose how much video you want from one participant: "high" | "medium" |
|
|
573
|
+
* "low" | "off" (audio only for them). Adaptive limits can still lower it.
|
|
574
|
+
*/
|
|
575
|
+
setVideoQuality(participantId: string, quality: VideoQuality): void;
|
|
576
|
+
/**
|
|
577
|
+
* Keep a participant's received video matched to the size of the element
|
|
578
|
+
* showing it (ResizeObserver). Returns a function that stops watching.
|
|
579
|
+
*/
|
|
580
|
+
fitVideoQuality(participantId: string, el: HTMLElement): () => void;
|
|
581
|
+
/**
|
|
582
|
+
* Audio-only mode: stop receiving everyone's camera video and turn your own
|
|
583
|
+
* camera off. Screen shares still come through. Turning it off restores both.
|
|
584
|
+
*/
|
|
585
|
+
setAudioOnly(on: boolean): void;
|
|
586
|
+
/** Audio only by choice: setAudioOnly(true), mode "audio" or the "audio" data saver. See also audioFallback. */
|
|
587
|
+
get audioOnly(): boolean;
|
|
588
|
+
/**
|
|
589
|
+
* Data saver for costly or weak mobile data. A preset ("off", "low",
|
|
590
|
+
* "minimal", "audio") or custom settings, e.g.
|
|
591
|
+
* `{ base: "low", activeSpeakerVideo: 2 }`. Applies straight away, both to
|
|
592
|
+
* what you send and what you receive. Your choice is shown to others as
|
|
593
|
+
* participant.state.dataSaver.
|
|
594
|
+
*/
|
|
595
|
+
setDataSaver(input: DataSaverInput): void;
|
|
596
|
+
/** The current data-saver mode and what it does. */
|
|
597
|
+
get dataSaver(): {
|
|
598
|
+
mode: DataSaverMode | "custom";
|
|
599
|
+
settings: DataSaverSettings;
|
|
600
|
+
};
|
|
601
|
+
/** True while your connection has fallen back to audio only (see "audio-fallback"). */
|
|
602
|
+
get audioFallback(): boolean;
|
|
603
|
+
/**
|
|
604
|
+
* Turn the audio-first fallback on or off during the call. Turning it off
|
|
605
|
+
* while it's active brings video back now.
|
|
606
|
+
*/
|
|
607
|
+
setAudioFallback(enabled: boolean): void;
|
|
608
|
+
/**
|
|
609
|
+
* Media data used in this call so far (uploaded + downloaded, as measured by
|
|
610
|
+
* WebRTC), the current rates and a per-hour projection. Updated every
|
|
611
|
+
* statsIntervalMs; also see the "data-usage" event and estimateDataUsage().
|
|
612
|
+
*/
|
|
613
|
+
get dataUsage(): DataUsage;
|
|
614
|
+
/** Highest video quality the adaptive logic currently allows you to receive. */
|
|
615
|
+
get receiveCap(): VideoQuality;
|
|
616
|
+
/** Participant ids currently speaking, loudest first (includes room.self.id). */
|
|
617
|
+
get activeSpeakers(): string[];
|
|
618
|
+
/** Connection rating for a participant (use room.self.id for yourself). */
|
|
619
|
+
getConnectionQuality(participantId: string): ConnectionQuality | undefined;
|
|
620
|
+
/** Latest connection measurement (updated every statsIntervalMs). */
|
|
621
|
+
get linkStats(): LinkSample | null;
|
|
622
|
+
/** Leave the room, stop camera/mic and clean everything up. */
|
|
623
|
+
leave(reason?: string): void;
|
|
624
|
+
/** @internal */
|
|
625
|
+
_start(): Promise<void>;
|
|
626
|
+
/** Retry playing remote audio after a user gesture (if autoplay was blocked). */
|
|
627
|
+
resumeAudio(): void;
|
|
628
|
+
}
|
|
629
|
+
/** Attach a track to a <video> or <audio> element. */
|
|
630
|
+
export declare function attachTrack(el: HTMLMediaElement, track: MediaStreamTrack | null): void;
|
|
631
|
+
/** Read (not verify) the claims in a join token. */
|
|
632
|
+
export declare function decodeClaims(token: string): JoinClaims;
|