obtainBuffer数据是如何传输

MediaPlayer那边就不看了,从AudioTrack开始研究。


1、AudioTrack::write函数
调用函数obtainBuffer获取到一块buffer,然后把传入的数据copy到获取的buffer中。


2、AudioTrack::obtainBuffer函数
该函数的主要功能就是对传入的audioBuffer进行赋值。
看看audioBuffer的类型:
class Buffer
    {
    public:
        enum {
            MUTE    = 0x00000001
        };
        uint32_t    flags;
        int         channelCount;
        int         format;
        size_t      frameCount;
        size_t      size;
        union {
            void*       raw;
            short*      i16;
            int8_t*     i8;
        };
    };

其中存放数据的是下面这个东东:
union {
            void*       raw;
            short*      i16;
            int8_t*     i8;
        };

对这块东东赋值的代码如下:
audioBuffer->raw = (int8_t *)cblk->buffer(u);


先看其中cblk的来历:
audio_track_cblk_t* cblk = mCblk;


mCblk的赋值在函数AudioTrack::createTrack中:
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());


cblk的由来:
sp<IMemory> cblk = track->getCblk();


track的由来:
    sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
                                                      streamType,
                                                      sampleRate,
                                                      format,
                                                      channelCount,
                                                      frameCount,
                                                      ((uint16_t)flags) << 16,
                                                      sharedBuffer,
                                                      output,
                                                      &mSessionId,
                                                      &status);
 
函数AudioFlinger::createTrack返回的是一个TrackHandle对象:
trackHandle = new TrackHandle(track);
return trackHandle;


track的由来:
        track = thread->createTrack_l(client, streamType, sampleRate, format,
                channelCount, frameCount, sharedBuffer, lSessionId, &lStatus);

函数AudioFlinger::PlaybackThread::createTrack_l返回的是一个Track对象:
        track = new Track(this, client, streamType, sampleRate, format,
                channelCount, frameCount, sharedBuffer, sessionId);
    return track;

看看函数TrackHandle::getCblk() :
return mTrack->getCblk();


mTrack就是作为构造函数传入的track对象。


函数AudioFlinger::ThreadBase::TrackBase::getCblk() 的实现:
return mCblkMemory;


mCblkMemory的赋值在构造函数AudioFlinger::ThreadBase::TrackBase::TrackBase中:
mCblkMemory = client->heap()->allocate(size);
mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer()); // 这个成员变量也很重要


client是构造函数参数:
const sp<Client>& client


函数AudioFlinger::Client::heap:
return mMemoryDealer;


mMemoryDealer的赋值在函数AudioFlinger::Client::Client中:
mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client"))


看看函数MemoryDealer::allocate:
sp<IMemory> MemoryDealer::allocate(size_t size)
{
    sp<IMemory> memory;
// allocator()直接返回mAllocator
// mAllocator的赋值在构造函数中:mAllocator(new SimpleBestFitAllocator(size))
/× 函数SimpleBestFitAllocator::allocate的实现:
size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags)
{
Mutex::Autolock _l(mLock);
// 暂止
ssize_t offset = alloc(size, flags);
return offset;
}
×/
    const ssize_t offset = allocator()->allocate(size);
    if (offset >= 0) {
// heap()直接返回mHeap
// mHeap的赋值在构造函数中:mHeap(new MemoryHeapBase(size, 0, name))
        memory = new Allocation(this, heap(), offset, size);
    }
    return memory;
}


可见前面的mCblkMemory其实就是一个Allocation对象。


可见AudioTrack的成员变量mCblk和AudioFlinger::ThreadBase::TrackBase的成员变量mCblk的值相同,
都是:static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())。


函数IMemory::pointer的实现:
void* IMemory::pointer() const {
    ssize_t offset;
    sp<IMemoryHeap> heap = getMemory(&offset);
    void* const base = heap!=0 ? heap->base() : MAP_FAILED;
    if (base == MAP_FAILED)
        return 0;
    return static_cast<char*>(base) + offset;
}


回头过去,看看函数audio_track_cblk_t::buffer:
return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;


可见audio_track_cblk_t的主要作用是申请了一块内存空间。
调用函数AudioTrack::write的时候,会先将数据写到这个内存空间中。


3、数据写入到了audio_track_cblk_t中,谁又会来使用这些数据呢?
看代码可知,函数AudioTrack::obtainBuffer中会先调用audio_track_cblk_t::framesAvailable。
同时,我们发现还有一个函数audio_track_cblk_t::framesReady。
单从字面上也可以看出来,这是告诉用户准备好了多少数据。
搜搜哪儿调用了函数audio_track_cblk_t::framesReady吧。
搜了下,发现有三个函数中调用了它,分别是:
AudioFlinger::MixerThread::prepareTracks_l函数
AudioFlinger::DirectOutputThread::threadLoop函数
AudioFlinger::PlaybackThread::Track::getNextBuffer函数


