這個世界音頻設備千變萬化,Android也不可能為每種設備都提供支持。Android定義了一個框架,這個框架來適配底層的音頻設備。該適配層的定義位於:
hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h
要想視頻底層的音頻設備必須要繼承該文件中定義的AudioStreamOut,AudioStreamIn,AudioHardwareInterface等類,並實現createAudioHardware函數。
下面我們看一下Android創建音頻設備的代碼,代碼位於:
frameworks/base/libs/audioflinger/AudioHardwareInterface.cpp
該文件有如下代碼:
AudioHardwareInterface * AudioHardwareInterface::create()
{
/*
*FIXME:This code needs to instantiate thecorrect audio device
*interface.For now-we use compile-timeswitches.
*/
AudioHardwareInterface*hw=0;
char value[PROPERTY_VALUE_MAX];
#ifdef GENERIC_AUDIO
hw=new AudioHardwareGeneric();
#else
//if running in emulation-use the emulatordriver
if(property_get("ro.kernel.qemu",value,0)){
LOGD("Running in emulation-usinggeneric audio driver");
hw=new AudioHardwareGeneric();
}
else{
LOGV("Creating Vendor Specific AudioHardware");
hw=createAudioHardware();
}
#endif
if(hw->initCheck()!=NO_ERROR){
LOGW("Using stubbed audio hardware.Nosound will be produced.");
delete hw;
hw=new AudioHardwareStub();
}
#ifdef WITH_A2DP
hw=new A2dpAudioInterface(hw);
#endif
#ifdef ENABLE_AUDIO_DUMP
//This code adds a record of buffers in afile to write calls made by AudioFlinger.
//It replaces the currentAudioHardwareInterface object by an intermediateone which
//will record buffers in a file(aftersending them to hardware)for testing purpose.
//This feature is enabled by definingsymbol ENABLE_AUDIO_DUMP.
//The output file is set withsetParameters("test_cmd_file_opening PCM dump
interface");
hw=new AudioDumpInterface(hw);//replaceinterface
#endif
return hw;
}
從代碼中我們可以看出如果定義了GENERIC_AUDIO的宏,則會創建AudioHardwareGeneric,如果是模擬器的話,AudioHardwareGeneric會不能初始化,進而創建AudioHardwareStub。這兩個類都是Audio設備的適配層,是Android默認提供的模擬器都是用AudioHardwareStub,不會有聲音輸出設備都是用AudioHardwareGeneric,因為默認GENERIC_AUDIO是設置的一般我們只關心AudioHardwareGeneric實現,誰會去給模擬器去調試聲音呢,反正我沒這個閑心。
首先說明一下這個音頻適配層是Android自帶的,可以保證你的音頻設備正常運行,但是不能發揮設備的最佳性能。
通過后面的描述你將會了解AudioHardwareGeneric的定義位於:
frameworks/base/libs/audioflinger/AudioHardwareGeneric.cpp
查看源碼你會發現這個適配層需要實現設備/dev/eac,並且該設備只輸出44.1khz采樣率的音頻數據給/dev/eac設備,如果不是44.1khz的采樣率的數據,AudioHardwareGeneric會經過Resample過程把它轉換成44.1kHZ的音頻數據,然后再輸出給音頻設備。44.1kHZ音頻數據是最普遍的音頻采樣率,大部分Mp3都是以這個采樣率壓縮的,所以選擇這個采樣率做為默認采樣率還是有一定的合理性的。
AudioHardwareGeneric是軟件實現Resample過程是,效率會比較低。很多音頻設備支持不同采樣率的數據,可以理解成硬件實現Resample過程。通過上面的描述我們可以知道這個通用音頻適配層只是讓你的設備可以用而已,不能發揮設備的性能優勢,如果你的設備對音頻質量有更高的要求,必須要自己實現音頻適配層。谷歌只能保證你的音頻可以播放,但是不能保證效率(他也沒有辦法保證效率)。
所支持的音頻格式
對於播放,Android支持各種各樣的音頻文件格式和編解碼。對於錄音的支持少一些。
以后我們學到錄音部分將會討論這點。
AAC:
高級音頻編碼(以及其擴展:HEAAC)編解碼,.m4a,.3gp文件.AAC是一個流行的標准,IPOD和其他便攜式媒體播放器都使用它。Android在MPEG4音頻文件和3GP文件內(都是基於MPEG4格式)支持這種音頻格式。最近AAC的附加規范HE AAC也被支持了。
MP3:
MPGE-1音頻層3,.mp3文件。Android支持MP3,MP3可能是使用最廣泛的音頻編解碼,這允許Android通過各種網站和音樂商店來使用大部分在線音頻。
AMR:
自適應多速率編解碼(AMR-NB,AMR-WB),.3gp,.amr文件。AMR音頻編解碼已經被標准化了,主要被3GPP(第三代合作伙伴項目)用於語音音頻編解碼。3GPP是一個為其合作伙伴創建規范的電信行業機構。換句話說,AMR編解碼主要用於現代移動電話的語音呼叫程序,並且手機廠商和手機攜帶者普遍都支持這個格式。AMR這格式一般對語音編碼很有用,但對更復雜的類型表現的不夠好,比如音樂。
Ogg:
Ogg Vorbis,.ogg文件。Ogg Vorbis是個開源的,無專利費的音頻編解碼。其品質可媲美商業性的,需繳納專利費的編解碼比如MP3,AAC它由一群自願者開發,當前由Xiph.Org基金會負責維護。
PCM:
脈沖編碼調制通常被用在WAVE,WAV文件,.wav文件。PCM這技術主要用於音頻在電腦和其他電子音頻設備上的存儲。它通常是個未壓縮的音頻文件,其數據代表隨着時間流逝一段音頻的振幅。“采樣率”是多長時間一次一個振幅讀取被存儲起來。“位深度”是指多少位被用來代表一個單獨的樣本。一段16KHZ采樣率,32位位深度的音頻數據是指它包含每秒鍾16000個的32位的數據用來表示音頻振幅。采樣率和位深度越高,數字化音頻越精准。采樣率和位深度也決定了音頻文件的大小。Android在WAV文件內支持PCM音頻數據。WAV是PC上的一個長期存在的標准音頻格式。
通過Intent使用內建的音頻播放器
正如使用攝像頭,在一個應用程序里提供播放音頻文件的能力,最容易的方法就是:使用內建的“音樂”程序的功能。這個程序有個用戶熟悉的界面,能播放所有Android支持的格式,並且能通過一個intent,被觸發去播放一個指定的文件。普通的android.content.Intent.ACTION_VIEW intent,其數據設置為一個音頻文件的Uri,並指定其MIME類型,這樣Android會自動選擇一個合適的應用程序來播放。這個程序應該是內建的音樂播放程序,但用戶可能被提供其他的選項,如果他/她安裝了其他的音頻播放軟件。
1.Intent intent=newIntent(android.content.Intent.ACTION_VIEW);
2.intent.setDataAndType(audioFileUri,"audio/mp3");
3.startActivity(intent);
注解:MIME全稱是MultipurposeInternet Mail Extension(s多用途互聯網郵件擴展)。它起初專門用來幫助電子郵件客戶端發送和接收附件。但它的使用范圍從電子郵件極大地擴展到其他的通訊協議,包括HTTP,標准萬維網服務。Android使用MIME類型來解析intent,並且用它來決定應該選擇哪個應用程序來處理intent.
每個文件類型都有特定的(有時候不止一個)MIME類型。MIME類型通過至少由2部分組成,由斜杠分開的字符來指定。第一部分是更通用的類型,比如“audio”.第二部分是更具體的類型,比如"mpeg".一個通用的類型"audio"和一個更具體的類型"mpeg"將產生一個“audio/mpeg"MIME類型字符,這個MIME類型通常用於MP3文件。
Android音頻實例分析
這里有個通過一個intent觸發內建的音頻播放程序的完整例子。
1.packagecom.apress.proandroidmedia.ch5.intentaudioplayer;
2.import java.io.File;
3.import android.app.Activity;
4.import android.content.Intent;
5.import android.net.Uri;
6.import android.os.Bundle;
7.import android.os.Environment;
8.import android.view.View;
9.importandroid.view.View.OnClickListener;
10.import android.widget.Button;
我們的activity在觸發音頻播放之前會一直監聽一個Botton是否被按下。
1.public class AudioPlayer extendsActivity implements OnClickListener{
2.Button playButton;
3.@Override
4.public void onCreate(BundlesavedInstanceState){
5.super.onCreate(savedInstanceState);
6.setContentView(R.layout.main);
我們將content view設置為我們的XML后,我們能得到一個Button的引用,並將我們的activity(this)設為OnClickListener.
1.playButton=(Button)this.findViewById(R.id.Button01);
2.playButton.setOnClickListener(this);
3.}
當我們的Button被點擊,OnClick方法會被調用。在這個方法里,我們用一個普通的android.content.Intent.ACTION_VIEW來構建intent,然后創建一個文件對象,這個對象是SD卡上已經存在的音頻文件的索引。這種情況下,這個音頻文件被手動放置到SD卡的“Music"目錄下,這個目錄通常放置和音樂相關的音頻文件。
1.public void onClick(View v){
2.Intent intent=new Intent(android.content.Intent.ACTION_VIEW);
3.Filesdcard=Environment.getExternalStorageDirectory();
4.File audioFile=newFile(sdcard.getPath()+"/Music/goodmorningandroid.mp3");
接下來,我們設置intent的數據為來源於音頻文件的Uri並將其類型設置為MIME類型,audio/mp3.最后傳遞我們的intent給startActivity來觸發內建的音樂播放程序。
1.intent.setDataAndType(Uri.fromFile(audioFile),"audio/mp3");
2.startActivity(intent);
3.}
下面是一個簡單的XML布局文件,其中Button的文本為"Play Audio",前面所述的
activity會用到這個Button.
1.<?xmlversion="1.0"encoding="utf-8"?>
2.<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
3.android:orientation="vertical"
4.android:layout_width="fill_parent"
5.android:layout_height="fill_parent"
6.>
7.<Button android:text="Play Audio"android:id="@+id/Button01"
8.android:layout_width="wrap_content"android:layout_height="wrap_content"
></Button>
9.</LinearLayout>
Android支持的視頻格式
先簡要說明下Android支持的視頻格式,如下:

由於硬件的不同,不同的手機支持的編解碼方式有些不一樣,在T-Mobile G1實際設備中增加了對WMA,WMV,H.264 AVC格式解碼的支持。Android支持的音/視頻編碼方式僅包括:AMR-NB,H.263,輸出的視頻格式也只*.3gp或者*.mp4,這點在以后的開發中需要注意。對Android的編解碼有了一些了解后,我們再去研究下如何在Android上來播放/錄制視頻,打開Android SDK中關於媒體方面的說明,摘要其主要部分如下:

首先注意的就是:MediaPlayer,MediaRecoder,主要是用來播放視頻與錄制視頻的類。
