音視頻 — AudioRecorder 和 AudioTrack

基礎(chǔ)知識(shí)

PCM(Pulse Code Modulation),脈沖編碼調(diào)制。人耳聽到的是模擬信號(hào),PCM是把聲音從模擬信號(hào)轉(zhuǎn)化為數(shù)字信號(hào)的技術(shù)。簡單來說就是一種無壓縮編碼

采樣頻率、量化精度(采樣位數(shù))和聲道數(shù):
  • 采樣頻率
    是設(shè)備一秒鐘內(nèi)對(duì)模擬信號(hào)的采樣次數(shù),在主流的采集卡上分為:(8Khz的電話采樣率就可以達(dá)到人的對(duì)話程度)
22.05KHz:無線電廣播; 
44.1KHz:音頻 CD,MP3等; 
48KHz:miniDV、數(shù)字電視、DVD、電影和專業(yè)音頻。
  • 采樣位數(shù)
    它是用來衡量聲音波動(dòng)變化的一個(gè)參數(shù),也可以說是聲卡的分辨率。它的數(shù)值越大,分辨率也就越高,所發(fā)出聲音的能力越強(qiáng)。
    在計(jì)算機(jī)中采樣位數(shù)一般有8位和16位之分,8位不是說把縱坐標(biāo)分成8份,而是分成2的8次方即256份; 同理16位是把縱坐標(biāo)分成2的16次方65536份。

  • 聲道數(shù)
    即聲音的通道的數(shù)目。有單聲道和立體聲之分,單聲道的聲音只能使用一個(gè)喇叭發(fā)聲(有的也處理成兩個(gè)喇叭輸出同一個(gè)聲道的聲音),立體聲的PCM可以使兩個(gè)喇叭都發(fā)聲(一般左右聲道有分工) ,更能感受到空間效果。
    單聲道 采樣數(shù)據(jù)為8位的短整數(shù)(short);
    雙聲道 采樣數(shù)據(jù)為16位的整數(shù),(int),高八位(左聲道)和低八位(右聲道)分別代表兩個(gè)聲道。

  • 存儲(chǔ)量= (采樣頻率 * 采樣位數(shù) * 聲道 * 時(shí)間)/8 (單位:字節(jié)數(shù))。

[時(shí)長]s * [采樣率]Hz * [采樣位數(shù)]bit * [聲道數(shù)] / 8 = [文件大小]byte 
某音頻信號(hào)是采樣率為8kHz、聲道數(shù)、位寬為16bit,時(shí)長為1s,則音頻數(shù)據(jù)的大小為: 
1 * 8000 * 16 *2 = 256000 bit / 8 = 32000 byte / 1024 = 31.25 KB

AudioRecorder

是 Android 中一種音頻采集的方式,另外一種是 MediaRecorder

MediaRecorder:錄制的音頻文件是經(jīng)過壓縮后的,需要設(shè)置編碼器。并且錄制的音頻文件可以用系統(tǒng)自帶的Music播放器播放。
優(yōu)點(diǎn):官方提供 API
缺點(diǎn): 不能實(shí)時(shí)處理音頻,輸出格式不多,且PCM可以處理生成
AudioRecord: 錄制的是PCM格式的音頻文件,需要用AudioTrack來播放。
優(yōu)點(diǎn):可以實(shí)時(shí)獲取音頻的數(shù)據(jù)做到邊錄邊播放,可以對(duì)獲取的音頻做處理,壓縮,傳輸?shù)?br> 缺點(diǎn):輸出的是原始數(shù)據(jù) PCM 所以播放器不能播放,需要通過AudioTrack處理

開始采集

采集音頻的步驟:
1.配置 AudioRecorder 構(gòu)造函數(shù)的參數(shù)
2.初始化緩沖區(qū)
3.開始采集 ,子線程里將緩沖區(qū)的數(shù)據(jù)取出,寫入文件流
4.停止采集,釋放資源

從 AudioRecord 的構(gòu)造函數(shù)開始

audioSource: 音頻采集的輸入源,可選的值以常量的形式定義在 MediaRecorder.AudioSource 類中,例如:MIC(由手機(jī)麥克風(fēng)輸入),VOICE_COMMUNICATION(用于VoIP應(yīng)用)等等。
sampleRateInHz:采樣率,注意,目前44100Hz是唯一可以保證兼容所有Android手機(jī)的采樣率。
channelConfig: 通道數(shù)的配置,可選的值以常量的形式定義在 AudioFormat 類中,常用的是CHANNEL_IN_MONO(單通道),CHANNEL_IN_STEREO(雙通道)
audioFormat: 返回的音頻數(shù)據(jù)的格式,可選的值也是以常量的形式定義在 AudioFormat 類中,常用的是 ENCODING_PCM_16BIT(16bit),ENCODING_PCM_8BIT(8bit),注意,前者是可以保證兼容所有Android手機(jī)的。
bufferSizeInBytes: AudioRecord 內(nèi)部的音頻緩沖區(qū)的大小,該緩沖區(qū)的值不能低于一幀“音頻幀”(Frame)的大小

  public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes)
    throws IllegalArgumentException {
        this((new AudioAttributes.Builder())
                    .setInternalCapturePreset(audioSource)
                    .build(),
                (new AudioFormat.Builder())
                    .setChannelMask(getChannelMaskFromLegacyConfig(channelConfig,
                                        true/*allow legacy configurations*/))
                    .setEncoding(audioFormat)
                    .setSampleRate(sampleRateInHz)
                    .build(),
                bufferSizeInBytes,
                AudioManager.AUDIO_SESSION_ID_GENERATE);
    }
