# -*- coding:utf-8 -*- from ssat_sdk.sat_environment import * from ssat_sdk.utils import LoggingUtil import os, sys, time import pyaudio import wave import threading import Queue READ_BUF_TIME = 0.02 #每帧长度20ms TAG = "audio_recorder" class ARecorder(): def __init__(self, CHANNELS=2,RATE=44100,WIDTH=2): self.pyaudio = None self.pyStream = None self.saveWav = False self.RecordStatus = 0#0停止录制,1正在录制 self.recordLock = threading.Condition() self.waveStatus = 0#0录制文件停止,1正在录制文件 self.waveFile = "" self.frameQue = Queue.Queue()#存储录制的音频帧 self.frameBufMax = 0 #每次录取的Buffer采集次数,也就是frameQue会存数据的次数。做到音频长度精准控制 '''Record param 44.1KHZ,16bit;96khz,24bit;192Khz,32bit ''' self.CHANNELS = CHANNELS self.RATE = RATE self.WIDTH = WIDTH # 采样时的字节宽度。2代表16bit self.FORMAT = pyaudio.get_format_from_width(WIDTH) # RATE = 192000 # FORMAT = pyaudio.paInt32 ''' 查询录音设备状态 True:正常,False:异常 ''' def getStatus(self): pa = pyaudio.PyAudio() devInfo = pa.get_default_input_device_info() print "getDeviceStatus,",devInfo if devInfo is None or len(devInfo) < 1: return False else: return True ''' 录制wave文件,可以设定录制的时间,单位s。 ''' def recordWave(self, filePath, time, channels = 2): print "Recording wave..." self.pyaudio = pyaudio.PyAudio() self.pyStream = self.pyaudio.open(format=self.FORMAT, channels=channels, rate=self.RATE, input=True, output=False, frames_per_buffer=self.CHUNK*channels) print("* recording") frames = [] for i in range(0, int(self.RATE / self.CHUNK * time)): data = self.pyStream.read(self.CHUNK) frames.append(data) print("* done") self.pyStream.stop_stream() self.pyStream.close() self.pyaudio.terminate() wf = wave.open(filePath, 'wb') wf.setnchannels(channels) wf.setsampwidth(self.WIDTH) wf.setframerate(self.RATE) wf.writeframes(b''.join(frames)) wf.close() def monitor(self,timeL,saveWave = False, waveFile=None, buf_time=None): self.recordLock.acquire() if waveFile is not None: self.waveFile = waveFile else: self.waveFile = None if buf_time is None: # 每次读取的帧数。人耳最低分辨频率20Hz,所以每次抓取0.02秒的数据。方便计算短时能。 self.CHUNK = int(self.RATE * READ_BUF_TIME) else: self.CHUNK = int(self.RATE * buf_time) self.frameBufMax = timeL * (self.RATE/self.CHUNK) self.frameBufDel = 1*(self.RATE/self.CHUNK) #前1秒录取的音频,需要删掉,采集的音频不准。 tryMax = 6 audioEnable = False while tryMax > 0:#在音频设备启动失败时,尝试6次,每次间隔0.5秒 tryMax -= 1 try: self.pyaudio = pyaudio.PyAudio() LoggingUtil.printLog(TAG,self.pyaudio.get_default_input_device_info()) self.pyStream = self.pyaudio.open(rate=self.RATE, channels=self.CHANNELS, format=self.FORMAT, input=True, frames_per_buffer=self.CHUNK, stream_callback=self.streamCallBack) LoggingUtil.printLog("AudioRecorder monitor, device init success!") audioEnable = True break except Exception,e: audioEnable = False LoggingUtil.printLog("AudioRecorder monitor, Error:"+e.message) if self.pyStream is not None: self.pyStream.close() self.pyStream = None if self.pyaudio is not None: self.pyaudio.terminate() self.pyaudio = None time.sleep(0.5) if audioEnable is False: return self.initRecordStatus(saveWave) LoggingUtil.printLog("Record sound....") self.pyStream.start_stream() self.recordLock.wait() #等待录音结束 self.recordLock.release() LoggingUtil.printLog("Record sound End") def streamCallBack(self, in_data,frame_count,time_info,status_flags): # print "streamCallBack.Thread:", threading.currentThread().getName() # print "Recording.streamCallBack:frame_count:",frame_count,";time_info:",time_info,";status_flags:",status_flags self.frameBufDel = self.frameBufDel - 1 #舍弃前1秒钟的音频内容 if self.frameBufDel > 0: return (None, pyaudio.paContinue) self.frameBufMax = self.frameBufMax - 1 self.frameQue.put_nowait(in_data) if self.saveWav is True: self.saveWavFrame(in_data) if self.frameBufMax <= 0: self.closeRecord() return (None, pyaudio.paComplete) else: return (None, pyaudio.paContinue) def initRecordStatus(self,saveWave): self.RecordStatus = 1 self.saveWav = saveWave if self.saveWav is True: self.initWavSave() def closeRecord(self): self.RecordStatus = 0 self.recordLock.acquire() self.recordLock.notify() self.recordLock.release() # self.pyStream.stop_stream() self.pyStream.close() self.pyaudio.terminate() if self.saveWav is True: self.closeWavSave() def initWavSave(self): if self.waveFile is None: self.waveFile = os.path.join(getSATTmpDIR(), "monitorSound" + str(time.time()) + ".wav") print "SoundTool, initWaveSave,audioRecord:", self.waveFile try: self.wf = wave.open(self.waveFile, 'wb') self.wf.setnchannels(self.CHANNELS) self.wf.setsampwidth(self.WIDTH) self.wf.setframerate(self.RATE) self.waveStatus = 1 return self.waveFile except Exception,e: LoggingUtil.printLog(TAG, "initWavSave.Audio Recorder File Open Fail!") def saveWavFrame(self, frame): # print "saveWavFrame,frame:",frame try: self.wf.writeframes(frame) except Exception,e: LoggingUtil.printLog(TAG, "saveWavFrame.Audio Recorder wave not exits!") def closeWavSave(self): try: self.wf.close() self.wf = None self.waveStatus = 0 except Exception,e: LoggingUtil.printLog(TAG, "closeWavSave.Audio Recorder wave not exits!") # print "closeWavSave.Audio Recorder wave not exits!", e def getWavFile(self): if self.saveWav is True: return self.waveFile else: return None def getFrameQue(self): return self.frameQue if __name__ == "__main__": recorder = ARecorder() # recorder.recordWave("test1.wav",5) recorder.monitor(3,True) # print 11111 # recorder.monitor(3,True) # print 22222 # recorder.monitor(3,True) # print 33333