android 錄音原始文件_音頻采集:Android基于AudioRecord的實現

前言

這篇文章簡單介紹下移動端Android系統下利用AudioRecord進行音頻采集方法。

按照慣例開始前先提供一份源碼 AudioRecordLib 。

AudioRecord采集的核心實現在于 AudioRecordCore.java 這個文件。

權限申請

想要使用AudioRecord這個API,需要在AndroidManifest.xml的配置文件里面增加錄音權限:

初始化

AudioRecord的初始化需要先創建一個AudioRecord實例。

構造函數原型如下:

public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig,

int audioFormat,int bufferSizeInBytes)

具體參數說明:

audioSource 這個參數指的是音頻采集的輸入源,接受的值定義在MediaRecorder.AudioSource里面,一般來說使用DEFAULT或者MIC即可。

sampleRateInHz 指定采集音頻的采樣頻率,比較通用的是44100(44.1kHz),這個值是科學家們通過奈葵斯特采樣定理得出的一個人能接受最佳的采樣頻率值。

channelConfig 指定AudioRecord采集幾個聲道的聲音,預設值定義在AudioFormat中,常用值有 CHANNEL_CONFIGURATION_MONO(單聲道) 和 CHANNEL_CONFIGURATION_STEREO(雙聲道)。

audioFormat 指定采樣PCM數據的采樣格式,預設值定義在也AudioFormat中,常用值有 ENCODING_PCM_8BIT、ENCODING_PCM_16BIT和ENCODING_PCM_FLOAT,值得強調的是ENCODING_PCM_16BIT可以保證兼容大部分Andorid手機。

bufferSizeInBytes 配置AudioRecord內部的音頻數據緩沖區,一般來說緩存區越小,產生的音頻延遲也越小;值得注意的是,我們可以利用AudioRecord.getMinBufferSize()這個方法幫我們算出最小的緩存區大小,這個數值最好不要自己計算,畢竟不同廠商可能有不同的緩存區采集實現。

檢測AudioRecord當前狀態

由于可能存在權限問題導致配置AudioRecord失敗,所以我們需要在開始采集前檢查一下AudioRecord的狀態:

if (mAudioRecord.getState() == AudioRecord.STATE_INITIALIZED) {

//todo start

}

如果getState()不等于AudioRecord.STATE_INITIALIZED說明創建AudioRecord失敗,這時候應該給用戶反饋信息。

完整代碼如下:

//獲取最低AudioRecord內部音視頻緩沖區大小,此大小依賴于各產商實現,最好不要自己計算

mRecordBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);

//初始化AudioRecord實例

mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, mRecordBufSize);

//檢測AudioRecord初始化是否成功

if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {

mAudioRecord = null;

mRecordBufSize = 0;

return false;

}

else {

//創建一個位置用于存放后續的PCM數據

mPcmData = new byte[mRecordBufSize];

mState = INIT;

return true;

}

開始采集

創建好了AudioRecord實例,調用如下的方法即可開始麥克風采集:

mAudioRecord.startRecording();

提取數據

調用了開始采集后,我們需要另起一條線程進行PCM數據提取。

我們需要循環不斷從AudioRecord的緩沖區里面將數據讀取出來,值得注意的是這個過程一定要及時,不然會出現“overrun”的錯誤,也就是沒有及時取走音頻數據導致音頻緩存區溢出了。

private Thread mReadDataThread = new Thread() {

@Override

public void run() {

int read;

while (mState == RECORDING) {

//讀取mRecordBufSize長度的音頻數據存入mPcmData中

read = mAudioRecord.read(mPcmData, 0, mRecordBufSize);

//如果讀取音頻數據沒有出現錯誤 ===> read 大于0

if (read >= AudioRecord.SUCCESS) {

synchronized (AudioRecordRecord.class){

if (mCallback != null)

mCallback.onPCMDataAvailable(mPcmData, read);

}

}

}

}

};

停止采集,釋放資源

停止錄音我們可以調用AudioRecord的stop方法來實現。

mAudioRecord.stop();

但是我們存在采集(音頻提取)線程,所以我們需要更改一個狀態變量讓線程結束

mState = INIT;

使得 while (mState == RECORDING) 退出循環邏輯。

