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