录制系统内部音频(扬声器输出)是 Windows 音频编程中的常见需求,但 PyAudio 本身主要面向麦克风输入设计。以下是几种经过验证的实现方案,从简到繁依次介绍。
方案一:启用"立体声混音"设备(最简便)
Windows 系统内置了一个名为 "立体声混音"(Stereo Mix) 的录制设备,它能捕获扬声器播放的所有声音 (citation:7)。
1. 启用立体声混音设备
默认情况下该设备是禁用的,需手动开启 (citation:7):
右键点击任务栏音量图标 → 打开 声音设置
选择右侧的 "声音控制面板"
切换到 "录制" 选项卡
在列表空白处 右键 → 勾选 "显示禁用的设备"
找到 "立体声混音",右键 → 启用
可选:右键 → "设置为默认设备"
注意:部分声卡驱动(尤其是笔记本电脑)可能不提供此选项 (citation:7)。
2. PyAudio 代码实现
import pyaudio
import wave
def record_system_audio(filename, duration=10, sample_rate=48000, channels=2, chunk=1024):
"""录制系统输出音频(通过立体声混音设备)"""
p = pyaudio.PyAudio()
# 查找立体声混音设备
device_index = None
for i in range(p.get_device_count()):
dev = p.get_device_info_by_index(i)
print(f" 设备 {i}: {dev['name']} (输入通道: {dev['maxInputChannels']})")
if "立体声混音" in dev["name"] or "Stereo Mix" in dev["name"]:
device_index = dev["index"]
print(f" --> 找到目标设备: {dev['name']}")
break
if device_index is None:
raise Exception(
"未找到立体声混音设备。请在 Windows 声音设置中启用该设备:\n"
"声音控制面板 → 录制选项卡 → 右键显示禁用设备 → 启用立体声混音"
)
stream = p.open(
format=pyaudio.paInt16,
channels=channels,
rate=sample_rate,
input=True,
input_device_index=device_index, # 关键:指定立体声混音设备
frames_per_buffer=chunk
)
print("● 开始录制系统音频...")
frames = []
for _ in range(0, int(sample_rate / chunk * duration)):
frames.append(stream.read(chunk))
print("■ 录制完成")
stream.stop_stream()
stream.close()
p.terminate()
# 保存为 WAV 文件
with wave.open(filename, 'wb') as wf:
wf.setnchannels(channels)
wf.setsampwidth(p.get_sample_size(pyaudio.paInt16))
wf.setframerate(sample_rate)
wf.writeframes(b''.join(frames))
print(f"✓ 文件已保存: {filename}")
record_system_audio("system_audio.wav", duration=15)方案二:WASAPI Loopback 模式(最专业)
从 Windows Vista 开始,微软提供了 WASAPI(Windows Audio Session API) 的 Loopback(环回)录制模式,可以直接捕获音频引擎正在播放的系统混合音频,无需额外硬件或虚拟设备 (citation:3)(citation:12)(citation:13)。
工作原理
"在 loopback 模式下,WASAPI 客户端可以捕获 rendering endpoint 设备(通常即声卡)正在播放的音频流。客户端只能为共享模式流(AUDCLNT_SHAREMODE_SHARED)启用 loopback 模式。" (citation:13)
WASAPI 在软件层面实现了环回功能——将音频引擎的输出流复制到应用程序的捕获缓冲区中 (citation:12)。
使用 soundcard 库简化操作
PyAudio 对 WASAPI Loopback 的支持不够直接,推荐使用 Python 的 soundcard 库,它底层封装了 WASAPI:
import soundcard
import numpy as np
import wave
def record_loopback(filename, duration=10, sample_rate=48000):
"""使用 WASAPI Loopback 录制系统音频"""
# 获取默认扬声器(即环回捕获源)
speaker = soundcard.default_speaker()
print(f"当前扬声器: {speaker.name}")
# 通过扬声器的 loopback 模式创建麦克风对象
mic = speaker.microphone()
print(f"环回设备: {mic.name}")
print(f"● 开始录制 ({duration} 秒)...")
# 采集音频数据(返回 numpy 数组)
data = mic.record(samplerate=sample_rate, numframes=sample_rate * duration)
print("■ 录制完成")
# 将 float32 转换为 int16 并保存 WAV
data_int16 = np.int16(data * 32767)
with wave.open(filename, 'wb') as wf:
wf.setnchannels(data_int16.shape[1] if len(data_int16.shape) > 1 else 1)
wf.setsampwidth(2) # 16-bit = 2 bytes
wf.setframerate(sample_rate)
wf.writeframes(data_int16.tobytes())
print(f"✓ 已保存: {filename}")
record_loopback("loopback_audio.wav", duration=15) 安装依赖:
pip install soundcard numpy
方案三:Virtual Audio Cable 虚拟声卡(通用性最强)
Virtual Audio Cable (VAC) 是一款虚拟声卡驱动程序,可以在系统中创建虚拟音频线路,在不同应用程序间传送音频讯号流 (citation:1)(citation:2)。
工作流程
VAC 的核心思路是:将系统默认播放设备设为虚拟声卡,再用 Audio Repeater 将虚拟声卡的输出转发到真实扬声器,同时用 PyAudio 从虚拟声卡录音 (citation:1):
应用程序音频输出 → VAC 虚拟声卡(录制端口) → PyAudio 采集
↘ Audio Repeater → 真实扬声器(听到声音) 操作步骤
安装 VAC,系统会出现新的虚拟音频设备 Line 1 (Virtual Audio Cable) (citation:1)
设置默认播放设备为 VAC(此时直接播放听不到声音,声音已转入虚拟线路)(citation:1)
打开 Audio Repeater,将 Wave In 设为 Line 1,Wave Out 设为真实扬声器 (citation:1)
用 PyAudio 从 VAC 录制:
import pyaudio
import wave
def record_vac(filename, duration=10, sample_rate=44100, channels=2, chunk=1024):
"""从 Virtual Audio Cable 虚拟声卡录制系统音频"""
p = pyaudio.PyAudio()
# 查找 VAC 设备
device_index = None
for i in range(p.get_device_count()):
dev = p.get_device_info_by_index(i)
if "Virtual Audio Cable" in dev["name"] and dev["maxInputChannels"] > 0:
device_index = dev["index"]
print(f"找到 VAC 设备: {dev['name']} (索引 {i})")
break
if device_index is None:
raise Exception("未找到 Virtual Audio Cable 设备,请先安装 VAC")
stream = p.open(
format=pyaudio.paInt16,
channels=channels,
rate=sample_rate,
input=True,
input_device_index=device_index,
frames_per_buffer=chunk
)
print("● 从 VAC 录制中...")
frames = []
for _ in range(0, int(sample_rate / chunk * duration)):
frames.append(stream.read(chunk))
print("■ 录制完成")
stream.stop_stream()
stream.close()
p.terminate()
with wave.open(filename, 'wb') as wf:
wf.setnchannels(channels)
wf.setsampwidth(p.get_sample_size(pyaudio.paInt16))
wf.setframerate(sample_rate)
wf.writeframes(b''.join(frames))
print(f"✓ 已保存: {filename}")三种方案对比
| 是否需要安装额外软件 | 否 | soundcard 库 | 需要安装 VAC 驱动 |
| 是否需要系统设置 | 需要手动启用设备 | 否 | 需要配置默认设备 |
| 是否影响日常使用 | 不影响 | 不影响 | 会影响默认播放设备 |
| 音质 | 原始数字音频,无损 | 原始数字音频,无损 | 原始数字音频,无损 |
| DRM 保护内容 | 不可录制 | 不可录制 (citation:13) | 不可录制 |
| 兼容性 | 部分声卡不支持 | Windows Vista+ | 通用 |
| 推荐场景 | 快速录音 | 专业应用开发 | 特殊设备/驱动环境 |
"传的讯号都是数字,所以不会有讯号污染或衰减的问题" (citation:2),三种方案在音质层面没有本质差异。
补充注意事项
音量调节:使用 VAC 或立体声混音时,调节耳机音量可能会导致系统自动切换默认输出设备。录制时需注意保持输出设备指向 VAC 或立体声混音 (citation:2)
DRM 限制:"WASAPI 不允许 loopback 录制包含 DRM 保护内容的数字流" (citation:12),受保护的流媒体音频无法通过任何方式录制
录音监听:如果需要在录制的同时听到声音,立体声混音方案天然支持;VAC 方案需要配合 Audio Repeater 转发 (citation:1)
网友回复
windows如何设置让多个人同时远程桌面连接同一台电脑同时可操作不被踢出?
什么是WebRCD技术?
如何在centos的服务器docker上安装运行微信qq?
如何用ai图片模型祛除图片油腻感?
google的gemini-omni多模态大模型在哪可以免费体验?
google的Antigravity 、Antigravity CLI、Antigravity IDE、Antigravity SDK有啥区别不同?
Pyaudio如何录制windows扬声器输出的声音?
为啥win10电脑上sounddevice与pyaudio无法播放声音?
半导体摩尔定律与韬(τ)定律区别?
千问qwen有没有实时同声翻译的ai大模型?


