Debug overlay (#97)
* add connection stats * add permissions * styling * css module * styles * scrolling * fix height * account for body height
This commit is contained in:
parent
2c984306cb
commit
2c202c25a2
4 changed files with 218 additions and 5 deletions
195
lib/Debug.tsx
195
lib/Debug.tsx
|
@ -1,10 +1,13 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useRoomContext } from '@livekit/components-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 }) => {
|
export const useDebugMode = ({ logLevel }: { logLevel?: LogLevel }) => {
|
||||||
setLogLevel(logLevel ?? 'debug');
|
setLogLevel(logLevel ?? 'debug');
|
||||||
const room = useRoomContext();
|
const room = useRoomContext();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
window.__lk_room = room;
|
window.__lk_room = room;
|
||||||
|
@ -13,10 +16,198 @@ export const useDebugMode = ({ logLevel }: { logLevel?: LogLevel }) => {
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
window.__lk_room = undefined;
|
window.__lk_room = undefined;
|
||||||
};
|
};
|
||||||
});
|
}, []);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DebugMode = ({ logLevel }: { logLevel?: LogLevel }) => {
|
export const DebugMode = ({ logLevel }: { logLevel?: LogLevel }) => {
|
||||||
|
const room = useRoomContext();
|
||||||
|
const [isOpen, setIsOpen] = React.useState(false);
|
||||||
|
const [, setRender] = React.useState({});
|
||||||
|
|
||||||
useDebugMode({ logLevel });
|
useDebugMode({ logLevel });
|
||||||
|
|
||||||
|
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<HTMLSelectElement>) => {
|
||||||
|
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 <></>;
|
return <></>;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className={styles.overlay}>
|
||||||
|
<section id="room-info">
|
||||||
|
<h3>
|
||||||
|
Room Info {room.name}: {room.sid}
|
||||||
|
</h3>
|
||||||
|
</section>
|
||||||
|
<details open>
|
||||||
|
<summary>
|
||||||
|
<b>Local Participant: {lp.identity}</b>
|
||||||
|
</summary>
|
||||||
|
<details open className={styles.detailsSection}>
|
||||||
|
<summary>
|
||||||
|
<b>Published tracks</b>
|
||||||
|
</summary>
|
||||||
|
<div>
|
||||||
|
{Array.from(lp.tracks.values()).map((t) => (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<i>
|
||||||
|
{t.source.toString()}
|
||||||
|
<span>{t.trackSid}</span>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Kind</td>
|
||||||
|
<td>
|
||||||
|
{t.kind}
|
||||||
|
{t.kind === 'video' && (
|
||||||
|
<span>
|
||||||
|
{t.track?.dimensions?.width}x{t.track?.dimensions?.height}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Bitrate</td>
|
||||||
|
<td>{Math.ceil(t.track!.currentBitrate / 1000)} kbps</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
<details open className={styles.detailsSection}>
|
||||||
|
<summary>
|
||||||
|
<b>Permissions</b>
|
||||||
|
</summary>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{lp.permissions &&
|
||||||
|
Object.entries(lp.permissions).map(([key, val]) => (
|
||||||
|
<>
|
||||||
|
<tr>
|
||||||
|
<td>{key}</td>
|
||||||
|
{key !== 'canPublishSources' ? (
|
||||||
|
<td>{val.toString()}</td>
|
||||||
|
) : (
|
||||||
|
<td> {val.join(', ')} </td>
|
||||||
|
)}
|
||||||
|
</tr>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<b>Remote Participants</b>
|
||||||
|
</summary>
|
||||||
|
{Array.from(room.participants.values()).map((p) => (
|
||||||
|
<details key={p.sid} className={styles.detailsSection}>
|
||||||
|
<summary>
|
||||||
|
<b>
|
||||||
|
{p.identity}
|
||||||
|
<span></span>
|
||||||
|
</b>
|
||||||
|
</summary>
|
||||||
|
<div>
|
||||||
|
{Array.from(p.tracks.values()).map((t) => (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<i>
|
||||||
|
{t.source.toString()}
|
||||||
|
<span>{t.trackSid}</span>
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Kind</td>
|
||||||
|
<td>
|
||||||
|
{t.kind}
|
||||||
|
{t.kind === 'video' && (
|
||||||
|
<span>
|
||||||
|
{t.dimensions?.width}x{t.dimensions?.height}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Status</td>
|
||||||
|
<td>{trackStatus(t)}</td>
|
||||||
|
</tr>
|
||||||
|
{t.track && (
|
||||||
|
<tr>
|
||||||
|
<td>Bitrate</td>
|
||||||
|
<td>{Math.ceil(t.track.currentBitrate / 1000)} kbps</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
))}
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function trackStatus(t: RemoteTrackPublication): string {
|
||||||
|
if (t.isSubscribed) {
|
||||||
|
return t.isEnabled ? 'enabled' : 'disabled';
|
||||||
|
} else {
|
||||||
|
return 'unsubscribed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
"next": "12.3.4",
|
"next": "12.3.4",
|
||||||
"next-seo": "^6.0.0",
|
"next-seo": "^6.0.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0",
|
||||||
|
"tinykeys": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "18.17.1",
|
"@types/node": "18.17.1",
|
||||||
|
|
16
styles/Debug.module.css
Normal file
16
styles/Debug.module.css
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -2249,6 +2249,11 @@ text-table@^0.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||||
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
|
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:
|
to-regex-range@^5.0.1:
|
||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||||
|
|
Loading…
Add table
Reference in a new issue