配置

參數(shù)配置:

    /**
     * 采樣率。現(xiàn)在能夠保證在所有設(shè)備上使用的采樣率是44100Hz
     */
    public static final int SAMPLE_RATE_INHZ = 44100;
    /**
     * 輸入聲道數(shù)。CHANNEL_IN_MONO and CHANNEL_IN_STEREO. 其中CHANNEL_IN_MONO是可以保證在所有設(shè)備能夠使用的。
     */
    public static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
    /**
     * 返回的音頻數(shù)據(jù)的格式。 ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, and ENCODING_PCM_FLOAT.
     */
    public static final int ENCODING_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
緩沖區(qū):

AudioRecord 提供了一個(gè)類為我們計(jì)算最小緩沖區(qū),參數(shù)就是我們上面配置的 采樣率,聲道, 返回的音頻數(shù)據(jù)的格式

 int minBufferSize = AudioRecord.getMinBufferSize(Config.SAMPLE_RATE_INHZ, Config.CHANNEL_CONFIG, Config.ENCODING_FORMAT);
    static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
        int channelCount = 0;
        switch (channelConfig) {
        case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
        case AudioFormat.CHANNEL_IN_MONO:
        case AudioFormat.CHANNEL_CONFIGURATION_MONO:
            channelCount = 1;
            break;
        case AudioFormat.CHANNEL_IN_STEREO:
        case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
        case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
            channelCount = 2;
            break;
        case AudioFormat.CHANNEL_INVALID:
        default:
            loge("getMinBufferSize(): Invalid channel configuration.");
            return ERROR_BAD_VALUE;
        }

        int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
        if (size == 0) {
            return ERROR_BAD_VALUE;
        }
        else if (size == -1) {
            return ERROR;
        }
        else {
            return size;
        }
    }
開始采集,子線程讀數(shù)據(jù)寫入文件流

直接調(diào)用創(chuàng)建好的 AudioRecorder 對(duì)象的 startRecording();

//開始采集
 mAudioRecorder.startRecording();
//需要再子線程里面調(diào)用(讀和存)
AudioRecord.read(byte[] audioData, int offsetInBytes, int sizeInBytes);
FileOutputStream 的 write()

停止采集
mAudioTrack.stop();
mAudioRecorder.release();

AudioTrack

開始播放

開始播放步驟:
1.配置參數(shù)
2.配置緩沖區(qū)
3.開啟子線程,把緩沖區(qū)讀數(shù)據(jù)轉(zhuǎn)換成輸入流,再調(diào)用AudioTrack讀 write()寫入數(shù)據(jù),最后調(diào)用 play()
4.結(jié)束釋放資源

配置參數(shù):

參數(shù)和 AudioRecorder 差不多,有區(qū)別的就是 AudioTrack 是輸出聲道,還要播放的類型,和播放的模式
streamType:播放的類型,都定義在 AudioManager 類中
mode: 播放的模式, MODE_STATIC, MODE_STREAM 兩種
兩者的區(qū)別

 /**   在播放之前必須把數(shù)據(jù)全部加載完成
     * Creation mode where audio data is transferred from Java to the native layer
     * only once before the audio starts playing.
     */
    public static final int MODE_STATIC = 0;
    /**
     *可以一邊錄音一邊播放
     * Creation mode where audio data is streamed from Java to the native layer
     * as the audio is playing.
     */
    public static final int MODE_STREAM = 1;
 public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode)
    throws IllegalArgumentException {
        this(streamType, sampleRateInHz, channelConfig, audioFormat,
                bufferSizeInBytes, mode, AudioManager.AUDIO_SESSION_ID_GENERATE);
    }

緩沖區(qū)

和上面的 AudioRecorder 的配置一樣

開啟子線程,把緩沖區(qū)數(shù)據(jù)轉(zhuǎn)換成輸入流,再調(diào)用AudioTrack讀 write()寫入數(shù)據(jù),最后調(diào)用 play()

int readCount = inStream.read(mBuffer);
mAudioTrack.write(mBuffer, 0, readCount);
 mAudioTrack.play();

停止釋放資源

 mAudioTrack.stop();
 mAudioTrack.release();

Demo https://github.com/wubobo952/LearnAudio

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容