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,6 +1,6 @@
1
1
  "use strict";
2
2
  const io = require("socket.io-client");
3
- const audioProcessing = require("./audioProcessing-BpbrdCk-.cjs");
3
+ const audioProcessing = require("./audioProcessing-VCbu70Jt.cjs");
4
4
  const createFrameworkConsumerContractError = (consumerName) => {
5
5
  return new Error(
6
6
  `${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.`
@@ -507,6 +507,7 @@ const closeAndResize = async ({ producerId, kind, parameters }) => {
507
507
  parameters = getUpdatedAllParams();
508
508
  let {
509
509
  allAudioStreams,
510
+ audioOnlyStreams = [],
510
511
  allVideoStreams,
511
512
  activeNames,
512
513
  participants,
@@ -531,6 +532,7 @@ const closeAndResize = async ({ producerId, kind, parameters }) => {
531
532
  updateMainWindow,
532
533
  updateActiveNames,
533
534
  updateAllAudioStreams,
535
+ updateAudioOnlyStreams,
534
536
  updateAllVideoStreams,
535
537
  updateShareScreenStarted,
536
538
  updateUpdateMainWindow,
@@ -554,6 +556,11 @@ const closeAndResize = async ({ producerId, kind, parameters }) => {
554
556
  return audioStream.producerId !== producerId;
555
557
  });
556
558
  updateAllAudioStreams(allAudioStreams);
559
+ const playerProducerId = (element) => String(element?.props?.remoteProducerId ?? element?.inputs?.remoteProducerId ?? element?.key ?? "");
560
+ if (audioOnlyStreams.some((element) => playerProducerId(element) === producerId)) {
561
+ audioOnlyStreams = audioOnlyStreams.filter((element) => playerProducerId(element) !== producerId);
562
+ updateAudioOnlyStreams?.(audioOnlyStreams);
563
+ }
557
564
  if (recordingDisplayType == "video" && recordingVideoOptimized == true) ;
558
565
  else {
559
566
  participant = participants.find(
@@ -812,12 +819,26 @@ async function connectSocket({ apiUserName, apiKey, apiToken, link }) {
812
819
  }
813
820
  let settled = false;
814
821
  let timeoutHandle;
822
+ const startedAt = Date.now();
823
+ let transportOpened = false;
824
+ let rejection = null;
815
825
  const cleanupHandshake = () => {
816
826
  if (timeoutHandle) clearTimeout(timeoutHandle);
817
827
  socket.off("connection-success", handleConnectionSuccess);
818
828
  socket.off("connect_error", handleConnectError);
819
829
  socket.off("disconnect", handleDisconnectBeforeReady);
830
+ socket.off("connect", handleTransportOpen);
831
+ socket.off("connection-rejected", handleConnectionRejected);
820
832
  };
833
+ const failure = (phase, transportError) => new audioProcessing.MediaSocketConnectError({
834
+ phase: rejection ? "rejected" : phase,
835
+ reason: rejection?.reason,
836
+ stage: rejection?.stage,
837
+ elapsedMs: Date.now() - startedAt,
838
+ online: audioProcessing.currentOnlineState(),
839
+ transportError,
840
+ link
841
+ });
821
842
  const settle = (action) => {
822
843
  if (settled) return;
823
844
  settled = true;
@@ -838,28 +859,40 @@ async function connectSocket({ apiUserName, apiKey, apiToken, link }) {
838
859
  const handleConnectError = (error) => {
839
860
  settle(() => {
840
861
  socket.disconnect();
841
- reject(new Error("Error connecting to media socket: " + error.message));
862
+ reject(failure(transportOpened ? "after-open" : "before-open", error?.message));
863
+ });
864
+ };
865
+ const handleTransportOpen = () => {
866
+ transportOpened = true;
867
+ };
868
+ const handleConnectionRejected = (payload) => {
869
+ rejection = {
870
+ reason: audioProcessing.normalizeRejectionReason(payload?.reason),
871
+ stage: typeof payload?.stage === "string" ? payload.stage : void 0
872
+ };
873
+ settle(() => {
874
+ try {
875
+ socket.disconnect();
876
+ } catch {
877
+ }
878
+ reject(failure("rejected"));
842
879
  });
843
880
  };
844
881
  const handleDisconnectBeforeReady = (reason) => {
845
- settle(
846
- () => reject(
847
- new Error(
848
- "Media socket closed before the room was ready (" + reason + ")."
849
- )
850
- )
851
- );
882
+ settle(() => reject(failure("after-open", reason)));
852
883
  };
853
884
  socket.on("connection-success", handleConnectionSuccess);
854
885
  socket.on("connect_error", handleConnectError);
855
886
  socket.on("disconnect", handleDisconnectBeforeReady);
887
+ socket.on("connect", handleTransportOpen);
888
+ socket.on("connection-rejected", handleConnectionRejected);
856
889
  timeoutHandle = setTimeout(() => {
857
890
  settle(() => {
858
891
  try {
859
892
  socket.disconnect();
860
893
  } catch {
861
894
  }
862
- reject(new Error("Timed out connecting to media socket."));
895
+ reject(failure("timeout"));
863
896
  });
864
897
  }, CONNECT_TIMEOUT_MS);
865
898
  });
@@ -873,11 +906,24 @@ async function connectLocalSocket({ link }) {
873
906
  socket = io(`${link}/media`, {
874
907
  transports: ["websocket"]
875
908
  });
909
+ const startedAt = Date.now();
910
+ let transportOpened = false;
911
+ socket.on("connect", () => {
912
+ transportOpened = true;
913
+ });
876
914
  socket.on("connection-success", (data) => {
877
915
  resolve({ socket, data });
878
916
  });
879
917
  socket.on("connect_error", (error) => {
880
- reject(new Error("Error connecting to media socket: " + error.message));
918
+ reject(
919
+ new audioProcessing.MediaSocketConnectError({
920
+ phase: transportOpened ? "after-open" : "before-open",
921
+ elapsedMs: Date.now() - startedAt,
922
+ online: audioProcessing.currentOnlineState(),
923
+ transportError: error?.message,
924
+ link
925
+ })
926
+ );
881
927
  });
882
928
  });
883
929
  }
@@ -1246,11 +1292,72 @@ const newPipeProducer = async ({
1246
1292
  updateFirst_round(updatedFirstRound);
1247
1293
  }
1248
1294
  };
1295
+ const SCREEN_AUDIO_MEDIA_TAG = "screen-audio";
1296
+ const SCREEN_AUDIO_CODEC_OPTIONS = {
1297
+ opusStereo: true,
1298
+ opusDtx: false,
1299
+ opusFec: true,
1300
+ opusMaxAverageBitrate: 128e3
1301
+ };
1302
+ const screenAudioProducerIds = /* @__PURE__ */ new Set();
1303
+ const markScreenAudioProducer = (producerId, mediaTag) => {
1304
+ if (producerId && mediaTag === SCREEN_AUDIO_MEDIA_TAG) screenAudioProducerIds.add(producerId);
1305
+ };
1306
+ const forgetScreenAudioProducer = (producerId) => {
1307
+ if (producerId) screenAudioProducerIds.delete(producerId);
1308
+ };
1309
+ const isScreenAudioProducer = ({ producerId, participants = [], appData }) => {
1310
+ if (!producerId) return false;
1311
+ if (screenAudioProducerIds.has(producerId)) return true;
1312
+ if (appData?.mediaTag === SCREEN_AUDIO_MEDIA_TAG) return true;
1313
+ return participants.some((participant) => participant?.ScreenAudioID === producerId);
1314
+ };
1315
+ const shouldShareScreenAudio = ({ supportsScreenAudio, screenAudioEnabled, screenAudioMode }) => supportsScreenAudio === true && screenAudioEnabled !== false && screenAudioMode !== "never";
1316
+ const canCaptureDisplayAudio = (nav = typeof navigator !== "undefined" ? navigator : void 0) => {
1317
+ if (!nav) return false;
1318
+ const ua = String(nav.userAgent || "");
1319
+ if (/Mobi|Android|iPhone|iPad|iPod/i.test(ua)) return false;
1320
+ const brands = (nav.userAgentData?.brands || []).map((entry) => String(entry?.brand || ""));
1321
+ if (brands.some((brand) => /Chromium|Google Chrome|Microsoft Edge|Opera|Brave/i.test(brand))) return true;
1322
+ return /(Chrome|Chromium|Edg)\//.test(ua) && !/Firefox|FxiOS|OPiOS/.test(ua);
1323
+ };
1324
+ const setScreenAudioPaused = (producer, paused) => {
1325
+ if (!producer || producer.closed) return false;
1326
+ if (paused && !producer.paused) producer.pause();
1327
+ if (!paused && producer.paused) producer.resume();
1328
+ return producer.paused;
1329
+ };
1330
+ const buildDisplayMediaOptions = ({ targetWidth, targetHeight, withAudio }) => {
1331
+ const options = {
1332
+ video: { width: targetWidth, height: targetHeight, frameRate: 30 },
1333
+ audio: withAudio ? { echoCancellation: false, noiseSuppression: false, autoGainControl: false } : false
1334
+ };
1335
+ if (withAudio) {
1336
+ options.systemAudio = "include";
1337
+ options.suppressLocalAudioPlayback = false;
1338
+ }
1339
+ return options;
1340
+ };
1341
+ const producersBySocket = /* @__PURE__ */ new WeakMap();
1342
+ const rememberScreenAudioProducer = (socket, producer) => {
1343
+ if (!socket) return;
1344
+ if (producer) producersBySocket.set(socket, producer);
1345
+ else producersBySocket.delete(socket);
1346
+ };
1347
+ const recallScreenAudioProducer = (socket) => socket && producersBySocket.get(socket) || null;
1348
+ const setScreenAudioVolume = (volume, root = typeof document !== "undefined" ? document : null) => {
1349
+ if (!root) return;
1350
+ const value = Math.min(1, Math.max(0, Number.isFinite(volume) ? volume : 1));
1351
+ root.querySelectorAll('audio[data-screen-audio="true"]').forEach((element) => {
1352
+ element.volume = value;
1353
+ });
1354
+ };
1249
1355
  const producerClosed = async ({
1250
1356
  remoteProducerId,
1251
1357
  parameters
1252
1358
  }) => {
1253
1359
  let { consumerTransports, closeAndResize: closeAndResize2, screenId, updateConsumerTransports } = parameters;
1360
+ forgetScreenAudioProducer(remoteProducerId);
1254
1361
  const activeTranslationProducerIds = parameters.activeTranslationProducerIds;
1255
1362
  const isTranslationProducer = activeTranslationProducerIds?.has?.(remoteProducerId);
1256
1363
  if (isTranslationProducer) {
@@ -1401,6 +1508,20 @@ const joinConsumeRoom = async ({
1401
1508
  };
1402
1509
  const pendingConsumeConnections = /* @__PURE__ */ new WeakMap();
1403
1510
  const normalizeConsumeEndpoint = (ip) => ip.trim().toLowerCase().replace(/\.$/, "");
1511
+ const CONSUME_REJECTION_COOLDOWN_MS = 6e4;
1512
+ const rejectedConsumeEndpoints = /* @__PURE__ */ new WeakMap();
1513
+ const consumeEndpointRecentlyRejected = (owner, endpoint) => {
1514
+ const at = rejectedConsumeEndpoints.get(owner)?.get(endpoint);
1515
+ return at !== void 0 && Date.now() - at < CONSUME_REJECTION_COOLDOWN_MS;
1516
+ };
1517
+ const rememberConsumeEndpointRejection = (owner, endpoint) => {
1518
+ let byEndpoint = rejectedConsumeEndpoints.get(owner);
1519
+ if (!byEndpoint) {
1520
+ byEndpoint = /* @__PURE__ */ new Map();
1521
+ rejectedConsumeEndpoints.set(owner, byEndpoint);
1522
+ }
1523
+ byEndpoint.set(endpoint, Date.now());
1524
+ };
1404
1525
  const hasConsumeEndpoint = (consumeSockets, endpoint) => {
1405
1526
  for (let index = consumeSockets.length - 1; index >= 0; index -= 1) {
1406
1527
  const socketObj = consumeSockets[index];
@@ -1468,7 +1589,9 @@ const connectIps = async ({
1468
1589
  });
1469
1590
  return [consume_sockets, roomRecvIPs];
1470
1591
  }
1592
+ const rejectionOwner = parameters?.socket || consume_sockets;
1471
1593
  for (const ip of remIP) {
1594
+ if (consumeEndpointRecentlyRejected(rejectionOwner, normalizeConsumeEndpoint(ip))) continue;
1472
1595
  const releaseReservation = await reserveConsumeEndpoint(
1473
1596
  consume_sockets,
1474
1597
  ip,
@@ -1480,11 +1603,25 @@ const connectIps = async ({
1480
1603
  try {
1481
1604
  remote_sock = await connectSocket({ apiUserName, apiKey, apiToken, link: `https://${ip}.mediasfu.com` });
1482
1605
  if (remote_sock.id) {
1606
+ let consumeRoomReady = false;
1607
+ const pendingProducers = [];
1483
1608
  if (!roomRecvIPs.includes(ip)) {
1484
1609
  roomRecvIPs.push(ip);
1485
1610
  updateRoomRecvIPs(roomRecvIPs);
1486
1611
  }
1487
- remote_sock.on("new-pipe-producer", async ({ producerId, islevel, isTranslation, translationMeta }) => {
1612
+ const consumeProducer = async ({ producerId, islevel, isTranslation, translationMeta, mediaTag }) => {
1613
+ markScreenAudioProducer(producerId, mediaTag);
1614
+ if (!consumeRoomReady) {
1615
+ pendingProducers.push({ producerId, islevel, isTranslation, translationMeta });
1616
+ return;
1617
+ }
1618
+ const preferDelay = isTranslation ? 0 : audioProcessing.consumerBackupPreferDelay(
1619
+ ip,
1620
+ parameters.getUpdatedAllParams?.()?.consume_sockets
1621
+ );
1622
+ if (preferDelay > 0) {
1623
+ await new Promise((resolve) => setTimeout(resolve, preferDelay));
1624
+ }
1488
1625
  if (newProducerMethod) {
1489
1626
  await newProducerMethod({
1490
1627
  producerId,
@@ -1495,7 +1632,8 @@ const connectIps = async ({
1495
1632
  translationMeta
1496
1633
  });
1497
1634
  }
1498
- });
1635
+ };
1636
+ remote_sock.on("new-pipe-producer", consumeProducer);
1499
1637
  remote_sock.on("producer-closed", async ({ remoteProducerId }) => {
1500
1638
  if (closedProducerMethod) {
1501
1639
  await closedProducerMethod({ remoteProducerId, parameters });
@@ -1512,6 +1650,11 @@ const connectIps = async ({
1512
1650
  throw new Error(`Consume room ${ip} did not return RTP capabilities.`);
1513
1651
  }
1514
1652
  }
1653
+ const queuedProducers = pendingProducers.splice(0);
1654
+ consumeRoomReady = true;
1655
+ for (const producer of queuedProducers) {
1656
+ await consumeProducer(producer);
1657
+ }
1515
1658
  consume_sockets.push({ [ip]: remote_sock });
1516
1659
  updateConsume_sockets(consume_sockets);
1517
1660
  connected = true;
@@ -1533,7 +1676,12 @@ const connectIps = async ({
1533
1676
  });
1534
1677
  }
1535
1678
  } catch (error) {
1536
- console.log("connectIps error", error);
1679
+ if (audioProcessing.isMediaSocketConnectError(error) && !error.retryable) {
1680
+ rememberConsumeEndpointRejection(rejectionOwner, normalizeConsumeEndpoint(ip));
1681
+ console.warn(`connectIps: ${ip} refused this room (${error.reason}); not retrying for ${CONSUME_REJECTION_COOLDOWN_MS / 1e3} s.`, error.message);
1682
+ } else {
1683
+ console.log("connectIps error", error);
1684
+ }
1537
1685
  } finally {
1538
1686
  if (!connected && remote_sock) {
1539
1687
  remote_sock.removeAllListeners?.();
@@ -2232,6 +2380,99 @@ const disconnectSendTransportAudio = async ({
2232
2380
  console.log("Error disconnecting primary audio send transport:", error);
2233
2381
  }
2234
2382
  };
2383
+ const currentScreenAudioProducer = (parameters) => parameters.screenAudioProducer || recallScreenAudioProducer(parameters.socket);
2384
+ const storeScreenAudioProducer = (parameters, producer) => {
2385
+ rememberScreenAudioProducer(parameters.socket, producer);
2386
+ parameters.updateScreenAudioProducer?.(producer);
2387
+ };
2388
+ const disconnectSendTransportScreenAudio = async ({
2389
+ parameters,
2390
+ notifyServer = false
2391
+ }) => {
2392
+ const params = parameters.getUpdatedAllParams ? parameters.getUpdatedAllParams() : parameters;
2393
+ const producer = currentScreenAudioProducer(params);
2394
+ if (!producer) return;
2395
+ try {
2396
+ if (!producer.closed) producer.close();
2397
+ } catch {
2398
+ }
2399
+ storeScreenAudioProducer(params, null);
2400
+ if (notifyServer) {
2401
+ try {
2402
+ params.socket?.emit("closeScreenAudioProducer");
2403
+ } catch {
2404
+ }
2405
+ }
2406
+ };
2407
+ const toggleScreenAudio = ({ parameters, paused }) => {
2408
+ const params = parameters.getUpdatedAllParams ? parameters.getUpdatedAllParams() : parameters;
2409
+ const producer = currentScreenAudioProducer(params);
2410
+ if (!producer || producer.closed) return null;
2411
+ const next = paused ?? !producer.paused;
2412
+ if (next && !producer.paused) producer.pause();
2413
+ if (!next && producer.paused) producer.resume();
2414
+ params.updateScreenAudioProducer?.(producer);
2415
+ return producer.paused;
2416
+ };
2417
+ const produceOnce = async (transport, track) => {
2418
+ const producer = await transport.produce({
2419
+ track,
2420
+ codecOptions: SCREEN_AUDIO_CODEC_OPTIONS,
2421
+ appData: { mediaTag: SCREEN_AUDIO_MEDIA_TAG },
2422
+ // The track belongs to the screen share stream, which stops it with the share.
2423
+ stopTracks: false
2424
+ });
2425
+ if (!producer?.id) {
2426
+ try {
2427
+ producer?.close();
2428
+ } catch {
2429
+ }
2430
+ return null;
2431
+ }
2432
+ return producer;
2433
+ };
2434
+ const connectSendTransportScreenAudio = async ({
2435
+ stream,
2436
+ parameters,
2437
+ retryDelayMs = 600
2438
+ }) => {
2439
+ const params = parameters.getUpdatedAllParams ? parameters.getUpdatedAllParams() : parameters;
2440
+ const track = stream?.getAudioTracks?.()[0];
2441
+ if (!track || track.readyState === "ended") return null;
2442
+ if (!shouldShareScreenAudio(params)) return null;
2443
+ const transport = params.producerTransport;
2444
+ if (!transport || transport.closed) return null;
2445
+ const existing = currentScreenAudioProducer(params);
2446
+ if (existing && !existing.closed) return existing;
2447
+ try {
2448
+ let producer = await produceOnce(transport, track);
2449
+ const trackEnded = () => track.readyState === "ended";
2450
+ if (!producer && retryDelayMs > 0 && !trackEnded()) {
2451
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
2452
+ producer = await produceOnce(transport, track);
2453
+ }
2454
+ if (!producer) return null;
2455
+ storeScreenAudioProducer(params, producer);
2456
+ const screenProducer = params.screenProducer;
2457
+ if (screenProducer?.paused) producer.pause();
2458
+ screenProducer?.observer?.on("pause", () => {
2459
+ if (!producer.closed) producer.pause();
2460
+ });
2461
+ screenProducer?.observer?.on("resume", () => {
2462
+ if (!producer.closed) producer.resume();
2463
+ });
2464
+ screenProducer?.observer?.on("close", () => {
2465
+ void disconnectSendTransportScreenAudio({ parameters: params });
2466
+ });
2467
+ track.addEventListener("ended", () => {
2468
+ void disconnectSendTransportScreenAudio({ parameters: params, notifyServer: true });
2469
+ });
2470
+ return producer;
2471
+ } catch (error) {
2472
+ console.log("connectSendTransportScreenAudio error", error);
2473
+ return null;
2474
+ }
2475
+ };
2235
2476
  const disconnectLocalSendTransportScreen = async ({ parameters }) => {
2236
2477
  try {
2237
2478
  let {
@@ -2253,6 +2494,10 @@ const disconnectLocalSendTransportScreen = async ({ parameters }) => {
2253
2494
  const disconnectSendTransportScreen = async ({ parameters }) => {
2254
2495
  let { getUpdatedAllParams } = parameters;
2255
2496
  parameters = getUpdatedAllParams();
2497
+ try {
2498
+ await disconnectSendTransportScreenAudio({ parameters });
2499
+ } catch {
2500
+ }
2256
2501
  try {
2257
2502
  let {
2258
2503
  screenProducer,
@@ -3654,6 +3899,11 @@ async function startShareScreen({ parameters }) {
3654
3899
  onWeb,
3655
3900
  targetWidth = 1280,
3656
3901
  targetHeight = 720,
3902
+ supportsScreenAudio,
3903
+ screenAudioEnabled,
3904
+ screenAudioMode = "ask",
3905
+ screenAudioPrompt,
3906
+ displayAudioCapable,
3657
3907
  streamSuccessScreen: streamSuccessScreen2
3658
3908
  } = parameters;
3659
3909
  try {
@@ -3666,15 +3916,23 @@ async function startShareScreen({ parameters }) {
3666
3916
  return;
3667
3917
  }
3668
3918
  if (mediaDevices && mediaDevices.getDisplayMedia) {
3919
+ let withAudio = shouldShareScreenAudio({ supportsScreenAudio, screenAudioEnabled, screenAudioMode }) && (displayAudioCapable ?? canCaptureDisplayAudio());
3920
+ if (withAudio && screenAudioMode === "ask" && screenAudioPrompt) {
3921
+ const choice = await screenAudioPrompt();
3922
+ if (choice === null) {
3923
+ updateShared(false);
3924
+ return;
3925
+ }
3926
+ withAudio = choice === "audio";
3927
+ }
3669
3928
  shared = true;
3670
- await mediaDevices.getDisplayMedia({
3671
- video: {
3672
- width: targetWidth,
3673
- height: targetHeight,
3674
- frameRate: 30
3675
- },
3676
- audio: false
3677
- }).then(async (stream) => {
3929
+ await mediaDevices.getDisplayMedia(
3930
+ buildDisplayMediaOptions({
3931
+ targetWidth,
3932
+ targetHeight,
3933
+ withAudio
3934
+ })
3935
+ ).then(async (stream) => {
3678
3936
  await streamSuccessScreen2({ stream, parameters });
3679
3937
  }).catch(async () => {
3680
3938
  shared = false;
@@ -4102,6 +4360,14 @@ const streamSuccessScreen = async ({
4102
4360
  });
4103
4361
  }
4104
4362
  socket.emit("startScreenShare");
4363
+ try {
4364
+ await connectSendTransportScreenAudio({
4365
+ stream: localStreamScreen,
4366
+ parameters: getUpdatedAllParams()
4367
+ });
4368
+ } catch (error) {
4369
+ console.log("Screen audio not shared:", error);
4370
+ }
4105
4371
  } catch (error) {
4106
4372
  showAlert?.({
4107
4373
  message: error.message,
@@ -5373,6 +5639,7 @@ const getPipedProducersAlt = async ({
5373
5639
  } else {
5374
5640
  producerId = producer.id;
5375
5641
  translationMeta = producer.translationMeta || null;
5642
+ markScreenAudioProducer(producerId, producer.mediaTag);
5376
5643
  }
5377
5644
  if (translationMeta) {
5378
5645
  const shouldConsume = shouldConsumeTranslationProducer(
@@ -5591,8 +5858,13 @@ function updateParticipantAudioDecibels({
5591
5858
  }
5592
5859
  updateAudioDecibels(audioDecibels);
5593
5860
  }
5861
+ exports.CONSUME_REJECTION_COOLDOWN_MS = CONSUME_REJECTION_COOLDOWN_MS;
5862
+ exports.SCREEN_AUDIO_CODEC_OPTIONS = SCREEN_AUDIO_CODEC_OPTIONS;
5863
+ exports.SCREEN_AUDIO_MEDIA_TAG = SCREEN_AUDIO_MEDIA_TAG;
5594
5864
  exports.autoAdjust = autoAdjust;
5865
+ exports.buildDisplayMediaOptions = buildDisplayMediaOptions;
5595
5866
  exports.calculateRowsAndColumns = calculateRowsAndColumns;
5867
+ exports.canCaptureDisplayAudio = canCaptureDisplayAudio;
5596
5868
  exports.changeVids = changeVids;
5597
5869
  exports.checkGrid = checkGrid;
5598
5870
  exports.checkPermission = checkPermission;
@@ -5608,6 +5880,7 @@ exports.connectRecvTransport = connectRecvTransport;
5608
5880
  exports.connectSendTransport = connectSendTransport;
5609
5881
  exports.connectSendTransportAudio = connectSendTransportAudio;
5610
5882
  exports.connectSendTransportScreen = connectSendTransportScreen;
5883
+ exports.connectSendTransportScreenAudio = connectSendTransportScreenAudio;
5611
5884
  exports.connectSendTransportVideo = connectSendTransportVideo;
5612
5885
  exports.connectSocket = connectSocket;
5613
5886
  exports.consumerResume = consumerResume;
@@ -5616,16 +5889,20 @@ exports.createFrameworkConsumerContractError = createFrameworkConsumerContractEr
5616
5889
  exports.createSendTransport = createSendTransport;
5617
5890
  exports.disconnectSendTransportAudio = disconnectSendTransportAudio;
5618
5891
  exports.disconnectSendTransportScreen = disconnectSendTransportScreen;
5892
+ exports.disconnectSendTransportScreenAudio = disconnectSendTransportScreenAudio;
5619
5893
  exports.disconnectSendTransportVideo = disconnectSendTransportVideo;
5620
5894
  exports.disconnectSocket = disconnectSocket;
5621
5895
  exports.dispStreams = dispStreams;
5896
+ exports.forgetScreenAudioProducer = forgetScreenAudioProducer;
5622
5897
  exports.generatePageContent = generatePageContent;
5623
5898
  exports.getEstimate = getEstimate;
5624
5899
  exports.getPipedProducersAlt = getPipedProducersAlt;
5625
5900
  exports.getProducersPiped = getProducersPiped;
5626
5901
  exports.getVideos = getVideos;
5902
+ exports.isScreenAudioProducer = isScreenAudioProducer;
5627
5903
  exports.joinConRoom = joinConRoom;
5628
5904
  exports.joinConsumeRoom = joinConsumeRoom;
5905
+ exports.markScreenAudioProducer = markScreenAudioProducer;
5629
5906
  exports.mixStreams = mixStreams;
5630
5907
  exports.newPipeProducer = newPipeProducer;
5631
5908
  exports.onScreenChanges = onScreenChanges;
@@ -5635,14 +5912,19 @@ exports.producerClosed = producerClosed;
5635
5912
  exports.rePort = rePort;
5636
5913
  exports.reUpdateInter = reUpdateInter;
5637
5914
  exports.readjust = readjust;
5915
+ exports.recallScreenAudioProducer = recallScreenAudioProducer;
5638
5916
  exports.receiveAllPipedTransports = receiveAllPipedTransports;
5639
5917
  exports.receiveRoomMessages = receiveRoomMessages;
5918
+ exports.rememberScreenAudioProducer = rememberScreenAudioProducer;
5640
5919
  exports.reorderStreams = reorderStreams;
5641
5920
  exports.requestScreenShare = requestScreenShare;
5642
5921
  exports.resumePauseAudioStreams = resumePauseAudioStreams;
5643
5922
  exports.resumePauseStreams = resumePauseStreams;
5644
5923
  exports.resumeSendTransportAudio = resumeSendTransportAudio;
5645
5924
  exports.selectVideoProducerCodec = selectVideoProducerCodec;
5925
+ exports.setScreenAudioPaused = setScreenAudioPaused;
5926
+ exports.setScreenAudioVolume = setScreenAudioVolume;
5927
+ exports.shouldShareScreenAudio = shouldShareScreenAudio;
5646
5928
  exports.signalNewConsumerTransport = signalNewConsumerTransport;
5647
5929
  exports.startShareScreen = startShareScreen;
5648
5930
  exports.stopShareScreen = stopShareScreen;
@@ -5653,8 +5935,9 @@ exports.streamSuccessVideo = streamSuccessVideo;
5653
5935
  exports.switchUserAudio = switchUserAudio;
5654
5936
  exports.switchUserVideo = switchUserVideo;
5655
5937
  exports.switchUserVideoAlt = switchUserVideoAlt;
5938
+ exports.toggleScreenAudio = toggleScreenAudio;
5656
5939
  exports.trigger = trigger;
5657
5940
  exports.updateMicLevel = updateMicLevel;
5658
5941
  exports.updateMiniCardsGrid = updateMiniCardsGrid;
5659
5942
  exports.updateParticipantAudioDecibels = updateParticipantAudioDecibels;
5660
- //# sourceMappingURL=updateParticipantAudioDecibels-BJ2PxJJD.cjs.map
5943
+ //# sourceMappingURL=updateParticipantAudioDecibels-Dni8i6AY.cjs.map