You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PyAudio录制麦克风与系统声音:线程代码整合失败求助

解决PyAudio线程中同时录制扬声器与麦克风并实时混音的问题

看起来你已经搞懂了单独录制和后期混音的逻辑,但把这套逻辑放到线程化的recorder类里时,核心问题在于原来的单流录制逻辑没有适配双流同步读取+实时混音,而是沿用了先分别存储所有帧再后期处理的方式,这不仅容易导致内存占用过高,更关键的是两个流的读取可能不同步,最终导致混音后的音频出现错位或者异常。

下面是修正后的完整recorder类代码,我会在后面解释关键改动点:

import pyaudio
import wave
import threading
import numpy as np

CHUNK = 1024
FORMAT = pyaudio.paInt16
RATE = 44100

class recorder:
    def __init__(self):
        self.going = False
        self.process = None
        # 预定义设备索引(根据你的设备列表)
        self.speaker_device_idx = 2  # 立体声混音设备
        self.mic_device_idx = 1       # 麦克风设备

    def record(self, filename):
        # 检查是否已有录制线程在运行
        if self.process and self.process.is_alive():
            self.stop_recording()
        self.filename = filename
        self.process = threading.Thread(target=self._record)
        self.process.start()

    def _record(self):
        p = pyaudio.PyAudio()
        frames = []

        # 打开扬声器混音流(立体声)
        speaker_stream = p.open(
            format=FORMAT,
            channels=2,
            rate=RATE,
            input=True,
            frames_per_buffer=CHUNK,
            input_device_index=self.speaker_device_idx,
            as_loopback=True
        )

        # 打开麦克风流(单声道)
        mic_stream = p.open(
            format=FORMAT,
            channels=1,
            rate=RATE,
            input=True,
            frames_per_buffer=CHUNK,
            input_device_index=self.mic_device_idx
        )

        print("* 开始录制(扬声器+麦克风)")
        self.going = True

        while self.going:
            try:
                # 同步读取两个流的chunk数据,避免缓冲区溢出中断
                speaker_data = speaker_stream.read(CHUNK, exception_on_overflow=False)
                mic_data = mic_stream.read(CHUNK, exception_on_overflow=False)

                # 解码为numpy数组
                speaker_decoded = np.frombuffer(speaker_data, dtype=np.int16)
                mic_decoded = np.frombuffer(mic_data, dtype=np.int16)

                # 分离扬声器左右声道并合并为单声道(避免音量过高)
                speaker_mono = (speaker_decoded[::2] + speaker_decoded[1::2]) // 2

                # 混音并限制音量范围,防止音频失真
                mixed = np.clip(speaker_mono + mic_decoded, -32767, 32766)

                # 重新编码为字节数据
                mixed_data = mixed.tobytes()

                # 将混音后的chunk加入帧列表
                frames.append(mixed_data)
            except Exception as e:
                print(f"录制过程中出错: {e}")
                break

        print("* 录制结束")

        # 关闭流并终止PyAudio
        speaker_stream.stop_stream()
        speaker_stream.close()
        mic_stream.stop_stream()
        mic_stream.close()
        p.terminate()

        # 保存混音后的音频文件
        wf = wave.open(self.filename, 'wb')
        wf.setnchannels(1)  # 最终输出单声道
        wf.setsampwidth(p.get_sample_size(FORMAT))
        wf.setframerate(RATE)
        wf.writeframes(b''.join(frames))
        wf.close()

    def stop_recording(self):
        self.going = False
        if self.process:
            self.process.join()

关键改动说明:

  1. 双流同步读取:在录制循环中,每次同时读取扬声器流和麦克风流的chunk数据,确保两者的时间轴完全同步,避免后期混音时出现音频错位。
  2. 实时混音:不再分别存储两个流的所有帧,而是每读取一块数据就立即完成混音处理,大大降低内存占用,同时保证实时性。
  3. 异常处理:添加exception_on_overflow=False和全局异常捕获,避免因系统负载导致的缓冲区溢出中断录制。
  4. 线程安全优化:在stop_recording中调用process.join(),确保录制线程完全终止后再进行后续操作。
  5. 音量控制:对扬声器左右声道做平均合并,再和麦克风音频叠加后用np.clip限制输出范围,防止音量过高导致的音频失真。

测试注意事项:

  • 确保你的立体声混音设备已经在系统中启用并设置为可用状态。
  • 如果出现音频卡顿或者不同步,可以尝试调整CHUNK的大小(比如改为2048),平衡延迟和稳定性。
  • 若设备索引有变动,直接修改__init__中的speaker_device_idxmic_device_idx即可。

内容的提问来源于stack exchange,提问作者Gabriel

火山引擎 最新活动