diff --git a/CHANGELOG.md b/CHANGELOG.md
index 72b2902..112c970 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
#### v1.1.0 > v1.2.0
+- Add audio pan filter
- Add video rotation filter ([#347](https://github.com/datarhei/restreamer/discussions/347))
- Add video h/v flip filter
- Add audio volume filter ([#313](https://github.com/datarhei/restreamer/issues/313))
@@ -18,9 +19,9 @@
- Add Telegram to publication services (thx Martin Held)
- Add Polish translations (thx Robert RykaĆa)
- Mod extends the datarhei Core publication service with srt streaming
-- Mod Allow decoders and encoders to set global options
+- Mod allow decoders and encoders to set global options
- Fix player problem with different stream formats (9:16)
-- Mod Allow trailing slash on Core address
+- Mod allow trailing slash on Core address
- Fix process report naming
- Fix publication service icon styles
- Fix VAAPI encoder
diff --git a/src/misc/BoxText.js b/src/misc/BoxText.js
index 0dd98e8..4bb8c3b 100644
--- a/src/misc/BoxText.js
+++ b/src/misc/BoxText.js
@@ -49,6 +49,7 @@ export default function Component(props) {
direction="column"
justifyContent="center"
alignItems="center"
+ textAlign={props.textAlign}
spacing={1}
className={
props.color === 'dark' ? classes.dark : props.color === 'success' ? classes.success : props.color === 'danger' ? classes.danger : classes.light
@@ -62,4 +63,5 @@ export default function Component(props) {
Component.defaultProps = {
color: 'light',
+ textAlign: 'left',
};
diff --git a/src/misc/controls/RTMP.js b/src/misc/controls/RTMP.js
index fa6c982..de2de9e 100644
--- a/src/misc/controls/RTMP.js
+++ b/src/misc/controls/RTMP.js
@@ -6,6 +6,7 @@ import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
+import BoxText from '../BoxText';
import Checkbox from '../Checkbox';
function init(settings) {
@@ -38,19 +39,25 @@ export default function Control(props) {
props.onChange(settings, false);
};
+
return (
-
- Enable} checked={settings.enable} disabled={!props.enabled} onChange={handleChange('enable')} />
-
- Make the channel available as an RTMP stream.
-
-
+ {props.enabled && (
+
+ Enable} checked={settings.enable} disabled={!props.enabled && settings.enable !== true} onChange={handleChange('enable')} />
+
+ Make the channel available as an RTMP stream.
+
+
+ )}
{!props.enabled && (
-
+
+ The RTMP output requires the RTMP Server.
+
+
)}
diff --git a/src/misc/controls/SRT.js b/src/misc/controls/SRT.js
index 77760b9..b4093a9 100644
--- a/src/misc/controls/SRT.js
+++ b/src/misc/controls/SRT.js
@@ -6,6 +6,7 @@ import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
+import BoxText from '../BoxText';
import Checkbox from '../Checkbox';
function init(settings) {
@@ -41,17 +42,22 @@ export default function Control(props) {
return (
-
- Enable} checked={settings.enable} disabled={!props.enabled} onChange={handleChange('enable')} />
-
- Make the channel available as an SRT stream.
-
-
+ {props.enabled && (
+
+ Enable} checked={settings.enable} disabled={!props.enabled && settings.enable !== true} onChange={handleChange('enable')} />
+
+ Make the channel available as an SRT stream.
+
+
+ )}
{!props.enabled && (
-
+
+ The SRT output requires the SRT Server.
+
+
)}
diff --git a/src/misc/filters/audio/Pan.js b/src/misc/filters/audio/Pan.js
new file mode 100644
index 0000000..a3fabc6
--- /dev/null
+++ b/src/misc/filters/audio/Pan.js
@@ -0,0 +1,124 @@
+import React from 'react';
+
+import { Trans } from '@lingui/macro';
+import Grid from '@mui/material/Grid';
+import MenuItem from '@mui/material/MenuItem';
+import Typography from '@mui/material/Typography';
+
+import Select from '../../Select';
+
+// Pan Filter
+// https://ffmpeg.org/ffmpeg-filters.html#pan-1
+
+function init(initialState) {
+ const state = {
+ value: 'none',
+ ...initialState,
+ };
+
+ return state;
+}
+
+function createGraph(settings) {
+ settings = init(settings);
+
+ const mapping = [];
+
+ switch (settings.value) {
+ case 'mute_left':
+ mapping.push('pan=stereo|c1=c1');
+ break;
+ case 'mute_right':
+ mapping.push('pan=stereo|c0=c0');
+ break;
+ default:
+ break;
+ }
+
+ return mapping;
+}
+
+// filter
+function Pan(props) {
+ return (
+
+
+
+ Mute a channel.
+
+
+ );
+}
+
+Pan.defaultProps = {
+ value: '',
+ onChange: function (event) {},
+};
+
+function Filter(props) {
+ const settings = init(props.settings);
+
+ const handleChange = (newSettings) => {
+ let automatic = false;
+ if (!newSettings) {
+ newSettings = settings;
+ automatic = true;
+ }
+
+ props.onChange(newSettings, createGraph(newSettings), automatic);
+ };
+
+ const update = (what) => (event) => {
+ const newSettings = {
+ ...settings,
+ };
+
+ newSettings[what] = event.target.value;
+
+ handleChange(newSettings);
+ };
+
+ React.useEffect(() => {
+ handleChange(null);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ return (
+
+
+
+
+
+ );
+}
+
+Filter.defaultProps = {
+ settings: {},
+ onChange: function (settings, graph, automatic) {},
+};
+
+const filter = 'pan';
+const name = 'Pan';
+const type = 'audio';
+const hwaccel = false;
+
+function summarize(settings) {
+
+
+ return `${name} (${settings.value.replace(/_/i, " ")})`;
+}
+
+function defaults() {
+ const settings = init({});
+
+ return {
+ settings: settings,
+ graph: createGraph(settings),
+ };
+}
+
+export { name, filter, type, hwaccel, summarize, defaults, createGraph, Filter as component };
diff --git a/src/misc/filters/audio/Volume.js b/src/misc/filters/audio/Volume.js
index 145e44f..7e606eb 100644
--- a/src/misc/filters/audio/Volume.js
+++ b/src/misc/filters/audio/Volume.js
@@ -54,7 +54,6 @@ function VolumeLevel(props) {
-
diff --git a/src/misc/filters/index.js b/src/misc/filters/index.js
index eebc322..8ace2f7 100644
--- a/src/misc/filters/index.js
+++ b/src/misc/filters/index.js
@@ -1,5 +1,6 @@
// Audio Filter
import * as AResample from './audio/Resample';
+import * as Pan from './audio/Pan';
import * as Volume from './audio/Volume';
import * as Loudnorm from './audio/Loudnorm';
@@ -44,6 +45,7 @@ class Registry {
// Audio Filters
const audioRegistry = new Registry('audio');
audioRegistry.Register(AResample);
+audioRegistry.Register(Pan);
audioRegistry.Register(Volume);
audioRegistry.Register(Loudnorm);
diff --git a/src/views/Edit/index.js b/src/views/Edit/index.js
index aee62bf..c67c850 100644
--- a/src/views/Edit/index.js
+++ b/src/views/Edit/index.js
@@ -102,8 +102,6 @@ export default function Edit(props) {
...metadata,
});
- console.log(metadata);
-
const skills = await props.restreamer.Skills();
setSkills(skills);
@@ -476,7 +474,7 @@ export default function Edit(props) {
- HLS
+ HLS Output
@@ -486,31 +484,43 @@ export default function Edit(props) {
-
- RTMP
-
-
-
-
-
-
-
-
-
-
- SRT
-
-
-
-
+
+
+
+
+
+ RTMP Output
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SRT Output
+
+
+
+
+
+
+
+