在回调模式下使用python与pyaudio的线程问题

时间:2017-09-05 09:39:44

标签: python multithreading pyaudio

我正在使用pyaudio录制音频,然后我想以块(例如,每5秒)处理一次。我在回调模式下使用pyaudio,其回调函数是为记录的每1500个音频样本调用的,在该函数中,这些样本被添加到队列中。我还将样本保存到wav文件中,因为它们只是为了验证它们是预期的而被记录。

q = Queue.Queue()
flag = False
waveFile = wave.open('recording.wav', 'wb')
waveFile.setnchannels(1)
waveFile.setsampwidth(2)
waveFile.setframerate(RATE)


def callback(in_data, frame_count, time_info, status):
    silent = is_silent(in_data)
    if silent == False:
        numpydata = np.fromstring(in_data, dtype=np.int16)
        waveFile.writeframes(in_data)
        q.put(numpydata)
        callback_flag = pyaudio.paContinue

    elif silent == True and flag == True:
        numpydata = np.fromstring(in_data, dtype=np.int16)
        if len(numpydata) != 0:
            waveFile.writeframes(in_data)
            q.put(numpydata)
        waveFile.close()
        callback_flag = pyaudio.paComplete
    else:
        callback_flag = pyaudio.paContinue

    return (in_data, callback_flag)

p=pyaudio.PyAudio() # start the PyAudio class
stream=p.open(format=pyaudio.paInt16,channels=1,rate=RATE,input=True,frames_per_buffer=1500, stream_callback = callback) #uses default input device

一旦队列不再为空,我进入一个while循环,它将队列中的数据添加到一个单独的缓冲区,然后每当添加5秒的音频时处理该缓冲区中的数据。

while q.empty() == True:
if q.empty() == False:
    break

buf = []

while 1:
    flag = True
    try:
        snd_data = q.get(True,timeout = 4)
        buf.extend(snd_data)
        if len(buf) >= 220500:

          process audio...


    except Queue.Empty:

我的问题是我注意到音频信号中出现奇怪的意外毛刺,好像程序暂时停止录制一些样本然后再次开始备份。我可以通过在Audacity中打开录制的wav文件并放大信号来看到这一点。我认为这是因为pyaudio在每1500个样本的单独线程中调用回调函数,有时它可能会尝试调用回调函数但是前一个回调函数的线程仍然打开,这个回调函数还没有完成,数据是仍然被添加到队列等(道歉,如果这是一个不连贯的解释,我不太确定使用什么术语)。

有谁知道如何解决这个问题?有没有一种方法可以同步它,这样每个回调函数只会在前一个回调函数处理完毕后被调用?

1 个答案:

答案 0 :(得分:0)

你应该非常小心你在回调函数中做了什么。最值得注意的是,您不应该在那里读取或写入文件。 您提到您正在编写文件仅用于调试,但实际上这可能会导致故障。

此外,您应该始终检查回调函数的status参数。这会告诉您是否有超支或欠款。 如果您遇到超支或欠载,可以尝试增加块大小(和延迟)直到它们消失。

这是我制作的一个示例脚本,用于记录声音文件:rec_unlimited.py。 以下是绘制输入信号的示例:plot_input.py。您可以对此进行调整以执行任何其他处理,而不是绘图。

  

有没有办法同步它,以便每个回调函数只能在前一个回调函数处理完毕后调用?

实际情况已经如此,对回调函数的调用永远不会重叠。但是,如果回调函数的一次调用花费的时间太长,则将生成的输出数据发送到声卡将为时已晚,并且必须丢弃此音频数据,从而导致可听见的丢失。这称为“输出欠载”。 如果先前调用回调函数花费的时间太长,则会有太多的音频输入数据可用,其中一些必须被丢弃,再次导致丢失。这被称为“输入溢出”。