在開發上,習慣的將音頻、視頻功能的使用稱之為多媒體,實際上如果講的寬泛一些的話,相機的使用,比如拍照,錄製視頻等,也可以劃分到多媒體的範疇裡面。
從本節課開始,我們就來看看Android中多媒體的API使用和具體的功能。
本篇文章我們先從音頻開發聊起。
零、音頻開發場景、內容和基本概念
在說音頻開發之前,我們可以先想一想自己琢磨一下,哪些應用場景會用到音頻開發。主要的應用場景大致包括:
- 音頻播放器
- 錄音機
- 語音電話
- 音視頻監控應用
- 音視頻直播應用
- 音頻編輯/處理軟體
- 藍牙耳機/音箱
- … …
如果我們要成系統的學習多媒體和音視頻的開發,大致會有涉及到哪些方面的知識呢,歸納來看主要有一下幾個方面的內容:
- 音頻採集/播放:已有音頻如何播放;如何採集一段音頻;
- 音頻演算法處理:主要包括去噪、靜音檢測、回聲消除、音效處理、功放/增強、混音/分離,等等
- 音頻的編解碼和格式轉換:不同格式之間的轉碼操作
- 音頻傳輸協議的開發:主要包括SIP,A2DP、AVRCP,等等
另外,如果要進行音頻開發,需要了解一些音頻的概念作為前置知識,一些常見的概念如下所示:
- SampleRate:採樣率,每秒採集聲音的數量,它用赫茲(Hz)來表示。採樣頻率越高,音頻質量越好。常用的音頻採樣頻率有:8kHz、16kHz、44.1kHz、48kHz 等。
- Channel:聲道數,表示聲音錄製時的音源數量或回放時相應的揚聲器數量。常用的是單聲道(Mono)和雙聲道(Stereo)。要記住這兩個詞:Stereo和Mono。
- BitDepth:採樣精度,每個採樣點用多少數據量表示,它以位(Bit)為單位。位數越多,表示得就越精細,聲音質量自然就越好,當然數據量也越大。常見的位寬是:8bit 或者 16bit。
- BitRate:比特率,每秒音頻佔用的比特數量,單位是 bps(Bit Per Second),比特率越高,壓縮比越小,聲音質量越好,音頻體積也越大。
一、音頻播放
說到音視頻多媒體,首先就有一個概念叫:媒體格式。也就是我們常說的不同格式的音視頻文件。在Android這個開放系統平台中,支持的媒體格式還是很豐富的,詳細內容如下:
音頻格式和編解碼器


