fix: Improve microphone permission handling and audio capture robustness
- Add device enumeration check before attempting to capture audio - Use simpler audio constraints (audio: true) instead of specific options - Add fallback to explicit device ID if simple constraints fail - Add more descriptive error messages for different failure modes - Enhance Electron permission handlers with better logging - Add setDevicePermissionHandler for audio device access - Include 'microphone' in allowed permissions list 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -446,8 +446,10 @@ app.whenReady().then(async () => {
|
|||||||
loadConfig();
|
loadConfig();
|
||||||
|
|
||||||
// Grant microphone permission automatically
|
// Grant microphone permission automatically
|
||||||
session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => {
|
session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) => {
|
||||||
const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture'];
|
console.log(`Permission request: ${permission}`, details);
|
||||||
|
// Allow all media-related permissions
|
||||||
|
const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture', 'microphone'];
|
||||||
if (allowedPermissions.includes(permission)) {
|
if (allowedPermissions.includes(permission)) {
|
||||||
console.log(`Granting permission: ${permission}`);
|
console.log(`Granting permission: ${permission}`);
|
||||||
callback(true);
|
callback(true);
|
||||||
@@ -458,11 +460,22 @@ app.whenReady().then(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Also handle permission check (for some Electron versions)
|
// Also handle permission check (for some Electron versions)
|
||||||
session.defaultSession.setPermissionCheckHandler((webContents, permission) => {
|
session.defaultSession.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||||
const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture'];
|
console.log(`Permission check: ${permission}`, { requestingOrigin, details });
|
||||||
|
const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture', 'microphone'];
|
||||||
return allowedPermissions.includes(permission);
|
return allowedPermissions.includes(permission);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set device permission handler for media devices
|
||||||
|
session.defaultSession.setDevicePermissionHandler((details) => {
|
||||||
|
console.log('Device permission request:', details);
|
||||||
|
// Allow all audio devices
|
||||||
|
if (details.deviceType === 'audio' || details.deviceType === 'hid') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
// Start backend sidecar if embedded mode is enabled
|
// Start backend sidecar if embedded mode is enabled
|
||||||
startBackendSidecar();
|
startBackendSidecar();
|
||||||
|
|
||||||
|
|||||||
@@ -405,9 +405,26 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for available audio devices first
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
const audioInputs = devices.filter(d => d.kind === 'audioinput');
|
||||||
|
console.log('Available audio inputs:', audioInputs.length, audioInputs);
|
||||||
|
|
||||||
|
if (audioInputs.length === 0) {
|
||||||
|
alert('No microphone found. Please connect a microphone and try again.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try with simple constraints first, fall back to more specific ones
|
||||||
|
try {
|
||||||
|
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||||
|
} catch (simpleErr) {
|
||||||
|
console.warn('Simple audio constraints failed, trying with device ID:', simpleErr);
|
||||||
|
// Try with explicit device ID
|
||||||
mediaStream = await navigator.mediaDevices.getUserMedia({
|
mediaStream = await navigator.mediaDevices.getUserMedia({
|
||||||
audio: { echoCancellation: true, noiseSuppression: true }
|
audio: { deviceId: audioInputs[0].deviceId }
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
isRecording = true;
|
isRecording = true;
|
||||||
recordBtn.textContent = 'Stop Recording';
|
recordBtn.textContent = 'Stop Recording';
|
||||||
@@ -422,7 +439,15 @@
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Start recording error:', error);
|
console.error('Start recording error:', error);
|
||||||
alert('Error starting recording: ' + error.message);
|
let errorMsg = 'Error starting recording: ' + error.message;
|
||||||
|
if (error.name === 'NotAllowedError') {
|
||||||
|
errorMsg = 'Microphone access denied. Please grant permission and try again.';
|
||||||
|
} else if (error.name === 'NotFoundError') {
|
||||||
|
errorMsg = 'No microphone found. Please connect a microphone and try again.';
|
||||||
|
} else if (error.name === 'NotReadableError') {
|
||||||
|
errorMsg = 'Microphone is in use by another application. Please close other apps using the microphone.';
|
||||||
|
}
|
||||||
|
alert(errorMsg);
|
||||||
await cleanupRecording();
|
await cleanupRecording();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user