国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android音頻開發之音頻采集的實現示例

2019-10-22 18:13:17
字體:
來源:轉載
供稿:網友

在 android/271640.html">Android 系統中,一般使用 AudioRecord 或者 MediaRecord 來采集音頻。

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

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

直播技術采用的就是 AudioRecorder 采集音頻數據。

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

基本API

獲取最小的緩沖區大小,用于存放 AudioRecord 采集到的音頻數據。

 

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

 

AudioRecord構造方法

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

參數描述:

音頻采集基本概念

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

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

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

聲道

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

音頻采樣精度

指定采樣的數據的格式和每次采樣的大小。

數據返回格式為 PCM 格式

每次采樣的位寬為 16bit

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

比特率

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

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

比特率越大表示單位時間內采樣的數據越多,傳輸的數據量越大。

audioResource

音頻采集的來源

audioSampleRate

音頻采樣率

channelConfig

聲道

audioFormat

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

bufferSizeInBytes

AudioRecord 采集到的音頻數據所存放的緩沖區大小。

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

開始采集

開始采集之后,狀態變為RECORDSTATE_RECORDING 。

public void startRecording ()

讀取錄制內容,將采集到的數據讀取到緩沖區

方法調用的返回值的狀態碼:

情況異常:

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)

停止采集

停止采集之后,狀態變為 RECORDSTATE_STOPPED 。

public void stop ()

獲取AudioRecord的狀態

用于檢測AudioRecord是否確保了獲得適當的硬件資源。在AudioRecord對象實例化之后調用。

STATE_INITIALIZED 初始完畢

STATE_UNINITIALIZED 未初始化

public int getState ()

返回當前AudioRecord的采集狀態

public static final int RECORDSTATE_STOPPED = 1; 停止狀態

調用 void stop() 之后的狀態

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

調用 startRecording () 之后的狀態

public int getRecordingState()

AudioRecord 采集音頻的基本流程

權限

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

構造一個 AudioRecord 對象。

開始采集。

讀取采集的數據。

停止采集。

構造一個 AudioRecord 對象

 

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

 

獲取 bufferSizeInBytes 值

bufferSizeInBytes 是 AudioRecord 采集到的音頻數據所存放的緩沖區大小。

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

 

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

 

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

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

開始采集

在開始錄音之前,首先要判斷一下 AudioRecord 的狀態是否已經初始化完畢了。

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

開始采集

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

讀取采集的數據

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

創建一個 數據流 ,一邊從 AudioRecord 中讀取音頻數據到 緩沖區 ,一邊將 緩沖區 中數據寫入到 數據流 。

因為需要使用IO操作,因此讀取數據的過程應該在子線程中執行

//創建一個流,存放從AudioRecord讀取的數據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() {    //設置線程的優先級    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIOR    Log.i(TAG, "設置采集音頻線程優先級");    final byte[] data = new byte[bufferSizeInBytes];    //標記為開始采集狀態    isRecording = true;    Log.i(TAG, "設置當前當前狀態為采集狀態");    //getRecordingState獲取當前AudioReroding是否正在采集數據的狀態    while (isRecording && audioRecord.getRecordingState() == AudioRecord      //讀取采集數據到緩沖區中,read就是讀取到的數據量      final int read = audioRecord.read(data, 0, bufferSizeInBytes);      if (AudioRecord.ERROR_INVALID_OPERATION != read && AudioRecord.E        //將數據寫入到文件中        dataOutputStream.write(buffer,0,read);      }    }  }};

停止采集

/** * 停止錄音 */public void stopRecord() throws IOException {  Log.i(TAG, "停止錄音,回收AudioRecord對象,釋放內存");  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()");    }  }}

幾個小問題

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

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

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

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 维西| 科尔| 无锡市| 沙坪坝区| 始兴县| 科尔| 绩溪县| 宾川县| 东台市| 太白县| 林芝县| 石狮市| 田林县| 改则县| 拉孜县| 寿阳县| 江山市| 东乡| 景洪市| 松滋市| 康定县| 阳信县| 北辰区| 大埔县| 临城县| 巴东县| 外汇| 安吉县| 湾仔区| 于都县| 理塘县| 衡南县| 德昌县| 阜南县| 蓬溪县| 威海市| 潼关县| 延边| 中超| 关岭| 襄垣县|