Electron - 音频与视频捕获
Electron - 现代音频和视频捕获
Section titled “Electron - 现代音频和视频捕获”捕获音频和视频对于视频会议、屏幕录制工具或需要访问网络摄像头(例如,捕捉个人资料图片)的功能至关重要。Electron 使用 Web 标准 API,如 navigator.mediaDevices.getUserMedia,以及其自己的 desktopCapturer 模块来捕获屏幕/窗口,从而简化了此过程。
首先,让我们在 main.js 中设置主进程。我们将启用 contextIsolation 并使用预加载脚本。可以使用 app.getPath('userData') API 来获取用于保存用户特定数据(例如录音)的标准目录。
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();});创建 preload.js 文件。这将是安全地将 desktopCapturer API 暴露给渲染进程的关键:
const { contextBridge, desktopCapturer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', { getScreenSources: () => desktopCapturer.getSources({ types: ['window', 'screen'] })});现在,创建 index.html 来处理网络摄像头/麦克风捕获和桌面捕获:
<!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>最后,创建 renderer.js 来实现捕获逻辑:
// renderer.jsdocument.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}`); } };});使用 npx electron . 运行应用。您将看到两个部分:
-
Webcam & Microphone Capture: 点击“Start Webcam/Mic”将提示请求权限。如果获得许可,您的网络摄像头画面将出现在第一个视频元素中。
-
Screen/Window Capture: 下拉列表中将填充可用的屏幕和打开的窗口。选择其中一个,然后点击“Start Screen Capture”。所选屏幕/窗口的内容将流式传输到第二个视频元素。
然后可以进一步处理这些捕获的流(MediaStream 对象),例如,使用 MediaRecorder API 进行录制,或通过网络传输进行视频会议。为了保存捕获的媒体,您通常会在渲染进程中使用 MediaRecorder,然后通过 IPC 将生成的 Blob 数据发送到主进程,以便使用 Node.js 的 fs 模块保存到文件中。这使文件系统操作远离渲染进程,符合安全最佳实践。
有关使用 MediaRecorder API 保存流的详细信息,请参阅 MDN Web Docs:https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder