@whereby.com/browser-sdk 2.0.0-alpha23 → 2.0.0-alpha25

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.
Files changed (83) hide show
  1. package/README.md +14 -0
  2. package/dist/LocalMedia.d.ts +53 -0
  3. package/dist/LocalMedia.js +154 -0
  4. package/dist/RoomConnection.d.ts +174 -0
  5. package/dist/RoomConnection.js +608 -0
  6. package/dist/RoomParticipant.d.ts +50 -0
  7. package/dist/RoomParticipant.js +48 -0
  8. package/dist/api/ApiClient.d.ts +26 -0
  9. package/dist/api/ApiClient.js +63 -0
  10. package/dist/api/Credentials.d.ts +17 -0
  11. package/dist/api/Credentials.js +16 -0
  12. package/dist/api/HttpClient.d.ts +16 -0
  13. package/dist/api/HttpClient.js +53 -0
  14. package/dist/api/MultipartHttpClient.d.ts +10 -0
  15. package/dist/api/MultipartHttpClient.js +25 -0
  16. package/dist/api/OrganizationApiClient.d.ts +16 -0
  17. package/dist/api/OrganizationApiClient.js +30 -0
  18. package/dist/api/Response.d.ts +29 -0
  19. package/dist/api/Response.js +9 -0
  20. package/dist/api/credentialsService/index.d.ts +27 -0
  21. package/dist/api/credentialsService/index.js +90 -0
  22. package/dist/api/deviceService/index.d.ts +9 -0
  23. package/dist/api/deviceService/index.js +25 -0
  24. package/dist/api/extractUtils.d.ts +16 -0
  25. package/dist/api/extractUtils.js +51 -0
  26. package/dist/api/index.d.ts +7 -0
  27. package/dist/api/index.js +7 -0
  28. package/dist/api/localStorageWrapper/index.d.ts +2 -0
  29. package/dist/api/localStorageWrapper/index.js +15 -0
  30. package/dist/api/models/Account.d.ts +20 -0
  31. package/dist/api/models/Account.js +24 -0
  32. package/dist/api/models/Meeting.d.ts +12 -0
  33. package/dist/api/models/Meeting.js +29 -0
  34. package/dist/api/models/Organization.d.ts +102 -0
  35. package/dist/api/models/Organization.js +81 -0
  36. package/dist/api/models/Room.d.ts +4 -0
  37. package/dist/api/models/Room.js +38 -0
  38. package/dist/api/models/account/EmbeddedFreeTierStatus.d.ts +13 -0
  39. package/dist/api/models/account/EmbeddedFreeTierStatus.js +17 -0
  40. package/dist/api/modules/AbstractStore.d.ts +5 -0
  41. package/dist/api/modules/AbstractStore.js +1 -0
  42. package/dist/api/modules/ChromeStorageStore.d.ts +10 -0
  43. package/dist/api/modules/ChromeStorageStore.js +21 -0
  44. package/dist/api/modules/LocalStorageStore.d.ts +9 -0
  45. package/dist/api/modules/LocalStorageStore.js +35 -0
  46. package/dist/api/modules/tests/__mocks__/storage.d.ts +10 -0
  47. package/dist/api/modules/tests/__mocks__/storage.js +19 -0
  48. package/dist/api/organizationService/index.d.ts +46 -0
  49. package/dist/api/organizationService/index.js +159 -0
  50. package/dist/api/organizationServiceCache/index.d.ts +13 -0
  51. package/dist/api/organizationServiceCache/index.js +20 -0
  52. package/dist/api/parameterAssertUtils.d.ts +13 -0
  53. package/dist/api/parameterAssertUtils.js +64 -0
  54. package/dist/api/roomService/index.d.ts +54 -0
  55. package/dist/api/roomService/index.js +160 -0
  56. package/dist/api/test/helpers.d.ts +5 -0
  57. package/dist/api/test/helpers.js +32 -0
  58. package/dist/api/types.d.ts +5 -0
  59. package/dist/api/types.js +1 -0
  60. package/dist/embed/index.d.ts +31 -0
  61. package/dist/embed/index.js +123 -0
  62. package/dist/index.d.ts +5 -0
  63. package/dist/index.js +5 -0
  64. package/dist/react/VideoView.d.ts +14 -0
  65. package/dist/react/VideoView.js +37 -0
  66. package/dist/react/index.d.ts +3 -0
  67. package/dist/react/index.js +3 -0
  68. package/dist/react/useLocalMedia.d.ts +28 -0
  69. package/dist/react/useLocalMedia.js +109 -0
  70. package/dist/react/useRoomConnection.d.ts +47 -0
  71. package/dist/react/useRoomConnection.js +283 -0
  72. package/dist/utils/debounce.d.ts +9 -0
  73. package/dist/utils/debounce.js +20 -0
  74. package/dist/utils/fakeAudioStream.d.ts +1 -0
  75. package/dist/utils/fakeAudioStream.js +18 -0
  76. package/dist/utils/fakeWebcamFrame.d.ts +1 -0
  77. package/dist/utils/fakeWebcamFrame.js +49 -0
  78. package/dist/v2-alpha25.js +1993 -0
  79. package/package.json +23 -11
  80. package/dist/lib.cjs +0 -6200
  81. package/dist/lib.esm.js +0 -6182
  82. package/dist/types.d.ts +0 -382
  83. package/dist/v2-alpha23.js +0 -43
