这个世界音频设备千变万化,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,主要是用来播放视频与录制视频的类。