Audio CB: audio_track_cblk_t
userBase, serverBase, frameCount, stepUser, stepServer, buffer, frameAvailable, frameReady
userBase: 写数据的基数位置
serverBase: 读数据的基数位置
FrameCount: 读写大小
stepUser:更新写数据的位置
stepServer: 更新读数据的位置
underrun模式:生产者跟不上消费者,消费者得wait,生产者有数据了signal
生产者:obtainBuffer/memcpy/releaseBuffer
消费者: getNextBuffer/releaseBuffer
-------------------------------------------------------------------------------------------
cblk_t | server读 | user写 | |
-------------------------------------------------------------------------------------------
stepUSER() and stepServer的作用是调整当前偏移的位置,可以看到,他们仅仅是把成员变量user server的值加上需要移动的数量,user和server的值并不考虑FIFO的边界问题,随着数据的不停写入和读出,user和server的值不断增加,只要处理得当,user总是出现在server的后面,因此frameAvailable和frameReady才会成立。根据这种算法,user和server都会大于FIFO的大小,frameCount,那么如何确定真正的写指针的位置了?需要用到userbase这个变量。在stepUser中,每当user的值越过(UserBase+farmeCount) userBase就会增加frameCount,这样映射到FIFO中的偏移总是可以通过user-userBase获得。因此,获得当前FIFO的写指针可以通过buffer()返回
p = mCblk->buffer(mcblk->user)
---------------- 华华丽丽的分割线----------------------------------
细读了android中关于audio这块的源码,发现有个地方设计的挺巧妙的。
他将一块有限的线性buffer,变成了可以循环的环形缓冲,生产者/消费者模式
原来的代码函数是,frameAvaliable Buffer stepUser// frameReady/stepServer etc.
我稍微简化了些,留作以后可能需要生产者/消费者的读写I/O
1 const int bufferSize = 1000;
2 const int loopStart = 1000;
3 //userBase = everytime the buffer write cross the scope,
4 //loop to the first place, userBase += bufferSize
5
6 /*
7 * buffer():provide the init position for write
8 */
9 void* audio_track_cblk_t::buffer(int write) const
10 {
11 return buffers + write - userBase;
12 }
13 //how many bytes could be available
14 int audio_track_cblk_t::bufferAvailable()
15 {
16 int limit = (read < loopStart) ? read : loopStart;
17 return limit + loopStart - write;
18 }
19 int audio_track_cblk_t::updateWrite(int frameCount)//frameCount is how many bytes been written
20 {
21 //update the position of write
22 write += frameCount;
23 if (write >= userBase + bufferSize){
24 userBase += bufferSize;//userBase will loop to the front
25 }
26 return write;
27 }
28 int audio_track_cblk_t::bufferCouldRead()
29 {
30 // write will always larger than read position
31 // whenever the loop has happened
32 // the max gap between write and read will be bufferSize
33 return write - read;
34 }
35 bool audio_track_cblk_t::updateReadPos(int frameCount)
36 {
37 LOG("after read, update the read position");
38 LOG("frameCount is the buffer size been read");
39 read+= frameCount;
40
41 if ( read >= userBase + bufferSize)
42 userBase += bufferSize;
43
44 signal();//signal the write side
45 return true;
46 }
稍微说明:
bufferSize就是这块线性内存的大小,userBase其实一直被增长,但是每次都是bufferSize的整数倍,当write越界了,超过bufferSize了,比如写了1300,bufferSize才1000,那userBase就必须加上1000,这样write-userBase=300,这样才是正确的相对写位置。读位置同理。
write要一直比read快,否则生产者/消费者模型就有问题了。wait/signal/broadcast/ could help.