@dxos/plugin-thread 0.8.3-staging.0fa589b → 0.8.4-main.f9ba587
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/ChannelContainer-5YH4FTBL.mjs +16 -0
- package/dist/lib/browser/ChatContainer-2UYQ23KO.mjs +15 -0
- package/dist/lib/browser/{app-graph-builder-OY7R7EJP.mjs → app-graph-builder-Q5V3KXE3.mjs} +6 -6
- package/dist/lib/browser/{call-manager-APQAZWHT.mjs → call-manager-NIPDYUVD.mjs} +6 -5
- package/dist/lib/browser/chunk-5ZVJ4GAS.mjs +21 -0
- package/dist/lib/browser/chunk-6NSMBO3B.mjs +56 -0
- package/dist/lib/browser/chunk-6NSMBO3B.mjs.map +7 -0
- package/dist/lib/browser/{chunk-5P5BH5GE.mjs → chunk-ERWASUQK.mjs} +66 -5
- package/dist/lib/browser/chunk-ERWASUQK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-IIUTBDVB.mjs → chunk-EV4JWI7L.mjs} +2 -2
- package/dist/lib/browser/{chunk-JKQUJOTX.mjs → chunk-GERVMFQW.mjs} +2 -2
- package/dist/lib/browser/{chunk-AEXWNS6Z.mjs → chunk-JVIKVYTI.mjs} +4 -4
- package/dist/lib/browser/{chunk-XZKBN3NS.mjs → chunk-LCJD3NOB.mjs} +32 -31
- package/dist/lib/browser/chunk-LCJD3NOB.mjs.map +7 -0
- package/dist/lib/browser/{chunk-R5MDLUPC.mjs → chunk-LGSDKXPF.mjs} +3 -3
- package/dist/lib/browser/chunk-NCSFNWBZ.mjs +479 -0
- package/dist/lib/browser/chunk-NCSFNWBZ.mjs.map +7 -0
- package/dist/lib/browser/chunk-YD57K2SL.mjs +367 -0
- package/dist/lib/browser/chunk-YD57K2SL.mjs.map +7 -0
- package/dist/lib/browser/{chunk-4H4A264L.mjs → chunk-ZE7KWN36.mjs} +85 -124
- package/dist/lib/browser/chunk-ZE7KWN36.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +28 -22
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{intent-resolver-FK2MDVDT.mjs → intent-resolver-MWE6XLPY.mjs} +6 -6
- package/dist/lib/browser/{markdown-TE5SWWNJ.mjs → markdown-ZO34G7RM.mjs} +7 -7
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/react-root-YNDNPODD.mjs +28 -0
- package/dist/lib/browser/{react-surface-VXUJKSOG.mjs → react-surface-2AXRNTCA.mjs} +12 -11
- package/dist/lib/browser/{settings-RB2RSLXV.mjs → settings-XZGPZNAU.mjs} +4 -4
- package/dist/lib/browser/{state-RKL5MSDP.mjs → state-H6CYONWE.mjs} +4 -4
- package/dist/lib/browser/types/index.mjs +2 -2
- package/dist/lib/node-esm/ChannelContainer-O2LZKMRM.mjs +17 -0
- package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs → ChatContainer-6N35MP5J.mjs} +6 -5
- package/dist/lib/node-esm/{app-graph-builder-BAHBHYWI.mjs → app-graph-builder-GAKBZNU3.mjs} +6 -6
- package/dist/lib/node-esm/{call-manager-UUYXLF4T.mjs → call-manager-D6O5ZJJ4.mjs} +6 -5
- package/dist/lib/{browser/call-manager-APQAZWHT.mjs.map → node-esm/call-manager-D6O5ZJJ4.mjs.map} +1 -1
- package/dist/lib/node-esm/{chunk-O3V45YJP.mjs → chunk-25ABSYP2.mjs} +65 -5
- package/dist/lib/node-esm/chunk-25ABSYP2.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-UJMPYKT3.mjs → chunk-3X3YKRM2.mjs} +4 -4
- package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs → chunk-57XR3LEF.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-2RNIPFDA.mjs → chunk-5UQ4KKDE.mjs} +32 -31
- package/dist/lib/node-esm/chunk-5UQ4KKDE.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs → chunk-75RJ5DJI.mjs} +3 -3
- package/dist/lib/node-esm/chunk-A6QLTZCY.mjs +480 -0
- package/dist/lib/node-esm/chunk-A6QLTZCY.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs → chunk-GRLRWTRU.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-WXNPD542.mjs → chunk-IHDNQLLR.mjs} +84 -124
- package/dist/lib/node-esm/chunk-IHDNQLLR.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-OU5BYIDO.mjs +58 -0
- package/dist/lib/node-esm/chunk-OU5BYIDO.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-RGTWAVEE.mjs +368 -0
- package/dist/lib/node-esm/chunk-RGTWAVEE.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-X62X3VOK.mjs +23 -0
- package/dist/lib/node-esm/index.mjs +28 -22
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{intent-resolver-BU73VYW3.mjs → intent-resolver-B6PNTMPY.mjs} +6 -6
- package/dist/lib/node-esm/{markdown-HJUWNBLS.mjs → markdown-ZJUFV2TA.mjs} +7 -7
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-root-RUXOAQNW.mjs → react-root-ZUVVTKWG.mjs} +12 -11
- package/dist/lib/{browser/react-root-NK3A4VG7.mjs.map → node-esm/react-root-ZUVVTKWG.mjs.map} +1 -1
- package/dist/lib/node-esm/{react-surface-ELXFYKP6.mjs → react-surface-OMEZTOU6.mjs} +12 -11
- package/dist/lib/{browser/react-surface-VXUJKSOG.mjs.map → node-esm/react-surface-OMEZTOU6.mjs.map} +1 -1
- package/dist/lib/node-esm/{settings-EA7DFSM6.mjs → settings-XECBSD6Q.mjs} +4 -4
- package/dist/lib/node-esm/{state-6AUTNROZ.mjs → state-D7WNDT3N.mjs} +4 -4
- package/dist/lib/node-esm/types/index.mjs +2 -2
- package/dist/types/src/calls/call-manager.d.ts +1 -1
- package/dist/types/src/calls/call-manager.d.ts.map +1 -1
- package/dist/types/src/calls/media-manager.d.ts.map +1 -1
- package/dist/types/src/calls/util/calls-service.d.ts +4 -1
- package/dist/types/src/calls/util/calls-service.d.ts.map +1 -1
- package/dist/types/src/calls/util/stub-media-streams.d.ts.map +1 -1
- package/dist/types/src/calls-service.stories.d.ts +22 -0
- package/dist/types/src/calls-service.stories.d.ts.map +1 -0
- package/dist/types/src/components/ChannelContainer.d.ts.map +1 -1
- package/dist/types/src/components/ChannelContainer.stories.d.ts +2 -2
- package/dist/types/src/components/ChannelContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/Chat.stories.d.ts +3 -2
- package/dist/types/src/components/Chat.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatContainer.d.ts +2 -2
- package/dist/types/src/components/ChatContainer.d.ts.map +1 -1
- package/dist/types/src/components/Comments.stories.d.ts +1 -1
- package/dist/types/src/components/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/components/CommentsContainer.d.ts +4 -4
- package/dist/types/src/components/CommentsContainer.d.ts.map +1 -1
- package/dist/types/src/components/CommentsThreadContainer.d.ts +14 -0
- package/dist/types/src/components/CommentsThreadContainer.d.ts.map +1 -0
- package/dist/types/src/components/Media/VideoObject.stories.d.ts +1 -1
- package/dist/types/src/components/Media/VideoObject.stories.d.ts.map +1 -1
- package/dist/types/src/components/MessageContainer.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts +1 -1
- package/dist/types/src/components/ResponsiveGrid/ResponsiveGrid.stories.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts +2 -0
- package/dist/types/src/hooks/useInaudibleAudioStreamTrack.d.ts.map +1 -0
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts +3 -0
- package/dist/types/src/hooks/useVideoStreamTrack.d.ts.map +1 -0
- package/dist/types/src/testing/stories.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +72 -194
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +47 -48
- package/src/ThreadPlugin.tsx +1 -1
- package/src/calls/call-manager.ts +6 -2
- package/src/calls/media-manager.ts +11 -4
- package/src/calls/util/calls-service.ts +8 -5
- package/src/calls/util/stub-media-streams.ts +3 -6
- package/src/calls-service.stories.tsx +216 -0
- package/src/components/Call/Call.tsx +1 -1
- package/src/components/Call/Toolbar.tsx +2 -2
- package/src/components/CallDebugPanel.tsx +2 -2
- package/src/components/ChannelContainer.stories.tsx +5 -5
- package/src/components/ChannelContainer.tsx +6 -5
- package/src/components/Chat.stories.tsx +4 -4
- package/src/components/ChatContainer.tsx +10 -9
- package/src/components/Comments.stories.tsx +22 -15
- package/src/components/CommentsContainer.tsx +16 -11
- package/src/components/{CommentContainer.tsx → CommentsThreadContainer.tsx} +49 -80
- package/src/components/Media/VideoObject.stories.tsx +1 -1
- package/src/components/MessageContainer.tsx +27 -43
- package/src/components/ResponsiveGrid/ResponsiveContainer.stories.tsx +2 -2
- package/src/components/ResponsiveGrid/ResponsiveGrid.stories.tsx +2 -2
- package/src/components/ResponsiveGrid/ResponsiveGridItem.tsx +2 -2
- package/src/components/ThreadComplementary.tsx +2 -2
- package/src/components/ThreadSettings.tsx +2 -2
- package/src/components/index.ts +1 -1
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useInaudibleAudioStreamTrack.tsx +27 -0
- package/src/hooks/useVideoStreamTrack.tsx +33 -0
- package/src/testing/stories.ts +5 -1
- package/src/translations.ts +9 -8
- package/dist/lib/browser/ChannelContainer-PKFBVENP.mjs +0 -15
- package/dist/lib/browser/ChatContainer-RSOKYAMK.mjs +0 -14
- package/dist/lib/browser/chunk-4H4A264L.mjs.map +0 -7
- package/dist/lib/browser/chunk-5P5BH5GE.mjs.map +0 -7
- package/dist/lib/browser/chunk-6NBVNXTM.mjs +0 -21
- package/dist/lib/browser/chunk-PG5CTFKK.mjs +0 -550
- package/dist/lib/browser/chunk-PG5CTFKK.mjs.map +0 -7
- package/dist/lib/browser/chunk-TAFSCSUR.mjs +0 -351
- package/dist/lib/browser/chunk-TAFSCSUR.mjs.map +0 -7
- package/dist/lib/browser/chunk-XZKBN3NS.mjs.map +0 -7
- package/dist/lib/browser/react-root-NK3A4VG7.mjs +0 -27
- package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs +0 -36
- package/dist/lib/node/ChannelContainer-YS5YT2ML.cjs.map +0 -7
- package/dist/lib/node/ChatContainer-GCOM3M56.cjs +0 -35
- package/dist/lib/node/ChatContainer-GCOM3M56.cjs.map +0 -7
- package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs +0 -179
- package/dist/lib/node/app-graph-builder-PBHJNDQY.cjs.map +0 -7
- package/dist/lib/node/call-manager-HV2XJW5O.cjs +0 -37
- package/dist/lib/node/call-manager-HV2XJW5O.cjs.map +0 -7
- package/dist/lib/node/chunk-44I33JDT.cjs +0 -1731
- package/dist/lib/node/chunk-44I33JDT.cjs.map +0 -7
- package/dist/lib/node/chunk-4YSNVPWU.cjs +0 -37
- package/dist/lib/node/chunk-4YSNVPWU.cjs.map +0 -7
- package/dist/lib/node/chunk-E3WBZTTI.cjs +0 -371
- package/dist/lib/node/chunk-E3WBZTTI.cjs.map +0 -7
- package/dist/lib/node/chunk-ERG7G6FF.cjs +0 -59
- package/dist/lib/node/chunk-ERG7G6FF.cjs.map +0 -7
- package/dist/lib/node/chunk-FUXJAVFZ.cjs +0 -108
- package/dist/lib/node/chunk-FUXJAVFZ.cjs.map +0 -7
- package/dist/lib/node/chunk-HLMCEE5K.cjs +0 -41
- package/dist/lib/node/chunk-HLMCEE5K.cjs.map +0 -7
- package/dist/lib/node/chunk-IP533AMV.cjs +0 -554
- package/dist/lib/node/chunk-IP533AMV.cjs.map +0 -7
- package/dist/lib/node/chunk-LR5NENBE.cjs +0 -54
- package/dist/lib/node/chunk-LR5NENBE.cjs.map +0 -7
- package/dist/lib/node/chunk-UM36TPCT.cjs +0 -984
- package/dist/lib/node/chunk-UM36TPCT.cjs.map +0 -7
- package/dist/lib/node/chunk-ZGDN3XBR.cjs +0 -149
- package/dist/lib/node/chunk-ZGDN3XBR.cjs.map +0 -7
- package/dist/lib/node/index.cjs +0 -310
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs +0 -363
- package/dist/lib/node/intent-resolver-SYSJ5SJG.cjs.map +0 -7
- package/dist/lib/node/markdown-GQIPJS2F.cjs +0 -178
- package/dist/lib/node/markdown-GQIPJS2F.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
- package/dist/lib/node/react-root-6HHDMULJ.cjs +0 -51
- package/dist/lib/node/react-root-6HHDMULJ.cjs.map +0 -7
- package/dist/lib/node/react-surface-NBH42NN2.cjs +0 -122
- package/dist/lib/node/react-surface-NBH42NN2.cjs.map +0 -7
- package/dist/lib/node/settings-4LQSFEDK.cjs +0 -36
- package/dist/lib/node/settings-4LQSFEDK.cjs.map +0 -7
- package/dist/lib/node/state-IY5XX3H2.cjs +0 -50
- package/dist/lib/node/state-IY5XX3H2.cjs.map +0 -7
- package/dist/lib/node/types/index.cjs +0 -38
- package/dist/lib/node/types/index.cjs.map +0 -7
- package/dist/lib/node-esm/ChannelContainer-O4QJII2P.mjs +0 -16
- package/dist/lib/node-esm/chunk-2RNIPFDA.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-O3V45YJP.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-O63QJPQX.mjs +0 -23
- package/dist/lib/node-esm/chunk-P6RLFCNT.mjs +0 -352
- package/dist/lib/node-esm/chunk-P6RLFCNT.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UZWVVFT3.mjs +0 -551
- package/dist/lib/node-esm/chunk-UZWVVFT3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-WXNPD542.mjs.map +0 -7
- package/dist/types/src/components/CommentContainer.d.ts +0 -13
- package/dist/types/src/components/CommentContainer.d.ts.map +0 -1
- package/dist/types/src/peers.stories.d.ts +0 -11
- package/dist/types/src/peers.stories.d.ts.map +0 -1
- package/src/peers.stories.tsx +0 -189
- /package/dist/lib/browser/{ChannelContainer-PKFBVENP.mjs.map → ChannelContainer-5YH4FTBL.mjs.map} +0 -0
- /package/dist/lib/browser/{ChatContainer-RSOKYAMK.mjs.map → ChatContainer-2UYQ23KO.mjs.map} +0 -0
- /package/dist/lib/browser/{app-graph-builder-OY7R7EJP.mjs.map → app-graph-builder-Q5V3KXE3.mjs.map} +0 -0
- /package/dist/lib/{node-esm/call-manager-UUYXLF4T.mjs.map → browser/call-manager-NIPDYUVD.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-6NBVNXTM.mjs.map → chunk-5ZVJ4GAS.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-IIUTBDVB.mjs.map → chunk-EV4JWI7L.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-JKQUJOTX.mjs.map → chunk-GERVMFQW.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-AEXWNS6Z.mjs.map → chunk-JVIKVYTI.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-R5MDLUPC.mjs.map → chunk-LGSDKXPF.mjs.map} +0 -0
- /package/dist/lib/browser/{intent-resolver-FK2MDVDT.mjs.map → intent-resolver-MWE6XLPY.mjs.map} +0 -0
- /package/dist/lib/browser/{markdown-TE5SWWNJ.mjs.map → markdown-ZO34G7RM.mjs.map} +0 -0
- /package/dist/lib/{node-esm/react-root-RUXOAQNW.mjs.map → browser/react-root-YNDNPODD.mjs.map} +0 -0
- /package/dist/lib/{node-esm/react-surface-ELXFYKP6.mjs.map → browser/react-surface-2AXRNTCA.mjs.map} +0 -0
- /package/dist/lib/browser/{settings-RB2RSLXV.mjs.map → settings-XZGPZNAU.mjs.map} +0 -0
- /package/dist/lib/browser/{state-RKL5MSDP.mjs.map → state-H6CYONWE.mjs.map} +0 -0
- /package/dist/lib/node-esm/{ChannelContainer-O4QJII2P.mjs.map → ChannelContainer-O2LZKMRM.mjs.map} +0 -0
- /package/dist/lib/node-esm/{ChatContainer-F6CSADV7.mjs.map → ChatContainer-6N35MP5J.mjs.map} +0 -0
- /package/dist/lib/node-esm/{app-graph-builder-BAHBHYWI.mjs.map → app-graph-builder-GAKBZNU3.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-UJMPYKT3.mjs.map → chunk-3X3YKRM2.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-PGRP3O4O.mjs.map → chunk-57XR3LEF.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-K4KAUOKT.mjs.map → chunk-75RJ5DJI.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-ESQC6SYE.mjs.map → chunk-GRLRWTRU.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-O63QJPQX.mjs.map → chunk-X62X3VOK.mjs.map} +0 -0
- /package/dist/lib/node-esm/{intent-resolver-BU73VYW3.mjs.map → intent-resolver-B6PNTMPY.mjs.map} +0 -0
- /package/dist/lib/node-esm/{markdown-HJUWNBLS.mjs.map → markdown-ZJUFV2TA.mjs.map} +0 -0
- /package/dist/lib/node-esm/{settings-EA7DFSM6.mjs.map → settings-XECBSD6Q.mjs.map} +0 -0
- /package/dist/lib/node-esm/{state-6AUTNROZ.mjs.map → state-D7WNDT3N.mjs.map} +0 -0
|
@@ -1,1731 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var chunk_44I33JDT_exports = {};
|
|
30
|
-
__export(chunk_44I33JDT_exports, {
|
|
31
|
-
CALLS_URL: () => CALLS_URL,
|
|
32
|
-
CallManager: () => CallManager,
|
|
33
|
-
CallSwarmSynchronizer: () => CallSwarmSynchronizer,
|
|
34
|
-
CallsServicePeer: () => CallsServicePeer,
|
|
35
|
-
MediaManager: () => MediaManager,
|
|
36
|
-
SpeakingMonitor: () => SpeakingMonitor,
|
|
37
|
-
TrackNameCodec: () => TrackNameCodec,
|
|
38
|
-
codec: () => codec,
|
|
39
|
-
createBlackCanvasStreamTrack: () => createBlackCanvasStreamTrack,
|
|
40
|
-
createInaudibleAudioStreamTrack: () => createInaudibleAudioStreamTrack,
|
|
41
|
-
getDeviceList: () => getDeviceList,
|
|
42
|
-
getScreenshare: () => getScreenshare,
|
|
43
|
-
getUserMediaTrack: () => getUserMediaTrack,
|
|
44
|
-
monitorAudioLevel: () => monitorAudioLevel
|
|
45
|
-
});
|
|
46
|
-
module.exports = __toCommonJS(chunk_44I33JDT_exports);
|
|
47
|
-
var import_buf = require("@dxos/protocols/buf");
|
|
48
|
-
var import_calls_pb = require("@dxos/protocols/buf/dxos/edge/calls_pb");
|
|
49
|
-
var import_md5_hex = __toESM(require("md5-hex"));
|
|
50
|
-
var import_async = require("@dxos/async");
|
|
51
|
-
var import_context = require("@dxos/context");
|
|
52
|
-
var import_display_name = require("@dxos/display-name");
|
|
53
|
-
var import_invariant = require("@dxos/invariant");
|
|
54
|
-
var import_keys = require("@dxos/keys");
|
|
55
|
-
var import_log = require("@dxos/log");
|
|
56
|
-
var import_buf2 = require("@dxos/protocols/buf");
|
|
57
|
-
var import_calls_pb2 = require("@dxos/protocols/buf/dxos/edge/calls_pb");
|
|
58
|
-
var import_messenger = require("@dxos/protocols/proto/dxos/edge/messenger");
|
|
59
|
-
var import_util = require("@dxos/util");
|
|
60
|
-
var import_async2 = require("@dxos/async");
|
|
61
|
-
var import_context2 = require("@dxos/context");
|
|
62
|
-
var import_invariant2 = require("@dxos/invariant");
|
|
63
|
-
var import_log2 = require("@dxos/log");
|
|
64
|
-
var import_log3 = require("@dxos/log");
|
|
65
|
-
var import_async3 = require("@dxos/async");
|
|
66
|
-
var import_context3 = require("@dxos/context");
|
|
67
|
-
var import_invariant3 = require("@dxos/invariant");
|
|
68
|
-
var import_async4 = require("@dxos/async");
|
|
69
|
-
var import_context4 = require("@dxos/context");
|
|
70
|
-
var import_async5 = require("@dxos/async");
|
|
71
|
-
var import_context5 = require("@dxos/context");
|
|
72
|
-
var import_log4 = require("@dxos/log");
|
|
73
|
-
var import_signals_core = require("@preact/signals-core");
|
|
74
|
-
var import_async6 = require("@dxos/async");
|
|
75
|
-
var import_context6 = require("@dxos/context");
|
|
76
|
-
var import_invariant4 = require("@dxos/invariant");
|
|
77
|
-
var import_live_object = require("@dxos/live-object");
|
|
78
|
-
var import_util2 = require("@dxos/util");
|
|
79
|
-
var CALLS_URL = "https://calls-service.dxos.workers.dev";
|
|
80
|
-
var codec = {
|
|
81
|
-
encode: (message) => {
|
|
82
|
-
return import_buf.buf.toBinary(import_calls_pb.UserStateSchema, import_buf.buf.create(import_calls_pb.UserStateSchema, message));
|
|
83
|
-
},
|
|
84
|
-
decode: (message) => {
|
|
85
|
-
return import_buf.buf.fromBinary(import_calls_pb.UserStateSchema, message);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
var TrackNameCodec = {
|
|
89
|
-
encode: (trackData) => {
|
|
90
|
-
return trackData.sessionId + "/" + trackData.trackName;
|
|
91
|
-
},
|
|
92
|
-
decode: (name) => {
|
|
93
|
-
const [sessionId, trackName] = name.split("/");
|
|
94
|
-
return {
|
|
95
|
-
sessionId,
|
|
96
|
-
trackName,
|
|
97
|
-
location: "remote"
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
102
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
103
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
104
|
-
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;
|
|
105
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
106
|
-
}
|
|
107
|
-
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/calls/call-swarm-synchronizer.ts";
|
|
108
|
-
var DISCONNECTED_ABRUPT_TIMEOUT = 1e4;
|
|
109
|
-
var CallSwarmSynchronizer = class extends import_context.Resource {
|
|
110
|
-
constructor({ networkService }) {
|
|
111
|
-
super();
|
|
112
|
-
this.stateUpdated = new import_async.Event();
|
|
113
|
-
this._state = {
|
|
114
|
-
activities: {}
|
|
115
|
-
};
|
|
116
|
-
this._lastSwarmEvent = void 0;
|
|
117
|
-
this._reconcileSwarmStateTask = void 0;
|
|
118
|
-
this._identityKey = void 0;
|
|
119
|
-
this._deviceKey = void 0;
|
|
120
|
-
this._displayName = void 0;
|
|
121
|
-
this._swarmCtx = void 0;
|
|
122
|
-
this._sendStateTask = void 0;
|
|
123
|
-
this._networkService = networkService;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* @internal
|
|
127
|
-
*/
|
|
128
|
-
_getState() {
|
|
129
|
-
return this._state;
|
|
130
|
-
}
|
|
131
|
-
setRaisedHand(raisedHand) {
|
|
132
|
-
if (this._state.raisedHand === raisedHand) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
this._state.raisedHand = raisedHand;
|
|
136
|
-
this._notifyAndSchedule();
|
|
137
|
-
}
|
|
138
|
-
setSpeaking(speaking) {
|
|
139
|
-
if (this._state.speaking === speaking) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
this._state.speaking = speaking;
|
|
143
|
-
this._notifyAndSchedule();
|
|
144
|
-
}
|
|
145
|
-
setJoined(joined) {
|
|
146
|
-
if (this._state.joined === joined) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
this._state.joined = joined;
|
|
150
|
-
this._notifyAndSchedule();
|
|
151
|
-
}
|
|
152
|
-
setTracks(tracks) {
|
|
153
|
-
this._state.tracks = {
|
|
154
|
-
...this._state.tracks,
|
|
155
|
-
...tracks
|
|
156
|
-
};
|
|
157
|
-
this._notifyAndSchedule();
|
|
158
|
-
}
|
|
159
|
-
setActivity(key, payload) {
|
|
160
|
-
const lamportTimestamp = LamportTimestampCrdt.increment(this._state.activities?.[key]?.lamportTimestamp ?? {
|
|
161
|
-
id: this._deviceKey
|
|
162
|
-
});
|
|
163
|
-
this._state.activities[key] = {
|
|
164
|
-
lamportTimestamp,
|
|
165
|
-
payload
|
|
166
|
-
};
|
|
167
|
-
this._notifyAndSchedule();
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* @internal
|
|
171
|
-
*/
|
|
172
|
-
_setIdentity(identity) {
|
|
173
|
-
this._identityKey = identity.identityKey.toHex();
|
|
174
|
-
this._displayName = identity.profile?.displayName ?? (0, import_display_name.generateName)(identity.identityKey.toHex());
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* @internal
|
|
178
|
-
*/
|
|
179
|
-
_setDevice(device) {
|
|
180
|
-
this._deviceKey = device.deviceKey.toHex();
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* @internal
|
|
184
|
-
*/
|
|
185
|
-
_setRoomId(roomId) {
|
|
186
|
-
if (this._swarmCtx) {
|
|
187
|
-
import_log.log.verbose("joined to a different room", {
|
|
188
|
-
roomId
|
|
189
|
-
}, {
|
|
190
|
-
F: __dxlog_file,
|
|
191
|
-
L: 152,
|
|
192
|
-
S: this,
|
|
193
|
-
C: (f, a) => f(...a)
|
|
194
|
-
});
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
this._state.roomId = roomId;
|
|
198
|
-
}
|
|
199
|
-
async _open() {
|
|
200
|
-
this._sendStateTask = new import_async.DeferredTask(this._ctx, async () => {
|
|
201
|
-
await this._sendState();
|
|
202
|
-
});
|
|
203
|
-
this._reconcileSwarmStateTask = new import_async.DeferredTask(this._ctx, async () => {
|
|
204
|
-
await this._reconcileSwarmState();
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
async _close() {
|
|
208
|
-
this._sendStateTask = void 0;
|
|
209
|
-
this._reconcileSwarmStateTask = void 0;
|
|
210
|
-
}
|
|
211
|
-
async join() {
|
|
212
|
-
(0, import_invariant.invariant)(this._state.roomId, void 0, {
|
|
213
|
-
F: __dxlog_file,
|
|
214
|
-
L: 176,
|
|
215
|
-
S: this,
|
|
216
|
-
A: [
|
|
217
|
-
"this._state.roomId",
|
|
218
|
-
""
|
|
219
|
-
]
|
|
220
|
-
});
|
|
221
|
-
(0, import_invariant.invariant)(!this._swarmCtx, "Already joined", {
|
|
222
|
-
F: __dxlog_file,
|
|
223
|
-
L: 177,
|
|
224
|
-
S: this,
|
|
225
|
-
A: [
|
|
226
|
-
"!this._swarmCtx",
|
|
227
|
-
"'Already joined'"
|
|
228
|
-
]
|
|
229
|
-
});
|
|
230
|
-
this._swarmCtx = new import_context.Context(void 0, {
|
|
231
|
-
F: __dxlog_file,
|
|
232
|
-
L: 179
|
|
233
|
-
});
|
|
234
|
-
const topic = getTopic(this._state.roomId);
|
|
235
|
-
(0, import_log.log)("joining swarm", {
|
|
236
|
-
topic,
|
|
237
|
-
peer: {
|
|
238
|
-
identityKey: this._identityKey,
|
|
239
|
-
peerKey: this._deviceKey
|
|
240
|
-
}
|
|
241
|
-
}, {
|
|
242
|
-
F: __dxlog_file,
|
|
243
|
-
L: 181,
|
|
244
|
-
S: this,
|
|
245
|
-
C: (f, a) => f(...a)
|
|
246
|
-
});
|
|
247
|
-
const stream = this._networkService.subscribeSwarmState({
|
|
248
|
-
topic
|
|
249
|
-
});
|
|
250
|
-
stream.subscribe((event) => this._processSwarmEvent(event));
|
|
251
|
-
const cleanup = () => {
|
|
252
|
-
void stream.close();
|
|
253
|
-
if (topic && this._identityKey && this._deviceKey) {
|
|
254
|
-
(0, import_log.log)("leaving swarm", {
|
|
255
|
-
topic,
|
|
256
|
-
peer: {
|
|
257
|
-
identityKey: this._identityKey,
|
|
258
|
-
peerKey: this._deviceKey
|
|
259
|
-
}
|
|
260
|
-
}, {
|
|
261
|
-
F: __dxlog_file,
|
|
262
|
-
L: 188,
|
|
263
|
-
S: this,
|
|
264
|
-
C: (f, a) => f(...a)
|
|
265
|
-
});
|
|
266
|
-
void this._networkService.leaveSwarm({
|
|
267
|
-
topic,
|
|
268
|
-
peer: {
|
|
269
|
-
identityKey: this._identityKey,
|
|
270
|
-
peerKey: this._deviceKey
|
|
271
|
-
}
|
|
272
|
-
}).catch((err) => import_log.log.catch(err, void 0, {
|
|
273
|
-
F: __dxlog_file,
|
|
274
|
-
L: 194,
|
|
275
|
-
S: this,
|
|
276
|
-
C: (f, a) => f(...a)
|
|
277
|
-
}));
|
|
278
|
-
}
|
|
279
|
-
window.removeEventListener("beforeunload", cleanup);
|
|
280
|
-
};
|
|
281
|
-
window.addEventListener("beforeunload", cleanup);
|
|
282
|
-
this._swarmCtx.onDispose(cleanup);
|
|
283
|
-
this._notifyAndSchedule();
|
|
284
|
-
}
|
|
285
|
-
async leave() {
|
|
286
|
-
if (!this._swarmCtx) {
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
await this._swarmCtx.dispose();
|
|
290
|
-
this._swarmCtx = void 0;
|
|
291
|
-
this._state.users = void 0;
|
|
292
|
-
this._state.self = void 0;
|
|
293
|
-
}
|
|
294
|
-
async querySwarm(roomId) {
|
|
295
|
-
const topic = getTopic(roomId);
|
|
296
|
-
const swarm = await this._networkService.querySwarm({
|
|
297
|
-
topic
|
|
298
|
-
});
|
|
299
|
-
return swarm.peers ?? [];
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Notify and schedule send state task.
|
|
303
|
-
*/
|
|
304
|
-
_notifyAndSchedule() {
|
|
305
|
-
this.stateUpdated.emit(this._state);
|
|
306
|
-
if (this._state.joined) {
|
|
307
|
-
this._sendStateTask?.schedule();
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
async _sendState() {
|
|
311
|
-
if (!this._state.roomId || !this._identityKey || !this._deviceKey || !this._state.joined) {
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
const state = {
|
|
315
|
-
...this._state,
|
|
316
|
-
id: this._deviceKey,
|
|
317
|
-
name: this._displayName,
|
|
318
|
-
activities: this._state.activities ? Object.fromEntries(Object.entries(this._state.activities).map(([key, activity]) => [
|
|
319
|
-
key,
|
|
320
|
-
import_buf2.buf.create(import_calls_pb2.ActivitySchema, activity)
|
|
321
|
-
])) : {}
|
|
322
|
-
};
|
|
323
|
-
await this._networkService.joinSwarm({
|
|
324
|
-
topic: getTopic(this._state.roomId),
|
|
325
|
-
peer: {
|
|
326
|
-
identityKey: this._identityKey,
|
|
327
|
-
peerKey: this._deviceKey,
|
|
328
|
-
state: codec.encode(state)
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
_processSwarmEvent(swarmEvent) {
|
|
333
|
-
if (!this._state.joined) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
this._lastSwarmEvent = swarmEvent;
|
|
337
|
-
this._reconcileSwarmStateTask.schedule();
|
|
338
|
-
}
|
|
339
|
-
async _reconcileSwarmState() {
|
|
340
|
-
const swarmEvent = this._lastSwarmEvent;
|
|
341
|
-
(0, import_invariant.invariant)(swarmEvent, void 0, {
|
|
342
|
-
F: __dxlog_file,
|
|
343
|
-
L: 273,
|
|
344
|
-
S: this,
|
|
345
|
-
A: [
|
|
346
|
-
"swarmEvent",
|
|
347
|
-
""
|
|
348
|
-
]
|
|
349
|
-
});
|
|
350
|
-
const peers = [
|
|
351
|
-
...swarmEvent.peers ?? [],
|
|
352
|
-
...(swarmEvent.inactivePeers ?? []).filter(({ disconnected, connectionState }) => connectionState === import_messenger.ConnectionState.DISCONNECTED_ABRUPT && disconnected && disconnected > Date.now() - DISCONNECTED_ABRUPT_TIMEOUT)
|
|
353
|
-
].sort((peer1, peer2) => peer1.peerKey.localeCompare(peer2.peerKey));
|
|
354
|
-
const users = peers.map((peer) => {
|
|
355
|
-
try {
|
|
356
|
-
return codec.decode(peer.state);
|
|
357
|
-
} catch (error) {
|
|
358
|
-
import_log.log.error("error decoding peer state", {
|
|
359
|
-
error,
|
|
360
|
-
peer
|
|
361
|
-
}, {
|
|
362
|
-
F: __dxlog_file,
|
|
363
|
-
L: 290,
|
|
364
|
-
S: this,
|
|
365
|
-
C: (f, a) => f(...a)
|
|
366
|
-
});
|
|
367
|
-
return void 0;
|
|
368
|
-
}
|
|
369
|
-
}).filter(import_util.isNonNullable);
|
|
370
|
-
this._state.users = users;
|
|
371
|
-
this._state.self = users.find((user) => user.id === this._deviceKey);
|
|
372
|
-
(0, import_log.log)("reconciling swarm state", {
|
|
373
|
-
users
|
|
374
|
-
}, {
|
|
375
|
-
F: __dxlog_file,
|
|
376
|
-
L: 297,
|
|
377
|
-
S: this,
|
|
378
|
-
C: (f, a) => f(...a)
|
|
379
|
-
});
|
|
380
|
-
if (users.length === 0) {
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
const activityKeys = new Set(users.flatMap((user) => Object.keys(user.activities)));
|
|
384
|
-
[
|
|
385
|
-
...activityKeys
|
|
386
|
-
].forEach((key) => {
|
|
387
|
-
const activities = users.map((user) => user.activities?.[key]).filter(import_util.isNonNullable);
|
|
388
|
-
const lastActivity = LamportTimestampCrdt.getLastState(activities);
|
|
389
|
-
if (lastActivity && lastActivity.lamportTimestamp.version > (this._state.activities[key]?.lamportTimestamp?.version ?? 0)) {
|
|
390
|
-
this._state.activities[key] = lastActivity;
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
this.stateUpdated.emit(this._state);
|
|
394
|
-
if (peers.some((peer) => peer.connectionState !== import_messenger.ConnectionState.CONNECTED)) {
|
|
395
|
-
(0, import_async.scheduleTaskInterval)(this._ctx, async () => this._reconcileSwarmStateTask.schedule(), Math.min(DISCONNECTED_ABRUPT_TIMEOUT / 2, 1e3));
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
};
|
|
399
|
-
_ts_decorate([
|
|
400
|
-
import_async.synchronized
|
|
401
|
-
], CallSwarmSynchronizer.prototype, "join", null);
|
|
402
|
-
_ts_decorate([
|
|
403
|
-
import_async.synchronized
|
|
404
|
-
], CallSwarmSynchronizer.prototype, "leave", null);
|
|
405
|
-
var LamportTimestampCrdt = class {
|
|
406
|
-
static getLastState(states) {
|
|
407
|
-
const maxTimestamp = Math.max(...states.map((state) => state.lamportTimestamp?.version ?? 0));
|
|
408
|
-
const sortedStates = states.filter((state) => state.lamportTimestamp && state.lamportTimestamp.version === maxTimestamp && state.lamportTimestamp.id).sort((a, b) => a.lamportTimestamp.id.localeCompare(b.lamportTimestamp.id));
|
|
409
|
-
return sortedStates[0];
|
|
410
|
-
}
|
|
411
|
-
static increment(timestamp) {
|
|
412
|
-
return {
|
|
413
|
-
...timestamp ?? {},
|
|
414
|
-
version: (timestamp?.version ?? 0) + 1
|
|
415
|
-
};
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
var getTopic = (roomId) => import_keys.PublicKey.fromHex((0, import_md5_hex.default)(roomId));
|
|
419
|
-
var monitorAudioLevel = ({ mediaStreamTrack, intervalMs = 1e3 / 10, onMeasure }) => {
|
|
420
|
-
let timeout = -1;
|
|
421
|
-
let interval = -1;
|
|
422
|
-
const audioContext = new AudioContext();
|
|
423
|
-
const stream = new MediaStream();
|
|
424
|
-
stream.addTrack(mediaStreamTrack);
|
|
425
|
-
const mediaStreamAudioSourceNode = audioContext.createMediaStreamSource(stream);
|
|
426
|
-
const analyserNode = audioContext.createAnalyser();
|
|
427
|
-
mediaStreamAudioSourceNode.connect(analyserNode);
|
|
428
|
-
analyserNode.fftSize = 32;
|
|
429
|
-
const pcmData = new Float32Array(analyserNode.fftSize);
|
|
430
|
-
let peak = 0;
|
|
431
|
-
interval = window.setInterval(() => {
|
|
432
|
-
onMeasure(peak);
|
|
433
|
-
peak = 0;
|
|
434
|
-
}, intervalMs);
|
|
435
|
-
const tick = () => {
|
|
436
|
-
timeout = window.setTimeout(() => {
|
|
437
|
-
analyserNode.getFloatTimeDomainData(pcmData);
|
|
438
|
-
let sumSquares = 0;
|
|
439
|
-
for (const amplitude of pcmData) {
|
|
440
|
-
sumSquares += amplitude * amplitude;
|
|
441
|
-
}
|
|
442
|
-
const current = Math.sqrt(sumSquares / pcmData.length);
|
|
443
|
-
if (current > peak) {
|
|
444
|
-
peak = current;
|
|
445
|
-
}
|
|
446
|
-
tick();
|
|
447
|
-
}, intervalMs);
|
|
448
|
-
};
|
|
449
|
-
tick();
|
|
450
|
-
return () => {
|
|
451
|
-
mediaStreamAudioSourceNode.disconnect();
|
|
452
|
-
analyserNode.disconnect();
|
|
453
|
-
void audioContext.close();
|
|
454
|
-
clearInterval(interval);
|
|
455
|
-
clearTimeout(timeout);
|
|
456
|
-
stream.removeTrack(mediaStreamTrack);
|
|
457
|
-
};
|
|
458
|
-
};
|
|
459
|
-
var HistoryCache = class {
|
|
460
|
-
constructor(limit = 100) {
|
|
461
|
-
this._limit = limit;
|
|
462
|
-
this._messages = [];
|
|
463
|
-
}
|
|
464
|
-
push(...messages) {
|
|
465
|
-
if (this._messages.length >= this._limit) {
|
|
466
|
-
this._messages.shift();
|
|
467
|
-
}
|
|
468
|
-
this._messages.push(...messages);
|
|
469
|
-
}
|
|
470
|
-
get() {
|
|
471
|
-
return this._messages;
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
var DefaultBatchSizeLimit = 64;
|
|
475
|
-
var FIFOScheduler = class {
|
|
476
|
-
#schedulerChain;
|
|
477
|
-
constructor() {
|
|
478
|
-
this.#schedulerChain = Promise.resolve();
|
|
479
|
-
}
|
|
480
|
-
schedule(task) {
|
|
481
|
-
return new Promise((resolve, reject) => {
|
|
482
|
-
this.#schedulerChain = this.#schedulerChain.then(async () => {
|
|
483
|
-
try {
|
|
484
|
-
resolve(await task());
|
|
485
|
-
} catch (error) {
|
|
486
|
-
reject(error);
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
};
|
|
492
|
-
var BulkRequestDispatcher = class {
|
|
493
|
-
#currentBatch;
|
|
494
|
-
#currentBulkResponse;
|
|
495
|
-
#batchSizeLimit;
|
|
496
|
-
constructor(batchSizeLimit = DefaultBatchSizeLimit) {
|
|
497
|
-
this.#currentBatch = [];
|
|
498
|
-
this.#currentBulkResponse = null;
|
|
499
|
-
this.#batchSizeLimit = batchSizeLimit;
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Returns a bulk response promise.
|
|
503
|
-
* At the event loop iteration end, the accumulated entries will be dispatched as a bulk request.
|
|
504
|
-
*/
|
|
505
|
-
doBulkRequest(params, bulkRequestFunc) {
|
|
506
|
-
if (this.#currentBatch.length >= this.#batchSizeLimit) {
|
|
507
|
-
this.#currentBatch = [];
|
|
508
|
-
this.#currentBulkResponse = null;
|
|
509
|
-
}
|
|
510
|
-
this.#currentBatch.push(params);
|
|
511
|
-
if (this.#currentBulkResponse != null) {
|
|
512
|
-
return this.#currentBulkResponse;
|
|
513
|
-
}
|
|
514
|
-
const batch = this.#currentBatch;
|
|
515
|
-
this.#currentBulkResponse = new Promise((resolve, reject) => {
|
|
516
|
-
setTimeout(() => {
|
|
517
|
-
this.#currentBulkResponse = null;
|
|
518
|
-
const batchCopy = batch.splice(0, batch.length);
|
|
519
|
-
bulkRequestFunc(batchCopy).then((result) => {
|
|
520
|
-
resolve(result);
|
|
521
|
-
}).catch((err) => {
|
|
522
|
-
reject(err);
|
|
523
|
-
});
|
|
524
|
-
}, 0);
|
|
525
|
-
});
|
|
526
|
-
return this.#currentBulkResponse;
|
|
527
|
-
}
|
|
528
|
-
};
|
|
529
|
-
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/calls/util/calls-service.ts";
|
|
530
|
-
var NETWORK_TIMEOUT = 5e3;
|
|
531
|
-
var CallsServicePeer = class extends import_context2.Resource {
|
|
532
|
-
constructor(config) {
|
|
533
|
-
super();
|
|
534
|
-
this.history = new HistoryCache(100);
|
|
535
|
-
this._persistentLifecycle = new import_async2.PersistentLifecycle({
|
|
536
|
-
start: () => this._startSession(),
|
|
537
|
-
stop: (session) => this._stopSession(session)
|
|
538
|
-
});
|
|
539
|
-
this.taskScheduler = new FIFOScheduler();
|
|
540
|
-
this.pushTrackDispatcher = new BulkRequestDispatcher(32);
|
|
541
|
-
this.pullTrackDispatcher = new BulkRequestDispatcher(32);
|
|
542
|
-
this.closeTrackDispatcher = new BulkRequestDispatcher(32);
|
|
543
|
-
this._config = config;
|
|
544
|
-
}
|
|
545
|
-
async _open(ctx) {
|
|
546
|
-
await this._persistentLifecycle.open(ctx);
|
|
547
|
-
}
|
|
548
|
-
async _close() {
|
|
549
|
-
await this._persistentLifecycle.close();
|
|
550
|
-
}
|
|
551
|
-
get session() {
|
|
552
|
-
return this._persistentLifecycle.state;
|
|
553
|
-
}
|
|
554
|
-
async _startSession() {
|
|
555
|
-
const peerConnection = await this._createRtcConnection();
|
|
556
|
-
const sessionId = await this._initiateCallSession();
|
|
557
|
-
return {
|
|
558
|
-
sessionId,
|
|
559
|
-
peerConnection
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
async _stopSession(session) {
|
|
563
|
-
session.peerConnection.close();
|
|
564
|
-
}
|
|
565
|
-
async _createRtcConnection() {
|
|
566
|
-
const peerConnection = new RTCPeerConnection({
|
|
567
|
-
iceServers: this._config.iceServers,
|
|
568
|
-
bundlePolicy: "max-bundle"
|
|
569
|
-
});
|
|
570
|
-
peerConnection.addEventListener("connectionstatechange", () => {
|
|
571
|
-
if (peerConnection.connectionState === "failed" || peerConnection.connectionState === "closed") {
|
|
572
|
-
import_log2.log.warn("calls connection failed", {
|
|
573
|
-
state: peerConnection.connectionState
|
|
574
|
-
}, {
|
|
575
|
-
F: __dxlog_file2,
|
|
576
|
-
L: 115,
|
|
577
|
-
S: this,
|
|
578
|
-
C: (f, a) => f(...a)
|
|
579
|
-
});
|
|
580
|
-
void this._persistentLifecycle.scheduleRestart();
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
let iceTimeout = -1;
|
|
584
|
-
peerConnection.addEventListener("iceconnectionstatechange", () => {
|
|
585
|
-
clearTimeout(iceTimeout);
|
|
586
|
-
if (peerConnection.iceConnectionState === "failed" || peerConnection.iceConnectionState === "closed") {
|
|
587
|
-
import_log2.log.warn("calls connection to ICEs failed", {
|
|
588
|
-
state: peerConnection.iceConnectionState
|
|
589
|
-
}, {
|
|
590
|
-
F: __dxlog_file2,
|
|
591
|
-
L: 124,
|
|
592
|
-
S: this,
|
|
593
|
-
C: (f, a) => f(...a)
|
|
594
|
-
});
|
|
595
|
-
void this._persistentLifecycle.scheduleRestart();
|
|
596
|
-
} else if (peerConnection.iceConnectionState === "disconnected") {
|
|
597
|
-
const timeoutSeconds = 7;
|
|
598
|
-
iceTimeout = window.setTimeout(() => {
|
|
599
|
-
if (peerConnection.iceConnectionState === "connected") {
|
|
600
|
-
import_log2.log.info("calls iceConnectionState is connected", void 0, {
|
|
601
|
-
F: __dxlog_file2,
|
|
602
|
-
L: 133,
|
|
603
|
-
S: this,
|
|
604
|
-
C: (f, a) => f(...a)
|
|
605
|
-
});
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
608
|
-
import_log2.log.warn("calls iceConnectionState timed out", {
|
|
609
|
-
state: peerConnection.iceConnectionState,
|
|
610
|
-
timeoutSeconds
|
|
611
|
-
}, {
|
|
612
|
-
F: __dxlog_file2,
|
|
613
|
-
L: 137,
|
|
614
|
-
S: this,
|
|
615
|
-
C: (f, a) => f(...a)
|
|
616
|
-
});
|
|
617
|
-
void this._persistentLifecycle.scheduleRestart();
|
|
618
|
-
}, timeoutSeconds * 1e3);
|
|
619
|
-
}
|
|
620
|
-
});
|
|
621
|
-
return peerConnection;
|
|
622
|
-
}
|
|
623
|
-
async _initiateCallSession() {
|
|
624
|
-
(0, import_log2.log)("creating new session", void 0, {
|
|
625
|
-
F: __dxlog_file2,
|
|
626
|
-
L: 147,
|
|
627
|
-
S: this,
|
|
628
|
-
C: (f, a) => f(...a)
|
|
629
|
-
});
|
|
630
|
-
const { sessionId } = await this._fetch("/sessions/new?SESSION", {
|
|
631
|
-
method: "POST"
|
|
632
|
-
});
|
|
633
|
-
return sessionId;
|
|
634
|
-
}
|
|
635
|
-
async _fetch(relativePath, requestInit) {
|
|
636
|
-
this.history.push({
|
|
637
|
-
type: "request",
|
|
638
|
-
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
639
|
-
method: requestInit?.method ?? "GET",
|
|
640
|
-
body: requestInit?.body
|
|
641
|
-
});
|
|
642
|
-
const response = await fetch(`${this._config.apiBase}${relativePath}`, {
|
|
643
|
-
...requestInit,
|
|
644
|
-
redirect: "manual"
|
|
645
|
-
});
|
|
646
|
-
if (response.status >= 400) {
|
|
647
|
-
import_log2.log.error("error while fetching from Calls service", {
|
|
648
|
-
status: response.status,
|
|
649
|
-
text: await response.text()
|
|
650
|
-
}, {
|
|
651
|
-
F: __dxlog_file2,
|
|
652
|
-
L: 162,
|
|
653
|
-
S: this,
|
|
654
|
-
C: (f, a) => f(...a)
|
|
655
|
-
});
|
|
656
|
-
throw new Error("Error while fetching from Calls service");
|
|
657
|
-
}
|
|
658
|
-
try {
|
|
659
|
-
const data = await response.clone().json();
|
|
660
|
-
this.history.push({
|
|
661
|
-
type: "response",
|
|
662
|
-
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
663
|
-
status: response.status,
|
|
664
|
-
json: data
|
|
665
|
-
});
|
|
666
|
-
if (data.errorCode) {
|
|
667
|
-
throw new Error(data.errorDescription);
|
|
668
|
-
}
|
|
669
|
-
return data;
|
|
670
|
-
} catch (error) {
|
|
671
|
-
const text = await response.text();
|
|
672
|
-
this.history.push({
|
|
673
|
-
type: "response",
|
|
674
|
-
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
675
|
-
status: response.status,
|
|
676
|
-
text
|
|
677
|
-
});
|
|
678
|
-
import_log2.log.error("Error parsing response from Calls service", {
|
|
679
|
-
error,
|
|
680
|
-
text,
|
|
681
|
-
status: response.status
|
|
682
|
-
}, {
|
|
683
|
-
F: __dxlog_file2,
|
|
684
|
-
L: 187,
|
|
685
|
-
S: this,
|
|
686
|
-
C: (f, a) => f(...a)
|
|
687
|
-
});
|
|
688
|
-
throw error;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
async _pushTrackInBulk({ ctx, peerConnection, transceiver, sessionId, trackName }) {
|
|
692
|
-
import_log2.log.verbose("pushing track ", trackName, {
|
|
693
|
-
F: __dxlog_file2,
|
|
694
|
-
L: 209,
|
|
695
|
-
S: this,
|
|
696
|
-
C: (f, a) => f(...a)
|
|
697
|
-
});
|
|
698
|
-
const pushedTrackPromise = this.pushTrackDispatcher.doBulkRequest({
|
|
699
|
-
trackName,
|
|
700
|
-
transceiver
|
|
701
|
-
}, (tracks) => this.taskScheduler.schedule(async () => {
|
|
702
|
-
const offer = await peerConnection.createOffer();
|
|
703
|
-
offer.sdp = offer.sdp?.replace("useinbandfec=1", "usedtx=1;useinbandfec=1");
|
|
704
|
-
await peerConnection.setLocalDescription(offer);
|
|
705
|
-
const response = await this._fetch(`/sessions/${sessionId}/tracks/new?PUSHING`, {
|
|
706
|
-
method: "POST",
|
|
707
|
-
body: JSON.stringify({
|
|
708
|
-
sessionDescription: {
|
|
709
|
-
sdp: offer.sdp,
|
|
710
|
-
type: "offer"
|
|
711
|
-
},
|
|
712
|
-
tracks: tracks.map(({ trackName: trackName2, transceiver: transceiver2 }) => ({
|
|
713
|
-
trackName: trackName2,
|
|
714
|
-
mid: transceiver2.mid,
|
|
715
|
-
location: "local"
|
|
716
|
-
}))
|
|
717
|
-
})
|
|
718
|
-
});
|
|
719
|
-
(0, import_invariant2.invariant)(response.tracks !== void 0, void 0, {
|
|
720
|
-
F: __dxlog_file2,
|
|
721
|
-
L: 234,
|
|
722
|
-
S: this,
|
|
723
|
-
A: [
|
|
724
|
-
"response.tracks !== undefined",
|
|
725
|
-
""
|
|
726
|
-
]
|
|
727
|
-
});
|
|
728
|
-
if (!response.errorCode) {
|
|
729
|
-
await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));
|
|
730
|
-
await peerConnectionIsConnected(peerConnection);
|
|
731
|
-
}
|
|
732
|
-
return {
|
|
733
|
-
tracks: response.tracks
|
|
734
|
-
};
|
|
735
|
-
})).then(({ tracks }) => {
|
|
736
|
-
const trackData = tracks.find((t) => t.mid === transceiver.mid);
|
|
737
|
-
if (trackData) {
|
|
738
|
-
return {
|
|
739
|
-
...trackData,
|
|
740
|
-
sessionId,
|
|
741
|
-
location: "remote"
|
|
742
|
-
};
|
|
743
|
-
} else {
|
|
744
|
-
import_log2.log.error("missing track data", void 0, {
|
|
745
|
-
F: __dxlog_file2,
|
|
746
|
-
L: 254,
|
|
747
|
-
S: this,
|
|
748
|
-
C: (f, a) => f(...a)
|
|
749
|
-
});
|
|
750
|
-
}
|
|
751
|
-
}).catch((err) => {
|
|
752
|
-
import_log2.log.catch(err, void 0, {
|
|
753
|
-
F: __dxlog_file2,
|
|
754
|
-
L: 258,
|
|
755
|
-
S: this,
|
|
756
|
-
C: (f, a) => f(...a)
|
|
757
|
-
});
|
|
758
|
-
});
|
|
759
|
-
const onDispose = async () => {
|
|
760
|
-
if (transceiver.mid) {
|
|
761
|
-
await this._closeTrackInBulk(peerConnection, transceiver.mid, sessionId);
|
|
762
|
-
}
|
|
763
|
-
};
|
|
764
|
-
ctx?.onDispose(async () => await onDispose());
|
|
765
|
-
this._ctx.onDispose(() => onDispose());
|
|
766
|
-
return pushedTrackPromise;
|
|
767
|
-
}
|
|
768
|
-
async pushTrack({ track, encodings = [], ctx, previousTrack }) {
|
|
769
|
-
await this.waitUntilOpen();
|
|
770
|
-
(0, import_invariant2.invariant)(this.session, void 0, {
|
|
771
|
-
F: __dxlog_file2,
|
|
772
|
-
L: 285,
|
|
773
|
-
S: this,
|
|
774
|
-
A: [
|
|
775
|
-
"this.session",
|
|
776
|
-
""
|
|
777
|
-
]
|
|
778
|
-
});
|
|
779
|
-
(0, import_log2.log)("trying to push track", {
|
|
780
|
-
track,
|
|
781
|
-
previousTrack,
|
|
782
|
-
encodings
|
|
783
|
-
}, {
|
|
784
|
-
F: __dxlog_file2,
|
|
785
|
-
L: 286,
|
|
786
|
-
S: this,
|
|
787
|
-
C: (f, a) => f(...a)
|
|
788
|
-
});
|
|
789
|
-
if (previousTrack) {
|
|
790
|
-
const transceiver2 = this.session.peerConnection.getTransceivers().find((t) => t.mid === previousTrack.mid);
|
|
791
|
-
if (transceiver2?.sender.track === track) {
|
|
792
|
-
import_log2.log.verbose("track already pushed", {
|
|
793
|
-
track,
|
|
794
|
-
previousTrack,
|
|
795
|
-
transceiver: transceiver2
|
|
796
|
-
}, {
|
|
797
|
-
F: __dxlog_file2,
|
|
798
|
-
L: 290,
|
|
799
|
-
S: this,
|
|
800
|
-
C: (f, a) => f(...a)
|
|
801
|
-
});
|
|
802
|
-
return previousTrack;
|
|
803
|
-
} else if (transceiver2) {
|
|
804
|
-
import_log2.log.verbose("replacing track", {
|
|
805
|
-
track,
|
|
806
|
-
previousTrack,
|
|
807
|
-
transceiver: transceiver2
|
|
808
|
-
}, {
|
|
809
|
-
F: __dxlog_file2,
|
|
810
|
-
L: 293,
|
|
811
|
-
S: this,
|
|
812
|
-
C: (f, a) => f(...a)
|
|
813
|
-
});
|
|
814
|
-
transceiver2.sender.replaceTrack(track).catch((err) => import_log2.log.catch(err, void 0, {
|
|
815
|
-
F: __dxlog_file2,
|
|
816
|
-
L: 294,
|
|
817
|
-
S: this,
|
|
818
|
-
C: (f, a) => f(...a)
|
|
819
|
-
}));
|
|
820
|
-
return previousTrack;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
(0, import_invariant2.invariant)(track, void 0, {
|
|
824
|
-
F: __dxlog_file2,
|
|
825
|
-
L: 298,
|
|
826
|
-
S: this,
|
|
827
|
-
A: [
|
|
828
|
-
"track",
|
|
829
|
-
""
|
|
830
|
-
]
|
|
831
|
-
});
|
|
832
|
-
const stableId = crypto.randomUUID();
|
|
833
|
-
const transceiver = this.session.peerConnection.addTransceiver(track, {
|
|
834
|
-
direction: "sendonly"
|
|
835
|
-
});
|
|
836
|
-
import_log2.log.verbose("creating transceiver", void 0, {
|
|
837
|
-
F: __dxlog_file2,
|
|
838
|
-
L: 303,
|
|
839
|
-
S: this,
|
|
840
|
-
C: (f, a) => f(...a)
|
|
841
|
-
});
|
|
842
|
-
const pushedTrackData = await this._pushTrackInBulk({
|
|
843
|
-
ctx,
|
|
844
|
-
peerConnection: this.session.peerConnection,
|
|
845
|
-
transceiver,
|
|
846
|
-
sessionId: this.session.sessionId,
|
|
847
|
-
trackName: stableId
|
|
848
|
-
});
|
|
849
|
-
(0, import_invariant2.invariant)(pushedTrackData, void 0, {
|
|
850
|
-
F: __dxlog_file2,
|
|
851
|
-
L: 312,
|
|
852
|
-
S: this,
|
|
853
|
-
A: [
|
|
854
|
-
"pushedTrackData",
|
|
855
|
-
""
|
|
856
|
-
]
|
|
857
|
-
});
|
|
858
|
-
const parameters = transceiver.sender.getParameters();
|
|
859
|
-
encodings.forEach((encoding, i) => {
|
|
860
|
-
const existing = parameters.encodings[i];
|
|
861
|
-
parameters.encodings[i] = {
|
|
862
|
-
...existing,
|
|
863
|
-
...encoding
|
|
864
|
-
};
|
|
865
|
-
});
|
|
866
|
-
transceiver.sender.setParameters(parameters).catch((err) => import_log2.log.catch(err, void 0, {
|
|
867
|
-
F: __dxlog_file2,
|
|
868
|
-
L: 319,
|
|
869
|
-
S: this,
|
|
870
|
-
C: (f, a) => f(...a)
|
|
871
|
-
}));
|
|
872
|
-
return pushedTrackData;
|
|
873
|
-
}
|
|
874
|
-
// TODO(mykola): Add retry logic if the tracks fails to pull.
|
|
875
|
-
async _pullTrackInBulk({ peerConnection, sessionId, trackData, ctx }) {
|
|
876
|
-
let mid = "";
|
|
877
|
-
(0, import_log2.log)("pulling track", {
|
|
878
|
-
trackName: trackData.trackName
|
|
879
|
-
}, {
|
|
880
|
-
F: __dxlog_file2,
|
|
881
|
-
L: 337,
|
|
882
|
-
S: this,
|
|
883
|
-
C: (f, a) => f(...a)
|
|
884
|
-
});
|
|
885
|
-
const pulledTrackPromise = this.pullTrackDispatcher.doBulkRequest(trackData, (tracks) => this.taskScheduler.schedule(async () => {
|
|
886
|
-
const newTrackResponse = await this._fetch(`/sessions/${sessionId}/tracks/new?PULLING`, {
|
|
887
|
-
method: "POST",
|
|
888
|
-
body: JSON.stringify({
|
|
889
|
-
tracks
|
|
890
|
-
})
|
|
891
|
-
});
|
|
892
|
-
if (newTrackResponse.errorCode) {
|
|
893
|
-
throw new Error(newTrackResponse.errorDescription);
|
|
894
|
-
}
|
|
895
|
-
(0, import_invariant2.invariant)(newTrackResponse.tracks, void 0, {
|
|
896
|
-
F: __dxlog_file2,
|
|
897
|
-
L: 350,
|
|
898
|
-
S: this,
|
|
899
|
-
A: [
|
|
900
|
-
"newTrackResponse.tracks",
|
|
901
|
-
""
|
|
902
|
-
]
|
|
903
|
-
});
|
|
904
|
-
const trackMap = tracks.reduce((acc, track) => {
|
|
905
|
-
const pulledTrackData = newTrackResponse.tracks?.find((t) => t.trackName === track.trackName && t.sessionId === track.sessionId);
|
|
906
|
-
if (pulledTrackData && pulledTrackData.mid) {
|
|
907
|
-
acc.set(track, {
|
|
908
|
-
mid: pulledTrackData.mid,
|
|
909
|
-
resolvedTrack: resolveTrack(peerConnection, (t) => t.mid === pulledTrackData.mid)
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
return acc;
|
|
913
|
-
}, /* @__PURE__ */ new Map());
|
|
914
|
-
if (newTrackResponse.requiresImmediateRenegotiation) {
|
|
915
|
-
await peerConnection.setRemoteDescription(new RTCSessionDescription(newTrackResponse.sessionDescription));
|
|
916
|
-
const answer = await peerConnection.createAnswer();
|
|
917
|
-
await peerConnection.setLocalDescription(answer);
|
|
918
|
-
const renegotiationResponse = await this._fetch(`/sessions/${sessionId}/renegotiate`, {
|
|
919
|
-
method: "PUT",
|
|
920
|
-
body: JSON.stringify({
|
|
921
|
-
sessionDescription: {
|
|
922
|
-
type: "answer",
|
|
923
|
-
sdp: peerConnection.currentLocalDescription?.sdp
|
|
924
|
-
}
|
|
925
|
-
})
|
|
926
|
-
});
|
|
927
|
-
if (renegotiationResponse.errorCode) {
|
|
928
|
-
throw new Error(renegotiationResponse.errorDescription);
|
|
929
|
-
} else {
|
|
930
|
-
await peerConnectionIsConnected(peerConnection);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
return {
|
|
934
|
-
trackMap
|
|
935
|
-
};
|
|
936
|
-
})).then(({ trackMap }) => {
|
|
937
|
-
const trackInfo = trackMap.get(trackData);
|
|
938
|
-
if (trackInfo) {
|
|
939
|
-
return trackInfo.resolvedTrack.then((track) => {
|
|
940
|
-
mid = trackInfo.mid;
|
|
941
|
-
return track;
|
|
942
|
-
}).catch((err) => import_log2.log.catch(err, void 0, {
|
|
943
|
-
F: __dxlog_file2,
|
|
944
|
-
L: 402,
|
|
945
|
-
S: this,
|
|
946
|
-
C: (f, a) => f(...a)
|
|
947
|
-
}));
|
|
948
|
-
} else {
|
|
949
|
-
import_log2.log.error("missing track info", void 0, {
|
|
950
|
-
F: __dxlog_file2,
|
|
951
|
-
L: 404,
|
|
952
|
-
S: this,
|
|
953
|
-
C: (f, a) => f(...a)
|
|
954
|
-
});
|
|
955
|
-
}
|
|
956
|
-
});
|
|
957
|
-
const onDispose = async () => {
|
|
958
|
-
if (mid) {
|
|
959
|
-
(0, import_log2.log)("closing pulled track ", trackData.trackName, {
|
|
960
|
-
F: __dxlog_file2,
|
|
961
|
-
L: 410,
|
|
962
|
-
S: this,
|
|
963
|
-
C: (f, a) => f(...a)
|
|
964
|
-
});
|
|
965
|
-
await this._closeTrackInBulk(peerConnection, mid, sessionId);
|
|
966
|
-
mid = "";
|
|
967
|
-
}
|
|
968
|
-
};
|
|
969
|
-
this._ctx.onDispose(() => onDispose());
|
|
970
|
-
ctx?.onDispose(() => onDispose());
|
|
971
|
-
return pulledTrackPromise;
|
|
972
|
-
}
|
|
973
|
-
async pullTrack({ ctx, trackData }) {
|
|
974
|
-
await this.waitUntilOpen();
|
|
975
|
-
(0, import_invariant2.invariant)(this.session, void 0, {
|
|
976
|
-
F: __dxlog_file2,
|
|
977
|
-
L: 431,
|
|
978
|
-
S: this,
|
|
979
|
-
A: [
|
|
980
|
-
"this.session",
|
|
981
|
-
""
|
|
982
|
-
]
|
|
983
|
-
});
|
|
984
|
-
const session = this.session;
|
|
985
|
-
return this._pullTrackInBulk({
|
|
986
|
-
peerConnection: session.peerConnection,
|
|
987
|
-
sessionId: session.sessionId,
|
|
988
|
-
trackData,
|
|
989
|
-
ctx
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
|
-
async _closeTrackInBulk(peerConnection, mid, sessionId) {
|
|
993
|
-
const transceiver = peerConnection.getTransceivers().find((t) => t.mid === mid);
|
|
994
|
-
if (peerConnection.connectionState !== "connected" || transceiver === void 0) {
|
|
995
|
-
return;
|
|
996
|
-
}
|
|
997
|
-
await this.closeTrackDispatcher.doBulkRequest({
|
|
998
|
-
mid
|
|
999
|
-
}, (mids) => this.taskScheduler.schedule(async () => {
|
|
1000
|
-
transceiver.stop();
|
|
1001
|
-
const activeTransceivers = peerConnection.getTransceivers().filter((t) => t.mid !== mid && t.direction !== "stopped");
|
|
1002
|
-
let requestBody;
|
|
1003
|
-
if (activeTransceivers.length > 0) {
|
|
1004
|
-
const offer = await peerConnection.createOffer();
|
|
1005
|
-
await peerConnection.setLocalDescription(offer);
|
|
1006
|
-
requestBody = {
|
|
1007
|
-
tracks: mids,
|
|
1008
|
-
sessionDescription: {
|
|
1009
|
-
sdp: peerConnection.localDescription?.sdp,
|
|
1010
|
-
type: "offer"
|
|
1011
|
-
},
|
|
1012
|
-
force: false
|
|
1013
|
-
};
|
|
1014
|
-
} else {
|
|
1015
|
-
requestBody = {
|
|
1016
|
-
tracks: mids,
|
|
1017
|
-
force: true
|
|
1018
|
-
};
|
|
1019
|
-
}
|
|
1020
|
-
const response = await this._fetch(`/sessions/${sessionId}/tracks/close`, {
|
|
1021
|
-
method: "PUT",
|
|
1022
|
-
body: JSON.stringify(requestBody)
|
|
1023
|
-
});
|
|
1024
|
-
if (requestBody.sessionDescription) {
|
|
1025
|
-
await peerConnection.setRemoteDescription(new RTCSessionDescription(response.sessionDescription));
|
|
1026
|
-
}
|
|
1027
|
-
}));
|
|
1028
|
-
}
|
|
1029
|
-
};
|
|
1030
|
-
var resolveTrack = async (peerConnection, compare, timeout = NETWORK_TIMEOUT) => new Promise((resolve, reject) => {
|
|
1031
|
-
setTimeout(reject, timeout);
|
|
1032
|
-
const handler = () => {
|
|
1033
|
-
const transceiver = peerConnection.getTransceivers().find(compare);
|
|
1034
|
-
if (transceiver) {
|
|
1035
|
-
resolve(transceiver.receiver.track);
|
|
1036
|
-
peerConnection.removeEventListener("track", handler);
|
|
1037
|
-
}
|
|
1038
|
-
};
|
|
1039
|
-
peerConnection.addEventListener("track", handler);
|
|
1040
|
-
});
|
|
1041
|
-
var peerConnectionIsConnected = async (peerConnection) => {
|
|
1042
|
-
if (peerConnection.connectionState !== "connected") {
|
|
1043
|
-
const connected = new Promise((resolve, reject) => {
|
|
1044
|
-
const timeout = setTimeout(() => {
|
|
1045
|
-
peerConnection.removeEventListener("connectionstatechange", connectionStateChangeHandler);
|
|
1046
|
-
reject(new Error("Connection timeout"));
|
|
1047
|
-
}, NETWORK_TIMEOUT);
|
|
1048
|
-
const connectionStateChangeHandler = () => {
|
|
1049
|
-
if (peerConnection.connectionState === "connected") {
|
|
1050
|
-
peerConnection.removeEventListener("connectionstatechange", connectionStateChangeHandler);
|
|
1051
|
-
clearTimeout(timeout);
|
|
1052
|
-
resolve(void 0);
|
|
1053
|
-
}
|
|
1054
|
-
};
|
|
1055
|
-
peerConnection.addEventListener("connectionstatechange", connectionStateChangeHandler);
|
|
1056
|
-
});
|
|
1057
|
-
await connected;
|
|
1058
|
-
}
|
|
1059
|
-
};
|
|
1060
|
-
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/calls/util/media.ts";
|
|
1061
|
-
var getUserMediaTrack = async (kind, constraints = {}, deviceList) => {
|
|
1062
|
-
deviceList ??= (await getDeviceList()).filter((device) => device.kind === kind);
|
|
1063
|
-
const firstDevice = deviceList[0];
|
|
1064
|
-
if (!firstDevice) {
|
|
1065
|
-
throw new Error("No devices found");
|
|
1066
|
-
}
|
|
1067
|
-
return acquireTrack(firstDevice, constraints);
|
|
1068
|
-
};
|
|
1069
|
-
var acquireTrack = async (device, constraints) => {
|
|
1070
|
-
const { deviceId, label } = device;
|
|
1071
|
-
import_log3.log.info(`requesting ${label}`, void 0, {
|
|
1072
|
-
F: __dxlog_file3,
|
|
1073
|
-
L: 23,
|
|
1074
|
-
S: void 0,
|
|
1075
|
-
C: (f, a) => f(...a)
|
|
1076
|
-
});
|
|
1077
|
-
const mediaStream = await navigator.mediaDevices.getUserMedia(device.kind === "videoinput" ? {
|
|
1078
|
-
video: {
|
|
1079
|
-
...constraints,
|
|
1080
|
-
deviceId
|
|
1081
|
-
}
|
|
1082
|
-
} : {
|
|
1083
|
-
audio: {
|
|
1084
|
-
...constraints,
|
|
1085
|
-
deviceId
|
|
1086
|
-
}
|
|
1087
|
-
});
|
|
1088
|
-
return device.kind === "videoinput" ? mediaStream.getVideoTracks()[0] : mediaStream.getAudioTracks()[0];
|
|
1089
|
-
};
|
|
1090
|
-
var getDeviceList = () => navigator.mediaDevices.enumerateDevices();
|
|
1091
|
-
var SCREENSHARE_CONSTRAINTS = {
|
|
1092
|
-
video: {
|
|
1093
|
-
width: {
|
|
1094
|
-
max: 1920
|
|
1095
|
-
},
|
|
1096
|
-
height: {
|
|
1097
|
-
max: 1080
|
|
1098
|
-
},
|
|
1099
|
-
frameRate: {
|
|
1100
|
-
max: 10
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
};
|
|
1104
|
-
var getScreenshare = async ({ contentHint }) => {
|
|
1105
|
-
const ms = await navigator.mediaDevices.getDisplayMedia(SCREENSHARE_CONSTRAINTS);
|
|
1106
|
-
ms.getVideoTracks().forEach((track) => {
|
|
1107
|
-
if (contentHint && "contentHint" in track) {
|
|
1108
|
-
track.contentHint = contentHint;
|
|
1109
|
-
}
|
|
1110
|
-
});
|
|
1111
|
-
return ms;
|
|
1112
|
-
};
|
|
1113
|
-
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/calls/util/stub-media-streams.ts";
|
|
1114
|
-
var createBlackCanvasStreamTrack = async ({ ctx, width, height }) => {
|
|
1115
|
-
const canvas = document.createElement("canvas");
|
|
1116
|
-
canvas.width = width;
|
|
1117
|
-
canvas.height = height;
|
|
1118
|
-
const canvasCtx = canvas.getContext("2d");
|
|
1119
|
-
(0, import_invariant3.invariant)(canvasCtx, void 0, {
|
|
1120
|
-
F: __dxlog_file4,
|
|
1121
|
-
L: 28,
|
|
1122
|
-
S: void 0,
|
|
1123
|
-
A: [
|
|
1124
|
-
"canvasCtx",
|
|
1125
|
-
""
|
|
1126
|
-
]
|
|
1127
|
-
});
|
|
1128
|
-
const drawFrame = () => {
|
|
1129
|
-
canvasCtx.fillStyle = "black";
|
|
1130
|
-
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
|
|
1131
|
-
};
|
|
1132
|
-
(0, import_async3.scheduleTaskInterval)(ctx, async () => drawFrame(), 1e3);
|
|
1133
|
-
const track = canvas.captureStream().getVideoTracks()[0];
|
|
1134
|
-
drawFrame();
|
|
1135
|
-
await (0, import_context3.cancelWithContext)(ctx, (0, import_async3.waitForCondition)({
|
|
1136
|
-
condition: () => track.readyState === "live",
|
|
1137
|
-
timeout: 1e3
|
|
1138
|
-
}));
|
|
1139
|
-
return track;
|
|
1140
|
-
};
|
|
1141
|
-
var createInaudibleAudioStreamTrack = async ({ ctx }) => {
|
|
1142
|
-
const audioContext = new window.AudioContext();
|
|
1143
|
-
const oscillator = audioContext.createOscillator();
|
|
1144
|
-
oscillator.type = "triangle";
|
|
1145
|
-
oscillator.frequency.setValueAtTime(0.1, audioContext.currentTime);
|
|
1146
|
-
const gainNode = audioContext.createGain();
|
|
1147
|
-
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
|
|
1148
|
-
oscillator.connect(gainNode);
|
|
1149
|
-
const destination = audioContext.createMediaStreamDestination();
|
|
1150
|
-
gainNode.connect(destination);
|
|
1151
|
-
oscillator.start();
|
|
1152
|
-
ctx.onDispose(async () => {
|
|
1153
|
-
oscillator.disconnect();
|
|
1154
|
-
oscillator.stop();
|
|
1155
|
-
await audioContext.close();
|
|
1156
|
-
});
|
|
1157
|
-
return destination.stream.getAudioTracks()[0];
|
|
1158
|
-
};
|
|
1159
|
-
var NOT_SPEAKING_AFTER = 500;
|
|
1160
|
-
var START_SPEAKING_THRESHOLD = 0.05;
|
|
1161
|
-
var CONTINUE_SPEAKING_THRESHOLD = 0.02;
|
|
1162
|
-
var MIN_EVENT_INTERVAL = 100;
|
|
1163
|
-
var SpeakingMonitor = class extends import_context4.Resource {
|
|
1164
|
-
constructor(_mediaStreamTrack) {
|
|
1165
|
-
super(), this._mediaStreamTrack = _mediaStreamTrack, this.speakingChanged = new import_async4.Event(), this._isSpeaking = false, this._lastEventTime = 0;
|
|
1166
|
-
}
|
|
1167
|
-
get isSpeaking() {
|
|
1168
|
-
return this._isSpeaking;
|
|
1169
|
-
}
|
|
1170
|
-
async _open() {
|
|
1171
|
-
this._deferredUpdate = new import_async4.DeferredTask(this._ctx, async () => this._emitSpeakingChanged());
|
|
1172
|
-
let timeout;
|
|
1173
|
-
const cleanup = monitorAudioLevel({
|
|
1174
|
-
mediaStreamTrack: this._mediaStreamTrack,
|
|
1175
|
-
onMeasure: (vol) => {
|
|
1176
|
-
const audioLevelAboveThreshold = vol > (this._isSpeaking ? CONTINUE_SPEAKING_THRESHOLD : START_SPEAKING_THRESHOLD);
|
|
1177
|
-
if (audioLevelAboveThreshold) {
|
|
1178
|
-
clearTimeout(timeout);
|
|
1179
|
-
timeout = void 0;
|
|
1180
|
-
if (!this._isSpeaking) {
|
|
1181
|
-
this._isSpeaking = true;
|
|
1182
|
-
this._deferredUpdate?.schedule();
|
|
1183
|
-
}
|
|
1184
|
-
} else if (timeout === void 0) {
|
|
1185
|
-
timeout = setTimeout(() => {
|
|
1186
|
-
this._isSpeaking = false;
|
|
1187
|
-
timeout = void 0;
|
|
1188
|
-
this._deferredUpdate?.schedule();
|
|
1189
|
-
}, NOT_SPEAKING_AFTER);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
this._ctx.onDispose(() => {
|
|
1194
|
-
cleanup();
|
|
1195
|
-
clearTimeout(timeout);
|
|
1196
|
-
});
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* Emits the speaking changed event with debouncing based on timing.
|
|
1200
|
-
*/
|
|
1201
|
-
async _emitSpeakingChanged() {
|
|
1202
|
-
const timeSinceLastEvent = Date.now() - this._lastEventTime;
|
|
1203
|
-
const timeToNextEvent = MIN_EVENT_INTERVAL - timeSinceLastEvent;
|
|
1204
|
-
if (timeToNextEvent > 0) {
|
|
1205
|
-
await (0, import_async4.sleep)(timeToNextEvent);
|
|
1206
|
-
}
|
|
1207
|
-
this._lastEventTime = Date.now();
|
|
1208
|
-
this.speakingChanged.emit(this._isSpeaking);
|
|
1209
|
-
}
|
|
1210
|
-
};
|
|
1211
|
-
function _ts_decorate2(decorators, target, key, desc) {
|
|
1212
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1213
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1214
|
-
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;
|
|
1215
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1216
|
-
}
|
|
1217
|
-
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/calls/media-manager.ts";
|
|
1218
|
-
var VIDEO_WIDTH = 1280;
|
|
1219
|
-
var VIDEO_HEIGHT = 720;
|
|
1220
|
-
var MAX_WEB_CAM_FRAMERATE = 24;
|
|
1221
|
-
var MAX_WEB_CAM_BITRATE = 12e5;
|
|
1222
|
-
var RETRY_INTERVAL = 500;
|
|
1223
|
-
var MediaManager = class extends import_context5.Resource {
|
|
1224
|
-
constructor() {
|
|
1225
|
-
super(...arguments);
|
|
1226
|
-
this.stateUpdated = new import_async5.Event();
|
|
1227
|
-
this._state = {
|
|
1228
|
-
pulledVideoStreams: {},
|
|
1229
|
-
pulledAudioTracks: {}
|
|
1230
|
-
};
|
|
1231
|
-
this._speakingMonitor = void 0;
|
|
1232
|
-
this._trackToReconcile = [];
|
|
1233
|
-
this._blackCanvasStreamTrack = void 0;
|
|
1234
|
-
this._inaudibleAudioStreamTrack = void 0;
|
|
1235
|
-
this._pushTracksTask = void 0;
|
|
1236
|
-
this._pullTracksTask = void 0;
|
|
1237
|
-
}
|
|
1238
|
-
get isSpeaking() {
|
|
1239
|
-
return this._speakingMonitor?.isSpeaking;
|
|
1240
|
-
}
|
|
1241
|
-
/**
|
|
1242
|
-
* @internal
|
|
1243
|
-
*/
|
|
1244
|
-
_getState() {
|
|
1245
|
-
return this._state;
|
|
1246
|
-
}
|
|
1247
|
-
async _open() {
|
|
1248
|
-
this._blackCanvasStreamTrack = await createBlackCanvasStreamTrack({
|
|
1249
|
-
ctx: this._ctx,
|
|
1250
|
-
width: VIDEO_WIDTH,
|
|
1251
|
-
height: VIDEO_HEIGHT
|
|
1252
|
-
});
|
|
1253
|
-
this._state.videoTrack = this._blackCanvasStreamTrack;
|
|
1254
|
-
this._state.videoStream = new MediaStream();
|
|
1255
|
-
this._state.videoStream.addTrack(this._state.videoTrack);
|
|
1256
|
-
this._inaudibleAudioStreamTrack = await createInaudibleAudioStreamTrack({
|
|
1257
|
-
ctx: this._ctx
|
|
1258
|
-
});
|
|
1259
|
-
this._state.audioTrack = this._inaudibleAudioStreamTrack;
|
|
1260
|
-
this._pushTracksTask = new import_async5.DeferredTask(this._ctx, async () => {
|
|
1261
|
-
await this._pushTracks();
|
|
1262
|
-
});
|
|
1263
|
-
this._pullTracksTask = new import_async5.DeferredTask(this._ctx, async () => {
|
|
1264
|
-
await this._reconcilePulledMedia();
|
|
1265
|
-
});
|
|
1266
|
-
}
|
|
1267
|
-
async _close() {
|
|
1268
|
-
void this._speakingMonitor?.close();
|
|
1269
|
-
this._state.videoTrack && this._state.videoStream?.removeTrack(this._state.videoTrack);
|
|
1270
|
-
this._state.audioTrack?.stop();
|
|
1271
|
-
this._state.videoTrack?.stop();
|
|
1272
|
-
this._state.screenshareTrack?.stop();
|
|
1273
|
-
this._pushTracksTask = void 0;
|
|
1274
|
-
this._pullTracksTask = void 0;
|
|
1275
|
-
}
|
|
1276
|
-
async join(serviceConfig) {
|
|
1277
|
-
this._state.peer = new CallsServicePeer(serviceConfig);
|
|
1278
|
-
await this._state.peer.open();
|
|
1279
|
-
this._pushTracksTask.schedule();
|
|
1280
|
-
}
|
|
1281
|
-
async leave() {
|
|
1282
|
-
await Promise.all(Object.values(this._state.pulledAudioTracks).map(({ ctx }) => ctx.dispose()));
|
|
1283
|
-
await Promise.all(Object.values(this._state.pulledVideoStreams).map(({ ctx }) => ctx.dispose()));
|
|
1284
|
-
this._trackToReconcile = [];
|
|
1285
|
-
await this._state.peer?.close();
|
|
1286
|
-
this._state.peer = void 0;
|
|
1287
|
-
this._state.pushedVideoTrack = void 0;
|
|
1288
|
-
this._state.pushedAudioTrack = void 0;
|
|
1289
|
-
this._state.pushedScreenshareTrack = void 0;
|
|
1290
|
-
this._state.pulledAudioTracks = {};
|
|
1291
|
-
this._state.pulledVideoStreams = {};
|
|
1292
|
-
}
|
|
1293
|
-
async turnVideoOn() {
|
|
1294
|
-
this._state.videoStream.removeTrack(this._state.videoTrack);
|
|
1295
|
-
this._state.videoTrack = await getUserMediaTrack("videoinput", {
|
|
1296
|
-
width: VIDEO_WIDTH,
|
|
1297
|
-
height: VIDEO_HEIGHT
|
|
1298
|
-
});
|
|
1299
|
-
this._state.videoStream.addTrack(this._state.videoTrack);
|
|
1300
|
-
this._state.videoEnabled = true;
|
|
1301
|
-
this.stateUpdated.emit(this._state);
|
|
1302
|
-
this._pushTracksTask.schedule();
|
|
1303
|
-
}
|
|
1304
|
-
async turnVideoOff() {
|
|
1305
|
-
if (this._state.videoTrack !== this._blackCanvasStreamTrack) {
|
|
1306
|
-
this._state.videoStream.removeTrack(this._state.videoTrack);
|
|
1307
|
-
this._state.videoTrack?.stop();
|
|
1308
|
-
this._state.videoTrack = this._blackCanvasStreamTrack;
|
|
1309
|
-
this._state.videoStream.addTrack(this._state.videoTrack);
|
|
1310
|
-
}
|
|
1311
|
-
this._state.videoEnabled = false;
|
|
1312
|
-
this.stateUpdated.emit(this._state);
|
|
1313
|
-
this._pushTracksTask.schedule();
|
|
1314
|
-
}
|
|
1315
|
-
// TODO(mykola): Change to `setAudioEnabled(enabled: boolean)`.
|
|
1316
|
-
async turnAudioOn() {
|
|
1317
|
-
void this._speakingMonitor?.close();
|
|
1318
|
-
this._state.audioEnabled = true;
|
|
1319
|
-
this._state.audioTrack = await getUserMediaTrack("audioinput", {
|
|
1320
|
-
echoCancellation: true,
|
|
1321
|
-
noiseSuppression: true,
|
|
1322
|
-
autoGainControl: true,
|
|
1323
|
-
sampleRate: 16e3
|
|
1324
|
-
});
|
|
1325
|
-
this.stateUpdated.emit(this._state);
|
|
1326
|
-
this._pushTracksTask.schedule();
|
|
1327
|
-
this._speakingMonitor = new SpeakingMonitor(this._state.audioTrack);
|
|
1328
|
-
this._speakingMonitor.speakingChanged.on(this._ctx, () => this.stateUpdated.emit(this._state));
|
|
1329
|
-
void this._speakingMonitor.open();
|
|
1330
|
-
}
|
|
1331
|
-
async turnAudioOff() {
|
|
1332
|
-
void this._speakingMonitor?.close();
|
|
1333
|
-
this._speakingMonitor = void 0;
|
|
1334
|
-
if (this._state.audioTrack !== this._inaudibleAudioStreamTrack) {
|
|
1335
|
-
this._state.audioTrack?.stop();
|
|
1336
|
-
this._state.audioTrack = this._inaudibleAudioStreamTrack;
|
|
1337
|
-
}
|
|
1338
|
-
this._state.audioEnabled = false;
|
|
1339
|
-
this.stateUpdated.emit(this._state);
|
|
1340
|
-
this._pushTracksTask.schedule();
|
|
1341
|
-
}
|
|
1342
|
-
async turnScreenshareOn() {
|
|
1343
|
-
const ms = await getScreenshare({
|
|
1344
|
-
contentHint: "text"
|
|
1345
|
-
});
|
|
1346
|
-
this._state.screenshareVideoStream = ms;
|
|
1347
|
-
this._state.screenshareTrack = ms.getVideoTracks()[0];
|
|
1348
|
-
this._state.screenshareEnabled = true;
|
|
1349
|
-
this.stateUpdated.emit(this._state);
|
|
1350
|
-
this._pushTracksTask.schedule();
|
|
1351
|
-
}
|
|
1352
|
-
async turnScreenshareOff() {
|
|
1353
|
-
this._state.screenshareEnabled = false;
|
|
1354
|
-
this._state.screenshareTrack?.stop();
|
|
1355
|
-
this._state.screenshareTrack = void 0;
|
|
1356
|
-
this.stateUpdated.emit(this._state);
|
|
1357
|
-
this._pushTracksTask.schedule();
|
|
1358
|
-
}
|
|
1359
|
-
/**
|
|
1360
|
-
* @internal
|
|
1361
|
-
*/
|
|
1362
|
-
_schedulePullTracks(tracks) {
|
|
1363
|
-
if (!tracks || this._trackToReconcile.every((name) => tracks.includes(name)) && this._trackToReconcile.length === tracks.length) {
|
|
1364
|
-
return;
|
|
1365
|
-
}
|
|
1366
|
-
this._trackToReconcile = tracks;
|
|
1367
|
-
this._pullTracksTask.schedule();
|
|
1368
|
-
}
|
|
1369
|
-
async _reconcilePulledMedia() {
|
|
1370
|
-
(0, import_log4.log)("reconciling tracks", void 0, {
|
|
1371
|
-
F: __dxlog_file5,
|
|
1372
|
-
L: 215,
|
|
1373
|
-
S: this,
|
|
1374
|
-
C: (f, a) => f(...a)
|
|
1375
|
-
});
|
|
1376
|
-
await (0, import_context5.cancelWithContext)(this._ctx, (0, import_async5.sleep)(800));
|
|
1377
|
-
const trackNames = this._trackToReconcile;
|
|
1378
|
-
const tracksToPull = trackNames.filter((name) => !this._state.pulledAudioTracks[name] && !this._state.pulledVideoStreams[name]);
|
|
1379
|
-
const audioTracksToClose = Object.entries(this._state.pulledAudioTracks).filter(([key]) => !trackNames.some((name) => name === key));
|
|
1380
|
-
const videoStreamsToClose = Object.entries(this._state.pulledVideoStreams).filter(([key]) => !trackNames.some((name) => name === key));
|
|
1381
|
-
(0, import_log4.log)("reconciling tracks", {
|
|
1382
|
-
trackNames,
|
|
1383
|
-
tracksToPull,
|
|
1384
|
-
videoStreamsToClose,
|
|
1385
|
-
audioTracksToClose,
|
|
1386
|
-
currentAudioTracks: Object.keys(this._state.pulledAudioTracks),
|
|
1387
|
-
currentVideoStreams: Object.keys(this._state.pulledVideoStreams)
|
|
1388
|
-
}, {
|
|
1389
|
-
F: __dxlog_file5,
|
|
1390
|
-
L: 234,
|
|
1391
|
-
S: this,
|
|
1392
|
-
C: (f, a) => f(...a)
|
|
1393
|
-
});
|
|
1394
|
-
await Promise.all(tracksToPull.map((name) => this._pullTrack(name)));
|
|
1395
|
-
await Promise.all([
|
|
1396
|
-
...audioTracksToClose,
|
|
1397
|
-
...videoStreamsToClose
|
|
1398
|
-
].map(([_, { ctx }]) => ctx.dispose()));
|
|
1399
|
-
(0, import_log4.log)("reconciled tracks", {
|
|
1400
|
-
currentAudioTracks: Object.keys(this._state.pulledAudioTracks),
|
|
1401
|
-
currentVideoStreams: Object.keys(this._state.pulledVideoStreams)
|
|
1402
|
-
}, {
|
|
1403
|
-
F: __dxlog_file5,
|
|
1404
|
-
L: 249,
|
|
1405
|
-
S: this,
|
|
1406
|
-
C: (f, a) => f(...a)
|
|
1407
|
-
});
|
|
1408
|
-
this.stateUpdated.emit(this._state);
|
|
1409
|
-
}
|
|
1410
|
-
async _pushTracks() {
|
|
1411
|
-
if (!this._state.peer?.isOpen) {
|
|
1412
|
-
return;
|
|
1413
|
-
}
|
|
1414
|
-
let updated = false;
|
|
1415
|
-
const [pushedVideoTrack, pushedAudioTrack, pushedScreenshareTrack] = await Promise.all([
|
|
1416
|
-
this._pushTrack(this._state.videoTrack, this._state.pushedVideoTrack, [
|
|
1417
|
-
{
|
|
1418
|
-
maxFramerate: MAX_WEB_CAM_FRAMERATE,
|
|
1419
|
-
maxBitrate: MAX_WEB_CAM_BITRATE
|
|
1420
|
-
}
|
|
1421
|
-
]),
|
|
1422
|
-
this._pushTrack(this._state.audioTrack, this._state.pushedAudioTrack, [
|
|
1423
|
-
{
|
|
1424
|
-
networkPriority: "high"
|
|
1425
|
-
}
|
|
1426
|
-
]),
|
|
1427
|
-
this._pushTrack(this._state.screenshareTrack, this._state.pushedScreenshareTrack)
|
|
1428
|
-
]);
|
|
1429
|
-
if (pushedVideoTrack !== this._state.pushedVideoTrack) {
|
|
1430
|
-
this._state.pushedVideoTrack = pushedVideoTrack;
|
|
1431
|
-
updated = true;
|
|
1432
|
-
}
|
|
1433
|
-
if (pushedAudioTrack !== this._state.pushedAudioTrack) {
|
|
1434
|
-
this._state.pushedAudioTrack = pushedAudioTrack;
|
|
1435
|
-
updated = true;
|
|
1436
|
-
}
|
|
1437
|
-
if (pushedScreenshareTrack !== this._state.pushedScreenshareTrack) {
|
|
1438
|
-
this._state.pushedScreenshareTrack = pushedScreenshareTrack;
|
|
1439
|
-
updated = true;
|
|
1440
|
-
}
|
|
1441
|
-
if (!updated) {
|
|
1442
|
-
return;
|
|
1443
|
-
}
|
|
1444
|
-
this.stateUpdated.emit(this._state);
|
|
1445
|
-
}
|
|
1446
|
-
async _pullTrack(name) {
|
|
1447
|
-
const ctx = this._ctx.derive();
|
|
1448
|
-
try {
|
|
1449
|
-
const trackData = TrackNameCodec.decode(name);
|
|
1450
|
-
const track = await this._state.peer.pullTrack({
|
|
1451
|
-
trackData,
|
|
1452
|
-
ctx
|
|
1453
|
-
});
|
|
1454
|
-
if (track?.readyState === "ended") {
|
|
1455
|
-
throw new Error("Pulled track ended immediately");
|
|
1456
|
-
}
|
|
1457
|
-
switch (track?.kind) {
|
|
1458
|
-
case "audio": {
|
|
1459
|
-
this._state.pulledAudioTracks[name] = {
|
|
1460
|
-
track,
|
|
1461
|
-
ctx
|
|
1462
|
-
};
|
|
1463
|
-
ctx.onDispose(() => delete this._state.pulledAudioTracks[name]);
|
|
1464
|
-
break;
|
|
1465
|
-
}
|
|
1466
|
-
case "video": {
|
|
1467
|
-
const mediaStream = new MediaStream();
|
|
1468
|
-
mediaStream.addTrack(track);
|
|
1469
|
-
this._state.pulledVideoStreams[name] = {
|
|
1470
|
-
stream: mediaStream,
|
|
1471
|
-
ctx
|
|
1472
|
-
};
|
|
1473
|
-
ctx.onDispose(() => {
|
|
1474
|
-
mediaStream.removeTrack(track);
|
|
1475
|
-
track.stop();
|
|
1476
|
-
delete this._state.pulledVideoStreams[name];
|
|
1477
|
-
});
|
|
1478
|
-
break;
|
|
1479
|
-
}
|
|
1480
|
-
default:
|
|
1481
|
-
throw new Error(`Invalid track kind: ${track?.kind}`);
|
|
1482
|
-
}
|
|
1483
|
-
} catch (err) {
|
|
1484
|
-
import_log4.log.verbose("failed to pull track", {
|
|
1485
|
-
err,
|
|
1486
|
-
name
|
|
1487
|
-
}, {
|
|
1488
|
-
F: __dxlog_file5,
|
|
1489
|
-
L: 319,
|
|
1490
|
-
S: this,
|
|
1491
|
-
C: (f, a) => f(...a)
|
|
1492
|
-
});
|
|
1493
|
-
void ctx.dispose();
|
|
1494
|
-
await (0, import_context5.cancelWithContext)(this._ctx, (0, import_async5.sleep)(RETRY_INTERVAL));
|
|
1495
|
-
import_log4.log.verbose("retrying pull track", {
|
|
1496
|
-
name
|
|
1497
|
-
}, {
|
|
1498
|
-
F: __dxlog_file5,
|
|
1499
|
-
L: 322,
|
|
1500
|
-
S: this,
|
|
1501
|
-
C: (f, a) => f(...a)
|
|
1502
|
-
});
|
|
1503
|
-
this._pullTracksTask.schedule();
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
async _pushTrack(track, previousTrack, encodings) {
|
|
1507
|
-
if (!track && !previousTrack) {
|
|
1508
|
-
return;
|
|
1509
|
-
}
|
|
1510
|
-
return this._state.peer.pushTrack({
|
|
1511
|
-
track: track ?? null,
|
|
1512
|
-
previousTrack,
|
|
1513
|
-
encodings
|
|
1514
|
-
});
|
|
1515
|
-
}
|
|
1516
|
-
};
|
|
1517
|
-
_ts_decorate2([
|
|
1518
|
-
import_async5.synchronized
|
|
1519
|
-
], MediaManager.prototype, "join", null);
|
|
1520
|
-
_ts_decorate2([
|
|
1521
|
-
import_async5.synchronized
|
|
1522
|
-
], MediaManager.prototype, "leave", null);
|
|
1523
|
-
function _ts_decorate3(decorators, target, key, desc) {
|
|
1524
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1525
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1526
|
-
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;
|
|
1527
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1528
|
-
}
|
|
1529
|
-
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/plugins/plugin-thread/src/calls/call-manager.ts";
|
|
1530
|
-
var CallManager = class extends import_context6.Resource {
|
|
1531
|
-
/** @reactive */
|
|
1532
|
-
get roomId() {
|
|
1533
|
-
return this._state.call.roomId;
|
|
1534
|
-
}
|
|
1535
|
-
/** @reactive */
|
|
1536
|
-
get raisedHand() {
|
|
1537
|
-
return this._raisedHandSignal.value;
|
|
1538
|
-
}
|
|
1539
|
-
/** @reactive */
|
|
1540
|
-
get speaking() {
|
|
1541
|
-
return this._speakingSignal.value;
|
|
1542
|
-
}
|
|
1543
|
-
/** @reactive */
|
|
1544
|
-
get joined() {
|
|
1545
|
-
return this._joinedSignal.value;
|
|
1546
|
-
}
|
|
1547
|
-
/** @reactive */
|
|
1548
|
-
get self() {
|
|
1549
|
-
return this._state.call.self ?? {};
|
|
1550
|
-
}
|
|
1551
|
-
/** @reactive */
|
|
1552
|
-
get tracks() {
|
|
1553
|
-
return this._state.call.tracks ?? {};
|
|
1554
|
-
}
|
|
1555
|
-
/** @reactive */
|
|
1556
|
-
get users() {
|
|
1557
|
-
return this._state.call.users ?? [];
|
|
1558
|
-
}
|
|
1559
|
-
/** @reactive */
|
|
1560
|
-
get media() {
|
|
1561
|
-
return this._state.media;
|
|
1562
|
-
}
|
|
1563
|
-
/** @reactive */
|
|
1564
|
-
get pulledAudioTracks() {
|
|
1565
|
-
return Object.values(this._state.media.pulledAudioTracks).map((track) => track.track);
|
|
1566
|
-
}
|
|
1567
|
-
/** @reactive */
|
|
1568
|
-
get state() {
|
|
1569
|
-
return this._state;
|
|
1570
|
-
}
|
|
1571
|
-
/** @reactive */
|
|
1572
|
-
getVideoStream(name) {
|
|
1573
|
-
return name ? this._state.media.pulledVideoStreams[name]?.stream : void 0;
|
|
1574
|
-
}
|
|
1575
|
-
/** @reactive */
|
|
1576
|
-
getActivity(key) {
|
|
1577
|
-
return this._state.call.activities?.[key];
|
|
1578
|
-
}
|
|
1579
|
-
setRoomId(roomId) {
|
|
1580
|
-
this._swarmSynchronizer._setRoomId(roomId);
|
|
1581
|
-
}
|
|
1582
|
-
setSpeaking(speaking) {
|
|
1583
|
-
this._swarmSynchronizer.setSpeaking(speaking);
|
|
1584
|
-
}
|
|
1585
|
-
setRaisedHand(raisedHand) {
|
|
1586
|
-
this._swarmSynchronizer.setRaisedHand(raisedHand);
|
|
1587
|
-
}
|
|
1588
|
-
setActivity(key, payload) {
|
|
1589
|
-
this._swarmSynchronizer.setActivity(key, payload);
|
|
1590
|
-
}
|
|
1591
|
-
turnAudioOn() {
|
|
1592
|
-
return this._mediaManager.turnAudioOn();
|
|
1593
|
-
}
|
|
1594
|
-
turnAudioOff() {
|
|
1595
|
-
return this._mediaManager.turnAudioOff();
|
|
1596
|
-
}
|
|
1597
|
-
turnVideoOn() {
|
|
1598
|
-
return this._mediaManager.turnVideoOn();
|
|
1599
|
-
}
|
|
1600
|
-
turnVideoOff() {
|
|
1601
|
-
return this._mediaManager.turnVideoOff();
|
|
1602
|
-
}
|
|
1603
|
-
turnScreenshareOn() {
|
|
1604
|
-
return this._mediaManager.turnScreenshareOn();
|
|
1605
|
-
}
|
|
1606
|
-
turnScreenshareOff() {
|
|
1607
|
-
return this._mediaManager.turnScreenshareOff();
|
|
1608
|
-
}
|
|
1609
|
-
// TODO(burdon): Can this be mocked?
|
|
1610
|
-
constructor(_client) {
|
|
1611
|
-
super(), this._client = _client, this.callStateUpdated = new import_async6.Event(), this.mediaStateUpdated = new import_async6.Event(), this.left = new import_async6.Event(), this._state = (0, import_live_object.live)({
|
|
1612
|
-
call: {},
|
|
1613
|
-
media: {
|
|
1614
|
-
pulledAudioTracks: {},
|
|
1615
|
-
pulledVideoStreams: {}
|
|
1616
|
-
}
|
|
1617
|
-
}), this._raisedHandSignal = (0, import_signals_core.computed)(() => this._state.call.raisedHand ?? false), this._speakingSignal = (0, import_signals_core.computed)(() => this._state.call.speaking ?? false), this._joinedSignal = (0, import_signals_core.computed)(() => this._state.call.joined ?? false);
|
|
1618
|
-
this._client.config.getOrThrow("runtime.services.edge.url");
|
|
1619
|
-
const networkService = this._client.services.services.NetworkService;
|
|
1620
|
-
(0, import_invariant4.invariant)(networkService, "network service not found", {
|
|
1621
|
-
F: __dxlog_file6,
|
|
1622
|
-
L: 155,
|
|
1623
|
-
S: this,
|
|
1624
|
-
A: [
|
|
1625
|
-
"networkService",
|
|
1626
|
-
"'network service not found'"
|
|
1627
|
-
]
|
|
1628
|
-
});
|
|
1629
|
-
this._swarmSynchronizer = new CallSwarmSynchronizer({
|
|
1630
|
-
networkService
|
|
1631
|
-
});
|
|
1632
|
-
this._mediaManager = new MediaManager();
|
|
1633
|
-
}
|
|
1634
|
-
async _open() {
|
|
1635
|
-
await this._mediaManager.open();
|
|
1636
|
-
await this._swarmSynchronizer.open();
|
|
1637
|
-
const subscription = this._client.halo.identity.subscribe((identity) => {
|
|
1638
|
-
if (identity) {
|
|
1639
|
-
this._swarmSynchronizer._setIdentity(identity);
|
|
1640
|
-
}
|
|
1641
|
-
if (this._client.halo.device) {
|
|
1642
|
-
this._swarmSynchronizer._setDevice(this._client.halo.device);
|
|
1643
|
-
}
|
|
1644
|
-
});
|
|
1645
|
-
this._ctx.onDispose(() => subscription.unsubscribe());
|
|
1646
|
-
this._swarmSynchronizer.stateUpdated.on(this._ctx, (state) => this._onCallStateUpdated(state));
|
|
1647
|
-
this._mediaManager.stateUpdated.on(this._ctx, (state) => this._onMediaStateUpdated(state));
|
|
1648
|
-
}
|
|
1649
|
-
async _close() {
|
|
1650
|
-
await this._swarmSynchronizer.leave();
|
|
1651
|
-
await this._swarmSynchronizer.close();
|
|
1652
|
-
await this._mediaManager.close();
|
|
1653
|
-
}
|
|
1654
|
-
async peek(roomId) {
|
|
1655
|
-
const peers = await this._swarmSynchronizer.querySwarm(roomId);
|
|
1656
|
-
return peers.length;
|
|
1657
|
-
}
|
|
1658
|
-
// TODO(mykola): Reconcile with _swarmSynchronizer.state.joined.
|
|
1659
|
-
async join() {
|
|
1660
|
-
this._swarmSynchronizer.setJoined(true);
|
|
1661
|
-
await this._swarmSynchronizer.join();
|
|
1662
|
-
await this._mediaManager.join({
|
|
1663
|
-
iceServers: this._client.config.get("runtime.services.ice"),
|
|
1664
|
-
apiBase: `${CALLS_URL}/api/calls`
|
|
1665
|
-
});
|
|
1666
|
-
}
|
|
1667
|
-
async leave() {
|
|
1668
|
-
this._swarmSynchronizer.setJoined(false);
|
|
1669
|
-
await this._swarmSynchronizer.leave();
|
|
1670
|
-
await this._mediaManager.leave();
|
|
1671
|
-
this.roomId && this.left.emit(this.roomId);
|
|
1672
|
-
}
|
|
1673
|
-
_onCallStateUpdated(state) {
|
|
1674
|
-
const tracksToPull = state.users?.filter((user) => user.joined && user.id !== state.self?.id)?.flatMap((user) => [
|
|
1675
|
-
user.tracks?.video,
|
|
1676
|
-
user.tracks?.audio,
|
|
1677
|
-
user.tracks?.screenshare
|
|
1678
|
-
]).filter(import_util2.isNonNullable);
|
|
1679
|
-
this._mediaManager._schedulePullTracks(tracksToPull);
|
|
1680
|
-
this.callStateUpdated.emit(state);
|
|
1681
|
-
this._updateState();
|
|
1682
|
-
}
|
|
1683
|
-
_onMediaStateUpdated(state) {
|
|
1684
|
-
this._swarmSynchronizer.setTracks({
|
|
1685
|
-
video: state.pushedVideoTrack ? TrackNameCodec.encode(state.pushedVideoTrack) : void 0,
|
|
1686
|
-
audio: state.pushedAudioTrack ? TrackNameCodec.encode(state.pushedAudioTrack) : void 0,
|
|
1687
|
-
screenshare: state.pushedScreenshareTrack ? TrackNameCodec.encode(state.pushedScreenshareTrack) : void 0,
|
|
1688
|
-
videoEnabled: state.videoEnabled,
|
|
1689
|
-
audioEnabled: state.audioEnabled,
|
|
1690
|
-
screenshareEnabled: state.screenshareEnabled
|
|
1691
|
-
});
|
|
1692
|
-
const isSpeaking = this._mediaManager.isSpeaking ?? false;
|
|
1693
|
-
this._swarmSynchronizer.setSpeaking(isSpeaking);
|
|
1694
|
-
this.mediaStateUpdated.emit([
|
|
1695
|
-
state,
|
|
1696
|
-
isSpeaking
|
|
1697
|
-
]);
|
|
1698
|
-
this._updateState();
|
|
1699
|
-
}
|
|
1700
|
-
/**
|
|
1701
|
-
* Only this method is allowed to change state.
|
|
1702
|
-
*/
|
|
1703
|
-
_updateState() {
|
|
1704
|
-
this._state.call = this._swarmSynchronizer._getState();
|
|
1705
|
-
this._state.media = this._mediaManager._getState();
|
|
1706
|
-
}
|
|
1707
|
-
};
|
|
1708
|
-
_ts_decorate3([
|
|
1709
|
-
import_async6.synchronized
|
|
1710
|
-
], CallManager.prototype, "join", null);
|
|
1711
|
-
_ts_decorate3([
|
|
1712
|
-
import_async6.synchronized
|
|
1713
|
-
], CallManager.prototype, "leave", null);
|
|
1714
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
1715
|
-
0 && (module.exports = {
|
|
1716
|
-
CALLS_URL,
|
|
1717
|
-
CallManager,
|
|
1718
|
-
CallSwarmSynchronizer,
|
|
1719
|
-
CallsServicePeer,
|
|
1720
|
-
MediaManager,
|
|
1721
|
-
SpeakingMonitor,
|
|
1722
|
-
TrackNameCodec,
|
|
1723
|
-
codec,
|
|
1724
|
-
createBlackCanvasStreamTrack,
|
|
1725
|
-
createInaudibleAudioStreamTrack,
|
|
1726
|
-
getDeviceList,
|
|
1727
|
-
getScreenshare,
|
|
1728
|
-
getUserMediaTrack,
|
|
1729
|
-
monitorAudioLevel
|
|
1730
|
-
});
|
|
1731
|
-
//# sourceMappingURL=chunk-44I33JDT.cjs.map
|