logo资料库

android Audio ALSA框架分析.pdf

第1页 / 共44页
第2页 / 共44页
第3页 / 共44页
第4页 / 共44页
第5页 / 共44页
第6页 / 共44页
第7页 / 共44页
第8页 / 共44页
资料共44页,剩余部分请下载后查看
Android Audio 框架分析
Andrioid系统框架图
Audio JNI层接口
Media库中的Audio框架部分
AudioFlinger层
AudioFlinger的启动
1、 AudioFlinger的初始化过程
2、 createTrack函数
openRecord函数
AudioFlinger对放音的管理
3、 AudioFlinger对录音的管理
AudioFlinger以及Media层放音录音小结
Audio硬件抽象层实现
Linux内核ALSA模块分析
STE声卡驱动底层相关操作
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,
分享到:
收藏