接著我們需要釋放錄制器的資源,以便設備的其他應用可以正常使用錄音器,我們可以調用AudioRecord的release方法。

mAudioRecord.release();

這樣就完整的結束了AudioRecord的采集業務。

播放PCM文件

Audacity這個工具可以導入pcm原始文件,并且提供了波形圖查看和播放功能。

操作流程是:

文件 => 導入 => 原始數據 => 設置PCM數據格式 => 導入

具體效果圖如下:

p1.png

結語

下一篇博客會介紹一下Android利用OpenSL ES進行錄音導出PCM數據。

本文同步發布于簡書、CSDN。

End!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372921.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372921.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372921.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Spring 3和Java EE 6 –不公平和不完整的比較

這篇小文章的初稿標題為“ Spring&Java EE –比較蘋果和橙子”。 在撰寫本文時,我了解到可以比較Spring Framework和Java EE,但這始終是不公平且不完整的工作。 Java for Enterprise和Spring Framework的發展緊密地聯系在一起。 兩者相互依存…

xml配置文件推薦方式

1.XML幫助類 /// <summary>/// Xml幫助類/// </summary>public class XmlHelper{/// <summary>/// 保存xml/// </summary>/// <typeparam name"T"></typeparam>/// <param name"path"></param>/// <p…

AFNetWorking https SSL認證

一般來講如果app用了web service , 我們需要防止數據嗅探來保證數據安全.通常的做法是用ssl來連接以防止數據抓包和嗅探 其實這么做的話還是不夠的 。 我們還需要防止中間人攻擊&#xff08;不明白的自己去百度&#xff09;。攻擊者通過偽造的ssl證書使app連接到了偽裝的假冒的…

查看環境列表_Xfce 4.14桌面環境正式發布,想要圖形界面又想節省內存?就它了...

1. Xfce 4.14桌面環境正式發布&#xff0c;它有什么新特性&#xff1f;本文主要講解Xfce 4.14桌面環境正式發布&#xff0c;它有什么新特性。Xfce已經開發了4年多&#xff0c;但是這個周末終于看到了期待已久的Xfce 4.14的發布。Xfce 4.14是這個輕量級桌面環境的最新穩定版本&a…

使用Log4jdbc記錄JDBC操作

當我們開發任何應用程序&#xff0c;完成它或結束其任何模塊時&#xff0c;我們都會開始優化過程。 大多數應用程序都包含數據庫訪問權限&#xff0c;并且如果您使用的是ORM &#xff0c;則可能會使用hibernate 。 優化休眠持久層&#xff0c;要求準備閱讀&#xff0c;理解和評…

android BluetoothAdapter藍牙BLE掃描總結

做室內定位的程序員應該都知道&#xff0c;在Android 5.0之后&#xff0c;google推出了藍牙掃描新接口&#xff0c;我們在實測中發現出一些問題&#xff0c;現在給大家列出&#xff0c;以供參考&#xff1a; 1.android 4.3.1(Build.VERSION_CODES.JELLY_BEAN_MR2)增加的startLe…

卷積神經網絡語音識別_用于物體識別的3D卷積神經網絡

本文提出了一種基于CNN的3D物體識別方法&#xff0c;能夠從3D圖像表示中識別3D物體&#xff0c;并在比較了不同的體素時的準確性。已有文獻中&#xff0c;3D CNN使用3D點云數據集或者RGBD圖像來構建3D CNNs&#xff0c;但是CNN也可以用于直接識別物體體積表示的體素。本文中&am…

段落排版--對齊(text-aliagn)

想為塊狀元素中的文本、圖片設置居中樣式嗎&#xff1f;可以使用text-align樣式代碼&#xff0c;如下代碼可實現文本居中顯示。(那么什么是塊狀元素呢&#xff1f;后面會講到呢~) h1{text-align:center; } <h1>了不起的蓋茨比</h1> 同樣可以設置居左&#xff1a; h…

Java 7:在不丟失數據的情況下關閉NIO.2文件通道

關閉異步文件通道可能非常困難。 如果您將I / O任務提交到異步通道&#xff0c;則需要確保正確執行了任務。 實際上&#xff0c;出于多種原因&#xff0c;這對于異步通道可能是一個棘手的要求。 默認的通道組使用守護進程線程作為工作線程&#xff0c;這不是一個好選擇&#xf…

