diff --git a/frigate/config.py b/frigate/config.py index a01df46c4..19fead137 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -590,12 +590,17 @@ class CameraConfig(FrigateBaseModel): # add roles to the input if there is only one if len(config["ffmpeg"]["inputs"]) == 1: + has_rtmp = "rtmp" in config["ffmpeg"]["inputs"][0]["roles"] + config["ffmpeg"]["inputs"][0]["roles"] = [ "record", "detect", "restream", ] + if has_rtmp: + config["ffmpeg"]["inputs"][0]["roles"].append("rtmp") + super().__init__(**config) @property diff --git a/frigate/test/test_config.py b/frigate/test/test_config.py index 319ae1e3b..70b6ba03f 100644 --- a/frigate/test/test_config.py +++ b/frigate/test/test_config.py @@ -1181,7 +1181,7 @@ class TestConfig(unittest.TestCase): "inputs": [ { "path": "rtsp://10.0.0.1:554/video", - "roles": ["detect"], + "roles": ["detect", "rtmp"], }, ] }, @@ -1225,11 +1225,11 @@ class TestConfig(unittest.TestCase): runtime_config = frigate_config.runtime_config assert not runtime_config.cameras["back"].rtmp.enabled - def test_global_live(self): + def test_global_jsmpeg(self): config = { "mqtt": {"host": "mqtt"}, - "live": {"quality": 4}, + "restream": {"jsmpeg": {"quality": 4}}, "cameras": { "back": { "ffmpeg": { @@ -1247,7 +1247,7 @@ class TestConfig(unittest.TestCase): assert config == frigate_config.dict(exclude_unset=True) runtime_config = frigate_config.runtime_config - assert runtime_config.cameras["back"].live.quality == 4 + assert runtime_config.cameras["back"].restream.jsmpeg.quality == 4 def test_default_live(self): @@ -1270,13 +1270,13 @@ class TestConfig(unittest.TestCase): assert config == frigate_config.dict(exclude_unset=True) runtime_config = frigate_config.runtime_config - assert runtime_config.cameras["back"].live.quality == 8 + assert runtime_config.cameras["back"].restream.jsmpeg.quality == 8 def test_global_live_merge(self): config = { "mqtt": {"host": "mqtt"}, - "live": {"quality": 4, "height": 480}, + "restream": {"jsmpeg": {"quality": 4, "height": 480}}, "cameras": { "back": { "ffmpeg": { @@ -1287,8 +1287,10 @@ class TestConfig(unittest.TestCase): }, ] }, - "live": { - "quality": 7, + "restream": { + "jsmpeg": { + "quality": 7, + } }, } }, @@ -1297,8 +1299,8 @@ class TestConfig(unittest.TestCase): assert config == frigate_config.dict(exclude_unset=True) runtime_config = frigate_config.runtime_config - assert runtime_config.cameras["back"].live.quality == 7 - assert runtime_config.cameras["back"].live.height == 480 + assert runtime_config.cameras["back"].restream.jsmpeg.quality == 7 + assert runtime_config.cameras["back"].restream.jsmpeg.height == 480 def test_global_timestamp_style(self): diff --git a/test.db-journal b/test.db-journal new file mode 100644 index 000000000..3649988aa Binary files /dev/null and b/test.db-journal differ diff --git a/web/config/handlers.js b/web/config/handlers.js index 0166d0c3a..c24fcd8d2 100644 --- a/web/config/handlers.js +++ b/web/config/handlers.js @@ -19,7 +19,7 @@ export const handlers = [ record: { enabled: true }, detect: { width: 1280, height: 720 }, snapshots: {}, - live: { height: 720 }, + restream: { enabled: true, jsmpeg: { height: 720 } }, ui: { dashboard: true, order: 0 }, }, side: { @@ -28,7 +28,7 @@ export const handlers = [ record: { enabled: false }, detect: { width: 1280, height: 720 }, snapshots: {}, - live: { height: 720 }, + restream: { enabled: true, jsmpeg: { height: 720 } }, ui: { dashboard: true, order: 1 }, }, }, diff --git a/web/src/routes/Camera.jsx b/web/src/routes/Camera.jsx index 9a1ba03d1..08545db57 100644 --- a/web/src/routes/Camera.jsx +++ b/web/src/routes/Camera.jsx @@ -29,7 +29,7 @@ export default function Camera({ camera }) { ? Math.round(cameraConfig.restream.jsmpeg.height * (cameraConfig.detect.width / cameraConfig.detect.height)) : 0; const [viewSource, setViewSource] = usePersistence(`${camera}-source`, 'jsmpeg'); - const sourceValues = cameraConfig.restream.enabled ? ['jsmpeg', 'mp4', 'webrtc'] : ['jsmpeg']; + const sourceValues = (cameraConfig && cameraConfig.restream.enabled) ? ['jsmpeg', 'mp4', 'webrtc'] : ['jsmpeg']; const [options, setOptions] = usePersistence(`${camera}-feed`, emptyObject); const handleSetOption = useCallback( @@ -100,7 +100,7 @@ export default function Camera({ camera }) { if (viewSource == 'mp4') { player = ( -
+
{ test('updates camera feed options to persistence', async () => { mockUsePersistence + .mockReturnValueOnce([{}, mockSetOptions]) + .mockReturnValueOnce([{}, mockSetOptions]) + .mockReturnValueOnce([{}, mockSetOptions]) + .mockReturnValueOnce([{}, mockSetOptions]) + .mockReturnValueOnce([{}, mockSetOptions]) .mockReturnValueOnce([{}, mockSetOptions]) .mockReturnValueOnce([{}, mockSetOptions]) .mockReturnValueOnce([{}, mockSetOptions]) @@ -63,9 +68,8 @@ describe('Camera Route', () => { fireEvent.change(screen.queryByTestId('timestamp-input'), { target: { checked: true } }); fireEvent.click(screen.queryByText('Hide Options')); - expect(mockUsePersistence).toHaveBeenCalledTimes(5); + expect(mockUsePersistence).toHaveBeenCalledTimes(10); expect(mockSetOptions).toHaveBeenCalledTimes(2); - expect(mockSetOptions).toHaveBeenCalledWith({ bbox: true, timestamp: true }); expect(screen.queryByTestId('mock-image')).toHaveTextContent('bbox=1×tamp=1'); }); });