mediasfu-shared 1.2.7 → 1.3.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 (101) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/ProducerClient/producerClientEmits/updateRoomParametersClient.d.ts +2 -0
  3. package/dist/ProducerClient/producerClientEmits/updateRoomParametersClient.d.ts.map +1 -1
  4. package/dist/audioProcessing-Ca5wm1nV.js +150 -0
  5. package/dist/audioProcessing-Ca5wm1nV.js.map +1 -0
  6. package/dist/audioProcessing-VCbu70Jt.cjs +149 -0
  7. package/dist/audioProcessing-VCbu70Jt.cjs.map +1 -0
  8. package/dist/consumers/closeAndResize.d.ts +3 -0
  9. package/dist/consumers/closeAndResize.d.ts.map +1 -1
  10. package/dist/consumers/connectIps.d.ts +6 -0
  11. package/dist/consumers/connectIps.d.ts.map +1 -1
  12. package/dist/consumers/connectSendTransportScreenAudio.d.ts +65 -0
  13. package/dist/consumers/connectSendTransportScreenAudio.d.ts.map +1 -0
  14. package/dist/consumers/consumerBackupPreference.d.ts +14 -0
  15. package/dist/consumers/consumerBackupPreference.d.ts.map +1 -0
  16. package/dist/consumers/disconnectSendTransportScreen.d.ts.map +1 -1
  17. package/dist/consumers/getPipedProducersAlt.d.ts.map +1 -1
  18. package/dist/consumers/index.cjs +23 -1
  19. package/dist/consumers/index.cjs.map +1 -1
  20. package/dist/consumers/index.d.ts +3 -0
  21. package/dist/consumers/index.d.ts.map +1 -1
  22. package/dist/consumers/index.js +61 -39
  23. package/dist/consumers/index.js.map +1 -1
  24. package/dist/consumers/screenAudio.d.ts +64 -0
  25. package/dist/consumers/screenAudio.d.ts.map +1 -0
  26. package/dist/consumers/socketReceiveMethods/producerClosed.d.ts.map +1 -1
  27. package/dist/consumers/startShareScreen.d.ts +14 -0
  28. package/dist/consumers/startShareScreen.d.ts.map +1 -1
  29. package/dist/consumers/streamSuccessScreen.d.ts.map +1 -1
  30. package/dist/{getParticipantMedia-c2bbdT5f.cjs → getParticipantMedia-1okyF4H7.cjs} +4 -4
  31. package/dist/{getParticipantMedia-c2bbdT5f.cjs.map → getParticipantMedia-1okyF4H7.cjs.map} +1 -1
  32. package/dist/{getParticipantMedia-DTZg8n5U.js → getParticipantMedia-DEJwXXhU.js} +4 -4
  33. package/dist/{getParticipantMedia-DTZg8n5U.js.map → getParticipantMedia-DEJwXXhU.js.map} +1 -1
  34. package/dist/index.cjs +36 -6
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1523 -1493
  39. package/dist/index.native.cjs +36 -6
  40. package/dist/index.native.cjs.map +1 -1
  41. package/dist/index.native.d.ts +4 -0
  42. package/dist/index.native.d.ts.map +1 -1
  43. package/dist/index.native.js +105 -75
  44. package/dist/{joinLocalRoom-1dRd2PCN.js → joinLocalRoom-DS6_6lJL.js} +6 -4
  45. package/dist/joinLocalRoom-DS6_6lJL.js.map +1 -0
  46. package/dist/{joinLocalRoom-DwY-3ZsH.cjs → joinLocalRoom-Dsn39SwS.cjs} +6 -4
  47. package/dist/joinLocalRoom-Dsn39SwS.cjs.map +1 -0
  48. package/dist/{joinRoomOnMediaSFU-BnAWLciF.js → joinRoomOnMediaSFU-B6tTA0Mx.js} +17 -13
  49. package/dist/joinRoomOnMediaSFU-B6tTA0Mx.js.map +1 -0
  50. package/dist/{joinRoomOnMediaSFU-D2C7q1GK.cjs → joinRoomOnMediaSFU-CxwD9fBz.cjs} +17 -13
  51. package/dist/joinRoomOnMediaSFU-CxwD9fBz.cjs.map +1 -0
  52. package/dist/methods/index.cjs +11 -8
  53. package/dist/methods/index.cjs.map +1 -1
  54. package/dist/methods/index.js +13 -9
  55. package/dist/methods/index.js.map +1 -1
  56. package/dist/methods/socketReceive/getDomains.d.ts.map +1 -1
  57. package/dist/methods/utils/checkLimitsAndMakeRequest.d.ts.map +1 -1
  58. package/dist/methods/welcome/handleWelcomeRequest.d.ts.map +1 -1
  59. package/dist/sockets/SocketManager.d.ts.map +1 -1
  60. package/dist/sockets/mediaSocketErrors.d.ts +62 -0
  61. package/dist/sockets/mediaSocketErrors.d.ts.map +1 -0
  62. package/dist/types/index.cjs +4 -3
  63. package/dist/types/index.cjs.map +1 -1
  64. package/dist/types/index.js +39 -38
  65. package/dist/types/shared-base-types.d.ts +4 -0
  66. package/dist/types/shared-base-types.d.ts.map +1 -1
  67. package/dist/{updateParticipantAudioDecibels-DiJ_LFfH.js → updateParticipantAudioDecibels-BBfdHWQ0.js} +344 -61
  68. package/dist/updateParticipantAudioDecibels-BBfdHWQ0.js.map +1 -0
  69. package/dist/{updateParticipantAudioDecibels-BJ2PxJJD.cjs → updateParticipantAudioDecibels-Dni8i6AY.cjs} +306 -23
  70. package/dist/updateParticipantAudioDecibels-Dni8i6AY.cjs.map +1 -0
  71. package/package.json +3 -2
  72. package/src/ProducerClient/producerClientEmits/updateRoomParametersClient.ts +4 -0
  73. package/src/consumers/closeAndResize.ts +14 -0
  74. package/src/consumers/connectIps.ts +81 -8
  75. package/src/consumers/connectSendTransportScreenAudio.ts +184 -0
  76. package/src/consumers/consumerBackupPreference.ts +43 -0
  77. package/src/consumers/disconnectSendTransportScreen.ts +8 -0
  78. package/src/consumers/getPipedProducersAlt.ts +4 -0
  79. package/src/consumers/index.ts +3 -0
  80. package/src/consumers/screenAudio.ts +132 -0
  81. package/src/consumers/socketReceiveMethods/producerClosed.ts +3 -0
  82. package/src/consumers/startShareScreen.ts +44 -8
  83. package/src/consumers/streamSuccessScreen.ts +11 -0
  84. package/src/index.native.ts +4 -0
  85. package/src/index.ts +4 -0
  86. package/src/methods/socketReceive/getDomains.ts +4 -0
  87. package/src/methods/utils/checkLimitsAndMakeRequest.ts +24 -11
  88. package/src/methods/welcome/handleWelcomeRequest.ts +15 -6
  89. package/src/sockets/SocketManager.ts +76 -12
  90. package/src/sockets/mediaSocketErrors.ts +156 -0
  91. package/src/types/shared-base-types.ts +4 -0
  92. package/dist/audioProcessing-0z5KlcmO.js +0 -35
  93. package/dist/audioProcessing-0z5KlcmO.js.map +0 -1
  94. package/dist/audioProcessing-BpbrdCk-.cjs +0 -34
  95. package/dist/audioProcessing-BpbrdCk-.cjs.map +0 -1
  96. package/dist/joinLocalRoom-1dRd2PCN.js.map +0 -1
  97. package/dist/joinLocalRoom-DwY-3ZsH.cjs.map +0 -1
  98. package/dist/joinRoomOnMediaSFU-BnAWLciF.js.map +0 -1
  99. package/dist/joinRoomOnMediaSFU-D2C7q1GK.cjs.map +0 -1
  100. package/dist/updateParticipantAudioDecibels-BJ2PxJJD.cjs.map +0 -1
  101. package/dist/updateParticipantAudioDecibels-DiJ_LFfH.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import io from "socket.io-client";
