@reactor-team/js-sdk 2.3.2 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +39 -8
- package/dist/index.d.ts +39 -8
- package/dist/index.js +131 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +137 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -206,6 +206,52 @@ function parseMessage(data) {
|
|
|
206
206
|
function closePeerConnection(pc) {
|
|
207
207
|
pc.close();
|
|
208
208
|
}
|
|
209
|
+
function extractConnectionStats(report) {
|
|
210
|
+
let rtt;
|
|
211
|
+
let availableOutgoingBitrate;
|
|
212
|
+
let localCandidateId;
|
|
213
|
+
let framesPerSecond;
|
|
214
|
+
let jitter;
|
|
215
|
+
let packetLossRatio;
|
|
216
|
+
report.forEach((stat) => {
|
|
217
|
+
if (stat.type === "candidate-pair" && stat.state === "succeeded") {
|
|
218
|
+
if (stat.currentRoundTripTime !== void 0) {
|
|
219
|
+
rtt = stat.currentRoundTripTime * 1e3;
|
|
220
|
+
}
|
|
221
|
+
if (stat.availableOutgoingBitrate !== void 0) {
|
|
222
|
+
availableOutgoingBitrate = stat.availableOutgoingBitrate;
|
|
223
|
+
}
|
|
224
|
+
localCandidateId = stat.localCandidateId;
|
|
225
|
+
}
|
|
226
|
+
if (stat.type === "inbound-rtp" && stat.kind === "video") {
|
|
227
|
+
if (stat.framesPerSecond !== void 0) {
|
|
228
|
+
framesPerSecond = stat.framesPerSecond;
|
|
229
|
+
}
|
|
230
|
+
if (stat.jitter !== void 0) {
|
|
231
|
+
jitter = stat.jitter;
|
|
232
|
+
}
|
|
233
|
+
if (stat.packetsReceived !== void 0 && stat.packetsLost !== void 0 && stat.packetsReceived + stat.packetsLost > 0) {
|
|
234
|
+
packetLossRatio = stat.packetsLost / (stat.packetsReceived + stat.packetsLost);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
let candidateType;
|
|
239
|
+
if (localCandidateId) {
|
|
240
|
+
const localCandidate = report.get(localCandidateId);
|
|
241
|
+
if (localCandidate == null ? void 0 : localCandidate.candidateType) {
|
|
242
|
+
candidateType = localCandidate.candidateType;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
rtt,
|
|
247
|
+
candidateType,
|
|
248
|
+
availableOutgoingBitrate,
|
|
249
|
+
framesPerSecond,
|
|
250
|
+
packetLossRatio,
|
|
251
|
+
jitter,
|
|
252
|
+
timestamp: Date.now()
|
|
253
|
+
};
|
|
254
|
+
}
|
|
209
255
|
|
|
210
256
|
// src/core/CoordinatorClient.ts
|
|
211
257
|
var INITIAL_BACKOFF_MS = 500;
|
|
@@ -581,6 +627,7 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
581
627
|
|
|
582
628
|
// src/core/GPUMachineClient.ts
|
|
583
629
|
var PING_INTERVAL_MS = 5e3;
|
|
630
|
+
var STATS_INTERVAL_MS = 2e3;
|
|
584
631
|
var GPUMachineClient = class {
|
|
585
632
|
constructor(config) {
|
|
586
633
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
@@ -664,6 +711,7 @@ var GPUMachineClient = class {
|
|
|
664
711
|
disconnect() {
|
|
665
712
|
return __async(this, null, function* () {
|
|
666
713
|
this.stopPing();
|
|
714
|
+
this.stopStatsPolling();
|
|
667
715
|
if (this.publishedTrack) {
|
|
668
716
|
yield this.unpublishTrack();
|
|
669
717
|
}
|
|
@@ -820,6 +868,31 @@ var GPUMachineClient = class {
|
|
|
820
868
|
}
|
|
821
869
|
}
|
|
822
870
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
871
|
+
// Stats Polling (RTT)
|
|
872
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
873
|
+
getStats() {
|
|
874
|
+
return this.stats;
|
|
875
|
+
}
|
|
876
|
+
startStatsPolling() {
|
|
877
|
+
this.stopStatsPolling();
|
|
878
|
+
this.statsInterval = setInterval(() => __async(this, null, function* () {
|
|
879
|
+
if (!this.peerConnection) return;
|
|
880
|
+
try {
|
|
881
|
+
const report = yield this.peerConnection.getStats();
|
|
882
|
+
this.stats = extractConnectionStats(report);
|
|
883
|
+
this.emit("statsUpdate", this.stats);
|
|
884
|
+
} catch (e) {
|
|
885
|
+
}
|
|
886
|
+
}), STATS_INTERVAL_MS);
|
|
887
|
+
}
|
|
888
|
+
stopStatsPolling() {
|
|
889
|
+
if (this.statsInterval !== void 0) {
|
|
890
|
+
clearInterval(this.statsInterval);
|
|
891
|
+
this.statsInterval = void 0;
|
|
892
|
+
}
|
|
893
|
+
this.stats = void 0;
|
|
894
|
+
}
|
|
895
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
823
896
|
// Private Helpers
|
|
824
897
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
825
898
|
setStatus(newStatus) {
|
|
@@ -838,6 +911,7 @@ var GPUMachineClient = class {
|
|
|
838
911
|
switch (state) {
|
|
839
912
|
case "connected":
|
|
840
913
|
this.setStatus("connected");
|
|
914
|
+
this.startStatsPolling();
|
|
841
915
|
break;
|
|
842
916
|
case "disconnected":
|
|
843
917
|
case "closed":
|
|
@@ -1127,7 +1201,11 @@ var Reactor = class {
|
|
|
1127
1201
|
setupMachineClientHandlers() {
|
|
1128
1202
|
if (!this.machineClient) return;
|
|
1129
1203
|
this.machineClient.on("message", (message, scope) => {
|
|
1130
|
-
|
|
1204
|
+
if (scope === "application") {
|
|
1205
|
+
this.emit("message", message);
|
|
1206
|
+
} else if (scope === "runtime") {
|
|
1207
|
+
this.emit("runtimeMessage", message);
|
|
1208
|
+
}
|
|
1131
1209
|
});
|
|
1132
1210
|
this.machineClient.on("statusChanged", (status) => {
|
|
1133
1211
|
switch (status) {
|
|
@@ -1154,6 +1232,9 @@ var Reactor = class {
|
|
|
1154
1232
|
this.emit("streamChanged", track, stream);
|
|
1155
1233
|
}
|
|
1156
1234
|
);
|
|
1235
|
+
this.machineClient.on("statsUpdate", (stats) => {
|
|
1236
|
+
this.emit("statsUpdate", stats);
|
|
1237
|
+
});
|
|
1157
1238
|
}
|
|
1158
1239
|
/**
|
|
1159
1240
|
* Disconnects from the coordinator and the gpu machine.
|
|
@@ -1240,6 +1321,10 @@ var Reactor = class {
|
|
|
1240
1321
|
getLastError() {
|
|
1241
1322
|
return this.lastError;
|
|
1242
1323
|
}
|
|
1324
|
+
getStats() {
|
|
1325
|
+
var _a;
|
|
1326
|
+
return (_a = this.machineClient) == null ? void 0 : _a.getStats();
|
|
1327
|
+
}
|
|
1243
1328
|
/**
|
|
1244
1329
|
* Create and store an error
|
|
1245
1330
|
*/
|
|
@@ -1328,10 +1413,10 @@ var createReactorStore = (initProps, publicState = defaultInitState) => {
|
|
|
1328
1413
|
// actions
|
|
1329
1414
|
onMessage: (handler) => {
|
|
1330
1415
|
console.debug("[ReactorStore] Registering message handler");
|
|
1331
|
-
get().internal.reactor.on("
|
|
1416
|
+
get().internal.reactor.on("message", handler);
|
|
1332
1417
|
return () => {
|
|
1333
1418
|
console.debug("[ReactorStore] Cleaning up message handler");
|
|
1334
|
-
get().internal.reactor.off("
|
|
1419
|
+
get().internal.reactor.off("message", handler);
|
|
1335
1420
|
};
|
|
1336
1421
|
},
|
|
1337
1422
|
sendCommand: (command, data, scope) => __async(null, null, function* () {
|
|
@@ -1534,7 +1619,7 @@ function useReactorStore(selector) {
|
|
|
1534
1619
|
|
|
1535
1620
|
// src/react/hooks.ts
|
|
1536
1621
|
import { useShallow } from "zustand/shallow";
|
|
1537
|
-
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
1622
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
1538
1623
|
function useReactor(selector) {
|
|
1539
1624
|
return useReactorStore(useShallow(selector));
|
|
1540
1625
|
}
|
|
@@ -1545,21 +1630,45 @@ function useReactorMessage(handler) {
|
|
|
1545
1630
|
handlerRef.current = handler;
|
|
1546
1631
|
}, [handler]);
|
|
1547
1632
|
useEffect2(() => {
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1633
|
+
const stableHandler = (message) => {
|
|
1634
|
+
handlerRef.current(message);
|
|
1635
|
+
};
|
|
1636
|
+
reactor.on("message", stableHandler);
|
|
1637
|
+
return () => {
|
|
1638
|
+
reactor.off("message", stableHandler);
|
|
1639
|
+
};
|
|
1640
|
+
}, [reactor]);
|
|
1641
|
+
}
|
|
1642
|
+
function useReactorInternalMessage(handler) {
|
|
1643
|
+
const reactor = useReactor((state) => state.internal.reactor);
|
|
1644
|
+
const handlerRef = useRef2(handler);
|
|
1645
|
+
useEffect2(() => {
|
|
1646
|
+
handlerRef.current = handler;
|
|
1647
|
+
}, [handler]);
|
|
1648
|
+
useEffect2(() => {
|
|
1649
|
+
const stableHandler = (message) => {
|
|
1650
|
+
handlerRef.current(message);
|
|
1651
|
+
};
|
|
1652
|
+
reactor.on("runtimeMessage", stableHandler);
|
|
1653
|
+
return () => {
|
|
1654
|
+
reactor.off("runtimeMessage", stableHandler);
|
|
1655
|
+
};
|
|
1656
|
+
}, [reactor]);
|
|
1657
|
+
}
|
|
1658
|
+
function useStats() {
|
|
1659
|
+
const reactor = useReactor((state) => state.internal.reactor);
|
|
1660
|
+
const [stats, setStats] = useState2(void 0);
|
|
1661
|
+
useEffect2(() => {
|
|
1662
|
+
const handler = (newStats) => {
|
|
1663
|
+
setStats(newStats);
|
|
1555
1664
|
};
|
|
1556
|
-
reactor.on("
|
|
1557
|
-
console.debug("[useReactorMessage] Message handler registered");
|
|
1665
|
+
reactor.on("statsUpdate", handler);
|
|
1558
1666
|
return () => {
|
|
1559
|
-
|
|
1560
|
-
|
|
1667
|
+
reactor.off("statsUpdate", handler);
|
|
1668
|
+
setStats(void 0);
|
|
1561
1669
|
};
|
|
1562
1670
|
}, [reactor]);
|
|
1671
|
+
return stats;
|
|
1563
1672
|
}
|
|
1564
1673
|
|
|
1565
1674
|
// src/react/ReactorView.tsx
|
|
@@ -1658,7 +1767,7 @@ function ReactorView({
|
|
|
1658
1767
|
}
|
|
1659
1768
|
|
|
1660
1769
|
// src/react/ReactorController.tsx
|
|
1661
|
-
import React, { useState as
|
|
1770
|
+
import React, { useState as useState3, useCallback } from "react";
|
|
1662
1771
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1663
1772
|
function ReactorController({
|
|
1664
1773
|
className,
|
|
@@ -1668,9 +1777,9 @@ function ReactorController({
|
|
|
1668
1777
|
sendCommand: state.sendCommand,
|
|
1669
1778
|
status: state.status
|
|
1670
1779
|
}));
|
|
1671
|
-
const [commands, setCommands] =
|
|
1672
|
-
const [formValues, setFormValues] =
|
|
1673
|
-
const [expandedCommands, setExpandedCommands] =
|
|
1780
|
+
const [commands, setCommands] = useState3({});
|
|
1781
|
+
const [formValues, setFormValues] = useState3({});
|
|
1782
|
+
const [expandedCommands, setExpandedCommands] = useState3({});
|
|
1674
1783
|
React.useEffect(() => {
|
|
1675
1784
|
if (status === "disconnected") {
|
|
1676
1785
|
setCommands({});
|
|
@@ -1697,8 +1806,8 @@ function ReactorController({
|
|
|
1697
1806
|
}, 5e3);
|
|
1698
1807
|
return () => clearInterval(interval);
|
|
1699
1808
|
}, [status, commands, requestCapabilities]);
|
|
1700
|
-
|
|
1701
|
-
if (
|
|
1809
|
+
useReactorInternalMessage((message) => {
|
|
1810
|
+
if (message && typeof message === "object" && message.type === "modelCapabilities" && message.data && "commands" in message.data) {
|
|
1702
1811
|
const commandsMessage = message.data;
|
|
1703
1812
|
setCommands(commandsMessage.commands);
|
|
1704
1813
|
const initialValues = {};
|
|
@@ -2111,7 +2220,7 @@ function ReactorController({
|
|
|
2111
2220
|
}
|
|
2112
2221
|
|
|
2113
2222
|
// src/react/WebcamStream.tsx
|
|
2114
|
-
import { useEffect as useEffect4, useRef as useRef4, useState as
|
|
2223
|
+
import { useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
|
|
2115
2224
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2116
2225
|
function WebcamStream({
|
|
2117
2226
|
className,
|
|
@@ -2123,9 +2232,9 @@ function WebcamStream({
|
|
|
2123
2232
|
showWebcam = true,
|
|
2124
2233
|
videoObjectFit = "contain"
|
|
2125
2234
|
}) {
|
|
2126
|
-
const [stream, setStream] =
|
|
2127
|
-
const [isPublishing, setIsPublishing] =
|
|
2128
|
-
const [permissionDenied, setPermissionDenied] =
|
|
2235
|
+
const [stream, setStream] = useState4(null);
|
|
2236
|
+
const [isPublishing, setIsPublishing] = useState4(false);
|
|
2237
|
+
const [permissionDenied, setPermissionDenied] = useState4(false);
|
|
2129
2238
|
const { status, publishVideoStream, unpublishVideoStream, reactor } = useReactor((state) => ({
|
|
2130
2239
|
status: state.status,
|
|
2131
2240
|
publishVideoStream: state.publishVideoStream,
|
|
@@ -2330,7 +2439,9 @@ export {
|
|
|
2330
2439
|
WebcamStream,
|
|
2331
2440
|
fetchInsecureJwtToken,
|
|
2332
2441
|
useReactor,
|
|
2442
|
+
useReactorInternalMessage,
|
|
2333
2443
|
useReactorMessage,
|
|
2334
|
-
useReactorStore
|
|
2444
|
+
useReactorStore,
|
|
2445
|
+
useStats
|
|
2335
2446
|
};
|
|
2336
2447
|
//# sourceMappingURL=index.mjs.map
|