欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android音頻開發(fā)之音頻采集的實現(xiàn)示例

 更新時間:2018年04月02日 13:54:29   作者:六號表哥  
本篇文章主要介紹了Android音頻開發(fā)之音頻采集的實現(xiàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

在 Android 系統(tǒng)中,一般使用 AudioRecord 或者 MediaRecord 來采集音頻。

AudioRecord 是一個比較偏底層的API,它可以獲取到一幀幀 PCM 數(shù)據(jù),之后可以對這些數(shù)據(jù)進行處理。

而 MediaRecorder 是基于 AudioRecorder 的 API(最終還是會創(chuàng)建AudioRecord用來與AudioFlinger進行交互) ,它可以直接將采集到的音頻數(shù)據(jù)轉(zhuǎn)化為執(zhí)行的編碼格式,并保存。

直播技術(shù)采用的就是 AudioRecorder 采集音頻數(shù)據(jù)。

本文主要介紹例如 AudioRecord 進行音頻的采集。

基本API

獲取最小的緩沖區(qū)大小,用于存放 AudioRecord 采集到的音頻數(shù)據(jù)。

復制代碼 代碼如下:
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)

AudioRecord構(gòu)造方法

根據(jù)具體的參數(shù)配置,請求硬件資源創(chuàng)建一個可以用于采集音頻的 AudioRecord 對象。

參數(shù)描述:

音頻采集基本概念

音頻采集一般使用 AudioRecod或者 MediaRecord

音頻采集的來源是什么?
MediaRecorder.AudioSource.MIC 一般是麥克風

采樣率(單位:赫茲)
每秒鐘音頻采樣點個數(shù)(8000/44100Hz)

聲道

  1. AudioFormat.CHANNEL_IN_MONO 單聲道,一個聲道進行采樣
  2. AudioFormat.CHANNEL_IN_STEREO 雙聲道,兩個聲道進行采樣

音頻采樣精度

指定采樣的數(shù)據(jù)的格式和每次采樣的大小。

數(shù)據(jù)返回格式為 PCM 格式

每次采樣的位寬為 16bit

一般都采用這個 AudioFormat.ENCODING_PCM_16BIT(官方文檔表示,該采樣精度保證所有設備都支持)

比特率

每秒傳送的比特(bit)數(shù)。單位為 bps(Bit Per Second),比特率越高,傳送數(shù)據(jù)速度越快。

采樣率x采樣大小x聲道數(shù)
每秒鐘采樣的大小=16bit(位寬) 2(雙通道) 44100(每次采樣的次數(shù)hz) = 1411200b=1411.2kbps

比特率越大表示單位時間內(nèi)采樣的數(shù)據(jù)越多,傳輸?shù)臄?shù)據(jù)量越大。

audioResource

音頻采集的來源

audioSampleRate

音頻采樣率

channelConfig

聲道

audioFormat

音頻采樣精度,指定采樣的數(shù)據(jù)的格式和每次采樣的大小。

bufferSizeInBytes

AudioRecord 采集到的音頻數(shù)據(jù)所存放的緩沖區(qū)大小。

//設置采集來源為麥克風
private static final int AUDIO_RESOURCE = MediaRecorder.AudioSource.MIC;
//設置采樣率為44100,目前為常用的采樣率,官方文檔表示這個值可以兼容所有的設置
private final static int AUDIO_SAMPLE_RATE = 44100;
//設置聲道聲道數(shù)量為雙聲道
private final static int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;
//設置采樣精度,將采樣的數(shù)據(jù)以PCM進行編碼,每次采集的數(shù)據(jù)位寬為16bit。
private final static int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;

public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)

開始采集

開始采集之后,狀態(tài)變?yōu)镽ECORDSTATE_RECORDING 。

public void startRecording ()

讀取錄制內(nèi)容,將采集到的數(shù)據(jù)讀取到緩沖區(qū)

方法調(diào)用的返回值的狀態(tài)碼:

情況異常:

1.ERROR_INVALID_OPERATION if the object wasn't properly initialized

2.ERROR_BAD_VALUE if the parameters don't resolve to valid data and indexes.

情況正常:the number of bytes that were read

public int read (ByteBuffer audioBuffer, int sizeInBytes)
public int read (byte[] audioData, int offsetInBytes, int sizeInBytes)
public int read (short[] audioData, int offsetInShorts, int sizeInShorts)

停止采集

