Python使用PyAudio/Sounddevice写入Virtual Audio Cable遇通道数错误求助
问题描述
尝试用Python(PyAudio/Sounddevice)将音频写入VB-Audio Virtual Cable时,初始化输出流触发错误:OSError: [Errno -9998] Invalid number of channels。设备列表显示相关设备的通道信息如下:
3 CABLE Output (VB-Audio Virtual , MME (2 in, 0 out)
9 CABLE Input (VB-Audio Virtual C, MME (0 in, 2 out)
9 CABLE Input (VB-Audio Virtual C, MME (0 in, 2 out)
20 CABLE Input (VB-Audio Virtual Cable), Windows DirectSound (0 in, 2 out)
24 CABLE Input (VB-Audio Virtual Cable), Windows WASAPI (0 in, 2 out)
28 CABLE Output (VB-Audio Virtual Cable), Windows WASAPI (2 in, 0 out)
35 CABLE Output (VB-Audio Point), Windows WDM-KS (8 in, 0 out)
用户尝试写入CABLE Input但设备显示0输入通道,使用通道数匹配的输出设备仍报错,相关代码见下文。
核心问题分析
- Virtual Audio Cable的CABLE Input本质是输出设备(对应代码里的
output=True):它的作用是接收音频输出,供其他软件从其“输入端”读取音频。设备列表里的(0 in, 2 out)表示该设备没有输入通道,只有2个输出通道,因此写入时必须把它当作输出设备,且通道数设为2。 - 你的代码中
v_cable_output_index = 14对应的设备不存在,且设置了channels=8,与目标设备实际通道数(2)不匹配,这是触发错误的直接原因。
具体修复步骤
1. 确认正确的设备索引和通道数
运行以下代码列出所有音频设备的详细信息,找到目标Virtual Cable设备(比如索引9、20、24的CABLE Input,均为2输出通道):
import pyaudio p = pyaudio.PyAudio() for i in range(p.get_device_count()): dev = p.get_device_info_by_index(i) print(f"Index {i}: {dev['name']}, {dev['hostApi']} (in: {dev['maxInputChannels']}, out: {dev['maxOutputChannels']})") p.terminate()
2. 修正输出流参数
将v_cable_output_index改为正确的设备索引,同时将channels调整为目标设备的实际输出通道数(2):
# 替换为你找到的正确设备索引 v_cable_output_index = 9 # 打开输出流(修正通道数为2) output_stream = p.open(format=pyaudio.paInt16, channels=2, rate=input_sample_rate, output=True, output_device_index=v_cable_output_index)
3. 确保音频数据通道数匹配
你的输入流是2通道,读取的audio_array为2通道扁平数组(左右声道采样点交替存储),直接写入输出流即可;若后续处理修改了通道数,需调整为与输出设备一致的2通道。
4. 清理资源
程序结束时关闭流并终止PyAudio,避免资源泄漏:
input_stream.stop_stream() input_stream.close() output_stream.stop_stream() output_stream.close() p.terminate()
额外提示
- 不要混淆Virtual Cable的Input/Output逻辑:CABLE Input是接收输出的设备(你要写音频到这里),CABLE Output是提供输入的设备(其他软件从这里读取音频)。
- 若使用Sounddevice模块,代码会更简洁,示例:
import sounddevice as sd import numpy as np mic_idx = 1 cable_idx = 9 sample_rate = int(sd.query_devices(mic_idx)['default_samplerate']) blocksize = 512 def callback(indata, outdata, frames, time, status): if status: print(status) outdata[:] = indata # 直接转发音频,可在此处添加处理逻辑 with sd.Stream(device=(mic_idx, cable_idx), samplerate=sample_rate, blocksize=blocksize, dtype='int16', channels=2, callback=callback): print("运行中...按回车键停止") input()
内容的提问来源于stack exchange,提问作者JRolfes

