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