@whereby.com/browser-sdk 2.0.0-alpha9 → 2.0.0-beta2
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/README.md +82 -29
- package/dist/LocalMedia.d.ts +70 -0
- package/dist/LocalMedia.js +208 -0
- package/dist/RoomConnection.d.ts +190 -0
- package/dist/RoomConnection.js +646 -0
- package/dist/RoomParticipant.d.ts +50 -0
- package/dist/RoomParticipant.js +48 -0
- package/dist/api/ApiClient.d.ts +26 -0
- package/dist/api/ApiClient.js +61 -0
- package/dist/api/Credentials.d.ts +17 -0
- package/dist/api/Credentials.js +16 -0
- package/dist/api/HttpClient.d.ts +16 -0
- package/dist/api/HttpClient.js +52 -0
- package/dist/api/MultipartHttpClient.d.ts +10 -0
- package/dist/api/MultipartHttpClient.js +25 -0
- package/dist/api/OrganizationApiClient.d.ts +16 -0
- package/dist/api/OrganizationApiClient.js +28 -0
- package/dist/api/Response.d.ts +29 -0
- package/dist/api/Response.js +9 -0
- package/dist/api/credentialsService/index.d.ts +27 -0
- package/dist/api/credentialsService/index.js +89 -0
- package/dist/api/deviceService/index.d.ts +9 -0
- package/dist/api/deviceService/index.js +23 -0
- package/dist/api/extractUtils.d.ts +16 -0
- package/dist/api/extractUtils.js +51 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.js +7 -0
- package/dist/api/localStorageWrapper/index.d.ts +2 -0
- package/dist/api/localStorageWrapper/index.js +15 -0
- package/dist/api/models/Account.d.ts +20 -0
- package/dist/api/models/Account.js +24 -0
- package/dist/api/models/Meeting.d.ts +12 -0
- package/dist/api/models/Meeting.js +29 -0
- package/dist/api/models/Organization.d.ts +102 -0
- package/dist/api/models/Organization.js +81 -0
- package/dist/api/models/Room.d.ts +4 -0
- package/dist/api/models/Room.js +38 -0
- package/dist/api/models/account/EmbeddedFreeTierStatus.d.ts +13 -0
- package/dist/api/models/account/EmbeddedFreeTierStatus.js +17 -0
- package/dist/api/modules/AbstractStore.d.ts +5 -0
- package/dist/api/modules/AbstractStore.js +1 -0
- package/dist/api/modules/ChromeStorageStore.d.ts +10 -0
- package/dist/api/modules/ChromeStorageStore.js +21 -0
- package/dist/api/modules/LocalStorageStore.d.ts +9 -0
- package/dist/api/modules/LocalStorageStore.js +35 -0
- package/dist/api/modules/tests/__mocks__/storage.d.ts +10 -0
- package/dist/api/modules/tests/__mocks__/storage.js +19 -0
- package/dist/api/organizationService/index.d.ts +46 -0
- package/dist/api/organizationService/index.js +158 -0
- package/dist/api/organizationServiceCache/index.d.ts +13 -0
- package/dist/api/organizationServiceCache/index.js +16 -0
- package/dist/api/parameterAssertUtils.d.ts +13 -0
- package/dist/api/parameterAssertUtils.js +64 -0
- package/dist/api/roomService/index.d.ts +54 -0
- package/dist/api/roomService/index.js +160 -0
- package/dist/api/test/helpers.d.ts +7 -0
- package/dist/api/test/helpers.js +32 -0
- package/dist/api/types.d.ts +5 -0
- package/dist/api/types.js +1 -0
- package/dist/embed/index.d.ts +32 -0
- package/dist/embed/index.js +124 -0
- package/dist/react/VideoView.d.ts +15 -0
- package/dist/react/VideoView.js +37 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +4 -0
- package/dist/react/useLocalMedia.d.ts +29 -0
- package/dist/react/useLocalMedia.js +109 -0
- package/dist/react/useRoomConnection.d.ts +57 -0
- package/dist/react/useRoomConnection.js +340 -0
- package/dist/utils/debounce.d.ts +9 -0
- package/dist/utils/debounce.js +18 -0
- package/dist/utils/fakeAudioStream.d.ts +1 -0
- package/dist/utils/fakeAudioStream.js +18 -0
- package/dist/utils/fakeWebcamFrame.d.ts +1 -0
- package/dist/utils/fakeWebcamFrame.js +49 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/v2-beta2.js +2000 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +110 -81
- package/dist/lib.cjs.js +0 -5868
- package/dist/lib.esm.js +0 -5850
- package/dist/types.d.ts +0 -308
- package/dist/v2-alpha9.js +0 -43
package/README.md
CHANGED
|
@@ -1,38 +1,51 @@
|
|
|
1
1
|
# `@whereby.com/browser-sdk`
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> [!WARNING]
|
|
4
|
+
> This is a pre-release of the v2 version of this library, adding support for
|
|
5
|
+
> more custom integration using React hooks and plain JavaScript classes in
|
|
6
|
+
> addition to the web component for embedding.
|
|
4
7
|
|
|
5
|
-
Whereby browser SDK is a library for seamless integration of Whereby
|
|
8
|
+
Whereby browser SDK is a library for seamless integration of Whereby
|
|
9
|
+
(https://whereby.com) video calls into your web application.
|
|
10
|
+
|
|
11
|
+
**For a more detailed set of instructions, including the building of a [simple telehealth app](https://docs.whereby.com/whereby-101/create-your-video-experience/in-a-web-page/using-whereby-react-hooks-build-a-telehealth-app), please see our [documentation](https://docs.whereby.com/reference/react-hooks-reference).**
|
|
6
12
|
|
|
7
13
|
## Installation
|
|
8
14
|
|
|
9
|
-
```
|
|
15
|
+
```shell
|
|
10
16
|
npm install @whereby.com/browser-sdk
|
|
11
17
|
```
|
|
18
|
+
|
|
12
19
|
or
|
|
13
|
-
|
|
20
|
+
|
|
21
|
+
```shell
|
|
14
22
|
yarn add @whereby.com/browser-sdk
|
|
15
23
|
```
|
|
16
24
|
|
|
17
25
|
## Usage
|
|
18
|
-
|
|
19
|
-
> In order to make use of this functionality, you must have a Whereby account
|
|
26
|
+
> [!IMPORTANT]
|
|
27
|
+
> In order to make use of this functionality, you must have a Whereby account
|
|
28
|
+
> from which you can create room urls, either [manually or through our
|
|
29
|
+
> API](https://docs.whereby.com/creating-and-deleting-rooms).
|
|
20
30
|
|
|
21
31
|
### React hooks
|
|
22
32
|
|
|
23
33
|
#### useLocalMedia
|
|
24
|
-
The `useLocalMedia` hook enables preview and selection of local devices (camera & microphone) prior to establishing a connection within a Whereby room. Use this hook to build rich pre-call
|
|
25
|
-
experiences, allowing end users to confirm their device selection up-front. This hook works seamlessly with the `useRoomConnection` hook described below.
|
|
26
34
|
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
The `useLocalMedia` hook enables preview and selection of local devices (camera
|
|
36
|
+
& microphone) prior to establishing a connection within a Whereby room. Use
|
|
37
|
+
this hook to build rich pre-call experiences, allowing end users to confirm
|
|
38
|
+
their device selection up-front. This hook works seamlessly with the
|
|
39
|
+
`useRoomConnection` hook described below.
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import { useLocalMedia, VideoView } from "@whereby.com/browser-sdk/react";
|
|
29
43
|
|
|
30
44
|
function MyPreCallUX() {
|
|
31
45
|
const localMedia = useLocalMedia({ audio: false, video: true });
|
|
32
46
|
|
|
33
47
|
const { currentCameraDeviceId, cameraDevices, localStream } = localMedia.state;
|
|
34
48
|
const { setCameraDevice, toggleCameraEnabled } = localMedia.actions;
|
|
35
|
-
const { VideoView } = components;
|
|
36
49
|
|
|
37
50
|
return <div className="preCallView">
|
|
38
51
|
{ /* Render any UI, making use of state */ }
|
|
@@ -54,18 +67,20 @@ function MyPreCallUX() {
|
|
|
54
67
|
|
|
55
68
|
```
|
|
56
69
|
|
|
57
|
-
|
|
58
70
|
#### useRoomConnection
|
|
59
|
-
The `useRoomConnection` hook provides a way to connect participants in a given room, subscribe to state updates, and perform actions on the connection, like toggling camera or microphone.
|
|
60
71
|
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
The `useRoomConnection` hook provides a way to connect participants in a given
|
|
73
|
+
room, subscribe to state updates, and perform actions on the connection, like
|
|
74
|
+
toggling camera or microphone.
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
import { useRoomConnection } from "@whereby.com/browser-sdk/react";
|
|
63
78
|
|
|
64
79
|
function MyCallUX( { roomUrl, localStream }) {
|
|
65
|
-
const
|
|
80
|
+
const { state, actions, components } = useRoomConnection(
|
|
66
81
|
"<room_url>"
|
|
67
82
|
{
|
|
68
|
-
localMedia: null, // Supply localMedia from `useLocalMedia` hook, or constraints
|
|
83
|
+
localMedia: null, // Supply localMedia from `useLocalMedia` hook, or constraints
|
|
69
84
|
localMediaConstraints: {
|
|
70
85
|
audio: true,
|
|
71
86
|
video: true,
|
|
@@ -87,27 +102,64 @@ function MyCallUX( { roomUrl, localStream }) {
|
|
|
87
102
|
|
|
88
103
|
```
|
|
89
104
|
|
|
90
|
-
|
|
105
|
+
#### Usage with Vite development environment
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
There is a [known Vite issue](https://github.com/vitejs/vite/issues/1973) where modules trying to access `process.env` throw `Uncaught ReferenceError: process is not defined`.
|
|
108
|
+
This can be solved in `vite.config.js` with the following line:
|
|
93
109
|
|
|
110
|
+
``` javascript
|
|
111
|
+
export default defineConfig({
|
|
112
|
+
...rest,
|
|
113
|
+
define: {
|
|
114
|
+
'process.env': {}
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
```
|
|
94
118
|
|
|
95
|
-
####
|
|
119
|
+
#### Usage with Next.js
|
|
96
120
|
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
If you are integrating these React hooks with Next.js, you need to ensure your
|
|
122
|
+
custom video experience components are rendered client side, as the underlying
|
|
123
|
+
APIs we use are only available in the browser context. Simply add `"use
|
|
124
|
+
client";` to the top of component, like in the following example:
|
|
99
125
|
|
|
100
|
-
|
|
101
|
-
|
|
126
|
+
```js
|
|
127
|
+
"use client";
|
|
128
|
+
|
|
129
|
+
import { VideoView, useLocalMedia } from "@whereby.com/browser-sdk/react";
|
|
130
|
+
|
|
131
|
+
export default function MyNextVideoExperience() {
|
|
132
|
+
const { state, actions } = useLocalMedia({ audio: false, video: true });
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<p>{ state.localStream && <VideoView muted stream={state.localStream} /> }</p>
|
|
136
|
+
);
|
|
102
137
|
}
|
|
103
138
|
|
|
104
|
-
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Web component for embedding
|
|
142
|
+
|
|
143
|
+
Use the `<whereby-embed />` web component to make use of Whereby's pre-built
|
|
144
|
+
responsive UI. Refer to our
|
|
145
|
+
[documentation](https://docs.whereby.com/embedding-rooms/in-a-web-page/using-the-whereby-embed-element)
|
|
146
|
+
to learn which attributes are supported.
|
|
105
147
|
|
|
148
|
+
#### React
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
import "@whereby.com/browser-sdk/embed";
|
|
152
|
+
|
|
153
|
+
const MyComponent = ({ roomUrl }) => {
|
|
154
|
+
return <whereby-embed chat="off" room={roomUrl} />;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export default MyComponent;
|
|
106
158
|
```
|
|
107
159
|
|
|
108
160
|
#### In plain HTML
|
|
109
161
|
|
|
110
|
-
```
|
|
162
|
+
```html
|
|
111
163
|
<html>
|
|
112
164
|
<head>
|
|
113
165
|
<script src="...."></script>
|
|
@@ -120,6 +172,7 @@ export default MyComponent
|
|
|
120
172
|
</html>
|
|
121
173
|
```
|
|
122
174
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
175
|
+
> [!NOTE]
|
|
176
|
+
> Although we have just higlighted two combinations of how to load and use the
|
|
177
|
+
> web component, it should be possible to use this library with all the major
|
|
178
|
+
> frontend frameworks.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import RtcManager from "@whereby/jslib-media/src/webrtc/RtcManager";
|
|
2
|
+
type CameraEnabledEvent = {
|
|
3
|
+
enabled: boolean;
|
|
4
|
+
};
|
|
5
|
+
type MicrophoneEnabledEvent = {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
};
|
|
8
|
+
type DeviceListUpdatedEvent = {
|
|
9
|
+
cameraDevices: MediaDeviceInfo[];
|
|
10
|
+
microphoneDevices: MediaDeviceInfo[];
|
|
11
|
+
speakerDevices: MediaDeviceInfo[];
|
|
12
|
+
};
|
|
13
|
+
type DeviceListUpdateErrorEvent = {
|
|
14
|
+
error: unknown;
|
|
15
|
+
};
|
|
16
|
+
type StreamUpdatedEvent = {
|
|
17
|
+
stream: MediaStream;
|
|
18
|
+
};
|
|
19
|
+
type StopResumeVideoEvent = {
|
|
20
|
+
track: MediaStreamTrack;
|
|
21
|
+
enable: boolean;
|
|
22
|
+
};
|
|
23
|
+
interface LocalMediaEventsMap {
|
|
24
|
+
camera_enabled: CustomEvent<CameraEnabledEvent>;
|
|
25
|
+
device_list_updated: CustomEvent<DeviceListUpdatedEvent>;
|
|
26
|
+
device_list_update_error: CustomEvent<DeviceListUpdateErrorEvent>;
|
|
27
|
+
microphone_enabled: CustomEvent<MicrophoneEnabledEvent>;
|
|
28
|
+
stream_updated: CustomEvent<StreamUpdatedEvent>;
|
|
29
|
+
stopresumevideo: CustomEvent<StopResumeVideoEvent>;
|
|
30
|
+
}
|
|
31
|
+
interface LocalMediaEventTarget extends EventTarget {
|
|
32
|
+
addEventListener<K extends keyof LocalMediaEventsMap>(type: K, listener: (ev: LocalMediaEventsMap[K]) => void, options?: boolean | AddEventListenerOptions): void;
|
|
33
|
+
addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
|
|
34
|
+
}
|
|
35
|
+
declare const TypedLocalMediaEventTarget: new () => LocalMediaEventTarget;
|
|
36
|
+
export interface LocalMediaOptions {
|
|
37
|
+
audio: boolean;
|
|
38
|
+
video: boolean;
|
|
39
|
+
}
|
|
40
|
+
export default class LocalMedia extends TypedLocalMediaEventTarget {
|
|
41
|
+
private _options;
|
|
42
|
+
_rtcManagers: RtcManager[];
|
|
43
|
+
private _devices;
|
|
44
|
+
stream: MediaStream;
|
|
45
|
+
screenshareStream?: MediaStream;
|
|
46
|
+
private _cameraEnabled;
|
|
47
|
+
private _currentCameraDeviceId;
|
|
48
|
+
private _isTogglingCameraEnabled;
|
|
49
|
+
private _microphoneEnabled;
|
|
50
|
+
private _currentMicrophoneDeviceId;
|
|
51
|
+
constructor(optionsOrStream: LocalMediaOptions | MediaStream);
|
|
52
|
+
addRtcManager(rtcManager: RtcManager): void;
|
|
53
|
+
removeRtcManager(rtcManager: RtcManager): void;
|
|
54
|
+
getCameraDeviceId(): string | undefined;
|
|
55
|
+
getMicrophoneDeviceId(): string | undefined;
|
|
56
|
+
isCameraEnabled(): boolean;
|
|
57
|
+
isMicrophoneEnabled(): boolean;
|
|
58
|
+
toggleCameraEnabled(enabled?: boolean): Promise<void>;
|
|
59
|
+
toggleMichrophoneEnabled(enabled?: boolean): void;
|
|
60
|
+
startScreenshare(): Promise<MediaStream>;
|
|
61
|
+
stopScreenshare(): void;
|
|
62
|
+
private _getConstraintsOptions;
|
|
63
|
+
private _setDevice;
|
|
64
|
+
setCameraDevice(deviceId: string): Promise<void>;
|
|
65
|
+
setMicrophoneDevice(deviceId: string): Promise<void>;
|
|
66
|
+
private _updateDeviceList;
|
|
67
|
+
start(): Promise<MediaStream>;
|
|
68
|
+
stop(): void;
|
|
69
|
+
}
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { getStream } from "@whereby/jslib-media/src/webrtc/MediaDevices";
|
|
3
|
+
class LocalMediaEvent extends CustomEvent {
|
|
4
|
+
constructor(eventType, eventInitDict) {
|
|
5
|
+
super(eventType, eventInitDict);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
const TypedLocalMediaEventTarget = EventTarget;
|
|
9
|
+
export default class LocalMedia extends TypedLocalMediaEventTarget {
|
|
10
|
+
constructor(optionsOrStream) {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
super();
|
|
13
|
+
this._options = null;
|
|
14
|
+
this._devices = [];
|
|
15
|
+
this._isTogglingCameraEnabled = false;
|
|
16
|
+
if (optionsOrStream instanceof MediaStream) {
|
|
17
|
+
this.stream = optionsOrStream;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
this._options = optionsOrStream;
|
|
21
|
+
this.stream = new MediaStream();
|
|
22
|
+
}
|
|
23
|
+
this._cameraEnabled = ((_a = this.stream.getVideoTracks()[0]) === null || _a === void 0 ? void 0 : _a.enabled) || false;
|
|
24
|
+
this._microphoneEnabled = ((_b = this.stream.getAudioTracks()[0]) === null || _b === void 0 ? void 0 : _b.enabled) || false;
|
|
25
|
+
this._rtcManagers = [];
|
|
26
|
+
this.screenshareStream = undefined;
|
|
27
|
+
navigator.mediaDevices.addEventListener("devicechange", this._updateDeviceList.bind(this));
|
|
28
|
+
}
|
|
29
|
+
addRtcManager(rtcManager) {
|
|
30
|
+
this._rtcManagers.push(rtcManager);
|
|
31
|
+
}
|
|
32
|
+
removeRtcManager(rtcManager) {
|
|
33
|
+
this._rtcManagers = this._rtcManagers.filter((r) => r !== rtcManager);
|
|
34
|
+
}
|
|
35
|
+
getCameraDeviceId() {
|
|
36
|
+
return this._currentCameraDeviceId;
|
|
37
|
+
}
|
|
38
|
+
getMicrophoneDeviceId() {
|
|
39
|
+
return this._currentMicrophoneDeviceId;
|
|
40
|
+
}
|
|
41
|
+
isCameraEnabled() {
|
|
42
|
+
return this._cameraEnabled;
|
|
43
|
+
}
|
|
44
|
+
isMicrophoneEnabled() {
|
|
45
|
+
return this._microphoneEnabled;
|
|
46
|
+
}
|
|
47
|
+
toggleCameraEnabled(enabled) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
if (this._isTogglingCameraEnabled) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
let track = this.stream.getVideoTracks()[0];
|
|
53
|
+
const newValue = enabled !== null && enabled !== void 0 ? enabled : !(track === null || track === void 0 ? void 0 : track.enabled);
|
|
54
|
+
if (this._cameraEnabled === newValue) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this._cameraEnabled = newValue;
|
|
58
|
+
this.dispatchEvent(new LocalMediaEvent("camera_enabled", { detail: { enabled: this._cameraEnabled } }));
|
|
59
|
+
const shouldStopTrack = !!this._options;
|
|
60
|
+
this._isTogglingCameraEnabled = true;
|
|
61
|
+
try {
|
|
62
|
+
if (this._cameraEnabled) {
|
|
63
|
+
if (track) {
|
|
64
|
+
track.enabled = true;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
yield getStream(Object.assign(Object.assign({}, this._getConstraintsOptions()), { audioId: false, videoId: this._currentCameraDeviceId, type: "exact" }), { replaceStream: this.stream });
|
|
68
|
+
track = this.stream.getVideoTracks()[0];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
if (!track) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
track.enabled = false;
|
|
76
|
+
if (shouldStopTrack) {
|
|
77
|
+
track.stop();
|
|
78
|
+
this.stream.removeTrack(track);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.stream.dispatchEvent(new LocalMediaEvent("stopresumevideo", { detail: { track, enable: this._cameraEnabled } }));
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
}
|
|
85
|
+
this._isTogglingCameraEnabled = false;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
toggleMichrophoneEnabled(enabled) {
|
|
89
|
+
const audioTrack = this.stream.getAudioTracks()[0];
|
|
90
|
+
if (!audioTrack) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this._microphoneEnabled = enabled !== null && enabled !== void 0 ? enabled : !audioTrack.enabled;
|
|
94
|
+
this.dispatchEvent(new LocalMediaEvent("microphone_enabled", { detail: { enabled: this._microphoneEnabled } }));
|
|
95
|
+
audioTrack.enabled = this._microphoneEnabled;
|
|
96
|
+
}
|
|
97
|
+
startScreenshare() {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
if (this.screenshareStream) {
|
|
100
|
+
return this.screenshareStream;
|
|
101
|
+
}
|
|
102
|
+
const screenshareStream = yield navigator.mediaDevices.getDisplayMedia();
|
|
103
|
+
this.screenshareStream = screenshareStream;
|
|
104
|
+
return this.screenshareStream;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
stopScreenshare() {
|
|
108
|
+
var _a;
|
|
109
|
+
(_a = this.screenshareStream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach((track) => track.stop());
|
|
110
|
+
this.screenshareStream = undefined;
|
|
111
|
+
}
|
|
112
|
+
_getConstraintsOptions() {
|
|
113
|
+
return {
|
|
114
|
+
devices: this._devices,
|
|
115
|
+
options: {
|
|
116
|
+
disableAEC: false,
|
|
117
|
+
disableAGC: false,
|
|
118
|
+
hd: true,
|
|
119
|
+
lax: false,
|
|
120
|
+
lowDataMode: false,
|
|
121
|
+
simulcast: true,
|
|
122
|
+
widescreen: true,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
_setDevice({ audioId, videoId }) {
|
|
127
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
128
|
+
const { replacedTracks } = yield getStream(Object.assign(Object.assign({}, this._getConstraintsOptions()), { audioId,
|
|
129
|
+
videoId, type: "exact" }), { replaceStream: this.stream });
|
|
130
|
+
if (replacedTracks) {
|
|
131
|
+
replacedTracks.forEach((oldTrack) => {
|
|
132
|
+
const newTrack = oldTrack.kind === "audio" ? this.stream.getAudioTracks()[0] : this.stream.getVideoTracks()[0];
|
|
133
|
+
this._rtcManagers.forEach((rtcManager) => {
|
|
134
|
+
rtcManager.replaceTrack(oldTrack, newTrack);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
this.dispatchEvent(new LocalMediaEvent("stream_updated", {
|
|
139
|
+
detail: { stream: this.stream },
|
|
140
|
+
}));
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
setCameraDevice(deviceId) {
|
|
144
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
this._currentCameraDeviceId = deviceId;
|
|
146
|
+
yield this._setDevice({ videoId: this._currentCameraDeviceId, audioId: false });
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
setMicrophoneDevice(deviceId) {
|
|
150
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
this._currentMicrophoneDeviceId = deviceId;
|
|
152
|
+
yield this._setDevice({ audioId: this._currentMicrophoneDeviceId, videoId: false });
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
_updateDeviceList() {
|
|
156
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
157
|
+
try {
|
|
158
|
+
const devices = yield navigator.mediaDevices.enumerateDevices();
|
|
159
|
+
this.dispatchEvent(new LocalMediaEvent("device_list_updated", {
|
|
160
|
+
detail: {
|
|
161
|
+
cameraDevices: devices.filter((d) => d.kind === "videoinput"),
|
|
162
|
+
microphoneDevices: devices.filter((d) => d.kind === "audioinput"),
|
|
163
|
+
speakerDevices: devices.filter((d) => d.kind === "audiooutput"),
|
|
164
|
+
},
|
|
165
|
+
}));
|
|
166
|
+
this._devices = devices;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
this.dispatchEvent(new LocalMediaEvent("device_list_update_error", {
|
|
170
|
+
detail: {
|
|
171
|
+
error,
|
|
172
|
+
},
|
|
173
|
+
}));
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
start() {
|
|
179
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
+
yield this._updateDeviceList();
|
|
181
|
+
if (this._options) {
|
|
182
|
+
yield getStream(Object.assign(Object.assign({}, this._getConstraintsOptions()), { audioId: this._options.audio, videoId: this._options.video }), { replaceStream: this.stream });
|
|
183
|
+
const cameraTrack = this.stream.getVideoTracks()[0];
|
|
184
|
+
if (cameraTrack) {
|
|
185
|
+
this._cameraEnabled = cameraTrack.enabled;
|
|
186
|
+
this._currentCameraDeviceId = cameraTrack.getSettings().deviceId;
|
|
187
|
+
}
|
|
188
|
+
const microphoneTrack = this.stream.getAudioTracks()[0];
|
|
189
|
+
if (microphoneTrack) {
|
|
190
|
+
this._microphoneEnabled = microphoneTrack.enabled;
|
|
191
|
+
this._currentMicrophoneDeviceId = microphoneTrack.getSettings().deviceId;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
this.dispatchEvent(new LocalMediaEvent("stream_updated", {
|
|
195
|
+
detail: { stream: this.stream },
|
|
196
|
+
}));
|
|
197
|
+
return this.stream;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
stop() {
|
|
201
|
+
var _a;
|
|
202
|
+
if (this._options) {
|
|
203
|
+
(_a = this.stream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach((t) => {
|
|
204
|
+
t.stop();
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { RtcStreamAddedPayload } from "@whereby/jslib-media/src/webrtc/RtcManagerDispatcher";
|
|
2
|
+
import { LocalParticipant, RemoteParticipant, Screenshare, WaitingParticipant } from "./RoomParticipant";
|
|
3
|
+
import { ChatMessage as SignalChatMessage } from "@whereby/jslib-media/src/utils/ServerSocket";
|
|
4
|
+
import LocalMedia, { LocalMediaOptions } from "./LocalMedia";
|
|
5
|
+
type Logger = Pick<Console, "debug" | "error" | "log" | "warn" | "info">;
|
|
6
|
+
export interface RoomConnectionOptions {
|
|
7
|
+
displayName?: string;
|
|
8
|
+
localMediaOptions?: LocalMediaOptions;
|
|
9
|
+
roomKey?: string;
|
|
10
|
+
logger?: Logger;
|
|
11
|
+
localMedia?: LocalMedia;
|
|
12
|
+
externalId?: string;
|
|
13
|
+
}
|
|
14
|
+
export type ChatMessage = Pick<SignalChatMessage, "senderId" | "timestamp" | "text">;
|
|
15
|
+
export type ConnectionStatus = "initializing" | "connecting" | "connected" | "room_locked" | "knocking" | "disconnecting" | "disconnected" | "knock_rejected";
|
|
16
|
+
export type CloudRecordingState = {
|
|
17
|
+
error?: string;
|
|
18
|
+
status: "recording" | "requested" | "error";
|
|
19
|
+
startedAt?: number;
|
|
20
|
+
};
|
|
21
|
+
export type LiveStreamState = {
|
|
22
|
+
status: "streaming";
|
|
23
|
+
startedAt: number;
|
|
24
|
+
};
|
|
25
|
+
export type RoomJoinedEvent = {
|
|
26
|
+
localParticipant: LocalParticipant;
|
|
27
|
+
remoteParticipants: RemoteParticipant[];
|
|
28
|
+
waitingParticipants: WaitingParticipant[];
|
|
29
|
+
};
|
|
30
|
+
export type ConnectionStatusChangedEvent = {
|
|
31
|
+
connectionStatus: ConnectionStatus;
|
|
32
|
+
};
|
|
33
|
+
export type ParticipantJoinedEvent = {
|
|
34
|
+
remoteParticipant: RemoteParticipant;
|
|
35
|
+
};
|
|
36
|
+
export type ParticipantLeftEvent = {
|
|
37
|
+
participantId: string;
|
|
38
|
+
};
|
|
39
|
+
export type ParticipantStreamAddedEvent = {
|
|
40
|
+
participantId: string;
|
|
41
|
+
stream: MediaStream;
|
|
42
|
+
streamId: string;
|
|
43
|
+
};
|
|
44
|
+
export type ParticipantAudioEnabledEvent = {
|
|
45
|
+
participantId: string;
|
|
46
|
+
isAudioEnabled: boolean;
|
|
47
|
+
};
|
|
48
|
+
export type ParticipantVideoEnabledEvent = {
|
|
49
|
+
participantId: string;
|
|
50
|
+
isVideoEnabled: boolean;
|
|
51
|
+
};
|
|
52
|
+
export type ParticipantMetadataChangedEvent = {
|
|
53
|
+
participantId: string;
|
|
54
|
+
displayName: string;
|
|
55
|
+
};
|
|
56
|
+
export type ScreenshareStartedEvent = {
|
|
57
|
+
participantId: string;
|
|
58
|
+
id: string;
|
|
59
|
+
hasAudioTrack: boolean;
|
|
60
|
+
stream: MediaStream;
|
|
61
|
+
isLocal: boolean;
|
|
62
|
+
};
|
|
63
|
+
export type ScreenshareStoppedEvent = {
|
|
64
|
+
participantId: string;
|
|
65
|
+
id: string;
|
|
66
|
+
};
|
|
67
|
+
export type WaitingParticipantJoinedEvent = {
|
|
68
|
+
participantId: string;
|
|
69
|
+
displayName: string | null;
|
|
70
|
+
};
|
|
71
|
+
export type WaitingParticipantLeftEvent = {
|
|
72
|
+
participantId: string;
|
|
73
|
+
};
|
|
74
|
+
export type LocalCameraEnabledEvent = {
|
|
75
|
+
enabled: boolean;
|
|
76
|
+
};
|
|
77
|
+
export type LocalMicrophoneEnabledEvent = {
|
|
78
|
+
enabled: boolean;
|
|
79
|
+
};
|
|
80
|
+
export interface RoomEventsMap {
|
|
81
|
+
chat_message: (e: CustomEvent<ChatMessage>) => void;
|
|
82
|
+
cloud_recording_request_started: (e: CustomEvent<CloudRecordingState>) => void;
|
|
83
|
+
cloud_recording_started: (e: CustomEvent<CloudRecordingState>) => void;
|
|
84
|
+
cloud_recording_started_error: (e: CustomEvent<CloudRecordingState>) => void;
|
|
85
|
+
cloud_recording_stopped: (e: CustomEvent<CloudRecordingState>) => void;
|
|
86
|
+
local_camera_enabled: (e: CustomEvent<LocalCameraEnabledEvent>) => void;
|
|
87
|
+
local_microphone_enabled: (e: CustomEvent<LocalMicrophoneEnabledEvent>) => void;
|
|
88
|
+
participant_audio_enabled: (e: CustomEvent<ParticipantAudioEnabledEvent>) => void;
|
|
89
|
+
participant_joined: (e: CustomEvent<ParticipantJoinedEvent>) => void;
|
|
90
|
+
participant_left: (e: CustomEvent<ParticipantLeftEvent>) => void;
|
|
91
|
+
participant_metadata_changed: (e: CustomEvent<ParticipantMetadataChangedEvent>) => void;
|
|
92
|
+
participant_stream_added: (e: CustomEvent<ParticipantStreamAddedEvent>) => void;
|
|
93
|
+
participant_video_enabled: (e: CustomEvent<ParticipantVideoEnabledEvent>) => void;
|
|
94
|
+
connection_status_changed: (e: CustomEvent<ConnectionStatusChangedEvent>) => void;
|
|
95
|
+
room_joined: (e: CustomEvent<RoomJoinedEvent>) => void;
|
|
96
|
+
screenshare_started: (e: CustomEvent<ScreenshareStartedEvent>) => void;
|
|
97
|
+
screenshare_stopped: (e: CustomEvent<ScreenshareStoppedEvent>) => void;
|
|
98
|
+
streaming_started: (e: CustomEvent<LiveStreamState>) => void;
|
|
99
|
+
streaming_stopped: (e: CustomEvent<LiveStreamState>) => void;
|
|
100
|
+
waiting_participant_joined: (e: CustomEvent<WaitingParticipantJoinedEvent>) => void;
|
|
101
|
+
waiting_participant_left: (e: CustomEvent<WaitingParticipantLeftEvent>) => void;
|
|
102
|
+
}
|
|
103
|
+
type ArgType<T> = T extends (arg: infer U) => unknown ? U : never;
|
|
104
|
+
type RoomEventKey = keyof RoomEventsMap;
|
|
105
|
+
type RoomEventHandler<T extends RoomEventKey> = RoomEventsMap[T];
|
|
106
|
+
type RoomEventType<T extends RoomEventKey> = ArgType<RoomEventHandler<T>>;
|
|
107
|
+
type RoomEventPayload<T extends RoomEventKey> = RoomEventType<T> extends CustomEvent<infer U> ? U : never;
|
|
108
|
+
declare class RoomConnectionEvent<T extends RoomEventKey> extends CustomEvent<RoomEventPayload<T>> {
|
|
109
|
+
constructor(eventType: T, eventInitDict?: CustomEventInit<RoomEventPayload<T>>);
|
|
110
|
+
}
|
|
111
|
+
export declare function handleStreamAdded(remoteParticipants: RemoteParticipant[], { clientId, stream, streamId, streamType }: RtcStreamAddedPayload): RoomConnectionEvent<"participant_stream_added"> | RoomConnectionEvent<"screenshare_started"> | undefined;
|
|
112
|
+
interface RoomEventTarget extends EventTarget {
|
|
113
|
+
addEventListener<K extends keyof RoomEventsMap>(type: K, listener: RoomEventsMap[K], options?: boolean | AddEventListenerOptions): void;
|
|
114
|
+
addEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
|
|
115
|
+
removeEventListener<K extends keyof RoomEventsMap>(type: K, listener: RoomEventsMap[K], options?: boolean | EventListenerOptions): void;
|
|
116
|
+
removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
|
|
117
|
+
}
|
|
118
|
+
declare const TypedEventTarget: new () => RoomEventTarget;
|
|
119
|
+
export default class RoomConnection extends TypedEventTarget {
|
|
120
|
+
localMedia: LocalMedia;
|
|
121
|
+
localParticipant?: LocalParticipant;
|
|
122
|
+
roomUrl: URL;
|
|
123
|
+
remoteParticipants: RemoteParticipant[];
|
|
124
|
+
screenshares: Screenshare[];
|
|
125
|
+
readonly localMediaConstraints?: MediaStreamConstraints;
|
|
126
|
+
readonly roomName: string;
|
|
127
|
+
private organizationId;
|
|
128
|
+
private credentialsService;
|
|
129
|
+
private apiClient;
|
|
130
|
+
private organizationService;
|
|
131
|
+
private organizationServiceCache;
|
|
132
|
+
private organizationApiClient;
|
|
133
|
+
private roomService;
|
|
134
|
+
private _deviceCredentials;
|
|
135
|
+
private signalSocket;
|
|
136
|
+
private signalSocketManager;
|
|
137
|
+
private rtcManagerDispatcher?;
|
|
138
|
+
private rtcManager?;
|
|
139
|
+
private connectionStatus;
|
|
140
|
+
private selfId;
|
|
141
|
+
private logger;
|
|
142
|
+
private _ownsLocalMedia;
|
|
143
|
+
private displayName?;
|
|
144
|
+
private externalId?;
|
|
145
|
+
private _roomKey;
|
|
146
|
+
constructor(roomUrl: string, { displayName, localMedia, localMediaOptions: localMediaConstraints, logger, roomKey, externalId, }: RoomConnectionOptions);
|
|
147
|
+
get roomKey(): string | null;
|
|
148
|
+
private _handleNewChatMessage;
|
|
149
|
+
private _handleCloudRecordingStarted;
|
|
150
|
+
private _handleRecorderClientJoined;
|
|
151
|
+
private _handleStreamingStarted;
|
|
152
|
+
private _handleNewClient;
|
|
153
|
+
private _handleClientLeft;
|
|
154
|
+
private _handleClientAudioEnabled;
|
|
155
|
+
private _handleClientVideoEnabled;
|
|
156
|
+
private _handleClientMetadataReceived;
|
|
157
|
+
private _handleKnockHandled;
|
|
158
|
+
private _handleKnockerLeft;
|
|
159
|
+
private _handleRoomJoined;
|
|
160
|
+
private _handleRoomKnocked;
|
|
161
|
+
private _handleReconnect;
|
|
162
|
+
private _handleDisconnect;
|
|
163
|
+
private _handleCloudRecordingStopped;
|
|
164
|
+
private _handleStreamingStopped;
|
|
165
|
+
private _handleScreenshareStarted;
|
|
166
|
+
private _handleScreenshareStopped;
|
|
167
|
+
private _handleRtcEvent;
|
|
168
|
+
private _handleRtcManagerCreated;
|
|
169
|
+
private _handleRtcManagerDestroyed;
|
|
170
|
+
private _handleAcceptStreams;
|
|
171
|
+
private _handleStreamAdded;
|
|
172
|
+
private _joinRoom;
|
|
173
|
+
join(): Promise<void>;
|
|
174
|
+
knock(): void;
|
|
175
|
+
leave(): void;
|
|
176
|
+
sendChatMessage(text: string): void;
|
|
177
|
+
setDisplayName(displayName: string): void;
|
|
178
|
+
acceptWaitingParticipant(participantId: string): void;
|
|
179
|
+
rejectWaitingParticipant(participantId: string): void;
|
|
180
|
+
updateStreamResolution({ streamId, width, height }: {
|
|
181
|
+
streamId?: string;
|
|
182
|
+
width: number;
|
|
183
|
+
height: number;
|
|
184
|
+
}): void;
|
|
185
|
+
startScreenshare(): Promise<void>;
|
|
186
|
+
stopScreenshare(): void;
|
|
187
|
+
startCloudRecording(): void;
|
|
188
|
+
stopCloudRecording(): void;
|
|
189
|
+
}
|
|
190
|
+
export {};
|