You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

反复点击音频收发按钮触发PyAudio流错误,无法实现双向音频传输

解决PyAudio反复启停音频流导致的[Errno Not input/output stream]错误

反复点击「receive-audio」和「Start」按钮时触发以下错误:

An error occurred: [Errno Not input stream] -9975
An error occurred: [Errno Not output stream] -9974

需要实现双向音频收发,当前代码无法完成,原代码如下:

def send_audio(self):
    p = pyaudio.PyAudio()
    
    while self.is_running:
        try:
            self.stream = p.open(format=pyaudio.paInt16,
                                channels=self.CHANNELS,
                                rate=self.RATE,
                                input=True,
                                frames_per_buffer=self.CHUNK)
    
            while self.is_running:
                data = self.stream.read(self.CHUNK)
                audio_data = np.frombuffer(data, np.int16)
                self.server_socket.sendall(audio_data)
    
                if not self.is_running:
                    break
    
            self.stream.stop_stream()
            self.stream.close()
            p.terminate()
        
        except Exception as e:
            print("An error occurred:", str(e))

def receive_audio(self):
    p = pyaudio.PyAudio()

    while self.is_running_recv:
        try:
            self.stream = p.open(format=self.FORMAT,
                                channels=self.CHANNELS,
                                rate=self.RATE,
                                output=True)
    
            while self.is_running_recv:
                data = self.server_socket.recv(self.CHUNK)
                
                if not data:
                    break
                if self.event.is_set():
                    self.stream.write(data)
    
            self.stream.stop_stream()
            self.stream.close()
            self.server_socket.close()
            p.terminate()
        
        except Exception as e:
            print("An error occurred:", str(e))

问题根源

  1. PyAudio实例反复销毁重建:两个函数每次循环都创建p = pyaudio.PyAudio(),循环结束就p.terminate(),反复点击会导致音频设备资源未正确释放,新实例无法创建有效流。
  2. 流对象冲突:两个函数共用self.stream,旧流未关闭就被新流覆盖,操作无效流引发错误。
  3. Socket提前关闭:receive_audio里循环结束就关闭socket,后续点击启动时socket已失效。
  4. 循环逻辑冗余:外层while内重复创建流,导致同一时间多个流争抢音频设备。

修复方案

调整资源管理逻辑,复用PyAudio实例,分开输入输出流,统一控制启停:

def __init__(self):
    # 初始化基础参数(根据实际情况调整)
    self.CHANNELS = 1
    self.RATE = 44100
    self.CHUNK = 1024
    self.FORMAT = pyaudio.paInt16
    self.is_running = False
    self.is_running_recv = False
    self.event = threading.Event()
    # 全局复用PyAudio实例
    self.p = pyaudio.PyAudio()
    self.input_stream = None
    self.output_stream = None
    self.server_socket = None  # 确保socket在初始化或连接方法中创建

def send_audio(self):
    try:
        # 仅当流未创建或未激活时初始化输入流
        if not self.input_stream or not self.input_stream.is_active():
            self.input_stream = self.p.open(
                format=pyaudio.paInt16,
                channels=self.CHANNELS,
                rate=self.RATE,
                input=True,
                frames_per_buffer=self.CHUNK
            )
        
        while self.is_running:
            data = self.input_stream.read(self.CHUNK)
            audio_data = np.frombuffer(data, np.int16)
            self.server_socket.sendall(audio_data)
        
        # 停止并清理输入流
        if self.input_stream:
            self.input_stream.stop_stream()
            self.input_stream.close()
            self.input_stream = None
            
    except Exception as e:
        print("An error occurred:", str(e))

def receive_audio(self):
    try:
        # 仅当流未创建或未激活时初始化输出流
        if not self.output_stream or not self.output_stream.is_active():
            self.output_stream = self.p.open(
                format=self.FORMAT,
                channels=self.CHANNELS,
                rate=self.RATE,
                output=True
            )
        
        while self.is_running_recv:
            data = self.server_socket.recv(self.CHUNK)
            if not data:
                break
            if self.event.is_set():
                self.output_stream.write(data)
        
        # 停止并清理输出流
        if self.output_stream:
            self.output_stream.stop_stream()
            self.output_stream.close()
            self.output_stream = None
            
    except Exception as e:
        print("An error occurred:", str(e))

# 统一停止所有音频操作并释放资源
def stop_all_audio(self):
    self.is_running = False
    self.is_running_recv = False
    # 清理输入流
    if self.input_stream:
        self.input_stream.stop_stream()
        self.input_stream.close()
        self.input_stream = None
    # 清理输出流
    if self.output_stream:
        self.output_stream.stop_stream()
        self.output_stream.close()
        self.output_stream = None
    # 关闭socket(按需调用,比如程序退出时)
    if self.server_socket:
        self.server_socket.close()

# 程序退出时调用,销毁PyAudio实例
def cleanup(self):
    self.stop_all_audio()
    self.p.terminate()

使用注意事项

  • 点击「Start」或「receive-audio」按钮前,先调用stop_all_audio()停止现有音频流,再设置self.is_running/self.is_running_recv为True并启动对应线程。
  • 确保send_audio和receive_audio在独立线程中运行,避免UI阻塞。
  • 如果需要重新连接服务器,重新创建self.server_socket对象,不要复用已关闭的socket。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 19:43:09