handling with ease

Wrote api to manage events easier and easier to parse. Added dummy when releasing devices.
This commit is contained in:
Extremesecrecy
2025-07-27 11:58:33 -07:00
parent 42c03a9c19
commit 3576f1c7cf
2 changed files with 136 additions and 80 deletions
+15
View File
@@ -55,6 +55,21 @@ export default class JackServerSettings {
bufferSize = 64; bufferSize = 64;
numberOfBuffers = 3; numberOfBuffers = 3;
/**
* Configure this instance to use the dummy audio device. This mirrors the
* behaviour of the backend JackServerSettings::UseDummyAudioDevice method
* and is used when temporarily releasing ALSA devices.
* Needed when changing devices and when testing new settings with apply button.
*/
useDummyAudioDevice() {
if (this.sampleRate === 0) {
this.sampleRate = 48000;
}
this.valid = true;
this.alsaInputDevice = "__DUMMY_AUDIO__dummy:channels_2";
this.alsaOutputDevice = "__DUMMY_AUDIO__dummy:channels_2";
}
getSummaryText() { getSummaryText() {
if (!this.valid || !this.alsaInputDevice || !this.alsaOutputDevice) { if (!this.valid || !this.alsaInputDevice || !this.alsaOutputDevice) {
return "Not selected"; return "Not selected";
+121 -80
View File
@@ -385,6 +385,56 @@ const JackServerSettingsDialog = withStyles(
} }
} }
// ---------------------- New API helpers ----------------------
/** Persist the current settings to permanent storage. */
saveSettings(settings?: JackServerSettings) {
const s = (settings ?? this.state.jackServerSettings).clone();
this.model.setJackServerSettings(s);
}
/**
* Save the current settings temporarily so they can be restored if the
* dialog is cancelled.
*/
saveSettingsTemporary(settings?: JackServerSettings) {
this.originalJackServerSettings = (settings ?? this.state.jackServerSettings).clone();
}
/** Apply the provided settings to the audio system. */
applySettings(settings?: JackServerSettings) {
const s = (settings ?? this.state.jackServerSettings).clone();
s.valid = true;
this.model.applyJackServerSettings(s);
}
/**
* Revert the dialog state to the persisted settings. The reverted
* settings are applied immediately as well.
*/
revertSettings() {
this.model.getJackServerSettings()
.then((s) => {
const applied = this.applyAlsaDevices(s.clone(), this.state.alsaDevices);
this.setState({
jackServerSettings: applied,
latencyText: getLatencyText(applied),
okEnabled: isOkEnabled(applied, this.state.alsaDevices)
});
this.applySettings(s);
})
.catch(() => { });
}
/**
* Release currently used ALSA devices by switching to the dummy audio
* driver. This allows testing alternative devices without conflicts.
*/
releaseDevices() {
const dummy = new JackServerSettings();
dummy.useDummyAudioDevice();
this.model.applyJackServerSettings(dummy);
}
applyAlsaDevices(jackServerSettings: JackServerSettings, alsaDevices?: AlsaDeviceInfo[]) { applyAlsaDevices(jackServerSettings: JackServerSettings, alsaDevices?: AlsaDeviceInfo[]) {
let result = jackServerSettings.clone(); let result = jackServerSettings.clone();
if (!alsaDevices || alsaDevices.length === 0) { if (!alsaDevices || alsaDevices.length === 0) {
@@ -449,7 +499,7 @@ const JackServerSettingsDialog = withStyles(
} }
componentDidUpdate(oldProps: JackServerSettingsDialogProps) { componentDidUpdate(oldProps: JackServerSettingsDialogProps) {
if ((this.props.open && !oldProps.open) && this.mounted) { if ((this.props.open && !oldProps.open) && this.mounted) {
this.originalJackServerSettings = this.props.jackServerSettings.clone(); this.saveSettingsTemporary(this.props.jackServerSettings);
// When opening, preserve the current settings until ALSA device // When opening, preserve the current settings until ALSA device
// information is loaded. If we don't have device info yet, just // information is loaded. If we don't have device info yet, just
// clone the provided settings without applying device defaults. // clone the provided settings without applying device defaults.
@@ -478,8 +528,9 @@ const JackServerSettingsDialog = withStyles(
this.stopStatusTimer(); this.stopStatusTimer();
if (this.originalJackServerSettings) { if (this.originalJackServerSettings) {
// Revert any unapplied changes when the dialog is unmounted // Revert any unapplied changes when the dialog is unmounted
this.model.applyJackServerSettings(this.originalJackServerSettings); this.applySettings(this.originalJackServerSettings);
this.model.setJackServerSettings(this.originalJackServerSettings); // Persist the original settings so future dialogs show them
this.saveSettings(this.originalJackServerSettings);
this.originalJackServerSettings = undefined; this.originalJackServerSettings = undefined;
} }
@@ -551,85 +602,76 @@ const JackServerSettingsDialog = withStyles(
} }
handleApply() { handleApply() {
if (this.state.okEnabled) if (this.state.okEnabled) {
{ this.applySettings();
let s = this.state.jackServerSettings.clone();
// Apply immediately so the status display can confirm
// whether the selected devices are working.
s.valid = true;
this.model.applyJackServerSettings(s);
this.startStatusTimer(); this.startStatusTimer();
} }
}; };
handleOk() {
applyAndPersistSettings(s: JackServerSettings) { if (!this.state.okEnabled) return;
// Accept the new settings so handleClose doesn't revert them if (this.state.jackServerSettings.alsaInputDevice !== this.state.jackServerSettings.alsaOutputDevice
this.originalJackServerSettings = undefined; && !this.suppressDeviceWarning) {
// Apply the new settings immediately and persist them. this.setState({ showDeviceWarning: true });
this.model.applyJackServerSettings(s); return;
this.model.setJackServerSettings(s);
this.startStatusTimer();
if (this.props.onApply) {
this.props.onApply(s);
} }
// apply and persist the selected settings
this.releaseDevices();
this.applySettings();
this.saveSettings();
this.originalJackServerSettings = undefined;
if (this.props.onApply) {
this.props.onApply(this.state.jackServerSettings.clone());
}
};
handleWarningProceed() {
if (this.state.dontShowWarningAgain) {
localStorage.setItem("suppressSeparateDeviceWarning", "1");
this.suppressDeviceWarning = true;
}
this.setState({ showDeviceWarning: false, dontShowWarningAgain: false }, () => {
this.releaseDevices();
this.applySettings();
this.saveSettings();
this.originalJackServerSettings = undefined;
if (this.props.onApply) {
this.props.onApply(this.state.jackServerSettings.clone());
}
});
} }
handleOk() {
if (!this.state.okEnabled) return; handleWarningCancel() {
if (this.state.jackServerSettings.alsaInputDevice !== this.state.jackServerSettings.alsaOutputDevice this.setState({ showDeviceWarning: false, dontShowWarningAgain: false });
&& !this.suppressDeviceWarning) { }
this.setState({ showDeviceWarning: true });
return; 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(); let s = this.state.jackServerSettings.clone();
s.valid = true; s.alsaInputDevice = d;
this.applyAndPersistSettings(s); s.valid = false;
let settings = this.applyAlsaDevices(s, this.state.alsaDevices);
this.setState({
jackServerSettings: settings,
latencyText: getLatencyText(settings),
okEnabled: isOkEnabled(settings, this.state.alsaDevices)
});
}
handleOutputDeviceChanged(e: any) {
}; const d = e.target.value as string;
let s = this.state.jackServerSettings.clone();
handleWarningProceed() { s.alsaOutputDevice = d;
if (this.state.dontShowWarningAgain) { s.valid = false;
localStorage.setItem("suppressSeparateDeviceWarning", "1"); let settings = this.applyAlsaDevices(s, this.state.alsaDevices);
this.suppressDeviceWarning = true; this.setState({
} jackServerSettings: settings,
this.setState({ showDeviceWarning: false, dontShowWarningAgain: false }, () => { latencyText: getLatencyText(settings),
let s = this.state.jackServerSettings.clone(); okEnabled: isOkEnabled(settings, this.state.alsaDevices)
s.valid = true; });
this.applyAndPersistSettings(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;
s.valid = false;
let settings = this.applyAlsaDevices(s, this.state.alsaDevices);
this.setState({
jackServerSettings: settings,
latencyText: getLatencyText(settings),
okEnabled: isOkEnabled(settings, this.state.alsaDevices)
});
}
handleOutputDeviceChanged(e: any) {
const d = e.target.value as string;
let s = this.state.jackServerSettings.clone();
s.alsaOutputDevice = d;
s.valid = false;
let settings = this.applyAlsaDevices(s, this.state.alsaDevices);
this.setState({
jackServerSettings: settings,
latencyText: getLatencyText(settings),
okEnabled: isOkEnabled(settings, this.state.alsaDevices)
});
}
render() { render() {
const classes = withStyles.getClasses(this.props); const classes = withStyles.getClasses(this.props);
@@ -637,12 +679,11 @@ const JackServerSettingsDialog = withStyles(
const { onClose, open } = this.props; const { onClose, open } = this.props;
const handleClose = () => { const handleClose = () => {
this.releaseDevices();
if (this.originalJackServerSettings) { if (this.originalJackServerSettings) {
// Revert the temporary settings. The dialog is being closed // Revert any applied settings
// without OK, so restore the previous configuration. this.applySettings(this.originalJackServerSettings);
this.model.applyJackServerSettings(this.originalJackServerSettings); this.saveSettings(this.originalJackServerSettings);
this.model.setJackServerSettings(this.originalJackServerSettings);
// Prevent componentWillUnmount from reverting again.
this.originalJackServerSettings = undefined; this.originalJackServerSettings = undefined;
} }
onClose(); onClose();