@camstack/ui-library 1.2.182 → 1.2.184
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.
|
@@ -17,6 +17,16 @@ import { WebrtcDebugStats } from './webrtc-debug-stats.js';
|
|
|
17
17
|
* (D393). In a tool whose whole job is telling a stalled decoder from a
|
|
18
18
|
* stalled transport, "nobody measured" and "measured nothing" are
|
|
19
19
|
* opposite conclusions.
|
|
20
|
+
* 4. It must not cover the picture, or the operator turns it off and the tool
|
|
21
|
+
* is worth nothing. So it is a one-line PILL by default — the verdict and
|
|
22
|
+
* the three numbers that carry it — and the full panel only when asked.
|
|
23
|
+
* Collapsed it is small enough to live alongside the app's own overlays
|
|
24
|
+
* (the audio meter, the box layer), which the operator positions freely
|
|
25
|
+
* and which this used to sit on top of.
|
|
26
|
+
*
|
|
27
|
+
* Density follows from the same rule: a cumulative counter and its window
|
|
28
|
+
* share ONE row (`12345 +30`), because two rows saying almost the same thing
|
|
29
|
+
* is how a panel grows until it covers the video it is describing.
|
|
20
30
|
*/
|
|
21
31
|
export interface StreamDebugOverlayProps {
|
|
22
32
|
/** The client half. Null before the first successful poll. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { CamProfile, StationaryOverlayBox } from '@camstack/types';
|
|
2
|
+
import { CamProfile, WebrtcSessionDebug, StationaryOverlayBox } from '@camstack/types';
|
|
3
3
|
import { SignalingResult, ClientOfferResult, ClientStreamHints, SessionSignalingState } from './camera-stream-player';
|
|
4
4
|
import { DeviceDetections } from '../hooks/use-device-detections';
|
|
5
5
|
/**
|
|
@@ -69,6 +69,12 @@ export interface StreamPanelProps {
|
|
|
69
69
|
* adaptive re-offer (steady-state behaviour is unchanged).
|
|
70
70
|
*/
|
|
71
71
|
readonly getSessionState?: (sessionId: string) => Promise<SessionSignalingState>;
|
|
72
|
+
/**
|
|
73
|
+
* The server half of the stream-debug overlay. Optional, and when it is
|
|
74
|
+
* absent the overlay SAYS so rather than showing an empty section — a panel
|
|
75
|
+
* that silently omits half its answer is worse than one that admits it.
|
|
76
|
+
*/
|
|
77
|
+
readonly getSessionDebug?: (sessionId: string) => Promise<WebrtcSessionDebug>;
|
|
72
78
|
/**
|
|
73
79
|
* When set, the panel switches to VOD mode: it renders an `HlsVideo`
|
|
74
80
|
* over this master `.m3u8` URL INSTEAD of the live WebRTC player, and
|
|
@@ -196,4 +202,4 @@ export interface StreamPanelProps {
|
|
|
196
202
|
readonly chromeless?: boolean;
|
|
197
203
|
readonly className?: string;
|
|
198
204
|
}
|
|
199
|
-
export declare function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIceServers, addIceCandidate, getIceCandidates, closeSession, getSessionState, playbackUrl, playbackAuthToken, onExitPlayback, posterUrl, streams, activeStreamId: controlledStreamId, onStreamChange, deviceName, phase, pipelineMetrics, detections, stationaryObjects, defaultShowDetections, defaultShowMotion, streamStats, autoPlay, showPlayStop, snapshotSrc, snapshotLoading, onRefreshSnapshot, showStreamStats, children, extraOverlay, ptzAvailable, ptzShown, ptzOverlay, onPtzToggle, intercomAvailable, intercomShown, onIntercomToggle, chromeless, className, }: StreamPanelProps): import("react").JSX.Element;
|
|
205
|
+
export declare function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIceServers, addIceCandidate, getIceCandidates, closeSession, getSessionState, getSessionDebug, playbackUrl, playbackAuthToken, onExitPlayback, posterUrl, streams, activeStreamId: controlledStreamId, onStreamChange, deviceName, phase, pipelineMetrics, detections, stationaryObjects, defaultShowDetections, defaultShowMotion, streamStats, autoPlay, showPlayStop, snapshotSrc, snapshotLoading, onRefreshSnapshot, showStreamStats, children, extraOverlay, ptzAvailable, ptzShown, ptzOverlay, onPtzToggle, intercomAvailable, intercomShown, onIntercomToggle, chromeless, className, }: StreamPanelProps): import("react").JSX.Element;
|
package/dist/index.cjs
CHANGED
|
@@ -27236,15 +27236,21 @@ var VERDICT_CLASS = {
|
|
|
27236
27236
|
"transport-stall": "bg-rose-500/30 text-rose-100",
|
|
27237
27237
|
"frozen-unknown": "bg-white/15 text-white/70"
|
|
27238
27238
|
};
|
|
27239
|
-
function Row({ label, value, strong = false }) {
|
|
27239
|
+
function Row({ label, value, window, strong = false }) {
|
|
27240
27240
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
27241
|
-
className: "flex items-baseline justify-between gap-
|
|
27241
|
+
className: "flex items-baseline justify-between gap-2 leading-[1.25]",
|
|
27242
27242
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27243
27243
|
className: "text-white/55 shrink-0",
|
|
27244
27244
|
children: label
|
|
27245
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
27246
|
-
className:
|
|
27247
|
-
children:
|
|
27245
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
27246
|
+
className: "flex items-baseline gap-1 text-right",
|
|
27247
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27248
|
+
className: strong ? "text-white font-semibold tabular-nums" : "text-white/90 tabular-nums",
|
|
27249
|
+
children: value
|
|
27250
|
+
}), window !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27251
|
+
className: "text-sky-300/80 tabular-nums",
|
|
27252
|
+
children: window
|
|
27253
|
+
})]
|
|
27248
27254
|
})]
|
|
27249
27255
|
});
|
|
27250
27256
|
}
|
|
@@ -27261,16 +27267,45 @@ function SectionHeader({ title, measuredAt, now }) {
|
|
|
27261
27267
|
})]
|
|
27262
27268
|
});
|
|
27263
27269
|
}
|
|
27270
|
+
/** The pill's dot: the verdict, in the one place that is always visible. */
|
|
27271
|
+
var VERDICT_DOT = {
|
|
27272
|
+
unknown: "bg-white/50",
|
|
27273
|
+
decoding: "bg-emerald-400",
|
|
27274
|
+
"decoder-stall": "bg-amber-400",
|
|
27275
|
+
"transport-stall": "bg-rose-400",
|
|
27276
|
+
"frozen-unknown": "bg-white/50"
|
|
27277
|
+
};
|
|
27264
27278
|
function StreamDebugOverlay(props) {
|
|
27265
27279
|
const { stats, server, serverError, serverWired, now, sessionId } = props;
|
|
27266
27280
|
const verdict = freezeVerdict(stats);
|
|
27267
27281
|
const win = stats?.window;
|
|
27282
|
+
const [expanded, setExpanded] = (0, react$1.useState)(false);
|
|
27283
|
+
const stale = stats !== null && now - stats.at > STALE_AFTER_MS;
|
|
27284
|
+
if (!expanded) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
27285
|
+
type: "button",
|
|
27286
|
+
onClick: () => setExpanded(true),
|
|
27287
|
+
className: "absolute bottom-10 left-2 z-20 transform-gpu flex items-center gap-1.5 rounded bg-neutral-950/90 ring-1 ring-white/20 px-1.5 py-0.5 text-[9px] font-mono text-white/85 tabular-nums select-text",
|
|
27288
|
+
"data-testid": "stream-debug-pill",
|
|
27289
|
+
title: verdict.label,
|
|
27290
|
+
children: [
|
|
27291
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `h-1.5 w-1.5 rounded-full ${VERDICT_DOT[verdict.kind]}` }),
|
|
27292
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: stats?.width !== null && stats?.width !== void 0 ? `${stats.width}×${stats.height}` : UNKNOWN }),
|
|
27293
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [n(stats?.fps), "fps"] }),
|
|
27294
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [n(win?.kbps), "k"] }),
|
|
27295
|
+
stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27296
|
+
className: "text-amber-300",
|
|
27297
|
+
children: "stale"
|
|
27298
|
+
})
|
|
27299
|
+
]
|
|
27300
|
+
});
|
|
27268
27301
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
27269
|
-
className: "absolute
|
|
27302
|
+
className: "absolute bottom-10 left-2 z-20 transform-gpu w-[13.5rem] max-h-[70%] overflow-y-auto rounded-md bg-neutral-950/95 ring-1 ring-white/25 shadow-lg px-1.5 py-1 text-[9px] font-mono text-white/90 select-text",
|
|
27270
27303
|
"data-testid": "stream-debug-overlay",
|
|
27271
27304
|
children: [
|
|
27272
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
27273
|
-
|
|
27305
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
27306
|
+
type: "button",
|
|
27307
|
+
onClick: () => setExpanded(false),
|
|
27308
|
+
className: `w-full text-left rounded px-1.5 py-0.5 mb-1 text-[9px] font-semibold ${VERDICT_CLASS[verdict.kind]}`,
|
|
27274
27309
|
children: verdict.label
|
|
27275
27310
|
}),
|
|
27276
27311
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SectionHeader, {
|
|
@@ -27281,11 +27316,7 @@ function StreamDebugOverlay(props) {
|
|
|
27281
27316
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27282
27317
|
label: "framesDecoded",
|
|
27283
27318
|
value: n(stats?.framesDecoded),
|
|
27284
|
-
|
|
27285
|
-
}),
|
|
27286
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27287
|
-
label: "· this window",
|
|
27288
|
-
value: n(win?.framesDecoded),
|
|
27319
|
+
window: win?.framesDecoded === null ? void 0 : `+${n(win?.framesDecoded)}`,
|
|
27289
27320
|
strong: true
|
|
27290
27321
|
}),
|
|
27291
27322
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
@@ -27294,40 +27325,28 @@ function StreamDebugOverlay(props) {
|
|
|
27294
27325
|
strong: true
|
|
27295
27326
|
}),
|
|
27296
27327
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27297
|
-
label: "
|
|
27328
|
+
label: "frozen",
|
|
27298
27329
|
value: n(stats?.totalFreezeMs, { suffix: "ms" }),
|
|
27330
|
+
window: win?.freezeMs === null ? void 0 : `+${n(win?.freezeMs)}ms`,
|
|
27299
27331
|
strong: true
|
|
27300
27332
|
}),
|
|
27301
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27302
|
-
label: "· this window",
|
|
27303
|
-
value: n(win?.freezeMs, { suffix: "ms" })
|
|
27304
|
-
}),
|
|
27305
27333
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27306
27334
|
label: "pliCount",
|
|
27307
27335
|
value: n(stats?.pliCount),
|
|
27336
|
+
window: win?.pliCount === null ? void 0 : `+${n(win?.pliCount)}`,
|
|
27308
27337
|
strong: true
|
|
27309
27338
|
}),
|
|
27310
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27311
|
-
label: "· this window",
|
|
27312
|
-
value: n(win?.pliCount)
|
|
27313
|
-
}),
|
|
27314
27339
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27315
27340
|
label: "framesDropped",
|
|
27316
27341
|
value: n(stats?.framesDropped)
|
|
27317
27342
|
}),
|
|
27318
27343
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27319
|
-
label: "decode
|
|
27344
|
+
label: "decode",
|
|
27320
27345
|
value: n(stats?.avgDecodeMs, {
|
|
27321
27346
|
digits: 1,
|
|
27322
27347
|
suffix: "ms"
|
|
27323
|
-
})
|
|
27324
|
-
|
|
27325
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27326
|
-
label: "· this window",
|
|
27327
|
-
value: n(win?.decodeMs, {
|
|
27328
|
-
digits: 1,
|
|
27329
|
-
suffix: "ms"
|
|
27330
|
-
})
|
|
27348
|
+
}),
|
|
27349
|
+
window: win?.decodeMs === null ? void 0 : `${n(win?.decodeMs, { digits: 1 })}ms`
|
|
27331
27350
|
}),
|
|
27332
27351
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SectionHeader, {
|
|
27333
27352
|
title: "picture",
|
|
@@ -27385,33 +27404,24 @@ function StreamDebugOverlay(props) {
|
|
|
27385
27404
|
}),
|
|
27386
27405
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27387
27406
|
label: "packetsLost",
|
|
27388
|
-
value: n(stats?.packetsLost)
|
|
27389
|
-
|
|
27390
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27391
|
-
label: "· this window",
|
|
27392
|
-
value: n(win?.packetsLost)
|
|
27407
|
+
value: n(stats?.packetsLost),
|
|
27408
|
+
window: win?.packetsLost === null ? void 0 : `+${n(win?.packetsLost)}`
|
|
27393
27409
|
}),
|
|
27394
27410
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27395
27411
|
label: "loss",
|
|
27396
27412
|
value: n(stats?.lossPercent, {
|
|
27397
27413
|
digits: 2,
|
|
27398
27414
|
suffix: "%"
|
|
27399
|
-
})
|
|
27400
|
-
|
|
27401
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27402
|
-
label: "· this window",
|
|
27403
|
-
value: n(win?.lossPercent, {
|
|
27415
|
+
}),
|
|
27416
|
+
window: win?.lossPercent === null ? void 0 : n(win?.lossPercent, {
|
|
27404
27417
|
digits: 2,
|
|
27405
27418
|
suffix: "%"
|
|
27406
27419
|
})
|
|
27407
27420
|
}),
|
|
27408
27421
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27409
27422
|
label: "nackCount",
|
|
27410
|
-
value: n(stats?.nackCount)
|
|
27411
|
-
|
|
27412
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27413
|
-
label: "· this window",
|
|
27414
|
-
value: n(win?.nackCount)
|
|
27423
|
+
value: n(stats?.nackCount),
|
|
27424
|
+
window: win?.nackCount === null ? void 0 : `+${n(win?.nackCount)}`
|
|
27415
27425
|
}),
|
|
27416
27426
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
27417
27427
|
label: "candidate pair",
|
|
@@ -27434,9 +27444,16 @@ function StreamDebugOverlay(props) {
|
|
|
27434
27444
|
measuredAt: server?.observedAt ?? null,
|
|
27435
27445
|
now
|
|
27436
27446
|
}),
|
|
27437
|
-
!serverWired ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
27438
|
-
className: "text-
|
|
27439
|
-
children:
|
|
27447
|
+
!serverWired ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
27448
|
+
className: "text-amber-300/90 leading-tight py-0.5",
|
|
27449
|
+
children: [
|
|
27450
|
+
"not wired on this surface — this player was mounted without",
|
|
27451
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
27452
|
+
className: "text-white/80",
|
|
27453
|
+
children: " getSessionDebug"
|
|
27454
|
+
}),
|
|
27455
|
+
", so the server half cannot be asked"
|
|
27456
|
+
]
|
|
27440
27457
|
}) : serverError !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
27441
27458
|
className: "text-rose-300 leading-tight py-0.5 break-words",
|
|
27442
27459
|
children: serverError
|
|
@@ -28598,7 +28615,10 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
|
|
|
28598
28615
|
let cancelled = false;
|
|
28599
28616
|
const tick = async () => {
|
|
28600
28617
|
const sid = activeSessionIdRef.current;
|
|
28601
|
-
if (sid === null)
|
|
28618
|
+
if (sid === null) {
|
|
28619
|
+
setServerDebugError("no session id on this player yet — nothing to ask the server about");
|
|
28620
|
+
return;
|
|
28621
|
+
}
|
|
28602
28622
|
try {
|
|
28603
28623
|
const answer = await getSessionDebug(sid);
|
|
28604
28624
|
if (cancelled) return;
|
|
@@ -51062,7 +51082,7 @@ function ImageOffIcon({ className }) {
|
|
|
51062
51082
|
]
|
|
51063
51083
|
});
|
|
51064
51084
|
}
|
|
51065
|
-
function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIceServers, addIceCandidate, getIceCandidates, closeSession, getSessionState, playbackUrl, playbackAuthToken, onExitPlayback, posterUrl, streams, activeStreamId: controlledStreamId, onStreamChange, deviceName, phase, pipelineMetrics, detections, stationaryObjects, defaultShowDetections = true, defaultShowMotion = false, streamStats, autoPlay = false, showPlayStop = false, snapshotSrc, snapshotLoading = false, onRefreshSnapshot, showStreamStats = false, children, extraOverlay, ptzAvailable = false, ptzShown = false, ptzOverlay, onPtzToggle, intercomAvailable = false, intercomShown = false, onIntercomToggle, chromeless = false, className }) {
|
|
51085
|
+
function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIceServers, addIceCandidate, getIceCandidates, closeSession, getSessionState, getSessionDebug, playbackUrl, playbackAuthToken, onExitPlayback, posterUrl, streams, activeStreamId: controlledStreamId, onStreamChange, deviceName, phase, pipelineMetrics, detections, stationaryObjects, defaultShowDetections = true, defaultShowMotion = false, streamStats, autoPlay = false, showPlayStop = false, snapshotSrc, snapshotLoading = false, onRefreshSnapshot, showStreamStats = false, children, extraOverlay, ptzAvailable = false, ptzShown = false, ptzOverlay, onPtzToggle, intercomAvailable = false, intercomShown = false, onIntercomToggle, chromeless = false, className }) {
|
|
51066
51086
|
const registeredButtons = usePlayerToolbarButtons();
|
|
51067
51087
|
const recordedPlayback = useRecordedPlayback();
|
|
51068
51088
|
const [isPlaying, setIsPlaying] = (0, react$1.useState)(autoPlay);
|
|
@@ -51380,6 +51400,7 @@ function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIce
|
|
|
51380
51400
|
handleOffer: playerHandleOffer,
|
|
51381
51401
|
reoffer: playerReoffer,
|
|
51382
51402
|
getSessionState,
|
|
51403
|
+
...getSessionDebug ? { getSessionDebug } : {},
|
|
51383
51404
|
getIceServers,
|
|
51384
51405
|
addIceCandidate,
|
|
51385
51406
|
getIceCandidates,
|
package/dist/index.js
CHANGED
|
@@ -27212,15 +27212,21 @@ var VERDICT_CLASS = {
|
|
|
27212
27212
|
"transport-stall": "bg-rose-500/30 text-rose-100",
|
|
27213
27213
|
"frozen-unknown": "bg-white/15 text-white/70"
|
|
27214
27214
|
};
|
|
27215
|
-
function Row({ label, value, strong = false }) {
|
|
27215
|
+
function Row({ label, value, window, strong = false }) {
|
|
27216
27216
|
return /* @__PURE__ */ jsxs("div", {
|
|
27217
|
-
className: "flex items-baseline justify-between gap-
|
|
27217
|
+
className: "flex items-baseline justify-between gap-2 leading-[1.25]",
|
|
27218
27218
|
children: [/* @__PURE__ */ jsx("span", {
|
|
27219
27219
|
className: "text-white/55 shrink-0",
|
|
27220
27220
|
children: label
|
|
27221
|
-
}), /* @__PURE__ */
|
|
27222
|
-
className:
|
|
27223
|
-
children:
|
|
27221
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
27222
|
+
className: "flex items-baseline gap-1 text-right",
|
|
27223
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
27224
|
+
className: strong ? "text-white font-semibold tabular-nums" : "text-white/90 tabular-nums",
|
|
27225
|
+
children: value
|
|
27226
|
+
}), window !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
27227
|
+
className: "text-sky-300/80 tabular-nums",
|
|
27228
|
+
children: window
|
|
27229
|
+
})]
|
|
27224
27230
|
})]
|
|
27225
27231
|
});
|
|
27226
27232
|
}
|
|
@@ -27237,16 +27243,45 @@ function SectionHeader({ title, measuredAt, now }) {
|
|
|
27237
27243
|
})]
|
|
27238
27244
|
});
|
|
27239
27245
|
}
|
|
27246
|
+
/** The pill's dot: the verdict, in the one place that is always visible. */
|
|
27247
|
+
var VERDICT_DOT = {
|
|
27248
|
+
unknown: "bg-white/50",
|
|
27249
|
+
decoding: "bg-emerald-400",
|
|
27250
|
+
"decoder-stall": "bg-amber-400",
|
|
27251
|
+
"transport-stall": "bg-rose-400",
|
|
27252
|
+
"frozen-unknown": "bg-white/50"
|
|
27253
|
+
};
|
|
27240
27254
|
function StreamDebugOverlay(props) {
|
|
27241
27255
|
const { stats, server, serverError, serverWired, now, sessionId } = props;
|
|
27242
27256
|
const verdict = freezeVerdict(stats);
|
|
27243
27257
|
const win = stats?.window;
|
|
27258
|
+
const [expanded, setExpanded] = useState(false);
|
|
27259
|
+
const stale = stats !== null && now - stats.at > STALE_AFTER_MS;
|
|
27260
|
+
if (!expanded) return /* @__PURE__ */ jsxs("button", {
|
|
27261
|
+
type: "button",
|
|
27262
|
+
onClick: () => setExpanded(true),
|
|
27263
|
+
className: "absolute bottom-10 left-2 z-20 transform-gpu flex items-center gap-1.5 rounded bg-neutral-950/90 ring-1 ring-white/20 px-1.5 py-0.5 text-[9px] font-mono text-white/85 tabular-nums select-text",
|
|
27264
|
+
"data-testid": "stream-debug-pill",
|
|
27265
|
+
title: verdict.label,
|
|
27266
|
+
children: [
|
|
27267
|
+
/* @__PURE__ */ jsx("span", { className: `h-1.5 w-1.5 rounded-full ${VERDICT_DOT[verdict.kind]}` }),
|
|
27268
|
+
/* @__PURE__ */ jsx("span", { children: stats?.width !== null && stats?.width !== void 0 ? `${stats.width}×${stats.height}` : UNKNOWN }),
|
|
27269
|
+
/* @__PURE__ */ jsxs("span", { children: [n(stats?.fps), "fps"] }),
|
|
27270
|
+
/* @__PURE__ */ jsxs("span", { children: [n(win?.kbps), "k"] }),
|
|
27271
|
+
stale && /* @__PURE__ */ jsx("span", {
|
|
27272
|
+
className: "text-amber-300",
|
|
27273
|
+
children: "stale"
|
|
27274
|
+
})
|
|
27275
|
+
]
|
|
27276
|
+
});
|
|
27244
27277
|
return /* @__PURE__ */ jsxs("div", {
|
|
27245
|
-
className: "absolute
|
|
27278
|
+
className: "absolute bottom-10 left-2 z-20 transform-gpu w-[13.5rem] max-h-[70%] overflow-y-auto rounded-md bg-neutral-950/95 ring-1 ring-white/25 shadow-lg px-1.5 py-1 text-[9px] font-mono text-white/90 select-text",
|
|
27246
27279
|
"data-testid": "stream-debug-overlay",
|
|
27247
27280
|
children: [
|
|
27248
|
-
/* @__PURE__ */ jsx("
|
|
27249
|
-
|
|
27281
|
+
/* @__PURE__ */ jsx("button", {
|
|
27282
|
+
type: "button",
|
|
27283
|
+
onClick: () => setExpanded(false),
|
|
27284
|
+
className: `w-full text-left rounded px-1.5 py-0.5 mb-1 text-[9px] font-semibold ${VERDICT_CLASS[verdict.kind]}`,
|
|
27250
27285
|
children: verdict.label
|
|
27251
27286
|
}),
|
|
27252
27287
|
/* @__PURE__ */ jsx(SectionHeader, {
|
|
@@ -27257,11 +27292,7 @@ function StreamDebugOverlay(props) {
|
|
|
27257
27292
|
/* @__PURE__ */ jsx(Row, {
|
|
27258
27293
|
label: "framesDecoded",
|
|
27259
27294
|
value: n(stats?.framesDecoded),
|
|
27260
|
-
|
|
27261
|
-
}),
|
|
27262
|
-
/* @__PURE__ */ jsx(Row, {
|
|
27263
|
-
label: "· this window",
|
|
27264
|
-
value: n(win?.framesDecoded),
|
|
27295
|
+
window: win?.framesDecoded === null ? void 0 : `+${n(win?.framesDecoded)}`,
|
|
27265
27296
|
strong: true
|
|
27266
27297
|
}),
|
|
27267
27298
|
/* @__PURE__ */ jsx(Row, {
|
|
@@ -27270,40 +27301,28 @@ function StreamDebugOverlay(props) {
|
|
|
27270
27301
|
strong: true
|
|
27271
27302
|
}),
|
|
27272
27303
|
/* @__PURE__ */ jsx(Row, {
|
|
27273
|
-
label: "
|
|
27304
|
+
label: "frozen",
|
|
27274
27305
|
value: n(stats?.totalFreezeMs, { suffix: "ms" }),
|
|
27306
|
+
window: win?.freezeMs === null ? void 0 : `+${n(win?.freezeMs)}ms`,
|
|
27275
27307
|
strong: true
|
|
27276
27308
|
}),
|
|
27277
|
-
/* @__PURE__ */ jsx(Row, {
|
|
27278
|
-
label: "· this window",
|
|
27279
|
-
value: n(win?.freezeMs, { suffix: "ms" })
|
|
27280
|
-
}),
|
|
27281
27309
|
/* @__PURE__ */ jsx(Row, {
|
|
27282
27310
|
label: "pliCount",
|
|
27283
27311
|
value: n(stats?.pliCount),
|
|
27312
|
+
window: win?.pliCount === null ? void 0 : `+${n(win?.pliCount)}`,
|
|
27284
27313
|
strong: true
|
|
27285
27314
|
}),
|
|
27286
|
-
/* @__PURE__ */ jsx(Row, {
|
|
27287
|
-
label: "· this window",
|
|
27288
|
-
value: n(win?.pliCount)
|
|
27289
|
-
}),
|
|
27290
27315
|
/* @__PURE__ */ jsx(Row, {
|
|
27291
27316
|
label: "framesDropped",
|
|
27292
27317
|
value: n(stats?.framesDropped)
|
|
27293
27318
|
}),
|
|
27294
27319
|
/* @__PURE__ */ jsx(Row, {
|
|
27295
|
-
label: "decode
|
|
27320
|
+
label: "decode",
|
|
27296
27321
|
value: n(stats?.avgDecodeMs, {
|
|
27297
27322
|
digits: 1,
|
|
27298
27323
|
suffix: "ms"
|
|
27299
|
-
})
|
|
27300
|
-
|
|
27301
|
-
/* @__PURE__ */ jsx(Row, {
|
|
27302
|
-
label: "· this window",
|
|
27303
|
-
value: n(win?.decodeMs, {
|
|
27304
|
-
digits: 1,
|
|
27305
|
-
suffix: "ms"
|
|
27306
|
-
})
|
|
27324
|
+
}),
|
|
27325
|
+
window: win?.decodeMs === null ? void 0 : `${n(win?.decodeMs, { digits: 1 })}ms`
|
|
27307
27326
|
}),
|
|
27308
27327
|
/* @__PURE__ */ jsx(SectionHeader, {
|
|
27309
27328
|
title: "picture",
|
|
@@ -27361,33 +27380,24 @@ function StreamDebugOverlay(props) {
|
|
|
27361
27380
|
}),
|
|
27362
27381
|
/* @__PURE__ */ jsx(Row, {
|
|
27363
27382
|
label: "packetsLost",
|
|
27364
|
-
value: n(stats?.packetsLost)
|
|
27365
|
-
|
|
27366
|
-
/* @__PURE__ */ jsx(Row, {
|
|
27367
|
-
label: "· this window",
|
|
27368
|
-
value: n(win?.packetsLost)
|
|
27383
|
+
value: n(stats?.packetsLost),
|
|
27384
|
+
window: win?.packetsLost === null ? void 0 : `+${n(win?.packetsLost)}`
|
|
27369
27385
|
}),
|
|
27370
27386
|
/* @__PURE__ */ jsx(Row, {
|
|
27371
27387
|
label: "loss",
|
|
27372
27388
|
value: n(stats?.lossPercent, {
|
|
27373
27389
|
digits: 2,
|
|
27374
27390
|
suffix: "%"
|
|
27375
|
-
})
|
|
27376
|
-
|
|
27377
|
-
/* @__PURE__ */ jsx(Row, {
|
|
27378
|
-
label: "· this window",
|
|
27379
|
-
value: n(win?.lossPercent, {
|
|
27391
|
+
}),
|
|
27392
|
+
window: win?.lossPercent === null ? void 0 : n(win?.lossPercent, {
|
|
27380
27393
|
digits: 2,
|
|
27381
27394
|
suffix: "%"
|
|
27382
27395
|
})
|
|
27383
27396
|
}),
|
|
27384
27397
|
/* @__PURE__ */ jsx(Row, {
|
|
27385
27398
|
label: "nackCount",
|
|
27386
|
-
value: n(stats?.nackCount)
|
|
27387
|
-
|
|
27388
|
-
/* @__PURE__ */ jsx(Row, {
|
|
27389
|
-
label: "· this window",
|
|
27390
|
-
value: n(win?.nackCount)
|
|
27399
|
+
value: n(stats?.nackCount),
|
|
27400
|
+
window: win?.nackCount === null ? void 0 : `+${n(win?.nackCount)}`
|
|
27391
27401
|
}),
|
|
27392
27402
|
/* @__PURE__ */ jsx(Row, {
|
|
27393
27403
|
label: "candidate pair",
|
|
@@ -27410,9 +27420,16 @@ function StreamDebugOverlay(props) {
|
|
|
27410
27420
|
measuredAt: server?.observedAt ?? null,
|
|
27411
27421
|
now
|
|
27412
27422
|
}),
|
|
27413
|
-
!serverWired ? /* @__PURE__ */
|
|
27414
|
-
className: "text-
|
|
27415
|
-
children:
|
|
27423
|
+
!serverWired ? /* @__PURE__ */ jsxs("div", {
|
|
27424
|
+
className: "text-amber-300/90 leading-tight py-0.5",
|
|
27425
|
+
children: [
|
|
27426
|
+
"not wired on this surface — this player was mounted without",
|
|
27427
|
+
/* @__PURE__ */ jsx("span", {
|
|
27428
|
+
className: "text-white/80",
|
|
27429
|
+
children: " getSessionDebug"
|
|
27430
|
+
}),
|
|
27431
|
+
", so the server half cannot be asked"
|
|
27432
|
+
]
|
|
27416
27433
|
}) : serverError !== null ? /* @__PURE__ */ jsx("div", {
|
|
27417
27434
|
className: "text-rose-300 leading-tight py-0.5 break-words",
|
|
27418
27435
|
children: serverError
|
|
@@ -28574,7 +28591,10 @@ function CameraStreamPlayer({ serverUrl, streamKey, label, autoPlay = true, mute
|
|
|
28574
28591
|
let cancelled = false;
|
|
28575
28592
|
const tick = async () => {
|
|
28576
28593
|
const sid = activeSessionIdRef.current;
|
|
28577
|
-
if (sid === null)
|
|
28594
|
+
if (sid === null) {
|
|
28595
|
+
setServerDebugError("no session id on this player yet — nothing to ask the server about");
|
|
28596
|
+
return;
|
|
28597
|
+
}
|
|
28578
28598
|
try {
|
|
28579
28599
|
const answer = await getSessionDebug(sid);
|
|
28580
28600
|
if (cancelled) return;
|
|
@@ -51038,7 +51058,7 @@ function ImageOffIcon({ className }) {
|
|
|
51038
51058
|
]
|
|
51039
51059
|
});
|
|
51040
51060
|
}
|
|
51041
|
-
function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIceServers, addIceCandidate, getIceCandidates, closeSession, getSessionState, playbackUrl, playbackAuthToken, onExitPlayback, posterUrl, streams, activeStreamId: controlledStreamId, onStreamChange, deviceName, phase, pipelineMetrics, detections, stationaryObjects, defaultShowDetections = true, defaultShowMotion = false, streamStats, autoPlay = false, showPlayStop = false, snapshotSrc, snapshotLoading = false, onRefreshSnapshot, showStreamStats = false, children, extraOverlay, ptzAvailable = false, ptzShown = false, ptzOverlay, onPtzToggle, intercomAvailable = false, intercomShown = false, onIntercomToggle, chromeless = false, className }) {
|
|
51061
|
+
function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIceServers, addIceCandidate, getIceCandidates, closeSession, getSessionState, getSessionDebug, playbackUrl, playbackAuthToken, onExitPlayback, posterUrl, streams, activeStreamId: controlledStreamId, onStreamChange, deviceName, phase, pipelineMetrics, detections, stationaryObjects, defaultShowDetections = true, defaultShowMotion = false, streamStats, autoPlay = false, showPlayStop = false, snapshotSrc, snapshotLoading = false, onRefreshSnapshot, showStreamStats = false, children, extraOverlay, ptzAvailable = false, ptzShown = false, ptzOverlay, onPtzToggle, intercomAvailable = false, intercomShown = false, onIntercomToggle, chromeless = false, className }) {
|
|
51042
51062
|
const registeredButtons = usePlayerToolbarButtons();
|
|
51043
51063
|
const recordedPlayback = useRecordedPlayback();
|
|
51044
51064
|
const [isPlaying, setIsPlaying] = useState(autoPlay);
|
|
@@ -51356,6 +51376,7 @@ function StreamPanel({ serverUrl, createSession, sendAnswer, handleOffer, getIce
|
|
|
51356
51376
|
handleOffer: playerHandleOffer,
|
|
51357
51377
|
reoffer: playerReoffer,
|
|
51358
51378
|
getSessionState,
|
|
51379
|
+
...getSessionDebug ? { getSessionDebug } : {},
|
|
51359
51380
|
getIceServers,
|
|
51360
51381
|
addIceCandidate,
|
|
51361
51382
|
getIceCandidates,
|