您的位置:首页 > 移动开发 > Android开发

Android音频数据传输

2012-04-11 22:32 239 查看
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中的数据写入到底层。

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息