电脑配置高性价比清单:7.3 Audio的硬件抽象层 - 《Android系统原理及开发要点详解》 - 免费试读 - book.csdn.net

来源:百度文库 编辑:偶看新闻 时间:2024/05/06 01:59:05
Android系统原理及开发要点详解
7.3 Audio的硬件抽象层 
http://book.csdn.net/2010-1-26 10:13:00
图书导读
当前章节:7.3 Audio的硬件抽象层
·1.3 Android的SDK与源代码
·7.1 Audio系统综述
·7.2 Audio系统和上层接口
7.3 Audio的硬件抽象层
7.3.1 Audio硬件抽象层的接口定义
Audio的硬件抽象层是AudioFlinger和Audio硬件的接口,在各个系统的移植过程中可以有不同的实现方式。Audio硬件抽象层的接口路径为:
hardware/libhardware_legacy/include/hardware/
其中主要的文件为:AudioHardwareBase.h和AudioHardwareInterface.h。
Android中的Audio硬件抽象层可以基于Linux标准的ALSA或OSS音频驱动实现,也可以基于私有的Audio驱动接口来实现。
在AudioHardwareInterface.h中定义了类:AudioStreamOut、AudioStreamIn和AudioHardwareInterface。AudioStreamOut和AudioStreamIn的主要定义如下所示:
class AudioStreamOut {
public:
virtual            ~AudioStreamOut() = 0;
virtual status_t   setVolume(float volume) = 0;
virtualssize_t     write(const void* buffer, size_t bytes) =0;
//......  省略部分内容
};
class AudioStreamIn {
public:
virtual            ~AudioStreamIn() = 0;
virtual status_t   setGain(float gain) = 0;
virtual ssize_t    read(void* buffer, ssize_t bytes) = 0;
//......  省略部分内容
};
AudioStreamOut和AudioStreamIn分别对应了音频的输出环节和输入环节,其中负责数据流的接口分别是wirte()和read(),参数是一块内存的指针和长度;另外还有一些设置和获取接口。
Audio的硬件抽象层主体AudioHardwareInterface类的定义如下所示:
class AudioHardwareInterface
{
public:
virtual status_t   initCheck() = 0;
virtual status_t   setVoiceVolume(float volume) = 0;
virtual status_t   setMasterVolume(float volume) = 0;
virtual status_t   setRouting(int mode, uint32_t routes) = 0;
virtual status_t   getRouting(int mode, uint32_t* routes) = 0;
virtual status_t   setMode(int mode) = 0;
virtual status_t   getMode(int* mode) = 0;
//......  省略部分内容
virtual AudioStreamOut*openOutputStream(        // 打开输出流
int format=0,
intchannelCount=0,
uint32_t sampleRate=0,
status_t *status=0) = 0;
virtual AudioStreamIn*openInputStream(           //打开输入流
int format,
int channelCount,
uint32_t sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics) = 0;
static AudioHardwareInterface*create();
};
在这个AudioHardwareInterface接口中,使用openOutputStream()和openInputStream()函数分别获取AudioStreamOut和AudioStreamIn两个类,它们作为音频输入/输出设备来  使用。
此外,AudioHardwareInterface.h定义了C语言的接口来获取一个AudioHardwareInterface类型的指针。
extern "C" AudioHardwareInterface*createAudioHardware(void);
如果实现一个Android的硬件抽象层,则需要实现AudioHardwareInterface、AudioStreamOut和AudioStreamIn三个类,将代码编译成动态库libauido.so。AudioFlinger会连接这个动态库,并调用其中的createAudioHardware()函数来获取接口。
在AudioHardwareBase.h中定义了类:AudioHardwareBase,它继承了AudioHardwareInterface,显然继承这个接口也可以实现Audio的硬件抽象层。
 提示:Android系统的Audio硬件抽象层可以通过继承类AudioHardwareInterface来实现,其中分为控制部分和输入/输出处理部分。
