fix(voice): robust microphone fallback for WebKitGTK "Invalid constraint"
All checks were successful
Build AppImage / build (push) Has been skipped

WebKitGTK throws various error types (TypeError, OverconstrainedError,
etc.) when getUserMedia is called. Instead of only catching specific
error names, now ALL errors trigger device-enumeration fallback chain:
1. { audio: true }
2. Explicit deviceId from enumerateDevices()
3. { audio: {} } as last resort

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eddy 2026-04-20 22:17:52 +02:00
parent 5d72b85bf4
commit e0653ddcab
2 changed files with 30 additions and 15 deletions

View file

@ -261,28 +261,29 @@
try {
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
} catch (initialErr) {
// OverconstrainedError oder NotFoundError — auf WebKitGTK/Tauri kann
// selbst { audio: true } fehlschlagen. Versuche explizites Device.
if (initialErr instanceof DOMException &&
(initialErr.name === 'OverconstrainedError' || initialErr.name === 'NotFoundError')) {
console.warn('getUserMedia fehlgeschlagen, versuche Device-Enumeration:', initialErr);
// WebKitGTK wirft verschiedene Fehler: OverconstrainedError, NotFoundError,
// TypeError("Invalid constraint"), etc. Bei JEDEM Fehler Fallback versuchen.
console.warn('getUserMedia({audio:true}) fehlgeschlagen, versuche Fallback:', initialErr);
try {
const devices = await navigator.mediaDevices.enumerateDevices();
const audioInput = devices.find(d => d.kind === 'audioinput');
if (audioInput) {
console.log('Audio-Device gefunden:', audioInput.label || audioInput.deviceId);
stream = await navigator.mediaDevices.getUserMedia({
audio: { deviceId: audioInput.deviceId }
audio: { deviceId: { exact: audioInput.deviceId } }
});
} else {
throw new Error(
'Kein Mikrofon gefunden. Unter WebKitGTK (Tauri/Linux) wird ' +
'PipeWire oder PulseAudio mit gst-plugin-pipewire benötigt.'
);
// Letzter Versuch: komplett ohne Constraints
stream = await navigator.mediaDevices.getUserMedia({ audio: {} });
}
} else {
throw initialErr;
} catch (fallbackErr) {
throw new Error(
'Kein Mikrofon verfügbar. Unter WebKitGTK (Tauri/Linux) wird ' +
'PipeWire oder PulseAudio mit gst-plugin-pipewire benötigt. ' +
`Original: ${initialErr instanceof Error ? initialErr.message : initialErr}`
);
}
}

View file

@ -77,10 +77,24 @@
});
console.log('🎤 Mikrofon mit optimalen Constraints geöffnet');
} catch (constraintErr) {
console.warn('Mikrofon-Constraints fehlgeschlagen, versuche Fallback:', constraintErr);
// WebKitGTK wirft diverse Fehler (OverconstrainedError, TypeError "Invalid constraint", etc.)
console.warn('Mikrofon-Constraints fehlgeschlagen, versuche Fallbacks:', constraintErr);
try {
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
} catch (_) {
// Auch { audio: true } fehlgeschlagen — versuche explizites Device
const devices = await navigator.mediaDevices.enumerateDevices();
const audioInput = devices.find(d => d.kind === 'audioinput');
if (audioInput) {
mediaStream = await navigator.mediaDevices.getUserMedia({
audio: { deviceId: { exact: audioInput.deviceId } }
});
} else {
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: {} });
}
}
usedFallback = true;
console.log('🎤 Mikrofon mit Fallback { audio: true } geöffnet');
console.log('🎤 Mikrofon mit Fallback geöffnet');
}
// Audio-Kontext für Visualisierung