@dxos/plugin-thread 0.8.4-main.9735255 → 0.8.4-main.9be5663bfe
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/add-message-A33GVGQX.mjs +97 -0
- package/dist/lib/browser/add-message-A33GVGQX.mjs.map +7 -0
- package/dist/lib/browser/blueprints/index.mjs +33 -4
- package/dist/lib/browser/blueprints/index.mjs.map +4 -4
- package/dist/lib/browser/chunk-2QNKWX4H.mjs +259 -0
- package/dist/lib/browser/chunk-2QNKWX4H.mjs.map +7 -0
- package/dist/lib/browser/chunk-7T7J6ZR6.mjs +61 -0
- package/dist/lib/browser/chunk-7T7J6ZR6.mjs.map +7 -0
- package/dist/lib/browser/create-N2ZVTONJ.mjs +55 -0
- package/dist/lib/browser/create-N2ZVTONJ.mjs.map +7 -0
- package/dist/lib/browser/create-channel-Y4H3535D.mjs +21 -0
- package/dist/lib/browser/create-channel-Y4H3535D.mjs.map +7 -0
- package/dist/lib/browser/create-channel-thread-6N7TKEAW.mjs +28 -0
- package/dist/lib/browser/create-channel-thread-6N7TKEAW.mjs.map +7 -0
- package/dist/lib/browser/create-proposals-VTOSWUOX.mjs +57 -0
- package/dist/lib/browser/create-proposals-VTOSWUOX.mjs.map +7 -0
- package/dist/lib/browser/delete-QZZE655Y.mjs +59 -0
- package/dist/lib/browser/delete-QZZE655Y.mjs.map +7 -0
- package/dist/lib/browser/delete-message-WQAZLYBO.mjs +64 -0
- package/dist/lib/browser/delete-message-WQAZLYBO.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +2225 -211
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/on-create-space-2UGS234J.mjs +25 -0
- package/dist/lib/browser/on-create-space-2UGS234J.mjs.map +7 -0
- package/dist/lib/browser/operations/index.mjs +14 -0
- package/dist/lib/browser/operations/index.mjs.map +7 -0
- package/dist/lib/browser/restore-KKQHFLYO.mjs +33 -0
- package/dist/lib/browser/restore-KKQHFLYO.mjs.map +7 -0
- package/dist/lib/browser/restore-message-VOP2UE7N.mjs +42 -0
- package/dist/lib/browser/restore-message-VOP2UE7N.mjs.map +7 -0
- package/dist/lib/browser/select-VBJ3MBLN.mjs +26 -0
- package/dist/lib/browser/select-VBJ3MBLN.mjs.map +7 -0
- package/dist/lib/browser/toggle-resolved-GIYF3KWJ.mjs +45 -0
- package/dist/lib/browser/toggle-resolved-GIYF3KWJ.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +5 -7
- package/dist/lib/node-esm/add-message-E6XC6E3Z.mjs +98 -0
- package/dist/lib/node-esm/add-message-E6XC6E3Z.mjs.map +7 -0
- package/dist/lib/node-esm/blueprints/index.mjs +33 -4
- package/dist/lib/node-esm/blueprints/index.mjs.map +4 -4
- package/dist/lib/node-esm/chunk-I6LAZYVU.mjs +260 -0
- package/dist/lib/node-esm/chunk-I6LAZYVU.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-UGSMYQLZ.mjs +62 -0
- package/dist/lib/node-esm/chunk-UGSMYQLZ.mjs.map +7 -0
- package/dist/lib/node-esm/create-A6XQZR7M.mjs +56 -0
- package/dist/lib/node-esm/create-A6XQZR7M.mjs.map +7 -0
- package/dist/lib/node-esm/create-channel-KA5T23ZS.mjs +22 -0
- package/dist/lib/node-esm/create-channel-KA5T23ZS.mjs.map +7 -0
- package/dist/lib/node-esm/create-channel-thread-44PXAPGM.mjs +29 -0
- package/dist/lib/node-esm/create-channel-thread-44PXAPGM.mjs.map +7 -0
- package/dist/lib/node-esm/create-proposals-HDBVDNUX.mjs +58 -0
- package/dist/lib/node-esm/create-proposals-HDBVDNUX.mjs.map +7 -0
- package/dist/lib/node-esm/delete-3RAWD5GG.mjs +60 -0
- package/dist/lib/node-esm/delete-3RAWD5GG.mjs.map +7 -0
- package/dist/lib/node-esm/delete-message-W4XFE4KW.mjs +65 -0
- package/dist/lib/node-esm/delete-message-W4XFE4KW.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +2225 -211
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/on-create-space-ZURB6UKR.mjs +26 -0
- package/dist/lib/node-esm/on-create-space-ZURB6UKR.mjs.map +7 -0
- package/dist/lib/node-esm/operations/index.mjs +15 -0
- package/dist/lib/node-esm/operations/index.mjs.map +7 -0
- package/dist/lib/node-esm/restore-PDYEKDE3.mjs +34 -0
- package/dist/lib/node-esm/restore-PDYEKDE3.mjs.map +7 -0
- package/dist/lib/node-esm/restore-message-O5XC34MW.mjs +43 -0
- package/dist/lib/node-esm/restore-message-O5XC34MW.mjs.map +7 -0
- package/dist/lib/node-esm/select-6KETLVWY.mjs +27 -0
- package/dist/lib/node-esm/select-6KETLVWY.mjs.map +7 -0
- package/dist/lib/node-esm/toggle-resolved-QR3SOXR7.mjs +46 -0
- package/dist/lib/node-esm/toggle-resolved-QR3SOXR7.mjs.map +7 -0
- package/dist/lib/node-esm/types/index.mjs +5 -7
- package/dist/types/src/ThreadPlugin.d.ts.map +1 -1
- package/dist/types/src/blueprints/index.d.ts +1 -1
- package/dist/types/src/blueprints/index.d.ts.map +1 -1
- package/dist/types/src/blueprints/thread-blueprint.d.ts +3 -20
- package/dist/types/src/blueprints/thread-blueprint.d.ts.map +1 -1
- package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
- package/dist/types/src/calls-service.stories.d.ts +2 -2
- package/dist/types/src/calls-service.stories.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts +6 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/call-manager.d.ts +6 -0
- package/dist/types/src/capabilities/call-manager.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +15 -10
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown.d.ts +5 -0
- package/dist/types/src/capabilities/markdown.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/{react-root/react-root.d.ts → react-root.d.ts} +1 -1
- package/dist/types/src/capabilities/react-root.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +5 -0
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
- package/dist/types/src/capabilities/settings.d.ts +6 -0
- package/dist/types/src/capabilities/settings.d.ts.map +1 -0
- package/dist/types/src/capabilities/state.d.ts +7 -0
- package/dist/types/src/capabilities/state.d.ts.map +1 -0
- package/dist/types/src/capabilities/undo-mappings.d.ts +5 -0
- package/dist/types/src/capabilities/undo-mappings.d.ts.map +1 -0
- package/dist/types/src/components/Call/Toolbar.d.ts +1 -1
- package/dist/types/src/components/Call/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/CommentsPanel/CommentsPanel.d.ts +13 -0
- package/dist/types/src/components/CommentsPanel/CommentsPanel.d.ts.map +1 -0
- package/dist/types/src/components/CommentsPanel/CommentsPanel.stories.d.ts +160 -0
- package/dist/types/src/components/CommentsPanel/CommentsPanel.stories.d.ts.map +1 -0
- package/dist/types/src/components/{CommentsThreadContainer.d.ts → CommentsPanel/CommentsThread.d.ts} +3 -3
- package/dist/types/src/components/CommentsPanel/CommentsThread.d.ts.map +1 -0
- package/dist/types/src/components/CommentsPanel/index.d.ts +3 -0
- package/dist/types/src/components/CommentsPanel/index.d.ts.map +1 -0
- package/dist/types/src/components/Lobby/Lobby.d.ts.map +1 -1
- package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
- package/dist/types/src/components/MessagePanel/MessagePanel.d.ts +15 -0
- package/dist/types/src/components/MessagePanel/MessagePanel.d.ts.map +1 -0
- package/dist/types/src/components/MessagePanel/index.d.ts +2 -0
- package/dist/types/src/components/MessagePanel/index.d.ts.map +1 -0
- package/dist/types/src/components/Participant/Participant.d.ts.map +1 -1
- package/dist/types/src/components/Participant/ParticipantGrid.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +142 -144
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/{ResponsiveContainer.d.ts → ResponsivePanel.d.ts} +4 -4
- package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.d.ts.map +1 -0
- package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.stories.d.ts +164 -0
- package/dist/types/src/components/ResponsiveGrid/ResponsivePanel.stories.d.ts.map +1 -0
- package/dist/types/src/components/ResponsiveGrid/index.d.ts +1 -1
- package/dist/types/src/components/ResponsiveGrid/index.d.ts.map +1 -1
- package/dist/types/src/components/ThreadSettings/ThreadSettings.d.ts +6 -0
- package/dist/types/src/components/ThreadSettings/ThreadSettings.d.ts.map +1 -0
- package/dist/types/src/components/ThreadSettings/ThreadSettings.stories.d.ts +161 -0
- package/dist/types/src/components/ThreadSettings/ThreadSettings.stories.d.ts.map +1 -0
- package/dist/types/src/components/ThreadSettings/index.d.ts +2 -0
- package/dist/types/src/components/ThreadSettings/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +4 -9
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/{components → containers/CallDebugPanel}/CallDebugPanel.d.ts +1 -1
- package/dist/types/src/containers/CallDebugPanel/CallDebugPanel.d.ts.map +1 -0
- package/dist/types/src/containers/CallDebugPanel/index.d.ts +2 -0
- package/dist/types/src/containers/CallDebugPanel/index.d.ts.map +1 -0
- package/dist/types/src/{components → containers/CallSidebar}/CallSidebar.d.ts +0 -1
- package/dist/types/src/containers/CallSidebar/CallSidebar.d.ts.map +1 -0
- package/dist/types/src/containers/CallSidebar/index.d.ts +2 -0
- package/dist/types/src/containers/CallSidebar/index.d.ts.map +1 -0
- package/dist/types/src/containers/ChannelContainer/ChannelContainer.d.ts +12 -0
- package/dist/types/src/containers/ChannelContainer/ChannelContainer.d.ts.map +1 -0
- package/dist/types/src/containers/ChannelContainer/ChannelContainer.stories.d.ts +162 -0
- package/dist/types/src/containers/ChannelContainer/ChannelContainer.stories.d.ts.map +1 -0
- package/dist/types/src/containers/ChannelContainer/index.d.ts +2 -0
- package/dist/types/src/containers/ChannelContainer/index.d.ts.map +1 -0
- package/dist/types/src/{components → containers/ChatContainer}/ChatContainer.d.ts +3 -5
- package/dist/types/src/containers/ChatContainer/ChatContainer.d.ts.map +1 -0
- package/dist/types/src/containers/ChatContainer/ChatContainer.stories.d.ts +162 -0
- package/dist/types/src/containers/ChatContainer/ChatContainer.stories.d.ts.map +1 -0
- package/dist/types/src/containers/ChatContainer/index.d.ts +4 -0
- package/dist/types/src/containers/ChatContainer/index.d.ts.map +1 -0
- package/dist/types/src/containers/ThreadCompanion/ThreadCompanion.d.ts +8 -0
- package/dist/types/src/containers/ThreadCompanion/ThreadCompanion.d.ts.map +1 -0
- package/dist/types/src/containers/ThreadCompanion/index.d.ts +2 -0
- package/dist/types/src/containers/ThreadCompanion/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +7 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/{components/command-extension.d.ts → extensions/command.d.ts} +1 -1
- package/dist/types/src/extensions/command.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +1 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/threads.d.ts +1 -1
- package/dist/types/src/extensions/threads.d.ts.map +1 -1
- package/dist/types/src/hooks/analytics.d.ts.map +1 -1
- package/dist/types/src/operations/add-message.d.ts +5 -0
- package/dist/types/src/operations/add-message.d.ts.map +1 -0
- package/dist/types/src/operations/create-channel-thread.d.ts +5 -0
- package/dist/types/src/operations/create-channel-thread.d.ts.map +1 -0
- package/dist/types/src/operations/create-channel.d.ts +5 -0
- package/dist/types/src/operations/create-channel.d.ts.map +1 -0
- package/dist/types/src/operations/create-proposals.d.ts +5 -0
- package/dist/types/src/operations/create-proposals.d.ts.map +1 -0
- package/dist/types/src/operations/create.d.ts +5 -0
- package/dist/types/src/operations/create.d.ts.map +1 -0
- package/dist/types/src/operations/definitions.d.ts +2789 -0
- package/dist/types/src/operations/definitions.d.ts.map +1 -0
- package/dist/types/src/operations/delete-message.d.ts +5 -0
- package/dist/types/src/operations/delete-message.d.ts.map +1 -0
- package/dist/types/src/operations/delete.d.ts +5 -0
- package/dist/types/src/operations/delete.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +4 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/on-create-space.d.ts +5 -0
- package/dist/types/src/operations/on-create-space.d.ts.map +1 -0
- package/dist/types/src/operations/restore-message.d.ts +5 -0
- package/dist/types/src/operations/restore-message.d.ts.map +1 -0
- package/dist/types/src/operations/restore.d.ts +5 -0
- package/dist/types/src/operations/restore.d.ts.map +1 -0
- package/dist/types/src/operations/select.d.ts +5 -0
- package/dist/types/src/operations/select.d.ts.map +1 -0
- package/dist/types/src/operations/toggle-resolved.d.ts +5 -0
- package/dist/types/src/operations/toggle-resolved.d.ts.map +1 -0
- package/dist/types/src/{components/testing.d.ts → testing/data.d.ts} +1 -1
- package/dist/types/src/testing/data.d.ts.map +1 -0
- package/dist/types/src/testing/stories.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +140 -142
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Channel.d.ts +25 -9
- package/dist/types/src/types/Channel.d.ts.map +1 -1
- package/dist/types/src/types/Settings.d.ts +4 -0
- package/dist/types/src/types/Settings.d.ts.map +1 -0
- package/dist/types/src/types/capabilities.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +1 -3227
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/src/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +88 -66
- package/src/ThreadPlugin.tsx +54 -56
- package/src/blueprints/index.ts +1 -1
- package/src/blueprints/thread-blueprint.ts +13 -8
- package/src/calls/util/calls-service.ts +0 -1
- package/src/calls-service.stories.tsx +10 -9
- package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +42 -50
- package/src/capabilities/blueprint-definition.ts +17 -0
- package/src/capabilities/{call-manager/call-manager.ts → call-manager.ts} +6 -5
- package/src/capabilities/index.ts +16 -10
- package/src/capabilities/{markdown/markdown.ts → markdown.ts} +14 -15
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/{react-root/react-root.tsx → react-root.tsx} +4 -4
- package/src/capabilities/react-surface.tsx +90 -0
- package/src/capabilities/{settings/settings.ts → settings.ts} +9 -7
- package/src/capabilities/{state/state.ts → state.ts} +1 -1
- package/src/capabilities/undo-mappings.ts +46 -0
- package/src/components/Call/Call.tsx +5 -5
- package/src/components/Call/Toolbar.tsx +30 -21
- package/src/components/{Comments.stories.tsx → CommentsPanel/CommentsPanel.stories.tsx} +16 -16
- package/src/components/{CommentsContainer.tsx → CommentsPanel/CommentsPanel.tsx} +15 -14
- package/src/components/{CommentsThreadContainer.tsx → CommentsPanel/CommentsThread.tsx} +19 -20
- package/src/components/CommentsPanel/index.ts +6 -0
- package/src/components/Lobby/Lobby.tsx +8 -7
- package/src/components/Media/VideoObject.stories.tsx +6 -7
- package/src/components/Media/VideoObject.tsx +1 -1
- package/src/components/{MessageContainer.tsx → MessagePanel/MessagePanel.tsx} +24 -18
- package/src/components/MessagePanel/index.ts +5 -0
- package/src/components/Participant/Participant.tsx +3 -2
- package/src/components/Participant/ParticipantGrid.tsx +0 -1
- package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +10 -11
- package/src/components/ResponsiveGrid/ResponsiveGrid.tsx +8 -8
- package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +9 -9
- package/src/components/ResponsiveGrid/{ResponsiveContainer.stories.tsx → ResponsivePanel.stories.tsx} +7 -8
- package/src/components/ResponsiveGrid/{ResponsiveContainer.tsx → ResponsivePanel.tsx} +5 -5
- package/src/components/ResponsiveGrid/index.ts +1 -1
- package/src/components/ThreadSettings/ThreadSettings.stories.tsx +31 -0
- package/src/components/ThreadSettings/ThreadSettings.tsx +20 -0
- package/src/components/ThreadSettings/index.ts +5 -0
- package/src/components/index.ts +5 -9
- package/src/{components → containers/CallDebugPanel}/CallDebugPanel.tsx +8 -7
- package/src/containers/CallDebugPanel/index.ts +5 -0
- package/src/{components → containers/CallSidebar}/CallSidebar.tsx +4 -6
- package/src/containers/CallSidebar/index.ts +5 -0
- package/src/{components → containers/ChannelContainer}/ChannelContainer.stories.tsx +14 -14
- package/src/{components → containers/ChannelContainer}/ChannelContainer.tsx +75 -59
- package/src/containers/ChannelContainer/index.ts +5 -0
- package/src/{components/Chat.stories.tsx → containers/ChatContainer/ChatContainer.stories.tsx} +22 -20
- package/src/containers/ChatContainer/ChatContainer.tsx +131 -0
- package/src/containers/ChatContainer/index.ts +8 -0
- package/src/{components → containers/ThreadCompanion}/ThreadCompanion.tsx +74 -50
- package/src/containers/ThreadCompanion/index.ts +5 -0
- package/src/containers/index.ts +11 -0
- package/src/{components/command-extension.ts → extensions/command.ts} +1 -1
- package/src/extensions/index.ts +1 -0
- package/src/extensions/threads.ts +14 -13
- package/src/hooks/analytics.ts +3 -2
- package/src/meta.ts +2 -2
- package/src/operations/add-message.ts +81 -0
- package/src/operations/create-channel-thread.ts +26 -0
- package/src/operations/create-channel.ts +20 -0
- package/src/operations/create-proposals.ts +49 -0
- package/src/operations/create.ts +48 -0
- package/src/operations/definitions.ts +177 -0
- package/src/operations/delete-message.ts +53 -0
- package/src/operations/delete.ts +63 -0
- package/src/operations/index.ts +22 -0
- package/src/operations/on-create-space.ts +27 -0
- package/src/operations/restore-message.ts +38 -0
- package/src/operations/restore.ts +38 -0
- package/src/operations/select.ts +24 -0
- package/src/operations/toggle-resolved.ts +41 -0
- package/src/{components/testing.ts → testing/data.ts} +7 -7
- package/src/testing/stories.ts +7 -11
- package/src/translations.ts +72 -76
- package/src/types/Channel.ts +11 -4
- package/src/types/Settings.ts +10 -0
- package/src/types/capabilities.ts +9 -7
- package/src/types/types.ts +2 -184
- package/src/util.ts +1 -1
- package/dist/lib/browser/app-graph-builder-7C2QW32W.mjs +0 -188
- package/dist/lib/browser/app-graph-builder-7C2QW32W.mjs.map +0 -7
- package/dist/lib/browser/blueprint-definition-UQ63QKQG.mjs +0 -17
- package/dist/lib/browser/blueprint-definition-UQ63QKQG.mjs.map +0 -7
- package/dist/lib/browser/call-manager-4P536YNX.mjs +0 -26
- package/dist/lib/browser/call-manager-4P536YNX.mjs.map +0 -7
- package/dist/lib/browser/chunk-2FIHSX35.mjs +0 -293
- package/dist/lib/browser/chunk-2FIHSX35.mjs.map +0 -7
- package/dist/lib/browser/chunk-CP7E2HRE.mjs +0 -31
- package/dist/lib/browser/chunk-CP7E2HRE.mjs.map +0 -7
- package/dist/lib/browser/chunk-DLO2G3DM.mjs +0 -184
- package/dist/lib/browser/chunk-DLO2G3DM.mjs.map +0 -7
- package/dist/lib/browser/chunk-ERK254BS.mjs +0 -1810
- package/dist/lib/browser/chunk-ERK254BS.mjs.map +0 -7
- package/dist/lib/browser/chunk-ISCHODBV.mjs +0 -106
- package/dist/lib/browser/chunk-ISCHODBV.mjs.map +0 -7
- package/dist/lib/browser/chunk-YSHXWAL3.mjs +0 -1815
- package/dist/lib/browser/chunk-YSHXWAL3.mjs.map +0 -7
- package/dist/lib/browser/chunk-ZFLSTQSE.mjs +0 -106
- package/dist/lib/browser/chunk-ZFLSTQSE.mjs.map +0 -7
- package/dist/lib/browser/markdown-QMJLRR6R.mjs +0 -210
- package/dist/lib/browser/markdown-QMJLRR6R.mjs.map +0 -7
- package/dist/lib/browser/operation-resolver-T63EP5TY.mjs +0 -441
- package/dist/lib/browser/operation-resolver-T63EP5TY.mjs.map +0 -7
- package/dist/lib/browser/react-root-56MJI77R.mjs +0 -25
- package/dist/lib/browser/react-root-56MJI77R.mjs.map +0 -7
- package/dist/lib/browser/react-surface-DMBHQOXJ.mjs +0 -110
- package/dist/lib/browser/react-surface-DMBHQOXJ.mjs.map +0 -7
- package/dist/lib/browser/repair-6OZ75AUU.mjs +0 -38
- package/dist/lib/browser/repair-6OZ75AUU.mjs.map +0 -7
- package/dist/lib/browser/settings-WZMJMML3.mjs +0 -32
- package/dist/lib/browser/settings-WZMJMML3.mjs.map +0 -7
- package/dist/lib/browser/state-SJR2GL5G.mjs +0 -24
- package/dist/lib/browser/state-SJR2GL5G.mjs.map +0 -7
- package/dist/lib/node-esm/app-graph-builder-JCSVFRVY.mjs +0 -189
- package/dist/lib/node-esm/app-graph-builder-JCSVFRVY.mjs.map +0 -7
- package/dist/lib/node-esm/blueprint-definition-MZZXXL37.mjs +0 -18
- package/dist/lib/node-esm/blueprint-definition-MZZXXL37.mjs.map +0 -7
- package/dist/lib/node-esm/call-manager-FMLRR5S5.mjs +0 -27
- package/dist/lib/node-esm/call-manager-FMLRR5S5.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-7XQLXMX7.mjs +0 -1816
- package/dist/lib/node-esm/chunk-7XQLXMX7.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ABUFOZVX.mjs +0 -33
- package/dist/lib/node-esm/chunk-ABUFOZVX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-AQHPP6ZX.mjs +0 -107
- package/dist/lib/node-esm/chunk-AQHPP6ZX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-KRBZBJRI.mjs +0 -185
- package/dist/lib/node-esm/chunk-KRBZBJRI.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-QP3KQOPQ.mjs +0 -1811
- package/dist/lib/node-esm/chunk-QP3KQOPQ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-VBI32FGI.mjs +0 -108
- package/dist/lib/node-esm/chunk-VBI32FGI.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-WMWUXWAS.mjs +0 -294
- package/dist/lib/node-esm/chunk-WMWUXWAS.mjs.map +0 -7
- package/dist/lib/node-esm/markdown-L6LLQLIN.mjs +0 -211
- package/dist/lib/node-esm/markdown-L6LLQLIN.mjs.map +0 -7
- package/dist/lib/node-esm/operation-resolver-G6GZPBRP.mjs +0 -442
- package/dist/lib/node-esm/operation-resolver-G6GZPBRP.mjs.map +0 -7
- package/dist/lib/node-esm/react-root-V4W4X5GL.mjs +0 -26
- package/dist/lib/node-esm/react-root-V4W4X5GL.mjs.map +0 -7
- package/dist/lib/node-esm/react-surface-ELDSTUA3.mjs +0 -111
- package/dist/lib/node-esm/react-surface-ELDSTUA3.mjs.map +0 -7
- package/dist/lib/node-esm/repair-6777EPOM.mjs +0 -39
- package/dist/lib/node-esm/repair-6777EPOM.mjs.map +0 -7
- package/dist/lib/node-esm/settings-37CO3SNR.mjs +0 -33
- package/dist/lib/node-esm/settings-37CO3SNR.mjs.map +0 -7
- package/dist/lib/node-esm/state-5R3TZJQE.mjs +0 -25
- package/dist/lib/node-esm/state-5R3TZJQE.mjs.map +0 -7
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
- package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
- package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/blueprint-definition/blueprint-definition.d.ts +0 -9
- package/dist/types/src/capabilities/blueprint-definition/blueprint-definition.d.ts.map +0 -1
- package/dist/types/src/capabilities/blueprint-definition/index.d.ts +0 -3
- package/dist/types/src/capabilities/blueprint-definition/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/call-manager/call-manager.d.ts +0 -6
- package/dist/types/src/capabilities/call-manager/call-manager.d.ts.map +0 -1
- package/dist/types/src/capabilities/call-manager/index.d.ts +0 -3
- package/dist/types/src/capabilities/call-manager/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/markdown/index.d.ts +0 -3
- package/dist/types/src/capabilities/markdown/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/markdown/markdown.d.ts +0 -5
- package/dist/types/src/capabilities/markdown/markdown.d.ts.map +0 -1
- package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
- package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
- package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-root/index.d.ts +0 -6
- package/dist/types/src/capabilities/react-root/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-root/react-root.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
- package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
- package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
- package/dist/types/src/capabilities/repair/index.d.ts +0 -3
- package/dist/types/src/capabilities/repair/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/repair/repair.d.ts +0 -6
- package/dist/types/src/capabilities/repair/repair.d.ts.map +0 -1
- package/dist/types/src/capabilities/settings/index.d.ts +0 -3
- package/dist/types/src/capabilities/settings/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/settings/settings.d.ts +0 -5
- package/dist/types/src/capabilities/settings/settings.d.ts.map +0 -1
- package/dist/types/src/capabilities/state/index.d.ts +0 -3
- package/dist/types/src/capabilities/state/index.d.ts.map +0 -1
- package/dist/types/src/capabilities/state/state.d.ts +0 -7
- package/dist/types/src/capabilities/state/state.d.ts.map +0 -1
- package/dist/types/src/components/CallDebugPanel.d.ts.map +0 -1
- package/dist/types/src/components/CallSidebar.d.ts.map +0 -1
- package/dist/types/src/components/ChannelContainer.d.ts +0 -13
- package/dist/types/src/components/ChannelContainer.d.ts.map +0 -1
- package/dist/types/src/components/ChannelContainer.stories.d.ts +0 -164
- package/dist/types/src/components/ChannelContainer.stories.d.ts.map +0 -1
- package/dist/types/src/components/Chat.stories.d.ts +0 -164
- package/dist/types/src/components/Chat.stories.d.ts.map +0 -1
- package/dist/types/src/components/ChatContainer.d.ts.map +0 -1
- package/dist/types/src/components/Comments.stories.d.ts +0 -162
- package/dist/types/src/components/Comments.stories.d.ts.map +0 -1
- package/dist/types/src/components/CommentsContainer.d.ts +0 -13
- package/dist/types/src/components/CommentsContainer.d.ts.map +0 -1
- package/dist/types/src/components/CommentsThreadContainer.d.ts.map +0 -1
- package/dist/types/src/components/MessageContainer.d.ts +0 -15
- package/dist/types/src/components/MessageContainer.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.d.ts.map +0 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +0 -166
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +0 -1
- package/dist/types/src/components/ThreadCompanion.d.ts +0 -5
- package/dist/types/src/components/ThreadCompanion.d.ts.map +0 -1
- package/dist/types/src/components/ThreadSettings.d.ts +0 -8
- package/dist/types/src/components/ThreadSettings.d.ts.map +0 -1
- package/dist/types/src/components/command-extension.d.ts.map +0 -1
- package/dist/types/src/components/testing.d.ts.map +0 -1
- package/dist/types/src/functions/create-proposals.d.ts +0 -6
- package/dist/types/src/functions/create-proposals.d.ts.map +0 -1
- package/dist/types/src/functions/index.d.ts +0 -2
- package/dist/types/src/functions/index.d.ts.map +0 -1
- package/src/capabilities/app-graph-builder/index.ts +0 -7
- package/src/capabilities/blueprint-definition/blueprint-definition.ts +0 -23
- package/src/capabilities/blueprint-definition/index.ts +0 -7
- package/src/capabilities/call-manager/index.ts +0 -7
- package/src/capabilities/markdown/index.ts +0 -7
- package/src/capabilities/operation-resolver/index.ts +0 -7
- package/src/capabilities/operation-resolver/operation-resolver.ts +0 -400
- package/src/capabilities/react-root/index.ts +0 -7
- package/src/capabilities/react-surface/index.ts +0 -7
- package/src/capabilities/react-surface/react-surface.tsx +0 -97
- package/src/capabilities/repair/index.ts +0 -7
- package/src/capabilities/repair/repair.ts +0 -51
- package/src/capabilities/settings/index.ts +0 -7
- package/src/capabilities/state/index.ts +0 -7
- package/src/components/ChatContainer.tsx +0 -155
- package/src/components/ThreadSettings.tsx +0 -21
- package/src/functions/create-proposals.ts +0 -57
- package/src/functions/index.ts +0 -5
|
@@ -1,209 +1,2220 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
useInaudibleAudioStreamTrack,
|
|
6
|
-
useOnEditAnalytics,
|
|
7
|
-
useStatus,
|
|
8
|
-
useVideoStreamTrack
|
|
9
|
-
} from "./chunk-KRBZBJRI.mjs";
|
|
10
|
-
import {
|
|
11
|
-
CALLS_URL,
|
|
12
|
-
CallManager,
|
|
13
|
-
CallSwarmSynchronizer,
|
|
14
|
-
CallsServicePeer,
|
|
15
|
-
MediaManager,
|
|
16
|
-
SpeakingMonitor,
|
|
17
|
-
TrackNameCodec,
|
|
18
|
-
codec,
|
|
19
|
-
getDeviceList,
|
|
20
|
-
getScreenshare,
|
|
21
|
-
getUserMediaTrack,
|
|
22
|
-
monitorAudioLevel
|
|
23
|
-
} from "./chunk-QP3KQOPQ.mjs";
|
|
24
|
-
import {
|
|
25
|
-
createBlackCanvasStreamTrack,
|
|
26
|
-
createInaudibleAudioStreamTrack
|
|
27
|
-
} from "./chunk-VBI32FGI.mjs";
|
|
28
|
-
import {
|
|
29
|
-
Channel_exports,
|
|
30
|
-
THREAD_ITEM,
|
|
31
|
-
ThreadCapabilities,
|
|
32
|
-
ThreadOperation,
|
|
33
|
-
meta
|
|
34
|
-
} from "./chunk-WMWUXWAS.mjs";
|
|
3
|
+
ThreadCapabilities
|
|
4
|
+
} from "./chunk-UGSMYQLZ.mjs";
|
|
35
5
|
import "./chunk-HSLMI22Q.mjs";
|
|
36
6
|
|
|
37
|
-
// src/
|
|
38
|
-
import
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import { MarkdownEvents } from "@dxos/plugin-markdown";
|
|
44
|
-
import { SpaceCapabilities, SpaceEvents } from "@dxos/plugin-space";
|
|
45
|
-
import { translations as threadTranslations } from "@dxos/react-ui-thread";
|
|
46
|
-
import { AnchoredTo, Message, Thread } from "@dxos/types";
|
|
7
|
+
// src/calls/call-manager.ts
|
|
8
|
+
import { Atom } from "@effect-atom/atom-react";
|
|
9
|
+
import { Event as Event4, synchronized as synchronized3 } from "@dxos/async";
|
|
10
|
+
import { Resource as Resource5 } from "@dxos/context";
|
|
11
|
+
import { invariant as invariant6 } from "@dxos/invariant";
|
|
12
|
+
import { isNonNullable as isNonNullable2 } from "@dxos/util";
|
|
47
13
|
|
|
48
|
-
// src/
|
|
49
|
-
import
|
|
50
|
-
|
|
14
|
+
// src/calls/call-swarm-synchronizer.ts
|
|
15
|
+
import md5Hex from "md5-hex";
|
|
16
|
+
import { DeferredTask, Event, scheduleTaskInterval, synchronized } from "@dxos/async";
|
|
17
|
+
import { Context, Resource } from "@dxos/context";
|
|
18
|
+
import { generateName } from "@dxos/display-name";
|
|
19
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
20
|
+
import { PublicKey } from "@dxos/keys";
|
|
21
|
+
import { log } from "@dxos/log";
|
|
22
|
+
import { buf as buf2 } from "@dxos/protocols/buf";
|
|
23
|
+
import { ActivitySchema } from "@dxos/protocols/buf/dxos/edge/calls_pb";
|
|
24
|
+
import { ConnectionState } from "@dxos/protocols/proto/dxos/edge/messenger";
|
|
25
|
+
import { isNonNullable } from "@dxos/util";
|
|
51
26
|
|
|
52
|
-
// src/
|
|
53
|
-
import {
|
|
54
|
-
|
|
27
|
+
// src/calls/types.ts
|
|
28
|
+
import { invariant } from "@dxos/invariant";
|
|
29
|
+
import { buf } from "@dxos/protocols/buf";
|
|
30
|
+
import { UserStateSchema } from "@dxos/protocols/buf/dxos/edge/calls_pb";
|
|
31
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/calls/types.ts";
|
|
32
|
+
var CALLS_URL = "https://calls-service.dxos.workers.dev";
|
|
33
|
+
var codec = {
|
|
34
|
+
encode: (message) => {
|
|
35
|
+
return buf.toBinary(UserStateSchema, buf.create(UserStateSchema, message));
|
|
36
|
+
},
|
|
37
|
+
decode: (message) => {
|
|
38
|
+
return buf.fromBinary(UserStateSchema, message);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var TrackNameCodec = {
|
|
42
|
+
encode: (trackData) => {
|
|
43
|
+
invariant(trackData.sessionId, void 0, {
|
|
44
|
+
F: __dxlog_file,
|
|
45
|
+
L: 65,
|
|
46
|
+
S: void 0,
|
|
47
|
+
A: [
|
|
48
|
+
"trackData.sessionId",
|
|
49
|
+
""
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
invariant(trackData.trackName, void 0, {
|
|
53
|
+
F: __dxlog_file,
|
|
54
|
+
L: 66,
|
|
55
|
+
S: void 0,
|
|
56
|
+
A: [
|
|
57
|
+
"trackData.trackName",
|
|
58
|
+
""
|
|
59
|
+
]
|
|
60
|
+
});
|
|
61
|
+
invariant(trackData.mid, void 0, {
|
|
62
|
+
F: __dxlog_file,
|
|
63
|
+
L: 67,
|
|
64
|
+
S: void 0,
|
|
65
|
+
A: [
|
|
66
|
+
"trackData.mid",
|
|
67
|
+
""
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
return trackData.sessionId + "/" + trackData.trackName + "/" + trackData.mid;
|
|
71
|
+
},
|
|
72
|
+
decode: (name) => {
|
|
73
|
+
const [sessionId, trackName, mid] = name.split("/");
|
|
74
|
+
return {
|
|
75
|
+
sessionId,
|
|
76
|
+
trackName,
|
|
77
|
+
location: "remote",
|
|
78
|
+
mid
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
};
|
|
55
82
|
|
|
56
|
-
// src/
|
|
57
|
-
|
|
58
|
-
var
|
|
83
|
+
// src/calls/call-swarm-synchronizer.ts
|
|
84
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
85
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
86
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
87
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
88
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
89
|
+
}
|
|
90
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/calls/call-swarm-synchronizer.ts";
|
|
91
|
+
var DISCONNECTED_ABRUPT_TIMEOUT = 1e4;
|
|
92
|
+
var CallSwarmSynchronizer = class extends Resource {
|
|
93
|
+
stateUpdated = new Event();
|
|
94
|
+
_state = {
|
|
95
|
+
activities: {}
|
|
96
|
+
};
|
|
97
|
+
_networkService;
|
|
98
|
+
_lastSwarmEvent = void 0;
|
|
99
|
+
_reconcileSwarmStateTask = void 0;
|
|
100
|
+
_identityKey = void 0;
|
|
101
|
+
_deviceKey = void 0;
|
|
102
|
+
_displayName = void 0;
|
|
103
|
+
_swarmCtx = void 0;
|
|
104
|
+
_sendStateTask = void 0;
|
|
105
|
+
constructor({ networkService }) {
|
|
106
|
+
super();
|
|
107
|
+
this._networkService = networkService;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
_getState() {
|
|
113
|
+
return this._state;
|
|
114
|
+
}
|
|
115
|
+
setRaisedHand(raisedHand) {
|
|
116
|
+
if (this._state.raisedHand === raisedHand) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this._state.raisedHand = raisedHand;
|
|
120
|
+
this._notifyAndSchedule();
|
|
121
|
+
}
|
|
122
|
+
setSpeaking(speaking) {
|
|
123
|
+
if (this._state.speaking === speaking) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
this._state.speaking = speaking;
|
|
127
|
+
this._notifyAndSchedule();
|
|
128
|
+
}
|
|
129
|
+
setJoined(joined) {
|
|
130
|
+
if (this._state.joined === joined) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
this._state.joined = joined;
|
|
134
|
+
this._notifyAndSchedule();
|
|
135
|
+
}
|
|
136
|
+
setTracks(tracks) {
|
|
137
|
+
this._state.tracks = {
|
|
138
|
+
...this._state.tracks,
|
|
139
|
+
...tracks
|
|
140
|
+
};
|
|
141
|
+
this._notifyAndSchedule();
|
|
142
|
+
}
|
|
143
|
+
setActivity(key, payload) {
|
|
144
|
+
const lamportTimestamp = LamportTimestampCrdt.increment(this._state.activities?.[key]?.lamportTimestamp ?? {
|
|
145
|
+
id: this._deviceKey
|
|
146
|
+
});
|
|
147
|
+
this._state.activities[key] = {
|
|
148
|
+
lamportTimestamp,
|
|
149
|
+
payload
|
|
150
|
+
};
|
|
151
|
+
this._notifyAndSchedule();
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @internal
|
|
155
|
+
*/
|
|
156
|
+
_setIdentity(identity) {
|
|
157
|
+
this._identityKey = identity.identityKey.toHex();
|
|
158
|
+
this._displayName = identity.profile?.displayName ?? generateName(identity.identityKey.toHex());
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* @internal
|
|
162
|
+
*/
|
|
163
|
+
_setDevice(device) {
|
|
164
|
+
this._deviceKey = device.deviceKey.toHex();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* @internal
|
|
168
|
+
*/
|
|
169
|
+
_setRoomId(roomId) {
|
|
170
|
+
if (this._swarmCtx) {
|
|
171
|
+
log.verbose("joined to a different room", {
|
|
172
|
+
roomId
|
|
173
|
+
}, {
|
|
174
|
+
F: __dxlog_file2,
|
|
175
|
+
L: 152,
|
|
176
|
+
S: this,
|
|
177
|
+
C: (f, a) => f(...a)
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
this._state.roomId = roomId;
|
|
182
|
+
}
|
|
183
|
+
async _open() {
|
|
184
|
+
this._sendStateTask = new DeferredTask(this._ctx, async () => {
|
|
185
|
+
await this._sendState();
|
|
186
|
+
});
|
|
187
|
+
this._reconcileSwarmStateTask = new DeferredTask(this._ctx, async () => {
|
|
188
|
+
await this._reconcileSwarmState();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
async _close() {
|
|
192
|
+
this._sendStateTask = void 0;
|
|
193
|
+
this._reconcileSwarmStateTask = void 0;
|
|
194
|
+
}
|
|
195
|
+
async join() {
|
|
196
|
+
invariant2(this._state.roomId, void 0, {
|
|
197
|
+
F: __dxlog_file2,
|
|
198
|
+
L: 176,
|
|
199
|
+
S: this,
|
|
200
|
+
A: [
|
|
201
|
+
"this._state.roomId",
|
|
202
|
+
""
|
|
203
|
+
]
|
|
204
|
+
});
|
|
205
|
+
invariant2(!this._swarmCtx, "Already joined", {
|
|
206
|
+
F: __dxlog_file2,
|
|
207
|
+
L: 177,
|
|
208
|
+
S: this,
|
|
209
|
+
A: [
|
|
210
|
+
"!this._swarmCtx",
|
|
211
|
+
"'Already joined'"
|
|
212
|
+
]
|
|
213
|
+
});
|
|
214
|
+
this._swarmCtx = new Context(void 0, {
|
|
215
|
+
F: __dxlog_file2,
|
|
216
|
+
L: 179
|
|
217
|
+
});
|
|
218
|
+
const topic = getTopic(this._state.roomId);
|
|
219
|
+
log("joining swarm", {
|
|
220
|
+
topic,
|
|
221
|
+
peer: {
|
|
222
|
+
identityKey: this._identityKey,
|
|
223
|
+
peerKey: this._deviceKey
|
|
224
|
+
}
|
|
225
|
+
}, {
|
|
226
|
+
F: __dxlog_file2,
|
|
227
|
+
L: 181,
|
|
228
|
+
S: this,
|
|
229
|
+
C: (f, a) => f(...a)
|
|
230
|
+
});
|
|
231
|
+
const stream = this._networkService.subscribeSwarmState({
|
|
232
|
+
topic
|
|
233
|
+
});
|
|
234
|
+
stream.subscribe((event) => this._processSwarmEvent(event));
|
|
235
|
+
const cleanup = () => {
|
|
236
|
+
void stream.close();
|
|
237
|
+
if (topic && this._identityKey && this._deviceKey) {
|
|
238
|
+
log("leaving swarm", {
|
|
239
|
+
topic,
|
|
240
|
+
peer: {
|
|
241
|
+
identityKey: this._identityKey,
|
|
242
|
+
peerKey: this._deviceKey
|
|
243
|
+
}
|
|
244
|
+
}, {
|
|
245
|
+
F: __dxlog_file2,
|
|
246
|
+
L: 188,
|
|
247
|
+
S: this,
|
|
248
|
+
C: (f, a) => f(...a)
|
|
249
|
+
});
|
|
250
|
+
void this._networkService.leaveSwarm({
|
|
251
|
+
topic,
|
|
252
|
+
peer: {
|
|
253
|
+
identityKey: this._identityKey,
|
|
254
|
+
peerKey: this._deviceKey
|
|
255
|
+
}
|
|
256
|
+
}).catch((err) => log.catch(err, void 0, {
|
|
257
|
+
F: __dxlog_file2,
|
|
258
|
+
L: 194,
|
|
259
|
+
S: this,
|
|
260
|
+
C: (f, a) => f(...a)
|
|
261
|
+
}));
|
|
262
|
+
}
|
|
263
|
+
window.removeEventListener("beforeunload", cleanup);
|
|
264
|
+
};
|
|
265
|
+
window.addEventListener("beforeunload", cleanup);
|
|
266
|
+
this._swarmCtx.onDispose(cleanup);
|
|
267
|
+
this._notifyAndSchedule();
|
|
268
|
+
}
|
|
269
|
+
async leave() {
|
|
270
|
+
if (!this._swarmCtx) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
await this._swarmCtx.dispose();
|
|
274
|
+
this._swarmCtx = void 0;
|
|
275
|
+
this._state.users = void 0;
|
|
276
|
+
this._state.self = void 0;
|
|
277
|
+
}
|
|
278
|
+
async querySwarm(roomId) {
|
|
279
|
+
const topic = getTopic(roomId);
|
|
280
|
+
const swarm = await this._networkService.querySwarm({
|
|
281
|
+
topic
|
|
282
|
+
});
|
|
283
|
+
return swarm.peers ?? [];
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Notify and schedule send state task.
|
|
287
|
+
*/
|
|
288
|
+
_notifyAndSchedule() {
|
|
289
|
+
this.stateUpdated.emit(this._state);
|
|
290
|
+
if (this._state.joined) {
|
|
291
|
+
this._sendStateTask?.schedule();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
async _sendState() {
|
|
295
|
+
if (!this._state.roomId || !this._identityKey || !this._deviceKey || !this._state.joined) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const state = {
|
|
299
|
+
...this._state,
|
|
300
|
+
id: this._deviceKey,
|
|
301
|
+
name: this._displayName,
|
|
302
|
+
activities: this._state.activities ? Object.fromEntries(Object.entries(this._state.activities).map(([key, activity]) => [
|
|
303
|
+
key,
|
|
304
|
+
buf2.create(ActivitySchema, activity)
|
|
305
|
+
])) : {}
|
|
306
|
+
};
|
|
307
|
+
await this._networkService.joinSwarm({
|
|
308
|
+
topic: getTopic(this._state.roomId),
|
|
309
|
+
peer: {
|
|
310
|
+
identityKey: this._identityKey,
|
|
311
|
+
peerKey: this._deviceKey,
|
|
312
|
+
state: codec.encode(state)
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
_processSwarmEvent(swarmEvent) {
|
|
317
|
+
if (!this._state.joined) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
this._lastSwarmEvent = swarmEvent;
|
|
321
|
+
this._reconcileSwarmStateTask.schedule();
|
|
322
|
+
}
|
|
323
|
+
async _reconcileSwarmState() {
|
|
324
|
+
const swarmEvent = this._lastSwarmEvent;
|
|
325
|
+
invariant2(swarmEvent, void 0, {
|
|
326
|
+
F: __dxlog_file2,
|
|
327
|
+
L: 273,
|
|
328
|
+
S: this,
|
|
329
|
+
A: [
|
|
330
|
+
"swarmEvent",
|
|
331
|
+
""
|
|
332
|
+
]
|
|
333
|
+
});
|
|
334
|
+
const peers = [
|
|
335
|
+
...swarmEvent.peers ?? [],
|
|
336
|
+
...(swarmEvent.inactivePeers ?? []).filter(({ disconnected, connectionState }) => connectionState === ConnectionState.DISCONNECTED_ABRUPT && disconnected && disconnected > Date.now() - DISCONNECTED_ABRUPT_TIMEOUT)
|
|
337
|
+
].sort((peer1, peer2) => peer1.peerKey.localeCompare(peer2.peerKey));
|
|
338
|
+
const users = peers.map((peer) => {
|
|
339
|
+
try {
|
|
340
|
+
return codec.decode(peer.state);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
log.error("error decoding peer state", {
|
|
343
|
+
error,
|
|
344
|
+
peer
|
|
345
|
+
}, {
|
|
346
|
+
F: __dxlog_file2,
|
|
347
|
+
L: 290,
|
|
348
|
+
S: this,
|
|
349
|
+
C: (f, a) => f(...a)
|
|
350
|
+
});
|
|
351
|
+
return void 0;
|
|
352
|
+
}
|
|
353
|
+
}).filter(isNonNullable);
|
|
354
|
+
this._state.users = users;
|
|
355
|
+
this._state.self = users.find((user) => user.id === this._deviceKey);
|
|
356
|
+
log("reconciling swarm state", {
|
|
357
|
+
users
|
|
358
|
+
}, {
|
|
359
|
+
F: __dxlog_file2,
|
|
360
|
+
L: 297,
|
|
361
|
+
S: this,
|
|
362
|
+
C: (f, a) => f(...a)
|
|
363
|
+
});
|
|
364
|
+
if (users.length === 0) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const activityKeys = new Set(users.flatMap((user) => Object.keys(user.activities)));
|
|
368
|
+
[
|
|
369
|
+
...activityKeys
|
|
370
|
+
].forEach((key) => {
|
|
371
|
+
const activities = users.map((user) => user.activities?.[key]).filter(isNonNullable);
|
|
372
|
+
const lastActivity = LamportTimestampCrdt.getLastState(activities);
|
|
373
|
+
if (lastActivity && lastActivity.lamportTimestamp.version > (this._state.activities[key]?.lamportTimestamp?.version ?? 0)) {
|
|
374
|
+
this._state.activities[key] = lastActivity;
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
this.stateUpdated.emit(this._state);
|
|
378
|
+
if (peers.some((peer) => peer.connectionState !== ConnectionState.CONNECTED)) {
|
|
379
|
+
scheduleTaskInterval(this._ctx, async () => this._reconcileSwarmStateTask.schedule(), Math.min(DISCONNECTED_ABRUPT_TIMEOUT / 2, 1e3));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
_ts_decorate([
|
|
384
|
+
synchronized
|
|
385
|
+
], CallSwarmSynchronizer.prototype, "join", null);
|
|
386
|
+
_ts_decorate([
|
|
387
|
+
synchronized
|
|
388
|
+
], CallSwarmSynchronizer.prototype, "leave", null);
|
|
389
|
+
var LamportTimestampCrdt = class {
|
|
390
|
+
static getLastState(states) {
|
|
391
|
+
const maxTimestamp = Math.max(...states.map((state) => state.lamportTimestamp?.version ?? 0));
|
|
392
|
+
const sortedStates = states.filter((state) => state.lamportTimestamp && state.lamportTimestamp.version === maxTimestamp && state.lamportTimestamp.id).sort((a, b) => a.lamportTimestamp.id.localeCompare(b.lamportTimestamp.id));
|
|
393
|
+
return sortedStates[0];
|
|
394
|
+
}
|
|
395
|
+
static increment(timestamp) {
|
|
396
|
+
return {
|
|
397
|
+
...timestamp ?? {},
|
|
398
|
+
version: (timestamp?.version ?? 0) + 1
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
var getTopic = (roomId) => PublicKey.fromHex(md5Hex(roomId));
|
|
59
403
|
|
|
60
|
-
// src/
|
|
61
|
-
import {
|
|
62
|
-
|
|
404
|
+
// src/calls/media-manager.ts
|
|
405
|
+
import { DeferredTask as DeferredTask3, Event as Event3, sleep as sleep2, synchronized as synchronized2 } from "@dxos/async";
|
|
406
|
+
import { Resource as Resource4, cancelWithContext as cancelWithContext2 } from "@dxos/context";
|
|
407
|
+
import { invariant as invariant5 } from "@dxos/invariant";
|
|
408
|
+
import { log as log4 } from "@dxos/log";
|
|
63
409
|
|
|
64
|
-
// src/
|
|
65
|
-
import {
|
|
66
|
-
|
|
410
|
+
// src/calls/speaking-monitor.ts
|
|
411
|
+
import { DeferredTask as DeferredTask2, Event as Event2, sleep } from "@dxos/async";
|
|
412
|
+
import { Resource as Resource3 } from "@dxos/context";
|
|
413
|
+
|
|
414
|
+
// src/calls/util/audio.ts
|
|
415
|
+
var monitorAudioLevel = ({ mediaStreamTrack, intervalMs = 1e3 / 10, onMeasure }) => {
|
|
416
|
+
let timeout = -1;
|
|
417
|
+
let interval = -1;
|
|
418
|
+
const audioContext = new AudioContext();
|
|
419
|
+
const stream = new MediaStream();
|
|
420
|
+
stream.addTrack(mediaStreamTrack);
|
|
421
|
+
const mediaStreamAudioSourceNode = audioContext.createMediaStreamSource(stream);
|
|
422
|
+
const analyserNode = audioContext.createAnalyser();
|
|
423
|
+
mediaStreamAudioSourceNode.connect(analyserNode);
|
|
424
|
+
analyserNode.fftSize = 32;
|
|
425
|
+
const pcmData = new Float32Array(analyserNode.fftSize);
|
|
426
|
+
let peak = 0;
|
|
427
|
+
interval = window.setInterval(() => {
|
|
428
|
+
onMeasure(peak);
|
|
429
|
+
peak = 0;
|
|
430
|
+
}, intervalMs);
|
|
431
|
+
const tick = () => {
|
|
432
|
+
timeout = window.setTimeout(() => {
|
|
433
|
+
analyserNode.getFloatTimeDomainData(pcmData);
|
|
434
|
+
let sumSquares = 0;
|
|
435
|
+
for (const amplitude of pcmData) {
|
|
436
|
+
sumSquares += amplitude * amplitude;
|
|
437
|
+
}
|
|
438
|
+
const current = Math.sqrt(sumSquares / pcmData.length);
|
|
439
|
+
if (current > peak) {
|
|
440
|
+
peak = current;
|
|
441
|
+
}
|
|
442
|
+
tick();
|
|
443
|
+
}, intervalMs);
|
|
444
|
+
};
|
|
445
|
+
tick();
|
|
446
|
+
return () => {
|
|
447
|
+
mediaStreamAudioSourceNode.disconnect();
|
|
448
|
+
analyserNode.disconnect();
|
|
449
|
+
void audioContext.close();
|
|
450
|
+
clearInterval(interval);
|
|
451
|
+
clearTimeout(timeout);
|
|
452
|
+
stream.removeTrack(mediaStreamTrack);
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// src/calls/util/calls-service.ts
|
|
457
|
+
import { PersistentLifecycle, Trigger, scheduleTask } from "@dxos/async";
|
|
458
|
+
import { Resource as Resource2 } from "@dxos/context";
|
|
459
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
460
|
+
import { log as log2 } from "@dxos/log";
|
|
461
|
+
|
|
462
|
+
// src/calls/util/history-cache.ts
|
|
463
|
+
var HistoryCache = class {
|
|
464
|
+
_limit;
|
|
465
|
+
_messages;
|
|
466
|
+
constructor(limit = 100) {
|
|
467
|
+
this._limit = limit;
|
|
468
|
+
this._messages = [];
|
|
469
|
+
}
|
|
470
|
+
push(...messages) {
|
|
471
|
+
if (this._messages.length >= this._limit) {
|
|
472
|
+
this._messages.shift();
|
|
473
|
+
}
|
|
474
|
+
this._messages.push(...messages);
|
|
475
|
+
}
|
|
476
|
+
get() {
|
|
477
|
+
return this._messages;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
67
480
|
|
|
68
|
-
// src/
|
|
69
|
-
|
|
70
|
-
var
|
|
481
|
+
// src/calls/util/task-scheduling.ts
|
|
482
|
+
var DefaultBatchSizeLimit = 64;
|
|
483
|
+
var FIFOScheduler = class {
|
|
484
|
+
#schedulerChain;
|
|
485
|
+
constructor() {
|
|
486
|
+
this.#schedulerChain = Promise.resolve();
|
|
487
|
+
}
|
|
488
|
+
schedule(task) {
|
|
489
|
+
return new Promise((resolve, reject) => {
|
|
490
|
+
this.#schedulerChain = this.#schedulerChain.then(async () => {
|
|
491
|
+
try {
|
|
492
|
+
resolve(await task());
|
|
493
|
+
} catch (error) {
|
|
494
|
+
reject(error);
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
var BulkRequestDispatcher = class {
|
|
501
|
+
#currentBatch;
|
|
502
|
+
#currentBulkResponse;
|
|
503
|
+
#batchSizeLimit;
|
|
504
|
+
constructor(batchSizeLimit = DefaultBatchSizeLimit) {
|
|
505
|
+
this.#currentBatch = [];
|
|
506
|
+
this.#currentBulkResponse = null;
|
|
507
|
+
this.#batchSizeLimit = batchSizeLimit;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Returns a bulk response promise.
|
|
511
|
+
* At the event loop iteration end, the accumulated entries will be dispatched as a bulk request.
|
|
512
|
+
*/
|
|
513
|
+
doBulkRequest(params, bulkRequestFunc) {
|
|
514
|
+
if (this.#currentBatch.length >= this.#batchSizeLimit) {
|
|
515
|
+
this.#currentBatch = [];
|
|
516
|
+
this.#currentBulkResponse = null;
|
|
517
|
+
}
|
|
518
|
+
this.#currentBatch.push(params);
|
|
519
|
+
if (this.#currentBulkResponse != null) {
|
|
520
|
+
return this.#currentBulkResponse;
|
|
521
|
+
}
|
|
522
|
+
const batch = this.#currentBatch;
|
|
523
|
+
this.#currentBulkResponse = new Promise((resolve, reject) => {
|
|
524
|
+
setTimeout(() => {
|
|
525
|
+
this.#currentBulkResponse = null;
|
|
526
|
+
const batchCopy = batch.splice(0, batch.length);
|
|
527
|
+
bulkRequestFunc(batchCopy).then((result) => {
|
|
528
|
+
resolve(result);
|
|
529
|
+
}).catch((err) => {
|
|
530
|
+
reject(err);
|
|
531
|
+
});
|
|
532
|
+
}, 0);
|
|
533
|
+
});
|
|
534
|
+
return this.#currentBulkResponse;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
71
537
|
|
|
72
|
-
// src/
|
|
73
|
-
|
|
74
|
-
var
|
|
538
|
+
// src/calls/util/calls-service.ts
|
|
539
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/calls/util/calls-service.ts";
|
|
540
|
+
var NETWORK_TIMEOUT = 5e3;
|
|
541
|
+
var CallsServicePeer = class extends Resource2 {
|
|
542
|
+
history = new HistoryCache(100);
|
|
543
|
+
_persistentLifecycle = new PersistentLifecycle({
|
|
544
|
+
start: () => this._startSession(),
|
|
545
|
+
stop: (session) => this._stopSession(session)
|
|
546
|
+
});
|
|
547
|
+
_config;
|
|
548
|
+
taskScheduler = new FIFOScheduler();
|
|
549
|
+
pushTrackDispatcher = new BulkRequestDispatcher(32);
|
|
550
|
+
pullTrackDispatcher = new BulkRequestDispatcher(32);
|
|
551
|
+
closeTrackDispatcher = new BulkRequestDispatcher(32);
|
|
552
|
+
constructor(config) {
|
|
553
|
+
super();
|
|
554
|
+
this._config = config;
|
|
555
|
+
}
|
|
556
|
+
async _open(ctx) {
|
|
557
|
+
await this._persistentLifecycle.open(ctx);
|
|
558
|
+
}
|
|
559
|
+
async _close() {
|
|
560
|
+
await this._persistentLifecycle.close();
|
|
561
|
+
}
|
|
562
|
+
get session() {
|
|
563
|
+
return this._persistentLifecycle.state;
|
|
564
|
+
}
|
|
565
|
+
async _startSession() {
|
|
566
|
+
const peerConnection = await this._createRtcConnection();
|
|
567
|
+
const sessionId = await this._initiateCallSession();
|
|
568
|
+
return {
|
|
569
|
+
sessionId,
|
|
570
|
+
peerConnection
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
async _stopSession(session) {
|
|
574
|
+
session.peerConnection.close();
|
|
575
|
+
}
|
|
576
|
+
async _createRtcConnection() {
|
|
577
|
+
const peerConnection = new RTCPeerConnection({
|
|
578
|
+
iceServers: this._config.iceServers,
|
|
579
|
+
bundlePolicy: "max-bundle"
|
|
580
|
+
});
|
|
581
|
+
peerConnection.addEventListener("connectionstatechange", () => {
|
|
582
|
+
if (peerConnection.connectionState === "failed" || peerConnection.connectionState === "closed") {
|
|
583
|
+
log2.info("calls connection failed", {
|
|
584
|
+
state: peerConnection.connectionState
|
|
585
|
+
}, {
|
|
586
|
+
F: __dxlog_file3,
|
|
587
|
+
L: 120,
|
|
588
|
+
S: this,
|
|
589
|
+
C: (f, a) => f(...a)
|
|
590
|
+
});
|
|
591
|
+
void this._persistentLifecycle.scheduleRestart();
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
let iceTimeout = -1;
|
|
595
|
+
peerConnection.addEventListener("iceconnectionstatechange", () => {
|
|
596
|
+
clearTimeout(iceTimeout);
|
|
597
|
+
if (peerConnection.iceConnectionState === "failed" || peerConnection.iceConnectionState === "closed") {
|
|
598
|
+
log2.info("calls connection to ICEs failed", {
|
|
599
|
+
state: peerConnection.iceConnectionState
|
|
600
|
+
}, {
|
|
601
|
+
F: __dxlog_file3,
|
|
602
|
+
L: 129,
|
|
603
|
+
S: this,
|
|
604
|
+
C: (f, a) => f(...a)
|
|
605
|
+
});
|
|
606
|
+
void this._persistentLifecycle.scheduleRestart();
|
|
607
|
+
} else if (peerConnection.iceConnectionState === "disconnected") {
|
|
608
|
+
const timeoutSeconds = 7;
|
|
609
|
+
iceTimeout = window.setTimeout(() => {
|
|
610
|
+
if (peerConnection.iceConnectionState === "connected") {
|
|
611
|
+
log2.info("calls iceConnectionState is connected", void 0, {
|
|
612
|
+
F: __dxlog_file3,
|
|
613
|
+
L: 138,
|
|
614
|
+
S: this,
|
|
615
|
+
C: (f, a) => f(...a)
|
|
616
|
+
});
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
log2.info("calls iceConnectionState timed out", {
|
|
620
|
+
state: peerConnection.iceConnectionState,
|
|
621
|
+
timeoutSeconds
|
|
622
|
+
}, {
|
|
623
|
+
F: __dxlog_file3,
|
|
624
|
+
L: 142,
|
|
625
|
+
S: this,
|
|
626
|
+
C: (f, a) => f(...a)
|
|
627
|
+
});
|
|
628
|
+
void this._persistentLifecycle.scheduleRestart();
|
|
629
|
+
}, timeoutSeconds * 1e3);
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
return peerConnection;
|
|
633
|
+
}
|
|
634
|
+
async _initiateCallSession() {
|
|
635
|
+
log2("creating new session", void 0, {
|
|
636
|
+
F: __dxlog_file3,
|
|
637
|
+
L: 152,
|
|
638
|
+
S: this,
|
|
639
|
+
C: (f, a) => f(...a)
|
|
640
|
+
});
|
|
641
|
+
const { sessionId } = await this._fetch("/sessions/new?SESSION", {
|
|
642
|
+
method: "POST"
|
|
643
|
+
});
|
|
644
|
+
return sessionId;
|
|
645
|
+
}
|
|
646
|
+
async _fetch(relativePath, requestInit) {
|
|
647
|
+
this.history.push({
|
|
648
|
+
endpoint: relativePath,
|
|
649
|
+
type: "request",
|
|
650
|
+
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
651
|
+
method: requestInit?.method ?? "GET",
|
|
652
|
+
body: requestInit?.body
|
|
653
|
+
});
|
|
654
|
+
const response = await fetch(`${this._config.apiBase}${relativePath}`, {
|
|
655
|
+
...requestInit,
|
|
656
|
+
redirect: "manual"
|
|
657
|
+
});
|
|
658
|
+
if (response.status >= 400) {
|
|
659
|
+
log2.error("error while fetching from Calls service", {
|
|
660
|
+
status: response.status,
|
|
661
|
+
text: await response.text()
|
|
662
|
+
}, {
|
|
663
|
+
F: __dxlog_file3,
|
|
664
|
+
L: 168,
|
|
665
|
+
S: this,
|
|
666
|
+
C: (f, a) => f(...a)
|
|
667
|
+
});
|
|
668
|
+
throw new Error("Error while fetching from Calls service");
|
|
669
|
+
}
|
|
670
|
+
try {
|
|
671
|
+
const data = await response.clone().json();
|
|
672
|
+
this.history.push({
|
|
673
|
+
endpoint: relativePath,
|
|
674
|
+
type: "response",
|
|
675
|
+
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
676
|
+
status: response.status,
|
|
677
|
+
json: data
|
|
678
|
+
});
|
|
679
|
+
if (data.errorCode) {
|
|
680
|
+
throw new Error(data.errorDescription);
|
|
681
|
+
}
|
|
682
|
+
return data;
|
|
683
|
+
} catch (error) {
|
|
684
|
+
const text = await response.text();
|
|
685
|
+
this.history.push({
|
|
686
|
+
endpoint: relativePath,
|
|
687
|
+
type: "response",
|
|
688
|
+
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
689
|
+
status: response.status,
|
|
690
|
+
text
|
|
691
|
+
});
|
|
692
|
+
log2.error("Error parsing response from Calls service", {
|
|
693
|
+
error,
|
|
694
|
+
text,
|
|
695
|
+
status: response.status
|
|
696
|
+
}, {
|
|
697
|
+
F: __dxlog_file3,
|
|
698
|
+
L: 195,
|
|
699
|
+
S: this,
|
|
700
|
+
C: (f, a) => f(...a)
|
|
701
|
+
});
|
|
702
|
+
throw error;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
async _pushTrackInBulk({ ctx, peerConnection, transceiver, sessionId, trackName }) {
|
|
706
|
+
log2.verbose("pushing track ", trackName, {
|
|
707
|
+
F: __dxlog_file3,
|
|
708
|
+
L: 217,
|
|
709
|
+
S: this,
|
|
710
|
+
C: (f, a) => f(...a)
|
|
711
|
+
});
|
|
712
|
+
const pushedTrackPromise = this.pushTrackDispatcher.doBulkRequest({
|
|
713
|
+
trackName,
|
|
714
|
+
transceiver
|
|
715
|
+
}, (tracks) => this.taskScheduler.schedule(async () => {
|
|
716
|
+
const offer = await peerConnection.createOffer();
|
|
717
|
+
offer.sdp = offer.sdp?.replace("useinbandfec=1", "usedtx=1;useinbandfec=1");
|
|
718
|
+
await peerConnection.setLocalDescription(offer);
|
|
719
|
+
const response = await this._fetch(`/sessions/${sessionId}/tracks/new?PUSHING`, {
|
|
720
|
+
method: "POST",
|
|
721
|
+
body: JSON.stringify({
|
|
722
|
+
sessionDescription: {
|
|
723
|
+
sdp: offer.sdp,
|
|
724
|
+
type: "offer"
|
|
725
|
+
},
|
|
726
|
+
tracks: tracks.map(({ trackName: trackName2, transceiver: transceiver2 }) => ({
|
|
727
|
+
trackName: trackName2,
|
|
728
|
+
mid: transceiver2.mid,
|
|
729
|
+
location: "local"
|
|
730
|
+
}))
|
|
731
|
+
})
|
|
732
|
+
});
|
|
733
|
+
invariant3(response.tracks !== void 0, void 0, {
|
|
734
|
+
F: __dxlog_file3,
|
|
735
|
+
L: 242,
|
|
736
|
+
S: this,
|
|
737
|
+
A: [
|
|
738
|
+
"response.tracks !== undefined",
|
|
739
|
+
""
|
|
740
|
+
]
|
|
741
|
+
});
|
|
742
|
+
if (!response.errorCode) {
|
|
743
|
+
await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));
|
|
744
|
+
await peerConnectionIsConnected(peerConnection);
|
|
745
|
+
}
|
|
746
|
+
return {
|
|
747
|
+
tracks: response.tracks
|
|
748
|
+
};
|
|
749
|
+
})).then(async ({ tracks }) => {
|
|
750
|
+
const trackData = tracks.find((t) => t.mid === transceiver.mid);
|
|
751
|
+
if (trackData) {
|
|
752
|
+
return {
|
|
753
|
+
...trackData,
|
|
754
|
+
sessionId,
|
|
755
|
+
location: "remote"
|
|
756
|
+
};
|
|
757
|
+
} else {
|
|
758
|
+
log2.error("missing track data", void 0, {
|
|
759
|
+
F: __dxlog_file3,
|
|
760
|
+
L: 266,
|
|
761
|
+
S: this,
|
|
762
|
+
C: (f, a) => f(...a)
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
const onDispose = async () => {
|
|
767
|
+
if (transceiver.mid) {
|
|
768
|
+
await this._closeTrackInBulk(peerConnection, transceiver.mid, sessionId);
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
ctx?.onDispose(async () => await onDispose());
|
|
772
|
+
this._ctx.onDispose(() => onDispose());
|
|
773
|
+
return pushedTrackPromise;
|
|
774
|
+
}
|
|
775
|
+
async pushTrack({ track, encodings = [], ctx, previousTrack }) {
|
|
776
|
+
await this.waitUntilOpen();
|
|
777
|
+
invariant3(this.session, void 0, {
|
|
778
|
+
F: __dxlog_file3,
|
|
779
|
+
L: 294,
|
|
780
|
+
S: this,
|
|
781
|
+
A: [
|
|
782
|
+
"this.session",
|
|
783
|
+
""
|
|
784
|
+
]
|
|
785
|
+
});
|
|
786
|
+
log2("trying to push track", {
|
|
787
|
+
track,
|
|
788
|
+
previousTrack,
|
|
789
|
+
encodings
|
|
790
|
+
}, {
|
|
791
|
+
F: __dxlog_file3,
|
|
792
|
+
L: 295,
|
|
793
|
+
S: this,
|
|
794
|
+
C: (f, a) => f(...a)
|
|
795
|
+
});
|
|
796
|
+
if (previousTrack) {
|
|
797
|
+
const transceiver2 = this.session.peerConnection.getTransceivers().find((t) => t.mid === previousTrack.mid);
|
|
798
|
+
if (transceiver2?.sender.track === track) {
|
|
799
|
+
log2.verbose("track already pushed", {
|
|
800
|
+
track,
|
|
801
|
+
previousTrack,
|
|
802
|
+
transceiver: transceiver2
|
|
803
|
+
}, {
|
|
804
|
+
F: __dxlog_file3,
|
|
805
|
+
L: 299,
|
|
806
|
+
S: this,
|
|
807
|
+
C: (f, a) => f(...a)
|
|
808
|
+
});
|
|
809
|
+
return previousTrack;
|
|
810
|
+
} else if (transceiver2) {
|
|
811
|
+
log2.verbose("replacing track", {
|
|
812
|
+
track,
|
|
813
|
+
previousTrack,
|
|
814
|
+
transceiver: transceiver2
|
|
815
|
+
}, {
|
|
816
|
+
F: __dxlog_file3,
|
|
817
|
+
L: 302,
|
|
818
|
+
S: this,
|
|
819
|
+
C: (f, a) => f(...a)
|
|
820
|
+
});
|
|
821
|
+
transceiver2.sender.replaceTrack(track).catch((err) => log2.catch(err, void 0, {
|
|
822
|
+
F: __dxlog_file3,
|
|
823
|
+
L: 303,
|
|
824
|
+
S: this,
|
|
825
|
+
C: (f, a) => f(...a)
|
|
826
|
+
}));
|
|
827
|
+
return previousTrack;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
invariant3(track, void 0, {
|
|
831
|
+
F: __dxlog_file3,
|
|
832
|
+
L: 307,
|
|
833
|
+
S: this,
|
|
834
|
+
A: [
|
|
835
|
+
"track",
|
|
836
|
+
""
|
|
837
|
+
]
|
|
838
|
+
});
|
|
839
|
+
const stableId = crypto.randomUUID();
|
|
840
|
+
const transceiver = this.session.peerConnection.addTransceiver(track, {
|
|
841
|
+
direction: "sendonly"
|
|
842
|
+
});
|
|
843
|
+
log2.verbose("creating transceiver", void 0, {
|
|
844
|
+
F: __dxlog_file3,
|
|
845
|
+
L: 312,
|
|
846
|
+
S: this,
|
|
847
|
+
C: (f, a) => f(...a)
|
|
848
|
+
});
|
|
849
|
+
const pushedTrackData = await this._pushTrackInBulk({
|
|
850
|
+
ctx,
|
|
851
|
+
peerConnection: this.session.peerConnection,
|
|
852
|
+
transceiver,
|
|
853
|
+
sessionId: this.session.sessionId,
|
|
854
|
+
trackName: stableId
|
|
855
|
+
});
|
|
856
|
+
invariant3(pushedTrackData, void 0, {
|
|
857
|
+
F: __dxlog_file3,
|
|
858
|
+
L: 321,
|
|
859
|
+
S: this,
|
|
860
|
+
A: [
|
|
861
|
+
"pushedTrackData",
|
|
862
|
+
""
|
|
863
|
+
]
|
|
864
|
+
});
|
|
865
|
+
const parameters = transceiver.sender.getParameters();
|
|
866
|
+
encodings.forEach((encoding, i) => {
|
|
867
|
+
const existing = parameters.encodings[i];
|
|
868
|
+
parameters.encodings[i] = {
|
|
869
|
+
...existing,
|
|
870
|
+
...encoding
|
|
871
|
+
};
|
|
872
|
+
});
|
|
873
|
+
transceiver.sender.setParameters(parameters).catch((err) => log2.catch(err, void 0, {
|
|
874
|
+
F: __dxlog_file3,
|
|
875
|
+
L: 328,
|
|
876
|
+
S: this,
|
|
877
|
+
C: (f, a) => f(...a)
|
|
878
|
+
}));
|
|
879
|
+
return pushedTrackData;
|
|
880
|
+
}
|
|
881
|
+
// TODO(mykola): Add retry logic if the tracks fails to pull.
|
|
882
|
+
async _pullTrackInBulk({ peerConnection, sessionId, trackData, ctx }) {
|
|
883
|
+
let mid = "";
|
|
884
|
+
log2("pulling track", {
|
|
885
|
+
trackName: trackData.trackName
|
|
886
|
+
}, {
|
|
887
|
+
F: __dxlog_file3,
|
|
888
|
+
L: 346,
|
|
889
|
+
S: this,
|
|
890
|
+
C: (f, a) => f(...a)
|
|
891
|
+
});
|
|
892
|
+
const pulledTrackPromise = this.pullTrackDispatcher.doBulkRequest(trackData, (tracks) => this.taskScheduler.schedule(async () => {
|
|
893
|
+
const newTrackResponse = await this._fetch(`/sessions/${sessionId}/tracks/new?PULLING`, {
|
|
894
|
+
method: "POST",
|
|
895
|
+
body: JSON.stringify({
|
|
896
|
+
tracks
|
|
897
|
+
})
|
|
898
|
+
});
|
|
899
|
+
if (newTrackResponse.errorCode) {
|
|
900
|
+
throw new Error(newTrackResponse.errorDescription);
|
|
901
|
+
}
|
|
902
|
+
invariant3(newTrackResponse.tracks, void 0, {
|
|
903
|
+
F: __dxlog_file3,
|
|
904
|
+
L: 359,
|
|
905
|
+
S: this,
|
|
906
|
+
A: [
|
|
907
|
+
"newTrackResponse.tracks",
|
|
908
|
+
""
|
|
909
|
+
]
|
|
910
|
+
});
|
|
911
|
+
const trackMap = tracks.reduce((acc, track) => {
|
|
912
|
+
const pulledTrackData = newTrackResponse.tracks?.find((t) => t.trackName === track.trackName && t.sessionId === track.sessionId);
|
|
913
|
+
if (pulledTrackData && pulledTrackData.mid) {
|
|
914
|
+
acc.set(track.trackName, {
|
|
915
|
+
mid: pulledTrackData.mid,
|
|
916
|
+
resolvedTrack: resolveTrack(peerConnection, (t) => t.mid === pulledTrackData.mid)
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
return acc;
|
|
920
|
+
}, /* @__PURE__ */ new Map());
|
|
921
|
+
if (newTrackResponse.requiresImmediateRenegotiation) {
|
|
922
|
+
await peerConnection.setRemoteDescription(new RTCSessionDescription(newTrackResponse.sessionDescription));
|
|
923
|
+
const answer = await peerConnection.createAnswer();
|
|
924
|
+
await peerConnection.setLocalDescription(answer);
|
|
925
|
+
const renegotiationResponse = await this._fetch(`/sessions/${sessionId}/renegotiate`, {
|
|
926
|
+
method: "PUT",
|
|
927
|
+
body: JSON.stringify({
|
|
928
|
+
sessionDescription: {
|
|
929
|
+
type: "answer",
|
|
930
|
+
sdp: peerConnection.currentLocalDescription?.sdp
|
|
931
|
+
}
|
|
932
|
+
})
|
|
933
|
+
});
|
|
934
|
+
if (renegotiationResponse.errorCode) {
|
|
935
|
+
throw new Error(renegotiationResponse.errorDescription);
|
|
936
|
+
} else {
|
|
937
|
+
await peerConnectionIsConnected(peerConnection);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
trackMap
|
|
942
|
+
};
|
|
943
|
+
})).then(({ trackMap }) => {
|
|
944
|
+
const trackInfo = trackMap.get(trackData.trackName);
|
|
945
|
+
if (trackInfo) {
|
|
946
|
+
return trackInfo.resolvedTrack.then((track) => {
|
|
947
|
+
mid = trackInfo.mid;
|
|
948
|
+
return track;
|
|
949
|
+
}).catch((err) => log2.catch(err, void 0, {
|
|
950
|
+
F: __dxlog_file3,
|
|
951
|
+
L: 411,
|
|
952
|
+
S: this,
|
|
953
|
+
C: (f, a) => f(...a)
|
|
954
|
+
}));
|
|
955
|
+
} else {
|
|
956
|
+
log2.info("missing track info", {
|
|
957
|
+
trackData,
|
|
958
|
+
availableTracks: Array.from(trackMap.keys())
|
|
959
|
+
}, {
|
|
960
|
+
F: __dxlog_file3,
|
|
961
|
+
L: 413,
|
|
962
|
+
S: this,
|
|
963
|
+
C: (f, a) => f(...a)
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
const onDispose = async () => {
|
|
968
|
+
if (mid) {
|
|
969
|
+
log2("closing pulled track ", trackData.trackName, {
|
|
970
|
+
F: __dxlog_file3,
|
|
971
|
+
L: 419,
|
|
972
|
+
S: this,
|
|
973
|
+
C: (f, a) => f(...a)
|
|
974
|
+
});
|
|
975
|
+
await this._closeTrackInBulk(peerConnection, mid, sessionId);
|
|
976
|
+
mid = "";
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
this._ctx.onDispose(() => onDispose());
|
|
980
|
+
ctx?.onDispose(() => onDispose());
|
|
981
|
+
return pulledTrackPromise;
|
|
982
|
+
}
|
|
983
|
+
async pullTrack({ ctx, trackData }) {
|
|
984
|
+
await this.waitUntilOpen();
|
|
985
|
+
invariant3(this.session, void 0, {
|
|
986
|
+
F: __dxlog_file3,
|
|
987
|
+
L: 440,
|
|
988
|
+
S: this,
|
|
989
|
+
A: [
|
|
990
|
+
"this.session",
|
|
991
|
+
""
|
|
992
|
+
]
|
|
993
|
+
});
|
|
994
|
+
const session = this.session;
|
|
995
|
+
return this._pullTrackInBulk({
|
|
996
|
+
peerConnection: session.peerConnection,
|
|
997
|
+
sessionId: session.sessionId,
|
|
998
|
+
trackData,
|
|
999
|
+
ctx
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
async _closeTrackInBulk(peerConnection, mid, sessionId) {
|
|
1003
|
+
const transceiver = peerConnection.getTransceivers().find((t) => t.mid === mid);
|
|
1004
|
+
if (peerConnection.connectionState !== "connected" || transceiver === void 0) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
await this.closeTrackDispatcher.doBulkRequest({
|
|
1008
|
+
mid
|
|
1009
|
+
}, (mids) => this.taskScheduler.schedule(async () => {
|
|
1010
|
+
transceiver.stop();
|
|
1011
|
+
const activeTransceivers = peerConnection.getTransceivers().filter((t) => t.mid !== mid && t.direction !== "stopped");
|
|
1012
|
+
let requestBody;
|
|
1013
|
+
if (activeTransceivers.length > 0) {
|
|
1014
|
+
const offer = await peerConnection.createOffer();
|
|
1015
|
+
await peerConnection.setLocalDescription(offer);
|
|
1016
|
+
requestBody = {
|
|
1017
|
+
tracks: mids,
|
|
1018
|
+
sessionDescription: {
|
|
1019
|
+
sdp: peerConnection.localDescription?.sdp,
|
|
1020
|
+
type: "offer"
|
|
1021
|
+
},
|
|
1022
|
+
force: false
|
|
1023
|
+
};
|
|
1024
|
+
} else {
|
|
1025
|
+
requestBody = {
|
|
1026
|
+
tracks: mids,
|
|
1027
|
+
force: true
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
const response = await this._fetch(`/sessions/${sessionId}/tracks/close`, {
|
|
1031
|
+
method: "PUT",
|
|
1032
|
+
body: JSON.stringify(requestBody)
|
|
1033
|
+
});
|
|
1034
|
+
if (requestBody.sessionDescription) {
|
|
1035
|
+
await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));
|
|
1036
|
+
}
|
|
1037
|
+
}));
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
var resolveTrack = async (peerConnection, compare, timeout = NETWORK_TIMEOUT) => new Promise((resolve, reject) => {
|
|
1041
|
+
setTimeout(reject, timeout);
|
|
1042
|
+
const handler = () => {
|
|
1043
|
+
const transceiver = peerConnection.getTransceivers().find(compare);
|
|
1044
|
+
if (transceiver) {
|
|
1045
|
+
resolve(transceiver.receiver.track);
|
|
1046
|
+
peerConnection.removeEventListener("track", handler);
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
peerConnection.addEventListener("track", handler);
|
|
1050
|
+
});
|
|
1051
|
+
var peerConnectionIsConnected = async (peerConnection) => {
|
|
1052
|
+
if (peerConnection.connectionState !== "connected") {
|
|
1053
|
+
const connected = new Promise((resolve, reject) => {
|
|
1054
|
+
const timeout = setTimeout(() => {
|
|
1055
|
+
peerConnection.removeEventListener("connectionstatechange", connectionStateChangeHandler);
|
|
1056
|
+
reject(new Error("Connection timeout"));
|
|
1057
|
+
}, NETWORK_TIMEOUT);
|
|
1058
|
+
const connectionStateChangeHandler = () => {
|
|
1059
|
+
if (peerConnection.connectionState === "connected") {
|
|
1060
|
+
peerConnection.removeEventListener("connectionstatechange", connectionStateChangeHandler);
|
|
1061
|
+
clearTimeout(timeout);
|
|
1062
|
+
resolve(void 0);
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
peerConnection.addEventListener("connectionstatechange", connectionStateChangeHandler);
|
|
1066
|
+
});
|
|
1067
|
+
await connected;
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
75
1070
|
|
|
76
|
-
// src/
|
|
77
|
-
import {
|
|
78
|
-
var
|
|
1071
|
+
// src/calls/util/media.ts
|
|
1072
|
+
import { log as log3 } from "@dxos/log";
|
|
1073
|
+
var __dxlog_file4 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/calls/util/media.ts";
|
|
1074
|
+
var getUserMediaTrack = async (kind, constraints = {}, deviceList) => {
|
|
1075
|
+
deviceList ??= (await getDeviceList()).filter((device) => device.kind === kind);
|
|
1076
|
+
const firstDevice = deviceList[0];
|
|
1077
|
+
if (!firstDevice) {
|
|
1078
|
+
throw new Error("No devices found");
|
|
1079
|
+
}
|
|
1080
|
+
return acquireTrack(firstDevice, constraints);
|
|
1081
|
+
};
|
|
1082
|
+
var acquireTrack = async (device, constraints) => {
|
|
1083
|
+
const { deviceId, label } = device;
|
|
1084
|
+
log3.info(`requesting ${label}`, void 0, {
|
|
1085
|
+
F: __dxlog_file4,
|
|
1086
|
+
L: 23,
|
|
1087
|
+
S: void 0,
|
|
1088
|
+
C: (f, a) => f(...a)
|
|
1089
|
+
});
|
|
1090
|
+
const mediaStream = await navigator.mediaDevices.getUserMedia(device.kind === "videoinput" ? {
|
|
1091
|
+
video: {
|
|
1092
|
+
...constraints,
|
|
1093
|
+
deviceId
|
|
1094
|
+
}
|
|
1095
|
+
} : {
|
|
1096
|
+
audio: {
|
|
1097
|
+
...constraints,
|
|
1098
|
+
deviceId
|
|
1099
|
+
}
|
|
1100
|
+
});
|
|
1101
|
+
return device.kind === "videoinput" ? mediaStream.getVideoTracks()[0] : mediaStream.getAudioTracks()[0];
|
|
1102
|
+
};
|
|
1103
|
+
var getDeviceList = () => navigator.mediaDevices.enumerateDevices();
|
|
1104
|
+
var SCREENSHARE_CONSTRAINTS = {
|
|
1105
|
+
video: {
|
|
1106
|
+
width: {
|
|
1107
|
+
max: 1920
|
|
1108
|
+
},
|
|
1109
|
+
height: {
|
|
1110
|
+
max: 1080
|
|
1111
|
+
},
|
|
1112
|
+
frameRate: {
|
|
1113
|
+
max: 10
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
var getScreenshare = async ({ contentHint }) => {
|
|
1118
|
+
const ms = await navigator.mediaDevices.getDisplayMedia(SCREENSHARE_CONSTRAINTS);
|
|
1119
|
+
ms.getVideoTracks().forEach((track) => {
|
|
1120
|
+
if (contentHint && "contentHint" in track) {
|
|
1121
|
+
track.contentHint = contentHint;
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
return ms;
|
|
1125
|
+
};
|
|
79
1126
|
|
|
80
|
-
// src/
|
|
81
|
-
import {
|
|
82
|
-
|
|
1127
|
+
// src/calls/util/stub-media-streams.ts
|
|
1128
|
+
import { scheduleTaskInterval as scheduleTaskInterval2, waitForCondition } from "@dxos/async";
|
|
1129
|
+
import { cancelWithContext } from "@dxos/context";
|
|
1130
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
1131
|
+
var __dxlog_file5 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/calls/util/stub-media-streams.ts";
|
|
1132
|
+
var createBlackCanvasStreamTrack = async ({ ctx, width, height }) => {
|
|
1133
|
+
const canvas = document.createElement("canvas");
|
|
1134
|
+
canvas.width = width;
|
|
1135
|
+
canvas.height = height;
|
|
1136
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1137
|
+
invariant4(canvasCtx, void 0, {
|
|
1138
|
+
F: __dxlog_file5,
|
|
1139
|
+
L: 28,
|
|
1140
|
+
S: void 0,
|
|
1141
|
+
A: [
|
|
1142
|
+
"canvasCtx",
|
|
1143
|
+
""
|
|
1144
|
+
]
|
|
1145
|
+
});
|
|
1146
|
+
const drawFrame = () => {
|
|
1147
|
+
canvasCtx.fillStyle = "black";
|
|
1148
|
+
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
|
|
1149
|
+
};
|
|
1150
|
+
scheduleTaskInterval2(ctx, async () => drawFrame(), 200);
|
|
1151
|
+
const track = canvas.captureStream().getVideoTracks()[0];
|
|
1152
|
+
drawFrame();
|
|
1153
|
+
await cancelWithContext(ctx, waitForCondition({
|
|
1154
|
+
condition: () => track.readyState === "live",
|
|
1155
|
+
timeout: 1e3
|
|
1156
|
+
}));
|
|
1157
|
+
return track;
|
|
1158
|
+
};
|
|
1159
|
+
var audioContextStartedPreviously = false;
|
|
1160
|
+
var userGestureEvents = [
|
|
1161
|
+
"click",
|
|
1162
|
+
"contextmenu",
|
|
1163
|
+
"auxclick",
|
|
1164
|
+
"dblclick",
|
|
1165
|
+
"mousedown",
|
|
1166
|
+
"mouseup",
|
|
1167
|
+
"pointerup",
|
|
1168
|
+
"touchend",
|
|
1169
|
+
"keydown",
|
|
1170
|
+
"keyup"
|
|
1171
|
+
];
|
|
1172
|
+
var createInaudibleAudioStreamTrack = async ({ ctx }) => {
|
|
1173
|
+
const audioContext = new window.AudioContext();
|
|
1174
|
+
const oscillator = audioContext.createOscillator();
|
|
1175
|
+
oscillator.type = "triangle";
|
|
1176
|
+
oscillator.frequency.setValueAtTime(20, audioContext.currentTime);
|
|
1177
|
+
const gainNode = audioContext.createGain();
|
|
1178
|
+
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
|
|
1179
|
+
oscillator.connect(gainNode);
|
|
1180
|
+
const destination = audioContext.createMediaStreamDestination();
|
|
1181
|
+
gainNode.connect(destination);
|
|
1182
|
+
let oscillatorStarted = false;
|
|
1183
|
+
const ensureOscillatorStarted = () => {
|
|
1184
|
+
if (oscillatorStarted) return;
|
|
1185
|
+
oscillator.start();
|
|
1186
|
+
oscillatorStarted = true;
|
|
1187
|
+
};
|
|
1188
|
+
const stateChangeHandler = () => {
|
|
1189
|
+
if (audioContext.state === "running") {
|
|
1190
|
+
audioContextStartedPreviously = true;
|
|
1191
|
+
ensureOscillatorStarted();
|
|
1192
|
+
}
|
|
1193
|
+
if (audioContext.state === "suspended" || audioContext.state === "interrupted") {
|
|
1194
|
+
resumeAudioContext();
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
audioContext.addEventListener("statechange", stateChangeHandler);
|
|
1198
|
+
const resumeAudioContext = () => {
|
|
1199
|
+
void audioContext.resume().then(() => {
|
|
1200
|
+
cleanUpUserGestureListeners();
|
|
1201
|
+
});
|
|
1202
|
+
};
|
|
1203
|
+
const cleanUpUserGestureListeners = () => {
|
|
1204
|
+
userGestureEvents.forEach((gesture) => {
|
|
1205
|
+
document.removeEventListener(gesture, resumeAudioContext, {
|
|
1206
|
+
capture: true
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
};
|
|
1210
|
+
if (audioContextStartedPreviously) {
|
|
1211
|
+
resumeAudioContext();
|
|
1212
|
+
} else {
|
|
1213
|
+
userGestureEvents.forEach((gesture) => {
|
|
1214
|
+
document.addEventListener(gesture, resumeAudioContext, {
|
|
1215
|
+
capture: true
|
|
1216
|
+
});
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
ctx.onDispose(async () => {
|
|
1220
|
+
cleanUpUserGestureListeners();
|
|
1221
|
+
oscillator.disconnect();
|
|
1222
|
+
oscillator.stop();
|
|
1223
|
+
await audioContext.close();
|
|
1224
|
+
});
|
|
1225
|
+
return destination.stream.getAudioTracks()[0];
|
|
1226
|
+
};
|
|
83
1227
|
|
|
84
|
-
// src/
|
|
85
|
-
|
|
86
|
-
var
|
|
1228
|
+
// src/calls/speaking-monitor.ts
|
|
1229
|
+
var NOT_SPEAKING_AFTER = 500;
|
|
1230
|
+
var START_SPEAKING_THRESHOLD = 0.05;
|
|
1231
|
+
var CONTINUE_SPEAKING_THRESHOLD = 0.02;
|
|
1232
|
+
var MIN_EVENT_INTERVAL = 100;
|
|
1233
|
+
var SpeakingMonitor = class extends Resource3 {
|
|
1234
|
+
_mediaStreamTrack;
|
|
1235
|
+
/**
|
|
1236
|
+
* Event that is emitted when the user starts or stops speaking.
|
|
1237
|
+
* It is debounced to prevent rapid state changes.
|
|
1238
|
+
*/
|
|
1239
|
+
speakingChanged = new Event2();
|
|
1240
|
+
/**
|
|
1241
|
+
* Real state of the user speaking.
|
|
1242
|
+
*/
|
|
1243
|
+
_isSpeaking = false;
|
|
1244
|
+
_lastEventTime = 0;
|
|
1245
|
+
_deferredUpdate;
|
|
1246
|
+
constructor(_mediaStreamTrack) {
|
|
1247
|
+
super(), this._mediaStreamTrack = _mediaStreamTrack;
|
|
1248
|
+
}
|
|
1249
|
+
get isSpeaking() {
|
|
1250
|
+
return this._isSpeaking;
|
|
1251
|
+
}
|
|
1252
|
+
async _open() {
|
|
1253
|
+
this._deferredUpdate = new DeferredTask2(this._ctx, async () => this._emitSpeakingChanged());
|
|
1254
|
+
let timeout;
|
|
1255
|
+
const cleanup = monitorAudioLevel({
|
|
1256
|
+
mediaStreamTrack: this._mediaStreamTrack,
|
|
1257
|
+
onMeasure: (vol) => {
|
|
1258
|
+
const audioLevelAboveThreshold = vol > (this._isSpeaking ? CONTINUE_SPEAKING_THRESHOLD : START_SPEAKING_THRESHOLD);
|
|
1259
|
+
if (audioLevelAboveThreshold) {
|
|
1260
|
+
clearTimeout(timeout);
|
|
1261
|
+
timeout = void 0;
|
|
1262
|
+
if (!this._isSpeaking) {
|
|
1263
|
+
this._isSpeaking = true;
|
|
1264
|
+
this._deferredUpdate?.schedule();
|
|
1265
|
+
}
|
|
1266
|
+
} else if (timeout === void 0) {
|
|
1267
|
+
timeout = setTimeout(() => {
|
|
1268
|
+
this._isSpeaking = false;
|
|
1269
|
+
timeout = void 0;
|
|
1270
|
+
this._deferredUpdate?.schedule();
|
|
1271
|
+
}, NOT_SPEAKING_AFTER);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
this._ctx.onDispose(() => {
|
|
1276
|
+
cleanup();
|
|
1277
|
+
clearTimeout(timeout);
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Emits the speaking changed event with debouncing based on timing.
|
|
1282
|
+
*/
|
|
1283
|
+
async _emitSpeakingChanged() {
|
|
1284
|
+
const timeSinceLastEvent = Date.now() - this._lastEventTime;
|
|
1285
|
+
const timeToNextEvent = MIN_EVENT_INTERVAL - timeSinceLastEvent;
|
|
1286
|
+
if (timeToNextEvent > 0) {
|
|
1287
|
+
await sleep(timeToNextEvent);
|
|
1288
|
+
}
|
|
1289
|
+
this._lastEventTime = Date.now();
|
|
1290
|
+
this.speakingChanged.emit(this._isSpeaking);
|
|
1291
|
+
}
|
|
1292
|
+
};
|
|
1293
|
+
|
|
1294
|
+
// src/calls/media-manager.ts
|
|
1295
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
1296
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1297
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1298
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1299
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1300
|
+
}
|
|
1301
|
+
var __dxlog_file6 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/calls/media-manager.ts";
|
|
1302
|
+
var VIDEO_WIDTH = 1280;
|
|
1303
|
+
var VIDEO_HEIGHT = 720;
|
|
1304
|
+
var MAX_WEB_CAM_FRAMERATE = 24;
|
|
1305
|
+
var MAX_WEB_CAM_BITRATE = 12e5;
|
|
1306
|
+
var RETRY_INTERVAL = 100;
|
|
1307
|
+
var USE_INAUDIBLE_AUDIO = true;
|
|
1308
|
+
var MediaManager = class extends Resource4 {
|
|
1309
|
+
stateUpdated = new Event3();
|
|
1310
|
+
_state = {
|
|
1311
|
+
pulledVideoStreams: {},
|
|
1312
|
+
pulledAudioTracks: {}
|
|
1313
|
+
};
|
|
1314
|
+
_speakingMonitor = void 0;
|
|
1315
|
+
_trackToReconcile = [];
|
|
1316
|
+
_blackCanvasStreamTrack = void 0;
|
|
1317
|
+
_inaudibleAudioStreamTrack = void 0;
|
|
1318
|
+
_pushTracksTask = void 0;
|
|
1319
|
+
_pullTracksTask = void 0;
|
|
1320
|
+
get isSpeaking() {
|
|
1321
|
+
return this._speakingMonitor?.isSpeaking;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* @internal
|
|
1325
|
+
*/
|
|
1326
|
+
_getState() {
|
|
1327
|
+
return this._state;
|
|
1328
|
+
}
|
|
1329
|
+
async _open() {
|
|
1330
|
+
this._blackCanvasStreamTrack = await createBlackCanvasStreamTrack({
|
|
1331
|
+
ctx: this._ctx,
|
|
1332
|
+
width: VIDEO_WIDTH,
|
|
1333
|
+
height: VIDEO_HEIGHT
|
|
1334
|
+
});
|
|
1335
|
+
this._state.videoTrack = this._blackCanvasStreamTrack;
|
|
1336
|
+
this._state.videoStream = new MediaStream();
|
|
1337
|
+
this._state.videoStream.addTrack(this._state.videoTrack);
|
|
1338
|
+
if (USE_INAUDIBLE_AUDIO) {
|
|
1339
|
+
this._inaudibleAudioStreamTrack = await createInaudibleAudioStreamTrack({
|
|
1340
|
+
ctx: this._ctx
|
|
1341
|
+
});
|
|
1342
|
+
this._state.audioTrack = this._inaudibleAudioStreamTrack;
|
|
1343
|
+
}
|
|
1344
|
+
this._pushTracksTask = new DeferredTask3(this._ctx, async () => {
|
|
1345
|
+
await this._pushTracks();
|
|
1346
|
+
});
|
|
1347
|
+
this._pullTracksTask = new DeferredTask3(this._ctx, async () => {
|
|
1348
|
+
await this._reconcilePulledMedia();
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
async _close() {
|
|
1352
|
+
void this._speakingMonitor?.close();
|
|
1353
|
+
this._state.videoTrack && this._state.videoStream?.removeTrack(this._state.videoTrack);
|
|
1354
|
+
this._state.audioTrack?.stop();
|
|
1355
|
+
this._state.videoTrack?.stop();
|
|
1356
|
+
this._state.screenshareTrack?.stop();
|
|
1357
|
+
this._pushTracksTask = void 0;
|
|
1358
|
+
this._pullTracksTask = void 0;
|
|
1359
|
+
}
|
|
1360
|
+
async join(serviceConfig) {
|
|
1361
|
+
this._state.peer = new CallsServicePeer(serviceConfig);
|
|
1362
|
+
await this._state.peer.open();
|
|
1363
|
+
this._pushTracksTask.schedule();
|
|
1364
|
+
}
|
|
1365
|
+
async leave() {
|
|
1366
|
+
await Promise.all(Object.values(this._state.pulledAudioTracks).map(({ ctx }) => ctx.dispose()));
|
|
1367
|
+
await Promise.all(Object.values(this._state.pulledVideoStreams).map(({ ctx }) => ctx.dispose()));
|
|
1368
|
+
this._trackToReconcile = [];
|
|
1369
|
+
await this._state.peer?.close();
|
|
1370
|
+
this._state.peer = void 0;
|
|
1371
|
+
this._state.pushedVideoTrack = void 0;
|
|
1372
|
+
this._state.pushedAudioTrack = void 0;
|
|
1373
|
+
this._state.pushedScreenshareTrack = void 0;
|
|
1374
|
+
this._state.pulledAudioTracks = {};
|
|
1375
|
+
this._state.pulledVideoStreams = {};
|
|
1376
|
+
}
|
|
1377
|
+
async turnVideoOn() {
|
|
1378
|
+
this._state.videoStream.removeTrack(this._state.videoTrack);
|
|
1379
|
+
this._state.videoTrack = await getUserMediaTrack("videoinput", {
|
|
1380
|
+
width: VIDEO_WIDTH,
|
|
1381
|
+
height: VIDEO_HEIGHT
|
|
1382
|
+
});
|
|
1383
|
+
this._state.videoStream.addTrack(this._state.videoTrack);
|
|
1384
|
+
this._state.videoEnabled = true;
|
|
1385
|
+
this.stateUpdated.emit(this._state);
|
|
1386
|
+
this._pushTracksTask.schedule();
|
|
1387
|
+
}
|
|
1388
|
+
async turnVideoOff() {
|
|
1389
|
+
if (this._state.videoTrack !== this._blackCanvasStreamTrack) {
|
|
1390
|
+
this._state.videoStream.removeTrack(this._state.videoTrack);
|
|
1391
|
+
this._state.videoTrack?.stop();
|
|
1392
|
+
this._state.videoTrack = this._blackCanvasStreamTrack;
|
|
1393
|
+
this._state.videoStream.addTrack(this._state.videoTrack);
|
|
1394
|
+
}
|
|
1395
|
+
this._state.videoEnabled = false;
|
|
1396
|
+
this.stateUpdated.emit(this._state);
|
|
1397
|
+
this._pushTracksTask.schedule();
|
|
1398
|
+
}
|
|
1399
|
+
// TODO(mykola): Change to `setAudioEnabled(enabled: boolean)`.
|
|
1400
|
+
async turnAudioOn() {
|
|
1401
|
+
void this._speakingMonitor?.close();
|
|
1402
|
+
this._state.audioEnabled = true;
|
|
1403
|
+
this._state.audioTrack = await getUserMediaTrack("audioinput", {
|
|
1404
|
+
echoCancellation: true,
|
|
1405
|
+
noiseSuppression: true,
|
|
1406
|
+
autoGainControl: true,
|
|
1407
|
+
sampleRate: 16e3
|
|
1408
|
+
});
|
|
1409
|
+
this.stateUpdated.emit(this._state);
|
|
1410
|
+
this._pushTracksTask.schedule();
|
|
1411
|
+
this._speakingMonitor = new SpeakingMonitor(this._state.audioTrack);
|
|
1412
|
+
this._speakingMonitor.speakingChanged.on(this._ctx, () => this.stateUpdated.emit(this._state));
|
|
1413
|
+
void this._speakingMonitor.open();
|
|
1414
|
+
}
|
|
1415
|
+
async turnAudioOff() {
|
|
1416
|
+
void this._speakingMonitor?.close();
|
|
1417
|
+
this._speakingMonitor = void 0;
|
|
1418
|
+
this._state.audioEnabled = false;
|
|
1419
|
+
if (USE_INAUDIBLE_AUDIO && this._state.audioTrack !== this._inaudibleAudioStreamTrack) {
|
|
1420
|
+
this._state.audioTrack?.stop();
|
|
1421
|
+
this._state.audioTrack = this._inaudibleAudioStreamTrack;
|
|
1422
|
+
} else {
|
|
1423
|
+
this._state.audioTrack?.stop();
|
|
1424
|
+
this._state.audioTrack = void 0;
|
|
1425
|
+
}
|
|
1426
|
+
this.stateUpdated.emit(this._state);
|
|
1427
|
+
this._pushTracksTask.schedule();
|
|
1428
|
+
}
|
|
1429
|
+
async turnScreenshareOn() {
|
|
1430
|
+
const ms = await getScreenshare({
|
|
1431
|
+
contentHint: "text"
|
|
1432
|
+
});
|
|
1433
|
+
this._state.screenshareVideoStream = ms;
|
|
1434
|
+
this._state.screenshareTrack = ms.getVideoTracks()[0];
|
|
1435
|
+
this._state.screenshareEnabled = true;
|
|
1436
|
+
this.stateUpdated.emit(this._state);
|
|
1437
|
+
this._pushTracksTask.schedule();
|
|
1438
|
+
}
|
|
1439
|
+
async turnScreenshareOff() {
|
|
1440
|
+
this._state.screenshareEnabled = false;
|
|
1441
|
+
this._state.screenshareTrack?.stop();
|
|
1442
|
+
this._state.screenshareTrack = void 0;
|
|
1443
|
+
this.stateUpdated.emit(this._state);
|
|
1444
|
+
this._pushTracksTask.schedule();
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* @internal
|
|
1448
|
+
*/
|
|
1449
|
+
_schedulePullTracks(tracks) {
|
|
1450
|
+
if (!tracks || this._trackToReconcile.every((name) => tracks.includes(name)) && this._trackToReconcile.length === tracks.length) {
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
this._trackToReconcile = tracks;
|
|
1454
|
+
this._pullTracksTask.schedule();
|
|
1455
|
+
}
|
|
1456
|
+
async _reconcilePulledMedia() {
|
|
1457
|
+
log4("reconciling tracks", void 0, {
|
|
1458
|
+
F: __dxlog_file6,
|
|
1459
|
+
L: 229,
|
|
1460
|
+
S: this,
|
|
1461
|
+
C: (f, a) => f(...a)
|
|
1462
|
+
});
|
|
1463
|
+
await cancelWithContext2(this._ctx, sleep2(800));
|
|
1464
|
+
const trackNames = this._trackToReconcile;
|
|
1465
|
+
const tracksToPull = trackNames.filter((name) => !this._state.pulledAudioTracks[name] && !this._state.pulledVideoStreams[name]);
|
|
1466
|
+
const audioTracksToClose = Object.entries(this._state.pulledAudioTracks).filter(([key]) => !trackNames.some((name) => name === key));
|
|
1467
|
+
const videoStreamsToClose = Object.entries(this._state.pulledVideoStreams).filter(([key]) => !trackNames.some((name) => name === key));
|
|
1468
|
+
log4("reconciling tracks", {
|
|
1469
|
+
trackNames,
|
|
1470
|
+
tracksToPull,
|
|
1471
|
+
videoStreamsToClose,
|
|
1472
|
+
audioTracksToClose,
|
|
1473
|
+
currentAudioTracks: Object.keys(this._state.pulledAudioTracks),
|
|
1474
|
+
currentVideoStreams: Object.keys(this._state.pulledVideoStreams)
|
|
1475
|
+
}, {
|
|
1476
|
+
F: __dxlog_file6,
|
|
1477
|
+
L: 247,
|
|
1478
|
+
S: this,
|
|
1479
|
+
C: (f, a) => f(...a)
|
|
1480
|
+
});
|
|
1481
|
+
const pullResults = await Promise.all(tracksToPull.map((name) => this._pullTrack(name)));
|
|
1482
|
+
await Promise.all([
|
|
1483
|
+
...audioTracksToClose,
|
|
1484
|
+
...videoStreamsToClose
|
|
1485
|
+
].map(([_, { ctx }]) => ctx.dispose()));
|
|
1486
|
+
log4("reconciled tracks", {
|
|
1487
|
+
currentAudioTracks: Object.keys(this._state.pulledAudioTracks),
|
|
1488
|
+
currentVideoStreams: Object.keys(this._state.pulledVideoStreams)
|
|
1489
|
+
}, {
|
|
1490
|
+
F: __dxlog_file6,
|
|
1491
|
+
L: 262,
|
|
1492
|
+
S: this,
|
|
1493
|
+
C: (f, a) => f(...a)
|
|
1494
|
+
});
|
|
1495
|
+
this.stateUpdated.emit(this._state);
|
|
1496
|
+
if (pullResults.some(({ shouldRetry }) => shouldRetry)) {
|
|
1497
|
+
await cancelWithContext2(this._ctx, sleep2(RETRY_INTERVAL));
|
|
1498
|
+
log4.info("retrying pull tracks", {
|
|
1499
|
+
tracksToPull
|
|
1500
|
+
}, {
|
|
1501
|
+
F: __dxlog_file6,
|
|
1502
|
+
L: 270,
|
|
1503
|
+
S: this,
|
|
1504
|
+
C: (f, a) => f(...a)
|
|
1505
|
+
});
|
|
1506
|
+
invariant5(this._pullTracksTask, void 0, {
|
|
1507
|
+
F: __dxlog_file6,
|
|
1508
|
+
L: 271,
|
|
1509
|
+
S: this,
|
|
1510
|
+
A: [
|
|
1511
|
+
"this._pullTracksTask",
|
|
1512
|
+
""
|
|
1513
|
+
]
|
|
1514
|
+
});
|
|
1515
|
+
this._pullTracksTask.schedule();
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
async _pushTracks() {
|
|
1519
|
+
if (!this._state.peer?.isOpen) {
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
let updated = false;
|
|
1523
|
+
const [pushVideoResult, pushAudioResult, pushScreenshareResult] = await Promise.all([
|
|
1524
|
+
this._maybePushTrack(this._state.videoTrack, this._state.pushedVideoTrack, [
|
|
1525
|
+
{
|
|
1526
|
+
maxFramerate: MAX_WEB_CAM_FRAMERATE,
|
|
1527
|
+
maxBitrate: MAX_WEB_CAM_BITRATE
|
|
1528
|
+
}
|
|
1529
|
+
]),
|
|
1530
|
+
this._maybePushTrack(this._state.audioTrack, this._state.pushedAudioTrack, [
|
|
1531
|
+
{
|
|
1532
|
+
networkPriority: "high"
|
|
1533
|
+
}
|
|
1534
|
+
]),
|
|
1535
|
+
this._maybePushTrack(this._state.screenshareTrack, this._state.pushedScreenshareTrack)
|
|
1536
|
+
]);
|
|
1537
|
+
if (pushVideoResult.track !== this._state.pushedVideoTrack) {
|
|
1538
|
+
this._state.pushedVideoTrack = pushVideoResult.track;
|
|
1539
|
+
updated = true;
|
|
1540
|
+
}
|
|
1541
|
+
if (pushAudioResult.track !== this._state.pushedAudioTrack) {
|
|
1542
|
+
this._state.pushedAudioTrack = pushAudioResult.track;
|
|
1543
|
+
updated = true;
|
|
1544
|
+
}
|
|
1545
|
+
if (pushScreenshareResult.track !== this._state.pushedScreenshareTrack) {
|
|
1546
|
+
this._state.pushedScreenshareTrack = pushScreenshareResult.track;
|
|
1547
|
+
updated = true;
|
|
1548
|
+
}
|
|
1549
|
+
const shouldRetry = pushVideoResult.shouldRetry || pushAudioResult.shouldRetry || pushScreenshareResult.shouldRetry;
|
|
1550
|
+
if (updated) {
|
|
1551
|
+
this.stateUpdated.emit(this._state);
|
|
1552
|
+
}
|
|
1553
|
+
if (shouldRetry) {
|
|
1554
|
+
await cancelWithContext2(this._ctx, sleep2(RETRY_INTERVAL));
|
|
1555
|
+
log4.info("retrying push tracks", {
|
|
1556
|
+
pushVideoResult,
|
|
1557
|
+
pushAudioResult,
|
|
1558
|
+
pushScreenshareResult
|
|
1559
|
+
}, {
|
|
1560
|
+
F: __dxlog_file6,
|
|
1561
|
+
L: 310,
|
|
1562
|
+
S: this,
|
|
1563
|
+
C: (f, a) => f(...a)
|
|
1564
|
+
});
|
|
1565
|
+
invariant5(this._pushTracksTask, void 0, {
|
|
1566
|
+
F: __dxlog_file6,
|
|
1567
|
+
L: 311,
|
|
1568
|
+
S: this,
|
|
1569
|
+
A: [
|
|
1570
|
+
"this._pushTracksTask",
|
|
1571
|
+
""
|
|
1572
|
+
]
|
|
1573
|
+
});
|
|
1574
|
+
this._pushTracksTask.schedule();
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
async _pullTrack(name) {
|
|
1578
|
+
const ctx = this._ctx.derive();
|
|
1579
|
+
try {
|
|
1580
|
+
const trackData = TrackNameCodec.decode(name);
|
|
1581
|
+
const track = await this._state.peer.pullTrack({
|
|
1582
|
+
trackData: {
|
|
1583
|
+
...trackData,
|
|
1584
|
+
mid: void 0
|
|
1585
|
+
},
|
|
1586
|
+
ctx
|
|
1587
|
+
});
|
|
1588
|
+
if (track?.readyState === "ended") {
|
|
1589
|
+
throw new Error("Pulled track ended immediately");
|
|
1590
|
+
}
|
|
1591
|
+
switch (track?.kind) {
|
|
1592
|
+
case "audio": {
|
|
1593
|
+
this._state.pulledAudioTracks[name] = {
|
|
1594
|
+
track,
|
|
1595
|
+
ctx
|
|
1596
|
+
};
|
|
1597
|
+
ctx.onDispose(() => delete this._state.pulledAudioTracks[name]);
|
|
1598
|
+
return {
|
|
1599
|
+
shouldRetry: false
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
case "video": {
|
|
1603
|
+
const mediaStream = new MediaStream();
|
|
1604
|
+
mediaStream.addTrack(track);
|
|
1605
|
+
this._state.pulledVideoStreams[name] = {
|
|
1606
|
+
stream: mediaStream,
|
|
1607
|
+
ctx
|
|
1608
|
+
};
|
|
1609
|
+
ctx.onDispose(() => {
|
|
1610
|
+
mediaStream.removeTrack(track);
|
|
1611
|
+
track.stop();
|
|
1612
|
+
delete this._state.pulledVideoStreams[name];
|
|
1613
|
+
});
|
|
1614
|
+
return {
|
|
1615
|
+
shouldRetry: false
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
default:
|
|
1619
|
+
throw new Error(`Invalid track kind: ${track?.kind}`);
|
|
1620
|
+
}
|
|
1621
|
+
} catch (err) {
|
|
1622
|
+
log4.info("failed to pull track", {
|
|
1623
|
+
err,
|
|
1624
|
+
name
|
|
1625
|
+
}, {
|
|
1626
|
+
F: __dxlog_file6,
|
|
1627
|
+
L: 347,
|
|
1628
|
+
S: this,
|
|
1629
|
+
C: (f, a) => f(...a)
|
|
1630
|
+
});
|
|
1631
|
+
void ctx.dispose();
|
|
1632
|
+
return {
|
|
1633
|
+
shouldRetry: true
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
async _maybePushTrack(track, previousTrack, encodings) {
|
|
1638
|
+
if (!track && !previousTrack) {
|
|
1639
|
+
return {
|
|
1640
|
+
track: void 0
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
const ctx = this._ctx.derive();
|
|
1644
|
+
try {
|
|
1645
|
+
return {
|
|
1646
|
+
track: await this._state.peer.pushTrack({
|
|
1647
|
+
ctx,
|
|
1648
|
+
track: track ?? null,
|
|
1649
|
+
previousTrack,
|
|
1650
|
+
encodings
|
|
1651
|
+
})
|
|
1652
|
+
};
|
|
1653
|
+
} catch (err) {
|
|
1654
|
+
log4.info("failed to push track", {
|
|
1655
|
+
err,
|
|
1656
|
+
track,
|
|
1657
|
+
previousTrack,
|
|
1658
|
+
encodings
|
|
1659
|
+
}, {
|
|
1660
|
+
F: __dxlog_file6,
|
|
1661
|
+
L: 373,
|
|
1662
|
+
S: this,
|
|
1663
|
+
C: (f, a) => f(...a)
|
|
1664
|
+
});
|
|
1665
|
+
void ctx.dispose();
|
|
1666
|
+
return {
|
|
1667
|
+
shouldRetry: true
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
_ts_decorate2([
|
|
1673
|
+
synchronized2
|
|
1674
|
+
], MediaManager.prototype, "join", null);
|
|
1675
|
+
_ts_decorate2([
|
|
1676
|
+
synchronized2
|
|
1677
|
+
], MediaManager.prototype, "leave", null);
|
|
1678
|
+
|
|
1679
|
+
// src/calls/call-manager.ts
|
|
1680
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
1681
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1682
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1683
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1684
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1685
|
+
}
|
|
1686
|
+
var __dxlog_file7 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/calls/call-manager.ts";
|
|
1687
|
+
var CallManager = class extends Resource5 {
|
|
1688
|
+
_client;
|
|
1689
|
+
_registry;
|
|
1690
|
+
callStateUpdated = new Event4();
|
|
1691
|
+
// TODO(wittjosiah): Consolidate isSpeaking into the MediaState type.
|
|
1692
|
+
mediaStateUpdated = new Event4();
|
|
1693
|
+
left = new Event4();
|
|
1694
|
+
/**
|
|
1695
|
+
* Atom-based state. Updated via `_updateState()`.
|
|
1696
|
+
* CAUTION: Do not change directly.
|
|
1697
|
+
*/
|
|
1698
|
+
_stateAtom = Atom.make({
|
|
1699
|
+
call: {},
|
|
1700
|
+
media: {
|
|
1701
|
+
pulledAudioTracks: {},
|
|
1702
|
+
pulledVideoStreams: {}
|
|
1703
|
+
}
|
|
1704
|
+
});
|
|
1705
|
+
// Derived atoms for reactive subscriptions.
|
|
1706
|
+
_roomIdAtom = Atom.make((get) => get(this._stateAtom).call.roomId);
|
|
1707
|
+
_raisedHandAtom = Atom.make((get) => get(this._stateAtom).call.raisedHand ?? false);
|
|
1708
|
+
_speakingAtom = Atom.make((get) => get(this._stateAtom).call.speaking ?? false);
|
|
1709
|
+
_joinedAtom = Atom.make((get) => get(this._stateAtom).call.joined ?? false);
|
|
1710
|
+
_selfAtom = Atom.make((get) => get(this._stateAtom).call.self ?? {});
|
|
1711
|
+
_tracksAtom = Atom.make((get) => get(this._stateAtom).call.tracks ?? {});
|
|
1712
|
+
_usersAtom = Atom.make((get) => get(this._stateAtom).call.users ?? []);
|
|
1713
|
+
_mediaAtom = Atom.make((get) => get(this._stateAtom).media);
|
|
1714
|
+
_audioTracksToPlayAtom = Atom.make((get) => {
|
|
1715
|
+
const state = get(this._stateAtom);
|
|
1716
|
+
return (state.call.users ?? []).map((user) => user.tracks?.audioEnabled ? user.tracks?.audio : void 0).filter(isNonNullable2).map((track) => state.media.pulledAudioTracks[track]?.track).filter(isNonNullable2);
|
|
1717
|
+
});
|
|
1718
|
+
_videoStreamAtomFamily = Atom.family((name) => Atom.make((get) => get(this._stateAtom).media.pulledVideoStreams[name]?.stream));
|
|
1719
|
+
_activityAtomFamily = Atom.family((key) => Atom.make((get) => get(this._stateAtom).call.activities?.[key]));
|
|
1720
|
+
_swarmSynchronizer;
|
|
1721
|
+
_mediaManager;
|
|
1722
|
+
//
|
|
1723
|
+
// Derived atoms for reactive UI subscriptions.
|
|
1724
|
+
//
|
|
1725
|
+
/** Derived atom for roomId. */
|
|
1726
|
+
get roomIdAtom() {
|
|
1727
|
+
return this._roomIdAtom;
|
|
1728
|
+
}
|
|
1729
|
+
/** Derived atom for raisedHand. */
|
|
1730
|
+
get raisedHandAtom() {
|
|
1731
|
+
return this._raisedHandAtom;
|
|
1732
|
+
}
|
|
1733
|
+
/** Derived atom for speaking. */
|
|
1734
|
+
get speakingAtom() {
|
|
1735
|
+
return this._speakingAtom;
|
|
1736
|
+
}
|
|
1737
|
+
/** Derived atom for joined. */
|
|
1738
|
+
get joinedAtom() {
|
|
1739
|
+
return this._joinedAtom;
|
|
1740
|
+
}
|
|
1741
|
+
/** Derived atom for self. */
|
|
1742
|
+
get selfAtom() {
|
|
1743
|
+
return this._selfAtom;
|
|
1744
|
+
}
|
|
1745
|
+
/** Derived atom for tracks. */
|
|
1746
|
+
get tracksAtom() {
|
|
1747
|
+
return this._tracksAtom;
|
|
1748
|
+
}
|
|
1749
|
+
/** Derived atom for users. */
|
|
1750
|
+
get usersAtom() {
|
|
1751
|
+
return this._usersAtom;
|
|
1752
|
+
}
|
|
1753
|
+
/** Derived atom for media. */
|
|
1754
|
+
get mediaAtom() {
|
|
1755
|
+
return this._mediaAtom;
|
|
1756
|
+
}
|
|
1757
|
+
/** Derived atom for audioTracksToPlay. */
|
|
1758
|
+
get audioTracksToPlayAtom() {
|
|
1759
|
+
return this._audioTracksToPlayAtom;
|
|
1760
|
+
}
|
|
1761
|
+
/** Returns the full state atom for reactive subscriptions. */
|
|
1762
|
+
get stateAtom() {
|
|
1763
|
+
return this._stateAtom;
|
|
1764
|
+
}
|
|
1765
|
+
/** Returns a derived atom for a video stream by name. */
|
|
1766
|
+
videoStreamAtom(name) {
|
|
1767
|
+
return this._videoStreamAtomFamily(name);
|
|
1768
|
+
}
|
|
1769
|
+
/** Returns a derived atom for an activity by key. */
|
|
1770
|
+
activityAtom(key) {
|
|
1771
|
+
return this._activityAtomFamily(key);
|
|
1772
|
+
}
|
|
1773
|
+
setRoomId(roomId) {
|
|
1774
|
+
this._swarmSynchronizer._setRoomId(roomId);
|
|
1775
|
+
}
|
|
1776
|
+
setSpeaking(speaking) {
|
|
1777
|
+
this._swarmSynchronizer.setSpeaking(speaking);
|
|
1778
|
+
}
|
|
1779
|
+
setRaisedHand(raisedHand) {
|
|
1780
|
+
this._swarmSynchronizer.setRaisedHand(raisedHand);
|
|
1781
|
+
}
|
|
1782
|
+
setActivity(key, payload) {
|
|
1783
|
+
this._swarmSynchronizer.setActivity(key, payload);
|
|
1784
|
+
}
|
|
1785
|
+
turnAudioOn() {
|
|
1786
|
+
return this._mediaManager.turnAudioOn();
|
|
1787
|
+
}
|
|
1788
|
+
turnAudioOff() {
|
|
1789
|
+
return this._mediaManager.turnAudioOff();
|
|
1790
|
+
}
|
|
1791
|
+
turnVideoOn() {
|
|
1792
|
+
return this._mediaManager.turnVideoOn();
|
|
1793
|
+
}
|
|
1794
|
+
turnVideoOff() {
|
|
1795
|
+
return this._mediaManager.turnVideoOff();
|
|
1796
|
+
}
|
|
1797
|
+
turnScreenshareOn() {
|
|
1798
|
+
return this._mediaManager.turnScreenshareOn();
|
|
1799
|
+
}
|
|
1800
|
+
turnScreenshareOff() {
|
|
1801
|
+
return this._mediaManager.turnScreenshareOff();
|
|
1802
|
+
}
|
|
1803
|
+
// TODO(burdon): Can this be mocked?
|
|
1804
|
+
constructor(_client, _registry) {
|
|
1805
|
+
super(), this._client = _client, this._registry = _registry;
|
|
1806
|
+
this._client.config.getOrThrow("runtime.services.edge.url");
|
|
1807
|
+
const networkService = this._client.services.services.NetworkService;
|
|
1808
|
+
invariant6(networkService, "network service not found", {
|
|
1809
|
+
F: __dxlog_file7,
|
|
1810
|
+
L: 180,
|
|
1811
|
+
S: this,
|
|
1812
|
+
A: [
|
|
1813
|
+
"networkService",
|
|
1814
|
+
"'network service not found'"
|
|
1815
|
+
]
|
|
1816
|
+
});
|
|
1817
|
+
this._swarmSynchronizer = new CallSwarmSynchronizer({
|
|
1818
|
+
networkService
|
|
1819
|
+
});
|
|
1820
|
+
this._mediaManager = new MediaManager();
|
|
1821
|
+
}
|
|
1822
|
+
async _open() {
|
|
1823
|
+
await this._mediaManager.open();
|
|
1824
|
+
await this._swarmSynchronizer.open();
|
|
1825
|
+
const subscription = this._client.halo.identity.subscribe((identity) => {
|
|
1826
|
+
if (identity) {
|
|
1827
|
+
this._swarmSynchronizer._setIdentity(identity);
|
|
1828
|
+
}
|
|
1829
|
+
if (this._client.halo.device) {
|
|
1830
|
+
this._swarmSynchronizer._setDevice(this._client.halo.device);
|
|
1831
|
+
}
|
|
1832
|
+
});
|
|
1833
|
+
this._ctx.onDispose(() => subscription.unsubscribe());
|
|
1834
|
+
this._swarmSynchronizer.stateUpdated.on(this._ctx, (state) => this._onCallStateUpdated(state));
|
|
1835
|
+
this._mediaManager.stateUpdated.on(this._ctx, (state) => this._onMediaStateUpdated(state));
|
|
1836
|
+
}
|
|
1837
|
+
async _close() {
|
|
1838
|
+
await this._swarmSynchronizer.leave();
|
|
1839
|
+
await this._swarmSynchronizer.close();
|
|
1840
|
+
await this._mediaManager.close();
|
|
1841
|
+
}
|
|
1842
|
+
async peek(roomId) {
|
|
1843
|
+
const peers = await this._swarmSynchronizer.querySwarm(roomId);
|
|
1844
|
+
return peers.length;
|
|
1845
|
+
}
|
|
1846
|
+
// TODO(mykola): Reconcile with _swarmSynchronizer.state.joined.
|
|
1847
|
+
async join() {
|
|
1848
|
+
this._swarmSynchronizer.setJoined(true);
|
|
1849
|
+
await this._swarmSynchronizer.join();
|
|
1850
|
+
await this._mediaManager.join({
|
|
1851
|
+
iceServers: this._client.config.get("runtime.services.ice"),
|
|
1852
|
+
apiBase: `${CALLS_URL}/api/calls`
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
async leave() {
|
|
1856
|
+
this._swarmSynchronizer.setJoined(false);
|
|
1857
|
+
await this._swarmSynchronizer.leave();
|
|
1858
|
+
await this._mediaManager.leave();
|
|
1859
|
+
const roomId = this._registry.get(this._roomIdAtom);
|
|
1860
|
+
roomId && this.left.emit(roomId);
|
|
1861
|
+
}
|
|
1862
|
+
_onCallStateUpdated(state) {
|
|
1863
|
+
const tracksToPull = state.users?.filter((user) => user.joined && user.id !== state.self.id)?.flatMap((user) => [
|
|
1864
|
+
user.tracks?.video,
|
|
1865
|
+
user.tracks?.audio,
|
|
1866
|
+
user.tracks?.screenshare
|
|
1867
|
+
]).filter(isNonNullable2);
|
|
1868
|
+
this._mediaManager._schedulePullTracks(tracksToPull);
|
|
1869
|
+
this.callStateUpdated.emit(state);
|
|
1870
|
+
this._updateState();
|
|
1871
|
+
}
|
|
1872
|
+
_onMediaStateUpdated(state) {
|
|
1873
|
+
this._swarmSynchronizer.setTracks({
|
|
1874
|
+
video: state.pushedVideoTrack ? TrackNameCodec.encode(state.pushedVideoTrack) : void 0,
|
|
1875
|
+
audio: state.pushedAudioTrack ? TrackNameCodec.encode(state.pushedAudioTrack) : void 0,
|
|
1876
|
+
screenshare: state.pushedScreenshareTrack ? TrackNameCodec.encode(state.pushedScreenshareTrack) : void 0,
|
|
1877
|
+
videoEnabled: state.videoEnabled,
|
|
1878
|
+
audioEnabled: state.audioEnabled,
|
|
1879
|
+
screenshareEnabled: state.screenshareEnabled
|
|
1880
|
+
});
|
|
1881
|
+
const isSpeaking = this._mediaManager.isSpeaking ?? false;
|
|
1882
|
+
this._swarmSynchronizer.setSpeaking(isSpeaking);
|
|
1883
|
+
this.mediaStateUpdated.emit([
|
|
1884
|
+
state,
|
|
1885
|
+
isSpeaking
|
|
1886
|
+
]);
|
|
1887
|
+
this._updateState();
|
|
1888
|
+
}
|
|
1889
|
+
/**
|
|
1890
|
+
* Only this method is allowed to change state.
|
|
1891
|
+
*/
|
|
1892
|
+
_updateState() {
|
|
1893
|
+
this._registry.set(this._stateAtom, {
|
|
1894
|
+
call: this._swarmSynchronizer._getState(),
|
|
1895
|
+
media: this._mediaManager._getState()
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
};
|
|
1899
|
+
_ts_decorate3([
|
|
1900
|
+
synchronized3
|
|
1901
|
+
], CallManager.prototype, "join", null);
|
|
1902
|
+
_ts_decorate3([
|
|
1903
|
+
synchronized3
|
|
1904
|
+
], CallManager.prototype, "leave", null);
|
|
1905
|
+
|
|
1906
|
+
// src/hooks/analytics.ts
|
|
1907
|
+
import { useCallback } from "react";
|
|
1908
|
+
import { useOperationInvoker } from "@dxos/app-framework/ui";
|
|
1909
|
+
import { Obj } from "@dxos/echo";
|
|
1910
|
+
import { ObservabilityOperation } from "@dxos/plugin-observability/operations";
|
|
1911
|
+
import { useOnTransition } from "@dxos/react-ui";
|
|
1912
|
+
var useOnEditAnalytics = (message, textBlock, editing) => {
|
|
1913
|
+
const { invokePromise } = useOperationInvoker();
|
|
1914
|
+
const onEdit = useCallback(() => {
|
|
1915
|
+
if (!message || !textBlock) {
|
|
1916
|
+
return;
|
|
1917
|
+
}
|
|
1918
|
+
const db = Obj.getDatabase(message);
|
|
1919
|
+
if (!db) {
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1922
|
+
void invokePromise(ObservabilityOperation.SendEvent, {
|
|
1923
|
+
name: "threads.message.update",
|
|
1924
|
+
properties: {
|
|
1925
|
+
spaceId: db.spaceId,
|
|
1926
|
+
messageId: message.id,
|
|
1927
|
+
messageLength: textBlock?.text.length
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1930
|
+
}, [
|
|
1931
|
+
invokePromise,
|
|
1932
|
+
message,
|
|
1933
|
+
textBlock
|
|
1934
|
+
]);
|
|
1935
|
+
useOnTransition(editing, true, false, onEdit);
|
|
1936
|
+
};
|
|
1937
|
+
|
|
1938
|
+
// src/hooks/useBlackCanvasStreamTrack.tsx
|
|
1939
|
+
import { useEffect, useState } from "react";
|
|
1940
|
+
import { scheduleTask as scheduleTask2 } from "@dxos/async";
|
|
1941
|
+
import { Context as Context2 } from "@dxos/context";
|
|
1942
|
+
var __dxlog_file8 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/hooks/useBlackCanvasStreamTrack.tsx";
|
|
1943
|
+
var useBlackCanvasStreamTrack = () => {
|
|
1944
|
+
const [blackCanvasStreamTrack, setBlackCanvasStreamTrack] = useState(void 0);
|
|
1945
|
+
useEffect(() => {
|
|
1946
|
+
const ctx = new Context2(void 0, {
|
|
1947
|
+
F: __dxlog_file8,
|
|
1948
|
+
L: 15
|
|
1949
|
+
});
|
|
1950
|
+
scheduleTask2(ctx, async () => {
|
|
1951
|
+
const blackCanvasStreamTrack2 = await createBlackCanvasStreamTrack({
|
|
1952
|
+
ctx,
|
|
1953
|
+
width: 720,
|
|
1954
|
+
height: 480
|
|
1955
|
+
});
|
|
1956
|
+
setBlackCanvasStreamTrack(blackCanvasStreamTrack2);
|
|
1957
|
+
});
|
|
1958
|
+
return () => {
|
|
1959
|
+
void ctx.dispose();
|
|
1960
|
+
};
|
|
1961
|
+
}, []);
|
|
1962
|
+
return blackCanvasStreamTrack;
|
|
1963
|
+
};
|
|
1964
|
+
|
|
1965
|
+
// src/hooks/useDebugMode.ts
|
|
1966
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1967
|
+
var useDebugMode = () => {
|
|
1968
|
+
const [enabled, setEnabled] = useState2(false);
|
|
1969
|
+
useEffect2(() => {
|
|
1970
|
+
const handler = (ev) => {
|
|
1971
|
+
if (ev.key.toLowerCase() === "d" && ev.ctrlKey) {
|
|
1972
|
+
ev.preventDefault();
|
|
1973
|
+
setEnabled(!enabled);
|
|
1974
|
+
}
|
|
1975
|
+
};
|
|
1976
|
+
document.addEventListener("keypress", handler);
|
|
1977
|
+
return () => {
|
|
1978
|
+
document.removeEventListener("keypress", handler);
|
|
1979
|
+
};
|
|
1980
|
+
}, [
|
|
1981
|
+
enabled
|
|
1982
|
+
]);
|
|
1983
|
+
return enabled;
|
|
1984
|
+
};
|
|
1985
|
+
|
|
1986
|
+
// src/hooks/useInaudibleAudioStreamTrack.tsx
|
|
1987
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
1988
|
+
import { scheduleTask as scheduleTask3 } from "@dxos/async";
|
|
1989
|
+
import { Context as Context3 } from "@dxos/context";
|
|
1990
|
+
var __dxlog_file9 = "/__w/dxos/dxos/packages/plugins/plugin-thread/src/hooks/useInaudibleAudioStreamTrack.tsx";
|
|
1991
|
+
var useInaudibleAudioStreamTrack = () => {
|
|
1992
|
+
const [audioStreamTrack, setAudioStreamTrack] = useState3(void 0);
|
|
1993
|
+
useEffect3(() => {
|
|
1994
|
+
const ctx = new Context3(void 0, {
|
|
1995
|
+
F: __dxlog_file9,
|
|
1996
|
+
L: 15
|
|
1997
|
+
});
|
|
1998
|
+
scheduleTask3(ctx, async () => {
|
|
1999
|
+
const audioStreamTrack2 = await createInaudibleAudioStreamTrack({
|
|
2000
|
+
ctx
|
|
2001
|
+
});
|
|
2002
|
+
setAudioStreamTrack(audioStreamTrack2);
|
|
2003
|
+
});
|
|
2004
|
+
return () => {
|
|
2005
|
+
void ctx.dispose();
|
|
2006
|
+
};
|
|
2007
|
+
}, []);
|
|
2008
|
+
return audioStreamTrack;
|
|
2009
|
+
};
|
|
2010
|
+
|
|
2011
|
+
// src/hooks/useStatus.ts
|
|
2012
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
2013
|
+
var useStatus = (space, channel) => {
|
|
2014
|
+
const [processing, setProcessing] = useState4(false);
|
|
2015
|
+
useEffect4(() => {
|
|
2016
|
+
if (!space || !channel) {
|
|
2017
|
+
return;
|
|
2018
|
+
}
|
|
2019
|
+
const unsubscribe = space.listen(`status/${channel}`, (status) => {
|
|
2020
|
+
const { event } = status.payload ?? {};
|
|
2021
|
+
setProcessing(event === "processing");
|
|
2022
|
+
});
|
|
2023
|
+
const t = setInterval(() => {
|
|
2024
|
+
setProcessing((prev) => {
|
|
2025
|
+
if (typeof prev?.ts === "number" && Date.now() - prev.ts > 3e4) {
|
|
2026
|
+
return void 0;
|
|
2027
|
+
} else {
|
|
2028
|
+
return prev;
|
|
2029
|
+
}
|
|
2030
|
+
});
|
|
2031
|
+
}, 1e3);
|
|
2032
|
+
return () => {
|
|
2033
|
+
unsubscribe();
|
|
2034
|
+
clearInterval(t);
|
|
2035
|
+
};
|
|
2036
|
+
}, [
|
|
2037
|
+
space,
|
|
2038
|
+
channel
|
|
2039
|
+
]);
|
|
2040
|
+
return processing;
|
|
2041
|
+
};
|
|
2042
|
+
|
|
2043
|
+
// src/hooks/useVideoStreamTrack.tsx
|
|
2044
|
+
import { useEffect as useEffect5, useRef, useState as useState5 } from "react";
|
|
2045
|
+
var useVideoStreamTrack = (videoElement, videoSrc) => {
|
|
2046
|
+
const [videoStreamTrack, setVideoStreamTrack] = useState5(void 0);
|
|
2047
|
+
const hadRun = useRef(false);
|
|
2048
|
+
useEffect5(() => {
|
|
2049
|
+
if (!videoElement.current || hadRun.current || !videoSrc) {
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
hadRun.current = true;
|
|
2053
|
+
videoElement.current.addEventListener("playing", () => {
|
|
2054
|
+
if (videoStreamTrack) {
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
const stream = videoElement.current.captureStream();
|
|
2058
|
+
const track = stream.getTracks()[0];
|
|
2059
|
+
if (track && !videoStreamTrack) {
|
|
2060
|
+
setVideoStreamTrack(track);
|
|
2061
|
+
}
|
|
2062
|
+
stream.onaddtrack = (event) => {
|
|
2063
|
+
if (event.track.kind === "video" && !videoStreamTrack) {
|
|
2064
|
+
setVideoStreamTrack(event.track);
|
|
2065
|
+
}
|
|
2066
|
+
};
|
|
2067
|
+
});
|
|
2068
|
+
videoElement.current.src = videoSrc;
|
|
2069
|
+
}, [
|
|
2070
|
+
videoElement.current,
|
|
2071
|
+
videoSrc
|
|
2072
|
+
]);
|
|
2073
|
+
return videoStreamTrack;
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2076
|
+
// src/meta.ts
|
|
2077
|
+
import { trim } from "@dxos/util";
|
|
2078
|
+
var meta = {
|
|
2079
|
+
id: "org.dxos.plugin.thread",
|
|
2080
|
+
name: "Chat",
|
|
2081
|
+
description: trim`
|
|
2082
|
+
Multi-modal communication platform supporting text chat, voice, and video conferencing.
|
|
2083
|
+
Create threaded conversations and add contextual comments directly on any workspace object.
|
|
2084
|
+
`,
|
|
2085
|
+
icon: "ph--video-conference--regular",
|
|
2086
|
+
iconHue: "rose",
|
|
2087
|
+
source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-thread"
|
|
2088
|
+
};
|
|
2089
|
+
var THREAD_ITEM = `${meta.id}.item`;
|
|
2090
|
+
|
|
2091
|
+
// src/ThreadPlugin.tsx
|
|
2092
|
+
import * as Effect from "effect/Effect";
|
|
2093
|
+
import * as Option from "effect/Option";
|
|
2094
|
+
import { Capability, Plugin } from "@dxos/app-framework";
|
|
2095
|
+
import { AppActivationEvents, AppPlugin } from "@dxos/app-toolkit";
|
|
2096
|
+
import { Annotation, Ref, Type as Type2 } from "@dxos/echo";
|
|
2097
|
+
import { Operation } from "@dxos/operation";
|
|
2098
|
+
import { ClientEvents } from "@dxos/plugin-client/types";
|
|
2099
|
+
import { MarkdownEvents } from "@dxos/plugin-markdown";
|
|
2100
|
+
import { SpaceOperation } from "@dxos/plugin-space/operations";
|
|
2101
|
+
import { SpaceCapabilities, SpaceEvents } from "@dxos/plugin-space/types";
|
|
2102
|
+
import { translations as threadTranslations } from "@dxos/react-ui-thread";
|
|
2103
|
+
import { AnchoredTo, Message, Thread } from "@dxos/types";
|
|
2104
|
+
import { AppGraphBuilder, BlueprintDefinition, CallManager as CallManager2, Markdown, OperationHandler, UndoMappings, ReactRoot, ReactSurface, ThreadState } from "#capabilities";
|
|
2105
|
+
import { THREAD_ITEM as THREAD_ITEM2, meta as meta3 } from "#meta";
|
|
2106
|
+
import { ThreadOperation } from "#operations";
|
|
2107
|
+
import { Channel as Channel2 } from "#types";
|
|
87
2108
|
|
|
88
2109
|
// src/translations.ts
|
|
89
2110
|
import { Type } from "@dxos/echo";
|
|
2111
|
+
import { meta as meta2 } from "#meta";
|
|
2112
|
+
import { Channel } from "#types";
|
|
90
2113
|
var translations = [
|
|
91
2114
|
{
|
|
92
2115
|
"en-US": {
|
|
93
|
-
[Type.getTypename(
|
|
94
|
-
"typename
|
|
95
|
-
"typename
|
|
96
|
-
"typename
|
|
97
|
-
"typename
|
|
98
|
-
"object
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"object
|
|
2116
|
+
[Type.getTypename(Channel.Channel)]: {
|
|
2117
|
+
"typename.label": "Channel",
|
|
2118
|
+
"typename.label_zero": "Channels",
|
|
2119
|
+
"typename.label_one": "Channel",
|
|
2120
|
+
"typename.label_other": "Channels",
|
|
2121
|
+
"object-name.placeholder": "New channel",
|
|
2122
|
+
"add-object.label": "Add channel",
|
|
2123
|
+
"rename-object.label": "Rename channel",
|
|
2124
|
+
"delete-object.label": "Delete channel",
|
|
2125
|
+
"object-deleted.label": "Channel deleted"
|
|
102
2126
|
},
|
|
103
|
-
[
|
|
104
|
-
"plugin
|
|
105
|
-
"channel
|
|
106
|
-
"message
|
|
107
|
-
"activity
|
|
108
|
-
"anonymous
|
|
109
|
-
"delete
|
|
110
|
-
"detached
|
|
111
|
-
"delete
|
|
112
|
-
"resolve
|
|
113
|
-
"thread
|
|
114
|
-
"message
|
|
115
|
-
"comments
|
|
116
|
-
"chat
|
|
117
|
-
"draft
|
|
118
|
-
"no
|
|
119
|
-
"no
|
|
120
|
-
"toggle
|
|
121
|
-
"unnamed
|
|
122
|
-
"mark
|
|
123
|
-
"mark
|
|
124
|
-
"save
|
|
125
|
-
"edit
|
|
126
|
-
"delete
|
|
127
|
-
"accept
|
|
128
|
-
"open
|
|
129
|
-
"comments
|
|
130
|
-
"show
|
|
131
|
-
"show
|
|
132
|
-
"add
|
|
133
|
-
"channel
|
|
134
|
-
"call
|
|
135
|
-
"display
|
|
136
|
-
"display
|
|
137
|
-
"display
|
|
138
|
-
"set
|
|
139
|
-
"call
|
|
140
|
-
"meeting
|
|
141
|
-
"share
|
|
142
|
-
"show
|
|
143
|
-
"show
|
|
144
|
-
"meeting
|
|
145
|
-
"summarize
|
|
146
|
-
"summarizing
|
|
147
|
-
"create
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"screenshare on": "Share screen",
|
|
166
|
-
"screenshare off": "Stop streaming"
|
|
2127
|
+
[meta2.id]: {
|
|
2128
|
+
"plugin.name": "Chat",
|
|
2129
|
+
"channel-title.label": "Title",
|
|
2130
|
+
"message.placeholder": "Reply\u2026",
|
|
2131
|
+
"activity.message": "Processing\u2026",
|
|
2132
|
+
"anonymous.label": "Anonymous",
|
|
2133
|
+
"delete-message-block.label": "Delete message block",
|
|
2134
|
+
"detached-thread.label": "Referenced content was removed",
|
|
2135
|
+
"delete-thread.label": "Delete thread",
|
|
2136
|
+
"resolve-thread.label": "Resolve thread",
|
|
2137
|
+
"thread-deleted.label": "Thread deleted",
|
|
2138
|
+
"message-deleted.label": "Message deleted",
|
|
2139
|
+
"comments.heading": "Comments",
|
|
2140
|
+
"chat.heading": "Chat",
|
|
2141
|
+
"draft.button": "DRAFT",
|
|
2142
|
+
"no-comments.title": "Comments",
|
|
2143
|
+
"no-comments.message": "Click on the <commentIcon></commentIcon> button in the document toolbar to create a comment thread on the selected text.",
|
|
2144
|
+
"toggle-show-resolved.label": "Show resolved",
|
|
2145
|
+
"unnamed-object-threads.label": "Threads",
|
|
2146
|
+
"mark-as-resolved.label": "Mark as resolved",
|
|
2147
|
+
"mark-as-unresolved.label": "Mark as unresolved",
|
|
2148
|
+
"save-message.label": "Save",
|
|
2149
|
+
"edit-message.label": "Edit",
|
|
2150
|
+
"delete-message.label": "Delete message",
|
|
2151
|
+
"accept-proposal.label": "Accept proposal",
|
|
2152
|
+
"open-comments-panel.label": "Show Comments",
|
|
2153
|
+
"comments.label": "Comments",
|
|
2154
|
+
"show-all.label": "All comments",
|
|
2155
|
+
"show-unresolved.label": "Unresolved comments",
|
|
2156
|
+
"add-comment.label": "Add comment",
|
|
2157
|
+
"channel-companion.label": "Channel",
|
|
2158
|
+
"call-panel.label": "Active Call",
|
|
2159
|
+
"display-name.label": "Display name",
|
|
2160
|
+
"display-name.description": "Set your display name before joining a meeting.",
|
|
2161
|
+
"display-name-input.placeholder": "Enter your name",
|
|
2162
|
+
"set-display-name.label": "Continue",
|
|
2163
|
+
"call-tab.label": "Call",
|
|
2164
|
+
"meeting-status.title": "Calls",
|
|
2165
|
+
"share-meeting-link.label": "Share meeting",
|
|
2166
|
+
"show-webrtc-stats.title": "WebRTC Stats",
|
|
2167
|
+
"show-calls-history.title": "Service History",
|
|
2168
|
+
"meeting-summary.label": "Summary",
|
|
2169
|
+
"summarize.label": "Summarize",
|
|
2170
|
+
"summarizing.label": "Creating summary...",
|
|
2171
|
+
"create-summary.message": "A summary doesn\u2019t exist for this meeting yet. Create one now?",
|
|
2172
|
+
"icon-pin.label": "Pin video",
|
|
2173
|
+
"icon-unpin.label": "Unpin video",
|
|
2174
|
+
"icon-wave.label": "Waving",
|
|
2175
|
+
"icon-muted.label": "Muted",
|
|
2176
|
+
"join-call.button": "Join",
|
|
2177
|
+
"leave-call.button": "Leave",
|
|
2178
|
+
"mic-on.button": "Unmute",
|
|
2179
|
+
"mic-off.button": "Mute",
|
|
2180
|
+
"camera-on.button": "Turn camera on",
|
|
2181
|
+
"camera-off.button": "Turn camera off",
|
|
2182
|
+
"camera-off.label": "Camera off",
|
|
2183
|
+
"raise-hand.button": "Raise hand",
|
|
2184
|
+
"lower-hand.button": "Lower hand",
|
|
2185
|
+
"screenshare-on.button": "Share screen",
|
|
2186
|
+
"screenshare-off.button": "Stop streaming",
|
|
2187
|
+
"channel-toolbar.title": "Channel actions",
|
|
2188
|
+
"start-video-call.menu": "Start video call"
|
|
167
2189
|
}
|
|
168
2190
|
}
|
|
169
2191
|
}
|
|
170
2192
|
];
|
|
171
2193
|
|
|
172
2194
|
// src/ThreadPlugin.tsx
|
|
173
|
-
var ThreadPlugin = Plugin.define(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
activatesOn: ClientEvents.ClientReady,
|
|
177
|
-
activate: CallManager2
|
|
178
|
-
}),
|
|
179
|
-
// TODO(wittjosiah): Currently not used but leaving because there will likely be settings for threads again.
|
|
180
|
-
// Plugin.addModule({
|
|
181
|
-
// id: 'settings',
|
|
182
|
-
// activatesOn: Events.SetupSettings,
|
|
183
|
-
// activate: ThreadSettings,
|
|
184
|
-
// }),
|
|
185
|
-
Plugin.addModule({
|
|
186
|
-
id: "state",
|
|
187
|
-
// TODO(wittjosiah): Does not integrate with settings store.
|
|
188
|
-
// Should this be a different event?
|
|
189
|
-
// Should settings store be renamed to be more generic?
|
|
190
|
-
activatesOn: Common.ActivationEvent.SetupSettings,
|
|
191
|
-
activate: ThreadState
|
|
2195
|
+
var ThreadPlugin = Plugin.define(meta3).pipe(
|
|
2196
|
+
AppPlugin.addAppGraphModule({
|
|
2197
|
+
activate: AppGraphBuilder
|
|
192
2198
|
}),
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
...translations,
|
|
196
|
-
...threadTranslations
|
|
197
|
-
]
|
|
2199
|
+
AppPlugin.addBlueprintDefinitionModule({
|
|
2200
|
+
activate: BlueprintDefinition
|
|
198
2201
|
}),
|
|
199
|
-
|
|
2202
|
+
AppPlugin.addMetadataModule({
|
|
200
2203
|
metadata: [
|
|
201
2204
|
{
|
|
202
|
-
id: Type2.getTypename(
|
|
2205
|
+
id: Type2.getTypename(Channel2.Channel),
|
|
203
2206
|
metadata: {
|
|
204
|
-
icon:
|
|
205
|
-
iconHue: "
|
|
206
|
-
createObject: (props) => Effect.
|
|
2207
|
+
icon: Annotation.IconAnnotation.get(Channel2.Channel).pipe(Option.getOrThrow).icon,
|
|
2208
|
+
iconHue: Annotation.IconAnnotation.get(Channel2.Channel).pipe(Option.getOrThrow).hue ?? "white",
|
|
2209
|
+
createObject: (props, options) => Effect.gen(function* () {
|
|
2210
|
+
const object = Channel2.make(props);
|
|
2211
|
+
return yield* Operation.invoke(SpaceOperation.AddObject, {
|
|
2212
|
+
object,
|
|
2213
|
+
target: options.target,
|
|
2214
|
+
hidden: true,
|
|
2215
|
+
targetNodeId: options.targetNodeId
|
|
2216
|
+
});
|
|
2217
|
+
})
|
|
207
2218
|
}
|
|
208
2219
|
},
|
|
209
2220
|
{
|
|
@@ -214,14 +2225,7 @@ var ThreadPlugin = Plugin.define(meta).pipe(
|
|
|
214
2225
|
}
|
|
215
2226
|
},
|
|
216
2227
|
{
|
|
217
|
-
id:
|
|
218
|
-
metadata: {
|
|
219
|
-
// TODO(wittjosiah): Move out of metadata.
|
|
220
|
-
loadReferences: () => []
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
id: THREAD_ITEM,
|
|
2228
|
+
id: THREAD_ITEM2,
|
|
225
2229
|
metadata: {
|
|
226
2230
|
parse: (item, type) => {
|
|
227
2231
|
switch (type) {
|
|
@@ -244,52 +2248,62 @@ var ThreadPlugin = Plugin.define(meta).pipe(
|
|
|
244
2248
|
}
|
|
245
2249
|
]
|
|
246
2250
|
}),
|
|
247
|
-
|
|
2251
|
+
AppPlugin.addOperationHandlerModule({
|
|
2252
|
+
activate: OperationHandler
|
|
2253
|
+
}),
|
|
2254
|
+
AppPlugin.addOperationHandlerModule({
|
|
2255
|
+
id: "undo-mappings",
|
|
2256
|
+
activate: UndoMappings
|
|
2257
|
+
}),
|
|
2258
|
+
AppPlugin.addReactRootModule({
|
|
2259
|
+
activate: ReactRoot
|
|
2260
|
+
}),
|
|
2261
|
+
AppPlugin.addSchemaModule({
|
|
248
2262
|
schema: [
|
|
249
2263
|
AnchoredTo.AnchoredTo,
|
|
250
|
-
|
|
2264
|
+
Channel2.Channel,
|
|
251
2265
|
Message.Message,
|
|
252
|
-
Message.MessageV1,
|
|
253
2266
|
Thread.Thread
|
|
254
2267
|
]
|
|
255
2268
|
}),
|
|
2269
|
+
AppPlugin.addSurfaceModule({
|
|
2270
|
+
activate: ReactSurface
|
|
2271
|
+
}),
|
|
2272
|
+
AppPlugin.addTranslationsModule({
|
|
2273
|
+
translations: [
|
|
2274
|
+
...translations,
|
|
2275
|
+
...threadTranslations
|
|
2276
|
+
]
|
|
2277
|
+
}),
|
|
256
2278
|
Plugin.addModule({
|
|
257
|
-
id: "
|
|
258
|
-
activatesOn: ClientEvents.
|
|
259
|
-
activate:
|
|
260
|
-
Message.MessageV1ToV2
|
|
261
|
-
]))
|
|
2279
|
+
id: "call-manager",
|
|
2280
|
+
activatesOn: ClientEvents.ClientReady,
|
|
2281
|
+
activate: CallManager2
|
|
262
2282
|
}),
|
|
2283
|
+
// TODO(wittjosiah): Currently not used but leaving because there will likely be settings for threads again.
|
|
2284
|
+
// Plugin.addModule({
|
|
2285
|
+
// id: 'settings',
|
|
2286
|
+
// activatesOn: Events.SetupSettings,
|
|
2287
|
+
// activate: ThreadSettings,
|
|
2288
|
+
// }),
|
|
263
2289
|
Plugin.addModule({
|
|
264
|
-
id: "
|
|
265
|
-
|
|
266
|
-
|
|
2290
|
+
id: "state",
|
|
2291
|
+
// TODO(wittjosiah): Does not integrate with settings store.
|
|
2292
|
+
// Should this be a different event?
|
|
2293
|
+
// Should settings store be renamed to be more generic?
|
|
2294
|
+
activatesOn: AppActivationEvents.SetupSettings,
|
|
2295
|
+
activate: ThreadState
|
|
267
2296
|
}),
|
|
268
2297
|
Plugin.addModule({
|
|
269
|
-
id: "
|
|
270
|
-
activatesOn:
|
|
271
|
-
activate:
|
|
2298
|
+
id: "on-space-created",
|
|
2299
|
+
activatesOn: SpaceEvents.SpaceCreated,
|
|
2300
|
+
activate: () => Effect.succeed(Capability.contributes(SpaceCapabilities.OnCreateSpace, (params) => Operation.invoke(ThreadOperation.OnCreateSpace, params)))
|
|
272
2301
|
}),
|
|
273
2302
|
Plugin.addModule({
|
|
274
2303
|
id: "markdown",
|
|
275
2304
|
activatesOn: MarkdownEvents.SetupExtensions,
|
|
276
2305
|
activate: Markdown
|
|
277
2306
|
}),
|
|
278
|
-
Common.Plugin.addReactRootModule({
|
|
279
|
-
activate: ReactRoot
|
|
280
|
-
}),
|
|
281
|
-
Common.Plugin.addSurfaceModule({
|
|
282
|
-
activate: ReactSurface
|
|
283
|
-
}),
|
|
284
|
-
Common.Plugin.addOperationResolverModule({
|
|
285
|
-
activate: OperationResolver
|
|
286
|
-
}),
|
|
287
|
-
Common.Plugin.addAppGraphModule({
|
|
288
|
-
activate: AppGraphBuilder
|
|
289
|
-
}),
|
|
290
|
-
Common.Plugin.addBlueprintDefinitionModule({
|
|
291
|
-
activate: BlueprintDefinition
|
|
292
|
-
}),
|
|
293
2307
|
Plugin.make
|
|
294
2308
|
);
|
|
295
2309
|
export {
|