893 lines
23 KiB
TypeScript
893 lines
23 KiB
TypeScript
import { invoke } from '@tauri-apps/api/core';
|
|
import { DSP } from '../../types';
|
|
import {
|
|
Channel,
|
|
InputChannel,
|
|
OutputChannel,
|
|
Ratio,
|
|
DelayUnit,
|
|
DiscreteFrequency,
|
|
CrossoverFilter,
|
|
PEQFilter,
|
|
PEQBand,
|
|
InputSource,
|
|
DSP408Snapshot,
|
|
} from './types';
|
|
import { SetDsps, NotifyFn, updateDSP, setPollingPaused } from '../../dsp/dspShared';
|
|
import { registerPollStopper } from '../../dsp/pollRegistry';
|
|
|
|
type DSP408 = Extract<DSP, { type: 'DSP408' }>;
|
|
|
|
export type DSP408Api = ReturnType<typeof forDSP408>;
|
|
|
|
// --- selection + polling state, private to this module -------------------
|
|
|
|
const selectedIds = new Set<number>();
|
|
const pollIntervals = new Map<number, ReturnType<typeof setInterval>>();
|
|
|
|
const ACTIVE_POLL_INTERVAL_MS = 1000;
|
|
const BACKGROUND_POLL_INTERVAL_MS = 5000;
|
|
|
|
function pollIntervalFor(id: number): number {
|
|
return selectedIds.has(id) ? ACTIVE_POLL_INTERVAL_MS : BACKGROUND_POLL_INTERVAL_MS;
|
|
}
|
|
|
|
async function poll(dsp: DSP408, setDsps: SetDsps) {
|
|
try {
|
|
const [input_meters, output_meters] = await invoke<
|
|
[DSP408['input_meters'], DSP408['output_meters']]
|
|
>('get_meter_levels', { id: dsp.id });
|
|
|
|
updateDSP(setDsps, dsp.id, (d) =>
|
|
d.pollingPaused
|
|
? d
|
|
: ({
|
|
...d,
|
|
input_meters,
|
|
output_meters,
|
|
} as DSP408)
|
|
);
|
|
} catch {
|
|
// transient poll failures — don't notify
|
|
}
|
|
}
|
|
|
|
function startPolling(dsp: DSP408, setDsps: SetDsps) {
|
|
stopPolling(dsp.id);
|
|
|
|
void poll(dsp, setDsps);
|
|
|
|
const interval = setInterval(() => poll(dsp, setDsps), pollIntervalFor(dsp.id));
|
|
|
|
pollIntervals.set(dsp.id, interval);
|
|
}
|
|
|
|
function restartPollingIfActive(dsp: DSP408, setDsps: SetDsps) {
|
|
// only reschedule if we're actually polling this dsp right now
|
|
if (pollIntervals.has(dsp.id)) startPolling(dsp, setDsps);
|
|
}
|
|
|
|
export function stopPolling(id: number) {
|
|
const interval = pollIntervals.get(id);
|
|
if (interval) {
|
|
clearInterval(interval);
|
|
pollIntervals.delete(id);
|
|
}
|
|
}
|
|
|
|
registerPollStopper('DSP408', stopPolling);
|
|
|
|
// --- pause helper ----------------------------------------------------------
|
|
|
|
async function withPollingPaused<T>(
|
|
dsp: DSP408,
|
|
setDsps: SetDsps,
|
|
operation: () => Promise<T>
|
|
): Promise<T> {
|
|
setPollingPaused(setDsps, dsp.id, true);
|
|
try {
|
|
return await operation();
|
|
} finally {
|
|
setPollingPaused(setDsps, dsp.id, false);
|
|
}
|
|
}
|
|
|
|
// --- factory -----------------------------------------------------------
|
|
|
|
export async function create(params: {
|
|
name: string;
|
|
ip: string;
|
|
port: number;
|
|
deviceId: number;
|
|
demo: boolean;
|
|
}): Promise<DSP408> {
|
|
const id = await invoke<number>('create_dsp408', {
|
|
ip: params.ip,
|
|
port: params.port,
|
|
deviceId: params.deviceId,
|
|
demo: params.demo,
|
|
});
|
|
|
|
const snapshot = await invoke<DSP408Snapshot>('get_dsp_snapshot', { id });
|
|
|
|
return {
|
|
id,
|
|
type: 'DSP408',
|
|
name: params.name,
|
|
ip: params.ip,
|
|
port: params.port,
|
|
deviceId: params.deviceId,
|
|
mode: snapshot.mode,
|
|
status: 'disconnected',
|
|
pollingPaused: true,
|
|
state: snapshot.state,
|
|
input_meters: snapshot.input_meters,
|
|
output_meters: snapshot.output_meters,
|
|
};
|
|
}
|
|
|
|
export function forDSP408(dsp: DSP408, setDsps: SetDsps, notify: NotifyFn) {
|
|
async function updateDSPState(): Promise<void> {
|
|
try {
|
|
const state = await invoke<DSP408['state']>('get_dsp_state', { id: dsp.id });
|
|
updateDSP(setDsps, dsp.id, (d) => ({ ...d, state }) as DSP408);
|
|
} catch (err) {
|
|
notify(`Failed to fetch state: ${String(err)}`, 'error', dsp.name);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
return {
|
|
type: 'DSP408' as const,
|
|
|
|
setDSPState(updater: (dsp: DSP) => DSP) {
|
|
updateDSP(setDsps, dsp.id, updater);
|
|
},
|
|
|
|
setActive(active: boolean) {
|
|
if (active) {
|
|
selectedIds.add(dsp.id);
|
|
} else {
|
|
selectedIds.delete(dsp.id);
|
|
}
|
|
restartPollingIfActive(dsp, setDsps);
|
|
},
|
|
|
|
updateDSPState,
|
|
|
|
async connect() {
|
|
updateDSP(setDsps, dsp.id, (d) => ({ ...d, status: 'connecting' }));
|
|
try {
|
|
await invoke('connect_dsp408', { id: dsp.id });
|
|
|
|
await updateDSPState();
|
|
|
|
updateDSP(setDsps, dsp.id, (d) => ({ ...d, status: 'connected', pollingPaused: false }));
|
|
|
|
notify('Connected', 'success', dsp.name);
|
|
|
|
startPolling(dsp, setDsps);
|
|
} catch (err) {
|
|
updateDSP(setDsps, dsp.id, (d) => ({ ...d, status: 'disconnected' }));
|
|
notify(`Connection failed: ${String(err)}`, 'error', dsp.name);
|
|
}
|
|
},
|
|
|
|
async disconnect() {
|
|
stopPolling(dsp.id);
|
|
|
|
try {
|
|
await withPollingPaused(dsp, setDsps, async () => {
|
|
await invoke('disconnect_dsp408', { id: dsp.id });
|
|
});
|
|
|
|
updateDSP(setDsps, dsp.id, (d) => ({
|
|
...d,
|
|
status: 'disconnected',
|
|
pollingPaused: true,
|
|
}));
|
|
|
|
notify('Disconnected', 'success', dsp.name);
|
|
} catch (err) {
|
|
notify(`Disconnection failed: ${String(err)}`, 'error', dsp.name);
|
|
}
|
|
},
|
|
|
|
async recallPreset(presetIndex: number): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('recall_preset', {
|
|
id: dsp.id,
|
|
presetIndex,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to recall preset', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify(`Preset ${presetIndex} recalled`, 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Preset recall failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setCurrentPresetName(name: string): Promise<boolean> {
|
|
const paddedName = name.slice(0, 14).padEnd(14, ' ');
|
|
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_current_preset_name', {
|
|
id: dsp.id,
|
|
name: paddedName,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to rename preset', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Preset renamed', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Preset rename failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setGain(channel: Channel, gain: number): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_channel_gain', {
|
|
id: dsp.id,
|
|
channel,
|
|
db: gain,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to set gain', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Gain updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Gain update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setMute(channel: Channel, muted: boolean): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_mute', {
|
|
id: dsp.id,
|
|
channel,
|
|
muted,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change mute state', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify(muted ? 'Muted' : 'Unmuted', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Mute update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setInverse(channel: Channel, inverted: boolean): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_channel_inverse_gain', {
|
|
id: dsp.id,
|
|
channel,
|
|
inverted,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change phase', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify(inverted ? 'Phase inverted' : 'Phase normal', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Phase update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setGate(
|
|
inputChannel: InputChannel,
|
|
threshold: number,
|
|
attack: number,
|
|
hold: number,
|
|
release: number
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_gate', {
|
|
id: dsp.id,
|
|
channel: inputChannel,
|
|
threshold,
|
|
attack,
|
|
hold,
|
|
release,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change gate settings', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Gate updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Gate update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setCompressor(
|
|
outputChannel: OutputChannel,
|
|
ratio: Ratio,
|
|
attack: number,
|
|
release: number,
|
|
knee: number,
|
|
threshold: number
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_compressor', {
|
|
id: dsp.id,
|
|
channel: outputChannel,
|
|
ratio,
|
|
attack,
|
|
release,
|
|
knee,
|
|
threshold,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change compressor settings', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Compressor updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Compressor update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setLimiter(
|
|
outputChannel: OutputChannel,
|
|
threshold: number,
|
|
attack: number,
|
|
release: number
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_limiter', {
|
|
id: dsp.id,
|
|
channel: outputChannel,
|
|
threshold,
|
|
attack,
|
|
release,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change limiter settings', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Limiter updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Limiter update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setDelayUnit(unit: DelayUnit): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_delay_unit', {
|
|
id: dsp.id,
|
|
unit,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change delay unit', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Delay unit updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Delay unit update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setDelay(channel: Channel, delay: number): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_delay', {
|
|
id: dsp.id,
|
|
channel,
|
|
delay,
|
|
unit: dsp.state.current_config.delay_unit,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change channel delay', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Channel delay updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Channel delay update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setMatrixRouting(output: OutputChannel, inputs: InputChannel[]): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_matrix_routing', {
|
|
id: dsp.id,
|
|
output,
|
|
inputs,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change matrix routing', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Matrix routing updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Matrix routing update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setMatrixGain(
|
|
inputChannel: InputChannel,
|
|
outputChannel: OutputChannel,
|
|
gain: number
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_matrix_gain', {
|
|
id: dsp.id,
|
|
inputChannel,
|
|
outputChannel,
|
|
gain,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change matrix gain', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Matrix gain updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Matrix gain update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setGeqBand(
|
|
inputChannel: InputChannel,
|
|
frequencyBand: DiscreteFrequency,
|
|
gain: number
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_geq_band', {
|
|
id: dsp.id,
|
|
inputChannel,
|
|
frequencyBand,
|
|
gain,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change GEQ band', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('GEQ band updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`GEQ band update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setGeqBypass(inputChannel: InputChannel, bypass: boolean): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_geq_bypass', {
|
|
id: dsp.id,
|
|
inputChannel,
|
|
bypass,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to change GEQ bypass', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify(bypass ? 'GEQ bypass enabled' : 'GEQ bypass disabled', 'success', dsp.name);
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`GEQ bypass update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setLowPass(
|
|
channel: Channel,
|
|
freq: number,
|
|
filterType: CrossoverFilter
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_low_pass', {
|
|
id: dsp.id,
|
|
channel,
|
|
freq,
|
|
filterType,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to set low-pass filter', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('Low-pass filter updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Low-pass update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setHighPass(
|
|
channel: Channel,
|
|
freq: number,
|
|
filterType: CrossoverFilter
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_high_pass', {
|
|
id: dsp.id,
|
|
channel,
|
|
freq,
|
|
filterType,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to set high-pass filter', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('High-pass filter updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`High-pass update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setPeqBand(
|
|
channel: Channel,
|
|
band: PEQBand,
|
|
gainDb: number,
|
|
freqHz: number,
|
|
q: number,
|
|
filterType: PEQFilter,
|
|
bypass: boolean
|
|
): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_peq_band', {
|
|
id: dsp.id,
|
|
channel,
|
|
band,
|
|
gainDb,
|
|
freqHz,
|
|
q,
|
|
filterType,
|
|
bypass,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to set PEQ band', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify('PEQ band updated', 'success', dsp.name);
|
|
return true;
|
|
} catch (err) {
|
|
notify(`PEQ update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setPEQBypass(channel: Channel, bypass: boolean): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_bypass_peq', {
|
|
id: dsp.id,
|
|
channel,
|
|
bypass,
|
|
});
|
|
|
|
if (!success) {
|
|
notify('Failed to set PEQ bypass', 'error', dsp.name);
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
notify(bypass ? 'PEQ bypass enabled' : 'PEQ bypass disabled', 'success', dsp.name);
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`PEQ bypass failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async storeCurrentConfiguration(presetIndex: number, force: boolean): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('store_current_configuration', {
|
|
id: dsp.id,
|
|
presetIndex,
|
|
force,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Store configuration failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async factoryReset(force: boolean): Promise<boolean> {
|
|
if (!force) {
|
|
return false;
|
|
}
|
|
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('factory_reset', {
|
|
id: dsp.id,
|
|
force,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Factory reset failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async copyChannel(channel1: Channel, channel2: Channel): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('copy_channel', {
|
|
id: dsp.id,
|
|
channel1,
|
|
channel2,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Channel copy failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setInputSource(inputSource: InputSource): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_input_source', {
|
|
id: dsp.id,
|
|
inputSource,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Input source update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async linkChannels(source: Channel, destinations: Channel[]): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('link_channels', {
|
|
id: dsp.id,
|
|
source,
|
|
destinations,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Channel linking failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async setChannelName(channel: Channel, name: string): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('set_channel_name', {
|
|
id: dsp.id,
|
|
channel,
|
|
name,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Channel name update failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async unlockDevice(password: string): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('unlock_device', {
|
|
id: dsp.id,
|
|
password,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Unlock failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
|
|
async lockDevice(password: string): Promise<boolean> {
|
|
return withPollingPaused(dsp, setDsps, async () => {
|
|
try {
|
|
const success = await invoke<boolean>('lock_device', {
|
|
id: dsp.id,
|
|
password,
|
|
});
|
|
|
|
if (!success) {
|
|
return false;
|
|
}
|
|
|
|
await updateDSPState();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
notify(`Lock failed: ${String(err)}`, 'error', dsp.name);
|
|
return false;
|
|
}
|
|
});
|
|
},
|
|
};
|
|
}
|