# -*- 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.recordLastTime = 0 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 self.devName = "" def setDeviceName(self,devName): self.devName = devName ''' 查找设备index。 :return :None表示用默认设备,-1表示找不到指定设备,正整数表示找到的设备索引index。 ''' def getDeviceIndex(self): if self.devName.__len__() < 1: LoggingUtil.printLog("采用默认录音设备") return None else: pa = pyaudio.PyAudio() count = pa.get_device_count() realName = getSoundDevice(self.devName) print "getDeviceIndex,devName:%s, realName:%s"%(self.devName,realName) for index in range(count): soundDev = pa.get_device_info_by_index(index) print "getDeviceIndex,soundDev:",soundDev if soundDev.has_key("name") and soundDev["name"].find(realName) > -1: LoggingUtil.printLog("采用录音设备:"+realName) return index LoggingUtil.printLog("未找到指定录音设备") return -1 ''' 查询录音设备状态 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 "recordWave,Start to record wave..." self.pyaudio = pyaudio.PyAudio() # 获取设备数量; # device_count = self.pyaudio.get_device_count() # http://people.csail.mit.edu/hubert/pyaudio/docs/ devIndex = self.getDeviceIndex() if devIndex == -1: return self.pyStream = self.pyaudio.open(format=self.FORMAT, channels=channels, rate=self.RATE, input=True, output=False, frames_per_buffer=self.CHUNK*channels, input_device_index = devIndex, output_device_index = None) print("recordWave, recording") frames = [] for i in range(0, int(self.RATE / self.CHUNK * time)): data = self.pyStream.read(self.CHUNK) frames.append(data) print("recordWave, 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): print "audio_recorder,monitor start" 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 print "audio_recorder,tryMax:",tryMax try: self.pyaudio = pyaudio.PyAudio() devIndex = self.getDeviceIndex() if devIndex == -1: LoggingUtil.printLog(TAG, self.pyaudio.get_default_input_device_info()) return elif devIndex is None: LoggingUtil.printLog(TAG,self.pyaudio.get_default_input_device_info()) else: LoggingUtil.printLog(TAG, self.pyaudio.get_device_info_by_index(devIndex)) 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, input_device_index = devIndex) LoggingUtil.printLog("AudioRecorder monitor, device init success!") audioEnable = True break except Exception,e: audioEnable = False LoggingUtil.printLog("AudioRecorder monitor, Error:"+e.message) self.releaseRecord() self.closeRecord() time.sleep(0.5) if audioEnable is False: return self.initRecordStatus(saveWave) LoggingUtil.printLog("Record sound....") self.recordLastTime = time.time() self.pyStream.start_stream() while self.RecordStatus == 1:#等待录音结束 curTime = time.time() dtime = curTime - self.recordLastTime if buf_time is None and dtime > READ_BUF_TIME * 10: self.releaseRecord() elif dtime > buf_time*10: self.releaseRecord() self.closeRecord() 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.recordLastTime = time.time() 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.releaseRecord() 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 releaseRecord(self): print "releaseRecord" self.RecordStatus = 0 def closeRecord(self): print "closeRecord" # self.pyStream.stop_stream() if self.pyStream is not None and self.pyStream.is_stopped(): # print "stop pyStream" self.pyStream.stop_stream() if self.pyStream is not None: # print "close pyStream" self.pyStream.close() self.pyStream = None if self.pyaudio is not None: # print "close pyaudio" self.pyaudio.terminate() self.pyaudio = None 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: print "close Wave file" 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