@whereby.com/browser-sdk 2.0.0-alpha1 → 2.0.0-alpha11

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/dist/lib.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { define, ref } from 'heresy';
2
- import React, { useCallback, useState, useReducer, useEffect } from 'react';
3
- import { __awaiter } from 'tslib';
2
+ import { __rest, __awaiter } from 'tslib';
3
+ import React, { useRef, useEffect, useState, useReducer } from 'react';
4
4
  import adapter from 'webrtc-adapter';
5
5
  import io from 'socket.io-client';
6
6
  import SDPUtils from 'sdp';
@@ -79,8 +79,7 @@ define("WherebyEmbed", {
79
79
  // Commands
80
80
  _postCommand(command, args = []) {
81
81
  if (this.iframe.current) {
82
- const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
83
- this.iframe.current.contentWindow.postMessage({ command, args }, url.origin);
82
+ this.iframe.current.contentWindow.postMessage({ command, args }, this.url.origin);
84
83
  }
85
84
  },
86
85
  startRecording() {
@@ -99,8 +98,7 @@ define("WherebyEmbed", {
99
98
  this._postCommand("toggle_screenshare", [enabled]);
100
99
  },
101
100
  onmessage({ origin, data }) {
102
- const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
103
- if (origin !== url.origin)
101
+ if (origin !== this.url.origin)
104
102
  return;
105
103
  const { type, payload: detail } = data;
106
104
  this.dispatchEvent(new CustomEvent(type, { detail }));
@@ -110,36 +108,290 @@ define("WherebyEmbed", {
110
108
  if (!room)
111
109
  return this.html `Whereby: Missing room attribute.`;
112
110
  // Get subdomain from room URL, or use it specified
113
- const m = /https:\/\/([^.]+)\.whereby.com\/.+/.exec(room);
111
+ const m = /https:\/\/([^.]+)(\.whereby.com|-ip-\d+-\d+-\d+-\d+.hereby.dev:4443)\/.+/.exec(room);
114
112
  const subdomain = (m && m[1]) || this.subdomain;
115
113
  if (!subdomain)
116
114
  return this.html `Whereby: Missing subdomain attr.`;
117
- const url = new URL(room, `https://${subdomain}.whereby.com`);
118
- Object.entries(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ jsApi: true, we: "2.0.0-alpha1", iframeSource: subdomain }, (displayName && { displayName })), (lang && { lang })), (metadata && { metadata })), (groups && { groups })), (virtualBackgroundUrl && { virtualBackgroundUrl })), (avatarUrl && { avatarUrl })), (minimal != null && { embed: minimal })), boolAttrs.reduce(
115
+ if (!m) {
116
+ return this.html `could not parse URL.`;
117
+ }
118
+ const baseURL = m[2] || `.whereby.com`;
119
+ this.url = new URL(room, `https://${subdomain}${baseURL}`);
120
+ const roomUrl = new URL(room);
121
+ if (roomUrl.searchParams.get("roomKey")) {
122
+ this.url.searchParams.append("roomKey", roomUrl.searchParams.get("roomKey"));
123
+ }
124
+ Object.entries(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ jsApi: true, we: "2.0.0-alpha11", iframeSource: subdomain }, (displayName && { displayName })), (lang && { lang })), (metadata && { metadata })), (groups && { groups })), (virtualBackgroundUrl && { virtualBackgroundUrl })), (avatarUrl && { avatarUrl })), (minimal != null && { embed: minimal })), boolAttrs.reduce(
119
125
  // add to URL if set in any way
120
126
  (o, v) => (this[v.toLowerCase()] != null ? Object.assign(Object.assign({}, o), { [v]: this[v.toLowerCase()] }) : o), {}))).forEach(([k, v]) => {
121
- if (!url.searchParams.has(k) && typeof v === "string") {
122
- url.searchParams.set(k, v);
127
+ if (!this.url.searchParams.has(k) && typeof v === "string") {
128
+ this.url.searchParams.set(k, v);
123
129
  }
124
130
  });
125
131
  return this.html `
126
132
  <iframe
127
133
  ref=${this.iframe}
128
- src=${url}
134
+ src=${this.url}
129
135
  allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
130
136
  `;
131
137
  },
132
138
  });
133
139
 
