Abel'Blog

我干了什么?究竟拿了时间换了什么?

0%

跨平台浏览器纯净音频内录指南

概述

在日常学习、技术调研与素材整理中,我们经常需要在浏览器(如 Microsoft Edge / Chrome)中播放媒体(如 B 站视频、技术公开课、网络播客),并希望将其内录为高品质音频文件(MP3 / WAV / WebM)。

然而在实际操作中,常规录制方式往往面临诸多痛点:

  1. 外放麦克风录制:会混入机械键盘声、环境底噪以及房间混响,音质损失严重;
  2. 系统全局混音录制:容易将微信、钉钉通知、邮件提醒或系统弹窗提示音一并录入;
  3. 平台底层差异:Windows 原生支持 WASAPI 声卡回环(Loopback),而 macOS 出于隐私安全限制,对应用内录有严格权限管控,导致跨平台方案难以统一。

针对上述问题,本文梳理一套全平台通用的纯净内录方案:借助 Edge/Chromium 原生提供的 chrome.tabCapture API 编写轻量扩展,直接在浏览器数字音频合成层截取目标标签页的数据流。实现免驱动、跨平台(Mac/Windows 完全统一)、零杂音干扰的高品质内录体验。


方案选型与技术对比

实现系统或应用音频内录,业内通常有三种常见技术路径:

方案维度 浏览器扩展(Tab Capture) 系统级声卡回环(Loopback) 虚拟声卡路由(如 BlackHole)
跨平台一致性 完全一致(基于 Chromium 内核) 仅限 Windows(WASAPI) 仅限 macOS(需额外内核驱动)
杂音隔绝程度 极高(仅截取目标标签页流,免疫系统杂音) 中(会录入系统提示音与其它软件声音) 中(需配置多输出设备,易受干扰)
安装与配置门槛 零安装配置(浏览器开启开发者模式直接加载) 依赖本地 Python 或专用音频宿主软件 需安装虚拟声卡并在音频 MIDI 中路由
权限与安全要求 仅浏览器内置标签页权限 普通系统权限 macOS 麦克风/屏幕录制系统权限

选型结论:
Microsoft Edge 在 Windows 和 macOS 上均基于 Chromium 架构。利用 chrome.tabCapture API 截取单一标签页音频流,不仅能彻底隔绝系统通知音,而且一套代码完全通用,是个人轻量内录与跨平台环境下的最优解。


核心工程实现

该工程只需 3 个文本文件,无需 Node.js 打包或 Webpack/Vite 编译,直接原生运行。

1. 目录结构

1
2
3
4
edge-audio-recorder/
├── manifest.json # 扩展清单配置 (Manifest V3)
├── popup.html # 弹出层控制面板
└── popup.js # 音频流截取、穿透监听与下载逻辑

2. 核心代码清单

(1) manifest.json

定义扩展的基础元数据与运行所需权限,主要包括 tabCapture(标签页捕获)与 downloads(文件下载)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"manifest_version": 3,
"name": "Edge 纯净标签页录音器",
"version": "1.0",
"description": "跨平台无杂音捕获当前标签页音频并导出",
"permissions": [
"tabCapture",
"downloads",
"activeTab"
],
"action": {
"default_popup": "popup.html",
"default_title": "点击录音"
}
}

(2) popup.html

简洁清晰的弹出交互面板,提供状态提示与录制开关控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<style>
body {
width: 220px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
padding: 12px;
text-align: center;
margin: 0;
background-color: #fafafa;
}
h4 { margin: 0 0 10px 0; color: #222; font-size: 15px; }
button {
width: 100%;
padding: 8px 0;
margin-top: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
border: none;
border-radius: 4px;
transition: opacity 0.2s;
}
button:disabled { opacity: 0.5; cursor: not-allowed; }
#startBtn { background-color: #0078d4; color: #fff; }
#stopBtn { background-color: #d83b01; color: #fff; }
#status { font-size: 12px; color: #666; margin-top: 10px; min-height: 16px; }
</style>
</head>
<body>
<h4>音频内录助手</h4>
<button id="startBtn">开始录音</button>
<button id="stopBtn" disabled>停止并下载</button>
<div id="status">就绪</div>
<script src="popup.js"></script>
</body>
</html>

(3) popup.js

核心逻辑实现,包含音频流截取、穿透路由(解决静音问题)、数据分片缓冲与本地保存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
let mediaRecorder = null;
let recordedChunks = [];
let audioContext = null;

const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const statusDiv = document.getElementById('status');

startBtn.onclick = () => {
// 1. 截取当前激活标签页的音频流
chrome.tabCapture.capture({ audio: true, video: false }, (stream) => {
if (!stream) {
statusDiv.innerText = "捕获失败,请刷新目标页面重试";
return;
}

// 2. 音频穿透监听(解决 tabCapture 默认使当前标签页静音的问题)
audioContext = new AudioContext();
const source = audioContext.createMediaStreamSource(stream);
source.connect(audioContext.destination);

// 3. 启动 MediaRecorder 编码流
recordedChunks = [];
mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });

mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
recordedChunks.push(event.data);
}
};

mediaRecorder.onstop = () => {
// 组装 Blob 并触发浏览器下载
const blob = new Blob(recordedChunks, { type: 'audio/webm' });
const url = URL.createObjectURL(blob);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');

chrome.downloads.download({
url: url,
filename: `audio_record_${timestamp}.webm`
});

// 释放流与上下文资源
stream.getTracks().forEach(track => track.stop());
if (audioContext) {
audioContext.close();
}
statusDiv.innerText = "已导出录音文件";
};

