2022-12-31 17:54:10 +03:00
|
|
|
import { h, Fragment } from 'preact';
|
|
|
|
|
import { usePersistence } from '../context';
|
|
|
|
|
import ActivityIndicator from '../components/ActivityIndicator';
|
2021-06-12 17:55:40 +03:00
|
|
|
import JSMpegPlayer from '../components/JSMpegPlayer';
|
|
|
|
|
import Heading from '../components/Heading';
|
2022-12-31 17:54:10 +03:00
|
|
|
import WebRtcPlayer from '../components/WebRtcPlayer';
|
|
|
|
|
import MsePlayer from '../components/MsePlayer';
|
|
|
|
|
import useSWR from 'swr';
|
2023-04-26 14:08:53 +03:00
|
|
|
import { useMemo } from 'preact/hooks';
|
|
|
|
|
import CameraControlPanel from '../components/CameraControlPanel';
|
2021-06-12 17:55:40 +03:00
|
|
|
|
|
|
|
|
export default function Birdseye() {
|
2022-12-31 17:54:10 +03:00
|
|
|
const { data: config } = useSWR('config');
|
|
|
|
|
|
2023-02-12 16:36:36 +03:00
|
|
|
const [viewSource, setViewSource, sourceIsLoaded] = usePersistence(
|
|
|
|
|
'birdseye-source',
|
|
|
|
|
getDefaultLiveMode(config)
|
|
|
|
|
);
|
2022-12-31 17:54:10 +03:00
|
|
|
const sourceValues = ['mse', 'webrtc', 'jsmpeg'];
|
|
|
|
|
|
2023-04-26 14:08:53 +03:00
|
|
|
const ptzCameras = useMemo(() => {
|
|
|
|
|
if (!config) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Object.entries(config.cameras)
|
2023-05-05 02:00:18 +03:00
|
|
|
.filter(([_, conf]) => conf.onvif?.host && conf.onvif.host != '')
|
2023-04-26 14:08:53 +03:00
|
|
|
.map(([_, camera]) => camera.name);
|
|
|
|
|
}, [config]);
|
|
|
|
|
|
2022-12-31 17:54:10 +03:00
|
|
|
if (!config || !sourceIsLoaded) {
|
|
|
|
|
return <ActivityIndicator />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let player;
|
2023-01-17 02:50:35 +03:00
|
|
|
if (viewSource == 'mse' && config.birdseye.restream) {
|
2023-01-14 02:27:16 +03:00
|
|
|
if ('MediaSource' in window) {
|
2022-12-31 17:54:10 +03:00
|
|
|
player = (
|
|
|
|
|
<Fragment>
|
2023-05-05 02:00:18 +03:00
|
|
|
<div className={ptzCameras.length ? 'max-w-5xl xl:w-1/2' : 'max-w-5xl'}>
|
2023-01-14 02:27:16 +03:00
|
|
|
<MsePlayer camera="birdseye" />
|
2022-12-31 17:54:10 +03:00
|
|
|
</div>
|
|
|
|
|
</Fragment>
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
player = (
|
|
|
|
|
<Fragment>
|
2023-01-14 02:27:16 +03:00
|
|
|
<div className="w-5xl text-center text-sm">
|
|
|
|
|
MSE is not supported on iOS devices. You'll need to use jsmpeg or webRTC. See the docs for more info.
|
2022-12-31 17:54:10 +03:00
|
|
|
</div>
|
|
|
|
|
</Fragment>
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-01-17 02:50:35 +03:00
|
|
|
} else if (viewSource == 'webrtc' && config.birdseye.restream) {
|
2022-12-31 17:54:10 +03:00
|
|
|
player = (
|
|
|
|
|
<Fragment>
|
2023-05-05 02:00:18 +03:00
|
|
|
<div className={ptzCameras.length ? 'max-w-5xl xl:w-1/2' : 'max-w-5xl'}>
|
2022-12-31 17:54:10 +03:00
|
|
|
<WebRtcPlayer camera="birdseye" />
|
|
|
|
|
</div>
|
|
|
|
|
</Fragment>
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
player = (
|
|
|
|
|
<Fragment>
|
2023-05-05 02:00:18 +03:00
|
|
|
<div className={ptzCameras.length ? 'max-w-5xl xl:w-1/2' : 'max-w-5xl'}>
|
2022-12-31 17:54:10 +03:00
|
|
|
<JSMpegPlayer camera="birdseye" />
|
|
|
|
|
</div>
|
|
|
|
|
</Fragment>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-12 17:55:40 +03:00
|
|
|
return (
|
2022-02-27 17:04:12 +03:00
|
|
|
<div className="space-y-4 p-2 px-4">
|
2022-12-31 17:54:10 +03:00
|
|
|
<div className="flex justify-between">
|
|
|
|
|
<Heading className="p-2" size="2xl">
|
|
|
|
|
Birdseye
|
|
|
|
|
</Heading>
|
|
|
|
|
|
2023-01-17 02:50:35 +03:00
|
|
|
{config.birdseye.restream && (
|
2022-12-31 17:54:10 +03:00
|
|
|
<select
|
|
|
|
|
className="basis-1/8 cursor-pointer rounded dark:bg-slate-800"
|
|
|
|
|
value={viewSource}
|
|
|
|
|
onChange={(e) => setViewSource(e.target.value)}
|
|
|
|
|
>
|
|
|
|
|
{sourceValues.map((item) => (
|
|
|
|
|
<option key={item} value={item}>
|
|
|
|
|
{item}
|
|
|
|
|
</option>
|
|
|
|
|
))}
|
|
|
|
|
</select>
|
|
|
|
|
)}
|
2021-06-12 17:55:40 +03:00
|
|
|
</div>
|
2022-12-31 17:54:10 +03:00
|
|
|
|
2023-04-26 14:08:53 +03:00
|
|
|
<div className="xl:flex justify-between">
|
|
|
|
|
{player}
|
|
|
|
|
|
2023-05-05 02:00:18 +03:00
|
|
|
{ptzCameras.length ? (
|
2023-04-26 14:08:53 +03:00
|
|
|
<div className="dark:bg-gray-800 shadow-md hover:shadow-lg rounded-lg transition-shadow p-4 w-full sm:w-min xl:h-min xl:w-1/2">
|
|
|
|
|
<Heading size="sm">Control Panel</Heading>
|
|
|
|
|
{ptzCameras.map((camera) => (
|
|
|
|
|
<div className="p-4" key={camera}>
|
|
|
|
|
<Heading size="lg">{camera.replaceAll('_', ' ')}</Heading>
|
|
|
|
|
<CameraControlPanel camera={camera} />
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2023-05-05 02:00:18 +03:00
|
|
|
) : null}
|
2023-04-26 14:08:53 +03:00
|
|
|
</div>
|
2021-06-12 17:55:40 +03:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
2023-02-12 16:36:36 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
function getDefaultLiveMode(config) {
|
|
|
|
|
if (config) {
|
|
|
|
|
if (config.birdseye.restream) {
|
|
|
|
|
return config.ui.live_mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 'jsmpeg';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|