è 7.3.2  AudioFlinger中自带Audio硬件抽象层实现
在AudioFlinger中可以通过编译宏的方式选择使用哪一个Audio硬件抽象层。这些Audio硬件抽象层既可以作为参考设计,也可以在没有实际的Audio硬件抽象层(甚至没有Audio设备)时使用,以保证系统的正常运行。
在AudioFlinger的编译文件Android.mk中,具有如下的定义:
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface
else
LOCAL_SHARED_LIBRARIES += libaudio
endif
LOCAL_MODULE:= libaudioflinger
include $(BUILD_SHARED_LIBRARY)
定义的含义为:当宏BOARD_USES_GENERIC_AUDIO为true时,连接libaudiointerface.a静态库;当BOARD_USES_GENERIC_AUDIO为false时,连接libaudiointerface.so动态库。在正常的情况下,一般是使用后者,即在另外的地方实现libaudiointerface.so动态库,由AudioFlinger的库libaudioflinger.so来连接使用。
libaudiointerface.a也在这个Android.mk中生成:
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
AudioHardwareGeneric.cpp \
AudioHardwareStub.cpp \
AudioDumpInterface.cpp \
AudioHardwareInterface.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libmedia \
libhardware_legacy
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_CFLAGS += -DGENERIC_AUDIO
endif
LOCAL_MODULE:= libaudiointerface
include $(BUILD_STATIC_LIBRARY)
以上内容通过编译4个源文件,生成了libaudiointerface.a静态库。其中AudioHardwareInterface.cpp负责实现基础类和管理,而AudioHardwareGeneric.cpp、AudioHardwareStub.cpp和AudioDumpInterface.cpp三个文件各自代表一种Auido硬件抽象层的实现。
n  AudioHardwareGeneric.cpp:实现基于特定驱动的通用Audio硬件抽象层;
n  AudioHardwareStub.cpp:实现Audio硬件抽象层的一个桩;
n  AudioDumpInterface.cpp:实现输出到文件的Audio硬件抽象层。
在AudioHardwareInterface.cpp中,实现了Audio硬件抽象层的创建函数    AudioHardwareInterface::create(),内容如下所示:
AudioHardwareInterface*AudioHardwareInterface::create()
{
AudioHardwareInterface* hw =0;
charvalue[PROPERTY_VALUE_MAX];
#ifdef GENERIC_AUDIO
hw = newAudioHardwareGeneric();           // 使用通用的Audio硬件抽象层
#else
if (property_get("ro.kernel.qemu",value, 0)) {
LOGD("Running in emulation - using generic audio driver");
hw = newAudioHardwareGeneric();
}
else {
LOGV("Creating Vendor Specific AudioHardware");
hw =createAudioHardware();              // 使用实际的Audio硬件抽象层
}
#endif
if (hw->initCheck() != NO_ERROR){
LOGW("Usingstubbed audio hardware. No sound will be produced.");
deletehw;
hw = newAudioHardwareStub();           // 使用实际的Audio硬件抽象层的桩实现
}
#ifdef DUMP_FLINGER_OUT
hw = newAudioDumpInterface(hw);           // 使用实际的Audio的Dump接口实现
#endif
return hw;
}
根据GENERIC_AUDIO、DUMP_FLINGER_OUT等宏选择创建几个不同的Audio硬件抽象层,最后返回的接口均为AudioHardwareInterface类型的指针。
1.用桩实现的Audio硬件抽象层
AudioHardwareStub.h和AudioHardwareStub.cpp是一个Android硬件抽象层的桩实现方式。这个实现不操作实际的硬件和文件,它所进行的是空操作,在系统没有实际的Audio设备时使用这个实现,来保证系统的正常工作。如果使用这个硬件抽象层,实际上Audio系统的输入和输出都将为空。
AudioHardwareStub.h定义了AudioStreamOutStub 和AudioStreamInStub类的情况  如下所示:
class AudioStreamOutStub : public AudioStreamOut {
public:
virtual status_t    set(int format,int channelCount, uint32_t sampleRate);
virtual uint32_t    sampleRate()const { return 44100; }
virtual size_t     bufferSize() const { return 4096; }
virtual int        channelCount() const { return 2; }
virtualint         format() const { returnAudioSystem::PCM_16_BIT; }
virtual uint32_t    latency() const{ return 0; }
virtual status_t    setVolume(floatvolume) { return NO_ERROR; }
virtual ssize_t    write(const void* buffer, size_t bytes);
virtual status_t   standby();
virtual status_t    dump(int fd,const Vector& args);
};
class AudioStreamInStub : public AudioStreamIn {
public:
virtualstatus_t set(int format, int channelCount, uint32_t sampleRate, AudioSystem::                       audio_in_acoustics acoustics);
virtual uint32_t    sampleRate()const { return 8000; }
virtual size_t     bufferSize() const { return 320; }
virtualint         channelCount() const {return 1; }
virtualint         format() const { returnAudioSystem::PCM_16_BIT; }
virtual status_t    setGain(floatgain) { return NO_ERROR; }
virtual ssize_t     read(void*buffer, ssize_t bytes);
virtual status_t    dump(int fd,const Vector& args);
virtual status_t    standby() {return NO_ERROR; }
};
上面实际上使用了最简单模式,只是用固定的参数(缓冲区大小、采样率、通道数),以及将一些函数直接无错误返回。
使用AudioHardwareStub类来继承AudioHardwareBase,事实上也就是继承AudioHardwareInterface。
class AudioHardwareStub : public  AudioHardwareBase
{
public:
AudioHardwareStub();
virtual            ~AudioHardwareStub();
virtual status_t   initCheck();
virtual status_t   setVoiceVolume(float volume);
virtual status_t   setMasterVolume(float volume);
virtual status_t    setMicMute(boolstate) { mMicMute = state;  return  NO_ERROR; }
virtual status_t   getMicMute(bool* state) { *state = mMicMute ; return NO_ERROR; }
virtual status_t   setParameter(const char* key, const char* value)
{return NO_ERROR; }
virtual AudioStreamOut*openOutputStream(        //打开输出流
int format=0,
int channelCount=0,
uint32_t sampleRate=0,
status_t *status=0);
virtual AudioStreamIn* openInputStream(     //打开输入流
int format,
int channelCount,
uint32_t sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
//…… 省略部分内容
};
在实现过程中,为了保证声音可以输入和输出,这个桩实现的主要内容是实现AudioStreamOutStub和AudioStreamInStub类的读/写函数。实现如下所示:
ssize_t AudioStreamOutStub::write(const void* buffer, size_tbytes)
{
usleep(bytes * 1000000 / sizeof(int16_t) /channelCount() / sampleRate());
return bytes;
}
ssize_t AudioStreamInStub::read(void* buffer, ssize_tbytes)
{
usleep(bytes * 1000000 / sizeof(int16_t) /channelCount() / sampleRate());
memset(buffer, 0, bytes);
return bytes;
}
由此可见,使用这个接口进行音频的输入和输出时,和真实的设备没有关系,输出和输入都使用延时来完成。对于输出的情况,不会有声音播出,但是返回值表示全部内容已经输出完成;对于输入的情况,将返回全部为0的数据。
此外,这种实现支持默认的参数,如果用set()函数设置的参数与默认参数不一致,还会返回错误。
2.Android通用的Audio硬件抽象层
AudioHardwareGeneric.h和AudioHardwareGeneric.cpp是Android通用的一个Audio硬件抽象层。与前面的桩实现不同,这是一个真正能够使用的Audio硬件抽象层,但是它需要Android的一种特殊的声音驱动程序的支持。
与前面类似,AudioStreamOutGeneric、AudioStreamInGeneric和AudioHardwareGeneric这3个类分别继承Audio硬件抽象层的3个接口。
class AudioStreamOutGeneric : public AudioStreamOut {
// ...... 通用Audio输出类的接口
};
class AudioStreamInGeneric : public AudioStreamIn {
// ...... 通用Audio输入类的接口
};
class AudioHardwareGeneric : public AudioHardwareBase
{
// ...... 通用Audio控制类的接口
};
在AudioHardwareGeneric.cpp的实现中,使用的驱动程序是/dev/eac,这是一个非标准程序,定义设备的路径如下所示:
static char const * const kAudioDeviceName ="/dev/eac";
对于Linux操作系统,这个驱动程序在文件系统中的节点主设备号为10,次设备号自动生成。
 提示:eac是Linux中的一个misc驱动程序,作为Android的通用音频驱动,写设备表示放音,读设备表示录音。
在AudioHardwareGeneric的构造函数中,打开这个驱动程序的设备节点。
AudioHardwareGeneric::AudioHardwareGeneric()
: mOutput(0), mInput(0), mFd(-1), mMicMute(false)
{
mFd = ::open(kAudioDeviceName,O_RDWR);  //打开通用音频设备的节点
}
这个音频设备是一个比较简单的驱动程序,没有很多设置接口,只是用写设备表示录音,读设备表示放音。放音和录音支持的都是16位的PCM。
ssize_t AudioStreamOutGeneric::write(const void*buffer, size_t bytes)
{
Mutex::Autolock_l(mLock);
return ssize_t(::write(mFd, buffer,bytes)); //写入硬件设备
}
ssize_t AudioStreamInGeneric::read(void* buffer,ssize_t bytes)
{
AutoMutex lock(mLock);
if (mFd < 0) {
returnNO_INIT;
}
return ::read(mFd, buffer,bytes);             // 读取硬件设备
}
虽然AudioHardwareGeneric是一个可以真正工作的Audio硬件抽象层,但是这种实现方式非常简单,不支持各种设置,参数也只能使用默认的。而且,这种驱动程序需要在Linux核心加入eac驱动程序的支持。
3.提供Dump功能的Audio硬件抽象层
AudioDumpInterface.h和AudioDumpInterface.cpp是一个提供了Dump功能的Audio硬件抽象层,它所起到的作用就是将输出的Audio数据写入到文件中。
AudioDumpInterface本身支持Audio的输出功能,不支持输入功能。AudioDumpInterface.h中的类定义如下:
class AudioStreamOutDump : public AudioStreamOut {
public:
AudioStreamOutDump( AudioStreamOut* FinalStream);
~AudioStreamOutDump();
virtualssize_t     write(const void* buffer, size_tbytes);
virtual uint32_t    sampleRate()const { return mFinalStream->sampleRate(); }
virtual size_t     bufferSize() const { return mFinalStream->bufferSize(); }
virtualint         channelCount() const {return mFinalStream->channelCount(); }
virtualint         format() const { returnmFinalStream->format(); }
virtual uint32_t    latency() const{ return mFinalStream->latency(); }
virtual status_t    setVolume(floatvolume)
{ return mFinalStream->setVolume(volume); }
virtual status_t   standby();
// …… 省略部分内容
};
class AudioDumpInterface : public AudioHardwareBase
{
virtual AudioStreamOut*openOutputStream(
intformat=0,
int channelCount=0,
uint32_t sampleRate=0,
status_t *status=0);
// …… 省略部分内容
}
只实现了AudioStreamOut,没有实现AudioStreamIn,因此这个Audio硬件抽象层只支持输出功能,不支持输入功能。
输出文件的名称被定义为:
#define FLINGER_DUMP_NAME "/data/FlingerOut.pcm"
在AudioDumpInterface.cpp的AudioStreamOut所实现的写函数中,写入的对象就是这个文件。
ssize_t AudioStreamOutDump::write(const void* buffer, size_tbytes)
{
ssize_t ret;
ret =mFinalStream->write(buffer, bytes);
if(!mOutFile && gFirst) {
gFirst = false;
mOutFile =fopen(FLINGER_DUMP_NAME, "r");
if(mOutFile) {
fclose(mOutFile);
mOutFile = fopen(FLINGER_DUMP_NAME, "ab");      //打开输出文件
}
}
if (mOutFile) {
fwrite(buffer, bytes, 1,mOutFile);            //写文件输出内容
}
return ret;
}
如果文件是打开的,则使用追加方式写入。因此使用这个Audio硬件抽象层时,播放的内容(PCM)将全部被写入文件。而且这个类支持各种格式的输出,这取决于调用者的设置。
AudioDumpInterface并不是为了实际的应用使用的,而是为了调试使用的类。当进行音频播放器调试时,有时无法确认是解码器的问题还是Audio输出单元的问题,这时就可以用这个类来替换实际的Audio硬件抽象层,将解码器输出的Audio的PCM数据写入文件中,由此可以判断解码器的输出是否正确。
 提示:使用AudioDumpInterface音频硬件抽象层,可以通过/data/FlingerOut.pcm文件找到PCM的输出数据。
è 7.3.3  Audio硬件抽象层的真正实现
实现一个真正的Audio硬件抽象层,需要完成的工作和实现以上的硬件抽象层类似。
例如:可以基于Linux标准的音频驱动:OSS(OpenSound System)或者ALSA(Advanced Linux Sound Architecture)驱动程序来实现。
对于OSS驱动程序,实现方式和前面的AudioHardwareGeneric类似,数据流的读/写操作通过对/dev/dsp设备的读/写来完成;区别在于OSS支持了更多的ioctl来进行设置,还涉及通过/dev/mixer设备进行控制,并支持更多不同的参数。
对于ALSA驱动程序,实现方式一般不是直接调用驱动程序的设备节点,而是先实现用户空间的alsa-lib,然后Audio硬件抽象层通过调用alsa-lib来实现。
在实现Audio硬件抽象层时,对于系统中有多个Audio设备的情况,可由硬件抽象层自行处理setRouting()函数设定,例如,可以选择支持多个设备的同时输出,或者有优先级输出。对于这种情况,数据流一般来自AudioStreamOut::write()函数,可由硬件抽象层确定输出方法。对于某种特殊的情况,也有可能采用硬件直接连接的方式,此时数据流可能并不来自上面的write(),这样就没有数据通道,只有控制接口。Audio硬件抽象层也是可以处理这种情况的。