mediaRecorder.start();
startBtn.disabled = true;
stopBtn.disabled = false;
statusDiv.innerText = "🔴 正在录制当前标签页...";
});
};

stopBtn.onclick = () => {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
startBtn.disabled = false;
stopBtn.disabled = true;
}
};

3. 核心机制剖析

  1. 防静音穿透路由(AudioContext Destination):
    Chromium 的 tabCapture 默认会将目标页面的音频输出直接导向流,导致扬声器/耳机瞬间失去声音。通过建立一个 AudioContext,将流源连接至 destination,即可在录制的同时保证耳机正常监听。
  2. 零拷贝高效录制:
    MediaRecorder 接收的原生流由浏览器底层的硬件解码与音频合成器直接供给,CPU 占用率极低。
  3. 生命周期管理:
    录音完成后显式调用 stream.getTracks().forEach(t => t.stop()) 与 audioContext.close(),避免内存泄漏与后台无意义占用。

部署与使用流程

在 macOS 与 Windows 上,安装与使用步骤完全相同:

  1. 准备源码目录:
    在本地新建名为 edge-audio-recorder 的文件夹,将上述 manifest.json、popup.html 和 popup.js 保存至该目录下。
  2. 打开扩展管理页:
    在 Edge 地址栏中输入 edge://extensions/ 并回车(Chrome 则输入 chrome://extensions/)。
  3. 开启开发人员模式:
    在扩展页面左侧边栏(或顶部),开启「开发人员模式」开关。
  4. 加载已解压的扩展:
    点击「加载解压缩的扩展」按钮,在文件选择对话框中选中刚才创建的 edge-audio-recorder 目录。
  5. 固定扩展图标:
    点击浏览器地址栏右侧的拼图图标(扩展管理器),将该录音插件固定在工具栏,以便快捷点击。
  6. 实测录音:
    • 打开需要内录的网页(如 B 站歌曲、播客);
    • 点击工具栏插件图标,点击「开始录音」;
    • 播放完毕后,点击「停止并下载」,纯净的 .webm 音频文件将自动保存至本地下载目录。

提示(Popup 窗口焦点特性):
浏览器扩展的 Popup 弹窗属于临时浮窗,若在录制过程中点击网页其他区域,浮窗会失焦关闭,从而中断录音。
解决技巧:在工具栏右键点击该插件图标,选择「审查弹出内容」(Inspect Popup),通过弹出的 DevTools 即可钉住 Popup 窗口,在录音期间可随意浏览和切换其他页面。


音频转码与自动化批处理

Chromium 内置的 MediaRecorder 默认输出采用高压缩比且高保真的 WebM(Opus 音频编码)格式。如果设备或播放器需要标准的 .mp3 格式,可通过以下方式快速处理:

1. FFmpeg 单文件快速转码

1
ffmpeg -i audio_record.webm -vn -c:a libmp3lame -b:a 320k output.mp3
  • -vn:过滤掉可能残留的视频流;
  • -c:a libmp3lame:使用高质量 MP3 编码器;
  • -b:a 320k:指定 320kbps 极高比特率,保障音质无损。

2. 跨平台一键批量转换脚本

将下载目录中的所有 .webm 文件一键转换为 .mp3:

  • macOS / Linux 终端:

    1
    2
    3
    for f in *.webm; do
    ffmpeg -i "$f" -vn -c:a libmp3lame -b:a 320k "${f%.webm}.mp3"
    done
  • Windows PowerShell:

    1
    2
    3
    Get-ChildItem *.webm | ForEach-Object {
    ffmpeg -i $_.FullName -vn -c:a libmp3lame -b:a 320k "$($_.BaseName).mp3"
    }

3. 纯前端集成方案(免转码工具)

如果希望插件在点击“停止”后直接下载 MP3,可在工程中引入前端编码库(如 lamejs),在 mediaRecorder.onstop 中通过 Web Worker 将 PCM 数据直接编码为 MP3 Blob,实现完全免除本地转码工具的纯净闭环。


系统原生内录方案参考

若需要在没有界面的服务器、后台自动化脚本或爬虫中内录音频,可参考各操作系统的原生方案:

1. Windows 原生方案(WASAPI Loopback)

  • 原理:基于 Windows Vista 引入的 Core Audio APIs,直接监听扬声器终端的回环流。
  • 实现工具:Python 中推荐使用 pyaudiowpatch 或 soundcard 库,枚举声卡设备并捕获 loopback=True 的输入流。
  • 注意事项:录音期间需打开系统“免打扰模式”,避免微信或系统弹窗提示音混入。

2. macOS 原生方案

  • 现代方案(macOS 13+ ScreenCaptureKit):
    Apple 官方推出的现代屏幕与音频捕获框架,支持按应用进程 Bundle ID(如 Edge 的 com.microsoft.edgemac)精确截取指定进程音频,原生免疫系统其他声音。
  • 传统驱动方案(BlackHole):
    安装开源虚拟音频驱动 BlackHole,在系统「音频 MIDI 设置」中配置“多输出设备”,一条路由至耳机监听,另一条路由至 BlackHole,再通过 Python sounddevice 读取虚拟设备音频。

总结

场景需求 推荐方案 核心优势
日常网页音频内录、无杂音、跨平台通吃 Edge/Chrome 扩展(Tab Capture) 零驱动安装、免系统级权限、一份代码跨平台运行
后台自动化脚本 / 静默采集 (Windows) WASAPI Loopback (Python) 依托 Windows 原生 API,无须人工交互
后台自动化脚本 / 进程级隔离 (macOS) ScreenCaptureKit (Swift / Objective-C) 现代官方接口,单进程音频过滤精确稳定

参考资料