diff --git a/src/views/Edit/Profile.js b/src/views/Edit/Profile.js index 2907c44..b7b3e57 100644 --- a/src/views/Edit/Profile.js +++ b/src/views/Edit/Profile.js @@ -80,6 +80,7 @@ export default function Profile({ const load = async () => { // Add pseudo sources skills.sources.noaudio = []; + skills.sources.sdp = []; let audio = $sources.audio; @@ -145,6 +146,7 @@ export default function Profile({ // Add pseudo sources skills.sources.noaudio = []; + skills.sources.sdp = []; let hasAudio = false; for (let i = 0; i < res.streams.length; i++) { diff --git a/src/views/Edit/Sources/SDP.js b/src/views/Edit/Sources/SDP.js new file mode 100644 index 0000000..e0934e4 --- /dev/null +++ b/src/views/Edit/Sources/SDP.js @@ -0,0 +1,208 @@ +import React from 'react'; + +import { Trans } from '@lingui/macro'; +import makeStyles from '@mui/styles/makeStyles'; +import Backdrop from '@mui/material/Backdrop'; +import Button from '@mui/material/Button'; +import CircularProgress from '@mui/material/CircularProgress'; +import Grid from '@mui/material/Grid'; +import Icon from '@mui/icons-material/Cached'; +import TextField from '@mui/material/TextField'; +import Typography from '@mui/material/Typography'; + +import Dialog from '../../../misc/modals/Dialog'; +import Filesize from '../../../misc/Filesize'; +import FormInlineButton from '../../../misc/FormInlineButton'; +import UploadButton from '../../../misc/UploadButton'; + +const imageTypes = [ + { mimetype: 'application/sdp', extension: '*.sdp', maxSize: 2 * 1024 * 1024 }, + { mimetype: '', extension: '*.sdp', maxSize: 2 * 1024 * 1024 } +]; + +const useStyles = makeStyles((theme) => ({ + gridContainer: { + marginTop: '0.5em', + }, +})); + +const initSettings = (initialSettings) => { + if (!initialSettings) { + initialSettings = {}; + } + + const settings = { + address: '', + mimetype: '', + ...initialSettings, + }; + + return settings; +}; + +const createInputs = (settings) => { + const address = '{diskfs}' + settings.address; + const input = { + address: address, + options: [], + }; + + + input.options.push('-protocol_whitelist', 'file,udp,rtp'); + input.options.push('-buffer_size', '671088640'); + input.options.push('-thread_queue_size', '4096'); + + return [input]; +}; + +function Source(props) { + const classes = useStyles(); + const settings = initSettings(props.settings); + const [$saving, setSaving] = React.useState(false); + const [$error, setError] = React.useState({ + open: false, + title: '', + message: '', + }); + + const handleFileUpload = async (data, extension, mimetype) => { + const path = await props.onStore('input.sdp', data); + + props.onChange({ + ...settings, + address: path, + mimetype: mimetype, + }); + + setSaving(false); + }; + + const handleUploadStart = () => { + setSaving(true); + }; + + const handleUploadError = (title) => (err) => { + let message = null; + + switch (err.type) { + case 'nofiles': + message = Please select a file to upload.; + break; + case 'mimetype': + message = ( + + The selected file type ({err.actual}) is not allowed. Allowed file types are {err.allowed.join(', ')} + + ); + break; + case 'size': + message = ( + + The selected file is too big ( + ). Only are allowed. + + ); + break; + case 'read': + message = There was an error during upload: {err.message}; + break; + default: + message = Unknown upload error; + } + + setSaving(false); + + showUploadError(title, message); + }; + + const showUploadError = (title, message) => { + setError({ + ...$error, + open: true, + title: title, + message: message, + }); + }; + + const hideUploadError = () => { + setError({ + ...$error, + open: false, + }); + }; + + const handleProbe = () => { + props.onProbe(settings, createInputs(settings)); + }; + + return ( + + + + + Upload an image or video file ({imageTypes.map((t) => t.mimetype).join(', ')}) in order to loop it. + + + + File path} value={settings.address} readOnly /> + + + Upload} + acceptTypes={imageTypes} + onStart={handleUploadStart} + onError={handleUploadError(Uploading the file failed)} + onUpload={handleFileUpload} + /> + + + + Probe + + + + + + + + OK + + } + > + {$error.message} + + + ); +} + +Source.defaultProps = { + knownDevices: [], + settings: {}, + onChange: function (settings) {}, + onProbe: function (settings, inputs) {}, + onRefresh: function () {}, + onStore: function (name, data) { + return ''; + }, +}; + +function SourceIcon(props) { + return ; +} + +const id = 'sdp'; +const name = SDP; +const capabilities = ['video', 'audio']; +const ffversion = '^4.1.0 || ^5.0.0 || ^6.1.0'; + +const func = { + initSettings, + createInputs, +}; + +export { id, name, capabilities, ffversion, SourceIcon as icon, Source as component, func }; diff --git a/src/views/Edit/Sources/index.js b/src/views/Edit/Sources/index.js index 65479bd..8b64adf 100644 --- a/src/views/Edit/Sources/index.js +++ b/src/views/Edit/Sources/index.js @@ -9,6 +9,7 @@ import * as VideoLoop from './VideoLoop'; import * as AudioLoop from './AudioLoop'; import * as VirtualAudio from './VirtualAudio'; import * as VirtualVideo from './VirtualVideo'; +import * as SDP from './SDP'; class Registry { constructor() { @@ -50,5 +51,6 @@ registry.Register(NoAudio); registry.Register(VideoAudio); registry.Register(VideoLoop); registry.Register(AudioLoop); +registry.Register(SDP); export default registry;