mediasfu-shared 1.1.0 → 1.2.0

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 (137) hide show
  1. package/README.md +17 -0
  2. package/dist/ProducerClient/producerClientEmits/createDeviceClient.d.ts +1 -1
  3. package/dist/ProducerClient/producerClientEmits/createDeviceClient.d.ts.map +1 -1
  4. package/dist/ProducerClient/producerClientEmits/updateRoomParametersClient.d.ts +1 -1
  5. package/dist/ProducerClient/producerClientEmits/updateRoomParametersClient.d.ts.map +1 -1
  6. package/dist/consumers/connectIps.d.ts +1 -1
  7. package/dist/consumers/connectIps.d.ts.map +1 -1
  8. package/dist/consumers/connectRecvTransport.d.ts +1 -1
  9. package/dist/consumers/connectRecvTransport.d.ts.map +1 -1
  10. package/dist/consumers/connectSendTransport.d.ts +1 -1
  11. package/dist/consumers/connectSendTransport.d.ts.map +1 -1
  12. package/dist/consumers/connectSendTransportAudio.d.ts +1 -1
  13. package/dist/consumers/connectSendTransportAudio.d.ts.map +1 -1
  14. package/dist/consumers/connectSendTransportScreen.d.ts +1 -1
  15. package/dist/consumers/connectSendTransportScreen.d.ts.map +1 -1
  16. package/dist/consumers/connectSendTransportVideo.d.ts +1 -1
  17. package/dist/consumers/connectSendTransportVideo.d.ts.map +1 -1
  18. package/dist/consumers/createSendTransport.d.ts +1 -1
  19. package/dist/consumers/createSendTransport.d.ts.map +1 -1
  20. package/dist/consumers/disconnectSendTransportAudio.d.ts +1 -1
  21. package/dist/consumers/disconnectSendTransportAudio.d.ts.map +1 -1
  22. package/dist/consumers/disconnectSendTransportScreen.d.ts +1 -1
  23. package/dist/consumers/disconnectSendTransportScreen.d.ts.map +1 -1
  24. package/dist/consumers/disconnectSendTransportVideo.d.ts +1 -1
  25. package/dist/consumers/disconnectSendTransportVideo.d.ts.map +1 -1
  26. package/dist/consumers/index.cjs +80 -0
  27. package/dist/consumers/index.cjs.map +1 -0
  28. package/dist/consumers/index.d.ts +62 -0
  29. package/dist/consumers/index.d.ts.map +1 -0
  30. package/dist/consumers/index.js +80 -0
  31. package/dist/consumers/index.js.map +1 -0
  32. package/dist/consumers/resumeSendTransportAudio.d.ts +1 -1
  33. package/dist/consumers/resumeSendTransportAudio.d.ts.map +1 -1
  34. package/dist/consumers/signalNewConsumerTransport.d.ts +1 -1
  35. package/dist/consumers/signalNewConsumerTransport.d.ts.map +1 -1
  36. package/dist/consumers/socketReceiveMethods/joinConsumeRoom.d.ts +1 -1
  37. package/dist/consumers/socketReceiveMethods/joinConsumeRoom.d.ts.map +1 -1
  38. package/dist/consumers/socketReceiveMethods/newPipeProducer.d.ts +1 -1
  39. package/dist/consumers/socketReceiveMethods/newPipeProducer.d.ts.map +1 -1
  40. package/dist/consumers/streamSuccessAudio.d.ts +1 -1
  41. package/dist/consumers/streamSuccessAudio.d.ts.map +1 -1
  42. package/dist/consumers/streamSuccessAudioSwitch.d.ts +1 -1
  43. package/dist/consumers/streamSuccessAudioSwitch.d.ts.map +1 -1
  44. package/dist/consumers/streamSuccessVideo.d.ts +1 -1
  45. package/dist/consumers/streamSuccessVideo.d.ts.map +1 -1
  46. package/dist/getParticipantMedia-B0JS6d2b.js +3555 -0
  47. package/dist/getParticipantMedia-B0JS6d2b.js.map +1 -0
  48. package/dist/getParticipantMedia-CdcYqcbD.cjs +3554 -0
  49. package/dist/getParticipantMedia-CdcYqcbD.cjs.map +1 -0
  50. package/dist/index.cjs +299 -252
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +1994 -1947
  55. package/dist/index.js.map +1 -1
  56. package/dist/index.native.cjs +230 -224
  57. package/dist/index.native.cjs.map +1 -1
  58. package/dist/index.native.js +349 -343
  59. package/dist/index.native.js.map +1 -1
  60. package/dist/joinLocalRoom-BdM1msQt.cjs +673 -0
  61. package/dist/joinLocalRoom-BdM1msQt.cjs.map +1 -0
  62. package/dist/joinLocalRoom-CvteNe4R.js +657 -0
  63. package/dist/joinLocalRoom-CvteNe4R.js.map +1 -0
  64. package/dist/joinRoomOnMediaSFU-CC8RVJgr.cjs +1222 -0
  65. package/dist/joinRoomOnMediaSFU-CC8RVJgr.cjs.map +1 -0
  66. package/dist/joinRoomOnMediaSFU-y6vJ1OBo.js +1223 -0
  67. package/dist/joinRoomOnMediaSFU-y6vJ1OBo.js.map +1 -0
  68. package/dist/methods/index.cjs +3975 -0
  69. package/dist/methods/index.cjs.map +1 -0
  70. package/dist/methods/index.js +3976 -0
  71. package/dist/methods/index.js.map +1 -0
  72. package/dist/methods/socketReceive/getDomains.d.ts +1 -1
  73. package/dist/methods/socketReceive/getDomains.d.ts.map +1 -1
  74. package/dist/methods/utils/headless/virtualBackground.d.ts +2 -2
  75. package/dist/methods/utils/headless/virtualBackground.d.ts.map +1 -1
  76. package/dist/methods/utils/virtualBackgroundCompositor.d.ts +21 -0
  77. package/dist/methods/utils/virtualBackgroundCompositor.d.ts.map +1 -0
  78. package/dist/methods/whiteboard/captureCanvasStream.d.ts +1 -1
  79. package/dist/methods/whiteboard/captureCanvasStream.d.ts.map +1 -1
  80. package/dist/producers/producerEmits/joinConRoom.d.ts +1 -1
  81. package/dist/producers/producerEmits/joinConRoom.d.ts.map +1 -1
  82. package/dist/producers/producerEmits/joinRoom.d.ts +1 -1
  83. package/dist/producers/producerEmits/joinRoom.d.ts.map +1 -1
  84. package/dist/translationConsumerSwitch-C20MfNNq.cjs +509 -0
  85. package/dist/translationConsumerSwitch-C20MfNNq.cjs.map +1 -0
  86. package/dist/translationConsumerSwitch-zKuS5wgH.js +510 -0
  87. package/dist/translationConsumerSwitch-zKuS5wgH.js.map +1 -0
  88. package/dist/types/index.cjs +85 -0
  89. package/dist/types/index.cjs.map +1 -0
  90. package/dist/types/index.d.ts +2 -0
  91. package/dist/types/index.d.ts.map +1 -0
  92. package/dist/types/index.js +85 -0
  93. package/dist/types/index.js.map +1 -0
  94. package/dist/types/shared-base-types.d.ts +1 -1
  95. package/dist/types/shared-base-types.d.ts.map +1 -1
  96. package/dist/updateParticipantAudioDecibels-DLd8Y-Fh.js +5392 -0
  97. package/dist/updateParticipantAudioDecibels-DLd8Y-Fh.js.map +1 -0
  98. package/dist/updateParticipantAudioDecibels-DPmHiy3K.cjs +5391 -0
  99. package/dist/updateParticipantAudioDecibels-DPmHiy3K.cjs.map +1 -0
  100. package/dist/validateAlphanumeric-DKn5BsUP.cjs +15 -0
  101. package/dist/validateAlphanumeric-DKn5BsUP.cjs.map +1 -0
  102. package/dist/validateAlphanumeric-Dk1JB80W.js +16 -0
  103. package/dist/validateAlphanumeric-Dk1JB80W.js.map +1 -0
  104. package/package.json +1 -1
  105. package/src/ProducerClient/producerClientEmits/createDeviceClient.ts +1 -2
  106. package/src/ProducerClient/producerClientEmits/updateRoomParametersClient.ts +1 -1
  107. package/src/consumers/connectIps.ts +1 -1
  108. package/src/consumers/connectRecvTransport.ts +1 -1
  109. package/src/consumers/connectSendTransport.ts +1 -1
  110. package/src/consumers/connectSendTransportAudio.ts +1 -1
  111. package/src/consumers/connectSendTransportScreen.ts +1 -1
  112. package/src/consumers/connectSendTransportVideo.ts +1 -1
  113. package/src/consumers/createSendTransport.ts +1 -1
  114. package/src/consumers/disconnectSendTransportAudio.ts +1 -1
  115. package/src/consumers/disconnectSendTransportScreen.ts +1 -1
  116. package/src/consumers/disconnectSendTransportVideo.ts +1 -1
  117. package/src/consumers/index.ts +61 -0
  118. package/src/consumers/resumeSendTransportAudio.ts +1 -1
  119. package/src/consumers/signalNewConsumerTransport.ts +1 -2
  120. package/src/consumers/socketReceiveMethods/joinConsumeRoom.ts +1 -1
  121. package/src/consumers/socketReceiveMethods/newPipeProducer.ts +1 -1
  122. package/src/consumers/streamSuccessAudio.ts +1 -2
  123. package/src/consumers/streamSuccessAudioSwitch.ts +1 -2
  124. package/src/consumers/streamSuccessVideo.ts +1 -1
  125. package/src/index.ts +2 -0
  126. package/src/methods/socketReceive/getDomains.ts +1 -1
  127. package/src/methods/utils/headless/virtualBackground.ts +45 -30
  128. package/src/methods/utils/virtualBackgroundCompositor.ts +53 -0
  129. package/src/methods/whiteboard/captureCanvasStream.ts +2 -2
  130. package/src/producers/producerEmits/joinConRoom.ts +1 -1
  131. package/src/producers/producerEmits/joinRoom.ts +1 -1
  132. package/src/types/index.ts +1 -0
  133. package/src/types/shared-base-types.ts +2 -3
  134. package/dist/getParticipantMedia-D9ChmEqq.js +0 -15265
  135. package/dist/getParticipantMedia-D9ChmEqq.js.map +0 -1
  136. package/dist/getParticipantMedia-DWvIhPPY.cjs +0 -15281
  137. package/dist/getParticipantMedia-DWvIhPPY.cjs.map +0 -1
