Live streaming tech selection (#24374)

* allow users to select live streaming technology

* fix webrtc being downgraded to mse on load

`useUserPersistence` seeds state with the default and loads asynchronously, so the first render always used `mse` instead of the saved choice, and `useWebRTCGloballyAvailable` reports `checking` until the probe settles and re-enters that state on every consumer mount, so a saved `webrtc` was rewritten to `mse` even after the probe had already passed. On Safari the MSE player then timed out and latched the jsmpeg fallback. A pending probe now counts as available, the player waits on `autoLive` until the stored preferences load, and `handleError` gates on the mode in use since the fallback flag no longer implies webrtc is untried. A rejected IndexedDB read also resolves `loaded` now, so a blocked store can't leave the player waiting forever.

* add support for configurable ICE servers in WebRTC player

* add mic error state, fix dialog overwriting saved choice and dashboard ignoring stream

* tweaks
This commit is contained in:
Josh Hawkins
2026-09-16 09:12:06 -05:00
committed by GitHub
parent 79ca18d439
commit 64d6366ac4
26 changed files with 1940 additions and 283 deletions
+4 -15
View File
@@ -22,6 +22,7 @@ import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";
import {
AudioState,
LivePlayerError,
LivePlayerMode,
LiveStreamMetadata,
StatsState,
@@ -65,9 +66,7 @@ type DraggableGridLayoutProps = {
fullscreen: boolean;
toggleFullscreen: () => void;
preferredLiveModes: { [key: string]: LivePlayerMode };
setPreferredLiveModes: React.Dispatch<
React.SetStateAction<{ [key: string]: LivePlayerMode }>
>;
handleError: (cameraName: string, error: LivePlayerError) => void;
resetPreferredLiveMode: (cameraName: string) => void;
isRestreamedStates: { [key: string]: boolean };
supportsAudioOutputStates: {
@@ -89,7 +88,7 @@ export default function DraggableGridLayout({
fullscreen,
toggleFullscreen,
preferredLiveModes,
setPreferredLiveModes,
handleError,
resetPreferredLiveMode,
isRestreamedStates,
supportsAudioOutputStates,
@@ -672,17 +671,7 @@ export default function DraggableGridLayout({
onSelectCamera(camera.name);
}
}}
onError={(e) => {
setPreferredLiveModes((prevModes) => {
const newModes = { ...prevModes };
if (e === "mse-decode") {
newModes[camera.name] = "webrtc";
} else {
newModes[camera.name] = "jsmpeg";
}
return newModes;
});
}}
onError={(e) => handleError(camera.name, e)}
onResetLiveMode={() => resetPreferredLiveMode(camera.name)}
playAudio={audioStates[camera.name]}
volume={volumeStates[camera.name]}