Android 音频架构
Android provides two native layers that handle audio software:
转者注:也就是说存在一个server用于处理更上层,比如一些应用的audio需求;
转者注:也就是说这是一个通用接口,它是一个桥梁,连接包括audioflinger在内的上层应用和底层的物理音频设备访问;
转者注:这个图还是画得很清楚,JNI之上是媒体框架和在媒体框架之上的一般客户端程序,这些估计是用java写的,通过jni访问真正的服务器端提供的音频接口函数,而audioflinger则是通过AudioHardwareInterface来实现物理的音频设备的访问的;
Porting Android to other Audio Stacks
Porting Android to other audio stacks (OSS, ALSA, proprietary user-space audio libraries, etc.) requires inheriting from and modifying AudioHardwareInterface to support the driver-specific implementation.
转者注:也就是说如果你要实现自己的硬件的音频接口,需要继承或者说实现AudioHardwareInterface,当然所谓移植都有两层,一层就是实现它规定的接口,另外一方面必须告诉上层,你多了一个这样的实现,这一步在有些情况要是不需要做的,而有些情况就需要你自己做,看下面就知道了。
AudioHardwareInterface Abstract Class
AudioHardwareInterface (//device/servers/audio/flinger) contains several pure virtual functions that the audio driver class being ported needs to implement.
Modifying AudioHardwareInterface
Once the audio driver that inherits AudioHardwareInterface is ready, modify the static function AudioHardwareInterface::create() in order to link/load the driver in Android.
Assume the manufacturer audio driver inherits from AudioHarddwareInterface and that it is compiled into a native shared library (libaudio.so). In this case, use dlopen to load the library.
You can find an example of a similar implementation in //device/libs/media/mediaplayer.cpp. (Note that the example below uses libpv.so because this is a real code snippet from mediaplayer.cpp. If your native shared library is called libaudio.so, replace libpv.so with your libaudio.so.)
// load PV library and create PV player
mLibHandle = dlopen("libpv.so", RTLD_NOW);
if (!mLibHandle) {
LOGE("dlopen failed on libpv.so/n");
return UNKNOWN_ERROR;
}
createPlayer_f createPlayer = reinterpret_cast(dlsym(mLibHandle, "createPlayer"));
if (!createPlayer) {
LOGE("dlsym failed on createPlayer in libpv.so/n");
return UNKNOWN_ERROR;
}
Load the libraries with a call from AudioHardwareInterface::create(), as illustrated below (full code found in //device/servers/audioflinger).
if (property_get("ro.kernel.qemu", value, 0)) {
LOGD("Running in emulation - using generic audio driver");
hw = new AudioHardwareGeneric();
}
else {
// Insert calling of dynamic loading of driver here...
}
if (hw->initCheck() != NO_ERROR) {
LOGW("Using stubbed audio hardware. No sound will be produced.");
delete hw;
hw = new AudioHardwareStub();
}
转者注:这里的意思就是说如果你的实现音频接口的内容是放在一个库里面,那么就需要通过dlopen等这些动态加载库的函数把它加载进来,在这个加载进来的库里面你必须实现AudioHarddwareInterface所规定的那些接口,上面说的第二步,在这里的体现其实就是AudioHardwareInterface::create()函数的实现,需要在这里加入你自己的类,这个用法有点像工厂模式,在工厂里面可以创造各种音频设备,虽然它可能是从别处进口的,但是这里是统一的给上层使用的地方;