Skip to content

Electron - Audio & Video Capturing

Electron - Modern Audio and Video Capturing

Section titled “Electron - Modern Audio and Video Capturing”

Capturing audio and video is essential for applications like video conferencing, screen recording tools, or features requiring webcam access (e.g., profile picture capture). Electron facilitates this using web standard APIs like navigator.mediaDevices.getUserMedia and its own desktopCapturer module for screen/window capturing.

First, let’s set up the main process in main.js. We’ll enable contextIsolation and use a preload script. The app.getPath('userData') API can be used to get a standard directory for saving user-specific data, like recordings.

const { app, BrowserWindow } = require('electron');
const path = require('path');
let mainWindow;
// Example: Define a path for saved recordings within the app's user data directory
// const recordingsPath = path.join(app.getPath('userData'), 'saved_recordings');
// You would then use Node's fs module (typically in the main process) to manage this directory.
// console.log('Recordings will be saved in:', recordingsPath);
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 700,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
}
});
mainWindow.loadFile(path.join(__dirname, 'index.html'));
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

Create a preload.js file. This will be crucial for securely exposing the desktopCapturer API to the renderer process:

const { contextBridge, desktopCapturer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
getScreenSources: () => desktopCapturer.getSources({ types: ['window', 'screen'] })
});

Now, create index.html to handle both webcam/microphone capture and desktop capture:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Audio and Video Capture</title>
<style>
body { font-family: Arial, sans-serif; padding: 10px; }
video { border: 1px solid black; margin-top: 10px; max-width: 100%; background-color: #333; }
.controls button { margin: 5px; padding: 8px 12px; }
.section { margin-bottom: 20px; padding: 10px; border: 1px solid #ccc; }
</style>
</head>
<body>
<div class="section">
<h2>Webcam & Microphone Capture</h2>
<button id="startWebcam">Start Webcam/Mic</button>
<video id="webcamVideo" autoplay playsinline></video>
</div>
<div class="section">
<h2>Screen/Window Capture</h2>
<p>Select a source to capture:</p>
<select id="sourceSelect"></select>
<button id="startScreenCapture">Start Screen Capture</button>
<video id="screenVideo" autoplay playsinline></video>
</div>
<script src="./renderer.js"></script>
</body>
</html>

Finally, create renderer.js to implement the capture logic:

// renderer.js
document.addEventListener('DOMContentLoaded', () => {
const webcamVideo = document.getElementById('webcamVideo');
const screenVideo = document.getElementById('screenVideo');
const startWebcamBtn = document.getElementById('startWebcam');
const startScreenCaptureBtn = document.getElementById('startScreenCapture');
const sourceSelect = document.getElementById('sourceSelect');
// Webcam and Microphone Capture
startWebcamBtn.onclick = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
webcamVideo.srcObject = stream;
webcamVideo.onloadedmetadata = () => webcamVideo.play();
} catch (e) {
console.error('Error accessing media devices.', e);
alert(`Error accessing media devices: ${e.name} - ${e.message}`);
}
};
// Populate screen/window sources
async function populateSources() {
if (window.electronAPI && window.electronAPI.getScreenSources) {
try {
const sources = await window.electronAPI.getScreenSources();
sourceSelect.innerHTML = ''; // Clear existing options
sources.forEach(source => {
const option = document.createElement('option');
option.value = source.id;
option.text = source.name;
sourceSelect.appendChild(option);
});
} catch (e) {
console.error('Error getting screen sources:', e);
alert('Error getting screen sources. Check console.');
}
} else {
console.warn('electronAPI.getScreenSources not available. Is preload script working?');
alert('Screen capture API not available.');
}
}
populateSources(); // Call on load
// Screen/Window Capture
startScreenCaptureBtn.onclick = async () => {
const sourceId = sourceSelect.value;
if (!sourceId) {
alert('Please select a source to capture.');
return;
}
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: false, // or { mandatory: { chromeMediaSource: 'desktop' } } for audio capture from desktop
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: sourceId,
minWidth: 1280,
maxWidth: 1920,
minHeight: 720,
maxHeight: 1080
}
}
});
screenVideo.srcObject = stream;
screenVideo.onloadedmetadata = () => screenVideo.play();
} catch (e) {
console.error('Error starting screen capture.', e);
alert(`Error starting screen capture: ${e.name} - ${e.message}`);
}
};
});

Run the app with npx electron .. You’ll see two sections:

  1. Webcam & Microphone Capture: Clicking ‘Start Webcam/Mic’ will prompt for permission. If granted, your webcam feed will appear in the first video element.

  2. Screen/Window Capture: A dropdown list will be populated with available screens and open windows. Select one, then click ‘Start Screen Capture’. The selected screen/window content will be streamed to the second video element.

These captured streams (MediaStream objects) can then be processed further, for example, recorded using the MediaRecorder API, or transmitted over a network for video conferencing. For saving captured media, you would typically use MediaRecorder in the renderer and then send the resulting Blob data to the main process via IPC for saving to a file using Node.js fs module. This keeps file system operations out of the renderer process, adhering to security best practices.

For detailed information on MediaRecorder API for saving streams, refer to the MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder