@whereby.com/browser-sdk 2.0.0-alpha5 → 2.0.0-alpha6

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
@@ -115,7 +115,7 @@ define("WherebyEmbed", {
115
115
  if (!subdomain)
116
116
  return this.html `Whereby: Missing subdomain attr.`;
117
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-alpha5", iframeSource: subdomain }, (displayName && { displayName })), (lang && { lang })), (metadata && { metadata })), (groups && { groups })), (virtualBackgroundUrl && { virtualBackgroundUrl })), (avatarUrl && { avatarUrl })), (minimal != null && { embed: minimal })), boolAttrs.reduce(
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-alpha6", iframeSource: subdomain }, (displayName && { displayName })), (lang && { lang })), (metadata && { metadata })), (groups && { groups })), (virtualBackgroundUrl && { virtualBackgroundUrl })), (avatarUrl && { avatarUrl })), (minimal != null && { embed: minimal })), boolAttrs.reduce(
119
119
  // add to URL if set in any way
120
120
  (o, v) => (this[v.toLowerCase()] != null ? Object.assign(Object.assign({}, o), { [v]: this[v.toLowerCase()] }) : o), {}))).forEach(([k, v]) => {
121
121
  if (!url.searchParams.has(k) && typeof v === "string") {
@@ -150,6 +150,242 @@ var VideoView = (_a) => {
150
150
  return React.createElement("video", Object.assign({ ref: videoEl, autoPlay: true, playsInline: true }, rest));
151
151
  };
152
152
 
153
+ const TypedLocalMediaEventTarget = EventTarget;
154
+ class LocalMedia extends TypedLocalMediaEventTarget {
155
+ constructor(constraints) {
156
+ super();
157
+ this._constraints = constraints;
158
+ this.stream = new MediaStream();
159
+ this._rtcManagers = [];
160
+ navigator.mediaDevices.addEventListener("devicechange", this._updateDeviceList.bind(this));
161
+ }
162
+ addRtcManager(rtcManager) {
163
+ this._rtcManagers.push(rtcManager);
164
+ }
165
+ removeRtcManager(rtcManager) {
166
+ this._rtcManagers = this._rtcManagers.filter((r) => r !== rtcManager);
167
+ }
168
+ getCameraDeviceId() {
169
+ var _a;
170
+ return (_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
171
+ }
172
+ getMicrophoneDeviceId() {
173
+ var _a;
174
+ return (_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.getSettings().deviceId;
175
+ }
176
+ isCameraEnabled() {
177
+ var _a;
178
+ return !!((_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
179
+ }
180
+ isMicrophoneEnabled() {
181
+ var _a;
182
+ return !!((_a = this.stream.getAudioTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled);
183
+ }
184
+ toggleCameraEnabled(enabled) {
185
+ const videoTrack = this.stream.getVideoTracks()[0];
186
+ if (!videoTrack) {
187
+ return;
188
+ }
189
+ const newValue = enabled !== null && enabled !== void 0 ? enabled : !videoTrack.enabled;
190
+ videoTrack.enabled = newValue;
191
+ this.dispatchEvent(new CustomEvent("camera_enabled", { detail: { enabled: newValue } }));
192
+ }
193
+ toggleMichrophoneEnabled(enabled) {
194
+ const audioTrack = this.stream.getAudioTracks()[0];
195
+ if (!audioTrack) {
196
+ return;
197
+ }
198
+ const newValue = enabled !== null && enabled !== void 0 ? enabled : !audioTrack.enabled;
199
+ audioTrack.enabled = newValue;
200
+ this.dispatchEvent(new CustomEvent("microphone_enabled", { detail: { enabled: newValue } }));
201
+ }
202
+ setCameraDevice(deviceId) {
203
+ return __awaiter(this, void 0, void 0, function* () {
204
+ const newStream = yield navigator.mediaDevices.getUserMedia({ video: { deviceId } });
205
+ const newVideoTrack = newStream.getVideoTracks()[0];
206
+ if (newVideoTrack) {
207
+ const oldVideoTrack = this.stream.getVideoTracks()[0];
208
+ newVideoTrack.enabled = oldVideoTrack.enabled;
209
+ oldVideoTrack === null || oldVideoTrack === void 0 ? void 0 : oldVideoTrack.stop();
210
+ this._rtcManagers.forEach((rtcManager) => {
211
+ rtcManager.replaceTrack(oldVideoTrack, newVideoTrack);
212
+ });
213
+ this.stream.removeTrack(oldVideoTrack);
214
+ this.stream.addTrack(newVideoTrack);
215
+ }
216
+ this.dispatchEvent(new CustomEvent("stream_updated", {
217
+ detail: { stream: this.stream },
218
+ }));
219
+ });
220
+ }
221
+ setMicrophoneDevice(deviceId) {
222
+ return __awaiter(this, void 0, void 0, function* () {
223
+ const newStream = yield navigator.mediaDevices.getUserMedia({ audio: { deviceId } });
224
+ const newAudioTrack = newStream.getAudioTracks()[0];
225
+ const oldAudioTrack = this.stream.getAudioTracks()[0];
226
+ if (oldAudioTrack) {
227
+ newAudioTrack.enabled = oldAudioTrack.enabled;
228
+ oldAudioTrack.stop();
229
+ this.stream.removeTrack(oldAudioTrack);
230
+ }
231
+ this._rtcManagers.forEach((rtcManager) => {
232
+ rtcManager.replaceTrack(oldAudioTrack, newAudioTrack);
233
+ });
234
+ this.stream.addTrack(newAudioTrack);
235
+ this.dispatchEvent(new CustomEvent("stream_updated", {
236
+ detail: { stream: this.stream },
237
+ }));
238
+ });
239
+ }
240
+ _updateDeviceList() {
241
+ return __awaiter(this, void 0, void 0, function* () {
242
+ try {
243
+ const devices = yield navigator.mediaDevices.enumerateDevices();
244
+ this.dispatchEvent(new CustomEvent("device_list_updated", {
245
+ detail: {
246
+ cameraDevices: devices.filter((d) => d.kind === "videoinput"),
247
+ microphoneDevices: devices.filter((d) => d.kind === "audioinput"),
248
+ speakerDevices: devices.filter((d) => d.kind === "audiooutput"),
249
+ },
250
+ }));
251
+ }
252
+ catch (error) {
253
+ this.dispatchEvent(new CustomEvent("device_list_update_error", {
254
+ detail: {
255
+ error,
256
+ },
257
+ }));
258
+ throw error;
259
+ }
260
+ });
261
+ }
262
+ start() {
263
+ return __awaiter(this, void 0, void 0, function* () {
264
+ const newStream = yield navigator.mediaDevices.getUserMedia(this._constraints);
265
+ newStream.getTracks().forEach((t) => this.stream.addTrack(t));
266
+ this._updateDeviceList();
267
+ this.dispatchEvent(new CustomEvent("stream_updated", {
268
+ detail: { stream: this.stream },
269
+ }));
270
+ return this.stream;
271
+ });
272
+ }
273
+ stop() {
274
+ var _a;
275
+ (_a = this.stream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach((t) => {
276
+ t.stop();
277
+ });
278
+ }
279
+ }
280
+
281
+ const initialState = {
282
+ cameraDeviceError: null,
283
+ cameraDevices: [],
284
+ isSettingCameraDevice: false,
285
+ isSettingMicrophoneDevice: false,
286
+ isStarting: false,
287
+ microphoneDeviceError: null,
288
+ microphoneDevices: [],
289
+ speakerDevices: [],
290
+ startError: null,
291
+ };
292
+ function reducer$1(state, action) {
293
+ switch (action.type) {
294
+ case "DEVICE_LIST_UPDATED":
295
+ return Object.assign(Object.assign({}, state), action.payload);
296
+ case "LOCAL_STREAM_UPDATED":
297
+ return Object.assign(Object.assign({}, state), { currentCameraDeviceId: action.payload.currentCameraDeviceId, currentMicrophoneDeviceId: action.payload.currentMicrophoneDeviceId, localStream: action.payload.stream });
298
+ case "SET_CAMERA_DEVICE":
299
+ return Object.assign(Object.assign({}, state), { cameraDeviceError: null, isSettingCameraDevice: true });
300
+ case "SET_CAMERA_DEVICE_COMPLETE":
301
+ return Object.assign(Object.assign({}, state), { isSettingCameraDevice: false });
302
+ case "SET_CAMERA_DEVICE_ERROR":
303
+ return Object.assign(Object.assign({}, state), { cameraDeviceError: action.payload, isSettingCameraDevice: false });
304
+ case "SET_MICROPHONE_DEVICE":
305
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: true, microphoneDeviceError: null });
306
+ case "SET_MICROPHONE_DEVICE_COMPLETE":
307
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false });
308
+ case "SET_MICROPHONE_DEVICE_ERROR":
309
+ return Object.assign(Object.assign({}, state), { isSettingMicrophoneDevice: false, microphoneDeviceError: action.payload });
310
+ case "START":
311
+ return Object.assign(Object.assign({}, state), { isStarting: true, startError: null });
312
+ case "START_COMPLETE":
313
+ return Object.assign(Object.assign({}, state), { isStarting: false });
314
+ case "START_ERROR":
315
+ return Object.assign(Object.assign({}, state), { isStarting: false, startError: action.payload });
316
+ default:
317
+ return state;
318
+ }
319
+ }
320
+ function useLocalMedia(constraints = { audio: true, video: true }) {
321
+ const [localMedia] = useState(() => new LocalMedia(constraints));
322
+ const [state, dispatch] = useReducer(reducer$1, initialState);
323
+ useEffect(() => {
324
+ localMedia.addEventListener("device_list_updated", (e) => {
325
+ const { cameraDevices, microphoneDevices, speakerDevices } = e.detail;
326
+ dispatch({ type: "DEVICE_LIST_UPDATED", payload: { cameraDevices, microphoneDevices, speakerDevices } });
327
+ });
328
+ localMedia.addEventListener("stream_updated", (e) => {
329
+ const { stream } = e.detail;
330
+ dispatch({
331
+ type: "LOCAL_STREAM_UPDATED",
332
+ payload: {
333
+ stream,
334
+ currentCameraDeviceId: localMedia.getCameraDeviceId(),
335
+ currentMicrophoneDeviceId: localMedia.getMicrophoneDeviceId(),
336
+ },
337
+ });
338
+ });
339
+ const start = () => __awaiter(this, void 0, void 0, function* () {
340
+ dispatch({ type: "START" });
341
+ try {
342
+ yield localMedia.start();
343
+ dispatch({ type: "START_COMPLETE" });
344
+ }
345
+ catch (error) {
346
+ dispatch({ type: "START_ERROR", payload: error });
347
+ }
348
+ });
349
+ start();
350
+ // Perform cleanup on unmount
351
+ return () => {
352
+ localMedia.stop();
353
+ };
354
+ }, []);
355
+ return {
356
+ state,
357
+ actions: {
358
+ setCameraDevice: (...args) => __awaiter(this, void 0, void 0, function* () {
359
+ dispatch({ type: "SET_CAMERA_DEVICE" });
360
+ try {
361
+ yield localMedia.setCameraDevice(...args);
362
+ dispatch({ type: "SET_CAMERA_DEVICE_COMPLETE" });
363
+ }
364
+ catch (error) {
365
+ dispatch({ type: "SET_CAMERA_DEVICE_ERROR", payload: error });
366
+ }
367
+ }),
368
+ setMicrophoneDevice: (...args) => __awaiter(this, void 0, void 0, function* () {
369
+ dispatch({ type: "SET_MICROPHONE_DEVICE" });
370
+ try {
371
+ yield localMedia.setMicrophoneDevice(...args);
372
+ dispatch({ type: "SET_MICROPHONE_DEVICE_COMPLETE" });
373
+ }
374
+ catch (error) {
375
+ dispatch({ type: "SET_MICROPHONE_DEVICE_ERROR", payload: error });
376
+ }
377
+ }),
378
+ toggleCameraEnabled: (...args) => {
379
+ return localMedia.toggleCameraEnabled(...args);
380
+ },
381
+ toggleMicrophoneEnabled: (...args) => {
382
+ return localMedia.toggleMichrophoneEnabled(...args);
383
+ },
384
+ },
385
+ _ref: localMedia,
386
+ };
387
+ }
388
+
153
389
  const EVENTS = {
154
390
  CLIENT_CONNECTION_STATUS_CHANGED: "client_connection_status_changed",
155
391
  STREAM_ADDED: "stream_added",
@@ -5036,11 +5272,12 @@ const noop = () => {
5036
5272
  };
5037
5273
  const TypedEventTarget = EventTarget;
5038
5274
  class RoomConnection extends TypedEventTarget {
5039
- constructor(roomUrl, { displayName, localMediaConstraints, localStream, logger }) {
5275
+ constructor(roomUrl, { displayName, localMediaConstraints, logger, localMedia }) {
5040
5276
  super();
5041
5277
  this.localParticipant = null;
5042
5278
  this.remoteParticipants = [];
5043
5279
  this.roomConnectionState = "";
5280
+ this._ownsLocalMedia = false;
5044
5281
  this.roomUrl = new URL(roomUrl); // Throw if invalid Whereby room url
5045
5282
  this.logger = logger || {
5046
5283
  debug: noop,
@@ -5049,10 +5286,19 @@ class RoomConnection extends TypedEventTarget {
5049
5286
  warn: noop,
5050
5287
  };
5051
5288
  this.displayName = displayName;
5052
- this.localStream = localStream;
5053
5289
  this.localMediaConstraints = localMediaConstraints;
5054
5290
  const urls = fromLocation({ host: this.roomUrl.host });
5055
- // Initialize services
5291
+ // Set up local media
5292
+ if (localMedia) {
5293
+ this.localMedia = localMedia;
5294
+ }
5295
+ else if (localMediaConstraints) {
5296
+ this.localMedia = new LocalMedia(localMediaConstraints);
5297
+ this._ownsLocalMedia = true;
5298
+ }
5299
+ else {
5300
+ throw new Error("Missing constraints");
5301
+ }
5056
5302
  this.credentialsService = CredentialsService.create({ baseUrl: API_BASE_URL });
5057
5303
  this.apiClient = new ApiClient({
5058
5304
  fetchDeviceCredentials: this.credentialsService.getCredentials.bind(this.credentialsService),
@@ -5078,6 +5324,15 @@ class RoomConnection extends TypedEventTarget {
5078
5324
  this.signalSocket.on("audio_enabled", this._handleClientAudioEnabled.bind(this));
5079
5325
  this.signalSocket.on("video_enabled", this._handleClientVideoEnabled.bind(this));
5080
5326
  this.signalSocket.on("client_metadata_received", this._handleClientMetadataReceived.bind(this));
5327
+ // Set up local media listeners
5328
+ this.localMedia.addEventListener("camera_enabled", (e) => {
5329
+ const { enabled } = e.detail;
5330
+ this.signalSocket.emit("enable_video", { enabled });
5331
+ });
5332
+ this.localMedia.addEventListener("microphone_enabled", (e) => {
5333
+ const { enabled } = e.detail;
5334
+ this.signalSocket.emit("enable_audio", { enabled });
5335
+ });
5081
5336
  }
5082
5337
  _handleNewClient({ client }) {
5083
5338
  if (NON_PERSON_ROLES.includes(client.role.roleName)) {
@@ -5135,10 +5390,11 @@ class RoomConnection extends TypedEventTarget {
5135
5390
  }
5136
5391
  }
5137
5392
  _handleRtcManagerCreated({ rtcManager }) {
5138
- var _a, _b, _c;
5393
+ var _a;
5139
5394
  this.rtcManager = rtcManager;
5140
- if (this.localStream) {
5141
- (_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)));
5395
+ this.localMedia.addRtcManager(rtcManager);
5396
+ if (this.localMedia.stream) {
5397
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream("0", this.localMedia.stream, !this.localMedia.isMicrophoneEnabled(), !this.localMedia.isCameraEnabled());
5142
5398
  }
5143
5399
  }
5144
5400
  _handleAcceptStreams(remoteParticipants) {
@@ -5163,8 +5419,6 @@ class RoomConnection extends TypedEventTarget {
5163
5419
  if (!newState) {
5164
5420
  return;
5165
5421
  }
5166
- // #endregion
5167
- // #region doAcceptStreams
5168
5422
  if (newState === "to_accept" ||
5169
5423
  (newState === "new_accept" && shouldAcceptNewClients) ||
5170
5424
  (newState === "old_accept" && !shouldAcceptNewClients)) {
@@ -5188,7 +5442,6 @@ class RoomConnection extends TypedEventTarget {
5188
5442
  else ;
5189
5443
  // Update stream state
5190
5444
  participant.updateStreamState(streamId, streamState.replace(/to_|new_|old_/, "done_"));
5191
- // #endregion
5192
5445
  });
5193
5446
  });
5194
5447
  }
@@ -5200,9 +5453,6 @@ class RoomConnection extends TypedEventTarget {
5200
5453
  }
5201
5454
  this.dispatchEvent(new CustomEvent("participant_stream_added", { detail: { participantId: clientId, stream, streamId } }));
5202
5455
  }
5203
- /**
5204
- * Public API
5205
- */
5206
5456
  join() {
5207
5457
  return __awaiter(this, void 0, void 0, function* () {
5208
5458
  if (["connected", "connecting"].includes(this.roomConnectionState)) {
@@ -5211,24 +5461,16 @@ class RoomConnection extends TypedEventTarget {
5211
5461
  }
5212
5462
  this.logger.log("Joining room");
5213
5463
  this.roomConnectionState = "connecting";
5214
- if (!this.localStream && this.localMediaConstraints) {
5215
- const localStream = yield navigator.mediaDevices.getUserMedia(this.localMediaConstraints);
5216
- this.localStream = localStream;
5217
- }
5218
- const organization = yield this.organizationServiceCache.fetchOrganization();
5219
- if (!organization) {
5220
- throw new Error("Invalid room url");
5464
+ if (this._ownsLocalMedia) {
5465
+ yield this.localMedia.start();
5221
5466
  }
5222
5467
  // TODO: Get room permissions
5223
5468
  // TODO: Get room features
5224
5469
  const webrtcProvider = {
5225
- getMediaConstraints: () => {
5226
- var _a, _b;
5227
- return ({
5228
- audio: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
5229
- video: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
5230
- });
5231
- },
5470
+ getMediaConstraints: () => ({
5471
+ audio: this.localMedia.isMicrophoneEnabled(),
5472
+ video: this.localMedia.isCameraEnabled(),
5473
+ }),
5232
5474
  deferrable(clientId) {
5233
5475
  return !clientId;
5234
5476
  },
@@ -5249,6 +5491,10 @@ class RoomConnection extends TypedEventTarget {
5249
5491
  simulcastScreenshareOn: false,
5250
5492
  },
5251
5493
  });
5494
+ const organization = yield this.organizationServiceCache.fetchOrganization();
5495
+ if (!organization) {
5496
+ throw new Error("Invalid room url");
5497
+ }
5252
5498
  // Identify device on signal connection
5253
5499
  const deviceCredentials = yield this.credentialsService.getCredentials();
5254
5500
  // TODO: Handle connection and failed connection properly
@@ -5257,12 +5503,11 @@ class RoomConnection extends TypedEventTarget {
5257
5503
  this.signalSocket.emit("identify_device", { deviceCredentials });
5258
5504
  }, 2000);
5259
5505
  this.signalSocket.once("device_identified", () => {
5260
- var _a, _b;
5261
5506
  this.signalSocket.emit("join_room", {
5262
5507
  avatarUrl: null,
5263
5508
  config: {
5264
- isAudioEnabled: !!((_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().find((t) => t.enabled)),
5265
- isVideoEnabled: !!((_b = this.localStream) === null || _b === void 0 ? void 0 : _b.getVideoTracks().find((t) => t.enabled)),
5509
+ isAudioEnabled: this.localMedia.isMicrophoneEnabled(),
5510
+ isVideoEnabled: this.localMedia.isCameraEnabled(),
5266
5511
  },
5267
5512
  deviceCapabilities: { canScreenshare: true },
5268
5513
  displayName: this.displayName,
@@ -5273,7 +5518,7 @@ class RoomConnection extends TypedEventTarget {
5273
5518
  roomKey: null,
5274
5519
  roomName: this.roomUrl.pathname,
5275
5520
  selfId: "",
5276
- userAgent: `browser-sdk:${sdkVersion }`
5521
+ userAgent: `browser-sdk:${sdkVersion }`,
5277
5522
  });
5278
5523
  });
5279
5524
  this.signalSocket.once("room_joined", (res) => {
@@ -5281,7 +5526,7 @@ class RoomConnection extends TypedEventTarget {
5281
5526
  const localClient = clients.find((c) => c.id === selfId);
5282
5527
  if (!localClient)
5283
5528
  throw new Error("Missing local client");
5284
- this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localStream }));
5529
+ this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localMedia.stream || undefined }));
5285
5530
  this.remoteParticipants = clients
5286
5531
  .filter((c) => c.id !== selfId)
5287
5532
  .map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
@@ -5301,6 +5546,14 @@ class RoomConnection extends TypedEventTarget {
5301
5546
  }
5302
5547
  leave() {
5303
5548
  return new Promise((resolve) => {
5549
+ if (this._ownsLocalMedia) {
5550
+ this.localMedia.stop();
5551
+ }
5552
+ if (this.rtcManager) {
5553
+ this.localMedia.removeRtcManager(this.rtcManager);
5554
+ this.rtcManager.disconnectAll();
5555
+ this.rtcManager = undefined;
5556
+ }
5304
5557
  if (!this.signalSocket) {
5305
5558
  return resolve();
5306
5559
  }
@@ -5315,30 +5568,6 @@ class RoomConnection extends TypedEventTarget {
5315
5568
  });
5316
5569
  });
5317
5570
  }
5318
- toggleCamera(enabled) {
5319
- var _a;
5320
- const localVideoTrack = (_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getVideoTracks()[0];
5321
- if (!localVideoTrack) {
5322
- this.logger.log("Tried toggling non-existing video track");
5323
- return;
5324
- }
5325
- // TODO: Do stopOrResumeVideo
5326
- const newValue = enabled !== null && enabled !== void 0 ? enabled : !localVideoTrack.enabled;
5327
- localVideoTrack.enabled = newValue;
5328
- this.signalSocket.emit("enable_video", { enabled: newValue });
5329
- }
5330
- toggleMicrophone(enabled) {
5331
- var _a;
5332
- const localAudioTrack = (_a = this.localStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks()[0];
5333
- if (!localAudioTrack) {
5334
- this.logger.log("Tried toggling non-existing audio track");
5335
- return;
5336
- }
5337
- // TODO: Do stopOrResumeAudio
5338
- const newValue = enabled !== null && enabled !== void 0 ? enabled : !localAudioTrack.enabled;
5339
- localAudioTrack.enabled = newValue;
5340
- this.signalSocket.emit("enable_audio", { enabled: newValue });
5341
- }
5342
5571
  setDisplayName(displayName) {
5343
5572
  this.signalSocket.emit("send_client_metadata", {
5344
5573
  type: "UserData",
@@ -5398,7 +5627,8 @@ function useRoomConnection(roomUrl, roomConnectionOptions) {
5398
5627
  const [roomConnection, setRoomConnection] = useState(null);
5399
5628
  const [state, dispatch] = useReducer(reducer, { remoteParticipants: [] });
5400
5629
  useEffect(() => {
5401
- setRoomConnection(new RoomConnection(roomUrl, roomConnectionOptions));
5630
+ var _a;
5631
+ setRoomConnection(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 })));
5402
5632
  }, [roomUrl]);
5403
5633
  useEffect(() => {
5404
5634
  if (!roomConnection) {
@@ -5441,10 +5671,10 @@ function useRoomConnection(roomUrl, roomConnectionOptions) {
5441
5671
  state,
5442
5672
  {
5443
5673
  toggleCamera: (enabled) => {
5444
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.toggleCamera(enabled);
5674
+ roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.localMedia.toggleCameraEnabled(enabled);
5445
5675
  },
5446
5676
  toggleMicrophone: (enabled) => {
5447
- roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.toggleMicrophone(enabled);
5677
+ roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.localMedia.toggleMichrophoneEnabled(enabled);
5448
5678
  },
5449
5679
  setDisplayName: (displayName) => {
5450
5680
  roomConnection === null || roomConnection === void 0 ? void 0 : roomConnection.setDisplayName(displayName);
@@ -5457,6 +5687,6 @@ function useRoomConnection(roomUrl, roomConnectionOptions) {
5457
5687
  ];
5458
5688
  }
5459
5689
 
5460
- const sdkVersion = "2.0.0-alpha5";
5690
+ const sdkVersion = "2.0.0-alpha6";
5461
5691
 
5462
- export { sdkVersion, useRoomConnection };
5692
+ export { VideoView, sdkVersion, useLocalMedia, useRoomConnection };
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import RtcManager from '@whereby/jslib-media/src/webrtc/RtcManager';
2
3
 
3
4
  interface WherebyEmbedAttributes {
4
5
  audio: string;
@@ -38,6 +39,82 @@ interface VideoViewSelfProps {
38
39
  type VideoViewProps = VideoViewSelfProps & React.DetailedHTMLProps<React.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>;
39
40
  declare const _default: ({ muted, stream, ...rest }: VideoViewProps) => JSX.Element;
40
41
 
42
+ type CameraEnabledEvent = {
43
+ enabled: boolean;
44
+ };
45
+ type MicrophoneEnabledEvent = {
46
+ enabled: boolean;
47
+ };
48
+ type DeviceListUpdatedEvent = {
49
+ cameraDevices: MediaDeviceInfo[];
50
+ microphoneDevices: MediaDeviceInfo[];
51
+ speakerDevices: MediaDeviceInfo[];
52
+ };
53
+ type DeviceListUpdateErrorEvent = {
54
+ error: unknown;
55
+ };
56
+ type StreamUpdatedEvent = {
57
+ stream: MediaStream;
58
+ };
59
+ interface LocalMediaEventsMap {
60
+ camera_enabled: CustomEvent<CameraEnabledEvent>;
61
+ device_list_updated: CustomEvent<DeviceListUpdatedEvent>;
62
+ device_list_update_error: CustomEvent<DeviceListUpdateErrorEvent>;
63
+ microphone_enabled: CustomEvent<MicrophoneEnabledEvent>;
64
+ stream_updated: CustomEvent<StreamUpdatedEvent>;
65
+ }
66
+ interface LocalMediaEventTarget extends EventTarget {
67
+ addEventListener<K extends keyof LocalMediaEventsMap>(type: K, listener: (ev: LocalMediaEventsMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
68
+ addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
69
+ }
70
+ declare const TypedLocalMediaEventTarget: new () => LocalMediaEventTarget;
71
+ declare class LocalMedia extends TypedLocalMediaEventTarget {
72
+ private _constraints;
73
+ _rtcManagers: RtcManager[];
74
+ stream: MediaStream;
75
+ constructor(constraints: MediaStreamConstraints);
76
+ addRtcManager(rtcManager: RtcManager): void;
77
+ removeRtcManager(rtcManager: RtcManager): void;
78
+ getCameraDeviceId(): string | undefined;
79
+ getMicrophoneDeviceId(): string | undefined;
80
+ isCameraEnabled(): boolean;
81
+ isMicrophoneEnabled(): boolean;
82
+ toggleCameraEnabled(enabled?: boolean): void;
83
+ toggleMichrophoneEnabled(enabled?: boolean): void;
84
+ setCameraDevice(deviceId: string): Promise<void>;
85
+ setMicrophoneDevice(deviceId: string): Promise<void>;
86
+ private _updateDeviceList;
87
+ start(): Promise<MediaStream>;
88
+ stop(): void;
89
+ }
90
+
91
+ interface LocalMediaState {
92
+ currentCameraDeviceId?: string;
93
+ currentMicrophoneDeviceId?: string;
94
+ cameraDeviceError: unknown;
95
+ cameraDevices: MediaDeviceInfo[];
96
+ isSettingCameraDevice: boolean;
97
+ isSettingMicrophoneDevice: boolean;
98
+ isStarting: boolean;
99
+ localStream?: MediaStream;
100
+ microphoneDeviceError: unknown;
101
+ microphoneDevices: MediaDeviceInfo[];
102
+ speakerDevices: MediaDeviceInfo[];
103
+ startError: unknown;
104
+ }
105
+ interface LocalMediaActions {
106
+ setCameraDevice: InstanceType<typeof LocalMedia>["setCameraDevice"];
107
+ setMicrophoneDevice: InstanceType<typeof LocalMedia>["setMicrophoneDevice"];
108
+ toggleCameraEnabled: InstanceType<typeof LocalMedia>["toggleCameraEnabled"];
109
+ toggleMicrophoneEnabled: InstanceType<typeof LocalMedia>["toggleMichrophoneEnabled"];
110
+ }
111
+ type LocalMediaRef = {
112
+ state: LocalMediaState;
113
+ actions: LocalMediaActions;
114
+ _ref: LocalMedia;
115
+ };
116
+ declare function useLocalMedia(constraints?: MediaStreamConstraints): LocalMediaRef;
117
+
41
118
  interface RoomParticipantData {
42
119
  displayName: string;
43
120
  id: string;
@@ -77,10 +154,10 @@ declare class LocalParticipant extends RoomParticipant {
77
154
  type Logger = Pick<Console, "debug" | "error" | "log" | "warn">;
78
155
  interface RoomConnectionOptions {
79
156
  displayName?: string;
80
- localStream?: MediaStream;
81
157
  localMediaConstraints?: MediaStreamConstraints;
82
158
  roomKey?: string;
83
159
  logger?: Logger;
160
+ localMedia?: LocalMedia;
84
161
  }
85
162
 
86
163
  type RemoteParticipantState = Omit<RemoteParticipant, "updateStreamState">;
@@ -98,8 +175,11 @@ interface RoomConnectionActions {
98
175
  interface RoomConnectionComponents {
99
176
  VideoView: typeof _default;
100
177
  }
101
- declare function useRoomConnection(roomUrl: string, roomConnectionOptions: RoomConnectionOptions): [state: RoomState, actions: RoomConnectionActions, components: RoomConnectionComponents];
178
+ interface UseRoomConnectionOptions extends Omit<RoomConnectionOptions, "localMedia"> {
179
+ localMedia?: LocalMediaRef;
180
+ }
181
+ declare function useRoomConnection(roomUrl: string, roomConnectionOptions: UseRoomConnectionOptions): [state: RoomState, actions: RoomConnectionActions, components: RoomConnectionComponents];
102
182
 
103
- declare const sdkVersion = "2.0.0-alpha5";
183
+ declare const sdkVersion = "2.0.0-alpha6";
104
184
 
105
- export { sdkVersion, useRoomConnection };
185
+ export { _default as VideoView, sdkVersion, useLocalMedia, useRoomConnection };