停止采集之后,狀態(tài)變?yōu)?RECORDSTATE_STOPPED 。

public void stop ()

獲取AudioRecord的狀態(tài)

用于檢測AudioRecord是否確保了獲得適當?shù)挠布Y源。在AudioRecord對象實例化之后調(diào)用。

STATE_INITIALIZED 初始完畢

STATE_UNINITIALIZED 未初始化

public int getState ()

返回當前AudioRecord的采集狀態(tài)

public static final int RECORDSTATE_STOPPED = 1; 停止狀態(tài)

調(diào)用 void stop() 之后的狀態(tài)

public static final int RECORDSTATE_RECORDING = 3;正在采集

調(diào)用 startRecording () 之后的狀態(tài)

public int getRecordingState()

AudioRecord 采集音頻的基本流程

權(quán)限

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

構(gòu)造一個 AudioRecord 對象。

開始采集。

讀取采集的數(shù)據(jù)。

停止采集。

構(gòu)造一個 AudioRecord 對象

復制代碼 代碼如下:
AudioRecord audioRecord = new AudioRecord(audioResource, audioSampleRate, channelConfig, audioFormat, bufferSizeInBytes);

獲取 bufferSizeInBytes 值

bufferSizeInBytes 是 AudioRecord 采集到的音頻數(shù)據(jù)所存放的緩沖區(qū)大小。

注意:這個大小不能隨便設置,AudioRecord 提供對應的 API 來獲取這個值。

復制代碼 代碼如下:
this.bufferSizeInBytes = AudioRecord.getMinBufferSize(audioSampleRate, channelConfig, audioFormat);

通過 bufferSizeInBytes 返回就可以知道傳入給 AudioRecord.getMinBufferSize 的參數(shù)是否支持當前的硬件設備。

if (AudioRecord.ERROR_BAD_VALUE == bufferSizeInBytes || AudioRecord.ERROR == bufferSizeInBytes) {
  throw new RuntimeException("Unable to getMinBufferSize");
}

//bufferSizeInBytes is available...

開始采集

在開始錄音之前,首先要判斷一下 AudioRecord 的狀態(tài)是否已經(jīng)初始化完畢了。

//判斷AudioRecord的狀態(tài)是否初始化完畢
//在AudioRecord對象構(gòu)造完畢之后,就處于AudioRecord.STATE_INITIALIZED狀態(tài)了。
int state = audioRecord.getState();
if (state == AudioRecord.STATE_UNINITIALIZED) {
  throw new RuntimeException("AudioRecord STATE_UNINITIALIZED");
}

開始采集

audioRecord.startRecording();
//開啟線程讀取數(shù)據(jù)
new Thread(recordTask).start();

讀取采集的數(shù)據(jù)

上面提到, AudioRecord 在采集數(shù)據(jù)時會將數(shù)據(jù)存放到緩沖區(qū)中,因此我們只需要創(chuàng)建一個數(shù)據(jù)流去從緩沖區(qū)中將采集的數(shù)據(jù)讀取出來即可。

創(chuàng)建一個 數(shù)據(jù)流 ,一邊從 AudioRecord 中讀取音頻數(shù)據(jù)到 緩沖區(qū) ,一邊將 緩沖區(qū) 中數(shù)據(jù)寫入到 數(shù)據(jù)流 。

因為需要使用IO操作,因此讀取數(shù)據(jù)的過程應該在子線程中執(zhí)行

//創(chuàng)建一個流,存放從AudioRecord讀取的數(shù)據(jù)
File saveFile = new File(Environment.getExternalStorageDirectory(), "audio-record.pcm");
DataOutputStream dataOutputStream = new DataOutputStream(
        new BufferedOutputStream(new FileOutputStream(saveFile)));

private Runnable recordTask = new Runnable() {
  @Override
  public void run() {
    //設置線程的優(yōu)先級
    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIOR
    Log.i(TAG, "設置采集音頻線程優(yōu)先級");
    final byte[] data = new byte[bufferSizeInBytes];
    //標記為開始采集狀態(tài)
    isRecording = true;
    Log.i(TAG, "設置當前當前狀態(tài)為采集狀態(tài)");
    //getRecordingState獲取當前AudioReroding是否正在采集數(shù)據(jù)的狀態(tài)
    while (isRecording && audioRecord.getRecordingState() == AudioRecord
      //讀取采集數(shù)據(jù)到緩沖區(qū)中,read就是讀取到的數(shù)據(jù)量
      final int read = audioRecord.read(data, 0, bufferSizeInBytes);
      if (AudioRecord.ERROR_INVALID_OPERATION != read && AudioRecord.E
        //將數(shù)據(jù)寫入到文件中
        dataOutputStream.write(buffer,0,read);
      }
    }
  }
};

