- 架构概述
- 代码详解
- 运作流程图
1. 架构概述
在Stagefright中,AwesomePlayer只负责完成Video的处理,而Audio部分则交由AudioPlayer完成。
整个Android Mediaframework 的运作部分可分为三层,即libmedia, libmediaplayerservice, libstagefright三大模块。AudioPlayer与AwesomePlayer同在stagefright模块,但AudioPlayer运作却联系到了mediaplayerservice层以及media层,如图所示。其中,mediaplayerservice模块中的AudioOutput作为AudioSink与AudioPlayer相接,而其本身又与media模块中的AudioTrack交互;AudioTrack是AudioThread线程触发的对象,主要完成对Audiobuffer的处理。AudioSystem则作为工具对象被AudioTrack所使用,例如获取audio的samplingrate, framecount等,另一个重要的作用就是AudioSystem通过Binder机制直接与AudioFingerService进行交互,并将AudioFingerClient交给AudioTrack使用。
2. 代码详解
当需要播放一段影音多媒体时,从上层调入到AwesomePlayer中的函数主要有三个,分别是setDataSource(), prepareAsync(), play()。而AudioPlayer是在play()函数之中建立的,AudioThread也是在这之后才开始的,因此前两个函数就不再展开了。这里要详说的是执行play()函数后的一系列关于audio的流程。
play()函数的实体是play_l(),主要完成两个工作。一是新建AudioPlayer,二是启动AudioPlayer。- status_t AwesomePlayer::play_l() {
- ...
- mAudioPlayer = new AudioPlayer(mAudioSink, this);
- mAudioPlayer->start(); // inside of startAudioPlayer_l()
- ...
- }
在这里可以注意到新建的同时设了两个参数给AudioPlayer,其中mAudioSink是在MediaPlayerService层执行SetDataSource()时初始化的,mAudioSink的实质对象其实就是位于该层的AudioOutput。
- status_t MediaPlayerService::Client::setDataSource(...)
- {
- ...
- mAudioOutput = new AudioOutput(mAudioSessionId);
- static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
- ...
- }
创建AudioPlayer第二个参数this就是把AwesomePlayer指针本身设给AudioPlayer作为观察者对象(mObserver),
以此获取AudioPlayer之后的通知,例如mObserver->postAudioEOS()。
当创建完AudioPlayer之后便调用其start()函数,AudioPlayer最核心的工作就从这里开始。
- status_t AudioPlayer::start(...)
- {
- mSource->read(...); ------- (1)
...
- if (mAudioSink.get() != NULL)
- {
- mAudioSink->open(..., &AudioPlayer::AudioSinkCallback, ...); ------- (2)
- mAudioSink->start();
------- (3)
- }
- else
- {
- mAudioTrack = new AudioTrack(..., &AudioPlayer::AudioCallback, ...);
- mAudioTrack->start();
- }
- }
(1)调用的是OMXCodec::read(),读取audio decoder数据,与video是一样的,这里就不详说了。(2)调用了位于libmediaservice模块的AudioOutput对象的AudioOutput::open(),意为开启AudioSink,其实是做了启动audio线程的前期工作,我们来具体看下。
- status_t MediaPlayerService::AudioOutput::open(
..., AudioCallback cb, ... )
- {
- mCallback = cb;
/*R2*/
- ...
-
- AudioTrack *t;
- if (mCallback != NULL) {
- t = new AudioTrack(..., CallbackWrapper,...);
- }
- ...
- mTrack = t;
- }
open函数里的形参cb其实就是AudioPlayer::AudioSinkCallback函数的指针,并把这个值设给mCallback,作为后续的回调函数使用。随后创建AudioTrack,并赋给mTrack。创建的同时会将自身的CallbackWrapper函数传给AudioTrack作为回调。下面我们来看下AudioTrack创建的过程,这里涉及到一些关键的地方。
- AudioTrack::AudioTrack(..., callback_t cbf,...)
- {
- mStatus = set(
..., cbf,... );
- }
- status_t AudioTrack::set(..., callback_t cbf,...)
- {
- ...
- status_t status = createTrack_l();
- ...
-
- if (cbf != 0)
- {
- mAudioTrackThread = new AudioTrackThread(...);
- ...
- }
- ...
mCbf = cbf; /*R1*/
- }
AudioTrack构造函数调用了自身的set()主要完成了两个工作,createTrack和创建AudioTrackThread。另外,成员回调函数mCbf最后得到的值其实就是AudioOutput::CallbackWrapper()。- status_t AudioTrack::createTrack_l(...)
- {
- const sp& audioFlinger = AudioSystem::get_audio_flinger();
...
sp track = audioFlinger->createTrack();
mAudioTrack = track;
- }
在createTrack过程中,先由AudioSystem获取一个AudioFlinger的client对象,然后通过binder机制在AudioFlinger实体中执行createTrack,track当然也是在
AudioFlinger 内部创建的,由于是跨进程,具体过程不再追溯。随后就是创建AudioTrackThread,该对象是用来驱动AudioTrack的,看到后面就会清楚。
至此,AudioOutput::open()的工作就结束了。到底做了哪些工作呢?归结起来就是两点。一是设置各层对象的回调函数;二是创建AudioTrack。而在AudioTrack的创建中其实就是创建了两个对象,一个位于AudioFlinger中的track,拿到的是该track的指针,另一个便是AudioTrackThread,用来对AudioTrack做线程驱动。如此一来,启动AudioTrack前的准备工作就算做好了。
(3)调用了AudioOutput::start(),我们下面就来看audio线程是如何启动和运作的。
- void MediaPlayerService::AudioOutput::start()
- {
- if (mTrack) {
- ...
- mTrack->start();
- }
- }
- void AudioTrack::start()
- {
- sp<AudioTrackThread> t = mAudioTrackThread;
- ...
- t->run(...);
- ...
- status = mAudioTrack->start();
- }
这边其实就两个工作:mAudioTrackThread->run() 和 mAudioTrack->start()。我们回顾下AudioOutput::open()时做的工作便可知道:前者是开启AudioTrackThread线程,从而驱动AudioTrack工作(其流程下面会做详细介绍)。后者则是开启AudioFlinger那侧的track,进行audio buffer的协同处理(属于AudioFlingerService进程范围不再深入)。我们来看下
AudioTrackThread 具体运作流程。运行mAudioTrackThread->run()对应启动的是AudioTrackThread 父类的Thread::run()。
- status_t Thread::run(...)
- {
- ...
- if (mCanCallJava) {
- res = createThreadEtc(_threadLoop,
- this, name, priority, stack, &mThread);
- } else {
- res = androidCreateRawThreadEtc(_threadLoop,
- this, name, priority, stack, &mThread);
- }
- ...
- }
这里无论是走哪个if分支都会启动一个Thread::_threadLoop()函数线程。- int Thread::_threadLoop(void* user)
- {
...
- bool first = true;
-
- do {
- bool result;
- if (first) {
- first = false;
- self->mStatus = self->readyToRun();
-
- ...
- }else{
- result = self->threadLoop();
- }
}while(strong != 0);
return 0;
- }
正常情况下在这个函数体内会循环运行自身的threadLoop(),也就是子类的AudioTrackThread::threadLoop()。- bool AudioTrack::AudioTrackThread::threadLoop()
- {
- return mReceiver.processAudioBuffer(this);
- }
mReceiver就是AudioTrack对象本身,是AudioTrackThread随同AudioTrack一起创建的时候赋的值。所以这里函数循环的实体便是AudioTrack::processAudioBuffer()。- bool AudioTrack::processAudioBuffer(...)
- {
...
- do{
status_t err = obtainBuffer(&audioBuffer, waitCount);
...
mCbf(..., &audioBuffer);
...
releaseBuffer(&audioBuffer);
}
while(frames);
- }
这里最关键的就是调用了mCbf,这个回调函数的值可以参照前文代码中“/*R1*/”注释的内容。其实就是调用了AudioOutput::CallbackWrapper()。- void MediaPlayerService::AudioOutput::CallbackWrapper()
- {
- ...
- size_t actualSize = (*me->mCallback)(...);
- ...
- }
函数内部又调用了AudioOutput自身的mCallback成员回调函数(参照上文代码/*R2*/),其实就是AudioPlayer::AudioSinkCallback()。- size_t AudioPlayer::AudioSinkCallback()
- {
- ...
return me->fillBuffer(buffer, size);
- }
size_t AudioPlayer::fillBuffer(...)
{
...
mSource->read(&mInputBuffer, ...);
...
memcpy(data, mInputBuffer->data(), ...);
}
通过fillBuffer()调用了OMXCodec::read(),随即将codec处理完的数据(mInputBuffer)复制到data(之后AudioOutput应该会去取用data),这样就完成了整个audio线程的运作。
3.运作流程图
阅读(1291) | 评论(0) | 转发(0) |