@dxos/plugin-thread 0.8.4-main.28f8d3d → 0.8.4-main.2c6827d
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.
- package/dist/lib/browser/ChannelContainer-JI3ZRZ5S.mjs +17 -0
- package/dist/lib/browser/ChatContainer-6FVFME3R.mjs +16 -0
- package/dist/lib/browser/{app-graph-builder-AF3M7UWN.mjs → app-graph-builder-URVQHGMR.mjs} +32 -32
- package/dist/lib/browser/app-graph-builder-URVQHGMR.mjs.map +7 -0
- package/dist/lib/browser/blueprint-definition-TQ4JFMZZ.mjs +101 -0
- package/dist/lib/browser/blueprint-definition-TQ4JFMZZ.mjs.map +7 -0
- package/dist/lib/browser/{call-manager-XRRCAVLI.mjs → call-manager-4YFT4XA6.mjs} +8 -7
- package/dist/lib/{node-esm/call-manager-EI7FXRAU.mjs.map → browser/call-manager-4YFT4XA6.mjs.map} +1 -1
- package/dist/lib/browser/chunk-6LWKNZUV.mjs +377 -0
- package/dist/lib/browser/chunk-6LWKNZUV.mjs.map +7 -0
- package/dist/lib/browser/chunk-CBUNHCOE.mjs +23 -0
- package/dist/lib/browser/chunk-CBUNHCOE.mjs.map +7 -0
- package/dist/lib/browser/chunk-CFC7LEPD.mjs +18 -0
- package/dist/lib/browser/chunk-CFC7LEPD.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GERVMFQW.mjs → chunk-CP7E2HRE.mjs} +2 -2
- package/dist/lib/browser/chunk-CP7E2HRE.mjs.map +7 -0
- package/dist/lib/browser/{chunk-ZJ7QBXK6.mjs → chunk-F36NHPJG.mjs} +47 -42
- package/dist/lib/browser/chunk-F36NHPJG.mjs.map +7 -0
- package/dist/lib/browser/{chunk-JGKMMI65.mjs → chunk-ISCHODBV.mjs} +54 -4
- package/dist/lib/browser/chunk-ISCHODBV.mjs.map +7 -0
- package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/browser/{chunk-X5PIP5YR.mjs → chunk-KOBXMDCI.mjs} +74 -41
- package/dist/lib/browser/chunk-KOBXMDCI.mjs.map +7 -0
- package/dist/lib/browser/chunk-QM34EZQK.mjs +20 -0
- package/dist/lib/browser/chunk-QM34EZQK.mjs.map +7 -0
- package/dist/lib/browser/chunk-R5UOPOO7.mjs +142 -0
- package/dist/lib/browser/chunk-R5UOPOO7.mjs.map +7 -0
- package/dist/lib/browser/chunk-VIRD2QSK.mjs +611 -0
- package/dist/lib/browser/chunk-VIRD2QSK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-TUFWPOVS.mjs → chunk-ZCW3NSDZ.mjs} +256 -161
- package/dist/lib/browser/chunk-ZCW3NSDZ.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +48 -38
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-DCY4P4OX.mjs → intent-resolver-YR6W4CRP.mjs} +33 -51
- package/dist/lib/browser/intent-resolver-YR6W4CRP.mjs.map +7 -0
- package/dist/lib/browser/{markdown-WZSXCEZJ.mjs → markdown-GSOBOXA7.mjs} +26 -24
- package/dist/lib/browser/markdown-GSOBOXA7.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-root-RAWRPF7Z.mjs +29 -0
- package/dist/lib/browser/react-root-RAWRPF7Z.mjs.map +7 -0
- package/dist/lib/browser/{react-surface-PYAMIADB.mjs → react-surface-GOEFSXQ6.mjs} +38 -36
- package/dist/lib/browser/react-surface-GOEFSXQ6.mjs.map +7 -0
- package/dist/lib/browser/{settings-AC6YSASL.mjs → settings-JN2HHORY.mjs} +6 -5
- package/dist/lib/{node-esm/settings-N52O7MLS.mjs.map → browser/settings-JN2HHORY.mjs.map} +1 -1
- package/dist/lib/browser/{state-2T4KDWBX.mjs → state-UYPLBGZJ.mjs} +6 -5
- package/dist/lib/{node-esm/state-62TQKQVB.mjs.map → browser/state-UYPLBGZJ.mjs.map} +1 -1
- package/dist/lib/browser/types/index.mjs +7 -10
- package/dist/lib/node-esm/ChannelContainer-RQY4PR4F.mjs +18 -0
- package/dist/lib/node-esm/ChatContainer-KWNON7EN.mjs +17 -0
- package/dist/lib/node-esm/ChatContainer-KWNON7EN.mjs.map +7 -0
- package/dist/lib/node-esm/{app-graph-builder-OLSJVCWY.mjs → app-graph-builder-2IH5RPR7.mjs} +32 -32
- package/dist/lib/node-esm/app-graph-builder-2IH5RPR7.mjs.map +7 -0
- package/dist/lib/node-esm/blueprint-definition-TSX5HHW7.mjs +102 -0
- package/dist/lib/node-esm/blueprint-definition-TSX5HHW7.mjs.map +7 -0
- package/dist/lib/node-esm/{call-manager-EI7FXRAU.mjs → call-manager-UMUXEYH5.mjs} +8 -7
- package/dist/lib/{browser/call-manager-XRRCAVLI.mjs.map → node-esm/call-manager-UMUXEYH5.mjs.map} +1 -1
- package/dist/lib/node-esm/chunk-2AEIN5MI.mjs +22 -0
- package/dist/lib/node-esm/chunk-2AEIN5MI.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-4TME3BR4.mjs → chunk-7KZWZS2U.mjs} +256 -161
- package/dist/lib/node-esm/chunk-7KZWZS2U.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-57XR3LEF.mjs → chunk-ABUFOZVX.mjs} +2 -2
- package/dist/lib/node-esm/chunk-ABUFOZVX.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
- package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-I3O6NXMN.mjs +25 -0
- package/dist/lib/node-esm/chunk-I3O6NXMN.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-MEIWWPR2.mjs +143 -0
- package/dist/lib/node-esm/chunk-MEIWWPR2.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-SED3O2XO.mjs → chunk-PZH2EDU5.mjs} +74 -41
- package/dist/lib/node-esm/chunk-PZH2EDU5.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-QFCIKJOD.mjs +612 -0
- package/dist/lib/node-esm/chunk-QFCIKJOD.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-RT6NRL2I.mjs +19 -0
- package/dist/lib/node-esm/chunk-RT6NRL2I.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-QBHKLWGR.mjs → chunk-VBI32FGI.mjs} +54 -4
- package/dist/lib/node-esm/chunk-VBI32FGI.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-YIDU3DXK.mjs → chunk-Y3F2SGNH.mjs} +47 -42
- package/dist/lib/node-esm/chunk-Y3F2SGNH.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-Z4GUSLWL.mjs +378 -0
- package/dist/lib/node-esm/chunk-Z4GUSLWL.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +48 -38
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-QGTPU6QB.mjs → intent-resolver-SJFABEE7.mjs} +33 -51
- package/dist/lib/node-esm/intent-resolver-SJFABEE7.mjs.map +7 -0
- package/dist/lib/node-esm/{markdown-3MZXUGUA.mjs → markdown-GG5566TL.mjs} +26 -24
- package/dist/lib/node-esm/markdown-GG5566TL.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/react-root-K5OGECUS.mjs +30 -0
- package/dist/lib/node-esm/react-root-K5OGECUS.mjs.map +7 -0
- package/dist/lib/node-esm/{react-surface-UJFCSFNO.mjs → react-surface-5QDQD7MN.mjs} +38 -36
- package/dist/lib/node-esm/react-surface-5QDQD7MN.mjs.map +7 -0
- package/dist/lib/node-esm/{settings-N52O7MLS.mjs → settings-VSPM3BIM.mjs} +6 -5
- package/dist/lib/{browser/settings-AC6YSASL.mjs.map → node-esm/settings-VSPM3BIM.mjs.map} +1 -1
- package/dist/lib/node-esm/{state-62TQKQVB.mjs → state-XNWOLBNE.mjs} +6 -5
- package/dist/lib/{browser/state-2T4KDWBX.mjs.map → node-esm/state-XNWOLBNE.mjs.map} +1 -1
- package/dist/lib/node-esm/types/index.mjs +7 -10
- package/dist/types/src/ThreadPlugin.d.ts +1 -1
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/calls/media-manager.d.ts +1 -1
- package/dist/types/src/calls/media-manager.d.ts.map +1 -1
- package/dist/types/src/calls/types.d.ts.map +1 -1
- package/dist/types/src/calls/util/calls-service.d.ts +3 -1
- package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
- package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -1
- package/dist/types/src/calls-service.stories.d.ts +10 -9
- package/dist/types/src/calls-service.stories.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
- package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/call-manager.d.ts +1 -1
- package/dist/types/src/capabilities/capabilities.d.ts +2 -2
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +11 -10
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown.d.ts +1 -1
- package/dist/types/src/capabilities/markdown.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-root.d.ts +2 -2
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/settings.d.ts +1 -1
- package/dist/types/src/capabilities/state.d.ts +2 -2
- package/dist/types/src/components/Call/Toolbar.d.ts +2 -2
- package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/CallDebugPanel.d.ts +7 -0
- package/dist/types/src/components/CallDebugPanel.d.ts.map +1 -1
- package/dist/types/src/components/ChannelContainer.d.ts +2 -2
- package/dist/types/src/components/ChannelContainer.d.ts.map +1 -1
- package/dist/types/src/components/ChannelContainer.stories.d.ts +155 -5
- package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Chat.stories.d.ts +158 -5
- package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatContainer.d.ts +6 -5
- package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
- package/dist/types/src/components/Comments.stories.d.ts +156 -4
- package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/components/CommentsContainer.d.ts +2 -2
- package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
- package/dist/types/src/components/CommentsThreadContainer.d.ts +9 -9
- package/dist/types/src/components/CommentsThreadContainer.d.ts.map +1 -1
- package/dist/types/src/components/Media/VideoObject.d.ts +2 -2
- package/dist/types/src/components/Media/VideoObject.d.ts.map +1 -1
- package/dist/types/src/components/Media/VideoObject.stories.d.ts +18 -4
- package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
- package/dist/types/src/components/MessageContainer.d.ts +6 -3
- package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
- package/dist/types/src/components/Participant/Participant.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +155 -3
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +157 -4
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGridItem.d.ts.map +1 -1
- package/dist/types/src/components/ThreadCompanion.d.ts +5 -0
- package/dist/types/src/components/ThreadCompanion.d.ts.map +1 -0
- package/dist/types/src/components/ThreadSettings.d.ts +1 -1
- package/dist/types/src/components/ThreadSettings.d.ts.map +1 -1
- package/dist/types/src/components/command-extension.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +3 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/components/testing.d.ts +3 -2
- package/dist/types/src/components/testing.d.ts.map +1 -1
- package/dist/types/src/extensions/threads.d.ts.map +1 -1
- package/dist/types/src/functions/create-proposals.d.ts +6 -0
- package/dist/types/src/functions/create-proposals.d.ts.map +1 -0
- package/dist/types/src/functions/index.d.ts +2 -0
- package/dist/types/src/functions/index.d.ts.map +1 -0
- package/dist/types/src/hooks/analytics.d.ts +2 -2
- package/dist/types/src/hooks/analytics.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts +2 -0
- package/dist/types/src/hooks/useBlackCanvasStreamTrack.d.ts.map +1 -0
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts +1 -1
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +1 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/testing/stories.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +75 -7
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Channel.d.ts +16 -0
- package/dist/types/src/types/Channel.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +206 -210
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +65 -59
- package/src/ThreadPlugin.tsx +139 -125
- package/src/calls/call-manager.ts +1 -1
- package/src/calls/media-manager.ts +64 -35
- package/src/calls/types.ts +7 -3
- package/src/calls/util/calls-service.ts +61 -11
- package/src/calls/util/stub-media-streams.ts +62 -5
- package/src/calls-service.stories.tsx +76 -63
- package/src/capabilities/app-graph-builder.ts +43 -30
- package/src/capabilities/blueprint-definition.ts +38 -0
- package/src/capabilities/capabilities.ts +7 -7
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/intent-resolver.ts +23 -30
- package/src/capabilities/markdown.ts +5 -3
- package/src/capabilities/react-root.tsx +2 -2
- package/src/capabilities/react-surface.tsx +25 -23
- package/src/components/Call/Call.tsx +1 -1
- package/src/components/Call/Toolbar.tsx +9 -9
- package/src/components/CallDebugPanel.tsx +112 -55
- package/src/components/CallSidebar.tsx +1 -1
- package/src/components/ChannelContainer.stories.tsx +13 -13
- package/src/components/ChannelContainer.tsx +19 -15
- package/src/components/Chat.stories.tsx +30 -34
- package/src/components/ChatContainer.tsx +32 -21
- package/src/components/Comments.stories.tsx +36 -39
- package/src/components/CommentsContainer.tsx +5 -7
- package/src/components/CommentsThreadContainer.tsx +38 -33
- package/src/components/Lobby/Lobby.tsx +1 -1
- package/src/components/Media/VideoObject.stories.tsx +35 -28
- package/src/components/Media/VideoObject.tsx +1 -1
- package/src/components/MessageContainer.tsx +45 -12
- package/src/components/Participant/Participant.tsx +14 -8
- package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +5 -6
- package/src/components/ResponsiveGrid/ResponsiveContainer.tsx +2 -2
- package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +42 -41
- package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +5 -5
- package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +5 -2
- package/src/components/{ThreadComplementary.tsx → ThreadCompanion.tsx} +72 -35
- package/src/components/ThreadSettings.tsx +6 -7
- package/src/components/command-extension.ts +4 -1
- package/src/components/index.ts +4 -4
- package/src/components/testing.ts +26 -6
- package/src/extensions/threads.ts +26 -17
- package/src/functions/create-proposals.ts +56 -0
- package/src/functions/index.ts +5 -0
- package/src/hooks/analytics.ts +4 -7
- package/src/hooks/index.ts +3 -1
- package/src/hooks/useBlackCanvasStreamTrack.tsx +27 -0
- package/src/hooks/useVideoStreamTrack.tsx +6 -3
- package/src/meta.ts +9 -5
- package/src/testing/stories.ts +3 -6
- package/src/translations.ts +7 -4
- package/src/types/Channel.ts +26 -0
- package/src/types/index.ts +1 -1
- package/src/types/types.ts +27 -28
- package/src/typings/peermetrics-webrtc-stats.d.ts +17 -1
- package/src/util.ts +1 -1
- package/dist/lib/browser/ChannelContainer-O2SFQJU7.mjs +0 -16
- package/dist/lib/browser/ChatContainer-PVT3DUZJ.mjs +0 -15
- package/dist/lib/browser/app-graph-builder-AF3M7UWN.mjs.map +0 -7
- package/dist/lib/browser/chunk-2CWJBXBH.mjs +0 -21
- package/dist/lib/browser/chunk-2CWJBXBH.mjs.map +0 -7
- package/dist/lib/browser/chunk-4APCDRSH.mjs +0 -18
- package/dist/lib/browser/chunk-4APCDRSH.mjs.map +0 -7
- package/dist/lib/browser/chunk-DW7JD64V.mjs +0 -137
- package/dist/lib/browser/chunk-DW7JD64V.mjs.map +0 -7
- package/dist/lib/browser/chunk-EV4JWI7L.mjs +0 -17
- package/dist/lib/browser/chunk-EV4JWI7L.mjs.map +0 -7
- package/dist/lib/browser/chunk-FY4ZRD5X.mjs +0 -367
- package/dist/lib/browser/chunk-FY4ZRD5X.mjs.map +0 -7
- package/dist/lib/browser/chunk-GERVMFQW.mjs.map +0 -7
- package/dist/lib/browser/chunk-J3JO5NWO.mjs +0 -477
- package/dist/lib/browser/chunk-J3JO5NWO.mjs.map +0 -7
- package/dist/lib/browser/chunk-JGKMMI65.mjs.map +0 -7
- package/dist/lib/browser/chunk-TUFWPOVS.mjs.map +0 -7
- package/dist/lib/browser/chunk-X5PIP5YR.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZJ7QBXK6.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-DCY4P4OX.mjs.map +0 -7
- package/dist/lib/browser/markdown-WZSXCEZJ.mjs.map +0 -7
- package/dist/lib/browser/react-root-QXPALOUQ.mjs +0 -28
- package/dist/lib/browser/react-root-QXPALOUQ.mjs.map +0 -7
- package/dist/lib/browser/react-surface-PYAMIADB.mjs.map +0 -7
- package/dist/lib/node-esm/ChannelContainer-B2ZGAE4P.mjs +0 -17
- package/dist/lib/node-esm/ChatContainer-2CT4PJ7I.mjs +0 -16
- package/dist/lib/node-esm/app-graph-builder-OLSJVCWY.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-4TME3BR4.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-57XR3LEF.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-6CRHHOST.mjs +0 -23
- package/dist/lib/node-esm/chunk-6CRHHOST.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-BF4UKS55.mjs +0 -368
- package/dist/lib/node-esm/chunk-BF4UKS55.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-GRLRWTRU.mjs +0 -19
- package/dist/lib/node-esm/chunk-GRLRWTRU.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-PYTVBN5J.mjs +0 -19
- package/dist/lib/node-esm/chunk-PYTVBN5J.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-QBHKLWGR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SED3O2XO.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-VNG6M2IY.mjs +0 -478
- package/dist/lib/node-esm/chunk-VNG6M2IY.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-XVKWHTH4.mjs +0 -138
- package/dist/lib/node-esm/chunk-XVKWHTH4.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YIDU3DXK.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-QGTPU6QB.mjs.map +0 -7
- package/dist/lib/node-esm/markdown-3MZXUGUA.mjs.map +0 -7
- package/dist/lib/node-esm/react-root-7ZFJYVUZ.mjs +0 -29
- package/dist/lib/node-esm/react-root-7ZFJYVUZ.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-UJFCSFNO.mjs.map +0 -7
- package/dist/types/src/components/ThreadComplementary.d.ts +0 -5
- package/dist/types/src/components/ThreadComplementary.d.ts.map +0 -1
- package/dist/types/src/types/schema.d.ts +0 -164
- package/dist/types/src/types/schema.d.ts.map +0 -1
- package/src/types/schema.ts +0 -33
- /package/dist/lib/browser/{ChannelContainer-O2SFQJU7.mjs.map → ChannelContainer-JI3ZRZ5S.mjs.map} +0 -0
- /package/dist/lib/browser/{ChatContainer-PVT3DUZJ.mjs.map → ChatContainer-6FVFME3R.mjs.map} +0 -0
- /package/dist/lib/{node-esm/ChannelContainer-B2ZGAE4P.mjs.map → browser/chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/node-esm/{ChatContainer-2CT4PJ7I.mjs.map → ChannelContainer-RQY4PR4F.mjs.map} +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { DeferredTask, Event, sleep, synchronized } from '@dxos/async';
|
|
6
6
|
import { type Context, Resource, cancelWithContext } from '@dxos/context';
|
|
7
|
+
import { invariant } from '@dxos/invariant';
|
|
7
8
|
import { log } from '@dxos/log';
|
|
8
9
|
|
|
9
10
|
import { SpeakingMonitor } from './speaking-monitor';
|
|
@@ -48,19 +49,23 @@ const VIDEO_WIDTH = 1280;
|
|
|
48
49
|
const VIDEO_HEIGHT = 720;
|
|
49
50
|
const MAX_WEB_CAM_FRAMERATE = 24;
|
|
50
51
|
const MAX_WEB_CAM_BITRATE = 120_0000;
|
|
51
|
-
const RETRY_INTERVAL =
|
|
52
|
+
const RETRY_INTERVAL = 100;
|
|
52
53
|
|
|
53
54
|
export type MediaManagerParams = {
|
|
54
55
|
serviceConfig: CallsServiceConfig;
|
|
55
56
|
};
|
|
56
57
|
|
|
57
|
-
const USE_INAUDIBLE_AUDIO =
|
|
58
|
+
const USE_INAUDIBLE_AUDIO = true;
|
|
58
59
|
|
|
59
60
|
export class MediaManager extends Resource {
|
|
60
61
|
public readonly stateUpdated = new Event<MediaState>();
|
|
61
|
-
private readonly _state: MediaState = { pulledVideoStreams: {}, pulledAudioTracks: {} };
|
|
62
|
-
private _speakingMonitor?: SpeakingMonitor = undefined;
|
|
63
62
|
|
|
63
|
+
private readonly _state: MediaState = {
|
|
64
|
+
pulledVideoStreams: {},
|
|
65
|
+
pulledAudioTracks: {},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
private _speakingMonitor?: SpeakingMonitor = undefined;
|
|
64
69
|
private _trackToReconcile: EncodedTrackName[] = [];
|
|
65
70
|
private _blackCanvasStreamTrack?: MediaStreamTrack = undefined;
|
|
66
71
|
private _inaudibleAudioStreamTrack?: MediaStreamTrack = undefined;
|
|
@@ -84,6 +89,7 @@ export class MediaManager extends Resource {
|
|
|
84
89
|
width: VIDEO_WIDTH,
|
|
85
90
|
height: VIDEO_HEIGHT,
|
|
86
91
|
});
|
|
92
|
+
|
|
87
93
|
this._state.videoTrack = this._blackCanvasStreamTrack;
|
|
88
94
|
this._state.videoStream = new MediaStream();
|
|
89
95
|
this._state.videoStream.addTrack(this._state.videoTrack);
|
|
@@ -136,6 +142,7 @@ export class MediaManager extends Resource {
|
|
|
136
142
|
this._state.videoStream!.removeTrack(this._state.videoTrack!);
|
|
137
143
|
this._state.videoTrack = await getUserMediaTrack('videoinput', { width: VIDEO_WIDTH, height: VIDEO_HEIGHT });
|
|
138
144
|
this._state.videoStream!.addTrack(this._state.videoTrack);
|
|
145
|
+
|
|
139
146
|
this._state.videoEnabled = true;
|
|
140
147
|
this.stateUpdated.emit(this._state);
|
|
141
148
|
this._pushTracksTask!.schedule();
|
|
@@ -225,7 +232,6 @@ export class MediaManager extends Resource {
|
|
|
225
232
|
// Wait for cloudflare to process the track.
|
|
226
233
|
await cancelWithContext(this._ctx, sleep(800));
|
|
227
234
|
const trackNames = this._trackToReconcile;
|
|
228
|
-
|
|
229
235
|
const tracksToPull = trackNames.filter(
|
|
230
236
|
(name) => !this._state.pulledAudioTracks[name] && !this._state.pulledVideoStreams[name],
|
|
231
237
|
);
|
|
@@ -248,7 +254,7 @@ export class MediaManager extends Resource {
|
|
|
248
254
|
});
|
|
249
255
|
|
|
250
256
|
// Pull new tracks.
|
|
251
|
-
await Promise.all(tracksToPull.map((name) => this._pullTrack(name)));
|
|
257
|
+
const pullResults = await Promise.all(tracksToPull.map((name) => this._pullTrack(name)));
|
|
252
258
|
|
|
253
259
|
// Close old tracks.
|
|
254
260
|
await Promise.all([...audioTracksToClose, ...videoStreamsToClose].map(([_, { ctx }]) => ctx.dispose()));
|
|
@@ -257,7 +263,14 @@ export class MediaManager extends Resource {
|
|
|
257
263
|
currentAudioTracks: Object.keys(this._state.pulledAudioTracks),
|
|
258
264
|
currentVideoStreams: Object.keys(this._state.pulledVideoStreams),
|
|
259
265
|
});
|
|
266
|
+
|
|
260
267
|
this.stateUpdated.emit(this._state);
|
|
268
|
+
if (pullResults.some(({ shouldRetry }) => shouldRetry)) {
|
|
269
|
+
await cancelWithContext(this._ctx, sleep(RETRY_INTERVAL));
|
|
270
|
+
log.info('retrying pull tracks', { tracksToPull });
|
|
271
|
+
invariant(this._pullTracksTask);
|
|
272
|
+
this._pullTracksTask.schedule();
|
|
273
|
+
}
|
|
261
274
|
}
|
|
262
275
|
|
|
263
276
|
private async _pushTracks(): Promise<void> {
|
|
@@ -266,38 +279,46 @@ export class MediaManager extends Resource {
|
|
|
266
279
|
}
|
|
267
280
|
|
|
268
281
|
let updated = false;
|
|
269
|
-
const [
|
|
270
|
-
this.
|
|
282
|
+
const [pushVideoResult, pushAudioResult, pushScreenshareResult] = await Promise.all([
|
|
283
|
+
this._maybePushTrack(this._state.videoTrack, this._state.pushedVideoTrack, [
|
|
271
284
|
{ maxFramerate: MAX_WEB_CAM_FRAMERATE, maxBitrate: MAX_WEB_CAM_BITRATE },
|
|
272
285
|
]),
|
|
273
|
-
this.
|
|
274
|
-
this.
|
|
286
|
+
this._maybePushTrack(this._state.audioTrack, this._state.pushedAudioTrack, [{ networkPriority: 'high' }]),
|
|
287
|
+
this._maybePushTrack(this._state.screenshareTrack, this._state.pushedScreenshareTrack),
|
|
275
288
|
]);
|
|
276
289
|
|
|
277
|
-
if (
|
|
278
|
-
this._state.pushedVideoTrack =
|
|
290
|
+
if (pushVideoResult.track !== this._state.pushedVideoTrack) {
|
|
291
|
+
this._state.pushedVideoTrack = pushVideoResult.track;
|
|
279
292
|
updated = true;
|
|
280
293
|
}
|
|
281
|
-
if (
|
|
282
|
-
this._state.pushedAudioTrack =
|
|
294
|
+
if (pushAudioResult.track !== this._state.pushedAudioTrack) {
|
|
295
|
+
this._state.pushedAudioTrack = pushAudioResult.track;
|
|
283
296
|
updated = true;
|
|
284
297
|
}
|
|
285
|
-
if (
|
|
286
|
-
this._state.pushedScreenshareTrack =
|
|
298
|
+
if (pushScreenshareResult.track !== this._state.pushedScreenshareTrack) {
|
|
299
|
+
this._state.pushedScreenshareTrack = pushScreenshareResult.track;
|
|
287
300
|
updated = true;
|
|
288
301
|
}
|
|
289
|
-
|
|
290
|
-
|
|
302
|
+
|
|
303
|
+
const shouldRetry = pushVideoResult.shouldRetry || pushAudioResult.shouldRetry || pushScreenshareResult.shouldRetry;
|
|
304
|
+
if (updated) {
|
|
305
|
+
this.stateUpdated.emit(this._state);
|
|
291
306
|
}
|
|
292
307
|
|
|
293
|
-
|
|
308
|
+
if (shouldRetry) {
|
|
309
|
+
await cancelWithContext(this._ctx, sleep(RETRY_INTERVAL));
|
|
310
|
+
log.info('retrying push tracks', { pushVideoResult, pushAudioResult, pushScreenshareResult });
|
|
311
|
+
invariant(this._pushTracksTask);
|
|
312
|
+
this._pushTracksTask.schedule();
|
|
313
|
+
}
|
|
294
314
|
}
|
|
295
315
|
|
|
296
|
-
private async _pullTrack(name: EncodedTrackName): Promise<
|
|
316
|
+
private async _pullTrack(name: EncodedTrackName): Promise<{ shouldRetry: boolean }> {
|
|
297
317
|
const ctx = this._ctx.derive();
|
|
298
318
|
try {
|
|
299
319
|
const trackData = TrackNameCodec.decode(name);
|
|
300
|
-
|
|
320
|
+
// We need to set mid here to `undefined`, because mid is peer specific.
|
|
321
|
+
const track = await this._state.peer!.pullTrack({ trackData: { ...trackData, mid: undefined }, ctx });
|
|
301
322
|
if (track?.readyState === 'ended') {
|
|
302
323
|
throw new Error('Pulled track ended immediately');
|
|
303
324
|
}
|
|
@@ -306,7 +327,7 @@ export class MediaManager extends Resource {
|
|
|
306
327
|
case 'audio': {
|
|
307
328
|
this._state.pulledAudioTracks[name] = { track, ctx };
|
|
308
329
|
ctx.onDispose(() => delete this._state.pulledAudioTracks[name]);
|
|
309
|
-
|
|
330
|
+
return { shouldRetry: false };
|
|
310
331
|
}
|
|
311
332
|
case 'video': {
|
|
312
333
|
const mediaStream = new MediaStream();
|
|
@@ -317,33 +338,41 @@ export class MediaManager extends Resource {
|
|
|
317
338
|
track.stop();
|
|
318
339
|
delete this._state.pulledVideoStreams[name];
|
|
319
340
|
});
|
|
320
|
-
|
|
341
|
+
return { shouldRetry: false };
|
|
321
342
|
}
|
|
322
343
|
default:
|
|
323
344
|
throw new Error(`Invalid track kind: ${track?.kind}`);
|
|
324
345
|
}
|
|
325
346
|
} catch (err) {
|
|
326
|
-
log.
|
|
347
|
+
log.info('failed to pull track', { err, name });
|
|
327
348
|
void ctx.dispose();
|
|
328
|
-
|
|
329
|
-
log.verbose('retrying pull track', { name });
|
|
330
|
-
this._pullTracksTask!.schedule();
|
|
349
|
+
return { shouldRetry: true };
|
|
331
350
|
}
|
|
332
351
|
}
|
|
333
352
|
|
|
334
|
-
private async
|
|
353
|
+
private async _maybePushTrack(
|
|
335
354
|
track?: MediaStreamTrack,
|
|
336
355
|
previousTrack?: TrackObject,
|
|
337
356
|
encodings?: RTCRtpEncodingParameters[],
|
|
338
|
-
): Promise<TrackObject
|
|
357
|
+
): Promise<{ track?: TrackObject; shouldRetry?: boolean }> {
|
|
339
358
|
if (!track && !previousTrack) {
|
|
340
|
-
return;
|
|
359
|
+
return { track: undefined };
|
|
341
360
|
}
|
|
342
361
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
362
|
+
const ctx = this._ctx.derive();
|
|
363
|
+
try {
|
|
364
|
+
return {
|
|
365
|
+
track: await this._state.peer!.pushTrack({
|
|
366
|
+
ctx,
|
|
367
|
+
track: track ?? null,
|
|
368
|
+
previousTrack,
|
|
369
|
+
encodings,
|
|
370
|
+
}),
|
|
371
|
+
};
|
|
372
|
+
} catch (err) {
|
|
373
|
+
log.info('failed to push track', { err, track, previousTrack, encodings });
|
|
374
|
+
void ctx.dispose();
|
|
375
|
+
return { shouldRetry: true };
|
|
376
|
+
}
|
|
348
377
|
}
|
|
349
378
|
}
|
package/src/calls/types.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { invariant } from '@dxos/invariant';
|
|
5
6
|
import { buf } from '@dxos/protocols/buf';
|
|
6
7
|
import {
|
|
7
8
|
type ActivitySchema,
|
|
@@ -61,10 +62,13 @@ export type EncodedTrackName = string & { __brand: 'EncodedTrackName' };
|
|
|
61
62
|
|
|
62
63
|
export const TrackNameCodec = {
|
|
63
64
|
encode: (trackData: TrackObject): EncodedTrackName => {
|
|
64
|
-
|
|
65
|
+
invariant(trackData.sessionId);
|
|
66
|
+
invariant(trackData.trackName);
|
|
67
|
+
invariant(trackData.mid);
|
|
68
|
+
return (trackData.sessionId + '/' + trackData.trackName + '/' + trackData.mid) as EncodedTrackName;
|
|
65
69
|
},
|
|
66
70
|
decode: (name: EncodedTrackName): TrackObject => {
|
|
67
|
-
const [sessionId, trackName] = name.split('/');
|
|
68
|
-
return { sessionId, trackName, location: 'remote' };
|
|
71
|
+
const [sessionId, trackName, mid] = name.split('/');
|
|
72
|
+
return { sessionId, trackName, location: 'remote', mid };
|
|
69
73
|
},
|
|
70
74
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { PersistentLifecycle } from '@dxos/async';
|
|
5
|
+
import { PersistentLifecycle, Trigger, scheduleTask } from '@dxos/async';
|
|
6
6
|
import { type Context, Resource } from '@dxos/context';
|
|
7
7
|
import { invariant } from '@dxos/invariant';
|
|
8
8
|
import { log } from '@dxos/log';
|
|
@@ -33,12 +33,14 @@ export type CallsServiceConfig = {
|
|
|
33
33
|
|
|
34
34
|
export type HistoryRecord =
|
|
35
35
|
| {
|
|
36
|
+
endpoint: string;
|
|
36
37
|
type: 'request';
|
|
37
38
|
time: string;
|
|
38
39
|
method: string;
|
|
39
40
|
body: any;
|
|
40
41
|
}
|
|
41
42
|
| {
|
|
43
|
+
endpoint: string;
|
|
42
44
|
type: 'response';
|
|
43
45
|
time: string;
|
|
44
46
|
status: number;
|
|
@@ -116,7 +118,7 @@ export class CallsServicePeer extends Resource {
|
|
|
116
118
|
});
|
|
117
119
|
peerConnection.addEventListener('connectionstatechange', () => {
|
|
118
120
|
if (peerConnection.connectionState === 'failed' || peerConnection.connectionState === 'closed') {
|
|
119
|
-
log.
|
|
121
|
+
log.info('calls connection failed', { state: peerConnection.connectionState });
|
|
120
122
|
void this._persistentLifecycle.scheduleRestart();
|
|
121
123
|
}
|
|
122
124
|
});
|
|
@@ -125,7 +127,7 @@ export class CallsServicePeer extends Resource {
|
|
|
125
127
|
peerConnection.addEventListener('iceconnectionstatechange', () => {
|
|
126
128
|
clearTimeout(iceTimeout);
|
|
127
129
|
if (peerConnection.iceConnectionState === 'failed' || peerConnection.iceConnectionState === 'closed') {
|
|
128
|
-
log.
|
|
130
|
+
log.info('calls connection to ICEs failed', { state: peerConnection.iceConnectionState });
|
|
129
131
|
void this._persistentLifecycle.scheduleRestart();
|
|
130
132
|
} else if (peerConnection.iceConnectionState === 'disconnected') {
|
|
131
133
|
// TODO(mykola): we should start to inspect the connection stats from here on for
|
|
@@ -138,7 +140,7 @@ export class CallsServicePeer extends Resource {
|
|
|
138
140
|
return;
|
|
139
141
|
}
|
|
140
142
|
|
|
141
|
-
log.
|
|
143
|
+
log.info('calls iceConnectionState timed out', { state: peerConnection.iceConnectionState, timeoutSeconds });
|
|
142
144
|
void this._persistentLifecycle.scheduleRestart();
|
|
143
145
|
}, timeoutSeconds * 1_000);
|
|
144
146
|
}
|
|
@@ -155,6 +157,7 @@ export class CallsServicePeer extends Resource {
|
|
|
155
157
|
|
|
156
158
|
private async _fetch<T extends ErrorResponse>(relativePath: string, requestInit?: RequestInit): Promise<T> {
|
|
157
159
|
this.history.push({
|
|
160
|
+
endpoint: relativePath,
|
|
158
161
|
type: 'request',
|
|
159
162
|
time: new Date().toISOString(),
|
|
160
163
|
method: requestInit?.method ?? 'GET',
|
|
@@ -170,6 +173,7 @@ export class CallsServicePeer extends Resource {
|
|
|
170
173
|
try {
|
|
171
174
|
const data = (await response.clone().json()) as T;
|
|
172
175
|
this.history.push({
|
|
176
|
+
endpoint: relativePath,
|
|
173
177
|
type: 'response',
|
|
174
178
|
time: new Date().toISOString(),
|
|
175
179
|
status: response.status,
|
|
@@ -183,6 +187,7 @@ export class CallsServicePeer extends Resource {
|
|
|
183
187
|
} catch (error) {
|
|
184
188
|
const text = await response.text();
|
|
185
189
|
this.history.push({
|
|
190
|
+
endpoint: relativePath,
|
|
186
191
|
type: 'response',
|
|
187
192
|
time: new Date().toISOString(),
|
|
188
193
|
status: response.status,
|
|
@@ -204,11 +209,11 @@ export class CallsServicePeer extends Resource {
|
|
|
204
209
|
sessionId,
|
|
205
210
|
trackName,
|
|
206
211
|
}: {
|
|
212
|
+
ctx: Context;
|
|
207
213
|
peerConnection: RTCPeerConnection;
|
|
208
214
|
transceiver: RTCRtpTransceiver;
|
|
209
215
|
sessionId: string;
|
|
210
216
|
trackName: string;
|
|
211
|
-
ctx?: Context;
|
|
212
217
|
}): Promise<TrackObject | void> {
|
|
213
218
|
log.verbose('pushing track ', trackName);
|
|
214
219
|
const pushedTrackPromise = this.pushTrackDispatcher
|
|
@@ -246,9 +251,13 @@ export class CallsServicePeer extends Resource {
|
|
|
246
251
|
};
|
|
247
252
|
}),
|
|
248
253
|
)
|
|
249
|
-
.then(({ tracks }) => {
|
|
254
|
+
.then(async ({ tracks }) => {
|
|
250
255
|
const trackData = tracks.find((t) => t.mid === transceiver.mid);
|
|
251
256
|
if (trackData) {
|
|
257
|
+
// we wait for the transceiver to start sending data before we emit
|
|
258
|
+
// the track metadata to ensure that the track will be able to be
|
|
259
|
+
// pulled before making the metadata available to anyone else.
|
|
260
|
+
// await waitForTransceiverToSendData(ctx, transceiver);
|
|
252
261
|
return {
|
|
253
262
|
...trackData,
|
|
254
263
|
sessionId,
|
|
@@ -257,9 +266,6 @@ export class CallsServicePeer extends Resource {
|
|
|
257
266
|
} else {
|
|
258
267
|
log.error('missing track data');
|
|
259
268
|
}
|
|
260
|
-
})
|
|
261
|
-
.catch((err) => {
|
|
262
|
-
log.catch(err);
|
|
263
269
|
});
|
|
264
270
|
|
|
265
271
|
const onDispose = async () => {
|
|
@@ -281,8 +287,8 @@ export class CallsServicePeer extends Resource {
|
|
|
281
287
|
previousTrack,
|
|
282
288
|
}: {
|
|
283
289
|
track: MediaStreamTrack | null;
|
|
290
|
+
ctx: Context;
|
|
284
291
|
encodings?: RTCRtpEncodingParameters[];
|
|
285
|
-
ctx?: Context;
|
|
286
292
|
previousTrack?: TrackObject;
|
|
287
293
|
}): Promise<TrackObject | undefined> {
|
|
288
294
|
await this.waitUntilOpen();
|
|
@@ -405,7 +411,7 @@ export class CallsServicePeer extends Resource {
|
|
|
405
411
|
})
|
|
406
412
|
.catch((err) => log.catch(err));
|
|
407
413
|
} else {
|
|
408
|
-
log.
|
|
414
|
+
log.info('missing track info', { trackData, availableTracks: Array.from(trackMap.keys()) });
|
|
409
415
|
}
|
|
410
416
|
});
|
|
411
417
|
|
|
@@ -529,3 +535,47 @@ const peerConnectionIsConnected = async (peerConnection: RTCPeerConnection) => {
|
|
|
529
535
|
await connected;
|
|
530
536
|
}
|
|
531
537
|
};
|
|
538
|
+
|
|
539
|
+
const INITIAL_DELAY = 50;
|
|
540
|
+
const MAX_DELAY = 500;
|
|
541
|
+
const MAX_RETRIES = 20;
|
|
542
|
+
const WAIT_FOR_DATA_TIMEOUT = 10_000;
|
|
543
|
+
|
|
544
|
+
const waitForTransceiverToSendData = async (ctx: Context, transceiver: RTCRtpTransceiver): Promise<void> => {
|
|
545
|
+
let delay = INITIAL_DELAY;
|
|
546
|
+
let checks = 0;
|
|
547
|
+
const waitForData = new Trigger();
|
|
548
|
+
ctx.onDispose(() => waitForData.throw(new Error('Transceiver was closed')));
|
|
549
|
+
|
|
550
|
+
const checkStats = async () => {
|
|
551
|
+
if (ctx.disposed) return;
|
|
552
|
+
|
|
553
|
+
try {
|
|
554
|
+
const stats = await transceiver.sender.getStats();
|
|
555
|
+
let dataFound = false;
|
|
556
|
+
stats.forEach((stat) => {
|
|
557
|
+
if (stat.type === 'outbound-rtp' && stat.bytesSent > 0) {
|
|
558
|
+
dataFound = true;
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
if (dataFound) {
|
|
563
|
+
waitForData.wake();
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
} catch {
|
|
567
|
+
// Stats might not be available yet, continue checking
|
|
568
|
+
}
|
|
569
|
+
checks++;
|
|
570
|
+
if (checks > MAX_RETRIES) {
|
|
571
|
+
waitForData.throw(new Error('Transceiver did not send data'));
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
delay = Math.min(delay * 2, MAX_DELAY); // Exponential backoff with max cap
|
|
576
|
+
scheduleTask(ctx, checkStats, delay);
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
void checkStats();
|
|
580
|
+
return waitForData.wait({ timeout: WAIT_FOR_DATA_TIMEOUT });
|
|
581
|
+
};
|
|
@@ -30,7 +30,7 @@ export const createBlackCanvasStreamTrack = async ({
|
|
|
30
30
|
canvasCtx.fillStyle = 'black';
|
|
31
31
|
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
|
|
32
32
|
};
|
|
33
|
-
scheduleTaskInterval(ctx, async () => drawFrame(),
|
|
33
|
+
scheduleTaskInterval(ctx, async () => drawFrame(), 200);
|
|
34
34
|
|
|
35
35
|
const track = canvas.captureStream().getVideoTracks()[0];
|
|
36
36
|
drawFrame();
|
|
@@ -40,27 +40,84 @@ export const createBlackCanvasStreamTrack = async ({
|
|
|
40
40
|
return track;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
let audioContextStartedPreviously = false;
|
|
44
|
+
const userGestureEvents = [
|
|
45
|
+
'click',
|
|
46
|
+
'contextmenu',
|
|
47
|
+
'auxclick',
|
|
48
|
+
'dblclick',
|
|
49
|
+
'mousedown',
|
|
50
|
+
'mouseup',
|
|
51
|
+
'pointerup',
|
|
52
|
+
'touchend',
|
|
53
|
+
'keydown',
|
|
54
|
+
'keyup',
|
|
55
|
+
];
|
|
56
|
+
|
|
43
57
|
/**
|
|
44
58
|
* Creates an inaudible audio stream track.
|
|
45
59
|
* We need this to have audio track available when audio is disabled.
|
|
46
60
|
*/
|
|
47
61
|
export const createInaudibleAudioStreamTrack = async ({ ctx }: { ctx: Context }): Promise<MediaStreamTrack> => {
|
|
48
62
|
const audioContext = new window.AudioContext();
|
|
63
|
+
|
|
49
64
|
const oscillator = audioContext.createOscillator();
|
|
50
65
|
oscillator.type = 'triangle';
|
|
51
|
-
// roughly sounds like a box fan
|
|
52
66
|
oscillator.frequency.setValueAtTime(20, audioContext.currentTime);
|
|
53
67
|
|
|
54
68
|
const gainNode = audioContext.createGain();
|
|
55
|
-
|
|
56
|
-
gainNode.gain.setValueAtTime(0.02, audioContext.currentTime);
|
|
69
|
+
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
|
|
57
70
|
oscillator.connect(gainNode);
|
|
58
71
|
|
|
59
72
|
const destination = audioContext.createMediaStreamDestination();
|
|
60
73
|
gainNode.connect(destination);
|
|
61
|
-
|
|
74
|
+
|
|
75
|
+
let oscillatorStarted = false;
|
|
76
|
+
const ensureOscillatorStarted = () => {
|
|
77
|
+
if (oscillatorStarted) return;
|
|
78
|
+
oscillator.start();
|
|
79
|
+
oscillatorStarted = true;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const stateChangeHandler = () => {
|
|
83
|
+
if (audioContext.state === 'running') {
|
|
84
|
+
audioContextStartedPreviously = true;
|
|
85
|
+
ensureOscillatorStarted();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (audioContext.state === 'suspended' || (audioContext.state as string) === 'interrupted') {
|
|
89
|
+
resumeAudioContext();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
audioContext.addEventListener('statechange', stateChangeHandler);
|
|
94
|
+
|
|
95
|
+
const resumeAudioContext = () => {
|
|
96
|
+
void audioContext.resume().then(() => {
|
|
97
|
+
cleanUpUserGestureListeners();
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const cleanUpUserGestureListeners = () => {
|
|
102
|
+
userGestureEvents.forEach((gesture) => {
|
|
103
|
+
document.removeEventListener(gesture, resumeAudioContext, {
|
|
104
|
+
capture: true,
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
if (audioContextStartedPreviously) {
|
|
110
|
+
resumeAudioContext();
|
|
111
|
+
} else {
|
|
112
|
+
userGestureEvents.forEach((gesture) => {
|
|
113
|
+
document.addEventListener(gesture, resumeAudioContext, {
|
|
114
|
+
capture: true,
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
62
118
|
|
|
63
119
|
ctx.onDispose(async () => {
|
|
120
|
+
cleanUpUserGestureListeners();
|
|
64
121
|
oscillator.disconnect();
|
|
65
122
|
oscillator.stop();
|
|
66
123
|
await audioContext.close();
|