如何在不同Android设备中得到有效的AudioRecord实例
16lz
2021-01-24
bill最近在倒腾Android上录制声音的API——AudioRecord。但始终得到初始化失败的异常(最终原因是各大android设备所支持的音频采样率、声道数等不尽相同,虽然google官方说44100Hz是所有设备均支持的,但实际上......),甚是恼火。在stackoverflow上找到了灵感,并最终在Michael-Pardo的博客里发现了一个简洁且设计较好的工具类——AudioMeter。
Pardo对类的描述是AudioMeter包裹了AudioRecord,但bill在阅读后发现AudioMeter实际上隐藏了AudioRecord的接口(如read),当然Pardo的软件可能并不需要read接口,但作为AudioRecord的倒腾者,bill是需要的,因此对AudioMeter做了轻量级修改,开放了AudioRecord的部分常用接口,使用起来也比较方便,现分享出来,希望更多的朋友受益于此,大家可以根据自己的需要完善、扩充这个工具类:
- importjava.nio.ByteBuffer;
- importandroid.media.AudioFormat;
- importandroid.media.AudioRecord;
- importandroid.media.MediaRecorder.AudioSource;
- importandroid.os.Process;
- /**
- *BasicallywhatthisclassdoesisconstructavalidAudioRecordObject,wrapAudioRecordmethods,andprovide
- *conversiontodecibels.ItalsocachestheAudioRecordconfigurationandpreventsmultipleinstancesoftherecorder.
- *
- *@authorMichael-Pardo/billhoo
- *@version0.12013-2-18
- */
- //TODO(billhoo)theAudioMeter.createAudioRecord()methodalwaysreturnedthefirstmatchedconfigurationcurrently,
- //ifthefirstcombination[8000Hz+PCM16+IN_MONO]isvalid,methodreturns,butthereisnowayifIwannause
- //16000Hzinstead,sothismethodshouldbechangedtoacleveroneinthefuture.
- publicclassAudioMeterextendsThread{
- /////////////////////////////////////////////////////////////////
- //PRIVATECONSTANTS
- privatestaticfinalfloatMAX_REPORTABLE_AMP=32767f;
- privatestaticfinalfloatMAX_REPORTABLE_DB=90.3087f;
- /////////////////////////////////////////////////////////////////
- //PRIVATEMEMBERS
- privateAudioRecordmAudioRecord;
- privateintmSampleRate;
- privateshortmAudioFormat;
- privateshortmChannelConfig;
- privateshort[]mBuffer;
- privateintmBufferSize=AudioRecord.ERROR_BAD_VALUE;
- privateintmLocks=0;
- /////////////////////////////////////////////////////////////////
- //CONSTRUCTOR
- privateAudioMeter(){
- Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);//settheAudioMeterthreadinURGENT_AUDIO
- //priority.
- createAudioRecord();
- }
- /////////////////////////////////////////////////////////////////
- //PUBLICMETHODS
- publicstaticAudioMetergetInstance(){
- returnInstanceHolder.INSTANCE;
- }
- publicfloatgetAmplitude(){
- return(float)(MAX_REPORTABLE_DB+(20*Math.log10(getRawAmplitude()
- /MAX_REPORTABLE_AMP)));
- }
- publicsynchronizedvoidstartRecording(){
- if(mAudioRecord==null
- ||mAudioRecord.getState()!=AudioRecord.STATE_INITIALIZED){
- thrownewIllegalStateException(
- "startRecording()calledonanuninitializedAudioRecord.");
- }
- if(mLocks==0){
- mAudioRecord.startRecording();
- }
- mLocks++;
- }
- publicsynchronizedvoidstopRecording(){
- mLocks--;
- if(mLocks==0){
- if(mAudioRecord!=null){
- mAudioRecord.stop();
- mAudioRecord.release();
- mAudioRecord=null;
- }
- }
- }
- /**
- *Readsaudiodatafromtheaudiohardwareforrecordingintoadirectbuffer.Ifthisbufferisnotadirect
- *buffer,thismethodwillalwaysreturn0.
- *
- *@paramaudioBuffer
- *thedirectbuffertowhichtherecordedaudiodataiswritten.
- *@paramsizeInBytes
- *thenumberofrequestedbytes.
- *@returnthenumberofbytesthatwerereadoror{@link#ERROR_INVALID_OPERATION}iftheobjectwasn'tproperly
- *initialized,or{@link#ERROR_BAD_VALUE}iftheparametersdon'tresolvetovaliddataandindexes.The
- *numberofbyteswillnotexceedsizeInBytes.
- */
- publicintread(ByteBufferaudioBuffer,intsizeInBytes){
- returnmAudioRecord.read(audioBuffer,sizeInBytes);
- }
- /**
- *Readsaudiodatafromtheaudiohardwareforrecordingintoabuffer.
- *
- *@paramaudioData
- *thearraytowhichtherecordedaudiodataiswritten.
- *@paramoffsetInShorts
- *indexinaudioDatafromwhichthedataiswrittenexpressedinshorts.
- *@paramsizeInShorts
- *thenumberofrequestedshorts.
- *@returnthenumberofshortsthatwerereadoror{@link#ERROR_INVALID_OPERATION}iftheobjectwasn'tproperly
- *initialized,or{@link#ERROR_BAD_VALUE}iftheparametersdon'tresolvetovaliddataandindexes.The
- *numberofshortswillnotexceedsizeInShorts.
- */
- publicintread(short[]audioData,intoffsetInShorts,intsizeInShorts){
- returnmAudioRecord.read(audioData,offsetInShorts,sizeInShorts);
- }
- /**
- *Readsaudiodatafromtheaudiohardwareforrecordingintoabuffer.
- *
- *@paramaudioData
- *thearraytowhichtherecordedaudiodataiswritten.
- *@paramoffsetInBytes
- *indexinaudioDatafromwhichthedataiswrittenexpressedinbytes.
- *@paramsizeInBytes
- *thenumberofrequestedbytes.
- *@returnthenumberofbytesthatwerereadoror{@link#ERROR_INVALID_OPERATION}iftheobjectwasn'tproperly
- *initialized,or{@link#ERROR_BAD_VALUE}iftheparametersdon'tresolvetovaliddataandindexes.The
- *numberofbyteswillnotexceedsizeInBytes.
- */
- publicintread(byte[]audioData,intoffsetInBytes,intsizeInBytes){
- returnmAudioRecord.read(audioData,offsetInBytes,sizeInBytes);
- }
- /**
- *ReturnstheconfiguredaudiodatasamplerateinHz
- */
- publicintgetSampleRate(){
- returnmSampleRate;
- }
- /**
- *Returnstheconfiguredaudiodataformat.See{@linkAudioFormat#ENCODING_PCM_16BIT}and
- *{@linkAudioFormat#ENCODING_PCM_8BIT}.
- */
- publicintgetAudioFormat(){
- returnmAudioFormat;
- }
- /**
- *Returnstheconfiguredchannelconfiguration.See{@linkAudioFormat#CHANNEL_IN_MONO}and
- *{@linkAudioFormat#CHANNEL_IN_STEREO}.
- */
- publicintgetChannelConfiguration(){
- returnmChannelConfig;
- }
- /**
- *ReturnsthestateoftheAudioRecordinstance.ThisisusefulaftertheAudioRecordinstancehasbeencreatedto
- *checkifitwasinitializedproperly.Thisensuresthattheappropriatehardwareresourceshavebeenacquired.
- *
- *@seeAudioRecord#STATE_INITIALIZED
- *@seeAudioRecord#STATE_UNINITIALIZED
- */
- publicintgetAudioRecordState(){
- returnmAudioRecord.getState();
- }
- /////////////////////////////////////////////////////////////////
- //PRIVATEMETHODS
- privatevoidcreateAudioRecord(){
- if(mSampleRate>0&&mAudioFormat>0&&mChannelConfig>0){
- mAudioRecord=newAudioRecord(AudioSource.MIC,mSampleRate,
- mChannelConfig,mAudioFormat,mBufferSize);
- return;
- }
- //TODO(billhoo)shouldtryuser'sspecificcombinationsfirst,ifit'sinvalid,thendoforlooptogeta
- //availablecombinationinstead.
- //Findbest/compatibleAudioRecord
- //Ifallcombinationsareinvalid,throwIllegalStateException
- for(intsampleRate:newint[]{8000,11025,16000,22050,32000,
- 44100,47250,48000}){
- for(shortaudioFormat:newshort[]{
- AudioFormat.ENCODING_PCM_16BIT,
- AudioFormat.ENCODING_PCM_8BIT}){
- for(shortchannelConfig:newshort[]{
- AudioFormat.CHANNEL_IN_MONO,
- AudioFormat.CHANNEL_IN_STEREO,
- AudioFormat.CHANNEL_CONFIGURATION_MONO,
- AudioFormat.CHANNEL_CONFIGURATION_STEREO}){
- //Trytoinitialize
- try{
- mBufferSize=AudioRecord.getMinBufferSize(sampleRate,
- channelConfig,audioFormat);
- if(mBufferSize<0){
- continue;
- }
- mBuffer=newshort[mBufferSize];
- mAudioRecord=newAudioRecord(AudioSource.MIC,
- sampleRate,channelConfig,audioFormat,
- mBufferSize);
- if(mAudioRecord.getState()==AudioRecord.STATE_INITIALIZED){
- mSampleRate=sampleRate;
- mAudioFormat=audioFormat;
- mChannelConfig=channelConfig;
- return;
- }
- mAudioRecord.release();
- mAudioRecord=null;
- }catch(Exceptione){
- //Donothing
- }
- }
- }
- }
- //ADDED(billhoo)allcombinationsarefailedonthisdevice.
- thrownewIllegalStateException(
- "getInstance()failed:nosuitableaudioconfigurationsonthisdevice.");
- }
- privateintgetRawAmplitude(){
- if(mAudioRecord==null){
- createAudioRecord();
- }
- finalintbufferReadSize=mAudioRecord.read(mBuffer,0,mBufferSize);
- if(bufferReadSize<0){
- return0;
- }
- intsum=0;
- for(inti=0;i<bufferReadSize;i++){
- sum+=Math.abs(mBuffer[i]);
- }
- if(bufferReadSize>0){
- returnsum/bufferReadSize;
- }
- return0;
- }
- /////////////////////////////////////////////////////////////////
- //PRIVATECLASSES
- //Singleton
- privatestaticclassInstanceHolder{
- privatestaticfinalAudioMeterINSTANCE=newAudioMeter();
- }
- }
更多相关文章
- Google 联合 MIT 开源 Android(安卓)App Inventor
- 为Android安装BusyBox
- Android程序反编
- Android(安卓)AES加密工具类分享
- android驱动学习1-驱动开发流程(Android.mk)
- android实现富文本
- Android中的接口的使用举例
- 获取 Android(安卓)设备的唯一标识码
- Android自带音乐播放器代码分析(2)