總結來說,Android中常見的音頻壓縮格式有:MP3,AAC,OGG,WMA,Opus,FLAC,APE,m4a,AMR,等等。
1.1 音頻的播放
1.1.1 MediaPlayer
首先認識兩個基礎的概念和API:
- MediaPlayer:用於播放聲音和視頻的主要 API。Android 多媒體框架支持播放各種常見媒體類型,可以輕鬆地將音頻、視頻和圖片集成到應用中。可以使用 MediaPlayer API,播放存儲在應用資源(原始資源)內的媒體文件、文件系統中的獨立文件或者通過網路連接獲得的數據流中的音頻或視頻。
- AudioManager:該類API用於管理設備上的音頻源和音頻輸出。
另外需要說一下,MediaPlayerl除了能夠獲取、解碼以及播放音頻和視頻,而且只需很簡單的設置即可以外。它還支持多種不同的媒體源,比如:
- 本地資源:即res目錄下的音頻資源。
- URI:比如可能是通過Content Provider解析到的某個資源URI
- 網路:通過網路,獲取流式傳輸數據進行播放。
使用步驟
- 1、初始化MediaPlayer對象
- 2、準備播放工作:準備工作主要是音頻數據源的獲取或者是音頻數據的解碼操作等,該過程屬於耗時操作,因此需要在工作線程中進行。
- 3、音頻狀態管理:在準備工作過後,可以對音頻進行播放、暫停等操作。同時需要注意的是MediaPlayer是有狀態的,包括:Idle、Initialized、Prepared、Started、Paused、PlaybackCompleted等狀態。當在進行狀態的切換時,需要注意幾個點:
- ① Started(開始)/Paused(暫停)到Stopped(停止)是單向轉換,無法再從Stopped直接轉換到Started,需要經歷Prepared重新裝載才可以重新播放。
- ② Initialized(初始化)狀態需要裝載數據才可以進行start()播放,但是如果使用prepareAsync()方法非同步準備,需要等待準備完成再開始播放,這裡需要使用一個回調方法:setOnPreparedListener(),它會在非同步裝載完成後調用。
- ③ End(結束)狀態是遊離在其他狀態之外的,在任何狀態皆可切換,一般在不需要繼續使用MediaPlayer的時候,才會使用release()回收資源。
- ④ Error(錯誤)狀態是遊離在其他狀態之外的,只有在MediaPlayer發生錯誤的時候才會轉換。為了保持應用的用戶體驗,通常會監聽setOnErrorListener()回調方法,它會在MediaPlayer發生錯誤的時候被回調。
注意事項
- 1、使用Service播放音頻。在使用MediaPlayer播放音頻流時,推薦使用一個Service來承載MediaPlayer,而不是直接在Activity里使用。
- 2、使用喚醒鎖。Android系統的功耗設計里,為了節約電池消耗,如果設備處於睡眠狀態,系統將試圖降低或者關閉一些沒設備必須的特性,包括CPU和Wifi硬體。如果是一個後台播放音樂的應用,降低CPU可能導致在後台運行的時候干擾音頻的正常播放,關閉Wifi將可能導致網路音頻流的獲取出現錯誤。因此為了保證功能的正常使用,我們必須阻止系統關閉服務。可以使用wake locks(喚醒鎖),它會告訴系統你正在使用某些功能,這樣就可以一直保持該功能處於喚醒狀態,即使鎖屏無操作也能繼續使用。這個鎖會在paused和stoped狀態下釋放。
1.1.2 SoundPool
如果應用程序經常播放密集、急促而又短暫的音效(如遊戲音效)那麼使用MediaPlayer顯得有些不太適合了。因為MediaPlayer存在如下缺點:
- 1、延時時間較長,且資源佔用率高。
- 2、不支持多個音頻同時播放。
Android中除了MediaPlayer播放音頻之外還提供了SoundPool來播放音效,SoundPool使用音效池的概念來管理多個短促的音效,例如它可以開始就載入20個音效,以後在程序中按音效的ID進行播放。SoundPool的特點和使用長江如下:
- 1、主要用於播放一些較短的聲音片段。
- 2、SoundPool對CPU資源佔用量低和反應延遲小。
- 3、SoundPool還支持自行設置聲音的品質、音量、 播放比率等參數。
SoundPool的API說明如下:
- 1、SoundPool(int maxStreams, int streamType, int srcQuality):指定它總共支持多少個聲音(也就是池的大小)、聲音的品質。該方法屬於5.0以下版本使用。
- 2、SoundPool.Builder:從5.0版本開始使用的是SoundPool.Builder模式。
- 3、load(Context context, int resld, int priority):從 resld 所對應的資源載入聲音。
- 4、load(FileDescriptor fd, long offset, long length, int priority):載入 fd 所對應的文件的offset開始、長度為length的聲音。
- 5、load(AssetFileDescriptor afd, int priority):從afd 所對應的文件中載入聲音。
- 6、load(String path, int priority):從path 對應的文件去載入聲音。
- 說明:4個load方法中都有一個priority參數,該參數目前還沒有任何作用,Android建議將該 參數設為1,保持和未來的兼容性。
- play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate):指定播放哪個聲音,2和3參數的意思是音量,priority指定播放的優先順序,數值越大優先順序越高;loop用於指定是否循環,0不循環,-1位循環;rate指定播放的比率,可選值為0.5 – 2 ,1為正常比率。
1.1.3 AudioTrack
AudioTrack屬於更偏底層的音頻播放,在Android的framework層有MediaPlayerService,其內部就是使用了AudioTrack。AudioTrack用於單個音頻播放和管理,相比於MediaPlayer具有:精鍊、高效的優點。因此,對於AutioTrack可以總結如下:
- 使用場景:更適合實時產生播放數據的情況,如加密的音頻,MediaPlayer是束手無策的,AudioTrack可以處理。
- 要求:AudioTrack用於播放PCM(PCM無壓縮的音頻格式)音樂流的回放,如果要播需放其它格式音頻,需要相應的解碼器,這也是AudioTrack用的比較少的原因,原因在於需要程序開發者自己解碼音頻。
- 播放模式:
- ① AudioTrack播放音頻有兩種播放模式,一種是靜態模式,即載入的數據和資源可以直接全部載入完畢,載入方式簡單,效率也比較高。但是如果數據量很大,往往不適合;
- ② 流模式和網路上播放視頻是類似的,即數據是按照一定規律不斷地傳遞給接收方的。音頻文件過大 音頻屬性要求高,比如採樣率高、深度大的數據;另外如果音頻數據是實時產生的,這種情況就只能用流模式。
使用AudioTrack公有三個步驟:
共有三個步驟:
- 構建AudioTrack對象,並且把PCM的參數傳到對象裡面
- 調用start
- 調用write。
另外,其實AudioTrack以外,還有一個Audio系統,在該系統中主要包含三個核心的API,分別是:
- AudioManager:主要是用來管理Audio系統的。
- AudioTrack:主要是用來播放聲音。
- AudioRecord:主要是用來錄音。
1.1.4 RingtoneManager
Ringtone為鈴聲、通知和其他類似聲音提供快速播放的方法,該種方式播放音頻時,還會涉及到一個核心的管理類」RingtoneManager」,該類作為管理類提供系統鈴聲列表檢索方法,並且RingtoneManager可以生成Ringtone實例。具體的Ringtone的使用步驟和相關的方法如下所示:
- 1、獲取Ringtone對象實例:
//1.通過鈴聲uri獲取
static Ringtone getRingtone(Context context, Uri ringtoneUri)
//2.通過鈴聲檢索位置獲取
Ringtone getRingtone(int position)- 2、RingtoneManager中重要的方法:
1. // 兩個構造方法
(Activity activity)
RingtoneManager(Context context)
2. // 獲取指定聲音類型(鈴聲、通知、鬧鈴等)的默認聲音的Uri
static Uri getDefaultUri(int type)
3. // 獲取系統所有Ringtone的cursor
Cursor getCursor()
4. // 獲取cursor指定位置的Ringtone uri
Uri getRingtoneUri(int position)
5. // 判斷指定Uri是否為默認鈴聲
static boolean isDefault(Uri ringtoneUri)
6. //獲取指定uri的所屬類型
static int getDefaultType(Uri defaultRingtoneUri)
7. //將指定Uri設置為指定聲音類型的默認聲音
static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri)
8、//播放
void play()
9、//停止播放
void stop()
1.1.5 音頻及音效的播放總結
經過如上幾種音效的播放方式的講解,我們可以對音效的播放做簡單的總結如下所示:
- 1.對於延遲度要求不高,並且希望能夠更全面的控制音樂的播放,MediaPlayer比較適合。
- 2.聲音短小,延遲度小,並且需要幾種聲音同時播放的場景,適合使用SoundPool。
- 3.播放大文件音樂,如WAV無損音頻和PCM無壓縮音頻,可使用更底層的播放方式AudioTrack。它支持流式播放,可以讀取(可來自本地和網路)音頻流,卻播放延遲較小。
- 4、AudioTrack直接支持WAV和PCM,其他音頻需要解碼成PCM格式才能播放。 .jet的音頻比較少見(有的遊戲中在使用),可使用專門的播放器JetPlayer播放。
- 5.對於系統類聲音的播放和操作,Ringtone更適合。
二、音頻的採集
手機一般都有麥克風和攝像頭,而Android系統就可以利用這些硬體來錄製音視頻了。為了增加對錄製音視頻的支持,Android系統提供了一個MediaRecorder的類。
與MediaPlayer類非常相似MediaRecorder也有它自己的狀態圖,MediaRecorder的各個狀態介紹如下:
- Initial:初始化狀態。使用new()方法創建MediaRecorder對象或者調用了reset()方法時,該MediaRecorder對象處於Initial狀態。
- Initialized:已初始化狀態,在Initial狀態調用setAudioSource()或setVideoSource()方法進入該狀態。在這個狀態可以通過setOutputFormat()方法設置輸出格式,此時MediaRecorder轉換為DataSourceConfigured狀態。另外,通過reset()重新進入Initial狀態。
- DataSourceConfigured:數據源配置狀態,這期間可以設定編碼方式、輸出文件、屏幕旋轉、預覽顯示等等。可以在Initialized狀態通過setOutputFormat()方法進入該狀態。可以通過prepare()方法到達Prepared狀態。
- Prepared:就緒狀態,在DataSourceConfigured狀態通過prepare()方法進入該狀態。可以通過start()進入錄製狀態。另外,可以通過reset()方法回到Initialized狀態。
- Recording:錄製狀態,通過調用start()方法進入該狀態。另外,它可以通過stop()方法或reset()方法回到Initial狀態。
- Released:釋放狀態,可以通過在Initial狀態調用release()方法來進入這個狀態,這時將會釋放所有和MediaRecorder對象綁定的資源。
- Error:錯誤狀態,當錯誤發生的時候進入這個狀態,它可以通過reset()方法進入Initial狀態。
需要說明的是,與MediaPlayer相似,使用MediaRecorder錄音錄像時需要嚴格遵守狀態函數調用的先後順序,在不同的狀態調用不同的函數,否則會出現異常。如上的文字描述可以轉換為如下狀態圖:

