diff --git a/docs/BuildPrerequisites.md b/docs/BuildPrerequisites.md index cbc120e..6885730 100644 --- a/docs/BuildPrerequisites.md +++ b/docs/BuildPrerequisites.md @@ -27,7 +27,7 @@ Run the following commands to install dependent libraries required by the PiPeda authbind libavahi-client-dev libnm-dev libicu-dev \ libsdbus-c++-dev libzip-dev google-perftools \ libgoogle-perftools-dev \ - libpipewire-0.3-dev libwebsocketpp-dev libsdl2-dev + libpipewire-0.3-dev libwebsocketpp-dev After installing these packages, run the dependency checker to verify that everything required is present: diff --git a/scripts/check_deps.sh b/scripts/check_deps.sh index 85f249f..48a171e 100644 --- a/scripts/check_deps.sh +++ b/scripts/check_deps.sh @@ -8,7 +8,7 @@ packages=(\ authbind libavahi-client-dev libnm-dev libicu-dev \ libsdbus-c++-dev libzip-dev google-perftools \ libgoogle-perftools-dev libpipewire-0.3-dev \ - libwebsocketpp-dev libsdl2-dev + libwebsocketpp-dev ) missing=() diff --git a/src/JackServerSettings.hpp b/src/JackServerSettings.hpp index 285af30..a495f44 100644 --- a/src/JackServerSettings.hpp +++ b/src/JackServerSettings.hpp @@ -80,10 +80,17 @@ namespace pipedal bool IsValid() const { return valid_; } - // JackServerSettings(uint64_t sampleRate, uint32_t bufferSize, uint32_t numberOfBuffers) + // Legacy constructor used by tests prior to the addition of + // separate input and output ALSA devices. + // JackServerSettings(const std::string &device, + // uint64_t sampleRate, + // uint32_t bufferSize, + // uint32_t numberOfBuffers) // { // this->valid_ = true; // this->rebootRequired_ = true; + // this->alsaInputDevice_ = device; + // this->alsaOutputDevice_ = device; // this->sampleRate_ = sampleRate; // this->bufferSize_ = bufferSize; // this->numberOfBuffers_ = numberOfBuffers; diff --git a/src/PiLatencyMain.cpp b/src/PiLatencyMain.cpp index 71ed03f..e1616ac 100644 --- a/src/PiLatencyMain.cpp +++ b/src/PiLatencyMain.cpp @@ -95,7 +95,7 @@ void PrintHelp() pp << Indent(0) << "Examples\n\n"; pp << Indent(2) << "pipedal_latency_test --list\n\n"; - pp << Indent(2) << "pipedal_latency_test hw:M2\n"; + pp << Indent(2) << "pipedal_latency_test hw:M2 hw:M2\n"; pp << Indent(2) << "pipedal_latency_test hw:M2 hw:Device2\n\n"; } diff --git a/src/PiPedalAlsa.cpp b/src/PiPedalAlsa.cpp index 89eac9d..50d1a16 100644 --- a/src/PiPedalAlsa.cpp +++ b/src/PiPedalAlsa.cpp @@ -22,6 +22,7 @@ #include "alsa/asoundlib.h" #include "Lv2Log.hpp" #include +#include using namespace pipedal; @@ -191,12 +192,24 @@ std::vector PiPedalAlsaDevices::GetAlsaDevices() } snd_config_update_free_global(); + auto isFiltered = [](const AlsaDeviceInfo &d) { + std::string name = d.name_ + " " + d.longName_; + std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c){return std::tolower(c);}); + return name.find("hdmi") != std::string::npos || name.find("bcm2835") != std::string::npos; + }; + + std::vector filtered; + for (auto &d : result) + { + if (!isFiltered(d)) filtered.push_back(d); + } + Lv2Log::debug("GetAlsaDevices --"); - for (auto &device : result) + for (auto &device : filtered) { Lv2Log::debug(SS(" " << device.name_ << " " << device.longName_ << " " << device.cardId_)); } - return result; + return filtered; } static void AddMidiCardDevicesToList(snd_ctl_t *ctl, int card, int device, AlsaMidiDeviceInfo::Direction direction, std::vector *result) diff --git a/src/Storage.cpp b/src/Storage.cpp index f8bb149..7276a26 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -1573,14 +1573,6 @@ std::map Storage::GetFavorites() const { json_reader reader(f); reader.read(&result); - if (!result.GetLegacyAlsaDevice().empty() && - result.GetAlsaInputDevice().empty() && - result.GetAlsaOutputDevice().empty()) - { - result.SetAlsaInputDevice(result.GetLegacyAlsaDevice()); - result.SetAlsaOutputDevice(result.GetLegacyAlsaDevice()); - result.SetLegacyAlsaDevice(""); - } } return result; } @@ -1606,6 +1598,14 @@ pipedal::JackServerSettings Storage::GetJackServerSettings() { json_reader reader(f); reader.read(&result); + if (!result.GetLegacyAlsaDevice().empty() && + result.GetAlsaInputDevice().empty() && + result.GetAlsaOutputDevice().empty()) + { + result.SetAlsaInputDevice(result.GetLegacyAlsaDevice()); + result.SetAlsaOutputDevice(result.GetLegacyAlsaDevice()); + result.SetLegacyAlsaDevice(""); + } } #if JACK_HOST result.Initialize(); diff --git a/vite/src/pipedal/JackServerSettings.tsx b/vite/src/pipedal/JackServerSettings.tsx index 1263ad8..dd83675 100644 --- a/vite/src/pipedal/JackServerSettings.tsx +++ b/vite/src/pipedal/JackServerSettings.tsx @@ -56,13 +56,22 @@ export default class JackServerSettings { numberOfBuffers = 3; getSummaryText() { - if (this.valid) { - let inDev = this.alsaInputDevice.startsWith("hw:") ? this.alsaInputDevice .substring(3) : this.alsaInputDevice; - let outDev = this.alsaOutputDevice.startsWith("hw:") ? this.alsaOutputDevice.substring(3) : this.alsaOutputDevice; - return "In: "+inDev+" Out: "+outDev+" — Rate "+this.sampleRate+", "+this.bufferSize+"×"+this.numberOfBuffers; + if (!this.valid || !this.alsaInputDevice || !this.alsaOutputDevice) { + return "Not selected"; + } + + let inDev = this.alsaInputDevice.startsWith("hw:") + ? this.alsaInputDevice.substring(3) + : this.alsaInputDevice; + let outDev = this.alsaOutputDevice.startsWith("hw:") + ? this.alsaOutputDevice.substring(3) + : this.alsaOutputDevice; + + if (inDev === outDev) { + return inDev; } else { - return "Not configured"; + return inDev+" → "+outDev; } } diff --git a/vite/src/pipedal/JackServerSettingsDialog.tsx b/vite/src/pipedal/JackServerSettingsDialog.tsx index 18c19ff..ee8093c 100644 --- a/vite/src/pipedal/JackServerSettingsDialog.tsx +++ b/vite/src/pipedal/JackServerSettingsDialog.tsx @@ -22,6 +22,7 @@ import { Theme } from '@mui/material/styles'; +import React from 'react'; import WithStyles from './WithStyles'; import {createStyles} from './WithStyles'; @@ -44,10 +45,18 @@ import IconButtonEx from './IconButtonEx'; import RefreshIcon from '@mui/icons-material/Refresh'; import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; +import JackHostStatus from './JackHostStatus'; import AlsaDeviceInfo from './AlsaDeviceInfo'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; +function filterDevices(devices: AlsaDeviceInfo[]): AlsaDeviceInfo[] { + return devices.filter(d => { + const name = (d.name + ' ' + d.longName).toLowerCase(); + return !(name.includes('hdmi') || name.includes('bcm2835')); + }); +} + function sortDevices(devices: AlsaDeviceInfo[]): AlsaDeviceInfo[] { function category(d: AlsaDeviceInfo): number { if (d.supportsCapture && d.supportsPlayback) return 0; @@ -73,14 +82,18 @@ interface BufferSetting { numberOfBuffers: number; }; -const INVALID_DEVICE_ID = "_invalid_"; +// empty string used when no valid device is selected - the default. +const INVALID_DEVICE_ID = ""; interface JackServerSettingsDialogState { latencyText: string; jackServerSettings: JackServerSettings; alsaDevices?: AlsaDeviceInfo[]; okEnabled: boolean; - useSameDevice: boolean; fullScreen: boolean; + compactWidth: boolean; + jackStatus?: JackHostStatus; + showDeviceWarning: boolean; + dontShowWarningAgain: boolean; } const styles = (theme: Theme) => @@ -92,6 +105,15 @@ const styles = (theme: Theme) => selectEmpty: { marginTop: theme.spacing(2), }, + inputLabel: { + backgroundColor: theme.palette.background.paper, + paddingLeft: 4, + paddingRight: 4 + }, + cpuStatusColor: { + color: theme.palette.text.secondary, + opacity: 0.7 + } }); export interface JackServerSettingsDialogProps extends WithStyles { open: boolean; @@ -101,13 +123,15 @@ export interface JackServerSettingsDialogProps extends WithStyles } function getLatencyText(settings?: JackServerSettings ): string { - if (!settings) - { + if (!settings) { return "\u00A0"; } - if (!settings.valid) return "\u00A0"; - let ms = settings.bufferSize * settings.numberOfBuffers / settings.sampleRate * 1000; + if (!settings.sampleRate || !settings.bufferSize || !settings.numberOfBuffers) { + return "\u00A0"; + } + + let ms = (settings.bufferSize * settings.numberOfBuffers) / settings.sampleRate * 1000; return ms.toFixed(1) + "ms"; } @@ -213,33 +237,57 @@ function getBestBuffers( return {bufferSize: bufferSize, numberOfBuffers:numberOfBuffers}; } } - // otherwise select a sensible starting value. + // otherwise select a sensible starting value. - // favored default: 64x3. - if (64*3 >= minSize && 64*3 <= maxSize) - { - return { bufferSize: 64, numberOfBuffers: 3}; + // Build candidate sizes with 32 first if present. + let validBufferSizes = getValidBufferSizesMultiple(inDevice, outDevice); + validBufferSizes.sort((a,b)=>a-b); + if (validBufferSizes.indexOf(32) !== -1) { + validBufferSizes = [32, ...validBufferSizes.filter(v => v !== 32)]; } - // if that isn't possible then minBufferSize/2 x 4. - bufferSize = minSize/2; + + function tryPick(count: number): BufferSetting | undefined { + for (let bs of validBufferSizes) { + const counts = getValidBufferCountsMultiple(bs, inDevice, outDevice); + if (counts.indexOf(count) !== -1) { + if (bs * count >= minSize && bs * count <= maxSize) { + return { bufferSize: bs, numberOfBuffers: count }; + } + } + } + return undefined; + } + + let result = tryPick(4); + if (!result) result = tryPick(3); + if (!result) result = tryPick(2); + if (result) return result; + + // Fallback to previous behaviour. + if (64*3 >= minSize && 64*3 <= maxSize) { + return { bufferSize: 64, numberOfBuffers: 3 }; + } + bufferSize = minSize/2; numberOfBuffers = 4; - // otherwise, minBufferSize/2 x 2. - if (bufferSize*numberOfBuffers > maxSize) - { + if (bufferSize * numberOfBuffers > maxSize) { numberOfBuffers = 2; } - return { bufferSize: bufferSize, numberOfBuffers: numberOfBuffers}; + return { bufferSize: bufferSize, numberOfBuffers: numberOfBuffers }; }; function isOkEnabled(jackServerSettings: JackServerSettings, alsaDevices?: AlsaDeviceInfo[]) { - if (!jackServerSettings.valid) return false; if (!alsaDevices) return false; - const inDevice = alsaDevices.find(d => d.id === jackServerSettings.alsaInputDevice && d.supportsCapture); + if (!jackServerSettings.alsaInputDevice || !jackServerSettings.alsaOutputDevice) return false; + + const inDevice = alsaDevices.find(d => d.id === jackServerSettings.alsaInputDevice && d.supportsCapture); const outDevice = alsaDevices.find(d => d.id === jackServerSettings.alsaOutputDevice && d.supportsPlayback); if (!inDevice || !outDevice) return false; + const sampleRates = intersectArrays(inDevice.sampleRates, outDevice.sampleRates); + if (sampleRates.indexOf(jackServerSettings.sampleRate) === -1) return false; + const deviceBufferSize = jackServerSettings.bufferSize * jackServerSettings.numberOfBuffers; const minSize = Math.max(inDevice.minBufferSize, outDevice.minBufferSize); const maxSize = Math.min(inDevice.maxBufferSize, outDevice.maxBufferSize); @@ -248,9 +296,6 @@ function isOkEnabled(jackServerSettings: JackServerSettings, alsaDevices?: AlsaD const validBufferCounts = getValidBufferCountsMultiple(jackServerSettings.bufferSize, inDevice, outDevice); if (validBufferCounts.indexOf(jackServerSettings.numberOfBuffers) === -1) return false; - const sampleRates = intersectArrays(inDevice.sampleRates, outDevice.sampleRates); - if (sampleRates.indexOf(jackServerSettings.sampleRate) === -1) return false; - return true; } @@ -265,18 +310,24 @@ const JackServerSettingsDialog = withStyles( this.model = PiPedalModelFactory.getInstance(); - const sameDevice = props.jackServerSettings.alsaInputDevice === props.jackServerSettings.alsaOutputDevice; - this.state = { - latencyText: getLatencyText(props.jackServerSettings), - jackServerSettings: props.jackServerSettings.clone(), // invalid, but not nullish - alsaDevices: undefined, - okEnabled: false, - useSameDevice: sameDevice, - fullScreen: this.getFullScreen() - }; + this.suppressDeviceWarning = localStorage.getItem("suppressSeparateDeviceWarning") === "1"; + this.state = { + latencyText: getLatencyText(props.jackServerSettings), + jackServerSettings: props.jackServerSettings.clone(), // invalid, but not nullish + alsaDevices: undefined, + okEnabled: false, + fullScreen: this.getFullScreen(), + compactWidth: document.documentElement.clientWidth < 600, + jackStatus: undefined, + showDeviceWarning: false, + dontShowWarningAgain: false + }; } mounted: boolean = false; + statusTimer?: number = undefined; + suppressDeviceWarning: boolean; + getFullScreen() { return document.documentElement.clientWidth < 420 || document.documentElement.clientHeight < 700; @@ -285,8 +336,9 @@ const JackServerSettingsDialog = withStyles( onWindowSizeChanged(width: number, height: number): void { super.onWindowSizeChanged(width, height); const fullScreen = this.getFullScreen(); - if (fullScreen !== this.state.fullScreen) { - this.setState({ fullScreen }); + const compactWidth = width < 600; + if (fullScreen !== this.state.fullScreen || compactWidth !== this.state.compactWidth) { + this.setState({ fullScreen, compactWidth }); } } @@ -295,15 +347,16 @@ const JackServerSettingsDialog = withStyles( .then((devices) => { if (this.mounted) { if (this.props.open) { - let settings = this.applyAlsaDevices(this.state.jackServerSettings, devices); + let f = filterDevices(devices); + let settings = this.applyAlsaDevices(this.state.jackServerSettings, f); this.setState({ - alsaDevices: devices, + alsaDevices: f, jackServerSettings: settings, latencyText: getLatencyText(settings), - okEnabled: isOkEnabled(settings,devices) + okEnabled: isOkEnabled(settings, f) }); } else { - this.setState({ alsaDevices: devices }); + this.setState({ alsaDevices: filterDevices(devices) }); } } }) @@ -312,7 +365,28 @@ const JackServerSettingsDialog = withStyles( }); } - applyAlsaDevices(jackServerSettings: JackServerSettings, alsaDevices?: AlsaDeviceInfo[], useSameDevice?: boolean) { + tickStatus() { + this.model.getJackStatus() + .then(status => { + if (this.mounted) { + this.setState({ jackStatus: status }); + } + }) + .catch(() => { }); + } + startStatusTimer() { + if (this.statusTimer) return; + this.tickStatus(); + this.statusTimer = window.setInterval(() => this.tickStatus(), 1000); + } + stopStatusTimer() { + if (this.statusTimer) { + clearInterval(this.statusTimer); + this.statusTimer = undefined; + } + } + + applyAlsaDevices(jackServerSettings: JackServerSettings, alsaDevices?: AlsaDeviceInfo[]) { let result = jackServerSettings.clone(); if (!alsaDevices || alsaDevices.length === 0) { result.valid = false; @@ -321,47 +395,33 @@ const JackServerSettingsDialog = withStyles( return result; } - let inDevice = alsaDevices.find(d => d.id === result.alsaInputDevice && d.supportsCapture); - let outDevice = alsaDevices.find(d => d.id === result.alsaOutputDevice && d.supportsPlayback); + let devices = filterDevices(alsaDevices); + let inDevice = devices.find(d => d.id === result.alsaInputDevice && d.supportsCapture); + let outDevice = devices.find(d => d.id === result.alsaOutputDevice && d.supportsPlayback); - const sameDevice = useSameDevice !== undefined ? useSameDevice : this.state.useSameDevice; - if (sameDevice) { - if (!inDevice || !inDevice.supportsPlayback) { - const both = alsaDevices.find(d => d.supportsCapture && d.supportsPlayback); - if (both) { - result.alsaInputDevice = both.id; - result.alsaOutputDevice = both.id; - inDevice = both; - outDevice = both; - } else { - result.valid = false; - result.alsaInputDevice = INVALID_DEVICE_ID; - result.alsaOutputDevice = INVALID_DEVICE_ID; - return result; - } - } else { - result.alsaOutputDevice = result.alsaInputDevice; - outDevice = inDevice; - } - } else { - if (!inDevice) { - result.valid = false; - result.alsaInputDevice = INVALID_DEVICE_ID; - } - if (!outDevice) { - result.valid = false; - result.alsaOutputDevice = INVALID_DEVICE_ID; - } - if (!inDevice || !outDevice) { - return result; + if (!inDevice || !outDevice) { + const capture = devices.filter(d => d.supportsCapture); + const playback = devices.filter(d => d.supportsPlayback); + if (capture.length === 1 && playback.length === 1) { + inDevice = capture[0]; + outDevice = playback[0]; + result.alsaInputDevice = inDevice.id; + result.alsaOutputDevice = outDevice.id; + } else if (capture.length === 1 && capture[0].supportsPlayback && playback.length === 0) { + inDevice = capture[0]; + outDevice = capture[0]; + result.alsaInputDevice = inDevice.id; + result.alsaOutputDevice = outDevice.id; } } if (!inDevice || !outDevice) { result.valid = false; + if (!inDevice) result.alsaInputDevice = INVALID_DEVICE_ID; + if (!outDevice) result.alsaOutputDevice = INVALID_DEVICE_ID; return result; } - + let sampleRates = intersectArrays(inDevice.sampleRates, outDevice.sampleRates); if (sampleRates.length !== 0 && sampleRates.indexOf(result.sampleRate) === -1) { let bestSr = sampleRates[0]; @@ -376,8 +436,6 @@ const JackServerSettingsDialog = withStyles( let bestBuffers = getBestBuffers(inDevice, outDevice, result.bufferSize, result.numberOfBuffers); result.bufferSize = bestBuffers.bufferSize; result.numberOfBuffers = bestBuffers.numberOfBuffers; - - result.valid = !!result.alsaInputDevice && !!result.alsaOutputDevice; return result; } @@ -386,27 +444,31 @@ const JackServerSettingsDialog = withStyles( this.mounted = true; if (this.props.open) { this.requestAlsaInfo(); + this.startStatusTimer(); } } componentDidUpdate(oldProps: JackServerSettingsDialogProps) { if ((this.props.open && !oldProps.open) && this.mounted) { let settings = this.applyAlsaDevices(this.props.jackServerSettings.clone(), this.state.alsaDevices); - this.setState({ + this.setState({ jackServerSettings: settings, latencyText: getLatencyText(settings), - okEnabled: isOkEnabled(settings,this.state.alsaDevices), - useSameDevice: settings.alsaInputDevice === settings.alsaOutputDevice + okEnabled: isOkEnabled(settings,this.state.alsaDevices) }); if (!this.state.alsaDevices) { this.requestAlsaInfo(); } + this.startStatusTimer(); + } else if (!this.props.open && oldProps.open) { + this.stopStatusTimer(); } } componentWillUnmount() { - super.componentWillUnmount(); + super.componentWillUnmount(); this.mounted = false; + this.stopStatusTimer(); } getSelectedDevice(deviceId: string): AlsaDeviceInfo | undefined { @@ -427,6 +489,7 @@ const JackServerSettingsDialog = withStyles( if (!inDev && !outDev) return; let settings = this.state.jackServerSettings.clone(); settings.sampleRate = rate; + settings.valid = false; this.setState({ jackServerSettings: settings, @@ -442,7 +505,8 @@ const JackServerSettingsDialog = withStyles( if (!inDev && !outDev) return; let settings = this.state.jackServerSettings.clone(); settings.bufferSize = size; - let bestBufferSetting = getBestBuffers(inDev,outDev,settings.bufferSize,settings.numberOfBuffers,true); + settings.valid = false; + let bestBufferSetting = getBestBuffers(inDev,outDev,settings.bufferSize,settings.numberOfBuffers,true); settings.bufferSize = bestBufferSetting.bufferSize; settings.numberOfBuffers = bestBufferSetting.numberOfBuffers; @@ -460,6 +524,7 @@ const JackServerSettingsDialog = withStyles( if (!inDev && !outDev) return; let settings = this.state.jackServerSettings.clone(); settings.numberOfBuffers = bufferCount; + settings.valid = false; this.setState({ jackServerSettings: settings, @@ -471,16 +536,46 @@ const JackServerSettingsDialog = withStyles( handleApply() { if (this.state.okEnabled) { - this.props.onApply(this.state.jackServerSettings.clone()); + let s = this.state.jackServerSettings.clone(); + s.valid = false; + this.model.setJackServerSettings(s); } }; + handleOk() { + if (!this.state.okEnabled) return; + if (this.state.jackServerSettings.alsaInputDevice !== this.state.jackServerSettings.alsaOutputDevice + && !this.suppressDeviceWarning) { + this.setState({ showDeviceWarning: true }); + return; + } + let s = this.state.jackServerSettings.clone(); + s.valid = true; + this.props.onApply(s); + }; + + handleWarningProceed() { + if (this.state.dontShowWarningAgain) { + localStorage.setItem("suppressSeparateDeviceWarning", "1"); + this.suppressDeviceWarning = true; + } + this.setState({ showDeviceWarning: false, dontShowWarningAgain: false }, () => { + let s = this.state.jackServerSettings.clone(); + s.valid = true; + this.props.onApply(s); + }); + } + handleWarningCancel() { + this.setState({ showDeviceWarning: false, dontShowWarningAgain: false }); + } + + handleWarningCheck(e: any, checked: boolean) { + this.setState({ dontShowWarningAgain: checked }); + } handleInputDeviceChanged(e: any) { const d = e.target.value as string; let s = this.state.jackServerSettings.clone(); s.alsaInputDevice = d; - if (this.state.useSameDevice) { - s.alsaOutputDevice = d; - } + s.valid = false; let settings = this.applyAlsaDevices(s, this.state.alsaDevices); this.setState({ jackServerSettings: settings, @@ -493,9 +588,7 @@ const JackServerSettingsDialog = withStyles( const d = e.target.value as string; let s = this.state.jackServerSettings.clone(); s.alsaOutputDevice = d; - if (this.state.useSameDevice) { - s.alsaInputDevice = d; - } + s.valid = false; let settings = this.applyAlsaDevices(s, this.state.alsaDevices); this.setState({ jackServerSettings: settings, @@ -503,28 +596,8 @@ const JackServerSettingsDialog = withStyles( okEnabled: isOkEnabled(settings, this.state.alsaDevices) }); } - handleUseSameDeviceChanged(e: any, checked: boolean) { - let s = this.state.jackServerSettings.clone(); - const useSame = checked; - if (!useSame) { - // clear selections when switching to separate devices - s.alsaInputDevice = INVALID_DEVICE_ID; - s.alsaOutputDevice = INVALID_DEVICE_ID; - s.valid = false; - } - - let settings = this.applyAlsaDevices(s, this.state.alsaDevices, useSame); - this.setState({ - useSameDevice: useSame, - jackServerSettings: settings, - latencyText: getLatencyText(settings), - okEnabled: isOkEnabled(settings, this.state.alsaDevices) - }, () => { - this.requestAlsaInfo(); - }); - } - render() { + render() { const classes = withStyles.getClasses(this.props); const { onClose, open } = this.props; @@ -537,14 +610,9 @@ const JackServerSettingsDialog = withStyles( let selectedInputDevice = this.getSelectedDevice(this.state.jackServerSettings.alsaInputDevice); let selectedOutputDevice = this.getSelectedDevice(this.state.jackServerSettings.alsaOutputDevice); - if (this.state.useSameDevice) { - selectedOutputDevice = selectedInputDevice; - } - const devicesSelected = this.state.useSameDevice ? - !!selectedInputDevice : - (selectedInputDevice && selectedOutputDevice); - + const devicesSelected = (selectedInputDevice && selectedOutputDevice); + let bufferSizes: number[] = devicesSelected ? getValidBufferSizesMultiple(selectedInputDevice, selectedOutputDevice) : []; let bufferCounts = devicesSelected ? @@ -553,67 +621,61 @@ const JackServerSettingsDialog = withStyles( let bufferCountDisabled = !devicesSelected; let sampleRates = devicesSelected && selectedInputDevice && selectedOutputDevice ? intersectArrays(selectedInputDevice.sampleRates, selectedOutputDevice.sampleRates) - : (this.state.useSameDevice && selectedInputDevice ? selectedInputDevice.sampleRates : []); + : []; let sampleRateOptions = sampleRates.length === 0 && this.state.jackServerSettings.sampleRate ? [this.state.jackServerSettings.sampleRate] : sampleRates; return ( + <> { - this.handleApply(); + this.handleOk(); }} - fullScreen={this.state.fullScreen} + fullScreen={this.state.fullScreen} > -
+
+
+
{/* Audio Input Device */} - - {this.state.useSameDevice ? "Device" : "Input Device"} - this.handleInputDeviceChanged(e)} + disabled={!this.state.alsaDevices || this.state.alsaDevices.length === 0} + style={{ width: 220 }} + > + {sortedDevices.filter(d => d.supportsCapture).map(d => ( + {d.name} )) || Loading...} - - + + {/* Audio Output Device */} - - Output Device - this.handleOutputDeviceChanged(e)} + disabled={!this.state.alsaDevices || this.state.alsaDevices.length === 0} + style={{ width: 220 }} + > {sortedDevices.filter(d => d.supportsPlayback).map(d => ( {d.name} )) || Loading...} - - this.requestAlsaInfo()} aria-label="refresh-audio-devices"> - - - this.handleUseSameDeviceChanged(e, c)} - /> - } - label="Use same device for input/output" - style={{ marginLeft: 16 }} - /> + +
+ this.requestAlsaInfo()} aria-label="refresh-audio-devices"> + + +
- - Sample rate + + Sample rate
- - Buffer size + + Buffer size - - Buffers + + Buffers