@whereby.com/browser-sdk 2.0.0-beta4 → 2.1.0-beta1

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.
@@ -1,4 +1,6 @@
1
- interface WherebyEmbedAttributes {
1
+ import { ReactHTMLElement } from 'react';
2
+
3
+ interface WherebyEmbedElementAttributes extends ReactHTMLElement<HTMLElement> {
2
4
  audio: string;
3
5
  avatarUrl: string;
4
6
  background: string;
@@ -35,10 +37,68 @@ interface WherebyEmbedAttributes {
35
37
  video: string;
36
38
  virtualBackgroundUrl: string;
37
39
  }
40
+ interface WherebyEmbedElementEventMap {
41
+ ready: CustomEvent;
42
+ knock: CustomEvent;
43
+ participantupdate: CustomEvent<{
44
+ count: number;
45
+ }>;
46
+ join: CustomEvent;
47
+ leave: CustomEvent<{
48
+ removed: boolean;
49
+ }>;
50
+ participant_join: CustomEvent<{
51
+ participant: {
52
+ metadata: string;
53
+ };
54
+ }>;
55
+ participant_leave: CustomEvent<{
56
+ participant: {
57
+ metadata: string;
58
+ };
59
+ }>;
60
+ microphone_toggle: CustomEvent<{
61
+ enabled: boolean;
62
+ }>;
63
+ camera_toggle: CustomEvent<{
64
+ enabled: boolean;
65
+ }>;
66
+ chat_toggle: CustomEvent<{
67
+ open: boolean;
68
+ }>;
69
+ pip_toggle: CustomEvent<{
70
+ open: boolean;
71
+ }>;
72
+ deny_device_permission: CustomEvent<{
73
+ denied: boolean;
74
+ }>;
75
+ screenshare_toggle: CustomEvent<{
76
+ enabled: boolean;
77
+ }>;
78
+ streaming_status_change: CustomEvent<{
79
+ status: string;
80
+ }>;
81
+ connection_status_change: CustomEvent<{
82
+ status: "stable" | "unstable";
83
+ }>;
84
+ }
85
+ interface WherebyEmbedElementCommands {
86
+ startRecording: () => void;
87
+ stopRecording: () => void;
88
+ startStreaming: () => void;
89
+ stopStreaming: () => void;
90
+ toggleCamera: (enabled?: boolean) => void;
91
+ toggleMicrophone: (enabled?: boolean) => void;
92
+ toggleScreenshare: (enabled?: boolean) => void;
93
+ toogleChat: (enabled?: boolean) => void;
94
+ }
95
+ interface WherebyEmbedElement extends HTMLIFrameElement, WherebyEmbedElementCommands {
96
+ addEventListener<K extends keyof (WherebyEmbedElementEventMap & HTMLElementEventMap)>(type: K, listener: (this: HTMLIFrameElement, ev: (WherebyEmbedElementEventMap & HTMLElementEventMap)[K]) => void, options?: boolean | AddEventListenerOptions | undefined): void;
97
+ }
38
98
  declare global {
39
99
  namespace JSX {
40
100
  interface IntrinsicElements {
41
- ["whereby-embed"]: Partial<WherebyEmbedAttributes>;
101
+ ["whereby-embed"]: Partial<WherebyEmbedElementAttributes>;
42
102
  }
43
103
  }
44
104
  }
@@ -46,4 +106,4 @@ declare const _default: {
46
106
  sdkVersion: string;
47
107
  };
48
108
 
49
- export { _default as default };
109
+ export { type WherebyEmbedElement, _default as default };
@@ -20,7 +20,7 @@ function parseRoomUrlAndSubdomain(roomAttribute, subdomainAttribute) {
20
20
  };
21
21
  }
22
22
 
23
- const sdkVersion = "2.0.0-beta4";
23
+ const sdkVersion = "2.1.0-beta1";
24
24
 
25
25
  const boolAttrs = [
26
26
  "audio",
@@ -119,7 +119,7 @@ define("WherebyEmbed", {
119
119
  toggleChat(enabled) {
120
120
  this._postCommand("toggle_chat", [enabled]);
121
121
  },
122
- onmessage({ origin, data }) {
122
+ onmessage({ origin, data, }) {
123
123
  if (!this.roomUrl || origin !== this.roomUrl.origin)
124
124
  return;
125
125
  const { type, payload: detail } = data;
@@ -147,7 +147,7 @@ define("WherebyEmbed", {
147
147
  title=${title || "Video calling component"}
148
148
  ref=${this.iframe}
149
149
  src=${this.roomUrl}
150
- allow="autoplay; camera; microphone; fullscreen; speaker; display-capture" />
150
+ allow="autoplay; camera; microphone; fullscreen; speaker; display-capture; media-capture" />
151
151
  `;
152
152
  },
153
153
  });
@@ -1,5 +1,4 @@
1
- import * as React from 'react';
2
- import React__default from 'react';
1
+ import * as React$1 from 'react';
3
2
  import _whereby_jslib_media_src_utils_ServerSocket, { ChatMessage as ChatMessage$2 } from '@whereby/jslib-media/src/utils/ServerSocket';
4
3
  import * as redux_thunk from 'redux-thunk';
5
4
  import { AxiosRequestConfig } from 'axios';
@@ -13,15 +12,18 @@ interface VideoViewSelfProps {
13
12
  stream: MediaStream;
14
13
  muted?: boolean;
15
14
  mirror?: boolean;
16
- style?: React__default.CSSProperties;
15
+ style?: React$1.CSSProperties;
17
16
  onResize?: ({ width, height, stream }: {
18
17
  width: number;
19
18
  height: number;
20
19
  stream: MediaStream;
21
20
  }) => void;
21
+ onSetAspectRatio?: ({ aspectRatio }: {
22
+ aspectRatio: number;
23
+ }) => void;
22
24
  }
23
- type VideoViewProps = VideoViewSelfProps & React__default.DetailedHTMLProps<React__default.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>;
24
- declare const _default: ({ muted, mirror, stream, onResize, ...rest }: VideoViewProps) => React__default.JSX.Element;
25
+ type VideoViewProps = VideoViewSelfProps & React$1.DetailedHTMLProps<React$1.VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>;
26
+ declare const _default: ({ muted, mirror, stream, onResize, onSetAspectRatio, ...rest }: VideoViewProps) => React$1.JSX.Element;
25
27
 
26
28
  interface RoomParticipantData {
27
29
  displayName: string;
@@ -584,6 +586,10 @@ type ConnectionStatus$1 = "initializing" | "connecting" | "connected" | "reconne
584
586
  * Reducer
585
587
  */
586
588
  interface RoomConnectionState$1 {
589
+ session: {
590
+ createdAt: string;
591
+ id: string;
592
+ } | null;
587
593
  status: ConnectionStatus$1;
588
594
  error: unknown;
589
595
  }
@@ -809,7 +815,6 @@ interface RoomConnectionActions {
809
815
  stopCloudRecording(): void;
810
816
  stopScreenshare(): void;
811
817
  }
812
-
813
818
  type VideoViewComponentProps = Omit<React.ComponentProps<typeof _default>, "onResize">;
814
819
  interface RoomConnectionComponents {
815
820
  VideoView: (props: VideoViewComponentProps) => ReturnType<typeof _default>;
@@ -820,6 +825,7 @@ type RoomConnectionRef = {
820
825
  components: RoomConnectionComponents;
821
826
  _ref: Store;
822
827
  };
828
+
823
829
  declare function useRoomConnection(roomUrl: string, roomConnectionOptions?: UseRoomConnectionOptions): RoomConnectionRef;
824
830
 
825
831
  declare function useLocalMedia(optionsOrStream?: UseLocalMediaOptions | MediaStream): UseLocalMediaResult;
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import React__default, { useRef, useEffect, useState, useCallback } from 'react';
2
+ import { useState, useEffect, useCallback } from 'react';
3
3
  import { createListenerMiddleware, createSlice, createAsyncThunk, createAction, createSelector, isAnyOf, combineReducers, configureStore } from '@reduxjs/toolkit';
4
4
  import { io } from 'socket.io-client';
5
5
  import adapter from 'webrtc-adapter';
@@ -85,19 +85,26 @@ function debounce(fn, { delay = 500, edges } = {}) {
85
85
  }
86
86
 
87
87
  var VideoView = (_a) => {
88
- var { muted, mirror = false, stream, onResize } = _a, rest = __rest(_a, ["muted", "mirror", "stream", "onResize"]);
89
- const videoEl = useRef(null);
90
- useEffect(() => {
91
- if (!videoEl.current || !onResize) {
88
+ var { muted, mirror = false, stream, onResize, onSetAspectRatio } = _a, rest = __rest(_a, ["muted", "mirror", "stream", "onResize", "onSetAspectRatio"]);
89
+ const videoEl = React.useRef(null);
90
+ React.useEffect(() => {
91
+ if (!videoEl.current) {
92
92
  return;
93
93
  }
94
94
  const resizeObserver = new ResizeObserver(debounce(() => {
95
95
  if (videoEl.current && (stream === null || stream === void 0 ? void 0 : stream.id)) {
96
- onResize({
97
- width: videoEl.current.clientWidth,
98
- height: videoEl.current.clientHeight,
99
- stream,
100
- });
96
+ if (onResize) {
97
+ onResize({
98
+ width: videoEl.current.clientWidth,
99
+ height: videoEl.current.clientHeight,
100
+ stream,
101
+ });
102
+ }
103
+ const h = videoEl.current.videoHeight;
104
+ const w = videoEl.current.videoWidth;
105
+ if (w && h && w + h > 20 && onSetAspectRatio) {
106
+ onSetAspectRatio({ aspectRatio: w / h });
107
+ }
101
108
  }
102
109
  }, { delay: 1000, edges: true }));
103
110
  resizeObserver.observe(videoEl.current);
@@ -105,7 +112,7 @@ var VideoView = (_a) => {
105
112
  resizeObserver.disconnect();
106
113
  };
107
114
  }, [stream]);
108
- useEffect(() => {
115
+ React.useEffect(() => {
109
116
  if (!videoEl.current) {
110
117
  return;
111
118
  }
@@ -118,7 +125,7 @@ var VideoView = (_a) => {
118
125
  videoEl.current.muted = Boolean(muted);
119
126
  }
120
127
  }, [muted, stream, videoEl]);
121
- return (React__default.createElement("video", Object.assign({ ref: videoEl, autoPlay: true, playsInline: true }, rest, { style: Object.assign({ transform: mirror ? "scaleX(-1)" : "none", width: "100%", height: "100%" }, rest.style) })));
128
+ return (React.createElement("video", Object.assign({ ref: videoEl, autoPlay: true, playsInline: true }, rest, { style: Object.assign({ transform: mirror ? "scaleX(-1)" : "none", width: "100%", height: "100%" }, rest.style) })));
122
129
  };
123
130
 
124
131
  const listenerMiddleware = createListenerMiddleware();
@@ -218,6 +225,7 @@ const signalEvents = {
218
225
  newClient: createSignalEventAction("newClient"),
219
226
  roomJoined: createSignalEventAction("roomJoined"),
220
227
  roomKnocked: createSignalEventAction("roomKnocked"),
228
+ roomSessionEnded: createSignalEventAction("roomSessionEnded"),
221
229
  screenshareStarted: createSignalEventAction("screenshareStarted"),
222
230
  screenshareStopped: createSignalEventAction("screenshareStopped"),
223
231
  streamingStopped: createSignalEventAction("streamingStopped"),
@@ -413,6 +421,7 @@ function forwardSocketEvents(socket, dispatch) {
413
421
  socket.on("chat_message", (payload) => dispatch(signalEvents.chatMessage(payload)));
414
422
  socket.on("disconnect", () => dispatch(signalEvents.disconnect()));
415
423
  socket.on("room_knocked", (payload) => dispatch(signalEvents.roomKnocked(payload)));
424
+ socket.on("room_session_ended", (payload) => dispatch(signalEvents.roomSessionEnded(payload)));
416
425
  socket.on("knocker_left", (payload) => dispatch(signalEvents.knockerLeft(payload)));
417
426
  socket.on("knock_handled", (payload) => dispatch(signalEvents.knockHandled(payload)));
418
427
  socket.on("screenshare_started", (payload) => dispatch(signalEvents.screenshareStarted(payload)));
@@ -1432,7 +1441,7 @@ const doStartLocalMedia = createAppAsyncThunk("localMedia/doStartLocalMedia", (p
1432
1441
  const onDeviceChange = debounce(() => {
1433
1442
  dispatch(doUpdateDeviceList());
1434
1443
  }, { delay: 500 });
1435
- if (global.navigator.mediaDevices) {
1444
+ if (navigator.mediaDevices) {
1436
1445
  navigator.mediaDevices.addEventListener("devicechange", onDeviceChange);
1437
1446
  }
1438
1447
  // Resolve if existing stream is passed
@@ -1464,7 +1473,7 @@ const doStopLocalMedia = createAppThunk(() => (dispatch, getState) => {
1464
1473
  stream === null || stream === void 0 ? void 0 : stream.getTracks().forEach((track) => {
1465
1474
  track.stop();
1466
1475
  });
1467
- if (global.navigator.mediaDevices && onDeviceChange) {
1476
+ if (navigator.mediaDevices && onDeviceChange) {
1468
1477
  navigator.mediaDevices.removeEventListener("devicechange", onDeviceChange);
1469
1478
  }
1470
1479
  dispatch(localMediaStopped());
@@ -2038,6 +2047,7 @@ const selectScreenshares = createSelector(selectLocalScreenshareStream, selectRe
2038
2047
  });
2039
2048
 
2040
2049
  const initialState$6 = {
2050
+ session: null,
2041
2051
  status: "initializing",
2042
2052
  error: null,
2043
2053
  };
@@ -2051,12 +2061,24 @@ const roomConnectionSlice = createSlice({
2051
2061
  },
2052
2062
  extraReducers: (builder) => {
2053
2063
  builder.addCase(signalEvents.roomJoined, (state, action) => {
2064
+ var _a, _b;
2054
2065
  //TODO: Handle error
2055
2066
  const { error, isLocked } = action.payload;
2056
2067
  if (error === "room_locked" && isLocked) {
2057
2068
  return Object.assign(Object.assign({}, state), { status: "room_locked" });
2058
2069
  }
2059
- return Object.assign(Object.assign({}, state), { status: "connected" });
2070
+ return Object.assign(Object.assign({}, state), { status: "connected", session: (_b = (_a = action.payload.room) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : null });
2071
+ });
2072
+ builder.addCase(signalEvents.newClient, (state, action) => {
2073
+ var _a, _b;
2074
+ return Object.assign(Object.assign({}, state), { session: (_b = (_a = action.payload.room) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : null });
2075
+ });
2076
+ builder.addCase(signalEvents.roomSessionEnded, (state, action) => {
2077
+ var _a;
2078
+ if (((_a = state.session) === null || _a === void 0 ? void 0 : _a.id) !== action.payload.roomSessionId) {
2079
+ return state;
2080
+ }
2081
+ return Object.assign(Object.assign({}, state), { session: null });
2060
2082
  });
2061
2083
  builder.addCase(socketReconnecting, (state) => {
2062
2084
  return Object.assign(Object.assign({}, state), { status: "reconnect" });
@@ -2128,6 +2150,7 @@ const doConnectRoom = createAppThunk(() => (dispatch, getState) => {
2128
2150
  });
2129
2151
  dispatch(connectionStatusChanged("connecting"));
2130
2152
  });
2153
+ const selectRoomConnectionSessionId = (state) => { var _a; return (_a = state.roomConnection.session) === null || _a === void 0 ? void 0 : _a.id; };
2131
2154
  const selectRoomConnectionStatus = (state) => state.roomConnection.status;
2132
2155
  /**
2133
2156
  * Reactors
@@ -7384,6 +7407,12 @@ const rtcAnalyticsCustomEvents = {
7384
7407
  getValue: (state) => selectSignalStatus(state),
7385
7408
  getOutput: (value) => ({ status: value }),
7386
7409
  },
7410
+ roomSessionId: {
7411
+ action: null,
7412
+ rtcEventName: "roomSessionId",
7413
+ getValue: (state) => selectRoomConnectionSessionId(state),
7414
+ getOutput: (value) => ({ roomSessionId: value }),
7415
+ },
7387
7416
  rtcConnectionStatus: {
7388
7417
  action: null,
7389
7418
  rtcEventName: "rtcConnectionStatus",
@@ -7422,6 +7451,16 @@ const doRtcAnalyticsCustomEventsInitialize = createAppThunk(() => (dispatch, get
7422
7451
  const rtcManager = selectRtcConnectionRaw(state).rtcManager;
7423
7452
  if (!rtcManager)
7424
7453
  return;
7454
+ // RTC stats require a `insightsStats` event to be sent to set the timestamp.
7455
+ // This is a temporary workaround, we just send one dummy event on initialization.
7456
+ rtcManager.sendStatsCustomEvent("insightsStats", {
7457
+ _time: Date.now(),
7458
+ ls: 0,
7459
+ lr: 0,
7460
+ bs: 0,
7461
+ br: 0,
7462
+ cpu: 0,
7463
+ });
7425
7464
  Object.values(rtcAnalyticsCustomEvents).forEach(({ rtcEventName, getValue, getOutput }) => {
7426
7465
  var _a;
7427
7466
  const value = getValue(state);
@@ -7554,7 +7593,7 @@ const doRejectWaitingParticipant = createAppThunk((payload) => (dispatch, getSta
7554
7593
  const selectWaitingParticipants = (state) => state.waitingParticipants.waitingParticipants;
7555
7594
 
7556
7595
  var _a;
7557
- const IS_DEV = (_a = process.env.REACT_APP_IS_DEV === "true") !== null && _a !== void 0 ? _a : false;
7596
+ const IS_DEV = (_a = undefined === "true") !== null && _a !== void 0 ? _a : false;
7558
7597
  const rootReducer = combineReducers({
7559
7598
  app: appSlice.reducer,
7560
7599
  chat: chatSlice.reducer,
@@ -8651,7 +8690,7 @@ const selectRoomConnectionState = createSelector(selectChatMessages, selectCloud
8651
8690
  return state;
8652
8691
  });
8653
8692
 
8654
- const sdkVersion = "2.0.0-beta4";
8693
+ const sdkVersion = "2.1.0-beta1";
8655
8694
 
8656
8695
  const initialState$1 = {
8657
8696
  chatMessages: [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whereby.com/browser-sdk",
3
- "version": "2.0.0-beta4",
3
+ "version": "2.1.0-beta1",
4
4
  "description": "Modules for integration Whereby video in web apps",
5
5
  "author": "Whereby AS",
6
6
  "license": "MIT",
@@ -96,6 +96,7 @@
96
96
  "rimraf": "^3.0.2",
97
97
  "rollup": "^4.3.0",
98
98
  "rollup-plugin-dts": "^6.1.0",
99
+ "rollup-plugin-polyfill-node": "^0.13.0",
99
100
  "rollup-plugin-terser": "^7.0.2",
100
101
  "rollup-plugin-typescript2": "^0.36.0",
101
102
  "storybook": "^7.5.2",