4、先看看函数AudioFlinger::MixerThread::prepareTracks_l函数。
字面上看,应该是准备提供数据的Tracks。
果然不错,函数中调用AudioMixer::setBufferProvider将Track设置到mAudioMixer(AudioMixer)中。
函数AudioMixer::setBufferProvider实现:
status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
{
    mState.tracks[ mActiveTrack ].bufferProvider = buffer;
    return NO_ERROR;
}
然后调用函数AudioMixer::setParameter将Track的main buffer也设置到mAudioMixer(AudioMixer)中。
函数AudioMixer::setParameter中与main buffer相关的部分代码:
        if (name == MAIN_BUFFER) {
            if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
                mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
                LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
                invalidateState(1<<mActiveTrack);
            }
            return NO_ERROR;
        }


类函数AudioMixer中是如何来使用bufferProvider的呢?
AudioMixer中的以process__为前缀的几个函数都是有到了bufferProvider。
但从数据传输上来说,这几个函数是类似的。
我们只看其中的AudioMixer::process__OneTrack16BitsStereoNoResampling函数。
函数中有代码:
t.bufferProvider->getNextBuffer(&b);
我们知道,bufferProvider其实就是Track,而我们探讨的是音频播放,所以就跳到了函数:AudioFlinger::PlaybackThread::Track::getNextBuffer,
也就是前面我们搜到的,调用audio_track_cblk_t::framesReady的三个函数之一。
函数AudioFlinger::PlaybackThread::Track::getNextBuffer是从audio_track_cblk_t中取得已准备好的音频数据,
写到什么地方去,下面我们开始研究。


回到函数process__OneTrack16BitsStereoNoResampling中,我们知道,调用AudioFlinger::PlaybackThread::Track::getNextBuffer获取的地址赋值给了in:
int16_t const *in = b.i16;


后来取in的数据给了rl:
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);


然后将rl赋值给out:
*out++ = (r<<16) | (l & 0xFFFF);


由此可见,我们刚才疑惑的“写到什么地方去”,其实就是写到out里了。


out的来历:
int32_t* out = t.mainBuffer;


这不就是函数AudioMixer::setParameter中赋值的main buffer么???
搞了一圈,原来AudioMixer的功能就是将Track里audio_track_cblk_t中的数据,赋值给Track里的mainBuffer。


下面好好看看这个main buffer的来历吧。


由前面的分析可知,调用函数AudioMixer::setParameter,来设置main buffer的地方是函数AudioFlinger::MixerThread::prepareTracks_l。
回过去看看对函数AudioMixer::setParameter的调用:
            mAudioMixer->setParameter(
                AudioMixer::TRACK,
                AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
函数mainBuffer()实现:
 return mMainBuffer; 
 
 mMainBuffer的赋值在函数setMainBuffer中:
 setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
 
 看看谁调用了函数setMainBuffer吧。
 
 有三个地方调用了函数setMainBuffer:
 a、AudioFlinger::PlaybackThread::createTrack_l函数
 b、AudioFlinger::PlaybackThread::addEffectChain_l函数
 c、AudioFlinger::PlaybackThread::removeEffectChain_l函数
 
 b和c类似,都是将PlaybackThread的mMixBuffer赋值给了main buffer。
 
 先看看a.
 track->setMainBuffer(chain->inBuffer());
 作为main buffer的是chain->inBuffer()这个东东。
 
 inBuffer()函数实现:return mInBuffer;
 mInBuffer中函数setInBuffer中被赋值:
 mInBuffer = buffer;
 
 看看调用setInBuffer函数的地方:
 AudioFlinger::PlaybackThread::addEffectChain_l函数
 AudioFlinger::EffectChain::addEffect_l函数
 
 先看看AudioFlinger::PlaybackThread::addEffectChain_l函数中的处理,
 函数中根据是否为DIRECT output thread,有两种处理方式:
 一种是处理direct output thread:
调用函数setMainBuffer将PlaybackThread的mMixBuffer告诉给Track,即告诉Track,在AudioMixer中往PlaybackThread的mMixBuffer中copy数据。
然后将effect  chain的input buffer和output buffer都设置为PlaybackThread的mMixBuffer。
(目的是让该effect chain不起作用?存在注释“Only one effect chain can be present in direct output thread and it usesthe mix buffer as input”)
另一种是处理非direct output thread:
new一段buffer出来。
调用函数setMainBuffer将新buffer告诉给Track,即告诉Track,在AudioMixer中往新buffer中copy数据。
调用函数setInBuffer来实装chain的input buffer。(发现函数AudioFlinger::PlaybackThread::createTrack_l中其实有将chain的input buffer赋值给Track的main buffer)。
然后将PlaybackThread的mMixBuffer赋值给chain的output buffer。
也就是说,Track将数据copy到自己的main buffer(即effect chain的input buffer),
effect chain对数据进行处理,然后将处理过的数据赋值给自己的output buffer(即PlaybackThread的mMixBuffer)

mMixBuffer是如何被使用的呢?


函数AudioFlinger::MixerThread::threadLoop中调用函数AudioStreamOutALSA::write(HAL侧)。
函数AudioStreamOutALSA::write中调用了函数snd_pcm_mmap_writei或者snd_pcm_writei。
函数snd_pcm_mmap_writei或者snd_pcm_writei将mMixBuffer中的数据写入到底层。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值