三、Android中多音視頻編解碼
音視頻的原始數據非常龐大,難以存儲和傳輸。要解決音視頻數據的存儲和傳輸問題,需要做如下處理:
- 音視頻編碼:即對數據進行壓縮,音視頻數據壓縮技術就是音視頻編碼。編碼的目的就是在最小圖像或音頻信息丟失情況下得到最大的壓縮。
- 音視頻解碼:解碼是相對編碼的,其目的是最大限度的還原原始圖像或聲音信息。
- 編解碼的作用:編解碼的意義就是便於數據傳輸和存儲。
而我們知道音視頻編解碼格式非常多(h264、h265、vp8、vp9、aac、opus……),實現每種編解碼都需要引入外部庫,導致項目臃腫、包體積過大且運行性能差。
因此Google提出了一套標準,這就是MediaCodec。具體來說,了解MediaCodec可以從以下幾個方面來說:
- 定義:MediaCodec是Google公司專門為Android開發者和晶元廠商搭建的一套用於調用硬體編解碼器組件的統一介面,全部遵循該介面規範即可簡單的使用,主要的目的在於統一標準。
- 特點:與常規編解碼庫相比,MediaCodec具有非常明顯的優勢,它速度快、效率高、CPU佔用率低、內存小、節省包體積。使用MediaCodec可以解決項目臃腫、減小包體積和提升編解碼性能。
關於MediaCodec的工作原理,可以參見下圖所示:

