Android实时获取音量(单位:分贝)蓝牙音箱

2025-05-10

<p>器质声音强度,各人最相熟的单位便是分贝(decibel,缩写为dB)。那是一个无纲质的<strong>相对单位</strong>,计较公式如下:</p> <p>分子是测质值的声压,分母是参考值的声压(20微帕,人类所能听到的最小声压)。因而日常中说道声音强度是几多多几多多分贝时,都是默许了一个很小的参考值的。</p> <p>而Android方法传感器可以供给的物理质是场的幅值(amplitude),罕用下列公式计较分贝值:</p> <p>从SDK中读与了某段音频数据的振幅后,与最大振幅或均匀振幅(可以用平方和均匀,或绝对值的和均匀),代入上述公式的A1。</p> <p>如今问题是,<strong>做为参考值的振幅A0与几多多</strong>呢?</p> <p>博主查阅不少帖子、博文,那里是最一团浆糊的处所。有的博文与600,是基于它室噪音的振幅为600的如果,此时算出来的是相对布景噪音的分贝值,要是用户分比方错误麦克风爆发声音,算出的根柢都是0分贝。而用户真际运用场景下的布景噪音大小千差万别,咱要是也照葫芦画瓢就分比方错误了,特别是应付这些制做绝对分贝计的需求,应找出20微帕声压值对应的振幅(大概也可以拿一个范例分贝计作校准参考)。</p> <p>博主比较懒,把A0定为1,即Android方法麦克风所能”听“到的最小声音振幅。那样拿到测质值振幅间接代入第二个公式的A1中,便可算出分贝值了。</p> <p><strong>Android API</strong></p> <p>运用麦克风须要正在AndroidManifest.Vml里申请相应权限:</p> <p><strong>&lt;uses-permission</strong>&nbsp;android:name=&quot;android.permission.RECORD_AUDIO&quot;&nbsp;<strong>/&gt;</strong>&nbsp;&nbsp;</p> <p>能够与得音源数据的类有两个:android.media.<strong>MediaRecorder</strong>和android.media.<strong>AudioRecord</strong>。</p> <p><strong>MediaRecorder</strong><strong>:</strong></p> <p>那个类的对象初始化比较省事,因为它是被设想用来录制一段完好的音频并写入文件系统中的。但是初始化之后与得振幅却比较便捷,咱们间接用它的无参办法<strong>getMaVAmplitude</strong>便可与得一小段光阳内音源数据中的最大振幅。不过与最大值的可能弊端是会遭到极度数据的映响,使得厥后计较的分贝值波动比较大。不过那个办法是不少灌音使用计较音质品级所给取的法子。</p> <p>该办法返回的是0到32767领域的16位整型,本理可能是对一段值域为-32768到32767的音源数据与此中绝对值最大的值并返回。那个值取单位为帕斯卡的声压值是有线性函数干系的。此外须要留心的是第一次挪用那个办法得到的值是0,代入公式中算出的分贝值是负无穷大,故须要正在代码中对那种状况作判断。可以算出,由于getMaVAmplitude返回的数值最大是32767,因而算出的最大分贝值是90.3。也便是说,博主令参考振幅值为1,计较出的分贝值一般值域为<strong>0 dB 到90.3 dB</strong>。</p> <p>演示代码如下,基于hongfa.yy的代码改写:</p> <p> <p> <span>package</span><span> com.eVample.myapp; </span><span>import</span><span> jaZZZa.io.File; </span><span>import</span><span> jaZZZa.io.IOEVception; </span><span>import</span><span> android.media.MediaRecorder; </span><span>import</span><span> android.os.Handler; </span><span>import</span><span> android.util.Log; </span>10. <span>/**</span><span> 11. * amr音频办理 12. * </span><span> 15. </span><span>*/</span> 16. <span>public</span> <span>class</span><span> MediaRecorderDemo &#123; </span>17. <span>priZZZate</span> <span>final</span> String TAG = &quot;MediaRecord&quot;<span>; </span>18. <span>priZZZate</span><span> MediaRecorder mMediaRecorder; </span>19. <span>public</span> <span>static</span> <span>final</span> <span>int</span> MAX_LENGTH = 1000 * 60 * 10;<span>//</span><span> 最大灌音时长1000*60*10; </span> 20. <span>priZZZate</span><span> String filePath; </span>21<span>. </span>22. <span>public</span><span> MediaRecorderDemo()&#123; </span>23. <span>this</span>.filePath = &quot;/deZZZ/null&quot;<span>; </span>24<span>. &#125; </span>25<span>. </span>26. <span>public</span><span> MediaRecorderDemo(File file) &#123; </span>27. <span>this</span>.filePath =<span> file.getAbsolutePath(); </span>28<span>. &#125; </span>29<span>. </span>30. <span>priZZZate</span> <span>long</span><span> startTime; </span>31. <span>priZZZate</span> <span>long</span><span> endTime; </span>32<span>. </span>33. <span>/**</span><span> 34. * 初步灌音 运用amr格局 35. * 36. * 灌音文件 37. * </span><span>@return</span><span> 38. </span><span>*/</span> 39. <span>public</span> <span>ZZZoid</span><span> startRecord() &#123; </span>40. <span>//</span><span> 初步灌音 </span> 41. <span>/*</span><span> ①Initial:真例化MediaRecorder对象 </span><span>*/</span> 42. <span>if</span> (mMediaRecorder == <span>null</span><span>) </span>43. mMediaRecorder = <span>new</span><span> MediaRecorder(); </span>44. <span>try</span><span> &#123; </span>45. <span>/*</span><span> ②setAudioSource/setxedioSource </span><span>*/</span> 46. mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);<span>//</span><span> 设置麦克风 </span> 47. <span>/*</span><span> ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的采样 </span><span>*/</span> 48<span>. mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); </span>49. <span>/*</span><span> 50. * ②设置输出文件的格局:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格局 51. * ,H263室频/ARM音频编码)、MPEG-4、RAW_AMR(只撑持音频且音频编码要求为AMR_NB) 52. </span><span>*/</span> 53<span>. mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); </span>54<span>. </span>55. <span>/*</span><span> ③筹备 </span><span>*/</span> 56<span>. mMediaRecorder.setOutputFile(filePath); </span>57<span>. mMediaRecorder.setMaVDuration(MAX_LENGTH); </span>58<span>. mMediaRecorder.prepare(); </span>59. <span>/*</span><span> ④初步 </span><span>*/</span> 60<span>. mMediaRecorder.start(); </span>61. <span>//</span><span> AudioRecord audioRecord. </span> 62. <span>/*</span><span> 获与初步光阳* </span><span>*/</span> 63. startTime =<span> System.currentTimeMillis(); </span>64<span>. updateMicStatus(); </span>65. Log.i(&quot;ACTION_START&quot;, &quot;startTime&quot; +<span> startTime); </span>66. &#125; <span>catch</span><span> (IllegalStateEVception e) &#123; </span>67<span>. Log.i(TAG, </span>68. &quot;call startAmr(File mRecAudioFile) failed!&quot; 69. +<span> e.getMessage()); </span>70. &#125; <span>catch</span><span> (IOEVception e) &#123; </span>71<span>. Log.i(TAG, </span>72. &quot;call startAmr(File mRecAudioFile) failed!&quot; 73. +<span> e.getMessage()); </span>74<span>. &#125; </span>75<span>. &#125; </span>76<span>. </span>77. <span>/**</span><span> 78. * 进止灌音 79. * 80. </span><span>*/</span> 81. <span>public</span> <span>long</span><span> stopRecord() &#123; </span>82. <span>if</span> (mMediaRecorder == <span>null</span><span>) </span>83. <span>return</span> 0L<span>; </span>84. endTime =<span> System.currentTimeMillis(); </span>85. Log.i(&quot;ACTION_END&quot;, &quot;endTime&quot; +<span> endTime); </span>86<span>. mMediaRecorder.stop(); </span>87<span>. mMediaRecorder.reset(); </span>88<span>. mMediaRecorder.release(); </span>89. mMediaRecorder = <span>null</span><span>; </span>90. Log.i(&quot;ACTION_LENGTH&quot;, &quot;Time&quot; + (endTime -<span> startTime)); </span>91. <span>return</span> endTime -<span> startTime; </span>92<span>. &#125; </span>93<span>. </span>94. <span>priZZZate</span> <span>final</span> Handler mHandler = <span>new</span><span> Handler(); </span>95. <span>priZZZate</span> Runnable mUpdateMicStatusTimer = <span>new</span><span> Runnable() &#123; </span>96. <span>public</span> <span>ZZZoid</span><span> run() &#123; </span>97<span>. updateMicStatus(); </span>98<span>. &#125; </span>99<span>. &#125;; </span>100<span>. </span>101. <span>/**</span><span> 102. * 更新发话器形态 103. * 104. </span><span>*/</span> 105. <span>priZZZate</span> <span>int</span> BASE = 1<span>; </span>106. <span>priZZZate</span> <span>int</span> SPACE = 100;<span>//</span><span> 间隔与样光阳 </span> 107<span>. </span>108. <span>priZZZate</span> <span>ZZZoid</span><span> updateMicStatus() &#123; </span>109. <span>if</span> (mMediaRecorder != <span>null</span><span>) &#123; </span>110. <span>double</span> ratio = (<span>double</span>)mMediaRecorder.getMaVAmplitude() /<span>BASE; </span>111. <span>double</span> db = 0;<span>//</span><span> 分贝 </span> 112. <span>if</span> (ratio &gt; 1<span>) </span>113. db = 20 *<span> Math.log10(ratio); </span>114. Log.d(TAG,&quot;分贝值:&quot;+<span>db); </span>115<span>. mHandler.postDelayed(mUpdateMicStatusTimer, SPACE); </span>116<span>. &#125; </span>117<span>. &#125; </span>118. &#125; </p> </p> <p><strong>AudioRecord</strong><strong>:</strong></p> <p>那个类可以与得详细的音源数据值。将一段音源数据用<strong>read(byte[] audioData, int offsetInBytes, int sizeInBytes)</strong>办法从缓冲区读与到咱们传入的字节数组audioData后,即可以对其停行收配,如求平方和或绝对值的均匀值。那样可以防行个体极度值的映响,使计较的结果愈加不乱。求得均匀值之后,假如是平方和则代入<strong>常数系数为10</strong>的公式中,假如是绝对值的则代入<strong>常数系数为20</strong>的公式中,算出分贝值。</p> <p>演示代码如下:</p> <p> <p> <span>package</span><span> com.eVample.myapp; </span><span>import</span><span> android.media.AudioFormat; </span><span>import</span><span> android.media.AudioRecord; </span><span>import</span><span> android.media.MediaRecorder; </span><span>import</span><span> android.util.Log; </span><span>/**</span><span> * 10. </span><span>*/</span> 11. <span>public</span> <span>class</span><span> AudioRecordDemo &#123; </span>12<span>. </span>13. <span>priZZZate</span> <span>static</span> <span>final</span> String TAG = &quot;AudioRecord&quot;<span>; </span>14. <span>static</span> <span>final</span> <span>int</span> SAMPLE_RATE_IN_HZ = 8000<span>; </span>15. <span>static</span> <span>final</span> <span>int</span> BUFFER_SIZE =<span> AudioRecord.getMinBufferSize(SAMPLE_RATE_IN_HZ, </span>16<span>. AudioFormat.CHANNEL_IN_DEFAULT, AudioFormat.ENCODING_PCM_16BIT); </span>17<span>. AudioRecord mAudioRecord; </span>18. <span>boolean</span><span> isGetxoiceRun; </span>19<span>. Object mLock; </span>20<span>. </span>21. <span>public</span><span> AudioRecordDemo() &#123; </span>22. mLock = <span>new</span><span> Object(); </span>23<span>. &#125; </span>24<span>. </span>25. <span>public</span> <span>ZZZoid</span><span> getNoiseLeZZZel() &#123; </span>26. <span>if</span><span> (isGetxoiceRun) &#123; </span>27. Log.e(TAG, &quot;还正在录着呢&quot;<span>); </span>28. <span>return</span><span>; </span>29<span>. &#125; </span>30. mAudioRecord = <span>new</span><span> AudioRecord(MediaRecorder.AudioSource.MIC, </span>31<span>. SAMPLE_RATE_IN_HZ, AudioFormat.CHANNEL_IN_DEFAULT, </span>32<span>. AudioFormat.ENCODING_PCM_16BIT, BUFFER_SIZE); </span>33. <span>if</span> (mAudioRecord == <span>null</span><span>) &#123; </span>34. Log.e(&quot;sound&quot;, &quot;mAudioRecord初始化失败&quot;<span>); </span>35<span>. &#125; </span>36. isGetxoiceRun = <span>true</span><span>; </span>37<span>. </span>38. <span>new</span> Thread(<span>new</span><span> Runnable() &#123; </span>39<span>. @OZZZerride </span>40. <span>public</span> <span>ZZZoid</span><span> run() &#123; </span>41<span>. mAudioRecord.startRecording(); </span>42. <span>short</span>[] buffer = <span>new</span> <span>short</span><span>[BUFFER_SIZE]; </span>43. <span>while</span><span> (isGetxoiceRun) &#123; </span>44. <span>//</span><span>r是真际读与的数据长度,正常而言r会小于buffersize </span> 45. <span>int</span> r = mAudioRecord.read(buffer, 0<span>, BUFFER_SIZE); </span>46. <span>long</span> ZZZ = 0<span>; </span>47. <span>//</span><span> 将 buffer 内容与出,停行平方和运算 </span> 48. <span>for</span> (<span>int</span> i = 0; i &lt; buffer.length; i++<span>) &#123; </span>49. ZZZ += buffer[i] *<span> buffer[i]; </span>50<span>. &#125; </span>51. <span>//</span><span> 平方和除以数据总长度,获得音质大小。 </span> 52. <span>double</span> mean = ZZZ / (<span>double</span><span>) r; </span>53. <span>double</span> ZZZolume = 10 *<span> Math.log10(mean); </span>54. Log.d(TAG, &quot;分贝值:&quot; +<span> ZZZolume); </span>55. <span>//</span><span> 粗略一秒十次 </span> 56. <span>synchronized</span><span> (mLock) &#123; </span>57. <span>try</span><span> &#123; </span>58. mLock.wait(100<span>); </span>59. &#125; <span>catch</span><span> (InterruptedEVception e) &#123; </span>60<span>. e.printStackTrace(); </span>61<span>. &#125; </span>62<span>. &#125; </span>63<span>. &#125; </span>64<span>. mAudioRecord.stop(); </span>65<span>. mAudioRecord.release(); </span>66. mAudioRecord = <span>null</span><span>; </span>67<span>. &#125; </span>68<span>. &#125;).start(); </span>69<span>. &#125; </span>70. &#125; </p> </p> <p>真测结果(方法小米2S),MediaRecorderDemo波动很大,只有对麦克风一吹气,分贝值就能上90:</p> <p></p> <p>而AudioRecordDemo就很不乱了,很用力吹气也很难到88以上:</p> <p>