@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.
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var heresy = require('heresy');
6
- var React = require('react');
7
6
  var tslib = require('tslib');
7
+ var React = require('react');
8
8
  var adapter = require('webrtc-adapter');
9
9
  var io = require('socket.io-client');
10
10
  var SDPUtils = require('sdp');
@@ -94,8 +94,7 @@ heresy.define("WherebyEmbed", {
94
94
  // Commands
95
95
  _postCommand(command, args = []) {
96
96
  if (this.iframe.current) {
97
- const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
98
- this.iframe.current.contentWindow.postMessage({ command, args }, url.origin);
97
+ this.iframe.current.contentWindow.postMessage({ command, args }, this.url.origin);
99
98
  }
100
99
  },
101
100
  startRecording() {
@@ -114,8 +113,7 @@ heresy.define("WherebyEmbed", {
114
113
  this._postCommand("toggle_screenshare", [enabled]);
115
114
  },
116
115
  onmessage({ origin, data }) {
117
- const url = new URL(this.room, `https://${this.subdomain}.whereby.com`);
118
- if (origin !== url.origin)
116
+ if (origin !== this.url.origin)
119
117
  return;
120
118
  const { type, payload: detail } = data;
121
119
  this.dispatchEvent(new CustomEvent(type, { detail }));
@@ -125,36 +123,290 @@ heresy.define("WherebyEmbed", {
125
123
  if (!room)
126
124
  return this.html `Whereby: Missing room attribute.`;
127
125
  // Get subdomain from room URL, or use it specified
128
- const m = /https:\/\/([^.]+)\.whereby.com\/.+/.exec(room);
126
+ const m = /https:\/\/([^.]+)(\.whereby.com|-ip-\d+-\d+-\d+-\d+.hereby.dev:4443)\/.+/.exec(room);
129
127
  const subdomain = (m && m[1]) || this.subdomain;
130
128
  if (!subdomain)
131
129
  return this.html `Whereby: Missing subdomain attr.`;
132
- const url = new URL(room, `https://${subdomain}.whereby.com`);
133
- 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(
130
+ if (!m) {
131
+ return this.html `could not parse URL.`;
132
+ }
133
+ const baseURL = m[2] || `.whereby.com`;
134
+ this.url = new URL(room, `https://${subdomain}${baseURL}`);
135
+ const roomUrl = new URL(room);
136
+ if (roomUrl.searchParams.get("roomKey")) {
137
+ this.url.searchParams.append("roomKey", roomUrl.searchParams.get("roomKey"));
138
+ }
139
+ 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(
134
140
  // add to URL if set in any way
135
141
  (o, v) => (this[v.toLowerCase()] != null ? Object.assign(Object.assign({}, o), { [v]: this[v.toLowerCase()] }) : o), {}))).forEach(([k, v]) => {
136
- if (!url.searchParams.has(k) && typeof v === "string") {
137
- url.searchParams.set(k, v);
142
+ if (!this.url.searchParams.has(k) && typeof v === "string") {
143
+ this.url.searchParams.set(k, v);
138
144
  }
139
145
  });
140
146
  return this.html `
141
147
  <iframe
142
148
  ref=${this.iframe}
143
- src=${url}
149
+ src=${this.url}
144
150
  allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
145
151
  `;
146
152
  },
147
153
  });
148
154
 
149
- var VideoElement = ({ stream, style }) => {
150
- const videoEl = React.useCallback((node) => {
151
- if (node !== null && node.srcObject !== stream) {
152
- node.srcObject = stream;
155
+ var VideoView = (_a) => {
156
+ var { muted, stream } = _a, rest = tslib.__rest(_a, ["muted", "stream"]);
157
+ const videoEl = React.useRef(null);
158
+ React.useEffect(() => {
159
+ if (!videoEl.current) {
160
+ return;
153
161
  }
154
- }, []);
155
- return React__default["default"].createElement("video", { ref: videoEl, autoPlay: true, playsInline: true, style: style });
162
+ if (videoEl.current.srcObject !== stream) {
163
+ videoEl.current.srcObject = stream;
164
+ }
165
+ // Handle muting programatically, not as video attribute
166
+ // https://stackoverflow.com/questions/14111917/html5-video-muted-but-still-playing
167
+ if (videoEl.current.muted !== muted) {
168
+ videoEl.current.muted = Boolean(muted);
169
+ }
170
+ }, [muted, stream, videoEl]);
171
+ return React__default["default"].createElement("video", Object.assign({ ref: videoEl, autoPlay: true, playsInline: true }, rest));
156
172
  };
157
173
 
174
+ const TypedLocalMediaEventTarget = EventTarget;
175
+ class LocalMedia extends TypedLocalMediaEventTarget {
176
+ constructor(constraints) {
177
+ super();
178
+ this._constraints = constraints;
179
+ this.stream = new MediaStream();
180
+ this._rtcManagers = [];
181
+ navigator.mediaDevices.addEventListener("devicechange", this._updateDeviceList.bind(this));
182
+ }
183
+ addRtcManager(rtcManager) {
184
+ this._rtcManagers.push(rtcManager);
185
+ }
186
+ removeRtcManager(rtcManager) {
187
+ this._rtcManagers = this._rtcManagers.filter((r) => r !== rtcManager);
188
+ }
189
+ getCameraDeviceId() {
190
+ var _a;
191
+ return (_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
192
+ }
193
+ getMicrophoneDeviceId() {
194
+ var _a;
195
+ return (_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
196
+ }
197
+ isCameraEnabled() {
198
+ var _a;
199
+ return !!((_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
200
+ }
201
+ isMicrophoneEnabled() {
202
+ var _a;
203
+ return !!((_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
204
+ }
205
+ toggleCameraEnabled(enabled) {
206
+ const videoTrack = this.stream.getVideoTracks()[0];
207
+ if (!videoTrack) {
208
+ return;
209
+ }
210
+ const newValue = enabled !== null && enabled !== void 0 ? enabled : !videoTrack.enabled;
211
+ videoTrack.enabled = newValue;
212
+ this.dispatchEvent(new CustomEvent("camera_enabled", { detail: { enabled: newValue } }));
213
+ }
214
+ toggleMichrophoneEnabled(enabled) {
215
+ const audioTrack = this.stream.getAudioTracks()[0];
216
+ if (!audioTrack) {
217
+ return;
218
+ }
219
+ const newValue = enabled !== null && enabled !== void 0 ? enabled : !audioTrack.enabled;
220
+ audioTrack.enabled = newValue;
221
+ this.dispatchEvent(new CustomEvent("microphone_enabled", { detail: { enabled: newValue } }));
222
+ }
223
+ setCameraDevice(deviceId) {
224
+ return tslib.__awaiter(this, void 0, void 0, function* () {
225
+ const newStream = yield navigator.mediaDevices.getUserMedia({ video: { deviceId } });
226
+ const newVideoTrack = newStream.getVideoTracks()[0];
227
+ if (newVideoTrack) {
228
+ const oldVideoTrack = this.stream.getVideoTracks()[0];
229
+ newVideoTrack.enabled = oldVideoTrack.enabled;
230
+ oldVideoTrack === null || oldVideoTrack === void 0 ? void 0 : oldVideoTrack.stop();
231
+ this._rtcManagers.forEach((rtcManager) => {
232
+ rtcManager.replaceTrack(oldVideoTrack, newVideoTrack);
233
+ });
234
+ this.stream.removeTrack(oldVideoTrack);
235
+ this.stream.addTrack(newVideoTrack);
236
+ }
237
+ this.dispatchEvent(new CustomEvent("stream_updated", {
238
+ detail: { stream: this.stream },
239
+ }));
240
+ });
241
+ }
242
+ setMicrophoneDevice(deviceId) {
243
+ return tslib.__awaiter(this, void 0, void 0, function* () {
244
+ const newStream = yield navigator.mediaDevices.getUserMedia({ audio: { deviceId } });
245
+ const newAudioTrack = newStream.getAudioTracks()[0];
246
+ const oldAudioTrack = this.stream.getAudioTracks()[0];
247
+ if (oldAudioTrack) {
248
+ newAudioTrack.enabled = oldAudioTrack.enabled;
249
+ oldAudioTrack.stop();
250
+ this.stream.removeTrack(oldAudioTrack);
251
+ }
252
+ this._rtcManagers.forEach((rtcManager) => {
253
+ rtcManager.replaceTrack(oldAudioTrack, newAudioTrack);
254
+ });
255
+ this.stream.addTrack(newAudioTrack);
256
+ this.dispatchEvent(new CustomEvent("stream_updated", {
257
+ detail: { stream: this.stream },
258
+ }));
259
+ });
260
+ }
261
+ _updateDeviceList() {
262
+ return tslib.__awaiter(this, void 0, void 0, function* () {
263
+ try {
264
+ const devices = yield navigator.mediaDevices.enumerateDevices();
265
+ this.dispatchEvent(new CustomEvent("device_list_updated", {
266
+ detail: {
267
+ cameraDevices: devices.filter((d) => d.kind === "videoinput"),
268
+ microphoneDevices: devices.filter((d) => d.kind === "audioinput"),
269
+ speakerDevices: devices.filter((d) => d.kind === "audiooutput"),
270
+ },
271
+ }));
272
+ }
273
+ catch (error) {
274
+ this.dispatchEvent(new CustomEvent("device_list_update_error", {
275
+ detail: {
276
+ error,
277
+ },
278
+ }));
279
+ throw error;
280
+ }
281
+ });
282
+ }
283
+ start() {
284
+ return tslib.__awaiter(this, void 0, void 0, function* () {
285
+ const newStream = yield navigator.mediaDevices.getUserMedia(this._constraints);
286
+ newStream.getTracks().forEach((t) => this.stream.addTrack(t));
287
+ this._updateDeviceList();
288
+ this.dispatchEvent(new CustomEvent("stream_updated", {
289
+ detail: { stream: this.stream },
290
+ }));
291
+ return this.stream;
292
+ });
293
+ }
294
+ stop() {
295
+ var _a;
296
+ (_a = this.stream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach((t) => {
297
+ t.stop();
298
+ });
299
+ }
300
+ }
301
+
302
+ const initialState$1 = {
303
+ cameraDeviceError: null,
304
+ cameraDevices: [],
305
+ isSettingCameraDevice: false,
306
+ isSettingMicrophoneDevice: false,
307
+ isStarting: false,
308
+ microphoneDeviceError: null,
309
+ microphoneDevices: [],
310
+ speakerDevices: [],
311
+ startError: null,
312
+ };
313
+ function reducer$1(state, action) {
314
+ switch (action.type) {
315
+ case "DEVICE_LIST_UPDATED":
316
+ return Object.assign(Object.assign({}, state), action.payload);
317
+ case "LOCAL_STREAM_UPDATED":
318
+ return Object.assign(Object.assign({}, state), { currentCameraDeviceId: action.payload.currentCameraDeviceId, currentMicrophoneDeviceId: action.payload.currentMicrophoneDeviceId, localStream: action.payload.stream });
319
+ case "SET_CAMERA_DEVICE":
320
+ return Object.assign(Object.assign({}, state), { cameraDeviceError: null, isSettingCameraDevice: true });
321
+ case "SET_CAMERA_DEVICE_COMPLETE":
322
+ return Object.assign(Object.assign({}, state), { isSettingCameraDevice: false });
323
+ case "SET_CAMERA_DEVICE_ERROR":
324
+ return Object.assign(Object.assign({}, state), { cameraDeviceError: action.payload, isSettingCameraDevice: false });
325
+ case "SET_MICROPHONE_DEVICE":
326
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: true, microphoneDeviceError: null });
327
+ case "SET_MICROPHONE_DEVICE_COMPLETE":
328
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false });
329
+ case "SET_MICROPHONE_DEVICE_ERROR":
330
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false, microphoneDeviceError: action.payload });
331
+ case "START":
332
+ return Object.assign(Object.assign({}, state), { isStarting: true, startError: null });
333
+ case "START_COMPLETE":
334
+ return Object.assign(Object.assign({}, state), { isStarting: false });
335
+ case "START_ERROR":
336
+ return Object.assign(Object.assign({}, state), { isStarting: false, startError: action.payload });
337
+ default:
338
+ return state;
339
+ }
340
+ }
341
+ function useLocalMedia(constraints = { audio: true, video: true }) {
342
+ const [localMedia] = React.useState(() => new LocalMedia(constraints));
343
+ const [state, dispatch] = React.useReducer(reducer$1, initialState$1);
344
+ React.useEffect(() => {
345
+ localMedia.addEventListener("device_list_updated", (e) => {
346
+ const { cameraDevices, microphoneDevices, speakerDevices } = e.detail;
347
+ dispatch({ type: "DEVICE_LIST_UPDATED", payload: { cameraDevices, microphoneDevices, speakerDevices } });
348
+ });
349
+ localMedia.addEventListener("stream_updated", (e) => {
350
+ const { stream } = e.detail;
351
+ dispatch({
352
+ type: "LOCAL_STREAM_UPDATED",
353
+ payload: {
354
+ stream,
355
+ currentCameraDeviceId: localMedia.getCameraDeviceId(),
356
+ currentMicrophoneDeviceId: localMedia.getMicrophoneDeviceId(),
357
+ },
358
+ });
359
+ });
360
+ const start = () => tslib.__awaiter(this, void 0, void 0, function* () {
361
+ dispatch({ type: "START" });
362
+ try {
363
+ yield localMedia.start();
364
+ dispatch({ type: "START_COMPLETE" });
365
+ }
366
+ catch (error) {
367
+ dispatch({ type: "START_ERROR", payload: error });
368
+ }
369
+ });
370
+ start();
371
+ // Perform cleanup on unmount
372
+ return () => {
373
+ localMedia.stop();
374
+ };
375
+ }, []);
376
+ return {
377
+ state,
378
+ actions: {
379
+ setCameraDevice: (...args) => tslib.__awaiter(this, void 0, void 0, function* () {
380
+ dispatch({ type: "SET_CAMERA_DEVICE" });
381
+ try {
382
+ yield localMedia.setCameraDevice(...args);
383
+ dispatch({ type: "SET_CAMERA_DEVICE_COMPLETE" });
384
+ }
385
+ catch (error) {
386
+ dispatch({ type: "SET_CAMERA_DEVICE_ERROR", payload: error });
387
+ }
388
+ }),
389
+ setMicrophoneDevice: (...args) => tslib.__awaiter(this, void 0, void 0, function* () {
390
+ dispatch({ type: "SET_MICROPHONE_DEVICE" });
391
+ try {
392
+ yield localMedia.setMicrophoneDevice(...args);
393
+ dispatch({ type: "SET_MICROPHONE_DEVICE_COMPLETE" });
394
+ }
395
+ catch (error) {
396
+ dispatch({ type: "SET_MICROPHONE_DEVICE_ERROR", payload: error });
397
+ }
398
+ }),
399
+ toggleCameraEnabled: (...args) => {
400
+ return localMedia.toggleCameraEnabled(...args);
401
+ },
402
+ toggleMicrophoneEnabled: (...args) => {
403
+ return localMedia.toggleMichrophoneEnabled(...args);
404
+ },
405
+ },
406
+ _ref: localMedia,
407
+ };
408
+ }
409
+
158
410
  const EVENTS = {
159
411
  CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
160
412
  STREAM_ADDED: "stream_added",
@@ -285,10 +537,10 @@ class ServerSocket {
285
537
  }
286
538
 
287
539
  this._socket = io__default["default"](hostName, options);
288
- this._socket.on("reconnect", () => {
540
+ this._socket.io.on("reconnect", () => {
289
541
  this._socket.sendBuffer = [];
290
542
  });
291
- this._socket.on("reconnect_attempt", () => {
543
+ this._socket.io.on("reconnect_attempt", () => {
292
544
  if (this._wasConnectedUsingWebsocket) {
293
545
  this._socket.io.opts.transports = ["websocket"];
294
546
  // only fallback to polling if not safari
@@ -346,6 +598,10 @@ class ServerSocket {
346
598
  );
347
599
  }
348
600
 
601
+ getManager() {
602
+ return this._socket.io;
603
+ }
604
+
349
605
  isConnecting() {
350
606
  return this._socket && this._socket.connecting;
351
607
  }
@@ -1979,10 +2235,11 @@ class VegaParser {
1979
2235
  }
1980
2236
 
1981
2237
  class VegaConnection extends EventEmitter.EventEmitter {
1982
- constructor(wsUrl, logger) {
2238
+ constructor(wsUrl, logger, protocol = "whereby-sfu#v4") {
1983
2239
  super();
1984
2240
 
1985
2241
  this.wsUrl = wsUrl;
2242
+ this.protocol = protocol;
1986
2243
  this.logger = logger;
1987
2244
 
1988
2245
  // This is the map of sent requests that are waiting for a response
@@ -1991,7 +2248,7 @@ class VegaConnection extends EventEmitter.EventEmitter {
1991
2248
  }
1992
2249
 
1993
2250
  _setupSocket() {
1994
- this.socket = new WebSocket(this.wsUrl, "whereby-sfu#v4");
2251
+ this.socket = new WebSocket(this.wsUrl, this.protocol);
1995
2252
  this.socket.onopen = this._onOpen.bind(this);
1996
2253
  this.socket.onmessage = this._onMessage.bind(this);
1997
2254
  this.socket.onclose = this._onClose.bind(this);
@@ -2011,7 +2268,9 @@ class VegaConnection extends EventEmitter.EventEmitter {
2011
2268
  }
2012
2269
 
2013
2270
  close() {
2014
- this.socket?.close();
2271
+ if (!this.socket) return;
2272
+
2273
+ this.socket.close();
2015
2274
  }
2016
2275
 
2017
2276
  _onOpen() {
@@ -2023,11 +2282,15 @@ class VegaConnection extends EventEmitter.EventEmitter {
2023
2282
  _onMessage(event) {
2024
2283
  const socketMessage = VegaParser.parse(event.data);
2025
2284
 
2285
+ if (!socketMessage) {
2286
+ return this.logger.log("VegaConnectionManager: Received invalid message", event.data);
2287
+ }
2288
+
2026
2289
  this.logger.log("VegaConnectionManager: Received message", socketMessage);
2027
2290
 
2028
- if (socketMessage?.response) {
2291
+ if (socketMessage.response) {
2029
2292
  this._handleResponse(socketMessage);
2030
- } else if (socketMessage?.message) {
2293
+ } else if (socketMessage.message) {
2031
2294
  this.emit("message", socketMessage);
2032
2295
  }
2033
2296
  }
@@ -2134,7 +2397,7 @@ const VIDEO_SETTINGS_VP9 = {
2134
2397
  codecOptions: {
2135
2398
  videoGoogleStartBitrate: 500,
2136
2399
  },
2137
- encodings: [{ scalabilityMode: "S3T3_KEY", networkPriority: "high" }],
2400
+ encodings: [{ scalabilityMode: "L3T2_KEY", networkPriority: "high" }],
2138
2401
  };
2139
2402
 
2140
2403
  const SCREEN_SHARE_SETTINGS = {
@@ -2143,13 +2406,13 @@ const SCREEN_SHARE_SETTINGS = {
2143
2406
 
2144
2407
  const SCREEN_SHARE_SIMULCAST_SETTINGS = {
2145
2408
  encodings: [
2146
- { dtx: true, maxBitrate: 500000 },
2147
- { dtx: true, maxBitrate: 1500000 },
2409
+ { scaleResolutionDownBy: 2, dtx: true, maxBitrate: 500000 },
2410
+ { scaleResolutionDownBy: 1, dtx: true, maxBitrate: 1500000 },
2148
2411
  ],
2149
2412
  };
2150
2413
 
2151
2414
  const SCREEN_SHARE_SETTINGS_VP9 = {
2152
- encodings: [{ scalabilityMode: "S3T3", dtx: true, networkPriority: "high" }],
2415
+ encodings: [{ scalabilityMode: "L1T1", dtx: true, networkPriority: "high" }],
2153
2416
  };
2154
2417
 
2155
2418
  const getMediaSettings = (kind, isScreenShare, features) => {
@@ -2165,8 +2428,8 @@ const getMediaSettings = (kind, isScreenShare, features) => {
2165
2428
 
2166
2429
  return SCREEN_SHARE_SETTINGS;
2167
2430
  } else {
2168
- if (lowDataModeEnabled) return VIDEO_SETTINGS_SD;
2169
2431
  if (vp9On) return VIDEO_SETTINGS_VP9;
2432
+ if (lowDataModeEnabled) return VIDEO_SETTINGS_SD;
2170
2433
 
2171
2434
  return VIDEO_SETTINGS_HD;
2172
2435
  }
@@ -5020,12 +5283,12 @@ class LocalParticipant extends RoomParticipant {
5020
5283
  }
5021
5284
  }
5022
5285
 
5023
- const API_BASE_URL = "https://api.appearin.net";
5286
+ const API_BASE_URL = "https://api.whereby.dev";
5024
5287
  const SIGNAL_BASE_URL = "wss://signal.appearin.net";
5025
5288
  const NON_PERSON_ROLES = ["recorder", "streamer"];
5026
5289
  function createSocket() {
5027
5290
  const parsedUrl = new URL(SIGNAL_BASE_URL);
5028
- const path = `${parsedUrl.pathname.replace(/^\/$/, "")}/protocol/socket.io/v1`;
5291
+ const path = `${parsedUrl.pathname.replace(/^\/$/, "")}/protocol/socket.io/v4`;
5029
5292
  const SOCKET_HOST = parsedUrl.origin;
5030
5293
  const socketConf = {
5031
5294
  host: SOCKET_HOST,
@@ -5033,6 +5296,7 @@ function createSocket() {
5033
5296
  reconnectionDelay: 5000,
5034
5297
  reconnectionDelayMax: 30000,
5035
5298
  timeout: 10000,
5299
+ withCredentials: true,
5036
5300
  };
5037
5301
  return new ServerSocket(SOCKET_HOST, socketConf);
5038
5302
  }
@@ -5041,12 +5305,17 @@ const noop = () => {
5041
5305
  };
5042
5306
  const TypedEventTarget = EventTarget;
5043
5307
  class RoomConnection extends TypedEventTarget {
5044
- constructor(roomUrl, { displayName, localMediaConstraints, localStream, logger }) {
5308
+ constructor(roomUrl, { displayName, localMedia, localMediaConstraints, logger, roomKey }) {
5045
5309
  super();
5046
5310
  this.localParticipant = null;
5047
5311
  this.remoteParticipants = [];
5048
- this.roomConnectionState = "";
5312
+ this._ownsLocalMedia = false;
5313
+ this.organizationId = "";
5314
+ this.roomConnectionStatus = "";
5049
5315
  this.roomUrl = new URL(roomUrl); // Throw if invalid Whereby room url
5316
+ const searchParams = new URLSearchParams(this.roomUrl.search);
5317
+ this._roomKey = roomKey || searchParams.get("roomKey");
5318
+ this.roomName = this.roomUrl.pathname;
5050
5319
  this.logger = logger || {
5051
5320
  debug: noop,
5052
5321
  error: noop,
@@ -5054,10 +5323,20 @@ class RoomConnection extends TypedEventTarget {
5054
5323
  warn: noop,
5055
5324
  };
5056
5325
  this.displayName = displayName;
5057
- this.localStream = localStream;
5058
5326
  this.localMediaConstraints = localMediaConstraints;
5059
5327
  const urls = fromLocation({ host: this.roomUrl.host });
5060
- // Initialize services
5328
+ // Set up local media
5329
+ if (localMedia) {
5330
+ this.localMedia = localMedia;
5331
+ }
5332
+ else if (localMediaConstraints) {
5333
+ this.localMedia = new LocalMedia(localMediaConstraints);
5334
+ this._ownsLocalMedia = true;
5335
+ }
5336
+ else {
5337
+ throw new Error("Missing constraints");
5338
+ }
5339
+ // Set up services
5061
5340
  this.credentialsService = CredentialsService.create({ baseUrl: API_BASE_URL });
5062
5341
  this.apiClient = new ApiClient({
5063
5342
  fetchDeviceCredentials: this.credentialsService.getCredentials.bind(this.credentialsService),
@@ -5079,10 +5358,30 @@ class RoomConnection extends TypedEventTarget {
5079
5358
  // Create signal socket and set up event listeners
5080
5359
  this.signalSocket = createSocket();
5081
5360
  this.signalSocket.on("new_client", this._handleNewClient.bind(this));
5361
+ this.signalSocket.on("chat_message", this._handleNewChatMessage.bind(this));
5082
5362
  this.signalSocket.on("client_left", this._handleClientLeft.bind(this));
5083
5363
  this.signalSocket.on("audio_enabled", this._handleClientAudioEnabled.bind(this));
5084
5364
  this.signalSocket.on("video_enabled", this._handleClientVideoEnabled.bind(this));
5085
5365
  this.signalSocket.on("client_metadata_received", this._handleClientMetadataReceived.bind(this));
5366
+ this.signalSocket.on("knock_handled", this._handleKnockHandled.bind(this));
5367
+ this.signalSocket.on("knocker_left", this._handleKnockerLeft.bind(this));
5368
+ this.signalSocket.on("room_joined", this._handleRoomJoined.bind(this));
5369
+ this.signalSocket.on("room_knocked", this._handleRoomKnocked.bind(this));
5370
+ // Set up local media listeners
5371
+ this.localMedia.addEventListener("camera_enabled", (e) => {
5372
+ const { enabled } = e.detail;
5373
+ this.signalSocket.emit("enable_video", { enabled });
5374
+ });
5375
+ this.localMedia.addEventListener("microphone_enabled", (e) => {
5376
+ const { enabled } = e.detail;
5377
+ this.signalSocket.emit("enable_audio", { enabled });
5378
+ });
5379
+ }
5380
+ get roomKey() {
5381
+ return this._roomKey;
5382
+ }
5383
+ _handleNewChatMessage(message) {
5384
+ this.dispatchEvent(new CustomEvent("chat_message", { detail: message }));
5086
5385
  }
5087
5386
  _handleNewClient({ client }) {
5088
5387
  if (NON_PERSON_ROLES.includes(client.role.roleName)) {
@@ -5128,6 +5427,70 @@ class RoomConnection extends TypedEventTarget {
5128
5427
  detail: { participantId: remoteParticipant.id, displayName },
5129
5428
  }));
5130
5429
  }
5430
+ _handleKnockHandled(payload) {
5431
+ const { resolution } = payload;
5432
+ if (resolution === "accepted") {
5433
+ this.roomConnectionStatus = "accepted";
5434
+ this._roomKey = payload.metadata.roomKey;
5435
+ this._joinRoom();
5436
+ }
5437
+ else if (resolution === "rejected") {
5438
+ this.roomConnectionStatus = "rejected";
5439
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5440
+ detail: {
5441
+ roomConnectionStatus: this.roomConnectionStatus,
5442
+ },
5443
+ }));
5444
+ }
5445
+ }
5446
+ _handleKnockerLeft(payload) {
5447
+ const { clientId } = payload;
5448
+ this.dispatchEvent(new CustomEvent("waiting_participant_left", {
5449
+ detail: { participantId: clientId },
5450
+ }));
5451
+ }
5452
+ _handleRoomJoined(event) {
5453
+ const { error, isLocked, room, selfId } = event;
5454
+ if (error === "room_locked" && isLocked) {
5455
+ this.roomConnectionStatus = "room_locked";
5456
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5457
+ detail: {
5458
+ roomConnectionStatus: this.roomConnectionStatus,
5459
+ },
5460
+ }));
5461
+ return;
5462
+ }
5463
+ // Check if we have an error
5464
+ // Check if it is a room joined error
5465
+ // Set state to connect_failed_locked
5466
+ // Set state to connect_failed_no_host
5467
+ if (room) {
5468
+ const { clients, knockers } = room;
5469
+ const localClient = clients.find((c) => c.id === selfId);
5470
+ if (!localClient)
5471
+ throw new Error("Missing local client");
5472
+ this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localMedia.stream || undefined }));
5473
+ this.remoteParticipants = clients
5474
+ .filter((c) => c.id !== selfId)
5475
+ .map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
5476
+ this.roomConnectionStatus = "connected";
5477
+ this.dispatchEvent(new CustomEvent("room_joined", {
5478
+ detail: {
5479
+ localParticipant: this.localParticipant,
5480
+ remoteParticipants: this.remoteParticipants,
5481
+ waitingParticipants: knockers.map((knocker) => {
5482
+ return { id: knocker.clientId, displayName: knocker.displayName };
5483
+ }),
5484
+ },
5485
+ }));
5486
+ }
5487
+ }
5488
+ _handleRoomKnocked(event) {
5489
+ const { clientId, displayName } = event;
5490
+ this.dispatchEvent(new CustomEvent("waiting_participant_joined", {
5491
+ detail: { participantId: clientId, displayName },
5492
+ }));
5493
+ }
5131
5494
  _handleRtcEvent(eventName, data) {
5132
5495
  if (eventName === "rtc_manager_created") {
5133
5496
  return this._handleRtcManagerCreated(data);
@@ -5140,10 +5503,14 @@ class RoomConnection extends TypedEventTarget {
5140
5503
  }
5141
5504
  }
5142
5505
  _handleRtcManagerCreated({ rtcManager }) {
5143
- var _a, _b, _c;
5506
+ var _a;
5144
5507
  this.rtcManager = rtcManager;
5145
- if (this.localStream) {
5146
- (_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)));
5508
+ this.localMedia.addRtcManager(rtcManager);
5509
+ if (this.localMedia.stream) {
5510
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream("0", this.localMedia.stream, !this.localMedia.isMicrophoneEnabled(), !this.localMedia.isCameraEnabled());
5511
+ }
5512
+ if (this.remoteParticipants.length) {
5513
+ this._handleAcceptStreams(this.remoteParticipants);
5147
5514
  }
5148
5515
  }
5149
5516
  _handleAcceptStreams(remoteParticipants) {
@@ -5168,8 +5535,6 @@ class RoomConnection extends TypedEventTarget {
5168
5535
  if (!newState) {
5169
5536
  return;
5170
5537
  }
5171
- // #endregion
5172
- // #region doAcceptStreams
5173
5538
  if (newState === "to_accept" ||
5174
5539
  (newState === "new_accept" && shouldAcceptNewClients) ||
5175
5540
  (newState === "old_accept" && !shouldAcceptNewClients)) {
@@ -5193,7 +5558,6 @@ class RoomConnection extends TypedEventTarget {
5193
5558
  else ;
5194
5559
  // Update stream state
5195
5560
  participant.updateStreamState(streamId, streamState.replace(/to_|new_|old_/, "done_"));
5196
- // #endregion
5197
5561
  });
5198
5562
  });
5199
5563
  }
@@ -5205,35 +5569,51 @@ class RoomConnection extends TypedEventTarget {
5205
5569
  }
5206
5570
  this.dispatchEvent(new CustomEvent("participant_stream_added", { detail: { participantId: clientId, stream, streamId } }));
5207
5571
  }
5208
- /**
5209
- * Public API
5210
- */
5572
+ _joinRoom() {
5573
+ this.signalSocket.emit("join_room", {
5574
+ avatarUrl: null,
5575
+ config: {
5576
+ isAudioEnabled: this.localMedia.isMicrophoneEnabled(),
5577
+ isVideoEnabled: this.localMedia.isCameraEnabled(),
5578
+ },
5579
+ deviceCapabilities: { canScreenshare: true },
5580
+ displayName: this.displayName,
5581
+ isCoLocated: false,
5582
+ isDevicePermissionDenied: false,
5583
+ kickFromOtherRooms: false,
5584
+ organizationId: this.organizationId,
5585
+ roomKey: this.roomKey,
5586
+ roomName: this.roomName,
5587
+ selfId: "",
5588
+ userAgent: `browser-sdk:${sdkVersion }`,
5589
+ });
5590
+ }
5211
5591
  join() {
5212
5592
  return tslib.__awaiter(this, void 0, void 0, function* () {
5213
- if (["connected", "connecting"].includes(this.roomConnectionState)) {
5214
- console.warn(`Trying to join room state is ${this.roomConnectionState}`);
5593
+ if (["connected", "connecting"].includes(this.roomConnectionStatus)) {
5594
+ console.warn(`Trying to join when room state is already ${this.roomConnectionStatus}`);
5215
5595
  return;
5216
5596
  }
5217
5597
  this.logger.log("Joining room");
5218
- this.roomConnectionState = "connecting";
5219
- if (!this.localStream && this.localMediaConstraints) {
5220
- const localStream = yield navigator.mediaDevices.getUserMedia(this.localMediaConstraints);
5221
- this.localStream = localStream;
5222
- }
5598
+ this.roomConnectionStatus = "connecting";
5599
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5600
+ detail: {
5601
+ roomConnectionStatus: this.roomConnectionStatus,
5602
+ },
5603
+ }));
5223
5604
  const organization = yield this.organizationServiceCache.fetchOrganization();
5224
5605
  if (!organization) {
5225
5606
  throw new Error("Invalid room url");
5226
5607
  }
5227
- // TODO: Get room permissions
5228
- // TODO: Get room features
5608
+ this.organizationId = organization.organizationId;
5609
+ if (this._ownsLocalMedia) {
5610
+ yield this.localMedia.start();
5611
+ }
5229
5612
  const webrtcProvider = {
5230
- getMediaConstraints: () => {
5231
- var _a, _b;
5232
- return ({
5233
- audio: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
5234
- video: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
5235
- });
5236
- },
5613
+ getMediaConstraints: () => ({
5614
+ audio: this.localMedia.isMicrophoneEnabled(),
5615
+ video: this.localMedia.isCameraEnabled(),
5616
+ }),
5237
5617
  deferrable(clientId) {
5238
5618
  return !clientId;
5239
5619
  },
@@ -5256,55 +5636,40 @@ class RoomConnection extends TypedEventTarget {
5256
5636
  });
5257
5637
  // Identify device on signal connection
5258
5638
  const deviceCredentials = yield this.credentialsService.getCredentials();
5259
- // TODO: Handle connection and failed connection properly
5260
- setTimeout(() => {
5261
- this.logger.log("Connected to signal socket");
5262
- this.signalSocket.emit("identify_device", { deviceCredentials });
5263
- }, 2000);
5639
+ this.logger.log("Connected to signal socket");
5640
+ this.signalSocket.emit("identify_device", { deviceCredentials });
5264
5641
  this.signalSocket.once("device_identified", () => {
5265
- var _a, _b;
5266
- this.signalSocket.emit("join_room", {
5267
- avatarUrl: null,
5268
- config: {
5269
- isAudioEnabled: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
5270
- isVideoEnabled: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
5271
- },
5272
- deviceCapabilities: { canScreenshare: true },
5273
- displayName: this.displayName,
5274
- isCoLocated: false,
5275
- isDevicePermissionDenied: false,
5276
- kickFromOtherRooms: false,
5277
- organizationId: organization.organizationId,
5278
- roomKey: null,
5279
- roomName: this.roomUrl.pathname,
5280
- selfId: "",
5281
- });
5282
- });
5283
- this.signalSocket.once("room_joined", (res) => {
5284
- const { selfId, room: { clients }, } = res;
5285
- const localClient = clients.find((c) => c.id === selfId);
5286
- if (!localClient)
5287
- throw new Error("Missing local client");
5288
- this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localStream }));
5289
- this.remoteParticipants = clients
5290
- .filter((c) => c.id !== selfId)
5291
- .map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
5292
- // Accept remote streams if RTC manager has been initialized
5293
- if (this.rtcManager) {
5294
- this._handleAcceptStreams(this.remoteParticipants);
5295
- }
5296
- this.roomConnectionState = "connected";
5297
- this.dispatchEvent(new CustomEvent("room_joined", {
5298
- detail: {
5299
- localParticipant: this.localParticipant,
5300
- remoteParticipants: this.remoteParticipants,
5301
- },
5302
- }));
5642
+ this._joinRoom();
5303
5643
  });
5304
5644
  });
5305
5645
  }
5646
+ knock() {
5647
+ this.roomConnectionStatus = "knocking";
5648
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
5649
+ detail: {
5650
+ roomConnectionStatus: this.roomConnectionStatus,
5651
+ },
5652
+ }));
5653
+ this.signalSocket.emit("knock_room", {
5654
+ displayName: this.displayName,
5655
+ imageUrl: null,
5656
+ kickFromOtherRooms: true,
5657
+ liveVideo: false,
5658
+ organizationId: this.organizationId,
5659
+ roomKey: this._roomKey,
5660
+ roomName: this.roomName,
5661
+ });
5662
+ }
5306
5663
  leave() {
5307
5664
  return new Promise((resolve) => {
5665
+ if (this._ownsLocalMedia) {
5666
+ this.localMedia.stop();
5667
+ }
5668
+ if (this.rtcManager) {
5669
+ this.localMedia.removeRtcManager(this.rtcManager);
5670
+ this.rtcManager.disconnectAll();
5671
+ this.rtcManager = undefined;
5672
+ }
5308
5673
  if (!this.signalSocket) {
5309
5674
  return resolve();
5310
5675
  }
@@ -5319,29 +5684,10 @@ class RoomConnection extends TypedEventTarget {
5319
5684
  });
5320
5685
  });
5321
5686
  }
5322
- toggleCamera(enabled) {
5323
- var _a;
5324
- const localVideoTrack = (_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks()[0];
5325
- if (!localVideoTrack) {
5326
- this.logger.log("Tried toggling non-existing video track");
5327
- return;
5328
- }
5329
- // TODO: Do stopOrResumeVideo
5330
- const newValue = enabled !== null && enabled !== void 0 ? enabled : !localVideoTrack.enabled;
5331
- localVideoTrack.enabled = newValue;
5332
- this.signalSocket.emit("enable_video", { enabled: newValue });
5333
- }
5334
- toggleMicrophone(enabled) {
5335
- var _a;
5336
- const localAudioTrack = (_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks()[0];
5337
- if (!localAudioTrack) {
5338
- this.logger.log("Tried toggling non-existing audio track");
5339
- return;
5340
- }
5341
- // TODO: Do stopOrResumeAudio
5342
- const newValue = enabled !== null && enabled !== void 0 ? enabled : !localAudioTrack.enabled;
5343
- localAudioTrack.enabled = newValue;
5344
- this.signalSocket.emit("enable_audio", { enabled: newValue });
5687
+ sendChatMessage(text) {
5688
+ this.signalSocket.emit("chat_message", {
5689
+ text,
5690
+ });
5345
5691
  }
5346
5692
  setDisplayName(displayName) {
5347
5693
  this.signalSocket.emit("send_client_metadata", {
@@ -5351,8 +5697,31 @@ class RoomConnection extends TypedEventTarget {
5351
5697
  },
5352
5698
  });
5353
5699
  }
5700
+ acceptWaitingParticipant(participantId) {
5701
+ this.signalSocket.emit("handle_knock", {
5702
+ action: "accept",
5703
+ clientId: participantId,
5704
+ response: {},
5705
+ });
5706
+ }
5707
+ rejectWaitingParticipant(participantId) {
5708
+ this.signalSocket.emit("handle_knock", {
5709
+ action: "reject",
5710
+ clientId: participantId,
5711
+ response: {},
5712
+ });
5713
+ }
5354
5714
  }
5355
5715
 
5716
+ const initialState = {
5717
+ chatMessages: [],
5718
+ roomConnectionStatus: "",
5719
+ isJoining: false,
5720
+ joinError: null,
5721
+ mostRecentChatMessage: null,
5722
+ remoteParticipants: [],
5723
+ waitingParticipants: [],
5724
+ };
5356
5725
  function updateParticipant(remoteParticipants, participantId, updates) {
5357
5726
  const existingParticipant = remoteParticipants.find((p) => p.id === participantId);
5358
5727
  if (!existingParticipant) {
@@ -5367,8 +5736,12 @@ function updateParticipant(remoteParticipants, participantId, updates) {
5367
5736
  }
5368
5737
  function reducer(state, action) {
5369
5738
  switch (action.type) {
5739
+ case "CHAT_MESSAGE":
5740
+ return Object.assign(Object.assign({}, state), { chatMessages: [...state.chatMessages, action.payload], mostRecentChatMessage: action.payload });
5370
5741
  case "ROOM_JOINED":
5371
- return Object.assign(Object.assign({}, state), { localParticipant: action.payload.localParticipant, remoteParticipants: action.payload.remoteParticipants, roomConnectionStatus: "connected" });
5742
+ return Object.assign(Object.assign({}, state), { localParticipant: action.payload.localParticipant, remoteParticipants: action.payload.remoteParticipants, waitingParticipants: action.payload.waitingParticipants, roomConnectionStatus: "connected" });
5743
+ case "ROOM_CONNECTION_STATUS_CHANGED":
5744
+ return Object.assign(Object.assign({}, state), { roomConnectionStatus: action.payload.roomConnectionStatus });
5372
5745
  case "PARTICIPANT_AUDIO_ENABLED":
5373
5746
  return Object.assign(Object.assign({}, state), { remoteParticipants: updateParticipant(state.remoteParticipants, action.payload.participantId, {
5374
5747
  isAudioEnabled: action.payload.isAudioEnabled,
@@ -5393,21 +5766,28 @@ function reducer(state, action) {
5393
5766
  if (!state.localParticipant)
5394
5767
  return state;
5395
5768
  return Object.assign(Object.assign({}, state), { localParticipant: Object.assign(Object.assign({}, state.localParticipant), { displayName: action.payload.displayName }) });
5769
+ case "WAITING_PARTICIPANT_JOINED":
5770
+ return Object.assign(Object.assign({}, state), { waitingParticipants: [
5771
+ ...state.waitingParticipants,
5772
+ { id: action.payload.participantId, displayName: action.payload.displayName },
5773
+ ] });
5774
+ case "WAITING_PARTICIPANT_LEFT":
5775
+ return Object.assign(Object.assign({}, state), { waitingParticipants: state.waitingParticipants.filter((wp) => wp.id !== action.payload.participantId) });
5396
5776
  default:
5397
5777
  throw state;
5398
5778
  }
5399
- }
5400
-
5779
+ }
5401
5780
  function useRoomConnection(roomUrl, roomConnectionOptions) {
5402
- const [roomConnection, setRoomConnection] = React.useState(null);
5403
- const [state, dispatch] = React.useReducer(reducer, { remoteParticipants: [] });
5404
- React.useEffect(() => {
5405
- setRoomConnection(new RoomConnection(roomUrl, roomConnectionOptions));
5406
- }, [roomUrl]);
5781
+ const [roomConnection] = React.useState(() => {
5782
+ var _a;
5783
+ 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 }));
5784
+ });
5785
+ const [state, dispatch] = React.useReducer(reducer, initialState);
5407
5786
  React.useEffect(() => {
5408
- if (!roomConnection) {
5409
- return;
5410
- }
5787
+ roomConnection.addEventListener("chat_message", (e) => {
5788
+ const chatMessage = e.detail;
5789
+ dispatch({ type: "CHAT_MESSAGE", payload: chatMessage });
5790
+ });
5411
5791
  roomConnection.addEventListener("participant_audio_enabled", (e) => {
5412
5792
  const { participantId, isAudioEnabled } = e.detail;
5413
5793
  dispatch({ type: "PARTICIPANT_AUDIO_ENABLED", payload: { participantId, isAudioEnabled } });
@@ -5424,9 +5804,13 @@ function useRoomConnection(roomUrl, roomConnectionOptions) {
5424
5804
  const { participantId, stream } = e.detail;
5425
5805
  dispatch({ type: "PARTICIPANT_STREAM_ADDED", payload: { participantId, stream } });
5426
5806
  });
5807
+ roomConnection.addEventListener("room_connection_status_changed", (e) => {
5808
+ const { roomConnectionStatus } = e.detail;
5809
+ dispatch({ type: "ROOM_CONNECTION_STATUS_CHANGED", payload: { roomConnectionStatus } });
5810
+ });
5427
5811
  roomConnection.addEventListener("room_joined", (e) => {
5428
- const { localParticipant, remoteParticipants } = e.detail;
5429
- dispatch({ type: "ROOM_JOINED", payload: { localParticipant, remoteParticipants } });
5812
+ const { localParticipant, remoteParticipants, waitingParticipants } = e.detail;
5813
+ dispatch({ type: "ROOM_JOINED", payload: { localParticipant, remoteParticipants, waitingParticipants } });
5430
5814
  });
5431
5815
  roomConnection.addEventListener("participant_video_enabled", (e) => {
5432
5816
  const { participantId, isVideoEnabled } = e.detail;
@@ -5436,32 +5820,55 @@ function useRoomConnection(roomUrl, roomConnectionOptions) {
5436
5820
  const { participantId, displayName } = e.detail;
5437
5821
  dispatch({ type: "PARTICIPANT_METADATA_CHANGED", payload: { participantId, displayName } });
5438
5822
  });
5823
+ roomConnection.addEventListener("waiting_participant_joined", (e) => {
5824
+ const { participantId, displayName } = e.detail;
5825
+ dispatch({ type: "WAITING_PARTICIPANT_JOINED", payload: { participantId, displayName } });
5826
+ });
5827
+ roomConnection.addEventListener("waiting_participant_left", (e) => {
5828
+ const { participantId } = e.detail;
5829
+ dispatch({ type: "WAITING_PARTICIPANT_LEFT", payload: { participantId } });
5830
+ });
5439
5831
  roomConnection.join();
5440
5832
  return () => {
5441
5833
  roomConnection.leave();
5442
5834
  };
5443
- }, [roomConnection]);
5444
- return [
5835
+ }, []);
5836
+ return {
5445
5837
  state,
5446
- {
5447
- toggleCamera: (enabled) => {
5448
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.toggleCamera(enabled);
5838
+ actions: {
5839
+ knock: () => {
5840
+ roomConnection.knock();
5449
5841
  },
5450
- toggleMicrophone: (enabled) => {
5451
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.toggleMicrophone(enabled);
5842
+ sendChatMessage: (text) => {
5843
+ roomConnection.sendChatMessage(text);
5452
5844
  },
5453
5845
  setDisplayName: (displayName) => {
5454
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.setDisplayName(displayName);
5846
+ roomConnection.setDisplayName(displayName);
5455
5847
  dispatch({ type: "LOCAL_CLIENT_DISPLAY_NAME_CHANGED", payload: { displayName } });
5456
5848
  },
5849
+ toggleCamera: (enabled) => {
5850
+ roomConnection.localMedia.toggleCameraEnabled(enabled);
5851
+ },
5852
+ toggleMicrophone: (enabled) => {
5853
+ roomConnection.localMedia.toggleMichrophoneEnabled(enabled);
5854
+ },
5855
+ acceptWaitingParticipant: (participantId) => {
5856
+ roomConnection.acceptWaitingParticipant(participantId);
5857
+ },
5858
+ rejectWaitingParticipant: (participantId) => {
5859
+ roomConnection.rejectWaitingParticipant(participantId);
5860
+ },
5457
5861
  },
5458
- {
5459
- VideoView: VideoElement,
5862
+ components: {
5863
+ VideoView,
5460
5864
  },
5461
- ];
5865
+ _ref: roomConnection,
5866
+ };
5462
5867
  }
5463
5868
 
5464
- const sdkVersion = "2.0.0-alpha1";
5869
+ const sdkVersion = "2.0.0-alpha11";
5465
5870
 
5871
+ exports.VideoView = VideoView;
5466
5872
  exports.sdkVersion = sdkVersion;
5873
+ exports.useLocalMedia = useLocalMedia;
5467
5874
  exports.useRoomConnection = useRoomConnection;