return u - s; } else {
Mutex::Autolock _l(lock); if (loopCount >= 0) {
return (loopEnd - loopStart)*loopCount + u - s; } else {
return UINT_MAX; } } } else {
return s - u; } }
我们看看下面的示意图:
_____________________________________________ ^ ^ ^ ^
buffer_start server(s) user(u) buffer_end
很明显,frameReady = u - s,frameAvalible = frameCount - frameReady = frameCount - u + s
可能有人会问,应为这是一个环形的buffer,一旦user越过了buffer_end以后,应该会发生下面的情况:
_____________________________________________ ^ ^ ^ ^
buffer_start user(u) server(s) buffer_end
这时候u在s的前面,用上面的公式计算就会错误,但是android使用了一些技巧,保证了上述公式一直成立。我们先看完下面三个函数的代码再分析: [c-sharp] view plaincopy
uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) {
uint32_t u = this->user; u += frameCount; ......
if (u >= userBase + this->frameCount) { userBase += this->frameCount; }
this->user = u; ...... return u; }
[c-sharp] view plaincopy
bool audio_track_cblk_t::stepServer(uint32_t frameCount) {
6
// the code below simulates lock-with-timeout
// we MUST do this to protect the AudioFlinger server // as this lock is shared with the client. status_t err;
err = lock.tryLock();
if (err == -EBUSY) { // just wait a bit usleep(1000);
err = lock.tryLock(); }
if (err != NO_ERROR) {
// probably, the client just died. return false; }
uint32_t s = this->server; s += frameCount; // 省略部分代码 // ......
if (s >= serverBase + this->frameCount) { serverBase += this->frameCount; }
this->server = s; cv.signal(); lock.unlock(); return true; }
[c-sharp] view plaincopy
void* audio_track_cblk_t::buffer(uint32_t offset) const {
return (int8_t *)this->buffers + (offset - userBase) * this->frameSize; }
stepUser()和stepServer的作用是调整当前偏移的位置,可以看到,他们仅仅是把成员变量user或server的值加上需要移动的数量,user和server的值并不考虑FIFO的边界问题,随着数据的不停写入和读出,user和server的值不断增加,只要处理得当,user总是出现在server的后面,因此frameAvalible()和
frameReady()中的算法才会一直成立。根据这种算法,user和server的值都可能大于FIFO的大小:framCount,那么,如何确定真正的写指针的位置呢?这里需要用到userBase这一成员变量,在stepUser()中,每当user的值越过
(userBase+frameCount),userBase就会增加frameCount,这样,映射到FIFO中的偏移总是可以通过(user-userBase)获得。因此,获得当前FIFO的写地址指针可以通过成员函数buffer()返回: p = mClbk->buffer(mclbk->user);
7
在AudioTrack中,封装了两个函数:obtainBuffer()和releaseBuffer()操作FIFO,obtainBuffer()获得当前可写的数量和写指针的位置,releaseBuffer()则在写入数据后被调用,它其实就是简单地调用stepUser()来调整偏移的位置。
IMemory接口
在createTrack的过程中,AudioFlinger会根据传入的frameCount参数,申请一块内存,AudioTrack可以通过IAudioTrack接口的getCblk()函数获得指向该内存块的IMemory接口,然后AudioTrack通过该IMemory接口的pointer()函数获得指向该内存块的指针,这块内存的开始部分就是audio_track_cblk_t结构,紧接着是大小为frameSize的FIFO内存。
IMemory->pointer() ---->|_______________________________________________________ |__audio_track_cblk_t__|_______buffer of FIFO(size==frameCount)____|
看看AudioTrack的createTrack()的代码就明白了: [c-sharp] view plaincopy
sp
sampleRate,
format, channelCount,
frameCount,
((uint16_t)flags) << 16,
sharedBuffer,
output, &status); // 得到IMemory接口
sp
// 得到audio_track_cblk_t结构
mCblk = static_cast(cblk->pointer()); // 该FIFO用于输出
8
mCblk->out = 1; // Update buffer size in case it has been limited by AudioFlinger during track creation
mFrameCount = mCblk->frameCount; if (sharedBuffer == 0) { // 给FIFO的起始地址赋值 mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else {
.......... }
1.Android Audio System 之二:AudioFlinger 引言 AudioFlinger是Android音频系统的两大服务之一,另一个服务是
AudioPolicyService,这两大服务都在系统启动时有MediaSever加载,加载的代码位于:frameworks/base/media/mediaserver/main_mediaserver.cpp。
AudioPolicyService的相关内容请参考另一编文章:《Android Audio System 之三: AudioPolicyService 和 AudioPolicyManager 》
http://blog.csdn.net/DroidPhone/archive/2010/10/18/5949280.aspx
本文主要介绍AudioFlinger,AudioFlinger向下访问AudioHardware,实现输出音频数据,控制音频参数。同时,AudioFlinger向上通过IAudioFinger接口提供服务。所以,AudioFlinger在Android的音频系统框架中起着承上启下的作用,地位相当重要。AudioFlinger的相关代码主要在:frameworks/base/libs/audioflinger,也有部分相关的代码在frameworks/base/media/libmedia里。 AudioFlinger的类结构
下面的图示描述了AudioFlinger类的内部结构和关系:
9
图一 AudioFlinger的类结构
不知道各位是否和我一样,第一次看到AudioFlinger类的定义的时候都很郁闷--这个类实在是庞大和臃肿,可是当你理清他的关系以后,你会觉得相当合理。下面我们一一展开讨论。 IAudioFlinger接口
这是AudioFlinger向外提供服务的接口,例如openOutput,openInput,createTrack,openRecord等等,应用程序或者其他service通过
ServiceManager可以获得该接口。该接口通过继承BnAudioFlinger得到。 ThreadBase
10