我正在尝试使用python和pyaudio进行一些实时音频处理。问题是我无法使输入流正常工作(回调版本)。想法是:
虽然输出流工作正常,但输入流似乎与数据完全不同步。一张声卡(USB)上的缓冲区录制时间为3.6秒至5.8秒,PCI声卡的录制时间约为13秒。更令人困惑的是,简单的in->输出线如本例中https://gist.github.com/fwaechter/8795472正常工作。两个流报告的cpu负载非常小~0.002。
这是代码(剥离):
import Queue, scipy, numpy, pyaudio
class chrono:
def __init__(self, indev=4, outdev=6, clockt=200, samplerate=48000, buflen=131072, lowpass=10000, highpass=2000):
self.samplerate = samplerate
self.buffer_len = buflen
self.frames_per_buf = 4096
self.err_cnt1 = 0
self.err_cnt2 = 0
self.ain_queue = Queue(maxsize=1000)
self.aout_queue = Queue(maxsize=1000)
self.indata = {"dat":scipy.zeros(self.buffer_len, dtype="int16"), "cur_frame": 0, "start_tm": 0.0}
self.outdata = {"dat":scipy.zeros(self.buffer_len, dtype="int16"), "cur_frame": self.buffer_len, "out_buf2":scipy.zeros(self.frames_per_buf*2, dtype="int16")}
self.pya = pyaudio.PyAudio()
printd("chrono.__init__: Audio devices:")
for i in range(self.pya.get_device_count()):
cdev = self.pya.get_device_info_by_index(i)
printd("chrono.__init__\tDev: %d: Name %s, Input channels %d, Output channels %d, Sample rate %d"%(i,cdev["name"],\
cdev["maxInputChannels"],cdev["maxOutputChannels"],cdev["defaultSampleRate"]))
self.auin_channels = self.pya.get_device_info_by_index(indev)["maxInputChannels"]
self.auout_channels = self.pya.get_device_info_by_index(outdev)["maxOutputChannels"]
self.pya.is_format_supported(rate=self.samplerate, input_device=indev, input_channels=self.auin_channels, input_format=pyaudio.paInt16)
self.pya.is_format_supported(rate=self.samplerate, output_device=outdev, output_channels=self.auout_channels, output_format=pyaudio.paInt16)
self.auin = pyaudio.Stream(PA_manager=self.pya, rate=self.samplerate, channels=self.auin_channels, format=pyaudio.paInt16, input=True, \
input_device_index=indev, frames_per_buffer=self.frames_per_buf, stream_callback=self.audio_in, start=False)
self.auout = pyaudio.Stream(PA_manager=self.pya, rate=self.samplerate, channels=self.auout_channels, format=pyaudio.paInt16, output=True, \
output_device_index=outdev, frames_per_buffer=self.frames_per_buf, stream_callback=self.audio_out, start=False)
return
def close(self):
self.auin.stop_stream()
self.auout.stop_stream()
self.auin.close()
self.auout.close()
self.pya.terminate()
return
def __del__(self):
return self.close()
def audio_in(self, data, frame_count, time_info, status):
self.err_cnt1 += 1
if (self.auin_channels == 2):
data = numpy.fromstring(data, dtype="int16")
self.indata["dat"][self.indata["cur_frame"]:self.indata["cur_frame"]+frame_count] = \
(data[0::2].astype("int32") + data[1::2]) / 2 # get mean of both channels
else:
self.indata["dat"][self.indata["cur_frame"]:self.indata["cur_frame"]+frame_count] = numpy.fromstring(data, dtype="int16")
if (self.indata["cur_frame"] == 0): # keep track of time - this is start of buffer
self.indata["start_tm"] = time_info["input_buffer_adc_time"]
self.indata["cur_frame"] += frame_count # keep track of data position in buffer
if (self.indata["cur_frame"] >= self.buffer_len):
self.indata["cur_frame"] = 0
self.ain_queue.put((self.indata["dat"].astype("float"), self.indata["start_tm"], time_info["current_time"])) # put new full buffer into queue
return(None, pyaudio.paContinue)
def audio_out(self, data, frame_count, time_info, status):
self.err_cnt2 += 1
if (self.outdata["cur_frame"] >= self.buffer_len):
try:
self.outdata["dat"] = self.aout_queue.get_nowait().astype("int16")
except:
return("\0"*frame_count*2*self.auout_channels, pyaudio.paContinue)
self.outdata["cur_frame"] = 0
self.aout_queue.task_done()
if (self.auout_channels == 2):
samples = self.outdata["dat"][self.outdata["cur_frame"]:self.outdata["cur_frame"]+frame_count]
self.outdata["out_buf2"][0::2] = samples
self.outdata["out_buf2"][1::2] = samples
data = self.outdata["out_buf2"].tostring()
else:
data = (self.outdata["dat"][self.outdata["cur_frame"]:self.outdata["cur_frame"]+frame_count]).tostring()
self.outdata["cur_frame"] += frame_count
return(data, pyaudio.paContinue)
def go(self, cnt=5):
self.auin.start_stream()
self.auout.start_stream()
while(cnt>0):
dat = self.ain_queue.get(timeout=15)
print("rec time %f"%(dat[2]-dat[1]))
self.aout_queue.put(dat[0])
cnt -= 1
print(cnt)
self.ain_queue.task_done()
self.auin.stop_stream()
self.auout.stop_stream()
return dat
通过以下方式验证代码:
import chrono.py
tst = chrono.chrono()
tst.go(10)
我正在研究gentoo Linux,python 2.7和pyaudio 2.9。 我在这里错过了什么? 在此先感谢Michael Widlok