threadLoop函数里会调用
nsecs_t ns = mReceiver.processAudioBuffer();
mReceiver就是一个AudioTrack,接收者?天知道为嘛这么叫。
咱们先不说这个很重要的函数 processAudioBuffer,先来看看AudioTrackThread是在哪使用的。
sp mAudioTrackThread;
在AudioTrack::set()函数中:
if (cbf != NULL) {
mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
// thread begins in paused state, and will not reference us until start()
}
callback存在的话,就new它,然后run之。但是注释都说了,start()之后,这个AudioTrackThread才会真正run起来,
因为:
sp<AudioTrackThread> t = mAudioTrackThread;
if (t != 0) {
if (previousState == STATE_STOPPING) {
mProxy->interrupt();
} else {
t->resume();
}
}
里头循环调用了
status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
然后
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
即获得buffer,然后,谁创建了AudioTrack,并且设置了回调(在AudioTrack构造函数中传入参数,构造函数会调用set进行赋值),就和谁要数据。比如说nuplayer。要数据的时候就把经过解码的pcm数据传下来。
真正干活的也不是这。干活的是:
status = proxy->obtainBuffer(&buffer, requested, elapsed);
实现在AudioTrackShare.cpp里头。
(某一种情况)这个地方取到buffer的地址,然后通过
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
举个MediaPlayer中的例子啊:
/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp中
case AudioTrack::EVENT_MORE_DATA: {
size_t actualSize = (*me->mCallback)(
me, buffer->raw, buffer->size, me->mCallbackCookie,
CB_EVENT_FILL_BUFFER);
...
case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
{
return me->fillAudioBuffer(buffer, size);
break;
}
MediaPlayer中fillAudioBuffer的源头.
把数据取回来,由于取到的这个buffer,audioFlinger那边也能访问,所以。。。
这里头有一个很重要的调用:createTrack_l(),这个函数在凡平老师的书里也说到了。AudioTrack和 AudioFlinger的联系啊简直是。
这里头又调用了以前经常见到的一个函数AudioSystem::getOutputForAttr,这个函数一路下调到apm里头,现在暂且略过不表。
createTrack_l()函数中经过了很复杂的流程,以及获取,设置了好多参数之后(其实是没看懂,一笔带过),调用了
sp track = audioFlinger->createTrack(streamType,
mSampleRate,mFormat,mChannelMask,&temp,&trackFlags,mSharedBuffer,output,tid,&mSessionId,(mClientPid << 16) |mClientUid,&status);
通过AudioFlinger的createTrack函数,返回了一个 sp
,我记得这个东西对应
的就是TrackHandle类(AudioFlinger里头一个小小的内部类)。
再之后,贯穿AudioTrack类其中的mAudioTrack变量就是从这来的。
mAudioTrack = track;
很多AudioTrack的操作,都是调用TrackHandle类。最终由playbackThread的track类完成实际工作。
这还涉及到了共享内存,共享buffer等内容。略过先。
还是先继续瞅瞅createTrack函数吧。
track = thread->createTrack_l(client, streamType, sampleRate, format,channelMask,
frameCount,sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus);
//妈蛋的,你瞅瞅,还要接着往下走,这个地方返回的track类型是啥呢?
sp track;
// return handle to client
trackHandle = new TrackHandle(track);
最终AudioFlinger的createTrack函数是这么返回的:
用PlaybackThread::createTrack_l()函数返回一个PlaybackThread::Track对象,然后用这个对象作为参数,构造一个TrackHandle对象,然后返回。
言归正传,接下来
if (!isTimed) {
track = new Track(this, client, streamType, sampleRate, format,
channelMask, frameCount, NULL, sharedBuffer,sessionId, uid, *flags,
TrackBase::TYPE_DEFAULT);
} else {
track = TimedTrack::create(this, client, streamType, sampleRate, format,
channelMask, frameCount, sharedBuffer, sessionId, uid);
}
TimedTrack是什么鬼,说普通的吧:
PlaybackThread内部类Track又是什么鬼?
这他妈应该是真正干活的了吧,再往下好像还有proxy.我要吐了。看到这边audioflinger,才发现,audiotrack的内容实在是太少了。
nsecs_t ns = mReceiver.processAudioBuffer();
这个函数返回纳秒,而函数内部return的地方,多是调用了
framesToNanoseconds()
static inline nsecs_t framesToNanoseconds(ssize_t frames, uint32_t sampleRate, float speed){
return ((double)frames * 1000000000) / ((double)sampleRate * speed);
}
函数的实现也很简单。虽然不是很懂,到应该是s转换成了ns(纳秒)。难道是每次拿到的数据所持续的播放时间?
//基类:Proxy
//Client系列:
- ClientProxy
- AudioTrackClientProxy
- StaticAudioTrackClientProxy
- AudioRecordClientProxy
//Server系列:
- AudioTrackServerProxy
- StaticAudioTrackServerProxy
- AudioRecordServerProxy
继承关系一目了然,从名字大概能猜出来。
代码的文件名中Share基本能说明,这些类应该和AudioFlinger,或者说给AudioTrack提供数据的一方关系很大。当然AudioTrack肯定是有关系的了。AudioTrack对应Client,AudioFlinger对应server。这两者之间还有一个生产者,消费者的关系(别人说的)。
话说AudioTrack类的obtainBuffer调用了
status_t ClientProxy::obtainBuffer
这里边有个函数
StaticAudioTrackServerProxy::pollPosition()
也同样被调用到,然后呢?没看懂呢,先不继续了。。。
// Proxy used by AudioFlinger server
class ServerProxy : public Proxy {
看着没?头文件都说了,AudioFlinger用的!
费了半天劲,在AudioFlinger找到了一个变量mServerProxy,sourceinsight无法跳转,grep搜索发现,定义在了TrackBase.h里了
void AudioFlinger::ThreadBase::TrackBase
,子类的子类呀!
让我们看看真正的证据吧:
AudioFlinger::PlaybackThread::Track::Track()
构造函数里调用了
if (sharedBuffer == 0) {
mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
mFrameSize, !isExternalTrack(), sampleRate);
} else {
mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
mFrameSize);
}
没错,和我们想的一样,就是用的ServerProxy.
上面的参数,mCblk,mBuffer,等参数在sourceInsight上是黑色的,没法跳转,根据经验,定义在基类里,即TrackBase.h文件里。比如说mBuffers(Track类的)从 StaticAudioTrackServerProxy()构造函数一路传了上去,最终,传到了前面说的Proxy类的mBuffers。
而这个mBuffers基本上就是obtainBuffer取数据的源泉啊。
mBuffers在AudioFlinger构造serverProxy的时候一步步传进来。然后在AudioTrack调用ClientProxy的obtainBuffer(write方式或者是processAudioBuffer方式都会调用)的时候通过参数返回。AudioTrack拿到共有缓冲区的地址之后,就可以往里放数据了也就是说,AudioFlinger和AudioTrack在通过这个mBuffers传递数据呀!这个地方还有一点需要说一下。就是
这个地方为什么有两个类,有一个前面多了一个static.使用场景不一样!static的那个是用在ShareBuffer给定(AudioTrack()那个参数不为空)的情况下,一直去里头取数据即可。所以说是static的。
ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
上层应用调用这个函数,然后不断往下写经过解码的数据。这里边的buffer就是数据了。
while (userSize >= mFrameSize) {
//。。。
status_t err = obtainBuffer(&audioBuffer,
blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
// 。。。
memcpy(audioBuffer.i8, buffer, toWrite);
//。。。
releaseBuffer(&audioBuffer);
}
其中的这个while循环不断做的事情就是通过obtainBuffer获得和AudioFlinger共享的buffer。然后往里头memcpy上层write的数据。最后releaseBuffer。
如果构造AudioTrack的时候,选用的构造函数是带callback_t cbf的那个,并且传入了存在的一个值,在AudioTrack的构造函数里就会调用set函数,把这个cbf传递给AudioTrack的mCbf这个成员变量。只要
``mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);``
类似这样的调用方式,就会回调到在构造函数里传入的那个地址。比如SoundPool就把process函数作为了回调函数传给了AudioTrack。
从字面意思看就是,我需要数据,快给我数据!不过soundPool一般是不会回调 EVENT_MORE_DATA的。因为一般数据量都很少,一次就可以搞定。soundPool一般都是回调EVENT_BUFFER_END。通知上层,数据没了。