Android Audio 框架分析
Android Audio 框架分析.................................................................................................................1
Andrioid 系统框架图..........................................................................................................................2
Audio JNI 层接口...............................................................................................................................2
Media 库中的 Audio 框架部分..........................................................................................................4
AudioFlinger 层...................................................................................................................................7
AudioFlinger 的启动..................................................................................................................8
1、AudioFlinger 的初始化过程................................................................................................8
2、createTrack 函数...................................................................................................................9
openRecord 函数.......................................................................................................................10
AudioFlinger
对放音的管理 ...................................................................................................12
3、AudioFlinger 对录音的管理..............................................................................................14
AudioFlinger 以及 Media 层放音录音小结............................................................................18
Audio 硬件抽象层实现....................................................................................................................22
Linux 内核 ALSA 模块分析............................................................................................................24
STE 声卡驱动底层相关操作...........................................................................................................41
Andrioid 系统框架图
从 框 图 中 可 以 看 出 android 对 于 java 层 一 共 提 供 3 个 接 口 , 分 别 是
MedialPlayer、MediaREcorder 以及 AudioServier,通过 JNI 则调用到 AudioTrack(放音),
AudioRecord(录音)以及(AudioSystem)主要音频参数设定。通过 Android Binder 机制与
AudioFlinger 层 相 同 步 , 之 后 调 用 到 AudioHardware , 其 中 提 供 的 接 口 主 要 是
AudioStreamOut 以及 AudioStreamin。最终将进入 Linux 内核调用到 ALSA。
Audio JNI 层接口
Audio 在 JNI 层 的 接 口 主 要 有 AudioTrack , AudioRecorder , AudioSystem 来 提 供 ,
AudioTrack 主要实现声音的播放功能,AudioRecorder 主要实现录音功能,AudioSystem 主
要为声音系统提供必要的支持函数。所以首先先分析下以 AudioTrack 为例子,分析 Audio
对 jni 所提供的接口。通过 JNI,可以调用到 AuidoTrack 所提供的函数,例如,当上层调用
native_start 的时候,便会调用函数 android_media_AudioTrack_start,其中的函数 start()
函数在 AudioTrack 中实现,所以通过 android_media_AudioTrack.cpp,jni 的 start 调用
将进入 AudioTrack 中,通过 start()函数的分析,可知,jni 调用的其他函数的传递方式和其
类似,所以不再分析。
static void
android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
{
AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
thiz, javaAudioTrackFields.nativeTrackInJavaObj);
if (lpTrack == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for start()");
}
lpTrack->start();
}
文件的 android_media_AudioTrack_native_setup 函数中,有对声音系统的一系列初始化
操作,例如设定采样率、格式,通道数等等,在设定好这些数据后,调用 lpTrack = new
AudioTrack()完成 AudioTrack 实例化,紧接着调用 lpTrack->set()
完成刚才一系列参数的 写
”入 工作。
AudioTrack* lpTrack = new AudioTrack();
if (lpTrack == NULL) {
LOGE("Error creating uninitialized AudioTrack");
goto native_track_failure;
}
// initialize the native AudioTrack object
if (memoryMode == javaAudioTrackFields.MODE_STREAM) {
“
lpTrack->set(
atStreamType,// stream type
sampleRateInHertz,
format,// word length, PCM
nbChannels,
frameCount,
0,// flags
audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data
(user)
0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed th
e AudioTrack
0,// shared mem
true);// thread can call Java
}
Media 库中的 Audio 框架部分
AudioTrack.cpp 中的代码主要是给 jni 层 android_media_AudioTrack 提供接口。在该文
件中有 AudioTrack 类中函数的实现方法。其中某些函数将会调用 AudioSystem 中的部分函
数。在 AudioTrack.cpp 与 AudioRecord.cpp 文件中,最关键的是 write 函数和 read 函数,因
为 这 是 录 音 和 放 音 的 数 据 传 递 函 数 , 因 为 和 AudioFlinger 层 关 系 密 切 , 所 以 放 在
AudioFlinger 的录音管理和放音管理中详细描述。
AudioTrack 类的构造函数只实现一个功能,便是设定声音系统的各种参数,这些参数
是由 set()来设定的,该调用时在 jni 层完成的。下面就首先分析 set()函数。
—
首先我们要确定 AudioTrack 类中的 mAudioTrack 没有被使用。否则的话将出错。然后
通过 AudioSystem 中的 get_audio_flinger 函数获得。通过这个函数就可以获得 IAudioflinger
实例化的对象。这个 IAudioFlinger 就是一个 binder 的代理接口。至于 binder 的实现,不再
Audio 的讨论范围。接下来是一系列参数的设定。首先根据传递进来的 streamType 来获得
当前的部分参数,然后根据条件进行部分参数的设定。例如如果 sampleRate 没有设定,则
设定采样率为当前值。当这些临时变量设定好后,到了最关键的部分 createtrack()通过这
个函数的返回,获得了一个 IAudioTrack 对象,这个对象控制着整个音频系统的录音功能。
整个 AudioTrack 的音频控制功能都是通过它完成的。这里可以把 IaudioTrack 理解成是一个
接口类,所有的工作都是通过它来和 binder 来完成通信。在初始化的最后完成 AudioTrack
内其他成员函数的初始化。
status_t AudioTrack::set(
void* user,
int notificationFrames,
const sp& sharedBuffer,
bool threadCanCallJava)
{
if (mAudioTrack != 0) {
LOGE("Track already in use");
return INVALID_OPERATION;
}
const sp& audioFlinger = AudioSystem::get_audio_flin
ger();
int afSampleRate;
if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_E
RROR) {
return NO_INIT;
}
if (channelCount == 0) {
channelCount = 2;
}
status_t status;
sp track = audioFlinger->createTrack(getpid(),
streamType, sampleRate, format, channelCount, frameCount, fl
ags, sharedBuffer, &status);
sp
cblk = track->getCblk();
if (cblk == 0) {
LOGE("Could not get control block");
return NO_INIT;
}
mAudioTrack = track;
mCblkMemory = cblk;
mCblk = static_cast(cblk->pointer());
mCblk->out = 1;
// Update buffer size in case it has been limited by AudioFlinger during track cre
ation
mFrameCount = mCblk->frameCount;
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
mVolume[LEFT] = 1.0f;
return NO_ERROR;
}
Start函数是jni
层将要调用的函数,这个函数实际上是一个开关 会通过 IaudioTrack将当
前Track纳入AudioFlinger管理,其中的mAudioTrackThread是由构造函数构造时获得的,
mAudioTrackThread的作用是用来获得Audio的event的数据的。其中还包含了一些线程的控
制参数。最终通过 mAudioTrack->start()将track纳入audioflinger管理。
void AudioTrack::start()
{
sp t = mAudioTrackThread;
LOGV("start %p", this);
if (t != 0) {
if (t->exitPending()) {
if (t->requestExitAndWait() == WOULD_BLOCK) {
LOGE("AudioTrack::start called from thread");
return;
}
}
t->mLock.lock();
}
if (android_atomic_or(1, &mActive) == 0) {
mNewPosition = mCblk->server + mUpdatePeriod;
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
}
mAudioTrack->start();
}
if (t != 0) {
t->mLock.unlock();
}
}
AudioSystem.cpp 维护着上层音频系统公共部分,比说说录音和放音都是有相同的
streamType 设定,都是有相同的模式设定,以及音量设定,以及静音设定。其中最为关键
的是 get_audio_flinger()函数,因为他提供给同一层的 AudioTrack 以及 AudioRecod 提供
IaudioFlinger 接口。首先看下 Audiosystem 类
在 Audiosystem 中可以看到整个音频系统需要使用的参数,包括音频类型,输出模式 ,
音频路由等信息,其中还包含一个私有数据 class AudioFlingerClient。
class AudioSystem
{
public:
enum stream_type {
};
enum audio_in_acoustics {
};
// routing helper functions
static status_t speakerphone(bool state);
static status_t isSpeakerphoneOn(bool* state);
static status_t bluetoothSco(bool state);
static status_t isBluetoothScoOn(bool* state);
static void setErrorCallback(audio_error_callback cb);
// helper function to obtain AudioFlinger service handle
static const sp
& get_audio_flinger();
private:
class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerC
lient
{
public:
AudioFlingerClient() {
}
};
static int getOutput(int streamType);
static sp gAudioFlingerClient;
static sp gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
};
};
再看看 get_audio_flinger 的实现,首先把锁锁上,,然后调用 gAudioFlinger.get 函数,
命名空间中的变量, IaudioFlinger 的含义与 IaudioTrack 意义类
gAudioFlinger 是在 android
似,通过它可以获得 AudioFlinger 的代理接口然后通过 binder 机制调用到最后的实现函数。
接下来,获得系统默认服务里的 media.audio_flinger 类,之后创建一个 gAudioFlingerClient
对象,interface_cast 本质上就是返回一个 bpIAudioFlinger。在这个 while 循环中可以看出,
AudioSystem 会一直通过 binder 监听 media.audio_flinger 是否已经启动。
sp AudioSystem::gAudioFlinger;
const sp& AudioSystem::get_audio_flinger()
{
Mutex::Autolock _l(gLock);
if (gAudioFlinger.get() == 0) {
sp sm = defaultServiceManager();
sp binder;
do {
binder = sm->getService(String16("media.audio_flinger"));
if (binder != 0)
break;
LOGW("AudioFlinger not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (gAudioFlingerClient == NULL) {
gAudioFlingerClient = new AudioFlingerClient();
} else {
if (gAudioErrorCallback) {
gAudioErrorCallback(NO_ERROR);
}
}
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast(binder);
gAudioFlinger->registerClient(gAudioFlingerClient);
return gAudioFlinger;
}
AudioFlinger 层
由上面分析可以看出来,media 层会通过 AudioSystem 中的 get_audio_flinger()而调用到
IaudioFlinger 里的代码,IaudioFlinger 中的是 AudioFlinger 的代理接口类,在 IaudioFlinger
中有个宏定义 IMPLEMENT_META_INTERFACE(AudioFlinger …, .);由此可以知道,
AudioFlinger.cpp 是 IAudioFlinger 类的实现。
AudioFlinger 是 Audio 系统的中间层,它主要是为 Audio 系统提供部分接口的功能,在
系统中起服务的功能。其代码路径在 frameworks/base/libs/audioflinger 文件夹下。
AudioFlinger 的启动
在 main_Mediaserver 函 数 或 者 system_init ( 运 行 于 Simulator 上 ) , 会 调 用
AudioFlinger::instantiate 函 数 以 便 将 AudioFlinger 注 册 进 入 默 认 系 统 服 务 中 去 。 在
addService 函数中,new AudioFlinger 实例化了 AudioFlinger。
void AudioFlinger::instantiate() {
defaultServiceManager()->addService(
String16("media.audio_flinger"), new AudioFlinger());
}
1、 AudioFlinger 的初始化过程
在开始的地方初始化了 BnAudioFlinger、mAudioHardWare 等参数,创建硬件接口,获
得硬件输出,紧接着设定硬件输出,为混音器建立线程,设定输出路由,设定音量设定静
音模式,这些设定参数都是 AudioSystem 中获得的。在初始化的最后部分创建录音接口。
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
mAudioHardware(0), mA2dpAudioInterface(0), mA2dpEnabled(false), mNotify
A2dpChange(false),
{
mHardwareStatus = AUDIO_HW_IDLE;
mAudioHardware = AudioHardwareInterface::create();
mHardwareStatus = AUDIO_HW_INIT;
if (mAudioHardware->initCheck() == NO_ERROR) {
// open 16-bit output stream for s/w mixer
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
status_t status;
AudioStreamOut *hwOutput = mAudioHardware->openOutputStrea
m(AudioSystem::PCM_16_BIT, 0, 0, &status);
mHardwareStatus = AUDIO_HW_IDLE;
mHardwareMixerThread = new MixerThread(this, hwOutput, A
udioSystem::AUDIO_OUTPUT_HARDWARE);
setRouting(AudioSystem::MODE_NORMAL, AudioSystem::ROUTE_
SPEAKER, AudioSystem::ROUTE_ALL);
setMode(AudioSystem::MODE_NORMAL);
setMasterVolume(1.0f);
setMasterMute(false);
// Start record thread
mAudioRecordThread = new AudioRecordThread(mAudioHardware,