<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                這個用例很簡單,但其中會有一些重要概念,應注意理解。 注意:要了解AudioTrack Java API的具體信息,需要仔細閱讀Android API中的相關文檔。閱讀API文檔,是一個能快速掌握相關知識的好方法。 **AudioTrackAPI使用例子(Java層)** ~~~ //① 根據音頻數據的特性來確定所要分配的緩沖區的最小size int bufsize = AudioTrack.getMinBufferSize(8000,//采樣率:每秒8K個點    AudioFormat.CHANNEL_CONFIGURATION_STEREO,//聲道數:雙聲道 AudioFormat.ENCODING_PCM_16BIT//采樣精度:一個采樣點16比特,相當于2個字節 ); //② 創建AudioTrack AudioTrack trackplayer = new AudioTrack( AudioManager.STREAM_MUSIC,//音頻流類型 8000,AudioFormat.CHANNEL_CONFIGURATION_ STEREO,    AudioFormat.ENCODING_PCM_16BIT, bufsize, AudioTrack.MODE_STREAM//數據加載模式); //③ 開始播放 trackplayer.play() ; ...... //④ 調用write寫數據 trackplayer.write(bytes_pkg, 0,bytes_pkg.length) ;//往track中寫數據 ...... //⑤ 停止播放和釋放資源 trackplayer.stop();//停止播放 trackplayer.release();//釋放底層資源 ~~~ 上面的用例引入了兩個新的概念,一個是數據加載模式,另一個是音頻流類型。下面進行詳細介紹。 1. AudioTrack的數據加載模式 AudioTrack有兩種數據加載模式:MODE_STREAM和MODE_STATIC,它們對應著兩種完全不同的使用場景。 - MODE_STREAM:在這種模式下,通過write一次次把音頻數據寫到AudioTrack中。這和平時通過write系統調用往文件中寫數據類似,但這種工作方式每次都需要把數據從用戶提供的Buffer中拷貝到AudioTrack內部的Buffer中,這在一定程度上會使引入延時。為解決這一問題,AudioTrack就引入了第二種模式。 * MODE_STATIC:這種模式下,在play之前只需要把所有數據通過一次write調用傳遞到AudioTrack中的內部緩沖區,后續就不必再傳遞數據了。這種模式適用于像鈴聲這種內存占用量較小,延時要求較高的文件。但它也有一個缺點,就是一次write的數據不能太多,否則系統無法分配足夠的內存來存儲全部數據。 這兩種模式中以MODE_STREAM模式相對常見和復雜,我們的分析將以它為主。 >[info]**注意**:如果采用STATIC模式,須先調用write寫數據,然后再調用play。 2. 音頻流的類型 在AudioTrack構造函數中,會接觸到AudioManager.STREAM_MUSIC這個參數。它的含義與Android系統對音頻流的管理和分類有關。 Android將系統的聲音分為好幾種流類型,下面是幾個常見的: - STREAM_ALARM:警告聲 - STREAM_MUSIC:音樂聲,例如music等 - STREAM_RING:鈴聲 - STREAM_SYSTEM:系統聲音,例如低電提示音,鎖屏音等 - STREAM_VOCIE_CALL:通話聲 * * * * * **注意**:上面這些類型的劃分和音頻數據本身并沒有關系。例如MUSIC和RING類型都可以是某首MP3歌曲。另外,聲音流類型的選擇沒有固定的標準,例如,鈴聲預覽中的鈴聲可以設置為MUSIC類型。 * * * * * 音頻流類型的劃分和Audio系統對音頻的管理策略有關。其具體作用,在以后的分析中再做詳細介紹。在目前的用例中,把它當做一個普通數值即可。 3. Buffer分配和Frame的概念 在用例中碰到的第一個重要函數就是getMinBufferSize。這個函數對于確定應用層分配多大的數據Buffer具有重要指導意義。先回顧一下它的調用方式: **AudioTrackAPI使用例子(Java層)** ~~~ //注意這些參數的值。想象我們正在一步步的Trace,這些參數都會派上用場 AudioTrack.getMinBufferSize(8000,//每秒8K個點    AudioFormat.CHANNEL_CONFIGURATION_STEREO,//雙聲道 AudioFormat.ENCODING_PCM_16BIT); ~~~ 來看這個函數的實現: **AudioTrack.java** ~~~ static public int getMinBufferSize(intsampleRateInHz, int channelConfig, intaudioFormat) { int channelCount = 0; switch(channelConfig) { case AudioFormat.CHANNEL_OUT_MONO: caseAudioFormat.CHANNEL_CONFIGURATION_MONO: channelCount = 1; break; case AudioFormat.CHANNEL_OUT_STEREO: case AudioFormat.CHANNEL_CONFIGURATION_STEREO: channelCount = 2;//目前最多支持雙聲道 break; default: return AudioTrack.ERROR_BAD_VALUE; } //目前只支持PCM8和PCM16精度的音頻數據 if((audioFormat != AudioFormat.ENCODING_PCM_16BIT) && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) { return AudioTrack.ERROR_BAD_VALUE; } //對采樣頻率也有要求,太低或太高都不行。 if( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) return AudioTrack.ERROR_BAD_VALUE; /* 調用Native函數,先想想為什么,如果是簡單計算,那么Java層做不到嗎? 原來,還需要確認硬件是否支持這些參數,當然得進入Native層查詢了 */ int size = native_get_min_buff_size(sampleRateInHz, channelCount,audioFormat); if((size == -1) || (size == 0)) { return AudioTrack.ERROR; } else { return size; } } ~~~ Native的函數將查詢Audio系統中音頻輸出硬件HAL對象的一些信息,并確認它們是否支持這些采樣率和采樣精度。 說明:HAL對象的具體實現和硬件廠商有關系,如果沒有特殊說明,我們則把硬件和HAL作為一種東西討論。 來看Native的native_get_min_buff_size函數。它在android_media_track.cpp中。 **android_media_track.cpp** ~~~ /* 注意我們傳入的參數是: sampleRateInHertz = 8000,nbChannels = 2 audioFormat = AudioFormat.ENCODING_PCM_16BIT */ static jintandroid_media_AudioTrack_get_min_buff_size( JNIEnv*env, jobject thiz, jintsampleRateInHertz, jint nbChannels, jint audioFormat) { intafSamplingRate; intafFrameCount; uint32_t afLatency; /* 下面這些調用涉及了AudioSystem,這個和AudioPolicy有關系。這里僅把它們看成是 信息查詢即可 */ //查詢采樣率,一般返回的是所支持的最高采樣率,例如44100 if(AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) { return -1; } //① 查詢硬件內部緩沖的大小,以Frame為單位。什么是Frame? if(AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) { return -1; } //查詢硬件的延時時間 if(AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) { return -1; } ...... ~~~ 這里有必要插入內容,因為代碼中出現了音頻系統中的一個重要概念:Frame(幀)。 說明:Frame是一個單位,經多方查尋,最終在ALSA的wiki中找到了對它的解釋。Frame直觀上用來描述數據量的多少,例如,一幀等于多少字節。1單位的Frame等于1個采樣點的字節數×聲道數(比如PCM16,雙聲道的1個Frame等于2×2=4字節)。 我們知道,1個采樣點只針對一個聲道,而實際上可能會有一或多個聲道。由于不能用一個獨立的單位來表示全部聲道一次采樣的數據量,也就引出了Frame的概念。Frame的大小,就是一個采樣點的字節數×聲道數。另外,在目前的聲卡驅動程序中,其內部緩沖區也是采用Frame作為單位來分配和管理的。 OK,繼續native_get_min_buff_size函數。 ~~~ ...... // minBufCount表示緩沖區的最少個數,它以Frame作為單位 uint32_t minBufCount = afLatency / ((1000 *afFrameCount)/afSamplingRate); if(minBufCount < 2) minBufCount = 2;//至少要兩個緩沖 //計算最小幀個數 uint32_tminFrameCount = (afFrameCount*sampleRateInHertz*minBufCount)/afSamplingRate; //下面根據最小的FrameCount計算最小的緩沖大小 intminBuffSize = minFrameCount //計算方法完全符合我們前面關于Frame的介紹 * (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1) * nbChannels; returnminBuffSize; } ~~~ getMinBufSize會綜合考慮硬件的情況(諸如是否支持采樣率,硬件本身的延遲情況等)后,得出一個最小緩沖區的大小。一般我們分配的緩沖大小會是它的整數倍。 好了,介紹完一些基本概念后,開始要分析AudioTrack了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看