diff --git a/src/utils/restreamer.js b/src/utils/restreamer.js
index 5f120a8..f8a785f 100644
--- a/src/utils/restreamer.js
+++ b/src/utils/restreamer.js
@@ -514,6 +514,9 @@ class Restreamer {
virtualvideo: [],
videoloop: [],
audioloop: [],
+ channel: [],
+ noaudio: [],
+ sdp: [],
},
sinks: {},
};
@@ -677,6 +680,15 @@ class Restreamer {
skills.sources['network'].push(...channels);
+ channels = this.ListChannels().map((channel) => {
+ return {
+ id: channel.channelid,
+ name: channel.name,
+ };
+ });
+
+ skills.sources['channel'].push(...channels);
+
this.skills = skills;
}
diff --git a/src/views/Edit/Profile.js b/src/views/Edit/Profile.js
index 1f7d986..8c64abe 100644
--- a/src/views/Edit/Profile.js
+++ b/src/views/Edit/Profile.js
@@ -78,10 +78,6 @@ export default function Profile({
}, []);
const load = async () => {
- // Add pseudo sources
- skills.sources.noaudio = [];
- skills.sources.sdp = [];
-
let audio = $sources.audio;
let hasAudio = false;
diff --git a/src/views/Edit/Sources/Channel.js b/src/views/Edit/Sources/Channel.js
new file mode 100644
index 0000000..f6996de
--- /dev/null
+++ b/src/views/Edit/Sources/Channel.js
@@ -0,0 +1,125 @@
+import React from 'react';
+
+import { useLingui } from '@lingui/react';
+import { Trans, t } from '@lingui/macro';
+import VideocamIcon from '@mui/icons-material/Videocam';
+import makeStyles from '@mui/styles/makeStyles';
+import Button from '@mui/material/Button';
+import Grid from '@mui/material/Grid';
+import RefreshIcon from '@mui/icons-material/Refresh';
+import Typography from '@mui/material/Typography';
+
+import FormInlineButton from '../../../misc/FormInlineButton';
+import SelectCustom from '../../../misc/SelectCustom';
+
+const useStyles = makeStyles((theme) => ({
+ gridContainer: {
+ marginTop: '0.5em',
+ },
+}));
+
+const initSettings = (initialSettings) => {
+ if (!initialSettings) {
+ initialSettings = {};
+ }
+
+ const settings = {
+ channelid: 'none',
+ ...initialSettings,
+ };
+
+ return settings;
+};
+
+const createInputs = (settings) => {
+ const address = `{fs:mem}/${settings.channelid}.m3u8`;
+ const input = {
+ address: address,
+ options: [],
+ };
+
+ return [input];
+};
+
+function Source({ knownDevices = [], settings = {}, onChange = function (settings) {}, onProbe = function (settings, inputs) {}, onRefresh = function () {} }) {
+ const classes = useStyles();
+ const { i18n } = useLingui();
+ settings = initSettings(settings);
+
+ const handleChange = (what) => (event) => {
+ let data = {};
+
+ if (['channelid'].includes(what)) {
+ data[what] = event.target.value;
+ }
+
+ onChange({
+ ...settings,
+ ...data,
+ });
+ };
+
+ const handleRefresh = () => {
+ onRefresh();
+ };
+
+ const handleProbe = () => {
+ onProbe(settings, createInputs(settings));
+ };
+
+ const options = knownDevices.map((device) => {
+ return {
+ value: device.id,
+ label: device.name + ' (' + device.id + ')',
+ };
+ });
+
+ options.unshift({
+ value: 'none',
+ label: i18n._(t`Choose an input channel ...`),
+ disabled: true,
+ });
+
+ return (
+
+
+
+ Select a channel:
+
+
+
+ Video device}
+ value={settings.channelid}
+ onChange={handleChange('channelid')}
+ variant="outlined"
+ />
+ } onClick={handleRefresh} sx={{ float: 'right' }}>
+ Refresh
+
+
+
+
+ Probe
+
+
+
+ );
+}
+
+function SourceIcon(props) {
+ return ;
+}
+
+const id = 'channel';
+const name = Channel;
+const capabilities = ['audio', 'video'];
+const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0 || ^7.0.0';
+
+const func = {
+ initSettings,
+ createInputs,
+};
+
+export { id, name, capabilities, ffversion, SourceIcon as icon, Source as component, func };
diff --git a/src/views/Edit/Sources/X11grab.js b/src/views/Edit/Sources/X11grab.js
index 508abc1..a861eb8 100644
--- a/src/views/Edit/Sources/X11grab.js
+++ b/src/views/Edit/Sources/X11grab.js
@@ -1,8 +1,8 @@
import React from 'react';
import { useLingui } from '@lingui/react';
-import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor';
import { Trans, t } from '@lingui/macro';
+import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor';
import makeStyles from '@mui/styles/makeStyles';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
diff --git a/src/views/Edit/Sources/index.js b/src/views/Edit/Sources/index.js
index cf56731..e8293a3 100644
--- a/src/views/Edit/Sources/index.js
+++ b/src/views/Edit/Sources/index.js
@@ -11,6 +11,7 @@ import * as VideoLoop from './VideoLoop';
import * as VirtualAudio from './VirtualAudio';
import * as VirtualVideo from './VirtualVideo';
import * as X11grab from './X11grab';
+import * as Channel from './Channel';
class Registry {
constructor() {
@@ -54,5 +55,6 @@ registry.Register(VideoLoop);
registry.Register(AudioLoop);
registry.Register(SDP);
registry.Register(X11grab);
+registry.Register(Channel);
export default registry;
diff --git a/src/views/Edit/index.js b/src/views/Edit/index.js
index 2ab3773..0f39df5 100644
--- a/src/views/Edit/index.js
+++ b/src/views/Edit/index.js
@@ -112,6 +112,7 @@ export default function Edit({ restreamer = null }) {
});
const skills = await restreamer.Skills();
+ skills.sources['channel'] = skills.sources['channel'].filter((channel) => channel.id !== _channelid);
setSkills(skills);
const config = await restreamer.ConfigActive();
@@ -208,6 +209,7 @@ export default function Edit({ restreamer = null }) {
await restreamer.RefreshSkills();
const skills = await restreamer.Skills();
+ skills.sources['channel'] = skills.sources['channel'].filter((channel) => channel.id !== _channelid);
setSkills(skills);
};