2
- import { v as validateAlphanumeric, b as audioProcessingConstraints } from "./audioProcessing-0z5KlcmO.js";
2
+ import { a as MediaSocketConnectError, b as currentOnlineState, n as normalizeRejectionReason, v as validateAlphanumeric, c as consumerBackupPreferDelay, i as isMediaSocketConnectError, k as audioProcessingConstraints } from "./audioProcessing-Ca5wm1nV.js";
3
3
  const createFrameworkConsumerContractError = (consumerName) => {
4
4
  return new Error(
5
5
  `${consumerName} is a render-coupled consumer helper and has no shared runtime implementation. Inject the framework-specific ${consumerName} implementation instead of calling the shared fallback export.`
@@ -506,6 +506,7 @@ const closeAndResize = async ({ producerId, kind, parameters }) => {
506
506
  parameters = getUpdatedAllParams();
507
507
  let {
508
508
  allAudioStreams,
509
+ audioOnlyStreams = [],
509
510
  allVideoStreams,
510
511
  activeNames,
511
512
  participants,
@@ -530,6 +531,7 @@ const closeAndResize = async ({ producerId, kind, parameters }) => {
530
531
  updateMainWindow,
531
532
  updateActiveNames,
532
533
  updateAllAudioStreams,
534
+ updateAudioOnlyStreams,
533
535
  updateAllVideoStreams,
534
536
  updateShareScreenStarted,
535
537
  updateUpdateMainWindow,
@@ -553,6 +555,11 @@ const closeAndResize = async ({ producerId, kind, parameters }) => {
553
555
  return audioStream.producerId !== producerId;
554
556
  });
555
557
  updateAllAudioStreams(allAudioStreams);
558
+ const playerProducerId = (element) => String(element?.props?.remoteProducerId ?? element?.inputs?.remoteProducerId ?? element?.key ?? "");
559
+ if (audioOnlyStreams.some((element) => playerProducerId(element) === producerId)) {
560
+ audioOnlyStreams = audioOnlyStreams.filter((element) => playerProducerId(element) !== producerId);
561
+ updateAudioOnlyStreams?.(audioOnlyStreams);
562
+ }
556
563
  if (recordingDisplayType == "video" && recordingVideoOptimized == true) ;
557
564
  else {
558
565
  participant = participants.find(
@@ -811,12 +818,26 @@ async function connectSocket({ apiUserName, apiKey, apiToken, link }) {
811
818
  }
812
819
  let settled = false;
813
820
  let timeoutHandle;
821
+ const startedAt = Date.now();
822
+ let transportOpened = false;
823
+ let rejection = null;
814
824
  const cleanupHandshake = () => {
815
825
  if (timeoutHandle) clearTimeout(timeoutHandle);
816
826
  socket.off("connection-success", handleConnectionSuccess);
817
827
  socket.off("connect_error", handleConnectError);
818
828
  socket.off("disconnect", handleDisconnectBeforeReady);
829
+ socket.off("connect", handleTransportOpen);
830
+ socket.off("connection-rejected", handleConnectionRejected);
819
831
  };
832
+ const failure = (phase, transportError) => new MediaSocketConnectError({
833
+ phase: rejection ? "rejected" : phase,
834
+ reason: rejection?.reason,
835
+ stage: rejection?.stage,
836
+ elapsedMs: Date.now() - startedAt,
837
+ online: currentOnlineState(),
838
+ transportError,
839
+ link
840
+ });
820
841
  const settle = (action) => {
821
842
  if (settled) return;
822
843
  settled = true;
@@ -837,28 +858,40 @@ async function connectSocket({ apiUserName, apiKey, apiToken, link }) {
837
858
  const handleConnectError = (error) => {
838
859
  settle(() => {
839
860
  socket.disconnect();
840
- reject(new Error("Error connecting to media socket: " + error.message));
861
+ reject(failure(transportOpened ? "after-open" : "before-open", error?.message));
862
+ });
863
+ };
864
+ const handleTransportOpen = () => {
865
+ transportOpened = true;
866
+ };
867
+ const handleConnectionRejected = (payload) => {
868
+ rejection = {
869
+ reason: normalizeRejectionReason(payload?.reason),
870
+ stage: typeof payload?.stage === "string" ? payload.stage : void 0
871
+ };
872
+ settle(() => {
873
+ try {
874
+ socket.disconnect();
875
+ } catch {
876
+ }
877
+ reject(failure("rejected"));
841
878
  });
842
879
  };
843
880
  const handleDisconnectBeforeReady = (reason) => {
844
- settle(
845
- () => reject(
846
- new Error(
847
- "Media socket closed before the room was ready (" + reason + ")."
848
- )
849
- )
850
- );
881
+ settle(() => reject(failure("after-open", reason)));
851
882
  };
852
883
  socket.on("connection-success", handleConnectionSuccess);
853
884
  socket.on("connect_error", handleConnectError);
854
885
  socket.on("disconnect", handleDisconnectBeforeReady);
886
+ socket.on("connect", handleTransportOpen);
887
+ socket.on("connection-rejected", handleConnectionRejected);
855
888
  timeoutHandle = setTimeout(() => {
856
889
  settle(() => {
857
890
  try {
858
891
  socket.disconnect();
859
892
  } catch {
860
893
  }
861
- reject(new Error("Timed out connecting to media socket."));
894
+ reject(failure("timeout"));
862
895
  });
863
896
  }, CONNECT_TIMEOUT_MS);
864
897
  });
@@ -872,11 +905,24 @@ async function connectLocalSocket({ link }) {
872
905
  socket = io(`${link}/media`, {
873
906
  transports: ["websocket"]
874
907
  });
908
+ const startedAt = Date.now();
909
+ let transportOpened = false;
910
+ socket.on("connect", () => {
911
+ transportOpened = true;
912
+ });
875
913
  socket.on("connection-success", (data) => {
876
914
  resolve({ socket, data });
877
915
  });
878
916
  socket.on("connect_error", (error) => {
879
- reject(new Error("Error connecting to media socket: " + error.message));
917
+ reject(
918
+ new MediaSocketConnectError({
919
+ phase: transportOpened ? "after-open" : "before-open",
920
+ elapsedMs: Date.now() - startedAt,
921
+ online: currentOnlineState(),
922
+ transportError: error?.message,
923
+ link
924
+ })
925
+ );
880
926
  });
881
927
  });
882
928
  }
@@ -1245,11 +1291,72 @@ const newPipeProducer = async ({
1245
1291
  updateFirst_round(updatedFirstRound);
1246
1292
  }
1247
1293
  };
1294
+ const SCREEN_AUDIO_MEDIA_TAG = "screen-audio";
1295
+ const SCREEN_AUDIO_CODEC_OPTIONS = {
1296
+ opusStereo: true,
1297
+ opusDtx: false,
1298
+ opusFec: true,
1299
+ opusMaxAverageBitrate: 128e3
1300
+ };
1301
+ const screenAudioProducerIds = /* @__PURE__ */ new Set();
1302
+ const markScreenAudioProducer = (producerId, mediaTag) => {
1303
+ if (producerId && mediaTag === SCREEN_AUDIO_MEDIA_TAG) screenAudioProducerIds.add(producerId);
1304
+ };
1305
+ const forgetScreenAudioProducer = (producerId) => {
1306
+ if (producerId) screenAudioProducerIds.delete(producerId);
1307
+ };
1308
+ const isScreenAudioProducer = ({ producerId, participants = [], appData }) => {
1309
+ if (!producerId) return false;
1310
+ if (screenAudioProducerIds.has(producerId)) return true;
1311
+ if (appData?.mediaTag === SCREEN_AUDIO_MEDIA_TAG) return true;
1312
+ return participants.some((participant) => participant?.ScreenAudioID === producerId);
1313
+ };
1314
+ const shouldShareScreenAudio = ({ supportsScreenAudio, screenAudioEnabled, screenAudioMode }) => supportsScreenAudio === true && screenAudioEnabled !== false && screenAudioMode !== "never";
1315
+ const canCaptureDisplayAudio = (nav = typeof navigator !== "undefined" ? navigator : void 0) => {
1316
+ if (!nav) return false;
1317
+ const ua = String(nav.userAgent || "");
1318
+ if (/Mobi|Android|iPhone|iPad|iPod/i.test(ua)) return false;
1319
+ const brands = (nav.userAgentData?.brands || []).map((entry) => String(entry?.brand || ""));
1320
+ if (brands.some((brand) => /Chromium|Google Chrome|Microsoft Edge|Opera|Brave/i.test(brand))) return true;
1321
+ return /(Chrome|Chromium|Edg)\//.test(ua) && !/Firefox|FxiOS|OPiOS/.test(ua);
1322
+ };
1323
+ const setScreenAudioPaused = (producer, paused) => {
1324
+ if (!producer || producer.closed) return false;
1325
+ if (paused && !producer.paused) producer.pause();
1326
+ if (!paused && producer.paused) producer.resume();
1327
+ return producer.paused;
1328
+ };
1329
+ const buildDisplayMediaOptions = ({ targetWidth, targetHeight, withAudio }) => {
1330
+ const options = {
1331
+ video: { width: targetWidth, height: targetHeight, frameRate: 30 },
1332
+ audio: withAudio ? { echoCancellation: false, noiseSuppression: false, autoGainControl: false } : false
1333
+ };
1334
+ if (withAudio) {
1335
+ options.systemAudio = "include";
1336
+ options.suppressLocalAudioPlayback = false;
1337
+ }
1338
+ return options;
1339
+ };
1340
+ const producersBySocket = /* @__PURE__ */ new WeakMap();
1341
+ const rememberScreenAudioProducer = (socket, producer) => {
1342
+ if (!socket) return;
1343
+ if (producer) producersBySocket.set(socket, producer);
1344
+ else producersBySocket.delete(socket);
1345
+ };
1346
+ const recallScreenAudioProducer = (socket) => socket && producersBySocket.get(socket) || null;
1347
+ const setScreenAudioVolume = (volume, root = typeof document !== "undefined" ? document : null) => {
1348
+ if (!root) return;
1349
+ const value = Math.min(1, Math.max(0, Number.isFinite(volume) ? volume : 1));
1350
+ root.querySelectorAll('audio[data-screen-audio="true"]').forEach((element) => {
1351
+ element.volume = value;
1352
+ });
1353
+ };
1248
1354
  const producerClosed = async ({
1249
1355
  remoteProducerId,
1250
1356
  parameters
1251
1357
  }) => {
1252
1358
  let { consumerTransports, closeAndResize: closeAndResize2, screenId, updateConsumerTransports } = parameters;
1359
+ forgetScreenAudioProducer(remoteProducerId);
1253
1360
  const activeTranslationProducerIds = parameters.activeTranslationProducerIds;
1254
1361
  const isTranslationProducer = activeTranslationProducerIds?.has?.(remoteProducerId);
1255
1362
  if (isTranslationProducer) {
@@ -1400,6 +1507,20 @@ const joinConsumeRoom = async ({
1400
1507
  };
1401
1508
  const pendingConsumeConnections = /* @__PURE__ */ new WeakMap();
1402
1509
  const normalizeConsumeEndpoint = (ip) => ip.trim().toLowerCase().replace(/\.$/, "");
1510
+ const CONSUME_REJECTION_COOLDOWN_MS = 6e4;
1511
+ const rejectedConsumeEndpoints = /* @__PURE__ */ new WeakMap();
1512
+ const consumeEndpointRecentlyRejected = (owner, endpoint) => {
1513
+ const at = rejectedConsumeEndpoints.get(owner)?.get(endpoint);
1514
+ return at !== void 0 && Date.now() - at < CONSUME_REJECTION_COOLDOWN_MS;
1515
+ };
1516
+ const rememberConsumeEndpointRejection = (owner, endpoint) => {
1517
+ let byEndpoint = rejectedConsumeEndpoints.get(owner);
1518
+ if (!byEndpoint) {
1519
+ byEndpoint = /* @__PURE__ */ new Map();
1520
+ rejectedConsumeEndpoints.set(owner, byEndpoint);
1521
+ }
1522
+ byEndpoint.set(endpoint, Date.now());
1523
+ };
1403
1524
  const hasConsumeEndpoint = (consumeSockets, endpoint) => {
1404
1525
  for (let index = consumeSockets.length - 1; index >= 0; index -= 1) {
1405
1526
  const socketObj = consumeSockets[index];
@@ -1467,7 +1588,9 @@ const connectIps = async ({
1467
1588
  });
1468
1589
  return [consume_sockets, roomRecvIPs];
1469
1590
  }
1591
+ const rejectionOwner = parameters?.socket || consume_sockets;
1470
1592
  for (const ip of remIP) {
1593
+ if (consumeEndpointRecentlyRejected(rejectionOwner, normalizeConsumeEndpoint(ip))) continue;
1471
1594
  const releaseReservation = await reserveConsumeEndpoint(
1472
1595
  consume_sockets,
1473
1596
  ip,
@@ -1479,11 +1602,25 @@ const connectIps = async ({
1479
1602
  try {
1480
1603
  remote_sock = await connectSocket({ apiUserName, apiKey, apiToken, link: `https://${ip}.mediasfu.com` });
1481
1604
  if (remote_sock.id) {
1605
+ let consumeRoomReady = false;
1606
+ const pendingProducers = [];
1482
1607
  if (!roomRecvIPs.includes(ip)) {
1483
1608
  roomRecvIPs.push(ip);
1484
1609
  updateRoomRecvIPs(roomRecvIPs);
1485
1610
  }
1486
- remote_sock.on("new-pipe-producer", async ({ producerId, islevel, isTranslation, translationMeta }) => {
1611
+ const consumeProducer = async ({ producerId, islevel, isTranslation, translationMeta, mediaTag }) => {
1612
+ markScreenAudioProducer(producerId, mediaTag);
1613
+ if (!consumeRoomReady) {
1614
+ pendingProducers.push({ producerId, islevel, isTranslation, translationMeta });
1615
+ return;
1616
+ }
1617
+ const preferDelay = isTranslation ? 0 : consumerBackupPreferDelay(
1618
+ ip,
1619
+ parameters.getUpdatedAllParams?.()?.consume_sockets
1620
+ );
1621
+ if (preferDelay > 0) {
1622
+ await new Promise((resolve) => setTimeout(resolve, preferDelay));
1623
+ }
1487
1624
  if (newProducerMethod) {
1488
1625
  await newProducerMethod({
1489
1626
  producerId,
@@ -1494,7 +1631,8 @@ const connectIps = async ({
1494
1631
  translationMeta
1495
1632
  });
1496
1633
  }
1497
- });
1634
+ };
1635
+ remote_sock.on("new-pipe-producer", consumeProducer);
1498
1636
  remote_sock.on("producer-closed", async ({ remoteProducerId }) => {
1499
1637
  if (closedProducerMethod) {
1500
1638
  await closedProducerMethod({ remoteProducerId, parameters });
@@ -1511,6 +1649,11 @@ const connectIps = async ({
1511
1649
  throw new Error(`Consume room ${ip} did not return RTP capabilities.`);
1512
1650
  }
1513
1651
  }
1652
+ const queuedProducers = pendingProducers.splice(0);
1653
+ consumeRoomReady = true;
1654
+ for (const producer of queuedProducers) {
1655
+ await consumeProducer(producer);
1656
+ }
1514
1657
  consume_sockets.push({ [ip]: remote_sock });
1515
1658
  updateConsume_sockets(consume_sockets);
1516
1659
  connected = true;
@@ -1532,7 +1675,12 @@ const connectIps = async ({
1532
1675
  });
1533
1676
  }
1534
1677
  } catch (error) {
1535
- console.log("connectIps error", error);
1678
+ if (isMediaSocketConnectError(error) && !error.retryable) {
1679
+ rememberConsumeEndpointRejection(rejectionOwner, normalizeConsumeEndpoint(ip));
1680
+ console.warn(`connectIps: ${ip} refused this room (${error.reason}); not retrying for ${CONSUME_REJECTION_COOLDOWN_MS / 1e3} s.`, error.message);
1681
+ } else {
1682
+ console.log("connectIps error", error);
1683
+ }
1536
1684
  } finally {
1537
1685
  if (!connected && remote_sock) {
1538
1686
  remote_sock.removeAllListeners?.();
@@ -2231,6 +2379,99 @@ const disconnectSendTransportAudio = async ({
2231
2379
  console.log("Error disconnecting primary audio send transport:", error);
2232
2380
  }
2233
2381
  };
2382
+ const currentScreenAudioProducer = (parameters) => parameters.screenAudioProducer || recallScreenAudioProducer(parameters.socket);
2383
+ const storeScreenAudioProducer = (parameters, producer) => {
2384
+ rememberScreenAudioProducer(parameters.socket, producer);
2385
+ parameters.updateScreenAudioProducer?.(producer);
2386
+ };
2387
+ const disconnectSendTransportScreenAudio = async ({
2388
+ parameters,
2389
+ notifyServer = false
2390
+ }) => {
2391
+ const params = parameters.getUpdatedAllParams ? parameters.getUpdatedAllParams() : parameters;
2392
+ const producer = currentScreenAudioProducer(params);
2393
+ if (!producer) return;
2394
+ try {
2395
+ if (!producer.closed) producer.close();
2396
+ } catch {
2397
+ }
2398
+ storeScreenAudioProducer(params, null);
2399
+ if (notifyServer) {
2400
+ try {
2401
+ params.socket?.emit("closeScreenAudioProducer");
2402
+ } catch {
2403
+ }
2404
+ }
2405
+ };
2406
+ const toggleScreenAudio = ({ parameters, paused }) => {
2407
+ const params = parameters.getUpdatedAllParams ? parameters.getUpdatedAllParams() : parameters;
2408
+ const producer = currentScreenAudioProducer(params);
2409
+ if (!producer || producer.closed) return null;
2410
+ const next = paused ?? !producer.paused;
2411
+ if (next && !producer.paused) producer.pause();
2412
+ if (!next && producer.paused) producer.resume();
2413
+ params.updateScreenAudioProducer?.(producer);
2414
+ return producer.paused;
2415
+ };
2416
+ const produceOnce = async (transport, track) => {
2417
+ const producer = await transport.produce({
2418
+ track,
2419
+ codecOptions: SCREEN_AUDIO_CODEC_OPTIONS,
2420
+ appData: { mediaTag: SCREEN_AUDIO_MEDIA_TAG },
2421
+ // The track belongs to the screen share stream, which stops it with the share.
2422
+ stopTracks: false
2423
+ });
2424
+ if (!producer?.id) {
2425
+ try {
2426
+ producer?.close();
2427
+ } catch {
2428
+ }
2429
+ return null;
2430
+ }
2431
+ return producer;
2432
+ };
2433
+ const connectSendTransportScreenAudio = async ({
2434
+ stream,
2435
+ parameters,
2436
+ retryDelayMs = 600
2437
+ }) => {
2438
+ const params = parameters.getUpdatedAllParams ? parameters.getUpdatedAllParams() : parameters;
2439
+ const track = stream?.getAudioTracks?.()[0];
2440
+ if (!track || track.readyState === "ended") return null;
2441
+ if (!shouldShareScreenAudio(params)) return null;
2442
+ const transport = params.producerTransport;
2443
+ if (!transport || transport.closed) return null;
2444
+ const existing = currentScreenAudioProducer(params);
2445
+ if (existing && !existing.closed) return existing;
2446
+ try {
2447
+ let producer = await produceOnce(transport, track);
2448
+ const trackEnded = () => track.readyState === "ended";
2449
+ if (!producer && retryDelayMs > 0 && !trackEnded()) {
2450
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
2451
+ producer = await produceOnce(transport, track);
2452
+ }
2453
+ if (!producer) return null;
2454
+ storeScreenAudioProducer(params, producer);
2455
+ const screenProducer = params.screenProducer;
2456
+ if (screenProducer?.paused) producer.pause();
2457
+ screenProducer?.observer?.on("pause", () => {
2458
+ if (!producer.closed) producer.pause();
2459
+ });
2460
+ screenProducer?.observer?.on("resume", () => {
2461
+ if (!producer.closed) producer.resume();
2462
+ });
2463
+ screenProducer?.observer?.on("close", () => {
2464
+ void disconnectSendTransportScreenAudio({ parameters: params });
2465
+ });
2466
+ track.addEventListener("ended", () => {
2467
+ void disconnectSendTransportScreenAudio({ parameters: params, notifyServer: true });
2468
+ });
2469
+ return producer;
2470
+ } catch (error) {
2471
+ console.log("connectSendTransportScreenAudio error", error);
2472
+ return null;
2473
+ }
2474
+ };
2234
2475
  const disconnectLocalSendTransportScreen = async ({ parameters }) => {
2235
2476
  try {
2236
2477
  let {
@@ -2252,6 +2493,10 @@ const disconnectLocalSendTransportScreen = async ({ parameters }) => {
2252
2493
  const disconnectSendTransportScreen = async ({ parameters }) => {
2253
2494
  let { getUpdatedAllParams } = parameters;
2254
2495
  parameters = getUpdatedAllParams();
2496
+ try {
2497
+ await disconnectSendTransportScreenAudio({ parameters });
2498
+ } catch {
2499
+ }
2255
2500
  try {
2256
2501
  let {
2257
2502
  screenProducer,
@@ -3653,6 +3898,11 @@ async function startShareScreen({ parameters }) {
3653
3898
  onWeb,
3654
3899
  targetWidth = 1280,
3655
3900
  targetHeight = 720,
3901
+ supportsScreenAudio,
3902
+ screenAudioEnabled,
3903
+ screenAudioMode = "ask",
3904
+ screenAudioPrompt,
3905
+ displayAudioCapable,
3656
3906
  streamSuccessScreen: streamSuccessScreen2
3657
3907
  } = parameters;
3658
3908
  try {
@@ -3665,15 +3915,23 @@ async function startShareScreen({ parameters }) {
3665
3915
  return;
3666
3916
  }
3667
3917
  if (mediaDevices && mediaDevices.getDisplayMedia) {
3918
+ let withAudio = shouldShareScreenAudio({ supportsScreenAudio, screenAudioEnabled, screenAudioMode }) && (displayAudioCapable ?? canCaptureDisplayAudio());
3919
+ if (withAudio && screenAudioMode === "ask" && screenAudioPrompt) {
3920
+ const choice = await screenAudioPrompt();
3921
+ if (choice === null) {
3922
+ updateShared(false);
3923
+ return;
3924
+ }
3925
+ withAudio = choice === "audio";
3926
+ }
3668
3927
  shared = true;
3669
- await mediaDevices.getDisplayMedia({
3670
- video: {
3671
- width: targetWidth,
3672
- height: targetHeight,
3673
- frameRate: 30
3674
- },
3675
- audio: false
3676
- }).then(async (stream) => {
3928
+ await mediaDevices.getDisplayMedia(
3929
+ buildDisplayMediaOptions({
3930
+ targetWidth,
3931
+ targetHeight,
3932
+ withAudio
3933
+ })
3934
+ ).then(async (stream) => {
3677
3935
  await streamSuccessScreen2({ stream, parameters });
3678
3936
  }).catch(async () => {
3679
3937
  shared = false;
@@ -4101,6 +4359,14 @@ const streamSuccessScreen = async ({
4101
4359
  });
4102
4360
  }
4103
4361
  socket.emit("startScreenShare");
4362
+ try {
4363
+ await connectSendTransportScreenAudio({
4364
+ stream: localStreamScreen,
4365
+ parameters: getUpdatedAllParams()
4366
+ });
4367
+ } catch (error) {
4368
+ console.log("Screen audio not shared:", error);
4369
+ }
4104
4370
  } catch (error) {
4105
4371
  showAlert?.({
4106
4372
  message: error.message,
@@ -5372,6 +5638,7 @@ const getPipedProducersAlt = async ({
5372
5638
  } else {
5373
5639
  producerId = producer.id;
5374
5640
  translationMeta = producer.translationMeta || null;
5641
+ markScreenAudioProducer(producerId, producer.mediaTag);
5375
5642
  }
5376
5643
  if (translationMeta) {
5377
5644
  const shouldConsume = shouldConsumeTranslationProducer(
@@ -5591,47 +5858,63 @@ function updateParticipantAudioDecibels({
5591
5858
  updateAudioDecibels(audioDecibels);
5592
5859
  }
5593
5860
  export {
5594
- checkPermission as $,
5861
+ checkGrid as $,
5595
5862
  receiveAllPipedTransports as A,
5596
5863
  reorderStreams as B,
5597
- rePort as C,
5598
- requestScreenShare as D,
5599
- resumePauseAudioStreams as E,
5600
- resumePauseStreams as F,
5601
- reUpdateInter as G,
5602
- signalNewConsumerTransport as H,
5603
- startShareScreen as I,
5604
- stopShareScreen as J,
5605
- streamSuccessAudio as K,
5606
- streamSuccessAudioSwitch as L,
5607
- streamSuccessScreen as M,
5608
- selectVideoProducerCodec as N,
5609
- streamSuccessVideo as O,
5610
- switchUserAudio as P,
5611
- switchUserVideo as Q,
5612
- switchUserVideoAlt as R,
5613
- trigger as S,
5614
- joinConsumeRoom as T,
5615
- newPipeProducer as U,
5616
- producerClosed as V,
5617
- clickVideo as W,
5618
- joinConRoom as X,
5619
- autoAdjust as Y,
5620
- calculateRowsAndColumns as Z,
5621
- checkGrid as _,
5864
+ CONSUME_REJECTION_COOLDOWN_MS as C,
5865
+ rePort as D,
5866
+ requestScreenShare as E,
5867
+ resumePauseAudioStreams as F,
5868
+ resumePauseStreams as G,
5869
+ reUpdateInter as H,
5870
+ signalNewConsumerTransport as I,
5871
+ startShareScreen as J,
5872
+ stopShareScreen as K,
5873
+ streamSuccessAudio as L,
5874
+ streamSuccessAudioSwitch as M,
5875
+ streamSuccessScreen as N,
5876
+ selectVideoProducerCodec as O,
5877
+ streamSuccessVideo as P,
5878
+ switchUserAudio as Q,
5879
+ switchUserVideo as R,
5880
+ switchUserVideoAlt as S,
5881
+ trigger as T,
5882
+ joinConsumeRoom as U,
5883
+ newPipeProducer as V,
5884
+ producerClosed as W,
5885
+ clickVideo as X,
5886
+ joinConRoom as Y,
5887
+ autoAdjust as Z,
5888
+ calculateRowsAndColumns as _,
5622
5889
  changeVids as a,
5623
- controlMedia as a0,
5624
- getEstimate as a1,
5625
- getPipedProducersAlt as a2,
5626
- getProducersPiped as a3,
5627
- receiveRoomMessages as a4,
5628
- resumeSendTransportAudio as a5,
5629
- updateMiniCardsGrid as a6,
5630
- updateParticipantAudioDecibels as a7,
5631
- connectSocket as a8,
5632
- disconnectSocket as a9,
5633
- connectLocalSocket as aa,
5634
- createFrameworkConsumerContractError as ab,
5890
+ checkPermission as a0,
5891
+ controlMedia as a1,
5892
+ getEstimate as a2,
5893
+ getPipedProducersAlt as a3,
5894
+ getProducersPiped as a4,
5895
+ receiveRoomMessages as a5,
5896
+ resumeSendTransportAudio as a6,
5897
+ updateMiniCardsGrid as a7,
5898
+ updateParticipantAudioDecibels as a8,
5899
+ disconnectSendTransportScreenAudio as a9,
5900
+ toggleScreenAudio as aa,
5901
+ connectSendTransportScreenAudio as ab,
5902
+ SCREEN_AUDIO_MEDIA_TAG as ac,
5903
+ SCREEN_AUDIO_CODEC_OPTIONS as ad,
5904
+ markScreenAudioProducer as ae,
5905
+ forgetScreenAudioProducer as af,
5906
+ isScreenAudioProducer as ag,
5907
+ shouldShareScreenAudio as ah,
5908
+ canCaptureDisplayAudio as ai,
5909
+ setScreenAudioPaused as aj,
5910
+ buildDisplayMediaOptions as ak,
5911
+ rememberScreenAudioProducer as al,
5912
+ recallScreenAudioProducer as am,
5913
+ setScreenAudioVolume as an,
5914
+ connectSocket as ao,
5915
+ disconnectSocket as ap,
5916
+ connectLocalSocket as aq,
5917
+ createFrameworkConsumerContractError as ar,
5635
5918
  checkScreenShare as b,
5636
5919
  consumerResume as c,
5637
5920
  closeAndResize as d,
@@ -5658,4 +5941,4 @@ export {
5658
5941
  processConsumerTransportsAudio as y,
5659
5942
  readjust as z
5660
5943
  };
5661
- //# sourceMappingURL=updateParticipantAudioDecibels-DiJ_LFfH.js.map
5944
+ //# sourceMappingURL=updateParticipantAudioDecibels-BBfdHWQ0.js.map