diff --git a/client/src/main.js b/client/src/main.js index afd85ef..cda103f 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -446,8 +446,10 @@ app.whenReady().then(async () => { loadConfig(); // Grant microphone permission automatically - session.defaultSession.setPermissionRequestHandler((webContents, permission, callback) => { - const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture']; + session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) => { + console.log(`Permission request: ${permission}`, details); + // Allow all media-related permissions + const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture', 'microphone']; if (allowedPermissions.includes(permission)) { console.log(`Granting permission: ${permission}`); callback(true); @@ -458,11 +460,22 @@ app.whenReady().then(async () => { }); // Also handle permission check (for some Electron versions) - session.defaultSession.setPermissionCheckHandler((webContents, permission) => { - const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture']; + session.defaultSession.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => { + console.log(`Permission check: ${permission}`, { requestingOrigin, details }); + const allowedPermissions = ['media', 'mediaKeySystem', 'audioCapture', 'microphone']; 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 startBackendSidecar(); diff --git a/client/src/pages/meeting-detail.html b/client/src/pages/meeting-detail.html index 35cca35..1fe6157 100644 --- a/client/src/pages/meeting-detail.html +++ b/client/src/pages/meeting-detail.html @@ -405,9 +405,26 @@ return; } - mediaStream = await navigator.mediaDevices.getUserMedia({ - audio: { echoCancellation: true, noiseSuppression: true } - }); + // 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({ + audio: { deviceId: audioInputs[0].deviceId } + }); + } isRecording = true; recordBtn.textContent = 'Stop Recording'; @@ -422,7 +439,15 @@ } catch (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(); } }