@@ -0,0 +1,3554 @@
1
+ "use strict";
2
+ const joinLocalRoom = require("./joinLocalRoom-BdM1msQt.cjs");
3
+ const updateParticipantAudioDecibels = require("./updateParticipantAudioDecibels-DPmHiy3K.cjs");
4
+ const launchBackground = ({
5
+ updateIsBackgroundModalVisible,
6
+ isBackgroundModalVisible
7
+ }) => {
8
+ updateIsBackgroundModalVisible(!isBackgroundModalVisible);
9
+ };
10
+ const handleStartBreakout = ({
11
+ socket,
12
+ localSocket,
13
+ breakoutRooms,
14
+ newParticipantAction,
15
+ roomName,
16
+ breakOutRoomStarted,
17
+ breakOutRoomEnded,
18
+ showAlert,
19
+ updateBreakOutRoomStarted,
20
+ updateBreakOutRoomEnded,
21
+ onBreakoutRoomsClose,
22
+ meetingDisplayType,
23
+ updateMeetingDisplayType
24
+ }) => {
25
+ const emitName = breakOutRoomStarted && !breakOutRoomEnded ? "updateBreakout" : "startBreakout";
26
+ const filteredBreakoutRooms = breakoutRooms.map(
27
+ (room) => room.map(({ name, breakRoom }) => ({ name, breakRoom }))
28
+ );
29
+ socket.emit(
30
+ emitName,
31
+ { breakoutRooms: filteredBreakoutRooms, newParticipantAction, roomName },
32
+ (response) => {
33
+ if (response.success) {
34
+ showAlert?.({ message: "Breakout rooms active", type: "success" });
35
+ updateBreakOutRoomStarted(true);
36
+ updateBreakOutRoomEnded(false);
37
+ onBreakoutRoomsClose();
38
+ if (meetingDisplayType !== "all") {
39
+ updateMeetingDisplayType("all");
40
+ }
41
+ } else {
42
+ showAlert?.({ message: response.reason, type: "danger" });
43
+ }
44
+ }
45
+ );
46
+ if (localSocket && localSocket.id) {
47
+ try {
48
+ localSocket.emit(
49
+ emitName,
50
+ { breakoutRooms: filteredBreakoutRooms, newParticipantAction, roomName },
51
+ (response) => {
52
+ if (response.success) {
53
+ }
54
+ }
55
+ );
56
+ } catch {
57
+ console.log("Error starting local breakout rooms:");
58
+ }
59
+ }
60
+ };
61
+ const handleStopBreakout = ({
62
+ socket,
63
+ localSocket,
64
+ roomName,
65
+ showAlert,
66
+ updateBreakOutRoomStarted,
67
+ updateBreakOutRoomEnded,
68
+ onBreakoutRoomsClose,
69
+ meetingDisplayType,
70
+ prevMeetingDisplayType,
71
+ updateMeetingDisplayType
72
+ }) => {
73
+ socket.emit("stopBreakout", { roomName }, (response) => {
74
+ if (response.success) {
75
+ showAlert?.({ message: "Breakout rooms stopped", type: "success" });
76
+ updateBreakOutRoomStarted(false);
77
+ updateBreakOutRoomEnded(true);
78
+ onBreakoutRoomsClose();
79
+ if (meetingDisplayType !== prevMeetingDisplayType) {
80
+ updateMeetingDisplayType(prevMeetingDisplayType);
81
+ }
82
+ } else {
83
+ showAlert?.({ message: response.reason, type: "danger" });
84
+ }
85
+ });
86
+ if (localSocket && localSocket.id) {
87
+ try {
88
+ localSocket.emit("stopBreakout", { roomName }, (response) => {
89
+ if (response.success) {
90
+ }
91
+ });
92
+ } catch {
93
+ console.log("Error stopping local breakout rooms:");
94
+ }
95
+ }
96
+ };
97
+ const launchBreakoutRooms = ({
98
+ updateIsBreakoutRoomsModalVisible,
99
+ isBreakoutRoomsModalVisible
100
+ }) => {
101
+ updateIsBreakoutRoomsModalVisible(!isBreakoutRoomsModalVisible);
102
+ };
103
+ const launchCoHost = ({ updateIsCoHostModalVisible, isCoHostModalVisible }) => {
104
+ updateIsCoHostModalVisible(!isCoHostModalVisible);
105
+ };
106
+ const modifyCoHostSettings = async ({
107
+ roomName,
108
+ // showAlert,
109
+ selectedParticipant,
110
+ coHost,
111
+ coHostResponsibility,
112
+ updateIsCoHostModalVisible,
113
+ updateCoHostResponsibility,
114
+ updateCoHost,
115
+ socket
116
+ }) => {
117
+ let newCoHost = coHost;
118
+ if (coHost !== "No coHost" || selectedParticipant && selectedParticipant !== "Select a participant") {
119
+ if (selectedParticipant && selectedParticipant !== "Select a participant") {
120
+ newCoHost = selectedParticipant;
121
+ updateCoHost(newCoHost);
122
+ }
123
+ updateCoHostResponsibility(coHostResponsibility);
124
+ socket.emit("updateCoHost", {
125
+ roomName,
126
+ coHost: newCoHost,
127
+ coHostResponsibility
128
+ });
129
+ }
130
+ updateIsCoHostModalVisible(false);
131
+ };
132
+ const launchDisplaySettings = ({
133
+ updateIsDisplaySettingsModalVisible,
134
+ isDisplaySettingsModalVisible
135
+ }) => {
136
+ updateIsDisplaySettingsModalVisible(!isDisplaySettingsModalVisible);
137
+ };
138
+ const modifyDisplaySettings = async ({
139
+ parameters
140
+ }) => {
141
+ let {
142
+ showAlert,
143
+ meetingDisplayType,
144
+ autoWave,
145
+ forceFullDisplay,
146
+ showSubtitlesOnCards = true,
147
+ meetingVideoOptimized,
148
+ islevel,
149
+ recordStarted,
150
+ recordResumed,
151
+ recordStopped,
152
+ recordPaused,
153
+ recordingDisplayType,
154
+ recordingVideoOptimized,
155
+ prevForceFullDisplay,
156
+ prevMeetingDisplayType,
157
+ updateMeetingDisplayType,
158
+ updateAutoWave,
159
+ updateForceFullDisplay,
160
+ updateShowSubtitlesOnCards,
161
+ updateMeetingVideoOptimized,
162
+ updatePrevForceFullDisplay,
163
+ updatePrevMeetingDisplayType,
164
+ updateIsDisplaySettingsModalVisible,
165
+ updateFirstAll,
166
+ updateUpdateMainWindow,
167
+ breakOutRoomStarted,
168
+ breakOutRoomEnded,
169
+ onScreenChanges
170
+ } = parameters;
171
+ updateAutoWave(autoWave);
172
+ updateForceFullDisplay(forceFullDisplay);
173
+ updateShowSubtitlesOnCards?.(showSubtitlesOnCards);
174
+ if (islevel === "2" && (recordStarted || recordResumed) && !recordStopped && !recordPaused) {
175
+ if (recordingDisplayType === "video" && meetingDisplayType === "video" && meetingVideoOptimized && !recordingVideoOptimized) {
176
+ showAlert?.({
177
+ message: "Meeting display type can be either video, media, or all when recording display type is non-optimized video.",
178
+ type: "danger",
179
+ duration: 3e3
180
+ });
181
+ meetingDisplayType = recordingDisplayType;
182
+ updateMeetingDisplayType(meetingDisplayType);
183
+ meetingVideoOptimized = recordingVideoOptimized;
184
+ updateMeetingVideoOptimized(meetingVideoOptimized);
185
+ return;
186
+ } else if (recordingDisplayType === "media" && meetingDisplayType === "video") {
187
+ showAlert?.({
188
+ message: "Meeting display type can be either media or all when recording display type is media.",
189
+ type: "danger",
190
+ duration: 3e3
191
+ });
192
+ meetingDisplayType = recordingDisplayType;
193
+ updateMeetingDisplayType(meetingDisplayType);
194
+ return;
195
+ } else if (recordingDisplayType === "all" && (meetingDisplayType === "video" || meetingDisplayType === "media")) {
196
+ showAlert?.({
197
+ message: "Meeting display type can be only all when recording display type is all.",
198
+ type: "danger",
199
+ duration: 3e3
200
+ });
201
+ meetingDisplayType = recordingDisplayType;
202
+ updateMeetingDisplayType(meetingDisplayType);
203
+ return;
204
+ }
205
+ }
206
+ updateMeetingDisplayType(meetingDisplayType);
207
+ updateMeetingVideoOptimized(meetingVideoOptimized);
208
+ updateIsDisplaySettingsModalVisible(false);
209
+ if (prevMeetingDisplayType !== meetingDisplayType || prevForceFullDisplay !== forceFullDisplay) {
210
+ if (breakOutRoomStarted && !breakOutRoomEnded && meetingDisplayType !== "all") {
211
+ showAlert?.({
212
+ message: "Breakout room is active. Display type can only be all.",
213
+ type: "danger"
214
+ });
215
+ meetingDisplayType = prevMeetingDisplayType;
216
+ updateMeetingDisplayType(prevMeetingDisplayType);
217
+ return;
218
+ }
219
+ updateFirstAll(meetingDisplayType !== "all" ? true : false);
220
+ updateUpdateMainWindow(true);
221
+ await onScreenChanges({
222
+ changed: true,
223
+ parameters: { ...parameters, meetingDisplayType, forceFullDisplay }
224
+ });
225
+ updatePrevForceFullDisplay(forceFullDisplay);
226
+ updatePrevMeetingDisplayType(meetingDisplayType);
227
+ }
228
+ };
229
+ const confirmExit = async ({
230
+ socket,
231
+ localSocket,
232
+ member,
233
+ roomName,
234
+ ban = false,
235
+ endRoomOnHostExit = true
236
+ }) => {
237
+ socket.emit("disconnectUser", {
238
+ member,
239
+ roomName,
240
+ ban,
241
+ endRoomOnHostExit
242
+ });
243
+ if (localSocket && localSocket.id) {
244
+ localSocket.emit("disconnectUser", {
245
+ member,
246
+ roomName,
247
+ ban,
248
+ endRoomOnHostExit
249
+ });
250
+ }
251
+ };
252
+ const launchConfirmExit = ({
253
+ updateIsConfirmExitModalVisible,
254
+ isConfirmExitModalVisible
255
+ }) => {
256
+ updateIsConfirmExitModalVisible(!isConfirmExitModalVisible);
257
+ };
258
+ const launchMediaSettings = async ({
259
+ updateIsMediaSettingsModalVisible,
260
+ isMediaSettingsModalVisible,
261
+ mediaDevices,
262
+ audioInputs,
263
+ videoInputs,
264
+ updateAudioInputs,
265
+ updateVideoInputs
266
+ }) => {
267
+ if (!isMediaSettingsModalVisible) {
268
+ try {
269
+ const devices = await mediaDevices.enumerateDevices();
270
+ videoInputs = devices.filter((device) => device.kind === "videoinput");
271
+ audioInputs = devices.filter((device) => device.kind === "audioinput");
272
+ updateVideoInputs(videoInputs);
273
+ updateAudioInputs(audioInputs);
274
+ } catch (error) {
275
+ console.log("Error getting media devices", error);
276
+ }
277
+ }
278
+ updateIsMediaSettingsModalVisible(!isMediaSettingsModalVisible);
279
+ };
280
+ const launchMenuModal = ({
281
+ updateIsMenuModalVisible,
282
+ isMenuModalVisible
283
+ }) => {
284
+ updateIsMenuModalVisible(!isMenuModalVisible);
285
+ };
286
+ const launchMessages = ({ updateIsMessagesModalVisible, isMessagesModalVisible }) => {
287
+ updateIsMessagesModalVisible(!isMessagesModalVisible);
288
+ };
289
+ const sendMessage = async ({
290
+ message,
291
+ receivers,
292
+ group,
293
+ messagesLength,
294
+ member,
295
+ sender,
296
+ islevel,
297
+ showAlert,
298
+ coHostResponsibility,
299
+ coHost,
300
+ roomName,
301
+ socket,
302
+ chatSetting
303
+ }) => {
304
+ let chatValue = false;
305
+ const normalizedReceivers = (receivers ?? []).filter(
306
+ (receiver) => typeof receiver === "string" && receiver.trim().length > 0
307
+ );
308
+ if (messagesLength > 100 && roomName.startsWith("d") || messagesLength > 500 && roomName.startsWith("s") || messagesLength > 1e5 && roomName.startsWith("p")) {
309
+ showAlert?.({
310
+ message: "You have reached the maximum number of messages allowed.",
311
+ type: "danger",
312
+ duration: 3e3
313
+ });
314
+ return;
315
+ }
316
+ if (!message || message === "") {
317
+ showAlert?.({
318
+ message: "Message is not valid.",
319
+ type: "danger",
320
+ duration: 3e3
321
+ });
322
+ return;
323
+ }
324
+ if (normalizedReceivers.length < 1 && group === false && islevel === "2") {
325
+ showAlert?.({
326
+ message: "Please select a message to reply to",
327
+ type: "danger",
328
+ duration: 3e3
329
+ });
330
+ return;
331
+ }
332
+ const messageObject = {
333
+ sender: sender ? sender : member,
334
+ receivers: normalizedReceivers,
335
+ message,
336
+ timestamp: (/* @__PURE__ */ new Date()).toLocaleTimeString(),
337
+ group: group !== void 0 && group !== null ? group : false
338
+ };
339
+ try {
340
+ chatValue = coHostResponsibility.find((item) => item.name === "chat")?.value ?? false;
341
+ } catch (error) {
342
+ console.error(error);
343
+ }
344
+ if (islevel === "2" || coHost === member && chatValue === true) ;
345
+ else {
346
+ if (!chatSetting) {
347
+ showAlert?.({
348
+ message: "You are not allowed to send a message in this event room",
349
+ type: "danger",
350
+ duration: 3e3
351
+ });
352
+ return;
353
+ }
354
+ }
355
+ socket.emit("sendMessage", {
356
+ messageObject,
357
+ roomName
358
+ });
359
+ };
360
+ const launchParticipants = ({ updateIsParticipantsModalVisible, isParticipantsModalVisible }) => {
361
+ updateIsParticipantsModalVisible(!isParticipantsModalVisible);
362
+ };
363
+ const messageParticipants = ({
364
+ coHostResponsibility = [],
365
+ participant,
366
+ member,
367
+ islevel,
368
+ showAlert,
369
+ coHost,
370
+ updateIsMessagesModalVisible,
371
+ updateDirectMessageDetails,
372
+ updateStartDirectMessage
373
+ }) => {
374
+ let chatValue = false;
375
+ try {
376
+ chatValue = coHostResponsibility.find((item) => item.name === "chat")?.value ?? false;
377
+ } catch (error) {
378
+ console.error(error);
379
+ }
380
+ if (islevel === "2" || coHost === member && chatValue === true) {
381
+ if (participant.islevel !== "2") {
382
+ updateDirectMessageDetails(participant);
383
+ updateStartDirectMessage(true);
384
+ updateIsMessagesModalVisible(true);
385
+ }
386
+ } else {
387
+ showAlert?.({
388
+ message: "You are not allowed to send this message",
389
+ type: "danger",
390
+ duration: 3e3
391
+ });
392
+ return;
393
+ }
394
+ };
395
+ const muteParticipants = async ({
396
+ socket,
397
+ coHostResponsibility = [],
398
+ participant,
399
+ member,
400
+ islevel,
401
+ showAlert,
402
+ coHost,
403
+ roomName
404
+ }) => {
405
+ let mediaValue = false;
406
+ try {
407
+ mediaValue = coHostResponsibility.find((item) => item.name === "media")?.value ?? false;
408
+ } catch (error) {
409
+ console.error(error);
410
+ }
411
+ if (islevel === "2" || coHost === member && mediaValue) {
412
+ if (!participant.muted && participant.islevel !== "2") {
413
+ const participantId = participant.id;
414
+ socket.emit("controlMedia", {
415
+ participantId,
416
+ participantName: participant.name,
417
+ type: "all",
418
+ roomName
419
+ });
420
+ }
421
+ } else {
422
+ showAlert?.({
423
+ message: "You are not allowed to mute other participants",
424
+ type: "danger",
425
+ duration: 3e3
426
+ });
427
+ }
428
+ };
429
+ const removeParticipants = async ({
430
+ coHostResponsibility,
431
+ participant,
432
+ member,
433
+ islevel,
434
+ showAlert,
435
+ coHost,
436
+ participants,
437
+ socket,
438
+ roomName,
439
+ updateParticipants
440
+ }) => {
441
+ let participantsValue = false;
442
+ try {
443
+ participantsValue = coHostResponsibility.find((item) => item.name === "participants")?.value ?? false;
444
+ } catch {
445
+ participantsValue = false;
446
+ }
447
+ if (islevel === "2" || coHost === member && participantsValue === true) {
448
+ if (participant.islevel !== "2") {
449
+ const participantId = participant.id;
450
+ socket.emit("disconnectUserInitiate", {
451
+ member: participant.name,
452
+ roomName,
453
+ id: participantId
454
+ });
455
+ const index = participants.findIndex((obj) => obj.name === participant.name);
456
+ if (index !== -1) {
457
+ participants.splice(index, 1);
458
+ }
459
+ updateParticipants(participants);
460
+ }
461
+ } else {
462
+ showAlert?.({
463
+ message: "You are not allowed to remove other participants",
464
+ type: "danger",
465
+ duration: 3e3
466
+ });
467
+ }
468
+ };
469
+ const handleCreatePoll = async ({
470
+ poll,
471
+ socket,
472
+ roomName,
473
+ showAlert,
474
+ updateIsPollModalVisible
475
+ }) => {
476
+ try {
477
+ socket.emit(
478
+ "createPoll",
479
+ { roomName, poll },
480
+ (response) => {
481
+ if (response.success) {
482
+ showAlert?.({ message: "Poll created successfully", type: "success" });
483
+ updateIsPollModalVisible(false);
484
+ } else {
485
+ showAlert?.({ message: response.reason || "Failed to create poll", type: "danger" });
486
+ }
487
+ }
488
+ );
489
+ } catch (error) {
490
+ console.error("Error creating poll:", error);
491
+ }
492
+ };
493
+ const handleEndPoll = async ({
494
+ pollId,
495
+ socket,
496
+ showAlert,
497
+ roomName,
498
+ updateIsPollModalVisible
499
+ }) => {
500
+ try {
501
+ socket.emit(
502
+ "endPoll",
503
+ { roomName, poll_id: pollId },
504
+ (response) => {
505
+ if (response.success) {
506
+ showAlert?.({
507
+ message: "Poll ended successfully",
508
+ type: "success"
509
+ });
510
+ updateIsPollModalVisible(false);
511
+ } else {
512
+ showAlert?.({ message: response.reason || "Failed to end poll", type: "danger" });
513
+ }
514
+ }
515
+ );
516
+ } catch (error) {
517
+ console.error("Error ending poll:", error);
518
+ }
519
+ };
520
+ const handleVotePoll = async ({
521
+ pollId,
522
+ optionIndex,
523
+ socket,
524
+ showAlert,
525
+ member,
526
+ roomName,
527
+ updateIsPollModalVisible
528
+ }) => {
529
+ try {
530
+ socket.emit(
531
+ "votePoll",
532
+ {
533
+ roomName,
534
+ poll_id: pollId,
535
+ member,
536
+ choice: optionIndex
537
+ },
538
+ (response) => {
539
+ if (response.success) {
540
+ showAlert?.({
541
+ message: "Vote submitted successfully",
542
+ type: "success"
543
+ });
544
+ updateIsPollModalVisible(false);
545
+ } else {
546
+ showAlert?.({ message: response.reason || "Failed to submit vote", type: "danger" });
547
+ }
548
+ }
549
+ );
550
+ } catch (error) {
551
+ console.error("Error submitting vote:", error);
552
+ }
553
+ };
554
+ const launchPoll = ({ updateIsPollModalVisible, isPollModalVisible }) => {
555
+ updateIsPollModalVisible(!isPollModalVisible);
556
+ };
557
+ const checkPauseState = async ({
558
+ recordingMediaOptions,
559
+ recordingVideoPausesLimit,
560
+ recordingAudioPausesLimit,
561
+ pauseRecordCount,
562
+ showAlert
563
+ }) => {
564
+ const refLimit = recordingMediaOptions === "video" ? recordingVideoPausesLimit : recordingAudioPausesLimit;
565
+ if (pauseRecordCount < refLimit) {
566
+ return true;
567
+ }
568
+ showAlert?.({
569
+ message: "You have reached the limit of pauses - you can choose to stop recording.",
570
+ type: "danger",
571
+ duration: 3e3
572
+ });
573
+ return false;
574
+ };
575
+ const checkResumeState = async ({
576
+ recordingMediaOptions,
577
+ recordingVideoPausesLimit,
578
+ recordingAudioPausesLimit,
579
+ pauseRecordCount
580
+ }) => {
581
+ const refLimit = recordingMediaOptions === "video" ? recordingVideoPausesLimit : recordingAudioPausesLimit;
582
+ return pauseRecordCount <= refLimit;
583
+ };
584
+ const ALERT_DURATION = 6e3;
585
+ const FULL_PARTICIPANT_RECORDING_ALERT_MESSAGE = "You are not allowed to record videos of all participants while the meeting display is set to All. Switch the meeting display to Media and try again.";
586
+ const confirmRecording = async ({
587
+ parameters
588
+ }) => {
589
+ parameters = parameters.getUpdatedAllParams();
590
+ let {
591
+ showAlert,
592
+ recordingMediaOptions,
593
+ recordingAudioOptions,
594
+ recordingVideoOptions,
595
+ recordingVideoType,
596
+ recordingDisplayType,
597
+ recordingNameTags,
598
+ recordingBackgroundColor,
599
+ recordingNameTagsColor,
600
+ recordingOrientationVideo,
601
+ recordingAddHLS,
602
+ recordingAddText,
603
+ recordingCustomText,
604
+ recordingCustomTextPosition,
605
+ recordingCustomTextColor,
606
+ meetingDisplayType,
607
+ recordingVideoParticipantsFullRoomSupport,
608
+ recordingAllParticipantsSupport,
609
+ recordingVideoParticipantsSupport,
610
+ recordingSupportForOtherOrientation,
611
+ recordingPreferredOrientation,
612
+ recordingMultiFormatsSupport,
613
+ recordingVideoOptimized,
614
+ recordingAllParticipantsFullRoomSupport,
615
+ meetingVideoOptimized,
616
+ eventType,
617
+ breakOutRoomStarted,
618
+ breakOutRoomEnded,
619
+ updateRecordingDisplayType,
620
+ updateRecordingVideoOptimized,
621
+ updateUserRecordingParams,
622
+ updateConfirmedToRecord
623
+ } = parameters;
624
+ if (!recordingVideoParticipantsFullRoomSupport && recordingVideoOptions === "all" && recordingMediaOptions === "video") {
625
+ if (meetingDisplayType === "all" && !(breakOutRoomStarted && !breakOutRoomEnded)) {
626
+ showAlert?.({
627
+ message: FULL_PARTICIPANT_RECORDING_ALERT_MESSAGE,
628
+ type: "danger",
629
+ duration: ALERT_DURATION
630
+ });
631
+ return;
632
+ }
633
+ }
634
+ if (!recordingAllParticipantsSupport && recordingVideoOptions === "all") {
635
+ showAlert?.({
636
+ message: "You are only allowed to record yourself.",
637
+ type: "danger",
638
+ duration: ALERT_DURATION
639
+ });
640
+ return;
641
+ }
642
+ if (!recordingVideoParticipantsSupport && recordingDisplayType === "video") {
643
+ showAlert?.({
644
+ message: "You are not allowed to record other video participants.",
645
+ type: "danger",
646
+ duration: ALERT_DURATION
647
+ });
648
+ return;
649
+ }
650
+ if (!recordingSupportForOtherOrientation && recordingOrientationVideo === "all") {
651
+ showAlert?.({
652
+ message: "You are not allowed to record all orientations.",
653
+ type: "danger",
654
+ duration: ALERT_DURATION
655
+ });
656
+ return;
657
+ }
658
+ if (recordingPreferredOrientation === "landscape" && recordingOrientationVideo === "portrait" || recordingPreferredOrientation === "portrait" && recordingOrientationVideo === "landscape") {
659
+ if (!recordingSupportForOtherOrientation) {
660
+ showAlert?.({
661
+ message: "You are not allowed to record this orientation.",
662
+ type: "danger",
663
+ duration: ALERT_DURATION
664
+ });
665
+ return;
666
+ }
667
+ }
668
+ if (!recordingMultiFormatsSupport && recordingVideoType === "all") {
669
+ showAlert?.({
670
+ message: "You are not allowed to record all formats.",
671
+ type: "danger",
672
+ duration: ALERT_DURATION
673
+ });
674
+ return;
675
+ }
676
+ if (eventType !== "broadcast") {
677
+ if (recordingMediaOptions === "video") {
678
+ if (meetingDisplayType === "media" && recordingDisplayType === "all") {
679
+ showAlert?.({
680
+ message: "Recording display type can be either video, video optimized, or media when meeting display type is media.",
681
+ type: "danger",
682
+ duration: ALERT_DURATION
683
+ });
684
+ updateRecordingDisplayType(meetingDisplayType);
685
+ return;
686
+ }
687
+ if (meetingDisplayType === "video") {
688
+ if (recordingDisplayType === "all" || recordingDisplayType === "media") {
689
+ showAlert?.({
690
+ message: "Recording display type can be either video or video optimized when meeting display type is video.",
691
+ type: "danger",
692
+ duration: ALERT_DURATION
693
+ });
694
+ updateRecordingDisplayType(meetingDisplayType);
695
+ return;
696
+ }
697
+ if (meetingVideoOptimized && !recordingVideoOptimized) {
698
+ showAlert?.({
699
+ message: "Recording display type can only be video optimized when meeting display type is video optimized.",
700
+ type: "danger",
701
+ duration: ALERT_DURATION
702
+ });
703
+ updateRecordingVideoOptimized(meetingVideoOptimized);
704
+ return;
705
+ }
706
+ }
707
+ } else {
708
+ updateRecordingDisplayType("media");
709
+ updateRecordingVideoOptimized(false);
710
+ }
711
+ }
712
+ if (recordingDisplayType === "all" && !recordingAllParticipantsFullRoomSupport) {
713
+ showAlert?.({
714
+ message: "You can only record all participants with media.",
715
+ type: "danger",
716
+ duration: ALERT_DURATION
717
+ });
718
+ return;
719
+ }
720
+ const mainSpecs = {
721
+ mediaOptions: recordingMediaOptions,
722
+ audioOptions: recordingAudioOptions,
723
+ videoOptions: recordingVideoOptions,
724
+ videoType: recordingVideoType,
725
+ videoOptimized: recordingVideoOptimized,
726
+ recordingDisplayType,
727
+ addHLS: recordingAddHLS
728
+ };
729
+ const dispSpecs = {
730
+ nameTags: recordingNameTags,
731
+ backgroundColor: recordingBackgroundColor,
732
+ nameTagsColor: recordingNameTagsColor,
733
+ orientationVideo: recordingOrientationVideo
734
+ };
735
+ const textSpecs = {
736
+ addText: recordingAddText,
737
+ customText: recordingCustomText,
738
+ customTextPosition: recordingCustomTextPosition,
739
+ customTextColor: recordingCustomTextColor
740
+ };
741
+ const userRecordingParams = { mainSpecs, dispSpecs, textSpecs };
742
+ updateUserRecordingParams(userRecordingParams);
743
+ updateConfirmedToRecord(true);
744
+ };
745
+ const launchRecording = ({
746
+ updateIsRecordingModalVisible,
747
+ isRecordingModalVisible,
748
+ showAlert,
749
+ stopLaunchRecord,
750
+ canLaunchRecord,
751
+ recordingAudioSupport,
752
+ recordingVideoSupport,
753
+ updateCanRecord,
754
+ updateClearedToRecord,
755
+ recordStarted,
756
+ recordPaused,
757
+ localUIMode
758
+ }) => {
759
+ if (!isRecordingModalVisible && stopLaunchRecord && !localUIMode) {
760
+ showAlert?.({
761
+ message: "Recording has already ended or you are not allowed to record",
762
+ type: "danger",
763
+ duration: 3e3
764
+ });
765
+ return;
766
+ }
767
+ if (!isRecordingModalVisible && canLaunchRecord && !localUIMode) {
768
+ if (!recordingAudioSupport && !recordingVideoSupport) {
769
+ showAlert?.({
770
+ message: "You are not allowed to record",
771
+ type: "danger",
772
+ duration: 3e3
773
+ });
774
+ return;
775
+ }
776
+ updateClearedToRecord(false);
777
+ updateCanRecord(false);
778
+ }
779
+ if (!isRecordingModalVisible && recordStarted && !recordPaused) {
780
+ showAlert?.({
781
+ message: "You can only re-configure recording after pausing it",
782
+ type: "danger",
783
+ duration: 3e3
784
+ });
785
+ return;
786
+ }
787
+ if (!isRecordingModalVisible && !recordingAudioSupport && !recordingVideoSupport && !localUIMode) {
788
+ showAlert?.({
789
+ message: "You are not allowed to record",
790
+ type: "danger",
791
+ duration: 3e3
792
+ });
793
+ return;
794
+ }
795
+ updateIsRecordingModalVisible(!isRecordingModalVisible);
796
+ };
797
+ const recordPauseTimer = ({
798
+ stop = false,
799
+ isTimerRunning,
800
+ canPauseResume,
801
+ showAlert
802
+ }) => {
803
+ if (isTimerRunning && canPauseResume) {
804
+ return true;
805
+ }
806
+ const message = stop ? "Can only stop after 15 seconds of starting or pausing or resuming recording" : "Can only pause or resume after 15 seconds of starting or pausing or resuming recording";
807
+ showAlert?.({
808
+ message,
809
+ type: "danger"
810
+ });
811
+ return false;
812
+ };
813
+ const recordUpdateTimer = ({
814
+ recordElapsedTime,
815
+ recordStartTime,
816
+ updateRecordElapsedTime,
817
+ updateRecordingProgressTime
818
+ }) => {
819
+ const padNumber = (value) => value.toString().padStart(2, "0");
820
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
821
+ let elapsedSeconds = recordElapsedTime;
822
+ elapsedSeconds = Math.floor((currentTime - recordStartTime) / 1e3);
823
+ updateRecordElapsedTime(elapsedSeconds);
824
+ const hours = Math.floor(elapsedSeconds / 3600);
825
+ const minutes = Math.floor(elapsedSeconds % 3600 / 60);
826
+ const seconds = elapsedSeconds % 60;
827
+ const formattedTime = `${padNumber(hours)}:${padNumber(minutes)}:${padNumber(seconds)}`;
828
+ updateRecordingProgressTime(formattedTime);
829
+ };
830
+ const recordResumeTimer = async ({ parameters }) => {
831
+ const { getUpdatedAllParams } = parameters;
832
+ parameters = getUpdatedAllParams();
833
+ let {
834
+ isTimerRunning,
835
+ canPauseResume,
836
+ recordElapsedTime,
837
+ recordStartTime,
838
+ recordTimerInterval,
839
+ showAlert,
840
+ updateRecordStartTime,
841
+ updateRecordTimerInterval,
842
+ updateIsTimerRunning,
843
+ updateCanPauseResume
844
+ } = parameters;
845
+ if (!isTimerRunning && canPauseResume) {
846
+ recordStartTime = (/* @__PURE__ */ new Date()).getTime() - recordElapsedTime * 1e3;
847
+ updateRecordStartTime(recordStartTime);
848
+ recordTimerInterval = setInterval(() => {
849
+ recordUpdateTimer({
850
+ recordElapsedTime,
851
+ recordStartTime,
852
+ updateRecordElapsedTime: parameters.updateRecordElapsedTime,
853
+ updateRecordingProgressTime: parameters.updateRecordingProgressTime
854
+ });
855
+ parameters = getUpdatedAllParams();
856
+ if (parameters.recordPaused || parameters.recordStopped || parameters.roomName === "" || parameters.roomName === null) {
857
+ clearInterval(recordTimerInterval);
858
+ updateRecordTimerInterval(null);
859
+ isTimerRunning = false;
860
+ updateIsTimerRunning(isTimerRunning);
861
+ canPauseResume = false;
862
+ updateCanPauseResume(canPauseResume);
863
+ }
864
+ }, 1e3);
865
+ updateRecordTimerInterval(recordTimerInterval);
866
+ isTimerRunning = true;
867
+ updateIsTimerRunning(isTimerRunning);
868
+ canPauseResume = false;
869
+ updateCanPauseResume(canPauseResume);
870
+ return true;
871
+ }
872
+ showAlert?.({
873
+ type: "danger",
874
+ message: "Can only pause or resume after 15 seconds of starting or pausing or resuming recording"
875
+ });
876
+ return false;
877
+ };
878
+ const recordStartTimer = async ({ parameters }) => {
879
+ const { getUpdatedAllParams } = parameters;
880
+ parameters = getUpdatedAllParams();
881
+ let {
882
+ recordStartTime,
883
+ recordTimerInterval,
884
+ isTimerRunning,
885
+ canPauseResume,
886
+ recordChangeSeconds,
887
+ updateRecordStartTime,
888
+ updateRecordTimerInterval,
889
+ updateIsTimerRunning,
890
+ updateCanPauseResume
891
+ } = parameters;
892
+ const enablePauseResume = () => {
893
+ canPauseResume = true;
894
+ updateCanPauseResume(canPauseResume);
895
+ };
896
+ if (!isTimerRunning) {
897
+ recordStartTime = (/* @__PURE__ */ new Date()).getTime();
898
+ updateRecordStartTime(recordStartTime);
899
+ recordTimerInterval = setInterval(() => {
900
+ recordUpdateTimer({
901
+ recordElapsedTime: parameters.recordElapsedTime,
902
+ recordStartTime,
903
+ updateRecordElapsedTime: parameters.updateRecordElapsedTime,
904
+ updateRecordingProgressTime: parameters.updateRecordingProgressTime
905
+ });
906
+ parameters = getUpdatedAllParams();
907
+ if (parameters.recordPaused || parameters.recordStopped || parameters.roomName === "" || parameters.roomName === null) {
908
+ clearInterval(recordTimerInterval);
909
+ updateRecordTimerInterval(null);
910
+ isTimerRunning = false;
911
+ updateIsTimerRunning(isTimerRunning);
912
+ canPauseResume = false;
913
+ updateCanPauseResume(canPauseResume);
914
+ }
915
+ }, 1e3);
916
+ updateRecordTimerInterval(recordTimerInterval);
917
+ isTimerRunning = true;
918
+ updateIsTimerRunning(isTimerRunning);
919
+ canPauseResume = false;
920
+ updateCanPauseResume(canPauseResume);
921
+ setTimeout(enablePauseResume, recordChangeSeconds);
922
+ }
923
+ };
924
+ const startRecording = async ({
925
+ parameters
926
+ }) => {
927
+ parameters = parameters.getUpdatedAllParams();
928
+ let {
929
+ roomName,
930
+ userRecordingParams,
931
+ socket,
932
+ localSocket,
933
+ updateIsRecordingModalVisible,
934
+ confirmedToRecord,
935
+ showAlert,
936
+ recordingMediaOptions,
937
+ videoAlreadyOn,
938
+ audioAlreadyOn,
939
+ recordStarted,
940
+ recordPaused,
941
+ recordResumed,
942
+ recordStopped,
943
+ startReport,
944
+ endReport,
945
+ canRecord,
946
+ updateClearedToRecord,
947
+ updateRecordStarted,
948
+ updateRecordPaused,
949
+ updateRecordResumed,
950
+ updateStartReport,
951
+ updateEndReport,
952
+ updateCanRecord,
953
+ whiteboardStarted,
954
+ whiteboardEnded,
955
+ rePort,
956
+ captureCanvasStream
957
+ } = parameters;
958
+ if (!confirmedToRecord) {
959
+ showAlert?.({
960
+ message: "You must click confirm before you can start recording",
961
+ type: "danger"
962
+ });
963
+ return false;
964
+ }
965
+ if (recordingMediaOptions === "video" && !videoAlreadyOn) {
966
+ showAlert?.({
967
+ message: "You must turn on your video before you can start recording",
968
+ type: "danger"
969
+ });
970
+ return false;
971
+ }
972
+ if (recordingMediaOptions === "audio" && !audioAlreadyOn) {
973
+ showAlert?.({
974
+ message: "You must turn on your audio before you can start recording",
975
+ type: "danger"
976
+ });
977
+ return false;
978
+ }
979
+ updateClearedToRecord(true);
980
+ let action = "startRecord";
981
+ if (recordStarted && recordPaused && !recordResumed && !recordStopped) {
982
+ action = "resumeRecord";
983
+ }
984
+ let recAttempt = false;
985
+ const socketRef = localSocket && localSocket.connected ? localSocket : socket;
986
+ await new Promise((resolve) => {
987
+ socketRef.emit(
988
+ action,
989
+ { roomName, userRecordingParams },
990
+ async ({ success, reason }) => {
991
+ if (success) {
992
+ recordStarted = true;
993
+ startReport = true;
994
+ endReport = false;
995
+ recordPaused = false;
996
+ recAttempt = true;
997
+ updateRecordStarted(recordStarted);
998
+ updateStartReport(startReport);
999
+ updateEndReport(endReport);
1000
+ updateRecordPaused(recordPaused);
1001
+ if (action === "startRecord") {
1002
+ await rePort({ parameters: parameters.getUpdatedAllParams() });
1003
+ await recordStartTimer({ parameters });
1004
+ } else {
1005
+ updateRecordResumed(true);
1006
+ await rePort({ restart: true, parameters: parameters.getUpdatedAllParams() });
1007
+ await recordResumeTimer({ parameters });
1008
+ }
1009
+ } else {
1010
+ showAlert?.({
1011
+ message: `Recording could not start - ${reason}`,
1012
+ type: "danger"
1013
+ });
1014
+ canRecord = true;
1015
+ startReport = false;
1016
+ endReport = true;
1017
+ recAttempt = false;
1018
+ updateCanRecord(canRecord);
1019
+ updateStartReport(startReport);
1020
+ updateEndReport(endReport);
1021
+ }
1022
+ resolve();
1023
+ }
1024
+ );
1025
+ });
1026
+ try {
1027
+ if (recAttempt && whiteboardStarted && !whiteboardEnded && recordingMediaOptions === "video") {
1028
+ await captureCanvasStream({ parameters: parameters.getUpdatedAllParams() });
1029
+ }
1030
+ } catch (error) {
1031
+ console.error("Error capturing canvas stream:", error);
1032
+ }
1033
+ updateIsRecordingModalVisible(false);
1034
+ return recAttempt;
1035
+ };
1036
+ const stopRecording = async ({ parameters }) => {
1037
+ let {
1038
+ roomName,
1039
+ socket,
1040
+ localSocket,
1041
+ showAlert,
1042
+ startReport,
1043
+ endReport,
1044
+ recordStarted,
1045
+ recordPaused,
1046
+ recordStopped,
1047
+ updateRecordPaused,
1048
+ updateRecordStopped,
1049
+ updateStartReport,
1050
+ updateEndReport,
1051
+ updateShowRecordButtons,
1052
+ whiteboardStarted,
1053
+ whiteboardEnded,
1054
+ recordingMediaOptions,
1055
+ captureCanvasStream
1056
+ } = parameters;
1057
+ let recAttempt = false;
1058
+ if (recordStarted && !recordStopped) {
1059
+ const stop = recordPauseTimer({
1060
+ stop: true,
1061
+ isTimerRunning: parameters.isTimerRunning,
1062
+ canPauseResume: parameters.canPauseResume,
1063
+ showAlert: parameters.showAlert
1064
+ });
1065
+ if (stop) {
1066
+ const action = "stopRecord";
1067
+ const socketRef = localSocket && localSocket.connected ? localSocket : socket;
1068
+ await new Promise((resolve) => {
1069
+ socketRef.emit(
1070
+ action,
1071
+ { roomName },
1072
+ ({ success, reason, recordState }) => {
1073
+ if (success) {
1074
+ startReport = false;
1075
+ endReport = true;
1076
+ recordPaused = false;
1077
+ recordStopped = true;
1078
+ recAttempt = true;
1079
+ updateStartReport(startReport);
1080
+ updateEndReport(endReport);
1081
+ updateRecordPaused(recordPaused);
1082
+ updateRecordStopped(recordStopped);
1083
+ showAlert?.({ message: "Recording Stopped", type: "success" });
1084
+ updateShowRecordButtons(false);
1085
+ } else {
1086
+ const reasonMessage = `Recording Stop Failed: ${reason}; the recording is currently ${recordState}`;
1087
+ showAlert?.({ message: reasonMessage, type: "danger" });
1088
+ recAttempt = false;
1089
+ }
1090
+ resolve();
1091
+ }
1092
+ );
1093
+ });
1094
+ try {
1095
+ if (recAttempt && whiteboardStarted && !whiteboardEnded && recordingMediaOptions === "video") {
1096
+ captureCanvasStream({ parameters: parameters.getUpdatedAllParams(), start: false });
1097
+ }
1098
+ } catch (error) {
1099
+ console.error("Error capturing canvas stream:", error);
1100
+ }
1101
+ } else {
1102
+ return;
1103
+ }
1104
+ } else {
1105
+ showAlert?.({
1106
+ message: "Recording is not started yet or already stopped",
1107
+ type: "danger"
1108
+ });
1109
+ }
1110
+ };
1111
+ const updateRecording = async ({ parameters }) => {
1112
+ let {
1113
+ roomName,
1114
+ userRecordingParams,
1115
+ socket,
1116
+ localSocket,
1117
+ updateIsRecordingModalVisible,
1118
+ confirmedToRecord,
1119
+ showAlert,
1120
+ recordingMediaOptions,
1121
+ videoAlreadyOn,
1122
+ audioAlreadyOn,
1123
+ recordStarted,
1124
+ recordPaused,
1125
+ recordResumed,
1126
+ recordStopped,
1127
+ recordChangeSeconds,
1128
+ pauseRecordCount,
1129
+ startReport,
1130
+ endReport,
1131
+ canRecord,
1132
+ canPauseResume,
1133
+ updateCanPauseResume,
1134
+ updatePauseRecordCount,
1135
+ updateClearedToRecord,
1136
+ updateRecordPaused,
1137
+ updateRecordResumed,
1138
+ updateStartReport,
1139
+ updateEndReport,
1140
+ updateCanRecord,
1141
+ rePort
1142
+ } = parameters;
1143
+ if (recordStopped) {
1144
+ showAlert?.({
1145
+ message: "Recording has already stopped",
1146
+ type: "danger",
1147
+ duration: 3e3
1148
+ });
1149
+ return;
1150
+ }
1151
+ if (recordingMediaOptions === "video" && !videoAlreadyOn) {
1152
+ showAlert?.({
1153
+ message: "You must turn on your video before you can start recording",
1154
+ type: "danger",
1155
+ duration: 3e3
1156
+ });
1157
+ return;
1158
+ }
1159
+ if (recordingMediaOptions === "audio" && !audioAlreadyOn) {
1160
+ showAlert?.({
1161
+ message: "You must turn on your audio before you can start recording",
1162
+ type: "danger",
1163
+ duration: 3e3
1164
+ });
1165
+ return;
1166
+ }
1167
+ const socketRef = localSocket && localSocket.connected ? localSocket : socket;
1168
+ if (recordStarted && !recordPaused && !recordStopped) {
1169
+ const proceed = await checkPauseState({
1170
+ recordingMediaOptions,
1171
+ recordingVideoPausesLimit: parameters.recordingVideoPausesLimit,
1172
+ recordingAudioPausesLimit: parameters.recordingAudioPausesLimit,
1173
+ pauseRecordCount,
1174
+ showAlert
1175
+ });
1176
+ if (!proceed) return;
1177
+ const record = recordPauseTimer({
1178
+ stop: false,
1179
+ isTimerRunning: parameters.isTimerRunning,
1180
+ canPauseResume: parameters.canPauseResume,
1181
+ showAlert
1182
+ });
1183
+ if (record) {
1184
+ const action = "pauseRecord";
1185
+ await new Promise((resolve) => {
1186
+ socketRef.emit(
1187
+ action,
1188
+ { roomName },
1189
+ async ({ success, reason, recordState, pauseCount }) => {
1190
+ pauseRecordCount = pauseCount;
1191
+ updatePauseRecordCount(pauseRecordCount);
1192
+ if (success) {
1193
+ startReport = false;
1194
+ endReport = true;
1195
+ recordPaused = true;
1196
+ updateStartReport(startReport);
1197
+ updateEndReport(endReport);
1198
+ updateRecordPaused(recordPaused);
1199
+ showAlert?.({
1200
+ message: "Recording paused",
1201
+ type: "success",
1202
+ duration: 3e3
1203
+ });
1204
+ updateIsRecordingModalVisible(false);
1205
+ setTimeout(() => {
1206
+ canPauseResume = true;
1207
+ updateCanPauseResume(canPauseResume);
1208
+ }, recordChangeSeconds);
1209
+ } else {
1210
+ showAlert?.({
1211
+ message: `Recording Pause Failed: ${reason}; the current state is: ${recordState}`,
1212
+ type: "danger",
1213
+ duration: 3e3
1214
+ });
1215
+ }
1216
+ resolve();
1217
+ }
1218
+ );
1219
+ });
1220
+ }
1221
+ } else if (recordStarted && recordPaused && !recordStopped) {
1222
+ if (!confirmedToRecord) {
1223
+ showAlert?.({
1224
+ message: "You must click confirm before you can start recording",
1225
+ type: "danger",
1226
+ duration: 3e3
1227
+ });
1228
+ return;
1229
+ }
1230
+ const proceed = await checkResumeState({
1231
+ recordingMediaOptions,
1232
+ recordingVideoPausesLimit: parameters.recordingVideoPausesLimit,
1233
+ recordingAudioPausesLimit: parameters.recordingAudioPausesLimit,
1234
+ pauseRecordCount
1235
+ });
1236
+ if (!proceed) return;
1237
+ const resume = await recordResumeTimer({ parameters });
1238
+ if (resume) {
1239
+ updateClearedToRecord(true);
1240
+ const action = "resumeRecord";
1241
+ await new Promise((resolve) => {
1242
+ socketRef.emit(
1243
+ action,
1244
+ { roomName, userRecordingParams },
1245
+ async ({ success, reason }) => {
1246
+ if (success) {
1247
+ recordResumed = true;
1248
+ recordPaused = false;
1249
+ updateRecordPaused(recordPaused);
1250
+ updateRecordResumed(recordResumed);
1251
+ await rePort({ restart: true, parameters: parameters.getUpdatedAllParams() });
1252
+ } else {
1253
+ showAlert?.({
1254
+ message: `Recording could not resume - ${reason}`,
1255
+ type: "danger",
1256
+ duration: 3e3
1257
+ });
1258
+ }
1259
+ canRecord = true;
1260
+ startReport = false;
1261
+ endReport = true;
1262
+ updateCanRecord(canRecord);
1263
+ updateStartReport(startReport);
1264
+ updateEndReport(endReport);
1265
+ resolve();
1266
+ }
1267
+ );
1268
+ });
1269
+ updateIsRecordingModalVisible(false);
1270
+ setTimeout(() => {
1271
+ updateCanPauseResume(true);
1272
+ }, recordChangeSeconds);
1273
+ }
1274
+ }
1275
+ };
1276
+ const launchRequests = ({ updateIsRequestsModalVisible, isRequestsModalVisible }) => {
1277
+ updateIsRequestsModalVisible(!isRequestsModalVisible);
1278
+ };
1279
+ const respondToRequests = async ({
1280
+ socket,
1281
+ request,
1282
+ updateRequestList,
1283
+ requestList = [],
1284
+ action,
1285
+ roomName
1286
+ }) => {
1287
+ if (!request || typeof request !== "object") {
1288
+ return;
1289
+ }
1290
+ if (!updateRequestList) {
1291
+ console.warn("[respondToRequests] Missing updateRequestList handler; aborting emit.");
1292
+ return;
1293
+ }
1294
+ const currentList = Array.isArray(requestList) ? requestList : [];
1295
+ const requestIdRaw = request.id;
1296
+ const requestIcon = request.icon;
1297
+ const requestName = request.name;
1298
+ if (requestIdRaw === void 0 || requestIcon === void 0 || requestName === void 0) {
1299
+ console.warn("[respondToRequests] Request payload is missing required fields; aborting emit.", request);
1300
+ return;
1301
+ }
1302
+ const requestId = String(requestIdRaw);
1303
+ if (!requestId || !requestIcon || !requestName) {
1304
+ console.warn("[respondToRequests] Request payload contains empty fields; aborting emit.", request);
1305
+ return;
1306
+ }
1307
+ const newRequestList = currentList.filter(
1308
+ (request_) => !(request_ && request_.id === requestId && request_.icon === requestIcon && request_.name === requestName)
1309
+ );
1310
+ updateRequestList(newRequestList);
1311
+ const requestResponse = {
1312
+ id: requestId,
1313
+ name: requestName,
1314
+ type: requestIcon,
1315
+ action
1316
+ };
1317
+ const socketReady = socket && typeof socket.emit === "function";
1318
+ if (!socketReady) {
1319
+ console.warn("[respondToRequests] Socket is not ready; skipping emit.");
1320
+ return;
1321
+ }
1322
+ socket.emit("updateUserofRequestStatus", { requestResponse, roomName });
1323
+ };
1324
+ const launchSettings = ({ updateIsSettingsModalVisible, isSettingsModalVisible }) => {
1325
+ updateIsSettingsModalVisible(!isSettingsModalVisible);
1326
+ };
1327
+ const switchAudio = async ({
1328
+ audioPreference,
1329
+ parameters
1330
+ }) => {
1331
+ let {
1332
+ defAudioID,
1333
+ userDefaultAudioInputDevice,
1334
+ prevAudioInputDevice,
1335
+ updateUserDefaultAudioInputDevice,
1336
+ updatePrevAudioInputDevice,
1337
+ //mediasfu functions
1338
+ switchUserAudio
1339
+ } = parameters;
1340
+ if (audioPreference !== defAudioID) {
1341
+ prevAudioInputDevice = userDefaultAudioInputDevice;
1342
+ updatePrevAudioInputDevice(prevAudioInputDevice);
1343
+ userDefaultAudioInputDevice = audioPreference;
1344
+ updateUserDefaultAudioInputDevice(userDefaultAudioInputDevice);
1345
+ if (defAudioID) {
1346
+ await switchUserAudio({ audioPreference, parameters });
1347
+ }
1348
+ }
1349
+ };
1350
+ const switchVideo = async ({
1351
+ videoPreference,
1352
+ parameters
1353
+ }) => {
1354
+ let {
1355
+ recordStarted,
1356
+ recordResumed,
1357
+ recordStopped,
1358
+ recordPaused,
1359
+ recordingMediaOptions,
1360
+ videoAlreadyOn,
1361
+ userDefaultVideoInputDevice,
1362
+ defVideoID,
1363
+ allowed,
1364
+ updateDefVideoID,
1365
+ updatePrevVideoInputDevice,
1366
+ updateUserDefaultVideoInputDevice,
1367
+ updateIsMediaSettingsModalVisible,
1368
+ //mediasfu functions
1369
+ showAlert,
1370
+ switchUserVideo
1371
+ } = parameters;
1372
+ let checkoff = false;
1373
+ if ((recordStarted || recordResumed) && !recordStopped && !recordPaused) {
1374
+ if (recordingMediaOptions === "video") {
1375
+ checkoff = true;
1376
+ }
1377
+ }
1378
+ if (!allowed) {
1379
+ showAlert?.({
1380
+ message: "Allow access to your camera by starting it for the first time.",
1381
+ type: "danger",
1382
+ duration: 3e3
1383
+ });
1384
+ return;
1385
+ }
1386
+ if (checkoff) {
1387
+ if (videoAlreadyOn) {
1388
+ showAlert?.({
1389
+ message: "Please turn off your video before switching.",
1390
+ type: "danger",
1391
+ duration: 3e3
1392
+ });
1393
+ return;
1394
+ }
1395
+ } else {
1396
+ if (!videoAlreadyOn) {
1397
+ showAlert?.({
1398
+ message: "Please turn on your video before switching.",
1399
+ type: "danger",
1400
+ duration: 3e3
1401
+ });
1402
+ return;
1403
+ }
1404
+ }
1405
+ if (!defVideoID) {
1406
+ defVideoID = userDefaultVideoInputDevice ?? "default";
1407
+ updateDefVideoID(defVideoID);
1408
+ }
1409
+ if (videoPreference !== defVideoID) {
1410
+ const prevVideoInputDevice = userDefaultVideoInputDevice;
1411
+ updatePrevVideoInputDevice(prevVideoInputDevice);
1412
+ userDefaultVideoInputDevice = videoPreference;
1413
+ updateUserDefaultVideoInputDevice(userDefaultVideoInputDevice);
1414
+ if (defVideoID) {
1415
+ updateIsMediaSettingsModalVisible(false);
1416
+ await switchUserVideo({ videoPreference, checkoff, parameters });
1417
+ }
1418
+ }
1419
+ };
1420
+ const switchVideoAlt = async ({
1421
+ parameters
1422
+ }) => {
1423
+ let {
1424
+ recordStarted,
1425
+ recordResumed,
1426
+ recordStopped,
1427
+ recordPaused,
1428
+ recordingMediaOptions,
1429
+ videoAlreadyOn,
1430
+ currentFacingMode,
1431
+ prevFacingMode,
1432
+ allowed,
1433
+ audioOnlyRoom,
1434
+ updateCurrentFacingMode,
1435
+ updateIsMediaSettingsModalVisible,
1436
+ updatePrevFacingMode,
1437
+ showAlert,
1438
+ //media functions
1439
+ switchUserVideoAlt
1440
+ } = parameters;
1441
+ if (audioOnlyRoom) {
1442
+ showAlert?.({
1443
+ message: "You cannot turn on your camera in an audio-only event.",
1444
+ type: "danger",
1445
+ duration: 3e3
1446
+ });
1447
+ return;
1448
+ }
1449
+ let checkoff = false;
1450
+ if ((recordStarted || recordResumed) && !recordStopped && !recordPaused && recordingMediaOptions === "video") {
1451
+ checkoff = true;
1452
+ }
1453
+ if (!allowed) {
1454
+ showAlert?.({
1455
+ message: "Allow access to your camera by starting it for the first time.",
1456
+ type: "danger",
1457
+ duration: 3e3
1458
+ });
1459
+ return;
1460
+ }
1461
+ if (checkoff) {
1462
+ if (videoAlreadyOn) {
1463
+ showAlert?.({
1464
+ message: "Please turn off your video before switching.",
1465
+ type: "danger",
1466
+ duration: 3e3
1467
+ });
1468
+ return;
1469
+ }
1470
+ } else {
1471
+ if (!videoAlreadyOn) {
1472
+ showAlert?.({
1473
+ message: "Please turn on your video before switching.",
1474
+ type: "danger",
1475
+ duration: 3e3
1476
+ });
1477
+ return;
1478
+ }
1479
+ }
1480
+ prevFacingMode = currentFacingMode;
1481
+ updatePrevFacingMode(prevFacingMode);
1482
+ currentFacingMode = currentFacingMode === "environment" ? "user" : "environment";
1483
+ updateCurrentFacingMode(currentFacingMode);
1484
+ updateIsMediaSettingsModalVisible(false);
1485
+ await switchUserVideoAlt({
1486
+ videoPreference: currentFacingMode,
1487
+ checkoff,
1488
+ parameters
1489
+ });
1490
+ };
1491
+ const getModalPosition = ({ position }) => {
1492
+ switch (position) {
1493
+ case "center":
1494
+ return { justifyContent: "center", alignItems: "center" };
1495
+ case "topLeft":
1496
+ return { justifyContent: "flex-start", alignItems: "flex-start" };
1497
+ case "topRight":
1498
+ return { justifyContent: "flex-start", alignItems: "flex-end" };
1499
+ case "bottomLeft":
1500
+ return { justifyContent: "flex-end", alignItems: "flex-start" };
1501
+ case "bottomRight":
1502
+ default:
1503
+ return { justifyContent: "flex-end", alignItems: "flex-end" };
1504
+ }
1505
+ };
1506
+ const launchWaiting = ({ updateIsWaitingModalVisible, isWaitingModalVisible }) => {
1507
+ updateIsWaitingModalVisible(!isWaitingModalVisible);
1508
+ };
1509
+ const respondToWaiting = async ({
1510
+ participantId,
1511
+ participantName,
1512
+ updateWaitingList,
1513
+ waitingList = [],
1514
+ type,
1515
+ roomName,
1516
+ socket
1517
+ }) => {
1518
+ if (!participantId || !participantName) {
1519
+ return;
1520
+ }
1521
+ if (!updateWaitingList) {
1522
+ console.warn("[respondToWaiting] Missing updateWaitingList handler; aborting emit.");
1523
+ return;
1524
+ }
1525
+ if (!socket || typeof socket.emit !== "function") {
1526
+ console.warn("[respondToWaiting] Socket is not ready; skipping emit.");
1527
+ return;
1528
+ }
1529
+ const newWaitingList = waitingList.filter((item) => item.name !== participantName);
1530
+ updateWaitingList(newWaitingList);
1531
+ const responseType = type === "true" || type === true ? "true" : "false";
1532
+ socket.emit("allowUserIn", {
1533
+ participantId,
1534
+ participantName,
1535
+ type: responseType,
1536
+ roomName
1537
+ });
1538
+ };
1539
+ const handleStartWhiteboard = async ({
1540
+ socket,
1541
+ whiteboardUsers,
1542
+ roomName,
1543
+ whiteboardStarted,
1544
+ whiteboardEnded,
1545
+ showAlert,
1546
+ updateWhiteboardStarted,
1547
+ updateWhiteboardEnded,
1548
+ updateIsConfigureWhiteboardModalVisible
1549
+ }) => {
1550
+ const emitName = whiteboardStarted && !whiteboardEnded ? "updateWhiteboard" : "startWhiteboard";
1551
+ const filteredWhiteboardUsers = whiteboardUsers.map(({ name, useBoard }) => ({ name, useBoard }));
1552
+ return new Promise((resolve) => {
1553
+ socket.emit(
1554
+ emitName,
1555
+ { whiteboardUsers: filteredWhiteboardUsers, roomName },
1556
+ (response) => {
1557
+ if (response.success) {
1558
+ showAlert?.({ message: "Whiteboard active", type: "success" });
1559
+ updateWhiteboardStarted(true);
1560
+ updateWhiteboardEnded(false);
1561
+ updateIsConfigureWhiteboardModalVisible(false);
1562
+ } else {
1563
+ showAlert?.({ message: response.reason || "Failed to start whiteboard", type: "danger" });
1564
+ }
1565
+ resolve(response.success);
1566
+ }
1567
+ );
1568
+ });
1569
+ };
1570
+ const handleStopWhiteboard = async ({
1571
+ socket,
1572
+ roomName,
1573
+ showAlert,
1574
+ updateWhiteboardStarted,
1575
+ updateWhiteboardEnded,
1576
+ updateIsConfigureWhiteboardModalVisible
1577
+ }) => {
1578
+ return new Promise((resolve) => {
1579
+ socket.emit("stopWhiteboard", { roomName }, (response) => {
1580
+ if (response.success) {
1581
+ showAlert?.({ message: "Whiteboard stopped", type: "success" });
1582
+ updateWhiteboardStarted(false);
1583
+ updateWhiteboardEnded(true);
1584
+ updateIsConfigureWhiteboardModalVisible(false);
1585
+ } else {
1586
+ showAlert?.({ message: response.reason || "Failed to stop whiteboard", type: "danger" });
1587
+ }
1588
+ resolve(response.success);
1589
+ });
1590
+ });
1591
+ };
1592
+ const launchConfigureWhiteboard = ({
1593
+ updateIsConfigureWhiteboardModalVisible,
1594
+ isConfigureWhiteboardModalVisible
1595
+ }) => {
1596
+ updateIsConfigureWhiteboardModalVisible(!isConfigureWhiteboardModalVisible);
1597
+ };
1598
+ function getRoomReadiness({ parameters }) {
1599
+ const source = parameters || {};
1600
+ if (!source.roomName) {
1601
+ return { ready: false, reason: "Waiting for the room name." };
1602
+ }
1603
+ if (!source.member) {
1604
+ return { ready: false, reason: "Waiting for the participant identity." };
1605
+ }
1606
+ if (source.validated !== true) {
1607
+ return { ready: false, reason: "Waiting for MediaSFU to validate the room." };
1608
+ }
1609
+ const socket = source.socket;
1610
+ if (!socket || socket.connected !== true) {
1611
+ return { ready: false, reason: "Connecting to the MediaSFU room." };
1612
+ }
1613
+ if (typeof socket.emit !== "function") {
1614
+ return { ready: false, reason: "The room signal is not ready yet." };
1615
+ }
1616
+ if (source.device?.loaded !== true) {
1617
+ return { ready: false, reason: "Waiting for the MediaSFU media device." };
1618
+ }
1619
+ return { ready: true, reason: "" };
1620
+ }
1621
+ const SELF_PRODUCER_IDS = /* @__PURE__ */ new Set(["youyou", "youyouyou"]);
1622
+ function toMediaStream(value) {
1623
+ if (value && typeof value.getTracks === "function") return value;
1624
+ const nested = value?.stream;
1625
+ return nested && typeof nested.getTracks === "function" ? nested : null;
1626
+ }
1627
+ function hasRenderableTrack(stream, kind, requireEnabled) {
1628
+ if (!stream || typeof stream.getTracks !== "function") return false;
1629
+ try {
1630
+ return stream.getTracks().some(
1631
+ (track) => track.kind === kind && track.readyState === "live" && (!requireEnabled || track.enabled !== false)
1632
+ );
1633
+ } catch {
1634
+ return false;
1635
+ }
1636
+ }
1637
+ function collect(entries) {
1638
+ return Array.isArray(entries) ? entries : [];
1639
+ }
1640
+ function dedupe(entries) {
1641
+ const seen = /* @__PURE__ */ new Set();
1642
+ const resolved = [];
1643
+ for (const entry of entries) {
1644
+ const producerId = entry?.producerId || "";
1645
+ if (SELF_PRODUCER_IDS.has(producerId)) continue;
1646
+ const stream = toMediaStream(entry);
1647
+ if (!hasRenderableTrack(stream, "video", false)) continue;
1648
+ const key = producerId || stream.id || "";
1649
+ if (key && seen.has(key)) continue;
1650
+ if (key) seen.add(key);
1651
+ resolved.push({
1652
+ stream,
1653
+ producerId,
1654
+ name: entry?.name || ""
1655
+ });
1656
+ }
1657
+ return resolved;
1658
+ }
1659
+ function getRemoteVideoStreams({
1660
+ parameters
1661
+ }) {
1662
+ const source = parameters || {};
1663
+ return dedupe([
1664
+ ...collect(source.oldAllStreams),
1665
+ ...collect(source.allVideoStreams)
1666
+ ]);
1667
+ }
1668
+ function getRemoteAudioStreams({
1669
+ parameters
1670
+ }) {
1671
+ const source = parameters || {};
1672
+ return dedupe(collect(source.allAudioStreams));
1673
+ }
1674
+ function getLocalVideoStream({
1675
+ parameters
1676
+ }) {
1677
+ const source = parameters || {};
1678
+ if (source.keepBackground && source.virtualStream) {
1679
+ const virtual = toMediaStream(source.virtualStream);
1680
+ if (hasRenderableTrack(virtual, "video", true)) return virtual;
1681
+ }
1682
+ const camera = toMediaStream(source.localStreamVideo);
1683
+ if (hasRenderableTrack(camera, "video", true)) return camera;
1684
+ const combined = toMediaStream(source.localStream);
1685
+ return hasRenderableTrack(combined, "video", true) ? combined : null;
1686
+ }
1687
+ function getLocalAudioStream({
1688
+ parameters
1689
+ }) {
1690
+ const source = parameters || {};
1691
+ const mic = toMediaStream(source.localStreamAudio);
1692
+ if (hasRenderableTrack(mic, "audio", true)) return mic;
1693
+ const combined = toMediaStream(source.localStream);
1694
+ return hasRenderableTrack(combined, "audio", true) ? combined : null;
1695
+ }
1696
+ function getScreenShareStream({
1697
+ parameters
1698
+ }) {
1699
+ const source = parameters || {};
1700
+ const remoteRaw = source.remoteScreenStream;
1701
+ const remote = Array.isArray(remoteRaw) ? toMediaStream(remoteRaw[0]) : toMediaStream(remoteRaw);
1702
+ if (hasRenderableTrack(remote, "video", false)) {
1703
+ return { stream: remote, isLocal: false, active: true };
1704
+ }
1705
+ const local = toMediaStream(source.localStreamScreen);
1706
+ if (hasRenderableTrack(local, "video", true)) {
1707
+ return { stream: local, isLocal: true, active: true };
1708
+ }
1709
+ return {
1710
+ stream: null,
1711
+ isLocal: false,
1712
+ active: Boolean(source.shareScreenStarted || source.shared)
1713
+ };
1714
+ }
1715
+ function getAudioGridComponents({ parameters }) {
1716
+ const source = parameters || {};
1717
+ return [
1718
+ ...Array.isArray(source.audioOnlyStreams) ? source.audioOnlyStreams : [],
1719
+ ...Array.isArray(source.translationStreams) ? source.translationStreams : []
1720
+ ].filter(Boolean);
1721
+ }
1722
+ function getCurrentParams({
1723
+ parameters
1724
+ }) {
1725
+ const source = parameters || {};
1726
+ if (typeof source.getCurrentParams === "function") {
1727
+ try {
1728
+ const refreshed = source.getCurrentParams();
1729
+ if (refreshed && typeof refreshed === "object") return refreshed;
1730
+ } catch {
1731
+ }
1732
+ }
1733
+ return source;
1734
+ }
1735
+ function usableSocket(parameters) {
1736
+ return [parameters?.localSocket, parameters?.socket].find(
1737
+ (socket) => socket?.connected === true && typeof socket.emit === "function"
1738
+ ) || null;
1739
+ }
1740
+ async function leaveRoom({
1741
+ parameters,
1742
+ ban = false,
1743
+ endRoomOnHostExit = true
1744
+ }) {
1745
+ try {
1746
+ const live = getCurrentParams({ parameters });
1747
+ const socket = live?.socket;
1748
+ if (!socket || typeof socket.emit !== "function") {
1749
+ return {
1750
+ ok: false,
1751
+ error: "Room exit is unavailable until the signaling connection is ready."
1752
+ };
1753
+ }
1754
+ if (!live?.member || !live?.roomName) {
1755
+ return { ok: false, error: "Room exit is unavailable until the room is joined." };
1756
+ }
1757
+ await confirmExit({
1758
+ socket,
1759
+ localSocket: live.localSocket,
1760
+ member: live.member,
1761
+ roomName: live.roomName,
1762
+ ban,
1763
+ endRoomOnHostExit
1764
+ });
1765
+ return { ok: true, error: "" };
1766
+ } catch (error) {
1767
+ return { ok: false, error: error?.message || "The room exit request failed." };
1768
+ }
1769
+ }
1770
+ async function sendChatMessage({
1771
+ parameters,
1772
+ message,
1773
+ receivers = [],
1774
+ group
1775
+ }) {
1776
+ try {
1777
+ const trimmed = String(message ?? "").trim();
1778
+ if (!trimmed) return { ok: false, error: "The message is empty." };
1779
+ const live = getCurrentParams({ parameters });
1780
+ const socket = usableSocket(live);
1781
+ if (!socket) {
1782
+ return { ok: false, error: "Chat is unavailable until the room connection is ready." };
1783
+ }
1784
+ if (!live?.roomName) {
1785
+ return { ok: false, error: "Chat is unavailable until the room is joined." };
1786
+ }
1787
+ await sendMessage({
1788
+ member: live.member || "",
1789
+ islevel: live.islevel || "1",
1790
+ showAlert: live.showAlert,
1791
+ coHostResponsibility: live.coHostResponsibility || [],
1792
+ coHost: live.coHost || "",
1793
+ chatSetting: live.chatSetting || "",
1794
+ message: trimmed,
1795
+ roomName: live.roomName,
1796
+ messagesLength: Array.isArray(live.messages) ? live.messages.length : 0,
1797
+ receivers,
1798
+ group: group ?? receivers.length === 0,
1799
+ sender: live.member || "",
1800
+ socket
1801
+ });
1802
+ return { ok: true, error: "" };
1803
+ } catch (error) {
1804
+ return { ok: false, error: error?.message || "The message could not be sent." };
1805
+ }
1806
+ }
1807
+ async function runMediaControl({
1808
+ parameters,
1809
+ control,
1810
+ extra
1811
+ }) {
1812
+ const live = getCurrentParams({ parameters });
1813
+ const readiness = getRoomReadiness({ parameters: live });
1814
+ if (!readiness.ready) return { ok: false, error: readiness.reason };
1815
+ const method = live?.[control];
1816
+ if (typeof method !== "function") {
1817
+ return { ok: false, error: `The SDK ${control} control is unavailable.` };
1818
+ }
1819
+ const alertBefore = live?.alertMessage || "";
1820
+ try {
1821
+ await method({ ...extra || {}, parameters: live });
1822
+ } catch (error) {
1823
+ return { ok: false, error: error?.message || "The media control failed." };
1824
+ }
1825
+ const settled = getCurrentParams({ parameters: live });
1826
+ const alertAfter = settled?.alertMessage || "";
1827
+ const alertType = settled?.alertType;
1828
+ if (alertAfter && alertAfter !== alertBefore && (alertType === "danger" || alertType === "warning")) {
1829
+ return { ok: false, error: alertAfter };
1830
+ }
1831
+ return { ok: true, error: "" };
1832
+ }
1833
+ function hasProducer(value) {
1834
+ return typeof value === "string" && value.length > 3 && value.toLowerCase() !== "none";
1835
+ }
1836
+ function participantList$1(parameters) {
1837
+ const source = parameters || {};
1838
+ const primary = Array.isArray(source.participants) ? source.participants : [];
1839
+ if (primary.length > 0) return primary;
1840
+ return Array.isArray(source.participantsAll) ? source.participantsAll : [];
1841
+ }
1842
+ function getParticipantMediaState({
1843
+ parameters,
1844
+ name = "",
1845
+ id = ""
1846
+ }) {
1847
+ const source = parameters || {};
1848
+ const participants = participantList$1(source);
1849
+ const participant = (id ? participants.find((part) => part.id === id) : void 0) || (name ? participants.find((part) => part.name === name) : void 0) || null;
1850
+ const videoProducerId = hasProducer(participant?.videoID) ? participant.videoID : "";
1851
+ const audioProducerId = hasProducer(participant?.audioID) ? participant.audioID : "";
1852
+ return {
1853
+ participant,
1854
+ name: participant?.name || "",
1855
+ isSelf: Boolean(participant?.name && participant.name === source.member),
1856
+ isHost: String(participant?.islevel) === "2",
1857
+ hasVideo: Boolean(videoProducerId),
1858
+ hasAudio: Boolean(audioProducerId),
1859
+ muted: participant?.muted === true,
1860
+ videoProducerId,
1861
+ audioProducerId
1862
+ };
1863
+ }
1864
+ function listParticipantMediaStates({
1865
+ parameters
1866
+ }) {
1867
+ const source = parameters || {};
1868
+ return participantList$1(source).map(
1869
+ (participant) => getParticipantMediaState({
1870
+ parameters: source,
1871
+ id: participant.id,
1872
+ name: participant.name
1873
+ })
1874
+ );
1875
+ }
1876
+ function getActiveSpeaker({ parameters }) {
1877
+ const source = parameters || {};
1878
+ const decibels = Array.isArray(source.audioDecibels) ? source.audioDecibels : [];
1879
+ const participants = participantList$1(source);
1880
+ let best = null;
1881
+ for (const entry of decibels) {
1882
+ if (!entry?.name || typeof entry.averageLoudness !== "number") continue;
1883
+ if (entry.averageLoudness <= 127.5) continue;
1884
+ if (!best || entry.averageLoudness > best.averageLoudness) best = entry;
1885
+ }
1886
+ if (!best) return { name: "", level: 0, participant: null };
1887
+ return {
1888
+ name: best.name,
1889
+ level: best.averageLoudness,
1890
+ participant: participants.find((part) => part.name === best.name) || null
1891
+ };
1892
+ }
1893
+ async function listMediaDevices({
1894
+ parameters
1895
+ }) {
1896
+ const source = parameters || {};
1897
+ try {
1898
+ if (typeof source.getMediaDevicesList === "function") {
1899
+ const [cameras, microphones] = await Promise.all([
1900
+ source.getMediaDevicesList("videoinput"),
1901
+ source.getMediaDevicesList("audioinput")
1902
+ ]);
1903
+ return {
1904
+ cameras: Array.isArray(cameras) ? cameras : [],
1905
+ microphones: Array.isArray(microphones) ? microphones : []
1906
+ };
1907
+ }
1908
+ const devices = await navigator.mediaDevices.enumerateDevices();
1909
+ return {
1910
+ cameras: devices.filter((device) => device.kind === "videoinput"),
1911
+ microphones: devices.filter((device) => device.kind === "audioinput")
1912
+ };
1913
+ } catch {
1914
+ return { cameras: [], microphones: [] };
1915
+ }
1916
+ }
1917
+ function getSelectedDevices({ parameters }) {
1918
+ const source = parameters || {};
1919
+ return {
1920
+ cameraId: source.userDefaultVideoInputDevice || "",
1921
+ microphoneId: source.userDefaultAudioInputDevice || "",
1922
+ cameras: Array.isArray(source.videoInputs) ? source.videoInputs : [],
1923
+ microphones: Array.isArray(source.audioInputs) ? source.audioInputs : []
1924
+ };
1925
+ }
1926
+ function isPanelist(parameters) {
1927
+ const panelists = Array.isArray(parameters.panelists) ? parameters.panelists : [];
1928
+ return panelists.some((entry) => entry?.name === parameters.member);
1929
+ }
1930
+ function getMediaPermissions({ parameters }) {
1931
+ const source = parameters || {};
1932
+ const isHost = String(source.islevel) === "2";
1933
+ const recording = Boolean(source.recordStarted || source.recordResumed) && !(source.recordPaused || source.recordStopped);
1934
+ const focusModeBlocked = Boolean(source.panelistsFocused) && !isHost && !isPanelist(source);
1935
+ const evaluate = (kind) => {
1936
+ const allow = () => ({ allowed: true, reason: "", needsApproval: false });
1937
+ const deny = (reason) => ({ allowed: false, reason, needsApproval: false });
1938
+ if (source.audioOnlyRoom && kind !== "audio") {
1939
+ return deny("This is an audio-only event.");
1940
+ }
1941
+ if (isHost && recording) {
1942
+ if (kind === "audio" && source.recordingMediaOptions === "audio") {
1943
+ return deny("Pause or stop the recording before changing your microphone.");
1944
+ }
1945
+ if (kind === "video" && source.recordingMediaOptions === "video") {
1946
+ return deny("Pause or stop the recording before changing your camera.");
1947
+ }
1948
+ }
1949
+ if (isHost) return allow();
1950
+ if (source.adminRestrictSetting) {
1951
+ return deny("Access denied by the host.");
1952
+ }
1953
+ if (focusModeBlocked && kind === "audio" && source.muteOthersMic) {
1954
+ return deny("Only panelists can unmute while focus mode is active.");
1955
+ }
1956
+ if (focusModeBlocked && kind === "video" && source.muteOthersCamera) {
1957
+ return deny("Only panelists can enable video while focus mode is active.");
1958
+ }
1959
+ const setting = kind === "audio" ? source.audioSetting : kind === "video" ? source.videoSetting : source.screenshareSetting;
1960
+ if (setting === "disallow") {
1961
+ return deny("The host has disabled this for participants.");
1962
+ }
1963
+ if (setting === "approval") {
1964
+ return { allowed: true, reason: "The host must approve this.", needsApproval: true };
1965
+ }
1966
+ return allow();
1967
+ };
1968
+ return {
1969
+ microphone: evaluate("audio"),
1970
+ camera: evaluate("video"),
1971
+ screenShare: evaluate("screenshare"),
1972
+ isHost,
1973
+ focusModeBlocked
1974
+ };
1975
+ }
1976
+ function hasResponsibility(parameters, area) {
1977
+ const list = Array.isArray(parameters?.coHostResponsibility) ? parameters.coHostResponsibility : [];
1978
+ return list.find((item) => item?.name === area)?.value === true;
1979
+ }
1980
+ function getModerationPermissions({
1981
+ parameters
1982
+ }) {
1983
+ const source = parameters || {};
1984
+ const isHost = String(source.islevel) === "2";
1985
+ const isCoHost = Boolean(source.coHost && source.coHost === source.member);
1986
+ const allow = (area) => isHost || isCoHost && hasResponsibility(source, area);
1987
+ return {
1988
+ isHost,
1989
+ isCoHost,
1990
+ canControlMedia: allow("media"),
1991
+ canManageParticipants: allow("participants"),
1992
+ canManageChat: allow("chat"),
1993
+ canManageWaitingRoom: allow("waiting")
1994
+ };
1995
+ }
1996
+ function participantList(parameters) {
1997
+ const source = parameters || {};
1998
+ const primary = Array.isArray(source.participants) ? source.participants : [];
1999
+ if (primary.length > 0) return primary;
2000
+ return Array.isArray(source.participantsAll) ? source.participantsAll : [];
2001
+ }
2002
+ function findParticipant(parameters, { id, name }) {
2003
+ const participants = participantList(parameters);
2004
+ return (id ? participants.find((part) => part.id === id) : void 0) || (name ? participants.find((part) => part.name === name) : void 0) || null;
2005
+ }
2006
+ async function setParticipantMedia({
2007
+ parameters,
2008
+ name = "",
2009
+ id = "",
2010
+ kind
2011
+ }) {
2012
+ try {
2013
+ const live = getCurrentParams({ parameters });
2014
+ const permissions = getModerationPermissions({ parameters: live });
2015
+ if (!permissions.canControlMedia) {
2016
+ return {
2017
+ ok: false,
2018
+ error: "You are not allowed to control media for other participants."
2019
+ };
2020
+ }
2021
+ const socket = live?.socket;
2022
+ if (!socket || typeof socket.emit !== "function" || !live?.roomName) {
2023
+ return { ok: false, error: "The room connection is not ready." };
2024
+ }
2025
+ const participant = findParticipant(live, { id, name });
2026
+ if (!participant) return { ok: false, error: "That participant is not in the room." };
2027
+ if (String(participant.islevel) === "2") {
2028
+ return { ok: false, error: "A host’s media cannot be turned off." };
2029
+ }
2030
+ socket.emit("controlMedia", {
2031
+ participantId: participant.id,
2032
+ participantName: participant.name,
2033
+ type: kind,
2034
+ roomName: live.roomName
2035
+ });
2036
+ return { ok: true, error: "" };
2037
+ } catch (error) {
2038
+ return { ok: false, error: error?.message || "The media control failed." };
2039
+ }
2040
+ }
2041
+ function muteParticipant(options) {
2042
+ return setParticipantMedia({ ...options, kind: "audio" });
2043
+ }
2044
+ function disableParticipantVideo(options) {
2045
+ return setParticipantMedia({ ...options, kind: "video" });
2046
+ }
2047
+ function stopParticipantScreenShare(options) {
2048
+ return setParticipantMedia({ ...options, kind: "screenshare" });
2049
+ }
2050
+ async function muteEveryone({
2051
+ parameters,
2052
+ kind = "audio"
2053
+ }) {
2054
+ const live = getCurrentParams({ parameters });
2055
+ const permissions = getModerationPermissions({ parameters: live });
2056
+ if (!permissions.canControlMedia) {
2057
+ return {
2058
+ ok: false,
2059
+ error: "You are not allowed to control media for other participants."
2060
+ };
2061
+ }
2062
+ const targets = participantList(live).filter(
2063
+ (part) => String(part.islevel) !== "2" && part.name !== live.member
2064
+ );
2065
+ if (targets.length === 0) return { ok: false, error: "There is nobody else to mute." };
2066
+ const results = await Promise.all(
2067
+ targets.map(
2068
+ (part) => setParticipantMedia({ parameters: live, id: part.id, name: part.name, kind })
2069
+ )
2070
+ );
2071
+ const failed = results.filter((result) => !result.ok);
2072
+ if (failed.length === results.length) {
2073
+ return { ok: false, error: failed[0]?.error || "No participant could be muted." };
2074
+ }
2075
+ return { ok: true, error: "" };
2076
+ }
2077
+ async function removeParticipant({
2078
+ parameters,
2079
+ name = "",
2080
+ id = ""
2081
+ }) {
2082
+ try {
2083
+ const live = getCurrentParams({ parameters });
2084
+ const permissions = getModerationPermissions({ parameters: live });
2085
+ if (!permissions.canManageParticipants) {
2086
+ return { ok: false, error: "You are not allowed to remove participants." };
2087
+ }
2088
+ const participant = findParticipant(live, { id, name });
2089
+ if (!participant) return { ok: false, error: "That participant is not in the room." };
2090
+ if (String(participant.islevel) === "2") {
2091
+ return { ok: false, error: "A host cannot be removed." };
2092
+ }
2093
+ await removeParticipants({
2094
+ coHostResponsibility: live.coHostResponsibility || [],
2095
+ participant,
2096
+ member: live.member || "",
2097
+ islevel: live.islevel || "1",
2098
+ showAlert: live.showAlert,
2099
+ coHost: live.coHost || "",
2100
+ participants: participantList(live),
2101
+ socket: live.socket,
2102
+ roomName: live.roomName || "",
2103
+ updateParticipants: live.updateParticipants
2104
+ });
2105
+ return { ok: true, error: "" };
2106
+ } catch (error) {
2107
+ return { ok: false, error: error?.message || "The participant could not be removed." };
2108
+ }
2109
+ }
2110
+ async function respondToWaitingParticipant({
2111
+ parameters,
2112
+ name = "",
2113
+ id = "",
2114
+ admit
2115
+ }) {
2116
+ try {
2117
+ const live = getCurrentParams({ parameters });
2118
+ const permissions = getModerationPermissions({ parameters: live });
2119
+ if (!permissions.canManageWaitingRoom) {
2120
+ return { ok: false, error: "You are not allowed to manage the waiting room." };
2121
+ }
2122
+ const waitingList = Array.isArray(live.waitingRoomList) ? live.waitingRoomList : [];
2123
+ const entry = (id ? waitingList.find((person) => person?.id === id) : void 0) || (name ? waitingList.find((person) => person?.name === name) : void 0);
2124
+ if (!entry) return { ok: false, error: "That person is no longer waiting to join." };
2125
+ await respondToWaiting({
2126
+ participantId: entry.id,
2127
+ participantName: entry.name,
2128
+ updateWaitingList: live.updateWaitingRoomList,
2129
+ waitingList,
2130
+ type: admit,
2131
+ roomName: live.roomName || "",
2132
+ socket: live.socket
2133
+ });
2134
+ return { ok: true, error: "" };
2135
+ } catch (error) {
2136
+ return {
2137
+ ok: false,
2138
+ error: error?.message || "The waiting-room response failed."
2139
+ };
2140
+ }
2141
+ }
2142
+ async function respondToParticipantRequest({
2143
+ parameters,
2144
+ requestId = "",
2145
+ name = "",
2146
+ approve
2147
+ }) {
2148
+ try {
2149
+ const live = getCurrentParams({ parameters });
2150
+ const permissions = getModerationPermissions({ parameters: live });
2151
+ if (!permissions.canManageParticipants) {
2152
+ return { ok: false, error: "You are not allowed to respond to requests." };
2153
+ }
2154
+ const requestList = Array.isArray(live.requestList) ? live.requestList : [];
2155
+ const request = (requestId ? requestList.find((item) => item?.id === requestId) : void 0) || (name ? requestList.find(
2156
+ (item) => item?.name === name || item?.username === name
2157
+ ) : void 0);
2158
+ if (!request) return { ok: false, error: "That request is no longer pending." };
2159
+ await respondToRequests({
2160
+ socket: live.socket,
2161
+ request,
2162
+ updateRequestList: live.updateRequestList,
2163
+ requestList,
2164
+ action: approve ? "accepted" : "rejected",
2165
+ roomName: live.roomName || ""
2166
+ });
2167
+ return { ok: true, error: "" };
2168
+ } catch (error) {
2169
+ return { ok: false, error: error?.message || "The request response failed." };
2170
+ }
2171
+ }
2172
+ async function setCoHost({
2173
+ parameters,
2174
+ name,
2175
+ areas = ["media", "participants"]
2176
+ }) {
2177
+ try {
2178
+ const live = getCurrentParams({ parameters });
2179
+ if (String(live.islevel) !== "2") {
2180
+ return { ok: false, error: "Only the host can assign a co-host." };
2181
+ }
2182
+ const all = ["media", "participants", "chat", "waiting"];
2183
+ const responsibilities = all.map((area) => ({
2184
+ name: area,
2185
+ value: areas.includes(area),
2186
+ dedicated: false
2187
+ }));
2188
+ await modifyCoHostSettings({
2189
+ roomName: live.roomName || "",
2190
+ showAlert: live.showAlert,
2191
+ selectedParticipant: name,
2192
+ coHost: live.coHost || "",
2193
+ coHostResponsibility: responsibilities,
2194
+ updateIsCoHostModalVisible: live.updateIsCoHostModalVisible || (() => void 0),
2195
+ updateCoHostResponsibility: live.updateCoHostResponsibility,
2196
+ updateCoHost: live.updateCoHost,
2197
+ socket: live.socket
2198
+ });
2199
+ return { ok: true, error: "" };
2200
+ } catch (error) {
2201
+ return { ok: false, error: error?.message || "The co-host update failed." };
2202
+ }
2203
+ }
2204
+ const noop = () => void 0;
2205
+ function getRecordingState({ parameters }) {
2206
+ const source = parameters || {};
2207
+ const canRecord = source.canRecord === true;
2208
+ let status = "idle";
2209
+ if (!canRecord && !source.recordStarted) status = "unavailable";
2210
+ else if (source.recordStopped) status = "stopped";
2211
+ else if (source.recordStarted && source.recordPaused) status = "paused";
2212
+ else if (source.recordStarted) status = "recording";
2213
+ return {
2214
+ status,
2215
+ active: status === "recording",
2216
+ canRecord,
2217
+ mediaOptions: source.recordingMediaOptions || "video",
2218
+ elapsedSeconds: Number(source.recordElapsedTime) || 0
2219
+ };
2220
+ }
2221
+ async function startRoomRecording({
2222
+ parameters
2223
+ }) {
2224
+ try {
2225
+ const live = getCurrentParams({ parameters });
2226
+ if (live.canRecord !== true) {
2227
+ return { ok: false, error: "Recording is not available in this room." };
2228
+ }
2229
+ if (live.recordStarted && !live.recordStopped) {
2230
+ return { ok: false, error: "Recording has already started." };
2231
+ }
2232
+ await confirmRecording({ parameters: live });
2233
+ const refreshed = getCurrentParams({ parameters: live });
2234
+ await startRecording({ parameters: refreshed });
2235
+ return { ok: true, error: "" };
2236
+ } catch (error) {
2237
+ return { ok: false, error: error?.message || "Recording could not be started." };
2238
+ }
2239
+ }
2240
+ async function pauseRoomRecording({
2241
+ parameters
2242
+ }) {
2243
+ return toggleRecordingPause(parameters, true);
2244
+ }
2245
+ async function resumeRoomRecording({
2246
+ parameters
2247
+ }) {
2248
+ return toggleRecordingPause(parameters, false);
2249
+ }
2250
+ async function toggleRecordingPause(parameters, pause) {
2251
+ try {
2252
+ const live = getCurrentParams({ parameters });
2253
+ const state = getRecordingState({ parameters: live });
2254
+ if (state.status !== (pause ? "recording" : "paused")) {
2255
+ return {
2256
+ ok: false,
2257
+ error: pause ? "There is no active recording to pause." : "There is no paused recording to resume."
2258
+ };
2259
+ }
2260
+ await updateRecording({ parameters: live });
2261
+ return { ok: true, error: "" };
2262
+ } catch (error) {
2263
+ return {
2264
+ ok: false,
2265
+ error: error?.message || "The recording state could not be changed."
2266
+ };
2267
+ }
2268
+ }
2269
+ async function stopRoomRecording({
2270
+ parameters
2271
+ }) {
2272
+ try {
2273
+ const live = getCurrentParams({ parameters });
2274
+ if (!live.recordStarted || live.recordStopped) {
2275
+ return { ok: false, error: "There is no active recording to stop." };
2276
+ }
2277
+ await stopRecording({ parameters: live });
2278
+ return { ok: true, error: "" };
2279
+ } catch (error) {
2280
+ return { ok: false, error: error?.message || "Recording could not be stopped." };
2281
+ }
2282
+ }
2283
+ function getWhiteboardState({ parameters }) {
2284
+ const source = parameters || {};
2285
+ return {
2286
+ active: source.whiteboardStarted === true && source.whiteboardEnded !== true,
2287
+ canStart: source.canStartWhiteboard === true,
2288
+ users: Array.isArray(source.whiteboardUsers) ? source.whiteboardUsers : [],
2289
+ limit: Number(source.whiteboardLimit) || 0,
2290
+ canvas: source.canvasWhiteboard || null
2291
+ };
2292
+ }
2293
+ async function startWhiteboard({
2294
+ parameters,
2295
+ users
2296
+ }) {
2297
+ try {
2298
+ const live = getCurrentParams({ parameters });
2299
+ if (live.breakOutRoomStarted && !live.breakOutRoomEnded) {
2300
+ return {
2301
+ ok: false,
2302
+ error: "The whiteboard cannot start while breakout rooms are active."
2303
+ };
2304
+ }
2305
+ const socket = live?.socket;
2306
+ if (!socket || typeof socket.emit !== "function" || !live?.roomName) {
2307
+ return { ok: false, error: "The room connection is not ready." };
2308
+ }
2309
+ const state = getWhiteboardState({ parameters: live });
2310
+ if (!state.active && !state.canStart) {
2311
+ return { ok: false, error: "You are not allowed to start the whiteboard." };
2312
+ }
2313
+ const whiteboardUsers = users ?? state.users;
2314
+ if (state.limit > 0 && whiteboardUsers.length > state.limit) {
2315
+ return {
2316
+ ok: false,
2317
+ error: `The whiteboard allows at most ${state.limit} participants.`
2318
+ };
2319
+ }
2320
+ const event = state.active ? "updateWhiteboard" : "startWhiteboard";
2321
+ const response = await new Promise((resolve) => {
2322
+ socket.emit(event, { whiteboardUsers, roomName: live.roomName }, resolve);
2323
+ });
2324
+ if (!response?.success) {
2325
+ return {
2326
+ ok: false,
2327
+ error: response?.reason || "The whiteboard could not be started."
2328
+ };
2329
+ }
2330
+ live.updateWhiteboardStarted?.(true);
2331
+ live.updateWhiteboardEnded?.(false);
2332
+ live.updateWhiteboardUsers?.(whiteboardUsers);
2333
+ live.updateCanStartWhiteboard?.(false);
2334
+ return { ok: true, error: "" };
2335
+ } catch (error) {
2336
+ return {
2337
+ ok: false,
2338
+ error: error?.message || "The whiteboard could not be started."
2339
+ };
2340
+ }
2341
+ }
2342
+ async function stopWhiteboard({
2343
+ parameters
2344
+ }) {
2345
+ try {
2346
+ const live = getCurrentParams({ parameters });
2347
+ const socket = live?.socket;
2348
+ if (!socket || typeof socket.emit !== "function" || !live?.roomName) {
2349
+ return { ok: false, error: "The room connection is not ready." };
2350
+ }
2351
+ if (!getWhiteboardState({ parameters: live }).active) {
2352
+ return { ok: false, error: "The whiteboard is not running." };
2353
+ }
2354
+ const response = await new Promise((resolve) => {
2355
+ socket.emit("stopWhiteboard", { roomName: live.roomName }, resolve);
2356
+ });
2357
+ if (!response?.success) {
2358
+ return {
2359
+ ok: false,
2360
+ error: response?.reason || "The whiteboard could not be stopped."
2361
+ };
2362
+ }
2363
+ live.updateWhiteboardStarted?.(false);
2364
+ live.updateWhiteboardEnded?.(true);
2365
+ return { ok: true, error: "" };
2366
+ } catch (error) {
2367
+ return {
2368
+ ok: false,
2369
+ error: error?.message || "The whiteboard could not be stopped."
2370
+ };
2371
+ }
2372
+ }
2373
+ function getPollState({ parameters }) {
2374
+ const source = parameters || {};
2375
+ const polls = Array.isArray(source.polls) ? source.polls : [];
2376
+ const active = source.poll && source.poll.status === "active" ? source.poll : polls.find((entry) => entry?.status === "active") || null;
2377
+ return { polls, active };
2378
+ }
2379
+ async function createRoomPoll({
2380
+ parameters,
2381
+ question,
2382
+ options,
2383
+ type = "custom"
2384
+ }) {
2385
+ try {
2386
+ const live = getCurrentParams({ parameters });
2387
+ if (!question?.trim()) return { ok: false, error: "The poll needs a question." };
2388
+ if (!Array.isArray(options) || options.length < 2) {
2389
+ return { ok: false, error: "The poll needs at least two options." };
2390
+ }
2391
+ await handleCreatePoll({
2392
+ poll: { question, options, type },
2393
+ socket: live.socket,
2394
+ roomName: live.roomName || "",
2395
+ showAlert: live.showAlert,
2396
+ updateIsPollModalVisible: live.updateIsPollModalVisible || noop
2397
+ });
2398
+ return { ok: true, error: "" };
2399
+ } catch (error) {
2400
+ return { ok: false, error: error?.message || "The poll could not be created." };
2401
+ }
2402
+ }
2403
+ async function voteInRoomPoll({
2404
+ parameters,
2405
+ pollId,
2406
+ optionIndex
2407
+ }) {
2408
+ try {
2409
+ const live = getCurrentParams({ parameters });
2410
+ await handleVotePoll({
2411
+ pollId,
2412
+ optionIndex,
2413
+ socket: live.socket,
2414
+ showAlert: live.showAlert,
2415
+ member: live.member || "",
2416
+ roomName: live.roomName || "",
2417
+ updateIsPollModalVisible: live.updateIsPollModalVisible || noop
2418
+ });
2419
+ return { ok: true, error: "" };
2420
+ } catch (error) {
2421
+ return { ok: false, error: error?.message || "The vote could not be cast." };
2422
+ }
2423
+ }
2424
+ async function endRoomPoll({
2425
+ parameters,
2426
+ pollId
2427
+ }) {
2428
+ try {
2429
+ const live = getCurrentParams({ parameters });
2430
+ if (String(live.islevel) !== "2") {
2431
+ return { ok: false, error: "Only the host can end a poll." };
2432
+ }
2433
+ await handleEndPoll({
2434
+ pollId,
2435
+ socket: live.socket,
2436
+ showAlert: live.showAlert,
2437
+ roomName: live.roomName || "",
2438
+ updateIsPollModalVisible: live.updateIsPollModalVisible || noop
2439
+ });
2440
+ return { ok: true, error: "" };
2441
+ } catch (error) {
2442
+ return { ok: false, error: error?.message || "The poll could not be ended." };
2443
+ }
2444
+ }
2445
+ function getBreakoutState({ parameters }) {
2446
+ const source = parameters || {};
2447
+ return {
2448
+ active: source.breakOutRoomStarted === true && source.breakOutRoomEnded !== true,
2449
+ canStart: source.canStartBreakout === true,
2450
+ rooms: Array.isArray(source.breakoutRooms) ? source.breakoutRooms : [],
2451
+ currentRoom: typeof source.hostNewRoom === "number" ? source.hostNewRoom : -1
2452
+ };
2453
+ }
2454
+ function getRecordingNotice({ parameters }) {
2455
+ const source = parameters || {};
2456
+ const isAudio = source.recordingMediaOptions === "audio";
2457
+ const pauseLimit = Number(
2458
+ isAudio ? source.recordingAudioPausesLimit : source.recordingVideoPausesLimit
2459
+ ) || 0;
2460
+ const pausesUsed = Number(source.pauseRecordCount) || 0;
2461
+ return {
2462
+ message: source.recordingNotice || "",
2463
+ elapsed: source.recordingProgressTime || "00:00:00",
2464
+ elapsedSeconds: Number(source.recordElapsedTime) || 0,
2465
+ canPauseResume: source.canPauseResume === true,
2466
+ pausesUsed,
2467
+ pauseLimit,
2468
+ pauseLimitReached: pauseLimit > 0 && pausesUsed >= pauseLimit
2469
+ };
2470
+ }
2471
+ function getRecordingCapabilities({
2472
+ parameters
2473
+ }) {
2474
+ const source = parameters || {};
2475
+ return {
2476
+ audio: source.recordingAudioSupport === true,
2477
+ video: source.recordingVideoSupport === true,
2478
+ allParticipants: source.recordingAllParticipantsSupport === true,
2479
+ videoParticipants: source.recordingVideoParticipantsSupport === true,
2480
+ hls: source.recordingAddHLS === true,
2481
+ audioPeopleLimit: Number(source.recordingAudioPeopleLimit) || 0,
2482
+ videoPeopleLimit: Number(source.recordingVideoPeopleLimit) || 0
2483
+ };
2484
+ }
2485
+ function getTranslationState({ parameters }) {
2486
+ const source = parameters || {};
2487
+ const preferences = source.listenerTranslationPreferences || {};
2488
+ const perSpeakerMap = preferences.perSpeaker;
2489
+ const perSpeaker = perSpeakerMap instanceof Map ? Array.from(perSpeakerMap.values()) : Array.isArray(perSpeakerMap) ? perSpeakerMap : [];
2490
+ const speakerStates = source.speakerTranslationStates;
2491
+ const languages = /* @__PURE__ */ new Set();
2492
+ const collect2 = (value) => {
2493
+ if (value?.language) languages.add(value.language);
2494
+ };
2495
+ if (speakerStates instanceof Map) speakerStates.forEach(collect2);
2496
+ else if (Array.isArray(speakerStates)) speakerStates.forEach(collect2);
2497
+ perSpeaker.forEach(collect2);
2498
+ if (preferences.globalLanguage) languages.add(preferences.globalLanguage);
2499
+ return {
2500
+ globalLanguage: preferences.globalLanguage ?? null,
2501
+ perSpeaker,
2502
+ active: Boolean(
2503
+ preferences.globalLanguage || perSpeaker.some((entry) => entry?.language && !entry.wantOriginal)
2504
+ ),
2505
+ availableLanguages: Array.from(languages)
2506
+ };
2507
+ }
2508
+ function setTranslationPreference({
2509
+ parameters,
2510
+ language = null,
2511
+ speakerId,
2512
+ wantOriginal = false
2513
+ }) {
2514
+ const source = parameters || {};
2515
+ const update = source.updateListenerTranslationPreferences;
2516
+ if (typeof update !== "function") {
2517
+ return { ok: false, error: "Translation is not available in this room." };
2518
+ }
2519
+ try {
2520
+ const current = source.listenerTranslationPreferences || {};
2521
+ const perSpeaker = current.perSpeaker instanceof Map ? new Map(current.perSpeaker) : /* @__PURE__ */ new Map();
2522
+ if (speakerId) {
2523
+ perSpeaker.set(speakerId, { speakerId, language, wantOriginal });
2524
+ update({ perSpeaker, globalLanguage: current.globalLanguage ?? null });
2525
+ } else {
2526
+ update({ perSpeaker, globalLanguage: language });
2527
+ }
2528
+ return { ok: true, error: "" };
2529
+ } catch (error) {
2530
+ return { ok: false, error: error?.message || "The translation preference could not be set." };
2531
+ }
2532
+ }
2533
+ function getFocusModeState({ parameters }) {
2534
+ const source = parameters || {};
2535
+ const panelists = Array.isArray(source.panelists) ? source.panelists : [];
2536
+ return {
2537
+ active: source.panelistsFocused === true,
2538
+ panelists,
2539
+ selfIsPanelist: panelists.some((entry) => entry?.name === source.member),
2540
+ mutesMicrophones: source.muteOthersMic === true,
2541
+ mutesCameras: source.muteOthersCamera === true
2542
+ };
2543
+ }
2544
+ function getVirtualBackgroundState({
2545
+ parameters
2546
+ }) {
2547
+ const source = parameters || {};
2548
+ const stream = source.virtualStream || source.processedStream;
2549
+ return {
2550
+ active: source.keepBackground === true && Boolean(stream),
2551
+ stream: stream || null,
2552
+ appliedBackground: source.appliedBackground ?? null,
2553
+ selectedImage: source.selectedImage ?? null
2554
+ };
2555
+ }
2556
+ const LOCALLY_PAUSED = /* @__PURE__ */ new Set();
2557
+ async function setParticipantPlayback({
2558
+ parameters,
2559
+ name = "",
2560
+ producerId = "",
2561
+ kind = "all",
2562
+ paused
2563
+ }) {
2564
+ try {
2565
+ const source = parameters || {};
2566
+ const participants = Array.isArray(source.participants) ? source.participants : [];
2567
+ const participant = name ? participants.find((part) => part?.name === name) : void 0;
2568
+ const targets = /* @__PURE__ */ new Set();
2569
+ if (producerId) targets.add(producerId);
2570
+ const usable = (value) => typeof value === "string" && value.length > 3 && value.toLowerCase() !== "none";
2571
+ if (participant) {
2572
+ if (kind !== "video" && usable(participant.audioID)) targets.add(participant.audioID);
2573
+ if (kind !== "audio" && usable(participant.videoID)) targets.add(participant.videoID);
2574
+ }
2575
+ if (targets.size === 0) {
2576
+ return { ok: false, error: "That participant is not publishing anything to pause.", affected: 0 };
2577
+ }
2578
+ const transports = Array.isArray(source.consumerTransports) ? source.consumerTransports : [];
2579
+ let affected = 0;
2580
+ for (const entry of transports) {
2581
+ const consumer = entry?.consumer;
2582
+ const id = entry?.producerId || consumer?.producerId;
2583
+ if (!consumer || !targets.has(id)) continue;
2584
+ if (kind !== "all" && consumer.track?.kind !== kind) continue;
2585
+ try {
2586
+ if (paused && typeof consumer.pause === "function") {
2587
+ await consumer.pause();
2588
+ LOCALLY_PAUSED.add(id);
2589
+ affected += 1;
2590
+ } else if (!paused && typeof consumer.resume === "function") {
2591
+ await consumer.resume();
2592
+ LOCALLY_PAUSED.delete(id);
2593
+ affected += 1;
2594
+ }
2595
+ } catch {
2596
+ }
2597
+ }
2598
+ return affected > 0 ? { ok: true, error: "", affected } : { ok: false, error: "No matching incoming stream was found.", affected: 0 };
2599
+ } catch (error) {
2600
+ return { ok: false, error: error?.message || "The playback change failed.", affected: 0 };
2601
+ }
2602
+ }
2603
+ async function setBreakoutRooms({
2604
+ parameters,
2605
+ rooms,
2606
+ newParticipantAction
2607
+ }) {
2608
+ try {
2609
+ const source = parameters || {};
2610
+ const socket = source.socket;
2611
+ if (!socket || typeof socket.emit !== "function" || !source.roomName) {
2612
+ return { ok: false, error: "The room connection is not ready." };
2613
+ }
2614
+ if (String(source.islevel) !== "2") {
2615
+ return { ok: false, error: "Only the host can change breakout rooms." };
2616
+ }
2617
+ const running = source.breakOutRoomStarted === true && source.breakOutRoomEnded !== true;
2618
+ const event = running ? "updateBreakout" : "startBreakout";
2619
+ const payload = (Array.isArray(rooms) ? rooms : []).map(
2620
+ (room) => (Array.isArray(room) ? room : []).map(({ name, breakRoom }) => ({ name, breakRoom }))
2621
+ );
2622
+ const response = await new Promise((resolve) => {
2623
+ socket.emit(
2624
+ event,
2625
+ {
2626
+ breakoutRooms: payload,
2627
+ newParticipantAction: newParticipantAction || source.newParticipantAction || "autoAssignNewRoom",
2628
+ roomName: source.roomName
2629
+ },
2630
+ resolve
2631
+ );
2632
+ });
2633
+ if (!response?.success) {
2634
+ return { ok: false, error: response?.reason || "The breakout rooms could not be updated." };
2635
+ }
2636
+ source.updateBreakoutRooms?.(payload);
2637
+ source.updateBreakOutRoomStarted?.(true);
2638
+ source.updateBreakOutRoomEnded?.(false);
2639
+ return { ok: true, error: "" };
2640
+ } catch (error) {
2641
+ return { ok: false, error: error?.message || "The breakout rooms could not be updated." };
2642
+ }
2643
+ }
2644
+ async function assignParticipantToBreakoutRoom({
2645
+ parameters,
2646
+ name,
2647
+ room,
2648
+ newParticipantAction
2649
+ }) {
2650
+ const source = parameters || {};
2651
+ if (!name) return { ok: false, error: "A participant name is required." };
2652
+ const current = Array.isArray(source.breakoutRooms) ? source.breakoutRooms.map((entry) => Array.isArray(entry) ? [...entry] : []) : [];
2653
+ const next = current.map((entry) => entry.filter((person) => person?.name !== name));
2654
+ if (room !== null && room !== void 0) {
2655
+ if (!Number.isInteger(room) || room < 0) {
2656
+ return { ok: false, error: "The destination room must be a room index." };
2657
+ }
2658
+ while (next.length <= room) next.push([]);
2659
+ next[room].push({ name, breakRoom: room });
2660
+ }
2661
+ return setBreakoutRooms({ parameters: source, rooms: next, newParticipantAction });
2662
+ }
2663
+ async function stopBreakoutRooms({
2664
+ parameters
2665
+ }) {
2666
+ try {
2667
+ const source = parameters || {};
2668
+ const socket = source.socket;
2669
+ if (!socket || typeof socket.emit !== "function" || !source.roomName) {
2670
+ return { ok: false, error: "The room connection is not ready." };
2671
+ }
2672
+ if (String(source.islevel) !== "2") {
2673
+ return { ok: false, error: "Only the host can stop breakout rooms." };
2674
+ }
2675
+ const response = await new Promise((resolve) => {
2676
+ socket.emit("stopBreakout", { roomName: source.roomName }, resolve);
2677
+ });
2678
+ if (!response?.success) {
2679
+ return { ok: false, error: response?.reason || "The breakout rooms could not be stopped." };
2680
+ }
2681
+ source.updateBreakOutRoomStarted?.(false);
2682
+ source.updateBreakOutRoomEnded?.(true);
2683
+ return { ok: true, error: "" };
2684
+ } catch (error) {
2685
+ return { ok: false, error: error?.message || "The breakout rooms could not be stopped." };
2686
+ }
2687
+ }
2688
+ async function reapplyLocalPlayback({
2689
+ parameters
2690
+ }) {
2691
+ if (LOCALLY_PAUSED.size === 0) return { ok: true, error: "", affected: 0 };
2692
+ try {
2693
+ const source = parameters || {};
2694
+ const transports = Array.isArray(source.consumerTransports) ? source.consumerTransports : [];
2695
+ let affected = 0;
2696
+ for (const entry of transports) {
2697
+ const consumer = entry?.consumer;
2698
+ const id = entry?.producerId || consumer?.producerId;
2699
+ if (!consumer || !LOCALLY_PAUSED.has(id)) continue;
2700
+ if (consumer.paused === true) continue;
2701
+ try {
2702
+ if (typeof consumer.pause === "function") {
2703
+ await consumer.pause();
2704
+ affected += 1;
2705
+ }
2706
+ } catch {
2707
+ }
2708
+ }
2709
+ return { ok: true, error: "", affected };
2710
+ } catch (error) {
2711
+ return { ok: false, error: error?.message || "Playback could not be re-applied.", affected: 0 };
2712
+ }
2713
+ }
2714
+ function getLocallyPausedProducerIds() {
2715
+ return Array.from(LOCALLY_PAUSED);
2716
+ }
2717
+ async function invokeChecked(live, run) {
2718
+ const alertBefore = live?.alertMessage || "";
2719
+ try {
2720
+ await run();
2721
+ } catch (error) {
2722
+ return { ok: false, error: error?.message || "The device switch failed." };
2723
+ }
2724
+ const settled = getCurrentParams({ parameters: live });
2725
+ const alertAfter = settled?.alertMessage || "";
2726
+ const alertType = settled?.alertType;
2727
+ if (alertAfter && alertAfter !== alertBefore && (alertType === "danger" || alertType === "warning")) {
2728
+ return { ok: false, error: alertAfter };
2729
+ }
2730
+ return { ok: true, error: "" };
2731
+ }
2732
+ async function switchCamera({
2733
+ parameters,
2734
+ deviceId
2735
+ }) {
2736
+ if (!deviceId) return { ok: false, error: "A camera deviceId is required." };
2737
+ const live = getCurrentParams({ parameters });
2738
+ return invokeChecked(live, () => switchVideo({ videoPreference: deviceId, parameters: live }));
2739
+ }
2740
+ async function flipCamera({ parameters }) {
2741
+ const live = getCurrentParams({ parameters });
2742
+ return invokeChecked(live, () => switchVideoAlt({ parameters: live }));
2743
+ }
2744
+ async function switchMicrophone({
2745
+ parameters,
2746
+ deviceId
2747
+ }) {
2748
+ if (!deviceId) return { ok: false, error: "A microphone deviceId is required." };
2749
+ const live = getCurrentParams({ parameters });
2750
+ return invokeChecked(live, () => switchAudio({ audioPreference: deviceId, parameters: live }));
2751
+ }
2752
+ async function setRoomMediaPolicy({
2753
+ parameters,
2754
+ audio,
2755
+ video,
2756
+ screenshare,
2757
+ chat
2758
+ }) {
2759
+ const live = getCurrentParams({ parameters });
2760
+ if (String(live.islevel) !== "2") {
2761
+ return { ok: false, error: "Only the host can change room settings." };
2762
+ }
2763
+ if (!live.socket) {
2764
+ return { ok: false, error: "The room connection is not ready yet." };
2765
+ }
2766
+ try {
2767
+ await joinLocalRoom.modifySettings({
2768
+ roomName: live.roomName || "",
2769
+ // The SDK requires all four on every call, so unspecified values are
2770
+ // filled from current state — otherwise changing one would blank the rest.
2771
+ audioSet: audio || live.audioSetting || "allow",
2772
+ videoSet: video || live.videoSetting || "allow",
2773
+ screenshareSet: screenshare || live.screenshareSetting || "allow",
2774
+ chatSet: chat || live.chatSetting || "allow",
2775
+ socket: live.socket,
2776
+ showAlert: live.showAlert,
2777
+ updateAudioSetting: live.updateAudioSetting,
2778
+ updateVideoSetting: live.updateVideoSetting,
2779
+ updateScreenshareSetting: live.updateScreenshareSetting,
2780
+ updateChatSetting: live.updateChatSetting,
2781
+ updateIsSettingsModalVisible: live.updateIsSettingsModalVisible || (() => {
2782
+ })
2783
+ });
2784
+ return { ok: true, error: "" };
2785
+ } catch (error) {
2786
+ return { ok: false, error: error?.message || "The room settings could not be updated." };
2787
+ }
2788
+ }
2789
+ function getChatMessages({
2790
+ parameters,
2791
+ scope = "all",
2792
+ withPerson = ""
2793
+ }) {
2794
+ const source = parameters || {};
2795
+ const raw = Array.isArray(source.messages) ? source.messages : [];
2796
+ const me = source.member || "";
2797
+ return raw.map((entry) => {
2798
+ const receivers = Array.isArray(entry?.receivers) ? entry.receivers : [];
2799
+ return {
2800
+ sender: entry?.sender || "",
2801
+ message: entry?.message || "",
2802
+ timestamp: entry?.timestamp || "",
2803
+ receivers,
2804
+ // MediaSFU marks group messages with an empty receivers list; anything
2805
+ // addressed is a DM.
2806
+ direct: receivers.length > 0,
2807
+ mine: entry?.sender === me
2808
+ };
2809
+ }).filter((message) => {
2810
+ if (scope === "group" && message.direct) return false;
2811
+ if (scope === "direct" && !message.direct) return false;
2812
+ if (withPerson) {
2813
+ return message.sender === withPerson || message.receivers.includes(withPerson);
2814
+ }
2815
+ return true;
2816
+ });
2817
+ }
2818
+ function getPendingApprovals({ parameters }) {
2819
+ const source = parameters || {};
2820
+ const waitingRaw = Array.isArray(source.waitingRoomList) ? source.waitingRoomList : [];
2821
+ const requestRaw = Array.isArray(source.requestList) ? source.requestList : [];
2822
+ const waiting = waitingRaw.map((entry) => ({
2823
+ name: entry?.name || "",
2824
+ id: entry?.id || ""
2825
+ }));
2826
+ const requests = requestRaw.map((entry) => ({
2827
+ id: entry?.id || "",
2828
+ name: entry?.name || "",
2829
+ // 'fa-microphone' | 'fa-video' | 'fa-desktop' | 'fa-comments' — what they asked for.
2830
+ icon: entry?.icon || "",
2831
+ username: entry?.username || entry?.name || ""
2832
+ }));
2833
+ return { waiting, requests, total: waiting.length + requests.length };
2834
+ }
2835
+ function getSessionTimer({ parameters }) {
2836
+ const source = parameters || {};
2837
+ return {
2838
+ elapsed: source.meetingProgressTime || "00:00",
2839
+ presenceCheckPending: Boolean(source.isConfirmHereModalVisible)
2840
+ };
2841
+ }
2842
+ function getPresenceCheck({ parameters }) {
2843
+ const source = parameters || {};
2844
+ return { pending: Boolean(source.isConfirmHereModalVisible) };
2845
+ }
2846
+ function confirmStillHere({ parameters }) {
2847
+ const live = getCurrentParams({ parameters });
2848
+ const update = live.updateIsConfirmHereModalVisible;
2849
+ if (typeof update !== "function") {
2850
+ return { ok: false, error: "The presence check control is unavailable." };
2851
+ }
2852
+ update(false);
2853
+ return { ok: true, error: "" };
2854
+ }
2855
+ function getPlaybackSources({ parameters }) {
2856
+ const source = parameters || {};
2857
+ const sources = [];
2858
+ const push = (protocol, url) => {
2859
+ if (typeof url === "string" && /^https:\/\//i.test(url)) sources.push({ protocol, url });
2860
+ };
2861
+ push("hls", source.hlsUrl || source.hlsPlaybackUrl || source.playbackUrl);
2862
+ push("whep", source.whepUrl || source.whepPlaybackUrl);
2863
+ return sources;
2864
+ }
2865
+ function inferProtocol(url, explicit) {
2866
+ if (explicit) return explicit;
2867
+ return /\.m3u8(\?|$)/i.test(url) ? "hls" : "whep";
2868
+ }
2869
+ function canPlayHlsNatively(video) {
2870
+ const claimsSupport = typeof video.canPlayType === "function" && video.canPlayType("application/vnd.apple.mpegurl") !== "";
2871
+ const hasMse = typeof MediaSource !== "undefined" || typeof globalThis.ManagedMediaSource !== "undefined";
2872
+ return claimsSupport && !hasMse;
2873
+ }
2874
+ async function attachHls(url, video, hlsFactory) {
2875
+ if (!video) throw new Error("HLS playback needs a <video> element.");
2876
+ if (typeof hlsFactory !== "function" && canPlayHlsNatively(video)) {
2877
+ video.src = url;
2878
+ const play = video.play?.();
2879
+ play?.catch?.(() => {
2880
+ });
2881
+ return {
2882
+ protocol: "hls",
2883
+ url,
2884
+ stream: null,
2885
+ detach: () => {
2886
+ video.removeAttribute("src");
2887
+ video.load?.();
2888
+ }
2889
+ };
2890
+ }
2891
+ if (typeof hlsFactory !== "function") {
2892
+ throw new Error(
2893
+ "HLS needs an hlsFactory on this browser. Pass () => new Hls(...) from hls.js; it is not bundled with the SDK. Only iOS Safari, which has no Media Source Extensions, plays HLS without one — Chrome reports that it can and then plays nothing."
2894
+ );
2895
+ }
2896
+ const hls = hlsFactory();
2897
+ hls.loadSource(url);
2898
+ hls.attachMedia(video);
2899
+ return {
2900
+ protocol: "hls",
2901
+ url,
2902
+ stream: null,
2903
+ detach: () => {
2904
+ try {
2905
+ hls.destroy();
2906
+ } catch {
2907
+ }
2908
+ video.removeAttribute("src");
2909
+ }
2910
+ };
2911
+ }
2912
+ async function attachWhep(url, video, headers = {}, iceServers) {
2913
+ if (typeof RTCPeerConnection === "undefined") {
2914
+ throw new Error("WHEP playback needs WebRTC support.");
2915
+ }
2916
+ const pc = new RTCPeerConnection(iceServers?.length ? { iceServers } : void 0);
2917
+ const stream = new MediaStream();
2918
+ pc.addTransceiver("video", { direction: "recvonly" });
2919
+ pc.addTransceiver("audio", { direction: "recvonly" });
2920
+ pc.ontrack = (event) => {
2921
+ if (event.track) stream.addTrack(event.track);
2922
+ if (video && video.srcObject !== stream) {
2923
+ video.srcObject = stream;
2924
+ const play = video.play?.();
2925
+ play?.catch?.(() => {
2926
+ });
2927
+ }
2928
+ };
2929
+ let resourceUrl = "";
2930
+ try {
2931
+ const offer = await pc.createOffer();
2932
+ await pc.setLocalDescription(offer);
2933
+ const response = await fetch(url, {
2934
+ method: "POST",
2935
+ headers: { "Content-Type": "application/sdp", ...headers },
2936
+ body: offer.sdp || ""
2937
+ });
2938
+ if (!response.ok) {
2939
+ throw new Error(`The WHEP endpoint refused the request (${response.status}).`);
2940
+ }
2941
+ const location = response.headers.get("Location") || "";
2942
+ resourceUrl = location ? new URL(location, url).toString() : "";
2943
+ const answer = await response.text();
2944
+ await pc.setRemoteDescription({ type: "answer", sdp: answer });
2945
+ } catch (error) {
2946
+ pc.close();
2947
+ throw error;
2948
+ }
2949
+ return {
2950
+ protocol: "whep",
2951
+ url,
2952
+ stream,
2953
+ detach: () => {
2954
+ if (resourceUrl) {
2955
+ try {
2956
+ void fetch(resourceUrl, { method: "DELETE", headers });
2957
+ } catch {
2958
+ }
2959
+ }
2960
+ try {
2961
+ pc.close();
2962
+ } catch {
2963
+ }
2964
+ stream.getTracks().forEach((track) => track.stop());
2965
+ if (video && video.srcObject === stream) video.srcObject = null;
2966
+ }
2967
+ };
2968
+ }
2969
+ async function attachPlayback({
2970
+ source,
2971
+ video,
2972
+ protocol,
2973
+ hlsFactory,
2974
+ headers,
2975
+ iceServers
2976
+ }) {
2977
+ const url = typeof source === "string" ? source : source?.url || "";
2978
+ if (!url) throw new Error("A playback URL is required.");
2979
+ const resolved = typeof source === "string" ? inferProtocol(url, protocol) : protocol || source.protocol || inferProtocol(url);
2980
+ return resolved === "hls" ? attachHls(url, video, hlsFactory) : attachWhep(url, video, headers, iceServers);
2981
+ }
2982
+ function detachPlayback(handle) {
2983
+ if (!handle || typeof handle.detach !== "function") return;
2984
+ try {
2985
+ handle.detach();
2986
+ } catch {
2987
+ }
2988
+ }
2989
+ async function publishWhip({
2990
+ url,
2991
+ stream,
2992
+ headers = {},
2993
+ iceServers
2994
+ }) {
2995
+ if (typeof RTCPeerConnection === "undefined") {
2996
+ throw new Error("WHIP publishing needs WebRTC support.");
2997
+ }
2998
+ if (!stream?.getTracks?.().length) throw new Error("A stream with at least one track is required.");
2999
+ const pc = new RTCPeerConnection(iceServers?.length ? { iceServers } : void 0);
3000
+ stream.getTracks().forEach((track) => pc.addTrack(track, stream));
3001
+ let resourceUrl = "";
3002
+ try {
3003
+ const offer = await pc.createOffer();
3004
+ await pc.setLocalDescription(offer);
3005
+ const response = await fetch(url, {
3006
+ method: "POST",
3007
+ headers: { "Content-Type": "application/sdp", ...headers },
3008
+ body: offer.sdp || ""
3009
+ });
3010
+ if (!response.ok) throw new Error(`The WHIP endpoint refused the request (${response.status}).`);
3011
+ const location = response.headers.get("Location") || "";
3012
+ resourceUrl = location ? new URL(location, url).toString() : "";
3013
+ await pc.setRemoteDescription({ type: "answer", sdp: await response.text() });
3014
+ } catch (error) {
3015
+ pc.close();
3016
+ throw error;
3017
+ }
3018
+ return {
3019
+ protocol: "whep",
3020
+ url,
3021
+ stream,
3022
+ detach: () => {
3023
+ if (resourceUrl) {
3024
+ try {
3025
+ void fetch(resourceUrl, { method: "DELETE", headers });
3026
+ } catch {
3027
+ }
3028
+ }
3029
+ try {
3030
+ pc.close();
3031
+ } catch {
3032
+ }
3033
+ }
3034
+ };
3035
+ }
3036
+ const MIN_INTERVAL_MS = 1e3;
3037
+ function createViewerSession({
3038
+ provider,
3039
+ roomName,
3040
+ displayName,
3041
+ pollIntervalMs = 5e3,
3042
+ heartbeatIntervalMs = 3e4,
3043
+ onChange
3044
+ }) {
3045
+ let snapshot = {
3046
+ phase: "idle",
3047
+ session: null,
3048
+ status: null,
3049
+ error: "",
3050
+ canRequestPromotion: typeof provider?.requestPromotion === "function"
3051
+ };
3052
+ let pollTimer = null;
3053
+ let heartbeatTimer = null;
3054
+ let stopped = false;
3055
+ const emit = (next) => {
3056
+ snapshot = { ...snapshot, ...next };
3057
+ try {
3058
+ onChange?.(snapshot);
3059
+ } catch {
3060
+ }
3061
+ };
3062
+ const clearTimers = () => {
3063
+ if (pollTimer) {
3064
+ clearInterval(pollTimer);
3065
+ pollTimer = null;
3066
+ }
3067
+ if (heartbeatTimer) {
3068
+ clearInterval(heartbeatTimer);
3069
+ heartbeatTimer = null;
3070
+ }
3071
+ };
3072
+ const startTimers = () => {
3073
+ clearTimers();
3074
+ if (typeof provider.poll === "function") {
3075
+ pollTimer = setInterval(async () => {
3076
+ if (stopped || !snapshot.session) return;
3077
+ try {
3078
+ const status = await provider.poll({ session: snapshot.session });
3079
+ if (stopped) return;
3080
+ const session = status?.playbackUrl ? { ...snapshot.session, playbackUrl: status.playbackUrl } : snapshot.session;
3081
+ emit({
3082
+ status,
3083
+ session,
3084
+ phase: status?.approved ? "approved" : snapshot.phase === "requested" ? "requested" : "watching"
3085
+ });
3086
+ if (status?.approved) clearTimers();
3087
+ } catch {
3088
+ }
3089
+ }, Math.max(MIN_INTERVAL_MS, pollIntervalMs));
3090
+ }
3091
+ if (typeof provider.heartbeat === "function") {
3092
+ heartbeatTimer = setInterval(() => {
3093
+ if (stopped || !snapshot.session) return;
3094
+ Promise.resolve(provider.heartbeat({ session: snapshot.session })).catch(() => {
3095
+ });
3096
+ }, Math.max(MIN_INTERVAL_MS, heartbeatIntervalMs));
3097
+ }
3098
+ };
3099
+ return {
3100
+ getSnapshot: () => snapshot,
3101
+ async start() {
3102
+ if (snapshot.phase !== "idle" && snapshot.phase !== "left" && snapshot.phase !== "error") {
3103
+ return snapshot;
3104
+ }
3105
+ stopped = false;
3106
+ emit({ phase: "joining", error: "" });
3107
+ try {
3108
+ const session = await provider.join({ roomName, displayName });
3109
+ if (stopped) return snapshot;
3110
+ if (!session?.viewerId) throw new Error("The viewer session provider returned no viewerId.");
3111
+ emit({ phase: "watching", session, error: "" });
3112
+ startTimers();
3113
+ } catch (error) {
3114
+ emit({ phase: "error", error: error?.message || "The viewer session could not start." });
3115
+ }
3116
+ return snapshot;
3117
+ },
3118
+ async requestPromotion() {
3119
+ if (!snapshot.session) {
3120
+ emit({ error: "Start the viewer session before requesting the floor." });
3121
+ return snapshot;
3122
+ }
3123
+ if (typeof provider.requestPromotion !== "function") {
3124
+ emit({ error: "This viewer session provider does not support promotion." });
3125
+ return snapshot;
3126
+ }
3127
+ try {
3128
+ await provider.requestPromotion({ session: snapshot.session });
3129
+ emit({ phase: "requested", error: "" });
3130
+ } catch (error) {
3131
+ emit({ error: error?.message || "The request could not be sent." });
3132
+ }
3133
+ return snapshot;
3134
+ },
3135
+ async stop() {
3136
+ stopped = true;
3137
+ clearTimers();
3138
+ const session = snapshot.session;
3139
+ emit({ phase: "left" });
3140
+ if (session && typeof provider.leave === "function") {
3141
+ try {
3142
+ await provider.leave({ session });
3143
+ } catch {
3144
+ }
3145
+ }
3146
+ }
3147
+ };
3148
+ }
3149
+ function hasLiveTrack(stream, kind) {
3150
+ if (!stream || typeof stream.getTracks !== "function") return false;
3151
+ try {
3152
+ return stream.getTracks().some((track) => track.kind === kind && track.readyState === "live");
3153
+ } catch {
3154
+ return false;
3155
+ }
3156
+ }
3157
+ function capOf(value) {
3158
+ if (typeof value === "number") return value;
3159
+ if (value && typeof value === "object") {
3160
+ const candidate = value.max ?? value.ideal;
3161
+ if (typeof candidate === "number") return candidate;
3162
+ }
3163
+ return 0;
3164
+ }
3165
+ function getCaptureLimits({ parameters, kind = "video" }) {
3166
+ const source = parameters || {};
3167
+ if (kind === "screen") {
3168
+ return {
3169
+ width: Number(source.targetWidth) || 0,
3170
+ height: Number(source.targetHeight) || 0,
3171
+ frameRate: Number(source.frameRate) || 30
3172
+ };
3173
+ }
3174
+ const vidCons = source.vidCons || {};
3175
+ return {
3176
+ width: capOf(vidCons.width),
3177
+ height: capOf(vidCons.height),
3178
+ frameRate: Number(source.frameRate) || 0
3179
+ };
3180
+ }
3181
+ async function enforceCaptureLimits(stream, parameters, kind, allowUnconstrained) {
3182
+ if (kind === "audio") return { ok: true, error: "" };
3183
+ const limits = getCaptureLimits({ parameters, kind });
3184
+ if (!limits.width && !limits.height && !limits.frameRate) return { ok: true, error: "" };
3185
+ let track;
3186
+ try {
3187
+ track = stream.getVideoTracks()[0];
3188
+ } catch {
3189
+ return { ok: true, error: "" };
3190
+ }
3191
+ if (!track) return { ok: true, error: "" };
3192
+ const constraints = {};
3193
+ if (limits.width) constraints.width = { max: limits.width };
3194
+ if (limits.height) constraints.height = { max: limits.height };
3195
+ if (limits.frameRate) constraints.frameRate = { max: limits.frameRate };
3196
+ try {
3197
+ await track.applyConstraints(constraints);
3198
+ } catch {
3199
+ }
3200
+ let settings = {};
3201
+ try {
3202
+ settings = track.getSettings?.() || {};
3203
+ } catch {
3204
+ return { ok: true, error: "" };
3205
+ }
3206
+ if (!settings.width && !settings.height && !settings.frameRate) {
3207
+ return { ok: true, error: "" };
3208
+ }
3209
+ const over = [];
3210
+ if (limits.width && settings.width && settings.width > limits.width) {
3211
+ over.push(`width ${settings.width} > ${limits.width}`);
3212
+ }
3213
+ if (limits.height && settings.height && settings.height > limits.height) {
3214
+ over.push(`height ${settings.height} > ${limits.height}`);
3215
+ }
3216
+ if (limits.frameRate && settings.frameRate && settings.frameRate > limits.frameRate + 1) {
3217
+ over.push(`frameRate ${Math.round(settings.frameRate)} > ${limits.frameRate}`);
3218
+ }
3219
+ if (over.length === 0) return { ok: true, error: "" };
3220
+ if (allowUnconstrained) return { ok: true, error: "" };
3221
+ return {
3222
+ ok: false,
3223
+ error: `This source exceeds the room's capture allowance (${over.join(", ")}). Reduce the source size or frame rate before publishing.`
3224
+ };
3225
+ }
3226
+ async function produceMedia({
3227
+ parameters,
3228
+ stream,
3229
+ kind,
3230
+ allowUnconstrained = false
3231
+ }) {
3232
+ try {
3233
+ const live = getCurrentParams({ parameters });
3234
+ const readiness = getRoomReadiness({ parameters: live });
3235
+ if (!readiness.ready) return { ok: false, error: readiness.reason };
3236
+ const trackKind = kind === "audio" ? "audio" : "video";
3237
+ if (!hasLiveTrack(stream, trackKind)) {
3238
+ return {
3239
+ ok: false,
3240
+ error: `The stream has no live ${trackKind} track to publish.`
3241
+ };
3242
+ }
3243
+ const limited = await enforceCaptureLimits(stream, live, kind, allowUnconstrained);
3244
+ if (!limited.ok) return limited;
3245
+ if (kind === "audio") {
3246
+ await updateParticipantAudioDecibels.streamSuccessAudio({ stream, parameters: live });
3247
+ } else if (kind === "screen") {
3248
+ await updateParticipantAudioDecibels.streamSuccessScreen({ stream, parameters: live });
3249
+ } else {
3250
+ await updateParticipantAudioDecibels.streamSuccessVideo({ stream, parameters: live });
3251
+ }
3252
+ return { ok: true, error: "" };
3253
+ } catch (error) {
3254
+ return { ok: false, error: error?.message || "The media could not be published." };
3255
+ }
3256
+ }
3257
+ async function stopProducing({
3258
+ parameters,
3259
+ kind
3260
+ }) {
3261
+ try {
3262
+ const live = getCurrentParams({ parameters });
3263
+ if (kind === "audio") {
3264
+ await updateParticipantAudioDecibels.disconnectSendTransportAudio({ parameters: live });
3265
+ } else if (kind === "screen") {
3266
+ await updateParticipantAudioDecibels.disconnectSendTransportScreen({ parameters: live });
3267
+ } else {
3268
+ await updateParticipantAudioDecibels.disconnectSendTransportVideo({ parameters: live });
3269
+ }
3270
+ return { ok: true, error: "" };
3271
+ } catch (error) {
3272
+ return { ok: false, error: error?.message || "The producer could not be stopped." };
3273
+ }
3274
+ }
3275
+ async function produceCanvas({
3276
+ parameters,
3277
+ canvas,
3278
+ frameRate = 30,
3279
+ as = "video"
3280
+ }) {
3281
+ try {
3282
+ if (!canvas || typeof canvas.captureStream !== "function") {
3283
+ return {
3284
+ ok: false,
3285
+ error: "This canvas cannot be captured in the current browser.",
3286
+ stream: null
3287
+ };
3288
+ }
3289
+ const stream = canvas.captureStream(frameRate);
3290
+ const result = await produceMedia({ parameters, stream, kind: as });
3291
+ if (!result.ok) {
3292
+ stream.getTracks().forEach((track) => track.stop());
3293
+ return { ...result, stream: null };
3294
+ }
3295
+ return { ...result, stream };
3296
+ } catch (error) {
3297
+ return {
3298
+ ok: false,
3299
+ error: error?.message || "The canvas could not be published.",
3300
+ stream: null
3301
+ };
3302
+ }
3303
+ }
3304
+ async function produceElement({
3305
+ parameters,
3306
+ element,
3307
+ withVideo,
3308
+ withAudio = true
3309
+ }) {
3310
+ try {
3311
+ const capture = element?.captureStream || element?.mozCaptureStream;
3312
+ if (typeof capture !== "function") {
3313
+ return {
3314
+ ok: false,
3315
+ error: "This element cannot be captured in the current browser.",
3316
+ stream: null
3317
+ };
3318
+ }
3319
+ const stream = capture.call(element);
3320
+ const wantsVideo = withVideo ?? hasLiveTrack(stream, "video");
3321
+ const results = [];
3322
+ if (wantsVideo && hasLiveTrack(stream, "video")) {
3323
+ results.push(await produceMedia({ parameters, stream, kind: "video" }));
3324
+ }
3325
+ if (withAudio && hasLiveTrack(stream, "audio")) {
3326
+ results.push(await produceMedia({ parameters, stream, kind: "audio" }));
3327
+ }
3328
+ if (results.length === 0) {
3329
+ return { ok: false, error: "The element has no live tracks yet.", stream: null };
3330
+ }
3331
+ const failure = results.find((result) => !result.ok);
3332
+ if (failure) return { ...failure, stream };
3333
+ return { ok: true, error: "", stream };
3334
+ } catch (error) {
3335
+ return {
3336
+ ok: false,
3337
+ error: error?.message || "The element could not be published.",
3338
+ stream: null
3339
+ };
3340
+ }
3341
+ }
3342
+ async function produceDisplay({
3343
+ parameters,
3344
+ constraints = { video: true },
3345
+ withAudio = false
3346
+ }) {
3347
+ try {
3348
+ const mediaDevices = parameters?.mediaDevices || (typeof navigator !== "undefined" ? navigator.mediaDevices : null);
3349
+ if (!mediaDevices || typeof mediaDevices.getDisplayMedia !== "function") {
3350
+ return {
3351
+ ok: false,
3352
+ error: "Screen capture is unavailable in this browser.",
3353
+ stream: null
3354
+ };
3355
+ }
3356
+ const stream = await mediaDevices.getDisplayMedia({
3357
+ ...constraints,
3358
+ ...withAudio ? { audio: true } : {}
3359
+ });
3360
+ const result = await produceMedia({ parameters, stream, kind: "screen" });
3361
+ if (!result.ok) {
3362
+ stream.getTracks().forEach((track) => track.stop());
3363
+ return { ...result, stream: null };
3364
+ }
3365
+ if (withAudio && hasLiveTrack(stream, "audio")) {
3366
+ await produceMedia({ parameters, stream, kind: "audio" });
3367
+ }
3368
+ return { ...result, stream };
3369
+ } catch (error) {
3370
+ const name = error?.name || "";
3371
+ if (name === "NotAllowedError" || name === "AbortError") {
3372
+ return { ok: false, error: "Screen sharing was cancelled.", stream: null };
3373
+ }
3374
+ return {
3375
+ ok: false,
3376
+ error: error?.message || "The screen could not be shared.",
3377
+ stream: null
3378
+ };
3379
+ }
3380
+ }
3381
+ async function replaceProducerTrack({
3382
+ parameters,
3383
+ track
3384
+ }) {
3385
+ try {
3386
+ if (!track || track.readyState !== "live") {
3387
+ return { ok: false, error: "The replacement track is not live." };
3388
+ }
3389
+ const live = getCurrentParams({ parameters });
3390
+ const producer = track.kind === "audio" ? live.audioProducer || live.localAudioProducer : live.videoProducer || live.localVideoProducer;
3391
+ if (!producer || typeof producer.replaceTrack !== "function") {
3392
+ return {
3393
+ ok: false,
3394
+ error: `There is no live ${track.kind} producer to replace.`
3395
+ };
3396
+ }
3397
+ await producer.replaceTrack({ track });
3398
+ return { ok: true, error: "" };
3399
+ } catch (error) {
3400
+ return { ok: false, error: error?.message || "The track could not be replaced." };
3401
+ }
3402
+ }
3403
+ async function getParticipantMedia({
3404
+ id = "",
3405
+ name = "",
3406
+ kind = "video",
3407
+ parameters
3408
+ }) {
3409
+ try {
3410
+ if (!parameters) return null;
3411
+ const live = typeof parameters.getCurrentParams === "function" ? parameters.getCurrentParams() || parameters : parameters;
3412
+ const participants = Array.isArray(live.participants) ? live.participants : [];
3413
+ const streams = Array.isArray(
3414
+ kind === "video" ? live.allVideoStreams : live.allAudioStreams
3415
+ ) ? kind === "video" ? live.allVideoStreams : live.allAudioStreams : [];
3416
+ if (streams.length === 0) return null;
3417
+ let participant = id ? participants.find((part) => part.id === id) : void 0;
3418
+ if (!participant && name) {
3419
+ participant = participants.find((part) => part.name === name);
3420
+ }
3421
+ const producerId = participant ? kind === "video" ? participant.videoID : participant.audioID : "";
3422
+ if (producerId) {
3423
+ const match = streams.find((stream) => stream.producerId === producerId);
3424
+ if (match && match.stream) return match.stream;
3425
+ }
3426
+ if (id) {
3427
+ const direct = streams.find((stream) => stream.producerId === id);
3428
+ if (direct && direct.stream) return direct.stream;
3429
+ }
3430
+ return null;
3431
+ } catch {
3432
+ return null;
3433
+ }
3434
+ }
3435
+ exports.assignParticipantToBreakoutRoom = assignParticipantToBreakoutRoom;
3436
+ exports.attachPlayback = attachPlayback;
3437
+ exports.checkPauseState = checkPauseState;
3438
+ exports.checkResumeState = checkResumeState;
3439
+ exports.confirmExit = confirmExit;
3440
+ exports.confirmRecording = confirmRecording;
3441
+ exports.confirmStillHere = confirmStillHere;
3442
+ exports.createRoomPoll = createRoomPoll;
3443
+ exports.createViewerSession = createViewerSession;
3444
+ exports.detachPlayback = detachPlayback;
3445
+ exports.disableParticipantVideo = disableParticipantVideo;
3446
+ exports.endRoomPoll = endRoomPoll;
3447
+ exports.flipCamera = flipCamera;
3448
+ exports.getActiveSpeaker = getActiveSpeaker;
3449
+ exports.getAudioGridComponents = getAudioGridComponents;
3450
+ exports.getBreakoutState = getBreakoutState;
3451
+ exports.getCaptureLimits = getCaptureLimits;
3452
+ exports.getChatMessages = getChatMessages;
3453
+ exports.getCurrentParams = getCurrentParams;
3454
+ exports.getFocusModeState = getFocusModeState;
3455
+ exports.getLocalAudioStream = getLocalAudioStream;
3456
+ exports.getLocalVideoStream = getLocalVideoStream;
3457
+ exports.getLocallyPausedProducerIds = getLocallyPausedProducerIds;
3458
+ exports.getMediaPermissions = getMediaPermissions;
3459
+ exports.getModalPosition = getModalPosition;
3460
+ exports.getModerationPermissions = getModerationPermissions;
3461
+ exports.getParticipantMedia = getParticipantMedia;
3462
+ exports.getParticipantMediaState = getParticipantMediaState;
3463
+ exports.getPendingApprovals = getPendingApprovals;
3464
+ exports.getPlaybackSources = getPlaybackSources;
3465
+ exports.getPollState = getPollState;
3466
+ exports.getPresenceCheck = getPresenceCheck;
3467
+ exports.getRecordingCapabilities = getRecordingCapabilities;
3468
+ exports.getRecordingNotice = getRecordingNotice;
3469
+ exports.getRecordingState = getRecordingState;
3470
+ exports.getRemoteAudioStreams = getRemoteAudioStreams;
3471
+ exports.getRemoteVideoStreams = getRemoteVideoStreams;
3472
+ exports.getRoomReadiness = getRoomReadiness;
3473
+ exports.getScreenShareStream = getScreenShareStream;
3474
+ exports.getSelectedDevices = getSelectedDevices;
3475
+ exports.getSessionTimer = getSessionTimer;
3476
+ exports.getTranslationState = getTranslationState;
3477
+ exports.getVirtualBackgroundState = getVirtualBackgroundState;
3478
+ exports.getWhiteboardState = getWhiteboardState;
3479
+ exports.handleCreatePoll = handleCreatePoll;
3480
+ exports.handleEndPoll = handleEndPoll;
3481
+ exports.handleStartBreakout = handleStartBreakout;
3482
+ exports.handleStartWhiteboard = handleStartWhiteboard;
3483
+ exports.handleStopBreakout = handleStopBreakout;
3484
+ exports.handleStopWhiteboard = handleStopWhiteboard;
3485
+ exports.handleVotePoll = handleVotePoll;
3486
+ exports.launchBackground = launchBackground;
3487
+ exports.launchBreakoutRooms = launchBreakoutRooms;
3488
+ exports.launchCoHost = launchCoHost;
3489
+ exports.launchConfigureWhiteboard = launchConfigureWhiteboard;
3490
+ exports.launchConfirmExit = launchConfirmExit;
3491
+ exports.launchDisplaySettings = launchDisplaySettings;
3492
+ exports.launchMediaSettings = launchMediaSettings;
3493
+ exports.launchMenuModal = launchMenuModal;
3494
+ exports.launchMessages = launchMessages;
3495
+ exports.launchParticipants = launchParticipants;
3496
+ exports.launchPoll = launchPoll;
3497
+ exports.launchRecording = launchRecording;
3498
+ exports.launchRequests = launchRequests;
3499
+ exports.launchSettings = launchSettings;
3500
+ exports.launchWaiting = launchWaiting;
3501
+ exports.leaveRoom = leaveRoom;
3502
+ exports.listMediaDevices = listMediaDevices;
3503
+ exports.listParticipantMediaStates = listParticipantMediaStates;
3504
+ exports.messageParticipants = messageParticipants;
3505
+ exports.modifyCoHostSettings = modifyCoHostSettings;
3506
+ exports.modifyDisplaySettings = modifyDisplaySettings;
3507
+ exports.muteEveryone = muteEveryone;
3508
+ exports.muteParticipant = muteParticipant;
3509
+ exports.muteParticipants = muteParticipants;
3510
+ exports.pauseRoomRecording = pauseRoomRecording;
3511
+ exports.produceCanvas = produceCanvas;
3512
+ exports.produceDisplay = produceDisplay;
3513
+ exports.produceElement = produceElement;
3514
+ exports.produceMedia = produceMedia;
3515
+ exports.publishWhip = publishWhip;
3516
+ exports.reapplyLocalPlayback = reapplyLocalPlayback;
3517
+ exports.recordPauseTimer = recordPauseTimer;
3518
+ exports.recordResumeTimer = recordResumeTimer;
3519
+ exports.recordStartTimer = recordStartTimer;
3520
+ exports.recordUpdateTimer = recordUpdateTimer;
3521
+ exports.removeParticipant = removeParticipant;
3522
+ exports.removeParticipants = removeParticipants;
3523
+ exports.replaceProducerTrack = replaceProducerTrack;
3524
+ exports.respondToParticipantRequest = respondToParticipantRequest;
3525
+ exports.respondToRequests = respondToRequests;
3526
+ exports.respondToWaiting = respondToWaiting;
3527
+ exports.respondToWaitingParticipant = respondToWaitingParticipant;
3528
+ exports.resumeRoomRecording = resumeRoomRecording;
3529
+ exports.runMediaControl = runMediaControl;
3530
+ exports.sendChatMessage = sendChatMessage;
3531
+ exports.sendMessage = sendMessage;
3532
+ exports.setBreakoutRooms = setBreakoutRooms;
3533
+ exports.setCoHost = setCoHost;
3534
+ exports.setParticipantMedia = setParticipantMedia;
3535
+ exports.setParticipantPlayback = setParticipantPlayback;
3536
+ exports.setRoomMediaPolicy = setRoomMediaPolicy;
3537
+ exports.setTranslationPreference = setTranslationPreference;
3538
+ exports.startRecording = startRecording;
3539
+ exports.startRoomRecording = startRoomRecording;
3540
+ exports.startWhiteboard = startWhiteboard;
3541
+ exports.stopBreakoutRooms = stopBreakoutRooms;
3542
+ exports.stopParticipantScreenShare = stopParticipantScreenShare;
3543
+ exports.stopProducing = stopProducing;
3544
+ exports.stopRecording = stopRecording;
3545
+ exports.stopRoomRecording = stopRoomRecording;
3546
+ exports.stopWhiteboard = stopWhiteboard;
3547
+ exports.switchAudio = switchAudio;
3548
+ exports.switchCamera = switchCamera;
3549
+ exports.switchMicrophone = switchMicrophone;
3550
+ exports.switchVideo = switchVideo;
3551
+ exports.switchVideoAlt = switchVideoAlt;
3552
+ exports.updateRecording = updateRecording;
3553
+ exports.voteInRoomPoll = voteInRoomPoll;
3554
+ //# sourceMappingURL=getParticipantMedia-CdcYqcbD.cjs.map