feat: pactl-based module loading, more device types

Backend:
- Switched null-sink and loopback to use pactl (works on all systems)
- Generic POST /api/load-module {module, args} for any pactl module
- Fixed SVG toolbar click issue (z-index layering)

Frontend:
- + Add Device dropdown now includes:
  - Null Sink (virtual audio output)
  - Loopback Device (paired input+output)
  - TCP Network Server (module-native-protocol-tcp)
  - TCP Tunnel Sink
  - TCP Tunnel Source
- Dropdown header and section separators
- Fixed canvas z-index so toolbar is clickable
This commit is contained in:
joren
2026-03-29 23:55:19 +02:00
parent 2879469d13
commit 9dc685acda
3 changed files with 110 additions and 50 deletions

View File

@@ -392,7 +392,7 @@ export async function createNullSink(name: string): Promise<number | null> {
body: JSON.stringify({ name }),
});
const data = await res.json();
return data.module_id || null;
return data.module_id > 0 ? data.module_id : null;
} catch (e) {
console.error('[api] create-null-sink failed:', e);
return null;
@@ -407,13 +407,28 @@ export async function createLoopback(name: string): Promise<number | null> {
body: JSON.stringify({ name }),
});
const data = await res.json();
return data.module_id || null;
return data.module_id > 0 ? data.module_id : null;
} catch (e) {
console.error('[api] create-loopback failed:', e);
return null;
}
}
export async function loadModule(module: string, args: string): Promise<number | null> {
try {
const res = await fetch('/api/load-module', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ module, args }),
});
const data = await res.json();
return data.module_id > 0 ? data.module_id : null;
} catch (e) {
console.error('[api] load-module failed:', e);
return null;
}
}
export async function unloadModule(moduleId: number) {
try {
await fetch('/api/unload-module', {