134
- var VideoElement = ({ stream, style }) => {
135
- const videoEl = useCallback((node) => {
136
- if (node !== null && node.srcObject !== stream) {
137
- node.srcObject = stream;
140
+ var VideoView = (_a) => {
141
+ var { muted, stream } = _a, rest = __rest(_a, ["muted", "stream"]);
142
+ const videoEl = useRef(null);
143
+ useEffect(() => {
144
+ if (!videoEl.current) {
145
+ return;
138
146
  }
139
- }, []);
140
- return React.createElement("video", { ref: videoEl, autoPlay: true, playsInline: true, style: style });
147
+ if (videoEl.current.srcObject !== stream) {
148
+ videoEl.current.srcObject = stream;
149
+ }
150
+ // Handle muting programatically, not as video attribute
151
+ // https://stackoverflow.com/questions/14111917/html5-video-muted-but-still-playing
152
+ if (videoEl.current.muted !== muted) {
153
+ videoEl.current.muted = Boolean(muted);
154
+ }
155
+ }, [muted, stream, videoEl]);
156
+ return React.createElement("video", Object.assign({ ref: videoEl, autoPlay: true, playsInline: true }, rest));
141
157
  };
142
158
 
159
+ const TypedLocalMediaEventTarget = EventTarget;
160
+ class LocalMedia extends TypedLocalMediaEventTarget {
161
+ constructor(constraints) {
162
+ super();
163
+ this._constraints = constraints;
164
+ this.stream = new MediaStream();
165
+ this._rtcManagers = [];
166
+ navigator.mediaDevices.addEventListener("devicechange", this._updateDeviceList.bind(this));
167
+ }
168
+ addRtcManager(rtcManager) {
169
+ this._rtcManagers.push(rtcManager);
170
+ }
171
+ removeRtcManager(rtcManager) {
172
+ this._rtcManagers = this._rtcManagers.filter((r) => r !== rtcManager);
173
+ }
174
+ getCameraDeviceId() {
175
+ var _a;
176
+ return (_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
177
+ }
178
+ getMicrophoneDeviceId() {
179
+ var _a;
180
+ return (_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
181
+ }
182
+ isCameraEnabled() {
183
+ var _a;
184
+ return !!((_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
185
+ }
186
+ isMicrophoneEnabled() {
187
+ var _a;
188
+ return !!((_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
189
+ }
190
+ toggleCameraEnabled(enabled) {
191
+ const videoTrack = this.stream.getVideoTracks()[0];
192
+ if (!videoTrack) {
193
+ return;
194
+ }
195
+ const newValue = enabled !== null && enabled !== void 0 ? enabled : !videoTrack.enabled;
196
+ videoTrack.enabled = newValue;
197
+ this.dispatchEvent(new CustomEvent("camera_enabled", { detail: { enabled: newValue } }));
198
+ }
199
+ toggleMichrophoneEnabled(enabled) {
200
+ const audioTrack = this.stream.getAudioTracks()[0];
201
+ if (!audioTrack) {
202
+ return;
203
+ }
204
+ const newValue = enabled !== null && enabled !== void 0 ? enabled : !audioTrack.enabled;
205
+ audioTrack.enabled = newValue;
206
+ this.dispatchEvent(new CustomEvent("microphone_enabled", { detail: { enabled: newValue } }));
207
+ }
208
+ setCameraDevice(deviceId) {
209
+ return __awaiter(this, void 0, void 0, function* () {
210
+ const newStream = yield navigator.mediaDevices.getUserMedia({ video: { deviceId } });
211
+ const newVideoTrack = newStream.getVideoTracks()[0];
212
+ if (newVideoTrack) {
213
+ const oldVideoTrack = this.stream.getVideoTracks()[0];
214
+ newVideoTrack.enabled = oldVideoTrack.enabled;
215
+ oldVideoTrack === null || oldVideoTrack === void 0 ? void 0 : oldVideoTrack.stop();
216
+ this._rtcManagers.forEach((rtcManager) => {
217
+ rtcManager.replaceTrack(oldVideoTrack, newVideoTrack);
218
+ });
219
+ this.stream.removeTrack(oldVideoTrack);
220
+ this.stream.addTrack(newVideoTrack);
221
+ }
222
+ this.dispatchEvent(new CustomEvent("stream_updated", {
223
+ detail: { stream: this.stream },
224
+ }));
225
+ });
226
+ }
227
+ setMicrophoneDevice(deviceId) {
228
+ return __awaiter(this, void 0, void 0, function* () {
229
+ const newStream = yield navigator.mediaDevices.getUserMedia({ audio: { deviceId } });
230
+ const newAudioTrack = newStream.getAudioTracks()[0];
231
+ const oldAudioTrack = this.stream.getAudioTracks()[0];
232
+ if (oldAudioTrack) {
233
+ newAudioTrack.enabled = oldAudioTrack.enabled;
234
+ oldAudioTrack.stop();
235
+ this.stream.removeTrack(oldAudioTrack);
236
+ }
237
+ this._rtcManagers.forEach((rtcManager) => {
238
+ rtcManager.replaceTrack(oldAudioTrack, newAudioTrack);
239
+ });
240
+ this.stream.addTrack(newAudioTrack);
241
+ this.dispatchEvent(new CustomEvent("stream_updated", {
242
+ detail: { stream: this.stream },
243
+ }));
244
+ });
245
+ }
246
+ _updateDeviceList() {
247
+ return __awaiter(this, void 0, void 0, function* () {
248
+ try {
249
+ const devices = yield navigator.mediaDevices.enumerateDevices();
250
+ this.dispatchEvent(new CustomEvent("device_list_updated", {
251
+ detail: {
252
+ cameraDevices: devices.filter((d) => d.kind === "videoinput"),
253
+ microphoneDevices: devices.filter((d) => d.kind === "audioinput"),
254
+ speakerDevices: devices.filter((d) => d.kind === "audiooutput"),
255
+ },
256
+ }));
257
+ }
258
+ catch (error) {
259
+ this.dispatchEvent(new CustomEvent("device_list_update_error", {
260
+ detail: {
261
+ error,
262
+ },
263
+ }));
264
+ throw error;
265
+ }
266
+ });
267
+ }
268
+ start() {
269
+ return __awaiter(this, void 0, void 0, function* () {
270
+ const newStream = yield navigator.mediaDevices.getUserMedia(this._constraints);
271
+ newStream.getTracks().forEach((t) => this.stream.addTrack(t));
272
+ this._updateDeviceList();
273
+ this.dispatchEvent(new CustomEvent("stream_updated", {
274
+ detail: { stream: this.stream },
275
+ }));
276
+ return this.stream;
277
+ });
278
+ }
279
+ stop() {
280
+ var _a;
281
+ (_a = this.stream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach((t) => {
282
+ t.stop();
283
+ });
284
+ }
285
+ }
286
+
287
+ const initialState$1 = {
288
+ cameraDeviceError: null,
289
+ cameraDevices: [],
290
+ isSettingCameraDevice: false,
291
+ isSettingMicrophoneDevice: false,
292
+ isStarting: false,
293
+ microphoneDeviceError: null,
294
+ microphoneDevices: [],
295
+ speakerDevices: [],
296
+ startError: null,
297
+ };
298
+ function reducer$1(state, action) {
299
+ switch (action.type) {
300
+ case "DEVICE_LIST_UPDATED":
301
+ return Object.assign(Object.assign({}, state), action.payload);
302
+ case "LOCAL_STREAM_UPDATED":
303
+ return Object.assign(Object.assign({}, state), { currentCameraDeviceId: action.payload.currentCameraDeviceId, currentMicrophoneDeviceId: action.payload.currentMicrophoneDeviceId, localStream: action.payload.stream });
304
+ case "SET_CAMERA_DEVICE":
305
+ return Object.assign(Object.assign({}, state), { cameraDeviceError: null, isSettingCameraDevice: true });
306
+ case "SET_CAMERA_DEVICE_COMPLETE":
307
+ return Object.assign(Object.assign({}, state), { isSettingCameraDevice: false });
308
+ case "SET_CAMERA_DEVICE_ERROR":
309
+ return Object.assign(Object.assign({}, state), { cameraDeviceError: action.payload, isSettingCameraDevice: false });
310
+ case "SET_MICROPHONE_DEVICE":
311
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: true, microphoneDeviceError: null });
312
+ case "SET_MICROPHONE_DEVICE_COMPLETE":
313
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false });
314
+ case "SET_MICROPHONE_DEVICE_ERROR":
315
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false, microphoneDeviceError: action.payload });
316
+ case "START":
317
+ return Object.assign(Object.assign({}, state), { isStarting: true, startError: null });
318
+ case "START_COMPLETE":
319
+ return Object.assign(Object.assign({}, state), { isStarting: false });
320
+ case "START_ERROR":
321
+ return Object.assign(Object.assign({}, state), { isStarting: false, startError: action.payload });
322
+ default:
323
+ return state;
324
+ }
325
+ }
326
+ function useLocalMedia(constraints = { audio: true, video: true }) {
327
+ const [localMedia] = useState(() => new LocalMedia(constraints));
328
+ const [state, dispatch] = useReducer(reducer$1, initialState$1);
329
+ useEffect(() => {
330
+ localMedia.addEventListener("device_list_updated", (e) => {
331
+ const { cameraDevices, microphoneDevices, speakerDevices } = e.detail;
332
+ dispatch({ type: "DEVICE_LIST_UPDATED", payload: { cameraDevices, microphoneDevices, speakerDevices } });
333
+ });
334
+ localMedia.addEventListener("stream_updated", (e) => {
335
+ const { stream } = e.detail;
336
+ dispatch({
337
+ type: "LOCAL_STREAM_UPDATED",
338
+ payload: {
339
+ stream,
340
+ currentCameraDeviceId: localMedia.getCameraDeviceId(),
341
+ currentMicrophoneDeviceId: localMedia.getMicrophoneDeviceId(),
342
+ },
343
+ });
344
+ });
345
+ const start = () => __awaiter(this, void 0, void 0, function* () {
346
+ dispatch({ type: "START" });
347
+ try {
348
+ yield localMedia.start();
349
+ dispatch({ type: "START_COMPLETE" });
350
+ }
351
+ catch (error) {
352
+ dispatch({ type: "START_ERROR", payload: error });
353
+ }
354
+ });
355
+ start();
356
+ // Perform cleanup on unmount
357
+ return () => {
358
+ localMedia.stop();
359
+ };
360
+ }, []);
361
+ return {
362
+ state,
363
+ actions: {
364
+ setCameraDevice: (...args) => __awaiter(this, void 0, void 0, function* () {
365
+ dispatch({ type: "SET_CAMERA_DEVICE" });
366
+ try {
367
+ yield localMedia.setCameraDevice(...args);
368
+ dispatch({ type: "SET_CAMERA_DEVICE_COMPLETE" });
369
+ }
370
+ catch (error) {
371
+ dispatch({ type: "SET_CAMERA_DEVICE_ERROR", payload: error });
372
+ }
373
+ }),
374
+ setMicrophoneDevice: (...args) => __awaiter(this, void 0, void 0, function* () {
375
+ dispatch({ type: "SET_MICROPHONE_DEVICE" });
376
+ try {
377
+ yield localMedia.setMicrophoneDevice(...args);
378
+ dispatch({ type: "SET_MICROPHONE_DEVICE_COMPLETE" });
379
+ }
380
+ catch (error) {
381
+ dispatch({ type: "SET_MICROPHONE_DEVICE_ERROR", payload: error });
382
+ }
383
+ }),
384
+ toggleCameraEnabled: (...args) => {
385
+ return localMedia.toggleCameraEnabled(...args);
386
+ },
387
+ toggleMicrophoneEnabled: (...args) => {
388
+ return localMedia.toggleMichrophoneEnabled(...args);
389
+ },
390
+ },
391
+ _ref: localMedia,
392
+ };
393
+ }
394
+
143
395
  const EVENTS = {
144
396
  CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
145
397
  STREAM_ADDED: "stream_added",
@@ -270,10 +522,10 @@ class ServerSocket {
270
522
  }
271
523
 
272
524
  this._socket = io(hostName, options);
273
- this._socket.on("reconnect", () => {
525
+ this._socket.io.on("reconnect", () => {
274
526
  this._socket.sendBuffer = [];
275
527
  });
276
- this._socket.on("reconnect_attempt", () => {
528
+ this._socket.io.on("reconnect_attempt", () => {
277
529
  if (this._wasConnectedUsingWebsocket) {
278
530
  this._socket.io.opts.transports = ["websocket"];
279
531
  // only fallback to polling if not safari
@@ -331,6 +583,10 @@ class ServerSocket {
331
583
  );
332
584
  }
333
585
 
586
+ getManager() {
587
+ return this._socket.io;
588
+ }
589
+
334
590
  isConnecting() {
335
591
  return this._socket && this._socket.connecting;
336
592
  }
@@ -1964,10 +2220,11 @@ class VegaParser {
1964
2220
  }
1965
2221
 
1966
2222
  class VegaConnection extends EventEmitter {
1967
- constructor(wsUrl, logger) {
2223
+ constructor(wsUrl, logger, protocol = "whereby-sfu#v4") {
1968
2224
  super();
1969
2225
 
1970
2226
  this.wsUrl = wsUrl;
2227
+ this.protocol = protocol;
1971
2228
  this.logger = logger;
1972
2229
 
1973
2230
  // This is the map of sent requests that are waiting for a response
@@ -1976,7 +2233,7 @@ class VegaConnection extends EventEmitter {
1976
2233
  }
1977
2234
 
1978
2235
  _setupSocket() {
1979
- this.socket = new WebSocket(this.wsUrl, "whereby-sfu#v4");
2236
+ this.socket = new WebSocket(this.wsUrl, this.protocol);
1980
2237
  this.socket.onopen = this._onOpen.bind(this);
1981
2238
  this.socket.onmessage = this._onMessage.bind(this);
1982
2239
  this.socket.onclose = this._onClose.bind(this);
@@ -1996,7 +2253,9 @@ class VegaConnection extends EventEmitter {
1996
2253
  }
1997
2254
 
1998
2255
  close() {
1999
- this.socket?.close();
2256
+ if (!this.socket) return;
2257
+
2258
+ this.socket.close();
2000
2259
  }
2001
2260
 
2002
2261
  _onOpen() {
@@ -2008,11 +2267,15 @@ class VegaConnection extends EventEmitter {
2008
2267
  _onMessage(event) {
2009
2268
  const socketMessage = VegaParser.parse(event.data);
2010
2269
 
2270
+ if (!socketMessage) {
2271
+ return this.logger.log("VegaConnectionManager: Received invalid message", event.data);
2272
+ }
2273
+
2011
2274
  this.logger.log("VegaConnectionManager: Received message", socketMessage);
2012
2275
 
2013
- if (socketMessage?.response) {
2276
+ if (socketMessage.response) {
2014
2277
  this._handleResponse(socketMessage);
2015
- } else if (socketMessage?.message) {
2278
+ } else if (socketMessage.message) {
2016
2279
  this.emit("message", socketMessage);
2017
2280
  }
2018
2281
  }
@@ -2119,7 +2382,7 @@ const VIDEO_SETTINGS_VP9 = {
2119
2382
  codecOptions: {
2120
2383
  videoGoogleStartBitrate: 500,
2121
2384
  },
2122
- encodings: [{ scalabilityMode: "S3T3_KEY", networkPriority: "high" }],
2385
+ encodings: [{ scalabilityMode: "L3T2_KEY", networkPriority: "high" }],
2123
2386
  };
2124
2387
 
2125
2388
  const SCREEN_SHARE_SETTINGS = {
@@ -2128,13 +2391,13 @@ const SCREEN_SHARE_SETTINGS = {
2128
2391
 
2129
2392
  const SCREEN_SHARE_SIMULCAST_SETTINGS = {
2130
2393
  encodings: [
2131
- { dtx: true, maxBitrate: 500000 },
2132
- { dtx: true, maxBitrate: 1500000 },
2394
+ { scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
2395
+ { scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
2133
2396
  ],
2134
2397
  };
2135
2398
 
2136
2399
  const SCREEN_SHARE_SETTINGS_VP9 = {
2137
- encodings: [{ scalabilityMode: "S3T3", dtx: true, networkPriority: "high" }],
2400
+ encodings: [{ scalabilityMode: "L1T1", dtx: true, networkPriority: "high" }],
2138
2401
  };
2139
2402
 
2140
2403
  const getMediaSettings = (kind, isScreenShare, features) => {
@@ -2150,8 +2413,8 @@ const getMediaSettings = (kind, isScreenShare, features) => {
2150
2413
 
2151
2414
  return SCREEN_SHARE_SETTINGS;
2152
2415
  } else {
2153
- if (lowDataModeEnabled) return VIDEO_SETTINGS_SD;
2154
2416
  if (vp9On) return VIDEO_SETTINGS_VP9;
2417
+ if (lowDataModeEnabled) return VIDEO_SETTINGS_SD;
2155
2418
 
2156
2419
  return VIDEO_SETTINGS_HD;
2157
2420
  }
@@ -5005,12 +5268,12 @@ class LocalParticipant extends RoomParticipant {
5005
5268
  }
5006
5269
  }
5007
5270
 
5008
- const API_BASE_URL = "https://api.appearin.net";
5271
+ const API_BASE_URL = "https://api.whereby.dev";
5009
5272
  const SIGNAL_BASE_URL = "wss://signal.appearin.net";
5010
5273
  const NON_PERSON_ROLES = ["recorder", "streamer"];
5011
5274
  function createSocket() {
5012
5275
  const parsedUrl = new URL(SIGNAL_BASE_URL);
5013
- const path = `${parsedUrl.pathname.replace(/^\/$/, "")}/protocol/socket.io/v1`;
5276
+ const path = `${parsedUrl.pathname.replace(/^\/$/, "")}/protocol/socket.io/v4`;
5014
5277
  const SOCKET_HOST = parsedUrl.origin;
5015
5278
  const socketConf = {
5016
5279
  host: SOCKET_HOST,
@@ -5018,6 +5281,7 @@ function createSocket() {
5018
5281
  reconnectionDelay: 5000,
5019
5282
  reconnectionDelayMax: 30000,
5020
5283
  timeout: 10000,
5284
+ withCredentials: true,
5021
5285
  };
5022
5286
  return new ServerSocket(SOCKET_HOST, socketConf);
5023
5287
  }
@@ -5026,12 +5290,17 @@ const noop = () => {
5026
5290
  };
5027
5291
  const TypedEventTarget = EventTarget;
5028
5292
  class RoomConnection extends TypedEventTarget {
5029
- constructor(roomUrl, { displayName, localMediaConstraints, localStream, logger }) {
5293
+ constructor(roomUrl, { displayName, localMedia, localMediaConstraints, logger, roomKey }) {
5030
5294
  super();
5031
5295
  this.localParticipant = null;
5032
5296
  this.remoteParticipants = [];
5033
- this.roomConnectionState = "";
5297
+ this._ownsLocalMedia = false;
5298
+ this.organizationId = "";
5299
+ this.roomConnectionStatus = "";
5034
5300
  this.roomUrl = new URL(roomUrl); // Throw if invalid Whereby room url
5301
+ const searchParams = new URLSearchParams(this.roomUrl.search);
5302
+ this._roomKey = roomKey || searchParams.get("roomKey");
5303
+ this.roomName = this.roomUrl.pathname;
5035
5304
  this.logger = logger || {
5036
5305
  debug: noop,
5037
5306
  error: noop,
@@ -5039,10 +5308,20 @@ class RoomConnection extends TypedEventTarget {
5039
5308
  warn: noop,
5040
5309
  };
5041
5310
  this.displayName = displayName;
5042
- this.localStream = localStream;
5043
5311
  this.localMediaConstraints = localMediaConstraints;
5044
5312
  const urls = fromLocation({ host: this.roomUrl.host });
5045
- // Initialize services
5313
+ // Set up local media
5314
+ if (localMedia) {
5315
+ this.localMedia = localMedia;
5316
+ }
5317
+ else if (localMediaConstraints) {
5318
+ this.localMedia = new LocalMedia(localMediaConstraints);
5319
+ this._ownsLocalMedia = true;
5320
+ }
5321
+ else {
5322
+ throw new Error("Missing constraints");
5323
+ }
5324
+ // Set up services
5046
5325
  this.credentialsService = CredentialsService.create({ baseUrl: API_BASE_URL });
5047
5326
  this.apiClient = new ApiClient({
5048
5327
  fetchDeviceCredentials: this.credentialsService.getCredentials.bind(this.credentialsService),
@@ -5064,10 +5343,30 @@ class RoomConnection extends TypedEventTarget {
5064
5343
  // Create signal socket and set up event listeners
5065
5344
  this.signalSocket = createSocket();
5066
5345
  this.signalSocket.on("new_client", this._handleNewClient.bind(this));
5346
+ this.signalSocket.on("chat_message", this._handleNewChatMessage.bind(this));
5067
5347
  this.signalSocket.on("client_left", this._handleClientLeft.bind(this));
5068
5348
  this.signalSocket.on("audio_enabled", this._handleClientAudioEnabled.bind(this));
5069
5349
  this.signalSocket.on("video_enabled", this._handleClientVideoEnabled.bind(this));
5070
5350
  this.signalSocket.on("client_metadata_received", this._handleClientMetadataReceived.bind(this));
5351
+ this.signalSocket.on("knock_handled", this._handleKnockHandled.bind(this));
5352
+ this.signalSocket.on("knocker_left", this._handleKnockerLeft.bind(this));
5353
+ this.signalSocket.on("room_joined", this._handleRoomJoined.bind(this));
5354
+ this.signalSocket.on("room_knocked", this._handleRoomKnocked.bind(this));
5355
+ // Set up local media listeners
5356
+ this.localMedia.addEventListener("camera_enabled", (e) => {
5357
+ const { enabled } = e.detail;
5358
+ this.signalSocket.emit("enable_video", { enabled });
5359
+ });
5360
+ this.localMedia.addEventListener("microphone_enabled", (e) => {
5361
+ const { enabled } = e.detail;
5362
+ this.signalSocket.emit("enable_audio", { enabled });
5363
+ });
5364
+ }
5365
+ get roomKey() {
5366
+ return this._roomKey;
5367
+ }
5368
+ _handleNewChatMessage(message) {
5369
+ this.dispatchEvent(new CustomEvent("chat_message", { detail: message }));
5071
5370
  }
5072
5371
  _handleNewClient({ client }) {
5073
5372
  if (NON_PERSON_ROLES.includes(client.role.roleName)) {
@@ -5113,6 +5412,70 @@ class RoomConnection extends TypedEventTarget {
5113
5412
  detail: { participantId: remoteParticipant.id, displayName },
5114
5413
  }));
5115
5414
  }
5415
+ _handleKnockHandled(payload) {
5416
+ const { resolution } = payload;
5417
+ if (resolution === "accepted") {
5418
+ this.roomConnectionStatus = "accepted";
5419
+ this._roomKey = payload.metadata.roomKey;
5420
+ this._joinRoom();
5421
+ }
5422
+ else if (resolution === "rejected") {
5423
+ this.roomConnectionStatus = "rejected";
5424
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5425
+ detail: {
5426
+ roomConnectionStatus: this.roomConnectionStatus,
5427
+ },
5428
+ }));
5429
+ }
5430
+ }
5431
+ _handleKnockerLeft(payload) {
5432
+ const { clientId } = payload;
5433
+ this.dispatchEvent(new CustomEvent("waiting_participant_left", {
5434
+ detail: { participantId: clientId },
5435
+ }));
5436
+ }
5437
+ _handleRoomJoined(event) {
5438
+ const { error, isLocked, room, selfId } = event;
5439
+ if (error === "room_locked" && isLocked) {
5440
+ this.roomConnectionStatus = "room_locked";
5441
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5442
+ detail: {
5443
+ roomConnectionStatus: this.roomConnectionStatus,
5444
+ },
5445
+ }));
5446
+ return;
5447
+ }
5448
+ // Check if we have an error
5449
+ // Check if it is a room joined error
5450
+ // Set state to connect_failed_locked
5451
+ // Set state to connect_failed_no_host
5452
+ if (room) {
5453
+ const { clients, knockers } = room;
5454
+ const localClient = clients.find((c) => c.id === selfId);
5455
+ if (!localClient)
5456
+ throw new Error("Missing local client");
5457
+ this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localMedia.stream || undefined }));
5458
+ this.remoteParticipants = clients
5459
+ .filter((c) => c.id !== selfId)
5460
+ .map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
5461
+ this.roomConnectionStatus = "connected";
5462
+ this.dispatchEvent(new CustomEvent("room_joined", {
5463
+ detail: {
5464
+ localParticipant: this.localParticipant,
5465
+ remoteParticipants: this.remoteParticipants,
5466
+ waitingParticipants: knockers.map((knocker) => {
5467
+ return { id: knocker.clientId, displayName: knocker.displayName };
5468
+ }),
5469
+ },
5470
+ }));
5471
+ }
5472
+ }
5473
+ _handleRoomKnocked(event) {
5474
+ const { clientId, displayName } = event;
5475
+ this.dispatchEvent(new CustomEvent("waiting_participant_joined", {
5476
+ detail: { participantId: clientId, displayName },
5477
+ }));
5478
+ }
5116
5479
  _handleRtcEvent(eventName, data) {
5117
5480
  if (eventName === "rtc_manager_created") {
5118
5481
  return this._handleRtcManagerCreated(data);
@@ -5125,10 +5488,14 @@ class RoomConnection extends TypedEventTarget {
5125
5488
  }
5126
5489
  }
5127
5490
  _handleRtcManagerCreated({ rtcManager }) {
5128
- var _a, _b, _c;
5491
+ var _a;
5129
5492
  this.rtcManager = rtcManager;
5130
- if (this.localStream) {
5131
- (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream("0", this.localStream, !((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getAudioTracks().find((t) => t.enabled)), !((_c = this.localStream) === null || _c === void 0 ? void 0 : _c.getVideoTracks().find((t) => t.enabled)));
5493
+ this.localMedia.addRtcManager(rtcManager);
5494
+ if (this.localMedia.stream) {
5495
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream("0", this.localMedia.stream, !this.localMedia.isMicrophoneEnabled(), !this.localMedia.isCameraEnabled());
5496
+ }
5497
+ if (this.remoteParticipants.length) {
5498
+ this._handleAcceptStreams(this.remoteParticipants);
5132
5499
  }
5133
5500
  }
5134
5501
  _handleAcceptStreams(remoteParticipants) {
@@ -5153,8 +5520,6 @@ class RoomConnection extends TypedEventTarget {
5153
5520
  if (!newState) {
5154
5521
  return;
5155
5522
  }
5156
- // #endregion
5157
- // #region doAcceptStreams
5158
5523
  if (newState === "to_accept" ||
5159
5524
  (newState === "new_accept" && shouldAcceptNewClients) ||
5160
5525
  (newState === "old_accept" && !shouldAcceptNewClients)) {
@@ -5178,7 +5543,6 @@ class RoomConnection extends TypedEventTarget {
5178
5543
  else ;
5179
5544
  // Update stream state
5180
5545
  participant.updateStreamState(streamId, streamState.replace(/to_|new_|old_/, "done_"));
5181
- // #endregion
5182
5546
  });
5183
5547
  });
5184
5548
  }
@@ -5190,35 +5554,51 @@ class RoomConnection extends TypedEventTarget {
5190
5554
  }
5191
5555
  this.dispatchEvent(new CustomEvent("participant_stream_added", { detail: { participantId: clientId, stream, streamId } }));
5192
5556
  }
5193
- /**
5194
- * Public API
5195
- */
5557
+ _joinRoom() {
5558
+ this.signalSocket.emit("join_room", {
5559
+ avatarUrl: null,
5560
+ config: {
5561
+ isAudioEnabled: this.localMedia.isMicrophoneEnabled(),
5562
+ isVideoEnabled: this.localMedia.isCameraEnabled(),
5563
+ },
5564
+ deviceCapabilities: { canScreenshare: true },
5565
+ displayName: this.displayName,
5566
+ isCoLocated: false,
5567
+ isDevicePermissionDenied: false,
5568
+ kickFromOtherRooms: false,
5569
+ organizationId: this.organizationId,
5570
+ roomKey: this.roomKey,
5571
+ roomName: this.roomName,
5572
+ selfId: "",
5573
+ userAgent: `browser-sdk:${sdkVersion }`,
5574
+ });
5575
+ }
5196
5576
  join() {
5197
5577
  return __awaiter(this, void 0, void 0, function* () {
5198
- if (["connected", "connecting"].includes(this.roomConnectionState)) {
5199
- console.warn(`Trying to join room state is ${this.roomConnectionState}`);
5578
+ if (["connected", "connecting"].includes(this.roomConnectionStatus)) {
5579
+ console.warn(`Trying to join when room state is already ${this.roomConnectionStatus}`);
5200
5580
  return;
5201
5581
  }
5202
5582
  this.logger.log("Joining room");
5203
- this.roomConnectionState = "connecting";
5204
- if (!this.localStream && this.localMediaConstraints) {
5205
- const localStream = yield navigator.mediaDevices.getUserMedia(this.localMediaConstraints);
5206
- this.localStream = localStream;
5207
- }
5583
+ this.roomConnectionStatus = "connecting";
5584
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5585
+ detail: {
5586
+ roomConnectionStatus: this.roomConnectionStatus,
5587
+ },
5588
+ }));
5208
5589
  const organization = yield this.organizationServiceCache.fetchOrganization();
5209
5590
  if (!organization) {
5210
5591
  throw new Error("Invalid room url");
5211
5592
  }
5212
- // TODO: Get room permissions
5213
- // TODO: Get room features
5593
+ this.organizationId = organization.organizationId;
5594
+ if (this._ownsLocalMedia) {
5595
+ yield this.localMedia.start();
5596
+ }
5214
5597
  const webrtcProvider = {
5215
- getMediaConstraints: () => {
5216
- var _a, _b;
5217
- return ({
5218
- audio: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
5219
- video: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
5220
- });
5221
- },
5598
+ getMediaConstraints: () => ({
5599
+ audio: this.localMedia.isMicrophoneEnabled(),
5600
+ video: this.localMedia.isCameraEnabled(),
5601
+ }),
5222
5602
  deferrable(clientId) {
5223
5603
  return !clientId;
5224
5604
  },
@@ -5241,55 +5621,40 @@ class RoomConnection extends TypedEventTarget {
5241
5621
  });
5242
5622
  // Identify device on signal connection
5243
5623
  const deviceCredentials = yield this.credentialsService.getCredentials();
5244
- // TODO: Handle connection and failed connection properly
5245
- setTimeout(() => {
5246
- this.logger.log("Connected to signal socket");
5247
- this.signalSocket.emit("identify_device", { deviceCredentials });
5248
- }, 2000);
5624
+ this.logger.log("Connected to signal socket");
5625
+ this.signalSocket.emit("identify_device", { deviceCredentials });
5249
5626
  this.signalSocket.once("device_identified", () => {
5250
- var _a, _b;
5251
- this.signalSocket.emit("join_room", {
5252
- avatarUrl: null,
5253
- config: {
5254
- isAudioEnabled: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
5255
- isVideoEnabled: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
5256
- },
5257
- deviceCapabilities: { canScreenshare: true },
5258
- displayName: this.displayName,
5259
- isCoLocated: false,
5260
- isDevicePermissionDenied: false,
5261
- kickFromOtherRooms: false,
5262
- organizationId: organization.organizationId,
5263
- roomKey: null,
5264
- roomName: this.roomUrl.pathname,
5265
- selfId: "",
5266
- });
5267
- });
5268
- this.signalSocket.once("room_joined", (res) => {
5269
- const { selfId, room: { clients }, } = res;
5270
- const localClient = clients.find((c) => c.id === selfId);
5271
- if (!localClient)
5272
- throw new Error("Missing local client");
5273
- this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localStream }));
5274
- this.remoteParticipants = clients
5275
- .filter((c) => c.id !== selfId)
5276
- .map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
5277
- // Accept remote streams if RTC manager has been initialized
5278
- if (this.rtcManager) {
5279
- this._handleAcceptStreams(this.remoteParticipants);
5280
- }
5281
- this.roomConnectionState = "connected";
5282
- this.dispatchEvent(new CustomEvent("room_joined", {
5283
- detail: {
5284
- localParticipant: this.localParticipant,
5285
- remoteParticipants: this.remoteParticipants,
5286
- },
5287
- }));
5627
+ this._joinRoom();
5288
5628
  });
5289
5629
  });
5290
5630
  }
5631
+ knock() {
5632
+ this.roomConnectionStatus = "knocking";
5633
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5634
+ detail: {
5635
+ roomConnectionStatus: this.roomConnectionStatus,
5636
+ },
5637
+ }));
5638
+ this.signalSocket.emit("knock_room", {
5639
+ displayName: this.displayName,
5640
+ imageUrl: null,
5641
+ kickFromOtherRooms: true,
5642
+ liveVideo: false,
5643
+ organizationId: this.organizationId,
5644
+ roomKey: this._roomKey,
5645
+ roomName: this.roomName,
5646
+ });
5647
+ }
5291
5648
  leave() {
5292
5649
  return new Promise((resolve) => {
5650
+ if (this._ownsLocalMedia) {
5651
+ this.localMedia.stop();
5652
+ }
5653
+ if (this.rtcManager) {
5654
+ this.localMedia.removeRtcManager(this.rtcManager);
5655
+ this.rtcManager.disconnectAll();
5656
+ this.rtcManager = undefined;
5657
+ }
5293
5658
  if (!this.signalSocket) {
5294
5659
  return resolve();
5295
5660
  }
@@ -5304,29 +5669,10 @@ class RoomConnection extends TypedEventTarget {
5304
5669
  });
5305
5670
  });
5306
5671
  }
5307
- toggleCamera(enabled) {
5308
- var _a;
5309
- const localVideoTrack = (_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks()[0];
5310
- if (!localVideoTrack) {
5311
- this.logger.log("Tried toggling non-existing video track");
5312
- return;
5313
- }
5314
- // TODO: Do stopOrResumeVideo
5315
- const newValue = enabled !== null && enabled !== void 0 ? enabled : !localVideoTrack.enabled;
5316
- localVideoTrack.enabled = newValue;
5317
- this.signalSocket.emit("enable_video", { enabled: newValue });
5318
- }
5319
- toggleMicrophone(enabled) {
5320
- var _a;
5321
- const localAudioTrack = (_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks()[0];
5322
- if (!localAudioTrack) {
5323
- this.logger.log("Tried toggling non-existing audio track");
5324
- return;
5325
- }
5326
- // TODO: Do stopOrResumeAudio
5327
- const newValue = enabled !== null && enabled !== void 0 ? enabled : !localAudioTrack.enabled;
5328
- localAudioTrack.enabled = newValue;
5329
- this.signalSocket.emit("enable_audio", { enabled: newValue });
5672
+ sendChatMessage(text) {
5673
+ this.signalSocket.emit("chat_message", {
5674
+ text,
5675
+ });
5330
5676
  }
5331
5677
  setDisplayName(displayName) {
5332
5678
  this.signalSocket.emit("send_client_metadata", {
@@ -5336,8 +5682,31 @@ class RoomConnection extends TypedEventTarget {
5336
5682
  },
5337
5683
  });
5338
5684
  }
5685
+ acceptWaitingParticipant(participantId) {
5686
+ this.signalSocket.emit("handle_knock", {
5687
+ action: "accept",
5688
+ clientId: participantId,
5689
+ response: {},
5690
+ });
5691
+ }
5692
+ rejectWaitingParticipant(participantId) {
5693
+ this.signalSocket.emit("handle_knock", {
5694
+ action: "reject",
5695
+ clientId: participantId,
5696
+ response: {},
5697
+ });
5698
+ }
5339
5699
  }
5340
5700
 
5701
+ const initialState = {
5702
+ chatMessages: [],
5703
+ roomConnectionStatus: "",
5704
+ isJoining: false,
5705
+ joinError: null,
5706
+ mostRecentChatMessage: null,
5707
+ remoteParticipants: [],
5708
+ waitingParticipants: [],
5709
+ };
5341
5710
  function updateParticipant(remoteParticipants, participantId, updates) {
5342
5711
  const existingParticipant = remoteParticipants.find((p) => p.id === participantId);
5343
5712
  if (!existingParticipant) {
@@ -5352,8 +5721,12 @@ function updateParticipant(remoteParticipants, participantId, updates) {
5352
5721
  }
5353
5722
  function reducer(state, action) {
5354
5723
  switch (action.type) {
5724
+ case "CHAT_MESSAGE":
5725
+ return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, action.payload], mostRecentChatMessage: action.payload });
5355
5726
  case "ROOM_JOINED":
5356
- return Object.assign(Object.assign({}, state), { localParticipant: action.payload.localParticipant, remoteParticipants: action.payload.remoteParticipants, roomConnectionStatus: "connected" });
5727
+ return Object.assign(Object.assign({}, state), { localParticipant: action.payload.localParticipant, remoteParticipants: action.payload.remoteParticipants, waitingParticipants: action.payload.waitingParticipants, roomConnectionStatus: "connected" });
5728
+ case "ROOM_CONNECTION_STATUS_CHANGED":
5729
+ return Object.assign(Object.assign({}, state), { roomConnectionStatus: action.payload.roomConnectionStatus });
5357
5730
  case "PARTICIPANT_AUDIO_ENABLED":
5358
5731
  return Object.assign(Object.assign({}, state), { remoteParticipants: updateParticipant(state.remoteParticipants, action.payload.participantId, {
5359
5732
  isAudioEnabled: action.payload.isAudioEnabled,
@@ -5378,21 +5751,28 @@ function reducer(state, action) {
5378
5751
  if (!state.localParticipant)
5379
5752
  return state;
5380
5753
  return Object.assign(Object.assign({}, state), { localParticipant: Object.assign(Object.assign({}, state.localParticipant), { displayName: action.payload.displayName }) });
5754
+ case "WAITING_PARTICIPANT_JOINED":
5755
+ return Object.assign(Object.assign({}, state), { waitingParticipants: [
5756
+ ...state.waitingParticipants,
5757
+ { id: action.payload.participantId, displayName: action.payload.displayName },
5758
+ ] });
5759
+ case "WAITING_PARTICIPANT_LEFT":
5760
+ return Object.assign(Object.assign({}, state), { waitingParticipants: state.waitingParticipants.filter((wp) => wp.id !== action.payload.participantId) });
5381
5761
  default:
5382
5762
  throw state;
5383
5763
  }
5384
- }
5385
-
5764
+ }
5386
5765
  function useRoomConnection(roomUrl, roomConnectionOptions) {
5387
- const [roomConnection, setRoomConnection] = useState(null);
5388
- const [state, dispatch] = useReducer(reducer, { remoteParticipants: [] });
5389
- useEffect(() => {
5390
- setRoomConnection(new RoomConnection(roomUrl, roomConnectionOptions));
5391
- }, [roomUrl]);
5766
+ const [roomConnection] = useState(() => {
5767
+ var _a;
5768
+ return new RoomConnection(roomUrl, Object.assign(Object.assign({}, roomConnectionOptions), { localMedia: ((_a = roomConnectionOptions === null || roomConnectionOptions === void 0 ? void 0 : roomConnectionOptions.localMedia) === null || _a === void 0 ? void 0 : _a._ref) || undefined }));
5769
+ });
5770
+ const [state, dispatch] = useReducer(reducer, initialState);
5392
5771
  useEffect(() => {
5393
- if (!roomConnection) {
5394
- return;
5395
- }
5772
+ roomConnection.addEventListener("chat_message", (e) => {
5773
+ const chatMessage = e.detail;
5774
+ dispatch({ type: "CHAT_MESSAGE", payload: chatMessage });
5775
+ });
5396
5776
  roomConnection.addEventListener("participant_audio_enabled", (e) => {
5397
5777
  const { participantId, isAudioEnabled } = e.detail;
5398
5778
  dispatch({ type: "PARTICIPANT_AUDIO_ENABLED", payload: { participantId, isAudioEnabled } });
@@ -5409,9 +5789,13 @@ function useRoomConnection(roomUrl, roomConnectionOptions) {
5409
5789
  const { participantId, stream } = e.detail;
5410
5790
  dispatch({ type: "PARTICIPANT_STREAM_ADDED", payload: { participantId, stream } });
5411
5791
  });
5792
+ roomConnection.addEventListener("room_connection_status_changed", (e) => {
5793
+ const { roomConnectionStatus } = e.detail;
5794
+ dispatch({ type: "ROOM_CONNECTION_STATUS_CHANGED", payload: { roomConnectionStatus } });
5795
+ });
5412
5796
  roomConnection.addEventListener("room_joined", (e) => {
5413
- const { localParticipant, remoteParticipants } = e.detail;
5414
- dispatch({ type: "ROOM_JOINED", payload: { localParticipant, remoteParticipants } });
5797
+ const { localParticipant, remoteParticipants, waitingParticipants } = e.detail;
5798
+ dispatch({ type: "ROOM_JOINED", payload: { localParticipant, remoteParticipants, waitingParticipants } });
5415
5799
  });
5416
5800
  roomConnection.addEventListener("participant_video_enabled", (e) => {
5417
5801
  const { participantId, isVideoEnabled } = e.detail;
@@ -5421,31 +5805,52 @@ function useRoomConnection(roomUrl, roomConnectionOptions) {
5421
5805
  const { participantId, displayName } = e.detail;
5422
5806
  dispatch({ type: "PARTICIPANT_METADATA_CHANGED", payload: { participantId, displayName } });
5423
5807
  });
5808
+ roomConnection.addEventListener("waiting_participant_joined", (e) => {
5809
+ const { participantId, displayName } = e.detail;
5810
+ dispatch({ type: "WAITING_PARTICIPANT_JOINED", payload: { participantId, displayName } });
5811
+ });
5812
+ roomConnection.addEventListener("waiting_participant_left", (e) => {
5813
+ const { participantId } = e.detail;
5814
+ dispatch({ type: "WAITING_PARTICIPANT_LEFT", payload: { participantId } });
5815
+ });
5424
5816
  roomConnection.join();
5425
5817
  return () => {
5426
5818
  roomConnection.leave();
5427
5819
  };
5428
- }, [roomConnection]);
5429
- return [
5820
+ }, []);
5821
+ return {
5430
5822
  state,
5431
- {
5432
- toggleCamera: (enabled) => {
5433
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.toggleCamera(enabled);
5823
+ actions: {
5824
+ knock: () => {
5825
+ roomConnection.knock();
5434
5826
  },
5435
- toggleMicrophone: (enabled) => {
5436
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.toggleMicrophone(enabled);
5827
+ sendChatMessage: (text) => {
5828
+ roomConnection.sendChatMessage(text);
5437
5829
  },
5438
5830
  setDisplayName: (displayName) => {
5439
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.setDisplayName(displayName);
5831
+ roomConnection.setDisplayName(displayName);
5440
5832
  dispatch({ type: "LOCAL_CLIENT_DISPLAY_NAME_CHANGED", payload: { displayName } });
5441
5833
  },
5834
+ toggleCamera: (enabled) => {
5835
+ roomConnection.localMedia.toggleCameraEnabled(enabled);
5836
+ },
5837
+ toggleMicrophone: (enabled) => {
5838
+ roomConnection.localMedia.toggleMichrophoneEnabled(enabled);
5839
+ },
5840
+ acceptWaitingParticipant: (participantId) => {
5841
+ roomConnection.acceptWaitingParticipant(participantId);
5842
+ },
5843
+ rejectWaitingParticipant: (participantId) => {
5844
+ roomConnection.rejectWaitingParticipant(participantId);
5845
+ },
5442
5846
  },
5443
- {
5444
- VideoView: VideoElement,
5847
+ components: {
5848
+ VideoView,
5445
5849
  },
5446
- ];
5850
+ _ref: roomConnection,
5851
+ };
5447
5852
  }
5448
5853
 
5449
- const sdkVersion = "2.0.0-alpha1";
5854
+ const sdkVersion = "2.0.0-alpha11";
5450
5855
 
5451
- export { sdkVersion, useRoomConnection };
5856
+ export { VideoView, sdkVersion, useLocalMedia, useRoomConnection };