工作步驟如下所示:
- MediaCodec處理輸入數據後生成輸出數據。通過非同步方式處理數據,並使用一組輸入和輸出緩衝區。
- 輸入端:請求一個空的輸入緩衝區,用數據填充它並將其發送到編解碼器進行處理。
- 輸出端:編解碼器處理完數據並將其轉換到一個空的輸出緩衝區。最後,請求一個已填滿的輸出緩衝區,使用它的內容並將其釋放回編解碼器。
可以操作的數據類型
MediaCodec可以對三種數據進行操作,分別是:
- 編碼數據
- 原始音頻數據
- 原始視頻數據
MediaCodec的狀態管理
MediaCodec存在三種狀態:停止(stoped)、執行(executing)、釋放(released)。
- 停止狀態:包含三個子狀態:配置(configured)、未初始化(uninitialized)、錯誤(error)
- 執行狀態:包含三個子狀態:刷新(flushed)、運行(running)、結束流(end-of-stream)

MediaCodec 發展
Android系統中關於MediaCodec的介紹,可以參考Android的官方網站提供的信息:https://developer.android.google.cn/reference/kotlin/android/media/MediaCodec
MediaCodec 是在 Android 4.1版本(API16 )中出現並可用的,它提供了一種極其原始的介面。MediaCodec類同時存在 Java和C++層中,但是只有前者是公共訪問方法。
在Android 4.3 (API18)中,MediaCodec被擴展為通過 Surface 提供輸入的方法(通過 createInputSurface方法),允許來自於相機的預覽或者是經過OpenGL ES呈現。在該版本中,MediaCodec是第一個過了CTS測試的版本。所謂的CTS,全稱是Compatibility Test Suite,主要是google推出的一種設備兼容性測試規範,用來保證不同設備一致的用戶體驗的規範。
除此之外,4.3版本還引入了 MediaMuxer。MediaMuxer允許將AVC編解碼器(原始H.264基本流)的輸出轉換為.MP4格式,可以和音頻流一起轉碼也可以單獨轉換。
音視頻編輯
MediaCodec通常與MediaExtractor、MediaSync、MediaMuxer、MediaCrypto、MediaDrm、Image、Surface和AudioTrack一起使用,幾乎可以實現大部分音視頻相關功能。主要的操作步驟如下所示:
- 1、初始化。
- 2、MediaExtractor:提取音視頻編碼數據,MediaExtractor用於對音視頻文件解封裝,提取出已編碼的媒體數據。
- 3、MediaCodec:使用解碼器進行解碼。
- 4、處理:對音視頻進行處理。
- 5、編碼:使用MediaCodec編碼器對音視頻數據編碼。
- 6、合成:MediaMuxer合成音視頻文件。MediaMuxer用於封裝編碼後的音視頻數據,目前支持MP4、Webm和3GP文件作為輸出。
- 7、 釋放資源。
代碼中的體現如下:
- createEncoderByType/createDecoderByType
- configure
- start
- while(true) {
- dequeueInputBuffer
- queueInputBuffer
- dequeueOutputBuffer
- releaseOutputBuffer
}
- stop
- release使用MediaCodec編碼音頻
- 初始化MediaCodec對象,如下所示:
private static MediaCodec createAudioEncoder() throws IOException {
MediaCodec codec = MediaCodec.createEncoderByType(AUDIO_MIME);
MediaFormat format = new MediaFormat();
format.setString(MediaFormat.KEY_MIME, AUDIO_MIME);
format.setInteger(MediaFormat.KEY_BIT_RATE, 64000);
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
codec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
return codec;
}- 讀取PCM數據,執行編碼操作。
...
while (!sawOutputEOS) {
if (!sawInputEOS) {
inputBufIndex = audioEncoder.dequeueInputBuffer(10_000);
if (inputBufIndex >= 0) {
ByteBuffer inputBuffer = audioInputBuffers[inputBufIndex];
//先清空緩衝區
inputBuffer.clear();
int bufferSize = inputBuffer.remaining();
if (bufferSize != rawInputBytes.length) {
rawInputBytes = new byte[bufferSize];
}
//讀取
readRawAudioCount = fisRawAudio.read(rawInputBytes);
//判斷是否到文件的末尾
if (readRawAudioCount == -1) {
readRawAudioEOS = true;
}
if (readRawAudioEOS) {
audioEncoder.queueInputBuffer(inputBufIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
sawInputEOS = true;
} else {
//放入緩衝區
inputBuffer.put(rawInputBytes, 0, readRawAudioCount);
rawAudioSize += readRawAudioCount;
//放入編碼隊列
audioEncoder.queueInputBuffer(inputBufIndex, 0, readRawAudioCount, audioTimeUs, 0);
audioTimeUs = (long) (1_000_000 * ((float) rawAudioSize / AUDIO_BYTES_PER_SAMPLE));
}
}
}
//輸出端
outputBufIndex = audioEncoder.dequeueOutputBuffer(outBufferInfo, 10_000);
if (outputBufIndex >= 0) {
// Simply ignore codec config buffers.
if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
Log.i(TAG, "audio encoder: codec config buffer");
audioEncoder.releaseOutputBuffer(outputBufIndex, false);
continue;
}
if (outBufferInfo.size != 0) {
ByteBuffer outBuffer = audioOutputBuffers[outputBufIndex];
outBuffer.position(outBufferInfo.offset);
outBuffer.limit(outBufferInfo.offset + outBufferInfo.size);
//Log.v(TAG, String.format(" writing audio sample : size=%s , presentationTimeUs=%s", outBufferInfo.size, outBufferInfo.presentationTimeUs));
if (lastAudioPresentationTimeUs <= outBufferInfo.presentationTimeUs) {
lastAudioPresentationTimeUs = outBufferInfo.presentationTimeUs;
int outBufSize = outBufferInfo.size;
int outPacketSize = outBufSize + 7;
outBuffer.position(outBufferInfo.offset);
outBuffer.limit(outBufferInfo.offset + outBufSize);
byte[] outData = new byte[outPacketSize];
addADTStoPacket(outData, outPacketSize);
outBuffer.get(outData, 7, outBufSize);
fosAccAudio.write(outData, 0, outData.length);
//Log.v(TAG, outData.length + " bytes written.");
} else {
Log.e(TAG, "error sample! its presentationTimeUs should not lower than before.");
}
}
audioEncoder.releaseOutputBuffer(outputBufIndex, false);
if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
sawOutputEOS = true;
}
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
audioOutputBuffers = audioEncoder.getOutputBuffers();
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat audioFormat = audioEncoder.getOutputFormat();
Log.i(TAG, "format change : " + audioFormat);
}
}
...以上是MediaCodec的編碼執行操作。如果是解碼,與編碼過程相反即可完成。
總結
- 優點:MediaCodec是Android重要的底層多媒體組件,合理使用MediaCodec可以實現播放器、直播、視頻編輯、視頻錄製、視頻通話、視頻會議等幾乎所有音視頻相關的編解碼功能,且與常規編解碼庫相比擁有絕對的性能優勢。
- 不足:MediaCodec也存在一些缺點,兼容性、穩定性都比較差,開發過程中會經常遇到機型、版本等適配問題,這些都可以通過適配合理解決。
四、音頻NDK API開發
如果遇到一些要求更高的項目開發,對音頻有高性能的需求,比如說:所需的不僅僅是簡單的聲音播放或錄製功能。它們需要響應式實時系統行為。一些典型用例如:音頻合成器、電子鼓、音樂學習應用、DJ 混音、音效、視頻/音頻會議等這類要求特別高的需求時。就要從更深層次的底層來提供功能支持,這裡就會用到NDK開發。
首先來了解一下NDK,全稱是Native Development Kit,翻譯為原生開發工具包,主要的作用是可以讓開發者在Android應用中利用C和c++代碼的工具,可用以從自己的源代碼構建,或者利用現有的預構建庫。
本部分的內容可以在如下的Android官方網站中進行查看和學習:https://developer.android.google.cn/ndk/guides/audio
Android官方給提供了如下選擇:
- OpenSL ES:全稱為Open Sound Library for Embedded Systems,嵌入式音頻加速標準。OpenSL ES是無授權費、跨平台、針對嵌入式系統精心優化的硬體音頻加速 API,為嵌入式移動多媒體設備上的本地 應用程序開發者提供了標準化、高性能、低響應時間的音頻功能實現方法,同時還實現了軟/硬體音頻性能的直接跨平台部署,不僅降低了執行難度,而且促進了高級音頻市場的發展。
- 與Android的關係:Android 2.3即API9時開始支持 OpenSL ES 標準,通過 NDK 提供相應的 API 開發介面。Android 實現的OpenSL ES只是OpenSL的子集,然後進行了擴展。
- Android 中OpenSL ES的相關資料:https://developer.android.google.cn/ndk/guides/audio/opensl
- AAudio:在 Android 8.0 版本後引入的音頻庫 , 該音頻庫需要使用C語言在Native層進行調用 , 屬於NDK開發範疇 。AAudio是OpenSL ES 庫的輕量級實現,同樣具有低延遲 , 高性能的特點。需要特別注意的是,AAudio作為一款定位為輕量級的音頻庫,只提供寫入音頻流進行發音的功能 , 不負責音頻設備管理 , 文件 I / O , 音頻編解碼 等操作 ;
- 音頻輸入:從話筒 , 耳機等音頻輸入設備中 , 使用AAudio音頻流採集音頻數據 , 讀取性能高 , 低延遲 。
- 音頻輸出:將音頻流寫入到 AAudio,以極高性能方式將音頻流輸出到發音設備中 。
- Oboe:該庫是基於AAudio封裝的一個開源庫,在github上有開源的地址,鏈接如下:https://github.com/google/oboe 該庫與AAudio是使用C++編寫的適用於Android開發的高效率的音頻開發,依然屬於NDK開發的範疇。Google官方推薦使用該庫。
五、音頻演算法的開源庫
FFmpeg:路人皆知
FFmpeg是一套可以用來記錄、轉換數字音頻、視頻,並能將其轉化為流的開源程序。它提供了錄製、轉換以及流化音視頻的完整解決方案。它包含了非常先進的音頻/視頻編解碼庫libavcodec,為了保證高可移植性和編解碼質量,libavcodec里很多code都是從頭開發的。
只要是做音視頻開發的開發者,幾乎沒有不知道FFmpeg庫的。在github上可以找到FFmpeg的主頁地址如下:https://github.com/FFmpeg/FFmpeg 官方網站的地址是:https://ffmpeg.org/
其中包含的庫主要包括:
- libavcodec:音/視頻編碼庫。
- libavformat:音視頻格式的生成和解析等操作。
- libavutil:公共的工具函數。
該程序最初在Linux平台上開發和使用,目前在windows、mac上均可以使用。
在Android中使用FFmpeg
如果需要在Android中使用FFmpeg,需要進行集成。需要經過幾個步驟:
- 編譯:首先要下載FFmpeg,並進行編譯,編譯出Android中需要的文件。
- 將編譯後的內容集成到Android項目中。
- 測試並調用集成的FFmpeg中的方法。
Speex
Speex主要是針對語音的開源免費,無專利保護的一種音頻壓縮格式,是專門為碼率在2-44kbps的語音壓縮而設計。Speex的特點主要包括:
- 窄帶(8kHz),寬頻(16kHz)和超寬頻(32kHz)壓縮於同一位流
- 可變比特率(VBR)
- 非連續傳輸(DTX)
- 感官回聲消除(AEC)
- 噪音屏蔽
Slik
Slik演算法主要的作用是實現語音和音頻的編解碼,其主要的特點是:
- 支持4種採樣率:8KHz、12KHz、16KHz、24KHz;三種複雜度:低、中、高。
- 編碼碼率在 6~40kbps。
- 提供了定點C代碼,非常有利於向ARM、DSP移植和優化。
六、總結
本篇文檔,我們用很長的篇幅介紹了多媒體開發中的音頻功能的開發和使用,在具體的開發和應用中,重點應該放在對整體知識的理解和架構的梳理上,不要拘泥於某個API的使用,參數的作用等。歸根到底,不同的實現方案,不同的解決方案最終的落腳點和代碼操作步驟幾乎是相同的。再次回顧總結我們本篇內容:
- 音頻的播放:MediaPlayer、SoundPool、AudioTrack、RingtoneManager
- 音頻的採集:MediaRecorder
- 音頻格式的轉換:MediaCodec
- 底層庫的支持和使用:OpenSL ES、AAudio、Oboe
- 開源庫的了解和介紹:FFmpeg
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/202130.html
微信掃一掃
支付寶掃一掃