停止采集

/**
 * 停止錄音
 */
public void stopRecord() throws IOException {
  Log.i(TAG, "停止錄音,回收AudioRecord對象,釋放內(nèi)存");
  isRecording = false;
  if (audioRecord != null) {
    if (audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
      audioRecord.stop();
      Log.i(TAG, "audioRecord.stop()");
    }
    if (audioRecord.getState() == AudioRecord.STATE_INITIALIZED) {
      audioRecord.release();
      Log.i(TAG, "audioRecord.release()");
    }
  }
}

幾個小問題

采集數(shù)據(jù)之后,保存的文件為 audio-record.pcm ,這個文件并不能使用普通的播放器播放。它是一個原始的文件,沒有任何播放格式,因此就無法被播放器識別并播放。

上面的問題可以有兩種解決方法

  1. 使用 AudioTrack 播放 pcm 格式的音頻數(shù)據(jù)。
  2. 將 pcm 數(shù)據(jù)轉(zhuǎn)化為 wav 格式的數(shù)據(jù),這樣就可以被播放器識別。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android編程實現(xiàn)禁止StatusBar下拉的方法

    Android編程實現(xiàn)禁止StatusBar下拉的方法

    這篇文章主要介紹了Android編程實現(xiàn)禁止StatusBar下拉的方法,涉及Android StatusBarManager相關(guān)屬性控制操作技巧,需要的朋友可以參考下
    2017-08-08
  • Android短信驗證碼自動填充功能

    Android短信驗證碼自動填充功能

    點擊獲取驗證碼按鈕,收到短信,當前應用不需要退出程序就可以獲取到短信中的驗證碼,并自動填充,這篇文章主要介紹了Android短信驗證碼自動填充功能,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Kotlin中的sam(函數(shù)式接口)詳解

    Kotlin中的sam(函數(shù)式接口)詳解

    這篇文章主要介紹了Kotlin中的sam(函數(shù)式接口)詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Android編程實現(xiàn)鬧鐘的方法詳解

    Android編程實現(xiàn)鬧鐘的方法詳解

    這篇文章主要介紹了Android編程實現(xiàn)鬧鐘的方法,結(jié)合實例形式較為詳細的分析了Android鬧鐘的原理、布局、權(quán)限控制及相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2017-02-02
  • Android開發(fā)環(huán)境搭建

    Android開發(fā)環(huán)境搭建

    本文詳細介紹了Android開發(fā)環(huán)境搭建,十分的詳盡,圖文并茂,有需要的小伙伴參考下。
    2015-01-01
  • Android AsyncTask實現(xiàn)機制詳細介紹及實例代碼

    Android AsyncTask實現(xiàn)機制詳細介紹及實例代碼

    這篇文章主要介紹了Android AsyncTask實現(xiàn)機制詳細介紹及實例代碼的相關(guān)資料,這里附有示例代碼,幫助大家學習理解,需要的朋友可以參考下
    2016-12-12
  • android studio節(jié)省C盤空間的配置方法

    android studio節(jié)省C盤空間的配置方法

    這篇文章主要介紹了android studio節(jié)省C盤空間的配置方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-07-07
  • Android快速實現(xiàn)發(fā)送郵件實例

    Android快速實現(xiàn)發(fā)送郵件實例

    本篇文章主要介紹了Android快速實現(xiàn)發(fā)送郵件實例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Android編程之滑動按鈕事件實例詳解

    Android編程之滑動按鈕事件實例詳解

    這篇文章主要介紹了Android編程之滑動按鈕事件,結(jié)合具體實例形式分析了Android滑動按鈕功能的具體實現(xiàn)步驟、布局及功能實現(xiàn)相關(guān)操作技巧,需要的朋友可以參考下
    2017-03-03
  • Android獲取手機型號/系統(tǒng)版本號/App版本號等信息實例講解

    Android獲取手機型號/系統(tǒng)版本號/App版本號等信息實例講解

    本示例獲得手機型號,系統(tǒng)版本,App版本號等信息,具體實現(xiàn)如下,感興趣的朋友可以參考下哈
    2013-06-06

最新評論