`
kerlubasola
  • 浏览: 678650 次
文章分类
社区版块
存档分类
最新评论

Android音频数据传输

 
阅读更多
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中的数据写入到底层。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics