From 2c202c25a24e3aacfdcba6e7bf24ecd6fb785ee6 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 4 Aug 2023 12:09:39 +0200 Subject: [PATCH] Debug overlay (#97) * add connection stats * add permissions * styling * css module * styles * scrolling * fix height * account for body height --- lib/Debug.tsx | 197 +++++++++++++++++++++++++++++++++++++++- package.json | 5 +- styles/Debug.module.css | 16 ++++ yarn.lock | 5 + 4 files changed, 218 insertions(+), 5 deletions(-) create mode 100644 styles/Debug.module.css diff --git a/lib/Debug.tsx b/lib/Debug.tsx index 6362398..e07ce70 100644 --- a/lib/Debug.tsx +++ b/lib/Debug.tsx @@ -1,10 +1,13 @@ import * as React from 'react'; import { useRoomContext } from '@livekit/components-react'; -import { setLogLevel, LogLevel } from 'livekit-client'; +import { setLogLevel, LogLevel, RemoteTrackPublication } from 'livekit-client'; +import { tinykeys } from 'tinykeys'; +import styles from '../styles/Debug.module.css'; export const useDebugMode = ({ logLevel }: { logLevel?: LogLevel }) => { setLogLevel(logLevel ?? 'debug'); const room = useRoomContext(); + React.useEffect(() => { // @ts-expect-error window.__lk_room = room; @@ -13,10 +16,198 @@ export const useDebugMode = ({ logLevel }: { logLevel?: LogLevel }) => { // @ts-expect-error window.__lk_room = undefined; }; - }); + }, []); }; export const DebugMode = ({ logLevel }: { logLevel?: LogLevel }) => { + const room = useRoomContext(); + const [isOpen, setIsOpen] = React.useState(false); + const [, setRender] = React.useState({}); + useDebugMode({ logLevel }); - return <>; + + React.useEffect(() => { + if (window) { + const unsubscribe = tinykeys(window, { + 'Shift+D': () => { + console.log('setting open'); + setIsOpen((open) => !open); + }, + }); + + // timer to re-render + const interval = setInterval(() => { + setRender({}); + }, 1000); + + return () => { + unsubscribe(); + clearInterval(interval); + }; + } + }, [isOpen]); + + if (typeof window === 'undefined' || !isOpen) { + return null; + } + + const handleSimulate = (event: React.ChangeEvent) => { + const { value } = event.target; + if (value == '') { + return; + } + event.target.value = ''; + let isReconnect = false; + switch (value) { + case 'signal-reconnect': + isReconnect = true; + + // fall through + default: + // @ts-expect-error + room.simulateScenario(value); + } + }; + + const lp = room.localParticipant; + + if (!isOpen) { + return <>; + } else { + return ( +
+
+

+ Room Info {room.name}: {room.sid} +

+
+
+ + Local Participant: {lp.identity} + +
+ + Published tracks + +
+ {Array.from(lp.tracks.values()).map((t) => ( + <> +
+ + {t.source.toString()} +  {t.trackSid} + +
+ + + + + + + + + + + +
Kind + {t.kind}  + {t.kind === 'video' && ( + + {t.track?.dimensions?.width}x{t.track?.dimensions?.height} + + )} +
Bitrate{Math.ceil(t.track!.currentBitrate / 1000)} kbps
+ + ))} +
+
+
+ + Permissions + +
+ + + {lp.permissions && + Object.entries(lp.permissions).map(([key, val]) => ( + <> + + + {key !== 'canPublishSources' ? ( + + ) : ( + + )} + + + ))} + +
{key}{val.toString()} {val.join(', ')}
+
+
+
+ +
+ + Remote Participants + + {Array.from(room.participants.values()).map((p) => ( +
+ + + {p.identity} + + + +
+ {Array.from(p.tracks.values()).map((t) => ( + <> +
+ + {t.source.toString()} +  {t.trackSid} + +
+ + + + + + + + + + + {t.track && ( + + + + + )} + +
Kind + {t.kind}  + {t.kind === 'video' && ( + + {t.dimensions?.width}x{t.dimensions?.height} + + )} +
Status{trackStatus(t)}
Bitrate{Math.ceil(t.track.currentBitrate / 1000)} kbps
+ + ))} +
+
+ ))} +
+
+ ); + } }; + +function trackStatus(t: RemoteTrackPublication): string { + if (t.isSubscribed) { + return t.isEnabled ? 'enabled' : 'disabled'; + } else { + return 'unsubscribed'; + } +} diff --git a/package.json b/package.json index 299bb90..d57f512 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "next": "12.3.4", "next-seo": "^6.0.0", "react": "18.2.0", - "react-dom": "18.2.0" + "react-dom": "18.2.0", + "tinykeys": "^2.1.0" }, "devDependencies": { "@types/node": "18.17.1", @@ -27,4 +28,4 @@ "source-map-loader": "^4.0.1", "typescript": "5.1.6" } -} \ No newline at end of file +} diff --git a/styles/Debug.module.css b/styles/Debug.module.css new file mode 100644 index 0000000..edd1ea4 --- /dev/null +++ b/styles/Debug.module.css @@ -0,0 +1,16 @@ +.overlay { + position: absolute; + top: 0; + background: rgba(0, 0, 0, 0.6); + padding: 1rem; + max-height: min(100%, 100vh); + overflow-y: auto; +} + +.detailsSection { + padding-left: 1rem; +} + +.detailsSection > div { + padding-left: 1rem; +} diff --git a/yarn.lock b/yarn.lock index d3a081b..6b4f86d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2249,6 +2249,11 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tinykeys@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tinykeys/-/tinykeys-2.1.0.tgz#1341563e92a7fac9ca90053fddaf2b7553500298" + integrity sha512-/MESnqBD1xItZJn5oGQ4OsNORQgJfPP96XSGoyu4eLpwpL0ifO0SYR5OD76u0YMhMXsqkb0UqvI9+yXTh4xv8Q== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"