bill最近在倒腾Android上录制声音的API——AudioRecord。但始终得到初始化失败的异常(最终原因是各大android设备所支持的音频采样率、声道数等不尽相同,虽然google官方说44100Hz是所有设备均支持的,但实际上......),甚是恼火。在stackoverflow上找到了灵感,并最终在Michael-Pardo的博客里发现了一个简洁且设计较好的工具类——AudioMeter。

Pardo对类的描述是AudioMeter包裹了AudioRecord,但bill在阅读后发现AudioMeter实际上隐藏了AudioRecord的接口(如read),当然Pardo的软件可能并不需要read接口,但作为AudioRecord的倒腾者,bill是需要的,因此对AudioMeter做了轻量级修改,开放了AudioRecord的部分常用接口,使用起来也比较方便,现分享出来,希望更多的朋友受益于此,大家可以根据自己的需要完善、扩充这个工具类:

  1. importjava.nio.ByteBuffer;
  2. importandroid.media.AudioFormat;
  3. importandroid.media.AudioRecord;
  4. importandroid.media.MediaRecorder.AudioSource;
  5. importandroid.os.Process;
  6. /**
  7. *BasicallywhatthisclassdoesisconstructavalidAudioRecordObject,wrapAudioRecordmethods,andprovide
  8. *conversiontodecibels.ItalsocachestheAudioRecordconfigurationandpreventsmultipleinstancesoftherecorder.
  9. *
  10. *@authorMichael-Pardo/billhoo
  11. *@version0.12013-2-18
  12. */
  13. //TODO(billhoo)theAudioMeter.createAudioRecord()methodalwaysreturnedthefirstmatchedconfigurationcurrently,
  14. //ifthefirstcombination[8000Hz+PCM16+IN_MONO]isvalid,methodreturns,butthereisnowayifIwannause
  15. //16000Hzinstead,sothismethodshouldbechangedtoacleveroneinthefuture.
  16. publicclassAudioMeterextendsThread{
  17. /////////////////////////////////////////////////////////////////
  18. //PRIVATECONSTANTS
  19. privatestaticfinalfloatMAX_REPORTABLE_AMP=32767f;
  20. privatestaticfinalfloatMAX_REPORTABLE_DB=90.3087f;
  21. /////////////////////////////////////////////////////////////////
  22. //PRIVATEMEMBERS
  23. privateAudioRecordmAudioRecord;
  24. privateintmSampleRate;
  25. privateshortmAudioFormat;
  26. privateshortmChannelConfig;
  27. privateshort[]mBuffer;
  28. privateintmBufferSize=AudioRecord.ERROR_BAD_VALUE;
  29. privateintmLocks=0;
  30. /////////////////////////////////////////////////////////////////
  31. //CONSTRUCTOR
  32. privateAudioMeter(){
  33. Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);//settheAudioMeterthreadinURGENT_AUDIO
  34. //priority.
  35. createAudioRecord();
  36. }
  37. /////////////////////////////////////////////////////////////////
  38. //PUBLICMETHODS
  39. publicstaticAudioMetergetInstance(){
  40. returnInstanceHolder.INSTANCE;
  41. }
  42. publicfloatgetAmplitude(){
  43. return(float)(MAX_REPORTABLE_DB+(20*Math.log10(getRawAmplitude()
  44. /MAX_REPORTABLE_AMP)));
  45. }
  46. publicsynchronizedvoidstartRecording(){
  47. if(mAudioRecord==null
  48. ||mAudioRecord.getState()!=AudioRecord.STATE_INITIALIZED){
  49. thrownewIllegalStateException(
  50. "startRecording()calledonanuninitializedAudioRecord.");
  51. }
  52. if(mLocks==0){
  53. mAudioRecord.startRecording();
  54. }
  55. mLocks++;
  56. }
  57. publicsynchronizedvoidstopRecording(){
  58. mLocks--;
  59. if(mLocks==0){
  60. if(mAudioRecord!=null){
  61. mAudioRecord.stop();
  62. mAudioRecord.release();
  63. mAudioRecord=null;
  64. }
  65. }
  66. }
  67. /**
  68. *Readsaudiodatafromtheaudiohardwareforrecordingintoadirectbuffer.Ifthisbufferisnotadirect
  69. *buffer,thismethodwillalwaysreturn0.
  70. *
  71. *@paramaudioBuffer
  72. *thedirectbuffertowhichtherecordedaudiodataiswritten.
  73. *@paramsizeInBytes
  74. *thenumberofrequestedbytes.
  75. *@returnthenumberofbytesthatwerereadoror{@link#ERROR_INVALID_OPERATION}iftheobjectwasn'tproperly
  76. *initialized,or{@link#ERROR_BAD_VALUE}iftheparametersdon'tresolvetovaliddataandindexes.The
  77. *numberofbyteswillnotexceedsizeInBytes.
  78. */
  79. publicintread(ByteBufferaudioBuffer,intsizeInBytes){
  80. returnmAudioRecord.read(audioBuffer,sizeInBytes);
  81. }
  82. /**
  83. *Readsaudiodatafromtheaudiohardwareforrecordingintoabuffer.
  84. *
  85. *@paramaudioData
  86. *thearraytowhichtherecordedaudiodataiswritten.
  87. *@paramoffsetInShorts
  88. *indexinaudioDatafromwhichthedataiswrittenexpressedinshorts.
  89. *@paramsizeInShorts
  90. *thenumberofrequestedshorts.
  91. *@returnthenumberofshortsthatwerereadoror{@link#ERROR_INVALID_OPERATION}iftheobjectwasn'tproperly
  92. *initialized,or{@link#ERROR_BAD_VALUE}iftheparametersdon'tresolvetovaliddataandindexes.The
  93. *numberofshortswillnotexceedsizeInShorts.
  94. */
  95. publicintread(short[]audioData,intoffsetInShorts,intsizeInShorts){
  96. returnmAudioRecord.read(audioData,offsetInShorts,sizeInShorts);
  97. }
  98. /**
  99. *Readsaudiodatafromtheaudiohardwareforrecordingintoabuffer.
  100. *
  101. *@paramaudioData
  102. *thearraytowhichtherecordedaudiodataiswritten.
  103. *@paramoffsetInBytes
  104. *indexinaudioDatafromwhichthedataiswrittenexpressedinbytes.
  105. *@paramsizeInBytes
  106. *thenumberofrequestedbytes.
  107. *@returnthenumberofbytesthatwerereadoror{@link#ERROR_INVALID_OPERATION}iftheobjectwasn'tproperly
  108. *initialized,or{@link#ERROR_BAD_VALUE}iftheparametersdon'tresolvetovaliddataandindexes.The
  109. *numberofbyteswillnotexceedsizeInBytes.
  110. */
  111. publicintread(byte[]audioData,intoffsetInBytes,intsizeInBytes){
  112. returnmAudioRecord.read(audioData,offsetInBytes,sizeInBytes);
  113. }
  114. /**
  115. *ReturnstheconfiguredaudiodatasamplerateinHz
  116. */
  117. publicintgetSampleRate(){
  118. returnmSampleRate;
  119. }
  120. /**
  121. *Returnstheconfiguredaudiodataformat.See{@linkAudioFormat#ENCODING_PCM_16BIT}and
  122. *{@linkAudioFormat#ENCODING_PCM_8BIT}.
  123. */
  124. publicintgetAudioFormat(){
  125. returnmAudioFormat;
  126. }
  127. /**
  128. *Returnstheconfiguredchannelconfiguration.See{@linkAudioFormat#CHANNEL_IN_MONO}and
  129. *{@linkAudioFormat#CHANNEL_IN_STEREO}.
  130. */
  131. publicintgetChannelConfiguration(){
  132. returnmChannelConfig;
  133. }
  134. /**
  135. *ReturnsthestateoftheAudioRecordinstance.ThisisusefulaftertheAudioRecordinstancehasbeencreatedto
  136. *checkifitwasinitializedproperly.Thisensuresthattheappropriatehardwareresourceshavebeenacquired.
  137. *
  138. *@seeAudioRecord#STATE_INITIALIZED
  139. *@seeAudioRecord#STATE_UNINITIALIZED
  140. */
  141. publicintgetAudioRecordState(){
  142. returnmAudioRecord.getState();
  143. }
  144. /////////////////////////////////////////////////////////////////
  145. //PRIVATEMETHODS
  146. privatevoidcreateAudioRecord(){
  147. if(mSampleRate>0&&mAudioFormat>0&&mChannelConfig>0){
  148. mAudioRecord=newAudioRecord(AudioSource.MIC,mSampleRate,
  149. mChannelConfig,mAudioFormat,mBufferSize);
  150. return;
  151. }
  152. //TODO(billhoo)shouldtryuser'sspecificcombinationsfirst,ifit'sinvalid,thendoforlooptogeta
  153. //availablecombinationinstead.
  154. //Findbest/compatibleAudioRecord
  155. //Ifallcombinationsareinvalid,throwIllegalStateException
  156. for(intsampleRate:newint[]{8000,11025,16000,22050,32000,
  157. 44100,47250,48000}){
  158. for(shortaudioFormat:newshort[]{
  159. AudioFormat.ENCODING_PCM_16BIT,
  160. AudioFormat.ENCODING_PCM_8BIT}){
  161. for(shortchannelConfig:newshort[]{
  162. AudioFormat.CHANNEL_IN_MONO,
  163. AudioFormat.CHANNEL_IN_STEREO,
  164. AudioFormat.CHANNEL_CONFIGURATION_MONO,
  165. AudioFormat.CHANNEL_CONFIGURATION_STEREO}){
  166. //Trytoinitialize
  167. try{
  168. mBufferSize=AudioRecord.getMinBufferSize(sampleRate,
  169. channelConfig,audioFormat);
  170. if(mBufferSize<0){
  171. continue;
  172. }
  173. mBuffer=newshort[mBufferSize];
  174. mAudioRecord=newAudioRecord(AudioSource.MIC,
  175. sampleRate,channelConfig,audioFormat,
  176. mBufferSize);
  177. if(mAudioRecord.getState()==AudioRecord.STATE_INITIALIZED){
  178. mSampleRate=sampleRate;
  179. mAudioFormat=audioFormat;
  180. mChannelConfig=channelConfig;
  181. return;
  182. }
  183. mAudioRecord.release();
  184. mAudioRecord=null;
  185. }catch(Exceptione){
  186. //Donothing
  187. }
  188. }
  189. }
  190. }
  191. //ADDED(billhoo)allcombinationsarefailedonthisdevice.
  192. thrownewIllegalStateException(
  193. "getInstance()failed:nosuitableaudioconfigurationsonthisdevice.");
  194. }
  195. privateintgetRawAmplitude(){
  196. if(mAudioRecord==null){
  197. createAudioRecord();
  198. }
  199. finalintbufferReadSize=mAudioRecord.read(mBuffer,0,mBufferSize);
  200. if(bufferReadSize<0){
  201. return0;
  202. }
  203. intsum=0;
  204. for(inti=0;i<bufferReadSize;i++){
  205. sum+=Math.abs(mBuffer[i]);
  206. }
  207. if(bufferReadSize>0){
  208. returnsum/bufferReadSize;
  209. }
  210. return0;
  211. }
  212. /////////////////////////////////////////////////////////////////
  213. //PRIVATECLASSES
  214. //Singleton
  215. privatestaticclassInstanceHolder{
  216. privatestaticfinalAudioMeterINSTANCE=newAudioMeter();
  217. }
  218. }

更多相关文章

  1. Google 联合 MIT 开源 Android(安卓)App Inventor
  2. 为Android安装BusyBox
  3. Android程序反编
  4. Android(安卓)AES加密工具类分享
  5. android驱动学习1-驱动开发流程(Android.mk)
  6. android实现富文本
  7. Android中的接口的使用举例
  8. 获取 Android(安卓)设备的唯一标识码
  9. Android自带音乐播放器代码分析(2)

随机推荐

  1. 需要知识的后深度学习时代,如何高效自动构
  2. 时代变了,这才是敏捷DevOps、低代码、微服
  3. 英特尔进击新能源发电,看AI如何用气象预报
  4. 在推荐系统中,我还有隐私吗?联邦学习:你可以
  5. CCKS 2020「基于标题的大规模商品实体检
  6. 10万字节跳动员工都在用的办公协同软件,如
  7. 让AI像Excel一样普及:这周末,我们聊了聊AI
  8. 如何从 0 到 1 构建埋点体系
  9. 微信小程序服务类目在哪里可以修改?
  10. 机器人是怎么知道如何抓握杯子的?