JavaScript封裝方法,兼容參數類型為Number和String

/*** 依據Kind確定跳轉到目標列表頁面。* param kind*/function gobackByKind(kind) {var kindStr String(kind);switch(kindStr){case "1"://跳轉到客戶列表頁面window.location.href/biz/customer/list;break;case "2"://跳轉到代理機構列表頁面window.…

#獲得請求來源ip_以太網數據包TCP、IP、ICMP、UDP、ARP協議頭結構詳解

以太網首部目地MAC地址(8字節)源MAC地址(8字節)類型(2字節)1、IP頭的結構版本(4位)頭長度(4位)服務類型(8位)封包總長度(16位)封包標識(16位)標志(3位)片斷偏移地址(13位)存活時間(8位)協議(8位)校驗和(16位)來源IP地址(32位)目的IP地址(32位)選項(可選)填充(可選)數據(1)字節和…

團隊項目第二次沖刺Ⅶ

今天將整體代碼的編碼方式改了&#xff0c;作業模塊基本修改完成 遇到的問題是對于添加問答模塊無從下手轉載于:https://www.cnblogs.com/brucekun/p/5573312.html

編寫Play 2的模塊,第2部分:攔截器

在本教程的第一部分中&#xff0c;我們介紹了創建&#xff0c;發布和調用模塊的基本知識。 我們創建的模塊并沒有真正做很多事情&#xff0c;因此現在是時候使用Play的某些功能來擴展功能了。 1.攔截器 攔截器使您可以攔截對控制器的調用&#xff0c;并增強或阻止其行為。 在第…

c# ef報錯_C# EF調用MySql出現“未將對象引用設置到對象的實例”錯誤解決方案

C# EF調用MySql出現“未將對象引用設置到對象的實例”錯誤解決方案---修改步驟---1.打開Nuget管理包&#xff0c;把Mysql.Data替換為6.10.0以下任意版本。這里選擇的是6.8.82.修改完畢后&#xff0c;繼續把Mysql.Data.Entity也修改為對應版本6.8.8。3.安裝完成后可以看到App.Co…

js格式化時間

Date.prototype.format function(fmt) {var o { "M" : this.getMonth()1, //月份 "d" : this.getDate(), //日 "h" : this.getHours(), //小時 "m" : this.getMinu…

PHP---函數

一.函數定義的四個要素 返回類型&#xff0c;函數名&#xff0c;參數列表&#xff0c;函數體 //1.最簡單的定義方式/*function show(){ echo "hello";}show();*///2.有參數的函數定義/*function show($a){ echo $a;}show("bbbbb");*///3.有默認值的函數定義…

ServletRequest startAsync()的有用性有限

前段時間我遇到了Servlet 3.0中AsyncContext.start&#xff08;…&#xff09;的目的是什么&#xff1f; 題。 引用上述方法的Javadoc &#xff1a; 使容器調度線程&#xff08;可能從托管線程池中&#xff09;運行指定的Runnable 。 提醒大家&#xff0c; AsyncContext是Servl…

mysql所支持的比較運算符_mysql比較運算符有哪些?Mysql比較運算符詳解

比較運算符可用于比較數字和字符串。今天發一篇Mysql比較運算符詳解&#xff0c;希望對初學者有所幫助&#xff0c;雖然現在流行NoSQL&#xff0c;但是MYSQL還是很有用的&#xff0c;數字作為浮點值進行比較&#xff0c;字符串以不區為例進行比較&#xff0c;運算符用于比較表達…

數據結構0類模板的使用

類模板的使用 #include <iostream> #include <conio.h> #include <string> #define N 3 using namespace std;template <class numtype> class Swap{public :Swap(numtype a,numtype b){xa;yb;}numtype ___(){tempx;xy;ytemp;return x;}//testnumtype …

JavaScript 函數

函數 由于JavaScript的函數也是一個對象&#xff0c;所以類似function abs(v){}函數實際上是一個函數對象&#xff0c;而函數名abs可以視為指向該函數的變量。 因此&#xff0c;第二種定義函數的方式如下&#xff1a; var abs function (x) {if (x > 0) {return x;} else {…