@@ -0,0 +1,608 @@
1
+ import { __awaiter } from "tslib";
2
+ import RtcManagerDispatcher from "@whereby/jslib-media/src/webrtc/RtcManagerDispatcher";
3
+ import { fromLocation } from "@whereby/jslib-media/src/utils/urls";
4
+ import { ApiClient, CredentialsService, OrganizationApiClient, OrganizationService, OrganizationServiceCache, RoomService, } from "./api";
5
+ import { LocalParticipant, RemoteParticipant } from "./RoomParticipant";
6
+ import ServerSocket from "@whereby/jslib-media/src/utils/ServerSocket";
7
+ import { sdkVersion } from "./index";
8
+ import LocalMedia from "./LocalMedia";
9
+ const API_BASE_URL = process.env["REACT_APP_API_BASE_URL"] || "https://api.whereby.dev";
10
+ const SIGNAL_BASE_URL = process.env["REACT_APP_SIGNAL_BASE_URL"] || "wss://signal.appearin.net";
11
+ const NON_PERSON_ROLES = ["recorder", "streamer"];
12
+ const reportedStreamResolutions = new Map();
13
+ function createSocket() {
14
+ const parsedUrl = new URL(SIGNAL_BASE_URL);
15
+ const path = `${parsedUrl.pathname.replace(/^\/$/, "")}/protocol/socket.io/v4`;
16
+ const SOCKET_HOST = parsedUrl.origin;
17
+ const socketConf = {
18
+ autoConnect: false,
19
+ host: SOCKET_HOST,
20
+ path,
21
+ reconnectionDelay: 5000,
22
+ reconnectionDelayMax: 30000,
23
+ timeout: 10000,
24
+ withCredentials: true,
25
+ };
26
+ return new ServerSocket(SOCKET_HOST, socketConf);
27
+ }
28
+ export function handleStreamAdded(remoteParticipants, { clientId, stream, streamId, streamType }) {
29
+ if (!streamId) {
30
+ streamId = stream.id;
31
+ }
32
+ const remoteParticipant = remoteParticipants.find((p) => p.id === clientId);
33
+ if (!remoteParticipant) {
34
+ return;
35
+ }
36
+ const remoteParticipantStream = remoteParticipant.streams.find((s) => s.id === streamId) || remoteParticipant.streams[0];
37
+ if ((remoteParticipant.stream && remoteParticipant.stream.id === streamId) ||
38
+ (!remoteParticipant.stream && streamType === "webcam") ||
39
+ (!remoteParticipant.stream && !streamType && remoteParticipant.streams.indexOf(remoteParticipantStream) < 1)) {
40
+ return new CustomEvent("participant_stream_added", { detail: { participantId: clientId, stream, streamId } });
41
+ }
42
+ return new CustomEvent("screenshare_started", {
43
+ detail: { participantId: clientId, stream, id: streamId, isLocal: false },
44
+ });
45
+ }
46
+ const noop = () => {
47
+ return;
48
+ };
49
+ const TypedEventTarget = EventTarget;
50
+ export default class RoomConnection extends TypedEventTarget {
51
+ constructor(roomUrl, { displayName, localMedia, localMediaConstraints, logger, roomKey }) {
52
+ super();
53
+ this.localParticipant = null;
54
+ this.remoteParticipants = [];
55
+ this.screenshares = [];
56
+ this._deviceCredentials = null;
57
+ this._ownsLocalMedia = false;
58
+ this.organizationId = "";
59
+ this.roomConnectionStatus = "";
60
+ this.selfId = null;
61
+ this.roomUrl = new URL(roomUrl);
62
+ const searchParams = new URLSearchParams(this.roomUrl.search);
63
+ this._roomKey = roomKey || searchParams.get("roomKey");
64
+ this.roomName = this.roomUrl.pathname;
65
+ this.logger = logger || {
66
+ debug: noop,
67
+ error: noop,
68
+ log: noop,
69
+ warn: noop,
70
+ };
71
+ this.displayName = displayName;
72
+ this.localMediaConstraints = localMediaConstraints;
73
+ const urls = fromLocation({ host: this.roomUrl.host });
74
+ if (localMedia) {
75
+ this.localMedia = localMedia;
76
+ }
77
+ else if (localMediaConstraints) {
78
+ this.localMedia = new LocalMedia(localMediaConstraints);
79
+ this._ownsLocalMedia = true;
80
+ }
81
+ else {
82
+ throw new Error("Missing constraints");
83
+ }
84
+ this.credentialsService = CredentialsService.create({ baseUrl: API_BASE_URL });
85
+ this.apiClient = new ApiClient({
86
+ fetchDeviceCredentials: this.credentialsService.getCredentials.bind(this.credentialsService),
87
+ baseUrl: API_BASE_URL,
88
+ });
89
+ this.organizationService = new OrganizationService({ apiClient: this.apiClient });
90
+ this.organizationServiceCache = new OrganizationServiceCache({
91
+ organizationService: this.organizationService,
92
+ subdomain: urls.subdomain,
93
+ });
94
+ this.organizationApiClient = new OrganizationApiClient({
95
+ apiClient: this.apiClient,
96
+ fetchOrganization: () => __awaiter(this, void 0, void 0, function* () {
97
+ const organization = yield this.organizationServiceCache.fetchOrganization();
98
+ return organization || undefined;
99
+ }),
100
+ });
101
+ this.roomService = new RoomService({ organizationApiClient: this.organizationApiClient });
102
+ this.signalSocket = createSocket();
103
+ this.signalSocket.on("new_client", this._handleNewClient.bind(this));
104
+ this.signalSocket.on("chat_message", this._handleNewChatMessage.bind(this));
105
+ this.signalSocket.on("client_left", this._handleClientLeft.bind(this));
106
+ this.signalSocket.on("audio_enabled", this._handleClientAudioEnabled.bind(this));
107
+ this.signalSocket.on("video_enabled", this._handleClientVideoEnabled.bind(this));
108
+ this.signalSocket.on("client_metadata_received", this._handleClientMetadataReceived.bind(this));
109
+ this.signalSocket.on("knock_handled", this._handleKnockHandled.bind(this));
110
+ this.signalSocket.on("knocker_left", this._handleKnockerLeft.bind(this));
111
+ this.signalSocket.on("room_joined", this._handleRoomJoined.bind(this));
112
+ this.signalSocket.on("room_knocked", this._handleRoomKnocked.bind(this));
113
+ this.signalSocket.on("cloud_recording_stopped", this._handleCloudRecordingStopped.bind(this));
114
+ this.signalSocket.on("screenshare_started", this._handleScreenshareStarted.bind(this));
115
+ this.signalSocket.on("screenshare_stopped", this._handleScreenshareStopped.bind(this));
116
+ this.signalSocket.on("streaming_stopped", this._handleStreamingStopped.bind(this));
117
+ this.signalSocket.on("disconnect", this._handleDisconnect.bind(this));
118
+ this.signalSocket.on("connect_error", this._handleDisconnect.bind(this));
119
+ this.signalSocketManager = this.signalSocket.getManager();
120
+ this.signalSocketManager.on("reconnect", this._handleReconnect.bind(this));
121
+ this.localMedia.addEventListener("camera_enabled", (e) => {
122
+ const { enabled } = e.detail;
123
+ this.signalSocket.emit("enable_video", { enabled });
124
+ });
125
+ this.localMedia.addEventListener("microphone_enabled", (e) => {
126
+ const { enabled } = e.detail;
127
+ this.signalSocket.emit("enable_audio", { enabled });
128
+ });
129
+ const webrtcProvider = {
130
+ getMediaConstraints: () => ({
131
+ audio: this.localMedia.isMicrophoneEnabled(),
132
+ video: this.localMedia.isCameraEnabled(),
133
+ }),
134
+ deferrable(clientId) {
135
+ return !clientId;
136
+ },
137
+ };
138
+ this.rtcManagerDispatcher = new RtcManagerDispatcher({
139
+ emitter: {
140
+ emit: this._handleRtcEvent.bind(this),
141
+ },
142
+ serverSocket: this.signalSocket,
143
+ webrtcProvider,
144
+ features: {
145
+ lowDataModeEnabled: false,
146
+ sfuServerOverrideHost: undefined,
147
+ turnServerOverrideHost: undefined,
148
+ useOnlyTURN: undefined,
149
+ vp9On: false,
150
+ h264On: false,
151
+ simulcastScreenshareOn: false,
152
+ },
153
+ });
154
+ }
155
+ get roomKey() {
156
+ return this._roomKey;
157
+ }
158
+ _handleNewChatMessage(message) {
159
+ this.dispatchEvent(new CustomEvent("chat_message", { detail: message }));
160
+ }
161
+ _handleCloudRecordingStarted({ client }) {
162
+ this.dispatchEvent(new CustomEvent("cloud_recording_started", {
163
+ detail: {
164
+ status: "recording",
165
+ startedAt: client.startedCloudRecordingAt
166
+ ? new Date(client.startedCloudRecordingAt).getTime()
167
+ : new Date().getTime(),
168
+ },
169
+ }));
170
+ }
171
+ _handleStreamingStarted() {
172
+ this.dispatchEvent(new CustomEvent("streaming_started", {
173
+ detail: {
174
+ status: "streaming",
175
+ startedAt: new Date().getTime(),
176
+ },
177
+ }));
178
+ }
179
+ _handleNewClient({ client }) {
180
+ if (client.role.roleName === "recorder") {
181
+ this._handleCloudRecordingStarted({ client });
182
+ }
183
+ if (client.role.roleName === "streamer") {
184
+ this._handleStreamingStarted();
185
+ }
186
+ if (NON_PERSON_ROLES.includes(client.role.roleName)) {
187
+ return;
188
+ }
189
+ const remoteParticipant = new RemoteParticipant(Object.assign(Object.assign({}, client), { newJoiner: true }));
190
+ this.remoteParticipants = [...this.remoteParticipants, remoteParticipant];
191
+ this._handleAcceptStreams([remoteParticipant]);
192
+ this.dispatchEvent(new CustomEvent("participant_joined", { detail: { remoteParticipant } }));
193
+ }
194
+ _handleClientLeft({ clientId }) {
195
+ const remoteParticipant = this.remoteParticipants.find((p) => p.id === clientId);
196
+ this.remoteParticipants = this.remoteParticipants.filter((p) => p.id !== clientId);
197
+ if (!remoteParticipant) {
198
+ return;
199
+ }
200
+ this.dispatchEvent(new CustomEvent("participant_left", { detail: { participantId: remoteParticipant.id } }));
201
+ }
202
+ _handleClientAudioEnabled({ clientId, isAudioEnabled }) {
203
+ const remoteParticipant = this.remoteParticipants.find((p) => p.id === clientId);
204
+ if (!remoteParticipant) {
205
+ return;
206
+ }
207
+ this.dispatchEvent(new CustomEvent("participant_audio_enabled", {
208
+ detail: { participantId: remoteParticipant.id, isAudioEnabled },
209
+ }));
210
+ }
211
+ _handleClientVideoEnabled({ clientId, isVideoEnabled }) {
212
+ const remoteParticipant = this.remoteParticipants.find((p) => p.id === clientId);
213
+ if (!remoteParticipant) {
214
+ return;
215
+ }
216
+ this.dispatchEvent(new CustomEvent("participant_video_enabled", {
217
+ detail: { participantId: remoteParticipant.id, isVideoEnabled },
218
+ }));
219
+ }
220
+ _handleClientMetadataReceived({ payload: { clientId, displayName } }) {
221
+ const remoteParticipant = this.remoteParticipants.find((p) => p.id === clientId);
222
+ if (!remoteParticipant) {
223
+ return;
224
+ }
225
+ this.dispatchEvent(new CustomEvent("participant_metadata_changed", {
226
+ detail: { participantId: remoteParticipant.id, displayName },
227
+ }));
228
+ }
229
+ _handleKnockHandled(payload) {
230
+ const { clientId, resolution } = payload;
231
+ if (clientId !== this.selfId) {
232
+ return;
233
+ }
234
+ if (resolution === "accepted") {
235
+ this.roomConnectionStatus = "accepted";
236
+ this._roomKey = payload.metadata.roomKey;
237
+ this._joinRoom();
238
+ }
239
+ else if (resolution === "rejected") {
240
+ this.roomConnectionStatus = "rejected";
241
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
242
+ detail: {
243
+ roomConnectionStatus: this.roomConnectionStatus,
244
+ },
245
+ }));
246
+ }
247
+ }
248
+ _handleKnockerLeft(payload) {
249
+ const { clientId } = payload;
250
+ this.dispatchEvent(new CustomEvent("waiting_participant_left", {
251
+ detail: { participantId: clientId },
252
+ }));
253
+ }
254
+ _handleRoomJoined(event) {
255
+ const { error, isLocked, room, selfId } = event;
256
+ this.selfId = selfId;
257
+ if (error === "room_locked" && isLocked) {
258
+ this.roomConnectionStatus = "room_locked";
259
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
260
+ detail: {
261
+ roomConnectionStatus: this.roomConnectionStatus,
262
+ },
263
+ }));
264
+ return;
265
+ }
266
+ if (room) {
267
+ const { clients, knockers } = room;
268
+ const localClient = clients.find((c) => c.id === selfId);
269
+ if (!localClient)
270
+ throw new Error("Missing local client");
271
+ this.localParticipant = new LocalParticipant(Object.assign(Object.assign({}, localClient), { stream: this.localMedia.stream || undefined }));
272
+ const recorderClient = clients.find((c) => c.role.roleName === "recorder");
273
+ if (recorderClient) {
274
+ this._handleCloudRecordingStarted({ client: recorderClient });
275
+ }
276
+ const streamerClient = clients.find((c) => c.role.roleName === "streamer");
277
+ if (streamerClient) {
278
+ this._handleStreamingStarted();
279
+ }
280
+ this.remoteParticipants = clients
281
+ .filter((c) => c.id !== selfId)
282
+ .filter((c) => !NON_PERSON_ROLES.includes(c.role.roleName))
283
+ .map((c) => new RemoteParticipant(Object.assign(Object.assign({}, c), { newJoiner: false })));
284
+ this.roomConnectionStatus = "connected";
285
+ this.dispatchEvent(new CustomEvent("room_joined", {
286
+ detail: {
287
+ localParticipant: this.localParticipant,
288
+ remoteParticipants: this.remoteParticipants,
289
+ waitingParticipants: knockers.map((knocker) => {
290
+ return { id: knocker.clientId, displayName: knocker.displayName };
291
+ }),
292
+ },
293
+ }));
294
+ }
295
+ }
296
+ _handleRoomKnocked(event) {
297
+ const { clientId, displayName } = event;
298
+ this.dispatchEvent(new CustomEvent("waiting_participant_joined", {
299
+ detail: { participantId: clientId, displayName },
300
+ }));
301
+ }
302
+ _handleReconnect() {
303
+ this.logger.log("Reconnected to signal socket");
304
+ this.signalSocket.emit("identify_device", { deviceCredentials: this._deviceCredentials });
305
+ this.signalSocket.once("device_identified", () => {
306
+ this._joinRoom();
307
+ });
308
+ }
309
+ _handleDisconnect() {
310
+ this.roomConnectionStatus = "disconnected";
311
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
312
+ detail: {
313
+ roomConnectionStatus: this.roomConnectionStatus,
314
+ },
315
+ }));
316
+ }
317
+ _handleCloudRecordingStopped() {
318
+ this.dispatchEvent(new CustomEvent("cloud_recording_stopped"));
319
+ }
320
+ _handleStreamingStopped() {
321
+ this.dispatchEvent(new CustomEvent("streaming_stopped"));
322
+ }
323
+ _handleScreenshareStarted(screenshare) {
324
+ const { clientId: participantId, streamId: id, hasAudioTrack } = screenshare;
325
+ const remoteParticipant = this.remoteParticipants.find((p) => p.id === participantId);
326
+ if (!remoteParticipant) {
327
+ this.logger.log("WARN: Could not find participant for screenshare");
328
+ return;
329
+ }
330
+ const foundScreenshare = this.screenshares.find((s) => s.id === id);
331
+ if (foundScreenshare) {
332
+ this.logger.log("WARN: Screenshare already exists");
333
+ return;
334
+ }
335
+ remoteParticipant.addStream(id, "to_accept");
336
+ this._handleAcceptStreams([remoteParticipant]);
337
+ this.screenshares = [
338
+ ...this.screenshares,
339
+ { participantId, id, hasAudioTrack, stream: undefined, isLocal: false },
340
+ ];
341
+ }
342
+ _handleScreenshareStopped(screenshare) {
343
+ const { clientId: participantId, streamId: id } = screenshare;
344
+ const remoteParticipant = this.remoteParticipants.find((p) => p.id === participantId);
345
+ if (!remoteParticipant) {
346
+ this.logger.log("WARN: Could not find participant for screenshare");
347
+ return;
348
+ }
349
+ remoteParticipant.removeStream(id);
350
+ this.screenshares = this.screenshares.filter((s) => !(s.participantId === participantId && s.id === id));
351
+ this.dispatchEvent(new CustomEvent("screenshare_stopped", { detail: { participantId, id } }));
352
+ }
353
+ _handleRtcEvent(eventName, data) {
354
+ if (eventName === "rtc_manager_created") {
355
+ return this._handleRtcManagerCreated(data);
356
+ }
357
+ else if (eventName === "stream_added") {
358
+ return this._handleStreamAdded(data);
359
+ }
360
+ else if (eventName === "rtc_manager_destroyed") {
361
+ return this._handleRtcManagerDestroyed();
362
+ }
363
+ else {
364
+ this.logger.log(`Unhandled RTC event ${eventName}`);
365
+ }
366
+ }
367
+ _handleRtcManagerCreated({ rtcManager }) {
368
+ var _a;
369
+ this.rtcManager = rtcManager;
370
+ this.localMedia.addRtcManager(rtcManager);
371
+ if (this.localMedia.stream) {
372
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream("0", this.localMedia.stream, !this.localMedia.isMicrophoneEnabled(), !this.localMedia.isCameraEnabled());
373
+ }
374
+ if (this.remoteParticipants.length) {
375
+ this._handleAcceptStreams(this.remoteParticipants);
376
+ }
377
+ }
378
+ _handleRtcManagerDestroyed() {
379
+ this.rtcManager = undefined;
380
+ }
381
+ _handleAcceptStreams(remoteParticipants) {
382
+ var _a, _b;
383
+ if (!this.rtcManager) {
384
+ this.logger.log("Unable to accept streams, no rtc manager");
385
+ return;
386
+ }
387
+ const shouldAcceptNewClients = (_b = (_a = this.rtcManager).shouldAcceptStreamsFromBothSides) === null || _b === void 0 ? void 0 : _b.call(_a);
388
+ const activeBreakout = false;
389
+ const myselfBroadcasting = false;
390
+ remoteParticipants.forEach((participant) => {
391
+ const { id: participantId, streams, newJoiner } = participant;
392
+ streams.forEach((stream) => {
393
+ var _a, _b;
394
+ const { id: streamId, state: streamState } = stream;
395
+ let newState = undefined;
396
+ const isInSameRoomOrGroupOrClientBroadcasting = true;
397
+ if (isInSameRoomOrGroupOrClientBroadcasting) {
398
+ if (streamState !== "done_accept") {
399
+ newState = `${newJoiner && streamId === "0" ? "new" : "to"}_accept`;
400
+ }
401
+ }
402
+ else if (myselfBroadcasting) {
403
+ if (streamState !== "done_accept") {
404
+ newState = `${newJoiner && streamId === "0" ? "done" : "old"}_accept`;
405
+ }
406
+ }
407
+ else {
408
+ if (streamState !== "done_unaccept") {
409
+ newState = "to_unaccept";
410
+ }
411
+ }
412
+ if (!newState) {
413
+ return;
414
+ }
415
+ if (newState === "to_accept" ||
416
+ (newState === "new_accept" && shouldAcceptNewClients) ||
417
+ (newState === "old_accept" && !shouldAcceptNewClients)) {
418
+ this.logger.log(`Accepting stream ${streamId} from ${participantId}`);
419
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.acceptNewStream({
420
+ streamId: streamId === "0" ? participantId : streamId,
421
+ clientId: participantId,
422
+ shouldAddLocalVideo: streamId === "0",
423
+ activeBreakout,
424
+ });
425
+ }
426
+ else if (newState === "new_accept" || newState === "old_accept") {
427
+ }
428
+ else if (newState === "to_unaccept") {
429
+ this.logger.log(`Disconnecting stream ${streamId} from ${participantId}`);
430
+ (_b = this.rtcManager) === null || _b === void 0 ? void 0 : _b.disconnect(streamId === "0" ? participantId : streamId, activeBreakout);
431
+ }
432
+ else if (newState !== "done_accept") {
433
+ this.logger.warn(`Stream state not handled: ${newState} for ${participantId}-${streamId}`);
434
+ return;
435
+ }
436
+ else {
437
+ }
438
+ participant.updateStreamState(streamId, streamState.replace(/to_|new_|old_/, "done_"));
439
+ });
440
+ });
441
+ }
442
+ _handleStreamAdded(args) {
443
+ const streamAddedEvent = handleStreamAdded(this.remoteParticipants, args);
444
+ if (streamAddedEvent) {
445
+ this.dispatchEvent(streamAddedEvent);
446
+ }
447
+ }
448
+ _joinRoom() {
449
+ this.signalSocket.emit("join_room", {
450
+ avatarUrl: null,
451
+ config: {
452
+ isAudioEnabled: this.localMedia.isMicrophoneEnabled(),
453
+ isVideoEnabled: this.localMedia.isCameraEnabled(),
454
+ },
455
+ deviceCapabilities: { canScreenshare: true },
456
+ displayName: this.displayName,
457
+ isCoLocated: false,
458
+ isDevicePermissionDenied: false,
459
+ kickFromOtherRooms: false,
460
+ organizationId: this.organizationId,
461
+ roomKey: this.roomKey,
462
+ roomName: this.roomName,
463
+ selfId: "",
464
+ userAgent: `browser-sdk:${sdkVersion || "unknown"}`,
465
+ });
466
+ }
467
+ join() {
468
+ return __awaiter(this, void 0, void 0, function* () {
469
+ if (["connected", "connecting"].includes(this.roomConnectionStatus)) {
470
+ console.warn(`Trying to join when room state is already ${this.roomConnectionStatus}`);
471
+ return;
472
+ }
473
+ this.logger.log("Joining room");
474
+ this.signalSocket.connect();
475
+ this.roomConnectionStatus = "connecting";
476
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
477
+ detail: {
478
+ roomConnectionStatus: this.roomConnectionStatus,
479
+ },
480
+ }));
481
+ const organization = yield this.organizationServiceCache.fetchOrganization();
482
+ if (!organization) {
483
+ throw new Error("Invalid room url");
484
+ }
485
+ this.organizationId = organization.organizationId;
486
+ if (this._ownsLocalMedia) {
487
+ yield this.localMedia.start();
488
+ }
489
+ this._deviceCredentials = yield this.credentialsService.getCredentials();
490
+ this.logger.log("Connected to signal socket");
491
+ this.signalSocket.emit("identify_device", { deviceCredentials: this._deviceCredentials });
492
+ this.signalSocket.once("device_identified", () => {
493
+ this._joinRoom();
494
+ });
495
+ });
496
+ }
497
+ knock() {
498
+ this.roomConnectionStatus = "knocking";
499
+ this.dispatchEvent(new CustomEvent("room_connection_status_changed", {
500
+ detail: {
501
+ roomConnectionStatus: this.roomConnectionStatus,
502
+ },
503
+ }));
504
+ this.signalSocket.emit("knock_room", {
505
+ displayName: this.displayName,
506
+ imageUrl: null,
507
+ kickFromOtherRooms: true,
508
+ liveVideo: false,
509
+ organizationId: this.organizationId,
510
+ roomKey: this._roomKey,
511
+ roomName: this.roomName,
512
+ });
513
+ }
514
+ leave() {
515
+ this.roomConnectionStatus = "disconnecting";
516
+ if (this._ownsLocalMedia) {
517
+ this.localMedia.stop();
518
+ }
519
+ if (this.rtcManager) {
520
+ this.localMedia.removeRtcManager(this.rtcManager);
521
+ this.rtcManager.disconnectAll();
522
+ this.rtcManager = undefined;
523
+ }
524
+ if (!this.signalSocket) {
525
+ return;
526
+ }
527
+ this.signalSocket.emit("leave_room");
528
+ this.signalSocket.disconnect();
529
+ this.roomConnectionStatus = "disconnected";
530
+ }
531
+ sendChatMessage(text) {
532
+ this.signalSocket.emit("chat_message", {
533
+ text,
534
+ });
535
+ }
536
+ setDisplayName(displayName) {
537
+ this.signalSocket.emit("send_client_metadata", {
538
+ type: "UserData",
539
+ payload: {
540
+ displayName,
541
+ },
542
+ });
543
+ }
544
+ acceptWaitingParticipant(participantId) {
545
+ this.signalSocket.emit("handle_knock", {
546
+ action: "accept",
547
+ clientId: participantId,
548
+ response: {},
549
+ });
550
+ }
551
+ rejectWaitingParticipant(participantId) {
552
+ this.signalSocket.emit("handle_knock", {
553
+ action: "reject",
554
+ clientId: participantId,
555
+ response: {},
556
+ });
557
+ }
558
+ updateStreamResolution({ streamId, width, height }) {
559
+ var _a, _b;
560
+ if (!streamId || !this.rtcManager) {
561
+ return;
562
+ }
563
+ if (((_b = (_a = this.localParticipant) === null || _a === void 0 ? void 0 : _a.stream) === null || _b === void 0 ? void 0 : _b.id) === streamId) {
564
+ return;
565
+ }
566
+ const old = reportedStreamResolutions.get(streamId);
567
+ if (!old || old.width !== width || old.height !== height) {
568
+ this.rtcManager.updateStreamResolution(streamId, null, { width: width || 1, height: height || 1 });
569
+ }
570
+ reportedStreamResolutions.set(streamId, { width, height });
571
+ }
572
+ startScreenshare() {
573
+ var _a;
574
+ return __awaiter(this, void 0, void 0, function* () {
575
+ const screenshareStream = this.localMedia.screenshareStream || (yield this.localMedia.startScreenshare());
576
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.addNewStream(screenshareStream.id, screenshareStream, false, true);
577
+ this.screenshares = [
578
+ ...this.screenshares,
579
+ {
580
+ participantId: this.selfId || "",
581
+ id: screenshareStream.id,
582
+ hasAudioTrack: false,
583
+ stream: screenshareStream,
584
+ isLocal: true,
585
+ },
586
+ ];
587
+ this.dispatchEvent(new CustomEvent("screenshare_started", {
588
+ detail: {
589
+ participantId: this.selfId || "",
590
+ id: screenshareStream.id,
591
+ hasAudioTrack: false,
592
+ stream: screenshareStream,
593
+ isLocal: true,
594
+ },
595
+ }));
596
+ });
597
+ }
598
+ stopScreenshare() {
599
+ var _a;
600
+ if (this.localMedia.screenshareStream) {
601
+ const { id } = this.localMedia.screenshareStream;
602
+ (_a = this.rtcManager) === null || _a === void 0 ? void 0 : _a.removeStream(id, this.localMedia.screenshareStream, null);
603
+ this.screenshares = this.screenshares.filter((s) => s.id !== id);
604
+ this.dispatchEvent(new CustomEvent("screenshare_stopped", { detail: { participantId: this.selfId, id } }));
605
+ this.localMedia.stopScreenshare();
606
+ }
607
+ }
608
+ }
@@ -0,0 +1,50 @@
1
+ interface RoomParticipantData {
2
+ displayName: string;
3
+ id: string;
4
+ stream?: MediaStream;
5
+ isAudioEnabled: boolean;
6
+ isVideoEnabled: boolean;
7
+ }
8
+ export default class RoomParticipant {
9
+ readonly displayName: string;
10
+ readonly id: string;
11
+ readonly stream?: MediaStream;
12
+ readonly isAudioEnabled: boolean;
13
+ readonly isLocalParticipant: boolean;
14
+ readonly isVideoEnabled: boolean;
15
+ constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled }: RoomParticipantData);
16
+ }
17
+ interface RemoteParticipantData {
18
+ newJoiner: boolean;
19
+ streams: string[];
20
+ }
21
+ export type StreamState = "new_accept" | "to_accept" | "old_accept" | "done_accept" | "to_unaccept" | "done_unaccept" | "auto";
22
+ interface Stream {
23
+ id: string;
24
+ state: StreamState;
25
+ }
26
+ export declare class RemoteParticipant extends RoomParticipant {
27
+ readonly newJoiner: boolean;
28
+ readonly streams: Stream[];
29
+ constructor({ displayName, id, newJoiner, streams, isAudioEnabled, isVideoEnabled, }: RoomParticipantData & RemoteParticipantData);
30
+ addStream(streamId: string, state: StreamState): void;
31
+ removeStream(streamId: string): void;
32
+ updateStreamState(streamId: string, state: StreamState): void;
33
+ }
34
+ export declare class LocalParticipant extends RoomParticipant {
35
+ readonly isLocalParticipant = true;
36
+ constructor({ displayName, id, stream, isAudioEnabled, isVideoEnabled }: RoomParticipantData);
37
+ }
38
+ export interface WaitingParticipant {
39
+ id: string;
40
+ displayName: string | null;
41
+ }
42
+ export declare class Screenshare {
43
+ readonly participantId: string;
44
+ readonly id: string;
45
+ readonly hasAudioTrack: boolean;
46
+ readonly stream?: MediaStream;
47
+ readonly isLocal: boolean;
48
+ constructor({ participantId, id, hasAudioTrack, stream, isLocal }: Screenshare);
49
+ }
50
+ export {};