Android深入浅出之Audio 第一部分 AudioTrack分析

http://www.cnblogs.com/innost/archive/2011/01/09/1931457.html

Android深入浅出之Audio 第二部分 AudioFlinger分析

http://www.cnblogs.com/innost/archive/2011/01/15/1936425.html

Android深入浅出之Audio第三部分Audio Policy[1]

http://www.cnblogs.com/innost/archive/2011/01/22/1942149.html

Android深入浅出之Audio

第一部分AudioTrack分析

一目的

本文的目的是通过从Audio系统来分析Android的代码,包括Android自定义的那套机制和一些常见类的使用,比如Thread,MemoryBase等。

分析的流程是:

l先从API层对应的某个类开始,用户层先要有一个简单的使用流程。

l根据这个流程,一步步进入到JNI,服务层。在此过程中,碰到不熟悉或者第一次见到的类或者方法,都会解释。也就是深度优先的方法。

1.1分析工具

分析工具很简单,就是sourceinsight和android的API doc文档。当然还得有android的源代码。我这里是基于froyo的源码。

注意,froyo源码太多了,不要一股脑的加入到sourceinsight中,只要把framwork目录下的源码加进去就可以了,后续如要用的话,再加别的目录。

二Audio系统

先看看Audio里边有哪些东西?通过Android的SDK文档,发现主要有三个:

lAudioManager:这个主要是用来管理Audio系统的

lAudioTrack:这个主要是用来播放声音的

lAudioRecord:这个主要是用来录音的

其中AudioManager的理解需要考虑整个系统上声音的策略问题,例如来电话铃声,短信铃声等,主要是策略上的问题。一般看来,最简单的就是播放声音了。所以我们打算从AudioTrack开始分析。

三AudioTrack(JAVA层)

JAVA的AudioTrack类的代码在:

framework\base\media\java\android\media\AudioTrack.java中。

3.1 AudioTrack API的使用例子

先看看使用例子,然后跟进去分析。至于AudioTrack的其他使用方法和说明,需要大家自己去看API文档了。

//根据采样率,采样精度,单双声道来得到frame的大小。

int bufsize = AudioTrack.getMinBufferSize(8000,//每秒8K个点

  AudioFormat.CHANNEL_CONFIGURATION_STEREO,//双声道

AudioFormat.ENCODING_PCM_16BIT);//一个采样点16比特-2个字节

//注意,按照数字音频的知识,这个算出来的是一秒钟buffer的大小。

//创建AudioTrack

AudioTrack trackplayer = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,

  AudioFormat.CHANNEL_CONFIGURATION_ STEREO,

  AudioFormat.ENCODING_PCM_16BIT,

  bufsize,

AudioTrack.MODE_STREAM);//

trackplayer.play() ;//开始

trackplayer.write(bytes_pkg, 0, bytes_pkg.length) ;//往track中写数据

….

trackplayer.stop();//停止播放

trackplayer.release();//释放底层资源。

这里需要解释下两个东西:

1 AudioTrack.MODE_STREAM的意思:

AudioTrack中有MODE_STATIC和MODE_STREAM两种分类。STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。这个和我们在socket中发送数据一样,应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。

这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。

而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack,后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。

这种方法对于铃声等内存占用较小,延时要求较高的声音来说很适用。

2 StreamType

这个在构造AudioTrack的第一个参数中使用。这个参数和Android中的AudioManager有关系,涉及到手机上的音频管理策略。

Android将系统的声音分为以下几类常见的(未写全):

lSTREAM_ALARM:警告声

lSTREAM_MUSCI:音乐声,例如music等

lSTREAM_RING:铃声

lSTREAM_SYSTEM:系统声音

lSTREAM_VOCIE_CALL:电话声音

为什么要分这么多呢?以前在台式机上开发的时候很少知道有这么多的声音类型,不过仔细思考下,发现这样做是有道理的。例如你在听music的时候接到电话,这个时候music播放肯定会停止,此时你只能听到电话,如果你调节音量的话,这个调节肯定只对电话起作用。当电话打完了,再回到music,你肯定不用再调节音量了。

其实系统将这几种声音的数据分开管理,所以,这个参数对AudioTrack来说,它的含义就是告诉系统,我现在想使用的是哪种类型的声音,这样系统就可以对应管理他们了。

3.2分析之getMinBufferSize

AudioTrack的例子就几个函数。先看看第一个函数:

AudioTrack.getMinBufferSize(8000,//每秒8K个点

  AudioFormat.CHANNEL_CONFIGURATION_STEREO,//双声道

AudioFormat.ENCODING_PCM_16BIT);

----->AudioTrack.JAVA

//注意,这是个static函数

static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {

int channelCount = 0;

switch(channelConfig) {

case AudioFormat.CHANNEL_OUT_MONO:

case AudioFormat.CHANNEL_CONFIGURATION_MONO:

channelCount = 1;

break;

case AudioFormat.CHANNEL_OUT_STEREO:

case AudioFormat.CHANNEL_CONFIGURATION_STEREO:

channelCount = 2;--->看到了吧,外面名字搞得这么酷,其实就是指声道数

break;

default:

loge("getMinBufferSize(): Invalid channel configuration.");

return AudioTrack.ERROR_BAD_VALUE;

}

//目前只支持PCM8和PCM16精度的音频

if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)

&& (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {

loge("getMinBufferSize(): Invalid audio format.");

return AudioTrack.ERROR_BAD_VALUE;

}

//ft,对采样频率也有要求,太低或太高都不行,人耳分辨率在20HZ到40KHZ之间

if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) {

loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate.");

return AudioTrack.ERROR_BAD_VALUE;

}

//调用native函数,够烦的,什么事情都搞到JNI层去。

int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);

if ((size == -1) || (size == 0)) {

loge("getMinBufferSize(): error querying hardware");

return AudioTrack.ERROR;

}

else {

return size;

}

native_get_min_buff_size--->在framework/base/core/jni/android_media_track.cpp中实现。(不了解JNI的一定要学习下,否则只能在JAVA层搞,太狭隘了。)最终对应到函数

static jint android_media_AudioTrack_get_min_buff_size(JNIEnv *env,jobject thiz,

jint sampleRateInHertz, jint nbChannels, jint audioFormat)

{//注意我们传入的参数是:

//sampleRateInHertz = 8000

//nbChannels = 2;

//audioFormat = AudioFormat.ENCODING_PCM_16BIT

int afSamplingRate;

int afFrameCount;

uint32_t afLatency;

//下面涉及到AudioSystem,这里先不解释了,

//反正知道从AudioSystem那查询了一些信息

if (AudioSystem::getOutputSamplingRate(&afSamplingRate) != NO_ERROR) {

return -1;

}

if (AudioSystem::getOutputFrameCount(&afFrameCount) != NO_ERROR) {

return -1;

}

if (AudioSystem::getOutputLatency(&afLatency) != NO_ERROR) {

return -1;

}

//音频中最常见的是frame这个单位,什么意思?经过多方查找,最后还是在ALSA的wiki中

//找到解释了。一个frame就是1个采样点的字节数*声道。为啥搞个frame出来?因为对于多//声道的话,用1个采样点的字节数表示不全,因为播放的时候肯定是多个声道的数据都要播出来//才行。所以为了方便,就说1秒钟有多少个frame,这样就能抛开声道数,把意思表示全了。

// Ensure that buffer depth covers at least audio hardware latency

uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSamplingRate);

if (minBufCount < 2) minBufCount = 2;

uint32_t minFrameCount =

(afFrameCount*sampleRateInHertz*minBufCount)/afSamplingRate;

//下面根据最小的framecount计算最小的buffersize

int minBuffSize = minFrameCount

* (audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1)

* nbChannels;

return minBuffSize;

}

getMinBufSize函数完了后,我们得到一个满足最小要求的缓冲区大小。这样用户分配缓冲区就有了依据。下面就需要创建AudioTrack对象了

3.3分析之new AudioTrack

先看看调用函数:

AudioTrack trackplayer = new AudioTrack(

AudioManager.STREAM_MUSIC,

8000,

  AudioFormat.CHANNEL_CONFIGURATION_ STEREO,

  AudioFormat.ENCODING_PCM_16BIT,

  bufsize,

AudioTrack.MODE_STREAM);//

其实现代码在AudioTrack.java中。

public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,

int bufferSizeInBytes, int mode)

throws IllegalArgumentException {

mState = STATE_UNINITIALIZED;

//获得主线程的Looper,这个在MediaScanner分析中已经讲过了

if ((mInitializationLooper = Looper.myLooper()) == null) {

mInitializationLooper = Looper.getMainLooper();

}

//检查参数是否合法之类的,可以不管它

audioParamCheck(streamType, sampleRateInHz, channelConfig, audioFormat, mode);

//我是用getMinBufsize得到的大小,总不会出错吧?

audioBuffSizeCheck(bufferSizeInBytes);

//调用native层的native_setup,把自己的WeakReference传进去了

//不了解JAVA WeakReference的可以上网自己查一下,很简单的

int initResult = native_setup(new WeakReference<AudioTrack>(this),

mStreamType,这个值是AudioManager.STREAM_MUSIC

mSampleRate,这个值是8000

mChannels,这个值是2

mAudioFormat,这个值是AudioFormat.ENCODING_PCM_16BIT

mNativeBufferSizeInBytes, //这个是刚才getMinBufSize得到的

mDataLoadMode);DataLoadMode是MODE_STREAM

....

}

上面函数调用最终进入了JNI层android_media_AudioTrack.cpp下面的函数

static int

android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,

jint streamType, jint sampleRateInHertz, jint channels,

jint audioFormat, jint buffSizeInBytes, jint memoryMode)

{

int afSampleRate;

int afFrameCount;

下面又要调用一堆东西,烦不烦呐?具体干什么用的,以后分析到AudioSystem再说。

AudioSystem::getOutputFrameCount(&afFrameCount, streamType);

AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);

AudioSystem::isOutputChannel(channels);

popCount是统计一个整数中有多少位为1的算法

int nbChannels = AudioSystem::popCount(channels);

if (streamType == javaAudioTrackFields.STREAM_MUSIC) {

atStreamType = AudioSystem::MUSIC;

}

int bytesPerSample = audioFormat == javaAudioTrackFields.PCM16 ? 2 : 1;

int format = audioFormat == javaAudioTrackFields.PCM16 ?

AudioSystem::PCM_16_BIT : AudioSystem::PCM_8_BIT;

int frameCount = buffSizeInBytes / (nbChannels * bytesPerSample);

//上面是根据Buffer大小和一个Frame大小来计算帧数的。

// AudioTrackJniStorage,就是一个保存一些数据的地方,这

//里边有一些有用的知识,下面再详细解释

AudioTrackJniStorage* lpJniStorage = new AudioTrackJniStorage();

jclass clazz = env->GetObjectClass(thiz);

lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);

lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);

lpJniStorage->mStreamType = atStreamType;

//创建真正的AudioTrack对象

AudioTrack* lpTrack = new AudioTrack();

if (memoryMode == javaAudioTrackFields.MODE_STREAM) {

//如果是STREAM流方式的话,把刚才那些参数设进去

lpTrack->set(

atStreamType,// stream type

sampleRateInHertz,

format,// word length, PCM

channels,

frameCount,

0,// flags

audioCallback,

&(lpJniStorage->mCallbackData),//callback, callback data (user)

0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack

0,//共享内存,STREAM模式需要用户一次次写,所以就不用共享内存了

true);// thread can call Java

} else if (memoryMode == javaAudioTrackFields.MODE_STATIC) {

//如果是static模式,需要用户一次性把数据写进去,然后

//再由audioTrack自己去把数据读出来,所以需要一个共享内存

//这里的共享内存是指C++AudioTrack和AudioFlinger之间共享的内容

//因为真正播放的工作是由AudioFlinger来完成的。

lpJniStorage->allocSharedMem(buffSizeInBytes);

lpTrack->set(

atStreamType,// stream type

sampleRateInHertz,

format,// word length, PCM

channels,

frameCount,

0,// flags

audioCallback,

&(lpJniStorage->mCallbackData),//callback, callback data (user));

0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack

lpJniStorage->mMemBase,// shared mem

true);// thread can call Java

}

if (lpTrack->initCheck() != NO_ERROR) {

LOGE("Error initializing AudioTrack");

goto native_init_failure;

}

//又来这一招,把C++AudioTrack对象指针保存到JAVA对象的一个变量中

//这样,Native层的AudioTrack对象就和JAVA层的AudioTrack对象关联起来了。

env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack);

env->SetIntField(thiz, javaAudioTrackFields.jniData, (int)lpJniStorage);

}

1 AudioTrackJniStorage详解

这个类其实就是一个辅助类,但是里边有一些知识很重要,尤其是Android封装的一套共享内存的机制。这里一并讲解,把这块搞清楚了,我们就能轻松得在两个进程间进行内存的拷贝。

AudioTrackJniStorage的代码很简单。

struct audiotrack_callback_cookie {

jclassaudioTrack_class;

jobjectaudioTrack_ref;

};cookie其实就是把JAVA中的一些东西保存了下,没什么特别的意义

class AudioTrackJniStorage {

public:

sp<MemoryHeapBase>mMemHeap;//这两个Memory很重要

sp<MemoryBase>mMemBase;

audiotrack_callback_cookie mCallbackData;

intmStreamType;

bool allocSharedMem(int sizeInBytes) {

mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");

mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);

//注意用法,先弄一个HeapBase,再把HeapBase传入到MemoryBase中去。

return true;

}

};

2 MemoryHeapBase

MemroyHeapBase也是Android搞的一套基于Binder机制的对内存操作的类。既然是Binder机制,那么肯定有一个服务端(Bnxxx),一个代理端Bpxxx。看看MemoryHeapBase定义:

class MemoryHeapBase : public virtual BnMemoryHeap

{

果然,从BnMemoryHeap派生,那就是Bn端。这样就和Binder挂上钩了

//Bp端调用的函数最终都会调到Bn这来

对Binder机制不了解的,可以参考:

http://blog.csdn.net/Innost/archive/2011/01/08/6124685.aspx

有好几个构造函数,我们看看我们使用的:

MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)

: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),

mDevice(0), mNeedUnmap(false)

{

const size_t pagesize = getpagesize();

size = ((size + pagesize-1) & ~(pagesize-1));

//创建共享内存,ashmem_create_region这个是系统提供的,可以不管它

//设备上打开的是/dev/ashmem设备,而Host上打开的是一个tmp文件

int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);

mapfd(fd, size);//把刚才那个fd通过mmap方式得到一块内存

//不明白得去man mmap看看

mapfd完了后,mBase变量指向内存的起始位置, mSize是分配的内存大小,mFd是

ashmem_create_region返回的文件描述符

}

MemoryHeapBase提供了一下几个函数,可以获取共享内存的大小和位置。

getBaseID()--->返回mFd,如果为负数,表明刚才创建共享内存失败了

getBase()->返回mBase,内存位置

getSize()->返回mSize,内存大小

有了MemoryHeapBase,又搞了一个MemoryBase,这又是一个和Binder机制挂钩的类。

唉,这个估计是一个在MemoryHeapBase上的方便类吧?因为我看见了offset

那么估计这个类就是一个能返回当前Buffer中写位置(就是offset)的方便类

这样就不用用户到处去计算读写位置了。

class MemoryBase : public BnMemory

{

public:

MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);

virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;

protected:

size_t getSize() const { return mSize; }

ssize_t getOffset() const { return mOffset; }

const sp<IMemoryHeap>& getHeap() const { return mHeap; }

};

好了,明白上面两个MemoryXXX,我们可以猜测下大概的使用方法了。

lBnXXX端先分配BnMemoryHeapBase和BnMemoryBase,

l然后把BnMemoryBase传递到BpXXX

lBpXXX就可以使用BpMemoryBase得到BnXXX端分配的共享内存了。

注意,既然是进程间共享内存,那么Bp端肯定使用memcpy之类的函数来操作内存,这些函数是没有同步保护的,而且Android也不可能在系统内部为这种共享内存去做增加同步保护。所以看来后续在操作这些共享内存的时候,肯定存在一个跨进程的同步保护机制。我们在后面讲实际播放的时候会碰到。

另外,这里的SharedBuffer最终会在Bp端也就是AudioFlinger那用到。

3.4分析之play和write

JAVA层到这一步后就是调用play和write了。JAVA层这两个函数没什么内容,都是直接转到native层干活了。

先看看play函数对应的JNI函数

static void

android_media_AudioTrack_start(JNIEnv *env, jobject thiz)

{

//看见没,从JAVA那个AudioTrack对象获取保存的C++层的AudioTrack对象指针

//从int类型直接转换成指针。要是以后ARM变成64位平台了,看google怎么改!

AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(

thiz, javaAudioTrackFields.nativeTrackInJavaObj);

lpTrack->start(); //这个以后再说

}

下面是write。我们写的是short数组,

static jint

android_media_AudioTrack_native_write_short(JNIEnv *env,jobject thiz,

jshortArray javaAudioData,

jint offsetInShorts,

jint sizeInShorts,

jint javaAudioFormat) {

return (android_media_AudioTrack_native_write(env, thiz,

(jbyteArray) javaAudioData,

offsetInShorts*2, sizeInShorts*2,

javaAudioFormat)

/ 2);

}

烦人,又根据Byte还是Short封装了下,最终会调到重要函数writeToTrack去

jint writeToTrack(AudioTrack* pTrack, jint audioFormat, jbyte* data,

jint offsetInBytes, jint sizeInBytes) {

ssize_t written = 0;

// regular write() or copy the data to the AudioTrack's shared memory?

if (pTrack->sharedBuffer() == 0) {

//创建的是流的方式,所以没有共享内存在track中

//还记得我们在native_setup中调用的set吗?流模式下AudioTrackJniStorage可没创建

//共享内存

written = pTrack->write(data + offsetInBytes, sizeInBytes);

} else {

if (audioFormat == javaAudioTrackFields.PCM16) {

// writing to shared memory, check for capacity

if ((size_t)sizeInBytes > pTrack->sharedBuffer()->size()) {

sizeInBytes = pTrack->sharedBuffer()->size();

}

//看见没?STATIC模式的,就直接把数据拷贝到共享内存里

//当然,这个共享内存是pTrack的,是我们在set时候把AudioTrackJniStorage的

//共享设进去的

memcpy(pTrack->sharedBuffer()->pointer(),

data + offsetInBytes, sizeInBytes);

written = sizeInBytes;

} else if (audioFormat == javaAudioTrackFields.PCM8) {

PCM8格式的要先转换成PCM16

}

return written;

}

到这里,似乎很简单啊,JAVA层的AudioTrack,无非就是调用write函数,而实际由JNI层的C++ AudioTrack write数据。反正JNI这层是再看不出什么有意思的东西了。

四AudioTrack(C++层)

接上面的内容,我们知道在JNI层,有以下几个步骤:

lnew了一个AudioTrack

l调用set函数,把AudioTrackJniStorage等信息传进去

l调用了AudioTrack的start函数

l调用AudioTrack的write函数

那么,我们就看看真正干活的的C++AudioTrack吧。

AudioTrack.cpp位于framework\base\libmedia\AudioTrack.cpp

4.1 new AudioTrack()和set调用

JNI层调用的是最简单的构造函数:

AudioTrack::AudioTrack()

: mStatus(NO_INIT) //把状态初始化成NO_INIT。Android大量使用了设计模式中的state。

{

}

接下来调用set。我们看看JNI那set了什么

lpTrack->set(

atStreamType, //应该是Music吧

sampleRateInHertz,//8000

format,//应该是PCM_16吧

channels,//立体声=2

frameCount,//

0,// flags

audioCallback, //JNI中的一个回调函数

&(lpJniStorage->mCallbackData),//回调函数的参数

0,//通知回调函数,表示AudioTrack需要数据,不过暂时没用上

0,//共享buffer地址,stream模式没有

true);//回调线程可以调JAVA的东西

那我们看看set函数把。

status_t AudioTrack::set(

int streamType,

uint32_t sampleRate,

int format,

int channels,

int frameCount,

uint32_t flags,

callback_t cbf,

void* user,

int notificationFrames,

const sp<IMemory>& sharedBuffer,

bool threadCanCallJava)

{

...前面一堆的判断,等以后讲AudioSystem再说

audio_io_handle_t output =

AudioSystem::getOutput((AudioSystem::stream_type)streamType,

sampleRate, format, channels, (AudioSystem::output_flags)flags);

//createTrack?看来这是真正干活的

status_t status = createTrack(streamType, sampleRate, format, channelCount,

frameCount, flags, sharedBuffer, output);

//cbf是JNI传入的回调函数audioCallback

if (cbf != 0) { //看来,怎么着也要创建这个线程了!

mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);

}

return NO_ERROR;

}

看看真正干活的createTrack

status_t AudioTrack::createTrack(

int streamType,

uint32_t sampleRate,

int format,

int channelCount,

int frameCount,

uint32_t flags,

const sp<IMemory>& sharedBuffer,

audio_io_handle_t output)

{

status_t status;

//啊,看来和audioFlinger挂上关系了呀。

const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();

//下面这个调用最终会在AudioFlinger中出现。暂时不管它。

sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),

streamType,

sampleRate,

format,

channelCount,

frameCount,

((uint16_t)flags) << 16,

sharedBuffer,

output,

&status);

//看见没,从track也就是AudioFlinger那边得到一个IMemory接口

//这个看来就是最终write写入的地方

sp<IMemory> cblk = track->getCblk();

mAudioTrack.clear();

mAudioTrack = track;

mCblkMemory.clear();//sp<XXX>的clear,就看着做是delete XXX吧

mCblkMemory = cblk;

mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());

mCblk->out = 1;

mFrameCount = mCblk->frameCount;

if (sharedBuffer == 0) {

//终于看到buffer相关的了。注意我们这里的情况

//STREAM模式没有传入共享buffer,但是数据确实又需要buffer承载。

//反正AudioTrack是没有创建buffer,那只能是刚才从AudioFlinger中得到

//的buffer了。

mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);

}

return NO_ERROR;

}

还记得我们说MemoryXXX没有同步机制,所以这里应该有一个东西能体现同步的,

那么我告诉大家,就在audio_track_cblk_t结构中。它的头文件在

framework/base/include/private/media/AudioTrackShared.h

实现文件就在AudioTrack.cpp中

audio_track_cblk_t::audio_track_cblk_t()

//看见下面的SHARED没?都是表示跨进程共享的意思。这个我就不跟进去说了

//等以后介绍同步方面的知识时,再细说

: lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),

userBase(0), serverBase(0), buffers(0), frameCount(0),

loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),

flowControlFlag(1), forceReady(0)

{

}

到这里,大家应该都有个大概的全景了。

lAudioTrack得到AudioFlinger中的一个IAudioTrack对象,这里边有一个很重要的数据结构audio_track_cblk_t,它包括一块缓冲区地址,包括一些进程间同步的内容,可能还有数据位置等内容

lAudioTrack启动了一个线程,叫AudioTrackThread,这个线程干嘛的呢?还不知道

lAudioTrack调用write函数,肯定是把数据写到那块共享缓冲了,然后IAudioTrack在另外一个进程AudioFlinger中(其实AudioFlinger是一个服务,在mediaservice中运行)接收数据,并最终写到音频设备中。

那我们先看看AudioTrackThread干什么了。

调用的语句是:

mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);

AudioTrackThread从Thread中派生,这个内容在深入浅出Binder机制讲过了。

反正最终会调用AudioTrackAThread的threadLoop函数。

先看看构造函数

AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)

: Thread(bCanCallJava), mReceiver(receiver)

{//mReceiver就是AudioTrack对象

// bCanCallJava为TRUE

}

这个线程的启动由AudioTrack的start函数触发。

void AudioTrack::start()

{

//start函数调用AudioTrackThread函数触发产生一个新的线程,执行mAudioTrackThread的

threadLoop

sp<AudioTrackThread> t = mAudioTrackThread;

t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);

//让AudioFlinger中的track也start

status_t status = mAudioTrack->start();

}

bool AudioTrack::AudioTrackThread::threadLoop()

{

//太恶心了,又调用AudioTrack的processAudioBuffer函数

return mReceiver.processAudioBuffer(this);

}

bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)

{

Buffer audioBuffer;

uint32_t frames;

size_t writtenSize;

...回调1

mCbf(EVENT_UNDERRUN, mUserData, 0);

...回调2都是传递一些信息到JNI里边

mCbf(EVENT_BUFFER_END, mUserData, 0);

// Manage loop end callback

while (mLoopCount > mCblk->loopCount) {

mCbf(EVENT_LOOP_END, mUserData, (void *)&loopCount);

}

//下面好像有写数据的东西

do {

audioBuffer.frameCount = frames;

//获得buffer,

status_t err = obtainBuffer(&audioBuffer, 1);

size_t reqSize = audioBuffer.size;

//把buffer回调到JNI那去,这是单独一个线程,而我们还有上层用户在那不停

//地write呢,怎么会这样?

mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);

audioBuffer.size = writtenSize;

frames -= audioBuffer.frameCount;

releaseBuffer(&audioBuffer); //释放buffer,和obtain相对应,看来是LOCK和UNLOCK

操作了

}

while (frames);

return true;

}

难道真的有两处在write数据?看来必须得到mCbf去看看了,传的是EVENT_MORE_DATA标志。

mCbf由set的时候传入C++的AudioTrack,实际函数是:

static void audioCallback(int event, void* user, void *info) {

if (event == AudioTrack::EVENT_MORE_DATA) {

//哈哈,太好了,这个函数没往里边写数据

AudioTrack::Buffer* pBuff = (AudioTrack::Buffer*)info;

pBuff->size = 0;

}

从代码上看,本来google考虑是异步的回调方式来写数据,可惜发现这种方式会比较复杂,尤其是对用户开放的JAVA AudioTrack会很不好处理,所以嘛,偷偷摸摸得给绕过去了。

太好了,看来就只有用户的write会真正的写数据了,这个AudioTrackThread除了通知一下,也没什么实际有意义的操作了。

让我们看看write吧。

4.2 write

ssize_t AudioTrack::write(const void* buffer, size_t userSize)

{

够简单,就是obtainBuffer,memcpy数据,然后releasBuffer

眯着眼睛都能想到,obtainBuffer一定是Lock住内存了,releaseBuffer一定是unlock内存了

do {

audioBuffer.frameCount = userSize/frameSize();

status_t err = obtainBuffer(&audioBuffer, -1);

size_t toWrite;

toWrite = audioBuffer.size;

memcpy(audioBuffer.i8, src, toWrite);

src += toWrite;

}

userSize -= toWrite;

written += toWrite;

releaseBuffer(&audioBuffer);

} while (userSize);

return written;

}

obtainBuffer太复杂了,不过大家知道其大概工作方式就可以了

status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)

{

//恕我中间省略太多,大部分都是和当前数据位置相关,

uint32_t framesAvail = cblk->framesAvailable();

cblk->lock.lock();//看见没,lock了

result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));

//我发现很多地方都要判断远端的AudioFlinger的状态,比如是否退出了之类的,难道

//没有一个好的方法来集中处理这种事情吗?

if (result == DEAD_OBJECT) {

result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount,

mFrameCount, mFlags, mSharedBuffer,getOutput());

}

//得到buffer

audioBuffer->raw = (int8_t *)cblk->buffer(u);

return active ? status_t(NO_ERROR) : status_t(STOPPED);

}

在看看releaseBuffer

void AudioTrack::releaseBuffer(Buffer* audioBuffer)

{

audio_track_cblk_t* cblk = mCblk;

cblk->stepUser(audioBuffer->frameCount);

}

uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)

{

uint32_t u = this->user;

u += frameCount;

if (out) {

if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) {

bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;

}

} else if (u > this->server) {

u = this->server;

}

if (u >= userBase + this->frameCount) {

userBase += this->frameCount;

}

this->user = u;

flowControlFlag = 0;

return u;

}

奇怪了,releaseBuffer没有unlock操作啊?难道我失误了?

再去看看obtainBuffer?为何写得这么晦涩难懂?

原来在obtainBuffer中会某一次进去lock,再某一次进去可能就是unlock了。没看到obtainBuffer中到处有lock,unlock,wait等同步操作吗。一定是这个道理。难怪写这么复杂。还使用了少用的goto语句。

唉,有必要这样吗!

五AudioTrack总结

通过这一次的分析,我自己觉得有以下几个点:

lAudioTrack的工作原理,尤其是数据的传递这一块,做了比较细致的分析,包括共享内存,跨进程的同步等,也能解释不少疑惑了。

l看起来,最重要的工作是在AudioFlinger中做的。通过AudioTrack的介绍,我们给后续深入分析AudioFlinger提供了一个切入点

工作原理和流程嘛,再说一次好了,JAVA层就看最前面那个例子吧,实在没什么说的。

lAudioTrack被new出来,然后set了一堆信息,同时会通过Binder机制调用另外一端的AudioFlinger,得到IAudioTrack对象,通过它和AudioFlinger交互。

l调用start函数后,会启动一个线程专门做回调处理,代码里边也会有那种数据拷贝的回调,但是JNI层的回调函数实际并没有往里边写数据,大家只要看write就可以了

l用户一次次得write,那AudioTrack无非就是把数据memcpy到共享buffer中咯

l可想而知,AudioFlinger那一定有一个线程在memcpy数据到音频设备中去。我们拭目以待。

一目的

本文承接Audio第一部分的AudioTrack,通过AudioTrack作为AF(AudioFlinger)的客户端,来看看AF是如何完成工作的。

在AT(AudioTrack)中,我们涉及到的都是流程方面的事务,而不是系统Audio策略上的内容。WHY?因为AT是AF的客户端,而AF是Android系统中Audio管理的中枢。AT我们分析的是按流程方法,那么以AT为切入点的话,AF的分析也应该是流程分析了。

对于分析AT来说,只要能把它的调用顺序(也就是流程说清楚就可以了),但是对于AF的话,简单的分析调用流程我自己感觉是不够的。因为我发现手机上的声音交互和管理是一件比较复杂的事情。举个简单例子,当听music的时候来电话了,声音处理会怎样?

虽然在Android中,还有一个叫AudioPolicyService的(APS)东西,但是它最终都会调用到AF中去,因为AF实际创建并管理了硬件设备。所以,针对Android声音策略上的分析,我会单独在以后来分析。

二从AT切入到AF

直接从头看代码是没法掌握AF的主干的,必须要有一个切入点,也就是用一个正常的调用流程来分析AF的处理流程。先看看AF的产生吧,这个C/S架构的服务者是如何产生的呢?

2.1 AudioFlinger的诞生

AF是一个服务,这个就不用我多说了吧?代码在

framework/base/media/mediaserver/Main_mediaServer.cpp中。

int main(int argc, char** argv)

{

sp<ProcessState> proc(ProcessState::self());

sp<IServiceManager> sm = defaultServiceManager();

....

AudioFlinger::instantiate();--->AF的实例化

AudioPolicyService::instantiate();--->APS的实例化

....

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

}

哇塞,看来这个程序的负担很重啊。没想到。为何AF,APS要和MediaService和CameraService都放到一个篮子里?

看看AF的实例化静态函数,在framework/base/libs/audioFlinger/audioFlinger.cpp中

void AudioFlinger::instantiate() {

defaultServiceManager()->addService( //把AF实例加入系统服务

String16("media.audio_flinger"), new AudioFlinger());

}

再来看看它的构造函数是什么做的。

AudioFlinger::AudioFlinger()

: BnAudioFlinger(),//初始化基类

mAudioHardware(0), //audio硬件的HAL对象

mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)

{

mHardwareStatus = AUDIO_HW_IDLE;

//创建代表Audio硬件的HAL对象

mAudioHardware = AudioHardwareInterface::create();

mHardwareStatus = AUDIO_HW_INIT;

if (mAudioHardware->initCheck() == NO_ERROR) {

setMode(AudioSystem::MODE_NORMAL);

//设置系统的声音模式等,其实就是设置硬件的模式

setMasterVolume(1.0f);

setMasterMute(false);

}

}

AF中经常有setXXX的函数,到底是干什么的呢?我们看看setMode函数。

status_t AudioFlinger::setMode(int mode)

{

mHardwareStatus = AUDIO_HW_SET_MODE;

status_t ret = mAudioHardware->setMode(mode);//设置硬件的模式

mHardwareStatus = AUDIO_HW_IDLE;

return ret;

}

当然,setXXX还有些别的东西,但基本上都会涉及到硬件对象。我们暂且不管它。等分析到Audio策略再说。

好了,Android系统启动的时候,看来AF也准备好硬件了。不过,创建硬件对象就代表我们可以播放了吗?

2.2 AT调用AF的流程

我这里简单的把AT调用AF的流程列一下,待会按这个顺序分析AF的工作方式。

--参加AudioTrack分析的4.1节

1.创建

AudioTrack* lpTrack = new AudioTrack();

lpTrack->set(...);

这个就进入到C++的AT了。下面是AT的set函数

audio_io_handle_t output =

AudioSystem::getOutput((AudioSystem::stream_type)streamType,

sampleRate, format, channels, (AudioSystem::output_flags)flags);

status_t status = createTrack(streamType, sampleRate, format, channelCount,

frameCount, flags, sharedBuffer, output);

----->creatTrack会和AF打交道。我们看看createTrack重要语句

const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();

//下面很重要,调用AF的createTrack获得一个IAudioTrack对象

sp<IAudioTrack> track = audioFlinger->createTrack();

sp<IMemory> cblk = track->getCblk();//获取共享内存的管理结构

总结一下创建的流程,AT调用AF的createTrack获得一个IAudioTrack对象,然后从这个对象中获得共享内存的对象。

2. start和write

看看AT的start,估计就是调用IAudioTrack的start吧?

void AudioTrack::start()

{

//果然啊...

status_t status = mAudioTrack->start();

}

那write呢?我们之前讲了,AT就是从共享buffer中:

lLock缓存

l写缓存

lUnlock缓存

注意,这里的Lock和Unlock是有问题的,什么问题呢?待会我们再说

按这种方式的话,那么AF一定是有一个线程在那也是:

lLock,

l读缓存,写硬件

lUnlock

总之,我们知道了AT的调用AF的流程了。下面一个一个看。

2.3 AF流程

1 createTrack

sp<IAudioTrack> AudioFlinger::createTrack(

pid_t pid,//AT的pid号

int streamType,//MUSIC,流类型

uint32_t sampleRate,//8000采样率

int format,//PCM_16类型

int channelCount,//2,双声道

int frameCount,//需要创建的buffer可包含的帧数

uint32_t flags,

const sp<IMemory>& sharedBuffer,//AT传入的共享buffer,这里为空

int output,//这个是从AuidoSystem获得的对应MUSIC流类型的索引

status_t *status)

{

sp<PlaybackThread::Track> track;

sp<TrackHandle> trackHandle;

sp<Client> client;

wp<Client> wclient;

status_t lStatus;

{

Mutex::Autolock _l(mLock);

//根据output句柄,获得线程?

PlaybackThread *thread = checkPlaybackThread_l(output);

//看看这个进程是不是已经是AF的客户了

//这里说明一下,由于是C/S架构,那么作为服务端的AF肯定有地方保存作为C的AT的信息

//那么,AF是根据pid作为客户端的唯一标示的

//mClients是一个类似map的数据组织结构

wclient = mClients.valueFor(pid);

if (wclient != NULL) {

} else {

//如果还没有这个客户信息,就创建一个,并加入到map中去

client = new Client(this, pid);

mClients.add(pid, client);

}

//从刚才找到的那个线程对象中创建一个track

track = thread->createTrack_l(client, streamType, sampleRate, format,

channelCount, frameCount, sharedBuffer, &lStatus);

}

//喔,还有一个trackHandle,而且返回到AF端的是这个trackHandle对象

trackHandle = new TrackHandle(track);

return trackHandle;

}

这个AF函数中,突然冒出来了很多新类型的数据结构。说实话,我刚开始接触的时候,大脑因为常接触到这些眼生的东西而死机!大家先不要拘泥于这些东西,我会一一分析到的。

先进入到checkPlaybackThread_l看看。

AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(int output) const

{

PlaybackThread *thread = NULL;

//看到这种indexOfKey的东西,应该立即能想到:

//喔,这可能是一个map之类的东西,根据key能找到实际的value

if (mPlaybackThreads.indexOfKey(output) >= 0) {

thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();

}

//这个函数的意思是根据output值,从一堆线程中找到对应的那个线程

return thread;

}

看到这里很疑惑啊:

lAF的构造函数中没有创建线程,只创建了一个audio的HAL对象

l如果AT是AF的第一个客户的话,我们刚才的调用流程里边,也没看到哪有创建线程的地方呀。

loutput是个什么玩意儿?为什么会根据它作为key来找线程呢?

看来,我们得去Output的来源那看看了。

我们知道,output的来源是由AT的set函数得到的:如下:

audio_io_handle_t output = AudioSystem::getOutput(

(AudioSystem::stream_type)streamType, //MUSIC类型

sampleRate, //8000

format, //PCM_16

channels, //2两个声道

(AudioSystem::output_flags)flags//0

);

上面这几个参数后续不再提示了,大家知道这些值都是由AT做为切入点传进去的

然后它在调用AT自己的createTrack,最终把这个output值传递到AF了。其中audio_io_handle_t类型就是一个int类型。

//叫handle啊?好像linux下这种叫法的很少,难道又是受MS的影响吗?

我们进到AudioSystem::getOutput看看。注意,大家想想这是系统的第一次调用,而且发生在AudioTrack那个进程里边。AudioSystem的位置在framework/base/media/libmedia/AudioSystem.cpp中

audio_io_handle_t AudioSystem::getOutput(stream_type stream,

uint32_t samplingRate,

uint32_t format,

uint32_t channels,

output_flags flags)

{

audio_io_handle_t output = 0;

if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0 &&

((stream != AudioSystem::VOICE_CALL && stream != AudioSystem::BLUETOOTH_SCO) ||

channels != AudioSystem::CHANNEL_OUT_MONO ||

(samplingRate != 8000 && samplingRate != 16000))) {

Mutex::Autolock _l(gLock);

//根据我们的参数,我们会走到这个里边来

//喔,又是从map中找到stream=music的output。可惜啊,我们是第一次进来

//output一定是0

output = AudioSystem::gStreamOutputMap.valueFor(stream);

}

if (output == 0) {

//我晕,又到AudioPolicyService(APS)

//由它去getOutput

const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();

output = aps->getOutput(stream, samplingRate, format, channels, flags);

if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) == 0) {

Mutex::Autolock _l(gLock);

//如果取到output了,再把output加入到AudioSystem维护的这个map中去

//说白了,就是保存一些信息吗。免得下次又这么麻烦去骚扰APS!

AudioSystem::gStreamOutputMap.add(stream, output);

}

}

return output;

}

怎么办?需要到APS中才能找到output的信息?

没办法,硬着头皮进去吧。那先得看看APS是如何创建的。不过这个刚才已经说了,是和AF一块在那个Main_mediaService.cpp中实例化的。

位置在framework/base/lib/libaudioflinger/ AudioPolicyService.cpp中

AudioPolicyService::AudioPolicyService()

: BnAudioPolicyService() , mpPolicyManager(NULL)

{

//下面两个线程以后再说

mTonePlaybackThread = new AudioCommandThread(String8(""));

mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));

#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)

//喔,使用普适的AudioPolicyManager,把自己this做为参数

//我们这里先使用普适的看看吧

mpPolicyManager = new AudioPolicyManagerBase(this);

//使用硬件厂商提供的特殊的AudioPolicyManager

//mpPolicyManager = createAudioPolicyManager(this);

}

}

我们看看AudioManagerBase的构造函数吧,在framework/base/lib/audioFlinger/

AudioPolicyManagerBase.cpp中。

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)

: mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false)

{

mpClientInterface = clientInterface;这个client就是APS,刚才通过this传进来了

AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();

outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;

mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,

&outputDesc->mSamplingRate,

&outputDesc->mFormat,

&outputDesc->mChannels,

&outputDesc->mLatency,

outputDesc->mFlags);

openOutput又交给APS的openOutput来完成了,真绕....

}

唉,看来我们还是得回到APS,

audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,

uint32_t *pSamplingRate,

uint32_t *pFormat,

uint32_t *pChannels,

uint32_t *pLatencyMs,

AudioSystem::output_flags flags)

{

sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();

//FT,FT,FT,FT,FT,FT,FT

//绕了这么一个大圈子,竟然回到AudioFlinger中了啊??

return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels,

pLatencyMs, flags);

}

在我们再次被绕晕之后,我们回眸看看足迹吧:

l在AudioTrack中,调用set函数

l这个函数会通过AudioSystem::getOutput来得到一个output的句柄

lAS的getOutput会调用AudioPolicyService的getOutput

l然后我们就没继续讲APS的getOutPut了,而是去看看APS创建的东西

l发现APS创建的时候会创建一个AudioManagerBase,这个AMB的创建又会调用APS的openOutput。

lAPS的openOutput又会调用AudioFlinger的openOutput

有一个疑问,AT中set参数会和APS构造时候最终传入到AF的openOutput一样吗?如果不一样,那么构造时候openOutput的又是什么参数呢?

先放下这个悬念,我们继续从APS的getOutPut看看。

audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream,

uint32_t samplingRate,

uint32_t format,

uint32_t channels,

AudioSystem::output_flags flags)

{

Mutex::Autolock _l(mLock);

//自己又不干活,由AudioManagerBase干活

return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags);

}

进去看看吧

audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream,

uint32_t samplingRate,

uint32_t format,

uint32_t channels,

AudioSystem::output_flags flags)

{

audio_io_handle_t output = 0;

uint32_t latency = 0;

// open a non direct output

output = mHardwareOutput; //这个是在哪里创建的?在AMB构造的时候..

return output;

}

具体AMB的分析待以后Audio系统策略的时候我们再说吧。反正,到这里,我们知道了,在APS构造的时候会open一个Output,而这个Output又会调用AF的openOutput。

int AudioFlinger::openOutput(uint32_t *pDevices,

uint32_t *pSamplingRate,

uint32_t *pFormat,

uint32_t *pChannels,

uint32_t *pLatencyMs,

uint32_t flags)

{

status_t status;

PlaybackThread *thread = NULL;

mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;

uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;

uint32_t format = pFormat ? *pFormat : 0;

uint32_t channels = pChannels ? *pChannels : 0;

uint32_t latency = pLatencyMs ? *pLatencyMs : 0;

Mutex::Autolock _l(mLock);

//由Audio硬件HAL对象创建一个AudioStreamOut对象

AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,

(int *)&format,

&channels,

&samplingRate,

&status);

mHardwareStatus = AUDIO_HW_IDLE;

if (output != 0) {

//创建一个Mixer线程

thread = new MixerThread(this, output, ++mNextThreadId);

}

//终于找到了,把这个线程加入线程管理组织中

mPlaybackThreads.add(mNextThreadId, thread);

return mNextThreadId;

}

}

明白了,看来AT在调用AF的createTrack的之前,AF已经在某个时候把线程创建好了,而且是一个Mixer类型的线程,看来和混音有关系呀。这个似乎和我们开始设想的AF工作有点联系喔。Lock,读缓存,写Audio硬件,Unlock。可能都是在这个线程里边做的。

2继续createTrack

AudioFlinger::createTrack(

pid_t pid,

int streamType,

uint32_t sampleRate,

int format,

int channelCount,

int frameCount,

uint32_t flags,

const sp<IMemory>& sharedBuffer,

int output,

status_t *status)

{

sp<PlaybackThread::Track> track;

sp<TrackHandle> trackHandle;

sp<Client> client;

wp<Client> wclient;

status_t lStatus;

{

//假设我们找到了对应的线程

Mutex::Autolock _l(mLock);

PlaybackThread *thread = checkPlaybackThread_l(output);

//晕,调用这个线程对象的createTrack_l

track = thread->createTrack_l(client, streamType, sampleRate, format,

channelCount, frameCount, sharedBuffer, &lStatus);

}

trackHandle = new TrackHandle(track);

return trackHandle;----》注意,这个对象是最终返回到AT进程中的。

实在是....太绕了。再进去看看thread->createTrack_l吧。_l的意思是这个函数进入之前已经获得同步锁了。

跟着sourceinsight ctrl+鼠标左键就进入到下面这个函数。

下面这个函数的签名好长啊。这是为何?

原来Android的C++类中大量定义了内部类。说实话,我之前几年的C++的经验中基本没接触过这么频繁使用内部类的东东。--->当然,你可以说STL也大量使用了呀。

我们就把C++的内部类当做普通的类一样看待吧,其实我感觉也没什么特殊的含义,和外部类是一样的,包括函数调用,public/private之类的东西。这个和JAVA的内部类是大不一样的。

sp<AudioFlinger::PlaybackThread::Track>AudioFlinger::PlaybackThread::createTrack_l(

const sp<AudioFlinger::Client>& client,

int streamType,

uint32_t sampleRate,

int format,

int channelCount,

int frameCount,

const sp<IMemory>& sharedBuffer,

status_t *status)

{

sp<Track> track;

status_t lStatus;

{ // scope for mLock

Mutex::Autolock _l(mLock);

//new一个track对象

//我有点愤怒了,Android真是层层封装啊,名字取得也非常相似。

//看看这个参数吧,注意sharedBuffer这个,此时的值应是0

track = new Track(this, client, streamType, sampleRate, format,

channelCount, frameCount, sharedBuffer);

mTracks.add(track); //把这个track加入到数组中,是为了管理用的。

}

lStatus = NO_ERROR;

return track;

}

看到这个数组的存在,我们应该能想到什么吗?这时已经有:

l一个MixerThread,内部有一个数组保存track的

看来,不管有多少个AudioTrack,最终在AF端都有一个track对象对应,而且这些所有的track对象都会由一个线程对象来处理。----难怪是Mixer啊

再去看看new Track,我们一直还没找到共享内存在哪里创建的!!!

AudioFlinger::PlaybackThread::Track::Track(

const wp<ThreadBase>& thread,

const sp<Client>& client,

int streamType,

uint32_t sampleRate,

int format,

int channelCount,

int frameCount,

const sp<IMemory>& sharedBuffer)

:TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),

mMute(false), mSharedBuffer(sharedBuffer), mName(-1)

{

// mCblk !=NULL?什么时候创建的??

//只能看基类TrackBase,还是很愤怒,太多继承了。

if (mCblk != NULL) {

mVolume[0] = 1.0f;

mVolume[1] = 1.0f;

mStreamType = streamType;

mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount *

sizeof(int16_t) : sizeof(int8_t);

}

}

看看基类TrackBase干嘛了

AudioFlinger::ThreadBase::TrackBase::TrackBase(

const wp<ThreadBase>& thread,

const sp<Client>& client,

uint32_t sampleRate,

int format,

int channelCount,

int frameCount,

uint32_t flags,

const sp<IMemory>& sharedBuffer)

:RefBase(),

mThread(thread),

mClient(client),

mCblk(0),

mFrameCount(0),

mState(IDLE),

mClientTid(-1),

mFormat(format),

mFlags(flags & ~SYSTEM_FLAGS_MASK)

{

size_t size = sizeof(audio_track_cblk_t);

size_t bufferSize = frameCount*channelCount*sizeof(int16_t);

if (sharedBuffer == 0) {

size += bufferSize;

}

//调用client的allocate函数。这个client是什么?就是我们在CreateTrack中创建的

那个Client,我不想再说了。反正这里会创建一块共享内存

mCblkMemory = client->heap()->allocate(size);

有了共享内存,但是还没有里边有同步锁的那个对象audio_track_cblk_t

mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());

下面这个语法好怪啊。什么意思???

new(mCblk) audio_track_cblk_t();

//各位,这就是C++语法中的placement new。干啥用的啊?new后面的括号中是一块buffer,再

后面是一个类的构造函数。对了,这个placement new的意思就是在这块buffer中构造一个对象。

我们之前的普通new是没法让一个对象在某块指定的内存中创建的。而placement new却可以。

这样不就达到我们的目的了吗?搞一块共享内存,再在这块内存上创建一个对象。这样,这个对象不也就能在两个内存中共享了吗?太牛牛牛牛牛了。怎么想到的?

// clear all buffers

mCblk->frameCount = frameCount;

mCblk->sampleRate = sampleRate;

mCblk->channels = (uint8_t)channelCount;

}

好了,解决一个重大疑惑,跨进程数据共享的重要数据结构audio_track_cblk_t是通过placement new在一块共享内存上来创建的。

回到AF的CreateTrack,有这么一句话:

trackHandle = new TrackHandle(track);

return trackHandle;----》注意,这个对象是最终返回到AT进程中的。

trackHandle的构造使用了thread->createTrack_l的返回值。

2.4到底有少种对象

读到这里的人,一定会被异常多的class类型,内部类,继承关系搞疯掉。说实话,这里废点心血整个或者paste一个大的UML图未尝不可。但是我是不太习惯用图说话,因为图我实在是记不住。那好吧。我们就用最简单的话语争取把目前出现的对象说清楚。

1 AudioFlinger

class AudioFlinger : public BnAudioFlinger, public IBinder::DeathRecipient

AudioFlinger类是代表整个AudioFlinger服务的类,其余所有的工作类都是通过内部类的方式在其中定义的。你把它当做一个壳子也行吧。

2 Client

Client是描述C/S结构的C端的代表,也就算是一个AT在AF端的对等物吧。不过可不是Binder机制中的BpXXX喔。因为AF是用不到AT的功能的。

class Client : public RefBase {

public:

sp<AudioFlinger>mAudioFlinger;//代表S端的AudioFlinger

sp<MemoryDealer>mMemoryDealer;//每个C端使用的共享内存,通过它分配

pid_tmPid;//C端的进程id

};

3 TrackHandle

Trackhandle是AT端调用AF的CreateTrack得到的一个基于Binder机制的Track。

这个TrackHandle实际上是对真正干活的PlaybackThread::Track的一个跨进程支持的封装。

什么意思?本来PlaybackThread::Track是真正在AF中干活的东西,不过为了支持跨进程的话,我们用TrackHandle对其进行了一下包转。这样在AudioTrack调用TrackHandle的功能,实际都由TrackHandle调用PlaybackThread::Track来完成了。可以认为是一种Proxy模式吧。

这个就是AudioFlinger异常复杂的一个原因!!!

class TrackHandle : public android::BnAudioTrack {

public:

TrackHandle(const sp<PlaybackThread::Track>& track);

virtual~TrackHandle();

virtual status_tstart();

virtual voidstop();

virtual voidflush();

virtual voidmute(bool);

virtual voidpause();

virtual voidsetVolume(float left, float right);

virtual sp<IMemory> getCblk() const;

sp<PlaybackThread::Track> mTrack;

};

4线程类

AF中有好几种不同类型的线程,分别有对应的线程类型:

lRecordThread:

RecordThread : public ThreadBase, public AudioBufferProvider

用于录音的线程。

lPlaybackThread:

class PlaybackThread : public ThreadBase

用于播放的线程

lMixerThread

MixerThread : public PlaybackThread

用于混音的线程,注意他是从PlaybackThread派生下来的。

lDirectoutputThread

DirectOutputThread : public PlaybackThread

直接输出线程,我们之前在代码里老看到DIRECT_OUTPUT之类的判断,看来最终和这个线程有关。

lDuplicatingThread:

DuplicatingThread : public MixerThread

复制线程?而且从混音线程中派生?暂时不知道有什么用

这么多线程,都有一个共同的父类ThreadBase,这个是AF对Audio系统单独定义的一个以Thread为基类的类。------》FT,真的很麻烦。

ThreadBase我们不说了,反正里边封装了一些有用的函数。

我们看看PlayingThread吧,里边由定义了内部类:

5PlayingThread的内部类Track

我们知道,TrackHandle构造用的那个Track是PlayingThread的createTrack_l得到的。

class Track : public TrackBase

晕喔,又来一个TrackBase。

TrackBase是ThreadBase定义的内部类

class TrackBase : public AudioBufferProvider, public RefBase

基类AudioBufferProvider是一个对Buffer的封装,以后在AF读共享缓冲,写数据到硬件HAL中用得到。

个人感觉:上面这些东西,其实完完全全可以独立到不同的文件中,然后加一些注释说明。

写这样的代码,要是我是BOSS的话,一定会很不爽。有什么意义吗?有什么好处吗?

2.5 AF流程继续

好了,这里终于在AF中的createTrack返回了TrackHandle。这个时候系统处于什么状态?

lAF中的几个Thread我们之前说了,在AF启动的某个时间就已经起来了。我们就假设AT调用AF服务前,这个线程就已经启动了。

这个可以看代码就知道了:

void AudioFlinger::PlaybackThread::onFirstRef()

{

const size_t SIZE = 256;

char buffer[SIZE];

snprintf(buffer, SIZE, "Playback Thread %p", this);

//onFirstRef,实际是RefBase的一个方法,在构造sp的时候就会被调用

//下面的run就真正创建了线程并开始执行threadLoop了

run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);

}

到底执行哪个线程的threadLoop?我记得我们是根据output句柄来查找线程的。

看看openOutput的实行,真正的线程对象创建是在那儿。

nt AudioFlinger::openOutput(uint32_t *pDevices,

uint32_t *pSamplingRate,

uint32_t *pFormat,

uint32_t *pChannels,

uint32_t *pLatencyMs,

uint32_t flags)

{

if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||

(format != AudioSystem::PCM_16_BIT) ||

(channels != AudioSystem::CHANNEL_OUT_STEREO)) {

thread = new DirectOutputThread(this, output, ++mNextThreadId);

//如果flags没有设置直接输出标准,或者format不是16bit,或者声道数不是2立体声

//则创建DirectOutputThread。

} else {

//可惜啊,我们创建的是最复杂的MixerThread

thread = new MixerThread(this, output, ++mNextThreadId);

1. MixerThread

非常重要的工作线程,我们看看它的构造函数。

AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)

:PlaybackThread(audioFlinger, output, id),

mAudioMixer(0)

{

mType = PlaybackThread::MIXER;

//混音器对象,传进去的两个参数时基类ThreadBase的,都为0

//这个对象巨复杂,最终混音的数据都由它生成,以后再说...

mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);

}

2. AT调用start

此时,AT得到IAudioTrack对象后,调用start函数。

status_t AudioFlinger::TrackHandle::start() {

return mTrack->start();

} //果然,自己又不干活,交给mTrack了,这个是PlayintThread createTrack_l得到的Track对象

status_t AudioFlinger::PlaybackThread::Track::start()

{

status_t status = NO_ERROR;

sp<ThreadBase> thread = mThread.promote();

//这个Thread就是调用createTrack_l的那个thread对象,这里是MixerThread

if (thread != 0) {

Mutex::Autolock _l(thread->mLock);

int state = mState;

if (mState == PAUSED) {

mState = TrackBase::RESUMING;

} else {

mState = TrackBase::ACTIVE;

}

//把自己由加到addTrack_l了

//奇怪,我们之前在看createTrack_l的时候,不是已经有个map保存创建的track了

//这里怎么又出现了一个类似的操作?

PlaybackThread *playbackThread = (PlaybackThread *)thread.get();

playbackThread->addTrack_l(this);

return status;

}

看看这个addTrack_l函数

status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)

{

status_t status = ALREADY_EXISTS;

// set retry count for buffer fill

track->mRetryCount = kMaxTrackStartupRetries;

if (mActiveTracks.indexOf(track) < 0) {

mActiveTracks.add(track);//啊,原来是加入到活跃Track的数组啊

status = NO_ERROR;

}

//我靠,有戏啊!看到这个broadcast,一定要想到:恩,在不远处有那么一个线程正

//等着这个CV呢。

mWaitWorkCV.broadcast();

return status;

}

让我们想想吧。start是把某个track加入到PlayingThread的活跃Track队列,然后触发一个信号事件。由于这个事件是PlayingThread的内部成员变量,而PlayingThread又创建了一个线程,那么难道是那个线程在等待这个事件吗?这时候有一个活跃track,那个线程应该可以干活了吧?

这个线程是MixerThread。我们去看看它的线程函数threadLoop吧。

bool AudioFlinger::MixerThread::threadLoop()

{

int16_t* curBuf = mMixBuffer;

Vector< sp<Track> > tracksToRemove;

while (!exitPending())

{

processConfigEvents();

//Mixer进到这个循环中来

mixerStatus = MIXER_IDLE;

{ // scope for mLock

Mutex::Autolock _l(mLock);

const SortedVector< wp<Track> >& activeTracks = mActiveTracks;

//每次都取当前最新的活跃Track数组

//下面是预备操作,返回状态看看是否有数据需要获取

mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);

}

//LIKELY,是GCC的一个东西,可以优化编译后的代码

//就当做是TRUE吧

if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {

// mix buffers...

//调用混音器,把buf传进去,估计得到了混音后的数据了

//curBuf是mMixBuffer,PlayingThread的内部buffer,在某个地方已经创建好了,

//缓存足够大

mAudioMixer->process(curBuf);

sleepTime = 0;

standbyTime = systemTime() + kStandbyTimeInNsecs;

}

有数据要写到硬件中,肯定不能sleep了呀

if (sleepTime == 0) {

//把缓存的数据写到outPut中。这个mOutput是AudioStreamOut

//由Audio HAL的那个对象创建得到。等我们以后分析再说

int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);

mStandby = false;

} else {

usleep(sleepTime);//如果没有数据,那就休息吧..

}

3. MixerThread核心

到这里,大家是不是有种焕然一新的感觉?恩,对了,AF的工作就是如此的精密,每个部分都配合得丝丝入扣。不过对于我们看代码的人来说,实在搞不懂这么做的好处----哈哈有点扯远了。

MixerThread的线程循环中,最重要的两个函数:

prepare_l和mAudioMixer->process,我们一一来看看。

uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)

{

uint32_t mixerStatus = MIXER_IDLE;

//得到活跃track个数,这里假设就是我们创建的那个AT吧,那么count=1

size_t count = activeTracks.size();

float masterVolume = mMasterVolume;

boolmasterMute = mMasterMute;

for (size_t i=0 ; i<count ; i++) {

sp<Track> t = activeTracks[i].promote();

Track* const track = t.get();

//得到placement new分配的那个跨进程共享的对象

audio_track_cblk_t* cblk = track->cblk();

//设置混音器,当前活跃的track。

mAudioMixer->setActiveTrack(track->name());

if (cblk->framesReady() && (track->isReady() || track->isStopped()) &&

!track->isPaused() && !track->isTerminated())

{

// compute volume for this track

//AT已经write数据了。所以肯定会进到这来。

int16_t left, right;

if (track->isMuted() || masterMute || track->isPausing() ||

mStreamTypes[track->type()].mute) {

left = right = 0;

if (track->isPausing()) {

track->setPaused();

}

//AT设置的音量假设不为零,我们需要聆听声音!

//所以走else流程

} else {

// read original volumes with volume control

float typeVolume = mStreamTypes[track->type()].volume;

float v = masterVolume * typeVolume;

float v_clamped = v * cblk->volume[0];

if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;

left = int16_t(v_clamped);

v_clamped = v * cblk->volume[1];

if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;

right = int16_t(v_clamped);

//计算音量

}

//注意,这里对混音器设置了数据提供来源,是一个track,还记得我们前面说的吗?Track从

AudioBufferProvider派生

mAudioMixer->setBufferProvider(track);

mAudioMixer->enable(AudioMixer::MIXING);

int param = AudioMixer::VOLUME;

//为这个track设置左右音量等

mAudioMixer->setParameter(param, AudioMixer::VOLUME0, left);

mAudioMixer->setParameter(param, AudioMixer::VOLUME1, right);

mAudioMixer->setParameter(

AudioMixer::TRACK,

AudioMixer::FORMAT, track->format());

mAudioMixer->setParameter(

AudioMixer::TRACK,

AudioMixer::CHANNEL_COUNT, track->channelCount());

mAudioMixer->setParameter(

AudioMixer::RESAMPLE,

AudioMixer::SAMPLE_RATE,

int(cblk->sampleRate));

} else {

if (track->isStopped()) {

track->reset();

}

//如果这个track已经停止了,那么把它加到需要移除的track队列tracksToRemove中去

//同时停止它在AudioMixer中的混音

if (track->isTerminated() || track->isStopped() || track->isPaused()) {

tracksToRemove->add(track);

mAudioMixer->disable(AudioMixer::MIXING);

} else {

mAudioMixer->disable(AudioMixer::MIXING);

}

}

}

// remove all the tracks that need to be...

count = tracksToRemove->size();

return mixerStatus;

}

看明白了吗?prepare_l的功能是什么?根据当前活跃的track队列,来为混音器设置信息。可想而知,一个track必然在混音器中有一个对应的东西。我们待会分析AudioMixer的时候再详述。

为混音器准备好后,下面调用它的process函数

void AudioMixer::process(void* output)

{

mState.hook(&mState, output);//hook?难道是钩子函数?

}

晕乎,就这么简单的函数???

CTRL+左键,hook是一个函数指针啊,在哪里赋值的?具体实现函数又是哪个?

没办法了,只能分析AudioMixer类了。

4. AudioMixer

AudioMixer实现在framework/base/libs/audioflinger/AudioMixer.cpp中

AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)

:mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)

{

mState.enabledTracks= 0;

mState.needsChanged = 0;

mState.frameCount= frameCount;

mState.outputTemp= 0;

mState.resampleTemp = 0;

mState.hook= process__nop;//process__nop,是该类的静态函数

track_t* t = mState.tracks;

//支持32路混音。牛死了

for (int i=0 ; i<32 ; i++) {

t->needs = 0;

t->volume[0] = UNITY_GAIN;

t->volume[1] = UNITY_GAIN;

t->volumeInc[0] = 0;

t->volumeInc[1] = 0;

t->channelCount = 2;

t->enabled = 0;

t->format = 16;

t->buffer.raw = 0;

t->bufferProvider = 0;

t->hook = 0;

t->resampler = 0;

t->sampleRate = mSampleRate;

t->in = 0;

t++;

}

}

//其中,mState是在AudioMixer.h中定义的一个数据结构

//注意,source insight没办法解析这个mState,因为....见下面的注释。

struct state_t {

uint32_tenabledTracks;

uint32_tneedsChanged;

size_tframeCount;

mix_thook;

int32_t*outputTemp;

int32_t*resampleTemp;

int32_treserved[2];

track_ttracks[32];// __attribute__((aligned(32)));《--把这里注释掉

//否则source insight会解析不了这个state_t类型

};

intmActiveTrack;

uint32_tmTrackNames;//names?搞得像字符串,实际是一个int

const uint32_tmSampleRate;

state_tmState

好了,没什么吗。hook对应的可选函数实现有:

process__validate

process__nop

process__genericNoResampling

process__genericResampling

process__OneTrack16BitsStereoNoResampling

process__TwoTracks16BitsStereoNoResampling

AudioMixer构造的时候,hook是process__nop,有几个地方会改变这个函数指针的指向。

这部分涉及到数字音频技术,我就无力讲解了。我们看看最接近的函数

process__OneTrack16BitsStereoNoResampling

void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)

{

单track,16bit双声道,不需要重采样,大部分是这种情况了

const int i = 31 - __builtin_clz(state->enabledTracks);

const track_t& t = state->tracks[i];

AudioBufferProvider::Buffer& b(t.buffer);

int32_t* out = static_cast<int32_t*>(output);

size_t numFrames = state->frameCount;

const int16_t vl = t.volume[0];

const int16_t vr = t.volume[1];

const uint32_t vrl = t.volumeRL;

while (numFrames) {

b.frameCount = numFrames;

//获得buffer

t.bufferProvider->getNextBuffer(&b);

int16_t const *in = b.i16;

size_t outFrames = b.frameCount;

ifUNLIKELY--->不走这.

else {

do {

//计算音量等数据,和数字音频技术有关。这里不说了

uint32_t rl = *reinterpret_cast<uint32_t const *>(in);

in += 2;

int32_t l = mulRL(1, rl, vrl) >> 12;

int32_t r = mulRL(0, rl, vrl) >> 12;

*out++ = (r<<16) | (l & 0xFFFF);

} while (--outFrames);

}

numFrames -= b.frameCount;

//释放buffer。

t.bufferProvider->releaseBuffer(&b);

}

}

好像挺简单的啊,不就是把数据处理下嘛。这里注意下buffer。到现在,我们还没看到取共享内存里AT端write的数据呐。

那只能到bufferProvider去看了。

注意,这里用的是AudioBufferProvider基类,实际的对象是Track。它从AudioBufferProvider派生。

我们用得是PlaybackThread的这个Track

status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)

{

//一阵暗喜吧。千呼万唤始出来,终于见到cblk了

audio_track_cblk_t* cblk = this->cblk();

uint32_t framesReady;

uint32_t framesReq = buffer->frameCount;

//哈哈,看看数据准备好了没,

framesReady = cblk->framesReady();

if (LIKELY(framesReady)) {

uint32_t s = cblk->server;

uint32_t bufferEnd = cblk->serverBase + cblk->frameCount;

bufferEnd = (cblk->loopEnd < bufferEnd) ? cblk->loopEnd : bufferEnd;

if (framesReq > framesReady) {

framesReq = framesReady;

}

if (s + framesReq > bufferEnd) {

framesReq = bufferEnd - s;

}

获得真实的数据地址

buffer->raw = getBuffer(s, framesReq);

if (buffer->raw == 0) goto getNextBuffer_exit;

buffer->frameCount = framesReq;

return NO_ERROR;

}

getNextBuffer_exit:

buffer->raw = 0;

buffer->frameCount = 0;

return NOT_ENOUGH_DATA;

}

再看看释放缓冲的地方:releaseBuffer,这个直接在ThreadBase中实现了

void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)

{

buffer->raw = 0;

mFrameCount = buffer->frameCount;

step();

buffer->frameCount = 0;

}

看看step吧。mFrameCount表示我已经用完了这么多帧。

bool AudioFlinger::ThreadBase::TrackBase::step() {

bool result;

audio_track_cblk_t* cblk = this->cblk();

result = cblk->stepServer(mFrameCount);//哼哼,调用cblk的stepServer,更新

服务端的使用位置

return result;

}

到这里,大伙应该都明白了吧。原来AudioTrack中write的数据,最终是这么被使用的呀!!!

恩,看一个process__OneTrack16BitsStereoNoResampling不过瘾,再看看

process__TwoTracks16BitsStereoNoResampling。

void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void*

output)

int i;

uint32_t en = state->enabledTracks;

i = 31 - __builtin_clz(en);

const track_t& t0 = state->tracks[i];

AudioBufferProvider::Buffer& b0(t0.buffer);

en &= ~(1<<i);

i = 31 - __builtin_clz(en);

const track_t& t1 = state->tracks[i];

AudioBufferProvider::Buffer& b1(t1.buffer);

int16_t const *in0;

const int16_t vl0 = t0.volume[0];

const int16_t vr0 = t0.volume[1];

size_t frameCount0 = 0;

int16_t const *in1;

const int16_t vl1 = t1.volume[0];

const int16_t vr1 = t1.volume[1];

size_t frameCount1 = 0;

int32_t* out = static_cast<int32_t*>(output);

size_t numFrames = state->frameCount;

int16_t const *buff = NULL;

while (numFrames) {

if (frameCount0 == 0) {

b0.frameCount = numFrames;

t0.bufferProvider->getNextBuffer(&b0);

if (b0.i16 == NULL) {

if (buff == NULL) {

buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];

}

in0 = buff;

b0.frameCount = numFrames;

} else {

in0 = b0.i16;

}

frameCount0 = b0.frameCount;

}

if (frameCount1 == 0) {

b1.frameCount = numFrames;

t1.bufferProvider->getNextBuffer(&b1);

if (b1.i16 == NULL) {

if (buff == NULL) {

buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];

}

in1 = buff;

b1.frameCount = numFrames;

} else {

in1 = b1.i16;

}

frameCount1 = b1.frameCount;

}

size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;

numFrames -= outFrames;

frameCount0 -= outFrames;

frameCount1 -= outFrames;

do {

int32_t l0 = *in0++;

int32_t r0 = *in0++;

l0 = mul(l0, vl0);

r0 = mul(r0, vr0);

int32_t l = *in1++;

int32_t r = *in1++;

l = mulAdd(l, vl1, l0) >> 12;

r = mulAdd(r, vr1, r0) >> 12;

// clamping...

l = clamp16(l);

r = clamp16(r);

*out++ = (r<<16) | (l & 0xFFFF);

} while (--outFrames);

if (frameCount0 == 0) {

t0.bufferProvider->releaseBuffer(&b0);

}

if (frameCount1 == 0) {

t1.bufferProvider->releaseBuffer(&b1);

}

}

if (buff != NULL) {

delete [] buff;

}

}

看不懂了吧??哈哈,知道有这回事就行了,专门搞数字音频的需要好好研究下了!

三再论共享audio_track_cblk_t

为什么要再论这个?因为我在网上找了下,有人说audio_track_cblk_t是一个环形buffer,环形buffer是什么意思?自己查查!

这个吗,和我之前的工作经历有关系,某BOSS费尽心机想搞一个牛掰掰的环形buffer,搞得我累死了。现在audio_track_cblk_t是环形buffer?我倒是想看看它是怎么实现的。

顺便我们要解释下,audio_track_cblk_t的使用和我之前说的Lock,读/写,Unlock不太一样。为何?

l第一因为我们没在AF代码中看到有缓冲buffer方面的wait,MixThread只有当没有数据的时候会usleep一下。

l第二,如果有多个track,多个audio_track_cblk_t的话,假如又是采用wait信号的办法,那么由于pthread库缺乏WaitForMultiObjects的机制,那么到底该等哪一个?这个问题是我们之前在做跨平台同步库的一个重要难题。

1.写者的使用

我们集中到audio_track_cblk_t这个类,来看看写者是如何使用的。写者就是AudioTrack端,在这个类中,叫user

lframesAvailable,看看是否有空余空间

lbuffer,获得写空间起始地址

lstepUser,更新user的位置。

2.读者的使用

读者是AF端,在这个类中加server。

lframesReady,获得可读的位置

lstepServer,更新读者的位置

看看这个类的定义:

struct audio_track_cblk_t

{

Mutexlock; //同步锁

Conditioncv;//CV

volatileuint32_tuser;//写者

volatileuint32_tserver;//读者

uint32_tuserBase;//写者起始位置

uint32_tserverBase;//读者起始位置

void*buffers;

uint32_tframeCount;

// Cache line boundary

uint32_tloopStart; //循环起始

uint32_tloopEnd; //循环结束

intloopCount;

uint8_tout;//如果是Track的话,out就是1,表示输出。

}

注意这是volatile,跨进程的对象,看来这个volatile也是可以跨进程的嘛。

l唉,又要发挥下了。volatile只是告诉编译器,这个单元的地址不要cache到CPU的缓冲中。也就是每次取值的时候都要到实际内存中去读,而且可能读内存的时候先要锁一下总线。防止其他CPU核执行的时候同时去修改。由于是跨进程共享的内存,这块内存在两个进程都是能见到的,又锁总线了,又是同一块内存,volatile当然保证了同步一致性。

lloopStart和loopEnd这两个值是表示循环播放的起点和终点的,下面还有一个loopCount吗,表示循环播放次数的

那就分析下吧。

先看写者的那几个函数

4写者分析

先用frameavail看看当前剩余多少空间,我们可以假设是第一次进来嘛。读者还在那sleep呢。

uint32_t audio_track_cblk_t::framesAvailable()

{

Mutex::Autolock _l(lock);

return framesAvailable_l();

}

int32_t audio_track_cblk_t::framesAvailable_l()

{

uint32_t u = this->user;当前写者位置,此时也为0

uint32_t s = this->server; //当前读者位置,此时为0

if (out) { out为1

uint32_t limit = (s < loopStart) ? s : loopStart;

我们不设循环播放时间吗。所以loopStart是初始值INT_MAX,所以limit=0

return limit + frameCount - u;

//返回0+frameCount-0,也就是全缓冲最大的空间。假设frameCount=1024帧

}

}

然后调用buffer获得其实位置,buffer就是得到一个地址位置。

void* audio_track_cblk_t::buffer(uint32_t offset) const

{

return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;

}

完了,我们更新写者,调用stepUser

uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount)

{

//framecount,表示我写了多少,假设这一次写了512帧

uint32_t u = this->user;//user位置还没更新呢,此时u=0;

u += frameCount;//u更新了,u=512

// Ensure that user is never ahead of server for AudioRecord

if (out) {

//没甚,计算下等待时间

}

//userBase还是初始值为0,可惜啊,我们只写了1024的一半

//所以userBase加不了

if (u >= userBase + this->frameCount) {

userBase += this->frameCount;

//但是这句话很重要,userBase也更新了。根据buffer函数的实现来看,似乎把这个

//环形缓冲铺直了....连绵不绝。

}

this->user = u;//喔,user位置也更新为512了,但是useBase还是0

return u;

}

好了,假设写者这个时候sleep了,而读者起来了。

5读者分析

uint32_t audio_track_cblk_t::framesReady()

{

uint32_t u = this->user; //u为512

uint32_t s = this->server;//还没读呢,s为零

if (out) {

if (u < loopEnd) {

return u - s;//loopEnd也是INT_MAX,所以这里返回512,表示有512帧可读了

} else {

Mutex::Autolock _l(lock);

if (loopCount >= 0) {

return (loopEnd - loopStart)*loopCount + u - s;

} else {

return UINT_MAX;

}

}

} else {

return s - u;

}

}

使用完了,然后stepServer

bool audio_track_cblk_t::stepServer(uint32_t frameCount)

{

status_t err;

err = lock.tryLock();

uint32_t s = this->server;

s += frameCount; //读了512帧了,所以s=512

if (out) {

}

没有设置循环播放嘛,所以不走这个

if (s >= loopEnd) {

s = loopStart;

if (--loopCount == 0) {

loopEnd = UINT_MAX;

loopStart = UINT_MAX;

}

}

//一样啊,把环形缓冲铺直了

if (s >= serverBase + this->frameCount) {

serverBase += this->frameCount;

}

this->server = s; //server为512了

cv.signal(); //读者读完了。触发下写者吧。

lock.unlock();

return true;

}

6真的是环形缓冲吗?

环形缓冲是这样一个场景,现在buffer共1024帧。

假设:

l写者先写到1024帧

l读者读到512帧

l那么,写者还可以从头写512帧。

所以,我们得回头看看frameavail是不是把这512帧算进来了。

uint32_t audio_track_cblk_t::framesAvailable_l()

{

uint32_t u = this->user;//1024

uint32_t s = this->server;//512

if (out) {

uint32_t limit = (s < loopStart) ? s : loopStart;

return limit + frameCount - u;返回512,用上了!

}

}

再看看stepUser这句话

if (u >= userBase + this->frameCount) {u为1024,userBase为0,frameCount为1024

userBase += this->frameCount;//好,userBase也为1024了

}

看看buffer

return (int8_t *)this->buffers + (offset - userBase) * this->frameSize;

//offset是外界传入的基于user的一个偏移量。offset-userBase,得到的正式从头开始的那段数据空间。太牛了!

一目的

上回我们说了AudioFlinger(AF),总感觉代码里边有好多东西没说清楚,心里发毛。就看了看AF的流程,我们敢说自己深入了解了Android系统吗?AudioPolicyService(APS)是个什么东西?为什么要有它的存在?下层的Audio HAL层又是怎么结合到Android中来的?更有甚者,问个实在问题:插入耳机后,声音又怎么从最开始的外放变成从耳机输出了?调节音量的时候到底是调节Music的还是调节来电音量呢?这些东西,我们在AF的流程中统统都没讲到。但是这些他们又是至关重要的。从我个人理解来看,策略(Policy)比流程更复杂和难懂。

当然,遵循我们的传统分析习惯,得有一个切入点,否则我们都不知道从何入手了。

这里的切入点将是:

lAF和APS系统第一次起来后,到底干了什么。

l检测到耳机插入事件后,AF和APS的处理。

大家跟着我一步步来看,很快就发现,啊哈,APS也不是那么难嘛。

另外,这次代码分析的格式将参考《Linux内核情景分析》的样子,函数调用的解析将采用深度优先的办法,即先解释所调用的函数,然后再出来继续讲。

我曾经数度放弃分析APS,关键原因是我没找到切入点,只知道代码从头看到尾!

二AF和APS的诞生

这个东西,已经说得太多了。在framework\base\media\MediaServer\Main_MediaServer中。

我们看看。

int main(int argc, char** argv)

{

sp<ProcessState> proc(ProcessState::self());

sp<IServiceManager> sm = defaultServiceManager();

//先创建AF

AudioFlinger::instantiate();

//再创建APS

AudioPolicyService::instantiate();

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

}

2.1 new AudioFlinger

前面说过,instantiate内部会实例化一个对象,那直接看AF的构造函数。

AudioFlinger::AudioFlinger()

: BnAudioFlinger(),//基类构造函数

mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)

{

注意mAudioHardware和mNextThreadId

mHardwareStatus = AUDIO_HW_IDLE;

//创建audio的HAL代表

mAudioHardware = AudioHardwareInterface::create();

mHardwareStatus = AUDIO_HW_INIT;

//下面这些不至于会使用APS吧?APS还没创建呢!

if (mAudioHardware->initCheck() == NO_ERROR) {

setMode(AudioSystem::MODE_NORMAL);

setMasterVolume(1.0f);

setMasterMute(false);

}

}

感觉上,AF的构造函数就是创建了一个最重要的AudioHardWare的HAL代表。

其他好像是没干什么策略上的事情。

不过:AF创建了一个AudioHardware的HAL对象。注意整个系统就这一个AudioHardware了。也就是说,不管是线控耳机,蓝牙耳机,麦克,外放等等,最后都会由这一个HAL统一管理。

再看APS吧。

2.2 new AudioPolicyService

AudioPolicyService::AudioPolicyService()

: BnAudioPolicyService() , mpPolicyManager(NULL)

{

//mpPolicyManager?策略管理器?可能很重要

char value[PROPERTY_VALUE_MAX];

// TonePlayback?播放铃声的?为什么放在这里?以后来看看

mTonePlaybackThread = new AudioCommandThread(String8(""));

// Audio Command?音频命令?看到Command,我就想到设计模式中的Command模式了

//Android尤其是MediaPlayerService中大量使用了这种模式。

mAudioCommandThread = new AudioCommandThread(String8("ApmCommandThread"));

#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)

//注意AudioPolicyManagerBase的构造函数,把this传进去了。

mpPolicyManager = new AudioPolicyManagerBase(this);

//先假设我们使用Generic的Audio设备吧。

#else

...

#endif

//根据系统属性来判断摄像机是否强制使用声音。这个...为什么会放在这里?

//手机带摄像机好像刚出来的时候,为了防止偷拍,强制按快门的时候必须发出声音

//就是这个目的吧?

property_get("ro.camera.sound.forced", value, "0");

mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);

}

so easy!,不至于吧?我们不应该放过任何一个疑问!这么多疑问,先看哪个呢?这里分析的是Audio Policy,而构造函数中又创建了一个AudioPolicyManagerBase,而且不同厂商还可以实现自己的AudioPolicyManager,看来这个对于音频策略有至关重要的作用了。

不得不说的是,Android代码中的这些命名在关键地方上还是比较慎重和准确的。

另外,AudioPolicyManagerBase的构造函数可是把APS传进去了,看来又会有一些回调靠APS了。真绕。

2.3 AudioPolicyManagerBase

代码位置在framework\base\libs\audioflinger\AudioPolicyManagerBase.cpp中

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)

:

mPhoneState(AudioSystem::MODE_NORMAL), ---->这里有电话的状态?

mRingerMode(0),

mMusicStopTime(0),

mLimitRingtoneVolume(false)

{

[--->mPhoneState(AudioSystem::MODE_NORMAL)]

AudioSystem其实是窥视Android如何管理音频系统的好地方。位置在

framework\base\include\media\AudioSystem.h中,定义了大量的枚举之类的东西来表达Google对音频系统的看法。我们只能见招拆招了。

下面是audio_mode的定义。这里要注意一个地方:

这些定义都和SDK中的JAVA层定义类似。实际上应该说先有C++层的定义,然后再反映到JAVA层中。但是C++层的定义一般没有解释说明,而SDK中有。所以我们不能不面对的一个痛苦现实就是:常常需要参考SDK的说明才能搞明白到底是什么。

关于C++的AudioSystem这块,SDK的说明在AudioManager中。

enum audio_mode {

//解释参考SDK说明,以下不再说明

MODE_INVALID = -2, //无效mode

MODE_CURRENT = -1,//当前mode,和音频设备的切换(路由)有关

MODE_NORMAL = 0,//正常mode,没有电话和铃声

MODE_RINGTONE,//收到来电信号了,此时会有铃声

MODE_IN_CALL,//电话mode,这里表示已经建立通话了

NUM_MODES// Android大量采用这种技巧来表示枚举结束了。

};

好,继续:

...

mPhoneState(AudioSystem::MODE_NORMAL), ---->这里有电话的状态?

mRingerMode(0),

mMusicStopTime(0),

mLimitRingtoneVolume(false)

{

mpClientInterface = clientInterface;//BT,保存APS对象。

//forceUse?这是个什么玩意儿?

for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {

mForceUse[i] = AudioSystem::FORCE_NONE;

}

[---->AudioSystem::FORCE_NONE和AudioSystem::NUM_FORCE_USE]

注意,这里有两个枚举,太无耻了。先看看FORCE_NONE这个

enum forced_config {强制_配置,看名字好像是强制使用设备吧,比如外放,耳机,蓝牙等

FORCE_NONE,

FORCE_SPEAKER,

FORCE_HEADPHONES,

FORCE_BT_SCO,

FORCE_BT_A2DP,

FORCE_WIRED_ACCESSORY,

FORCE_BT_CAR_DOCK,

FORCE_BT_DESK_DOCK,

NUM_FORCE_CONFIG,

FORCE_DEFAULT = FORCE_NONE //这个,太无聊了。

};

再看看AudioSystem::NUM_FORCE_USE这个

enum force_use {

FOR_COMMUNICATION,//这里是for_xxx,不是force_xxx。

FOR_MEDIA,

FOR_RECORD,

FOR_DOCK,

NUM_FORCE_USE

};

不懂,两个都不懂。为何?能猜出来什么吗?也不行。因为我们没找到合适的场景!那好吧,我们去SDK找找。恩

我看到AudioManager这个函数setSpeakerphoneOn (boolean on)。好吧,我

这么调用

setSpeakerphoneOn(true),看看实现。

这次我没再浪费时间了,我用一个新的工具coolfind,把搜索framework目录,寻找*.java文件,匹配字符串setSpeakerphone。终于,我在

framework/base/media/java/android/media/AudioService.java中找到了。

public void setSpeakerphoneOn(boolean on){

if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {

return;

}

if (on) {

//看到这里,是不是明白十之八九了?下面这个调用是:

//强制通话使用speaker!原来是这么个意思!

AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION,

AudioSystem.FORCE_SPEAKER);

mForcedUseForComm = AudioSystem.FORCE_SPEAKER;

} else {

AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION,

AudioSystem.FORCE_NONE);

mForcedUseForComm = AudioSystem.FORCE_NONE;

}

}

好了,说点题外话,既然Android源码都放开给我们了,有什么理由我们不去多搜搜呢?上网google也是搜,查源代码也是一样吗。不过我们要有目的:就是找到一个合适的使用场景。

force_use和force_config就不用我再解释了吧?

[--->AudioPolicyManagerBase::AudioPolicyManagerBase]

...

//下面这个意思就是把几种for_use的情况使用的设备全部置为NONE。

//比如设置FOR_MEDIA的场景,使用的设备就是FORCE_NONE

for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) {

mForceUse[i] = AudioSystem::FORCE_NONE;

}

//目前可以的输出设备,耳机和外放

mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |

AudioSystem::DEVICE_OUT_SPEAKER;

//目前可用的输入设备,内置MIC

mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;

又得来看看AudioSystem是怎么定义输入输出设备的了。

[--->mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE]

enum audio_devices {

// output devices

DEVICE_OUT_EARPIECE = 0x1,

DEVICE_OUT_SPEAKER = 0x2,

DEVICE_OUT_WIRED_HEADSET = 0x4,

DEVICE_OUT_WIRED_HEADPHONE = 0x8,

DEVICE_OUT_BLUETOOTH_SCO = 0x10,

DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,

DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,

DEVICE_OUT_BLUETOOTH_A2DP = 0x80,

DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,

DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,

DEVICE_OUT_AUX_DIGITAL = 0x400,

DEVICE_OUT_DEFAULT = 0x8000,

DEVICE_OUT_ALL= (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER |

DEVICE_OUT_WIRED_HEADSET | DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |DEVICE_OUT_BLUETOOTH_SCO_CARKIT |

DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |

DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT),

DEVICE_OUT_ALL_A2DP= (DEVICE_OUT_BLUETOOTH_A2DP |

DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),

// input devices

DEVICE_IN_COMMUNICATION = 0x10000,

DEVICE_IN_AMBIENT = 0x20000,

DEVICE_IN_BUILTIN_MIC = 0x40000,

DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,

DEVICE_IN_WIRED_HEADSET = 0x100000,

DEVICE_IN_AUX_DIGITAL = 0x200000,

DEVICE_IN_VOICE_CALL = 0x400000,

DEVICE_IN_BACK_MIC = 0x800000,

DEVICE_IN_DEFAULT = 0x80000000,

DEVICE_IN_ALL= (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT |

DEVICE_IN_BUILTIN_MIC |DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET |

DEVICE_IN_AUX_DIGITAL | DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC |

DEVICE_IN_DEFAULT)

};

一些比较容易眼花的东西我标成红色的了。这么多东西,不过没什么我们不明白的了。

得嘞,继续走。

[--->AudioPolicyManagerBase::AudioPolicyManagerBase]

//目前可以的输出设备,又有耳机又有外放,配置很强悍啊。

//注意这里是OR操作符,最终mAvailableOutputDevices = 0X3

mAvailableOutputDevices = AudioSystem::DEVICE_OUT_EARPIECE |

AudioSystem::DEVICE_OUT_SPEAKER;

//目前可用的输入设备,内置MIC,mAvailableInputDevices为0x4000,不过我们不关注input

mAvailableInputDevices = AudioSystem::DEVICE_IN_BUILTIN_MIC;

...

下面东西就很少了,我们一气呵成。

//创建一个AudioOutputDescriptor,并设置它的device为外设0x2

AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();

outputDesc->mDevice = (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER;

//调用APS的openOutput,得到一个mHardwareOutput东东。这是个int型

//不过保不准是一个指针也不一定喔。

//而且,下面的参数都是指针类型(flags除外),难道?有人会改value吗?

mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,

&outputDesc->mSamplingRate,

&outputDesc->mFormat,

&outputDesc->mChannels,

&outputDesc->mLatency,

outputDesc->mFlags);

//这个...估计是把int和指针加入到一个map了,方便管理。

addOutput(mHardwareOutput, outputDesc);

//不知道干嘛,待会看。

setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);

//不知道干嘛,待会看。

updateDeviceForStrategy();

好了,上面还有一系列函数,等着我们调用呢。我们一个一个看。

提前说一下,这块可是AudioManagerBase的核心喔。

[---->AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor()]

AudioOutputDescriptor是个什么?我不是神,我也得看注释。

// descriptor for audio outputs. Used to maintain current configuration of each opened audio output

// and keep track of the usage of this output by each audio stream type.

明白了么?大概意思就是它,是这么一个东西:

l描述audio输出的,可以用来保存一些配置信息。

l跟踪音频stream类型使用这个output的一些情况。

没明白吧?以后碰到场景就明白了。

它的构造函数干了如下勾当:

AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor()

: mId(0), mSamplingRate(0), mFormat(0), mChannels(0), mLatency(0),

mFlags((AudioSystem::output_flags)0), mDevice(0), mOutput1(0), mOutput2(0)

{}

//很好,统统都置零了。上面这些东西不用我解释了吧?命名规则也可以看出来。

OK,go on.

[--->mHardwareOutput = mpClientInterface->openOutput()]:

这里调用的是APS的openOutput,看看去:

[--->AudioPolicyService::openOutput]

audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices,

uint32_t *pSamplingRate,

uint32_t *pFormat,

uint32_t *pChannels,

uint32_t *pLatencyMs,

AudioSystem::output_flags flags)

{

sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();

//娘希匹,搞到AF去了

return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels,

pLatencyMs, flags);

}

[----->AudioFlinger::openOutput]

int AudioFlinger::openOutput(uint32_t *pDevices,

uint32_t *pSamplingRate,

uint32_t *pFormat,

uint32_t *pChannels,

uint32_t *pLatencyMs,

uint32_t flags)

{

//我们思考下传进来的值吧

//*pDevices=0x2,代表外放

//其他都是0。 嘿嘿,有了值,这不就知道下面该怎么走了吗?

status_t status;

PlaybackThread *thread = NULL;

mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;

uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;

uint32_t format = pFormat ? *pFormat : 0;

uint32_t channels = pChannels ? *pChannels : 0;

uint32_t latency = pLatencyMs ? *pLatencyMs : 0;

Mutex::Autolock _l(mLock);

//HAL对象得到一个AudioStreamOut,传进去的值会改吗?

AudioStreamOut *output = mAudioHardware->openOutputStream(*pDevices,

(int *)&format,

&channels,

&samplingRate,

&status);

mHardwareStatus = AUDIO_HW_IDLE;

if (output != 0) {

//走哪个分支?我把答案告诉大家吧。

//刚才那个mAudioHardware->openOutputStream确实会更改指针对应的value。

//当然,我们说了,AF使用的是GENERIC的Audio硬件。大家有兴趣可以去看看它的实现。

//我待会再贴出它的内容。反正到这里。

//那几个值变成:format为PCM_16_BIT,channels为2,samplingRate为44100

//这样的话,那只能走else分支了。

if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||

(format != AudioSystem::PCM_16_BIT) ||

(channels != AudioSystem::CHANNEL_OUT_STEREO)) {

thread = new DirectOutputThread(this, output, ++mNextThreadId);

} else {

//还记得前两节分析的同学,看到这里是不是明白了?恩,原来

//open一个Output,就会在AF中创建一个混音线程。设计得真好。

//想象下,所有设置为外放的程序,它的输出都是这个外放stream混音线程来工作

//所有设置为耳机的程序,它的输出都是这个耳机stream混音线程来完成。

//为什么对stream特加强调呢,没看见

//我们调用的是mAudioHardware->openOutputStream(0x2,,,)嘛。返回的

//是一个AudioStreamOut,可不是设备喔。Android把这些个东西都交给HAL层去实现了。

//不用自己来管理系统上有什么耳机,外设,蓝牙真实设备之类的东东,它反正用AudioStreamOut来表示它想要的就可以了。例如Generic的Audio Hal只支持一个OutputStream。--> only my opinion

thread = new MixerThread(this, output, ++mNextThreadId);

}

//好了,又多得了一个线程,

mPlaybackThreads.add(mNextThreadId, thread);

if (pSamplingRate) *pSamplingRate = samplingRate;

if (pFormat) *pFormat = format;

if (pChannels) *pChannels = channels;

if (pLatencyMs) *pLatencyMs = thread->latency();

//从这里返回的是混音线程的索引。

return mNextThreadId;

}

return 0;//如果没创建成功线程,则返回零。

}

好,我们回到AudioManagerBase中。

[--->AudioPolicyManagerBase::AudioPolicyManagerBase]

mHardwareOutput = mpClientInterface->openOutput(&outputDesc->mDevice,

&outputDesc->mSamplingRate,

&outputDesc->mFormat,

&outputDesc->mChannels,

&outputDesc->mLatency,

outputDesc->mFlags);

//上面实际就返回一个线程index。我有点疑惑,难道APS就只这么一个实际是线程index的东西就就行了吗?虽然它把这个index当成hardware的标识了。

//这个...估计是把int和指针加入到一个map了,方便管理。不看了。

addOutput(mHardwareOutput, outputDesc);

//不知道干嘛,待会看。

setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);

[--->setOutputDevice(mHardwareOutput,...)]

这个函数,很重要!另外,再传点技巧。不要老在source insight中后退后退了,直接找到window菜单,里边列出了最近打开的文件,找到我们的AudioManagerBase.cpp,不就行了吗?

void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)

{

//注意我们的参数:

// output = 1,

//device为AudioSystem::DEVICE_OUT_SPEAKER

// force为true,delayMs用默认值0

//map吧?刚才通过addOutput已经加进去了

AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);

if (outputDesc->isDuplicated()) {

setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);

setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);

return;

}

//还记得addOutput前设置的device吗?对了,为0X3,外放|耳机

uint32_t prevDevice = (uint32_t)outputDesc->device();

现在设置的是外设,

if ((device == 0 || device == prevDevice) && !force) {

return;

}

//喔,设置这个outputDesc为外放

outputDesc->mDevice = device;

popCount为2,因为device=0x2=0010

//另外,我对下面这个output== mHardwareOutput尤其感兴趣。还记得我们刚才的疑问吗?

// mHardwareOutput实际上是AF返回的一个线程索引,那AMB怎么根据这样一个东西来

//管理所有的线程呢?果然,这里就比较了output是不是等于最初创建的线程索引

//这就表明。虽然只有这么一个mHardwareOutput,但实际上还是能够操作其他output的!

if (output == mHardwareOutput && AudioSystem::popCount(device) == 2) {

setStrategyMute(STRATEGY_MEDIA, true, output);

usleep(outputDesc->mLatency*2*1000);

}

//晕,又冒出来一个AudioParameter,不过意思却很明白

//说我们要设置路由,新的输出设备为外放

//等我们以后讲由外放切换到耳机,再来看这个问题。

AudioParameter param = AudioParameter();

param.addInt(String8(AudioParameter::keyRouting), (int)device);

mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);

// update stream volumes according to new device

applyStreamVolumes(output, device, delayMs);

// if changing from a combined headset + speaker route, unmute media streams

if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) {

//这里说,把media的音量置为0。以后再说。

setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);

}

}

好了,返回了。

setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true);

这个调研,更新了mHardwareOutput对应的输出路由设备,而且还发了一个命令给APS,说你给我更新对应混音线程的输出路由设备。

[--->AudioPolicyManagerBase::AudioPolicyManagerBase]

.....

addOutput(mHardwareOutput, outputDesc);

setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER,

true);

//只剩下最后一个函数了

updateDeviceForStrategy();

[----->updateDeviceForStrategy()]

void AudioPolicyManagerBase::updateDeviceForStrategy()

{

for (int i = 0; i < NUM_STRATEGIES; i++) {

mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);

}

}

晕,又出来一个枚举。我们看看

[---->for (int i = 0; i < NUM_STRATEGIES; i++)]

NUM_STRATEGIES在hardware/libhardware_legacy/include/hardware_legacy/

AudioPolicyManagerBase.h中定义。

enum routing_strategy {

//好像很好理解

STRATEGY_MEDIA,

STRATEGY_PHONE,//通话音吗?

STRATEGY_SONIFICATION,//除了其他三个外的,可以是铃声,提醒声等。

STRATEGY_DTMF,//好像是拨号音

NUM_STRATEGIES

};

这个,反正我在SDK上没找到对应说明,我们待到以后看看会不会柳暗花明呢?

[----->getDeviceForStrategy((routing_strategy)i, false)]

看这个函数名的意思是,为各种策略找到它对应的设备。

uint32_t AudioPolicyManagerBase::getDeviceForStrategy(routing_strategy strategy, bool fromCache)

{

//fromCache为false

//放眼望去,这个函数好像涉及到很对策略方面的事情。

//我们大概讲解下,至于系统为什么要这么做,问Google吧。

uint32_t device = 0;

switch (strategy) {

case STRATEGY_DTMF:

if (mPhoneState != AudioSystem::MODE_IN_CALL) {

//如果在打电话过程中,你再按按键,则和MEDIA走一个设备

device = getDeviceForStrategy(STRATEGY_MEDIA, false);

break;

}

//注意这里没有break,所以在其他mode下,DTMF和PHONE用一个策略

case STRATEGY_PHONE:

//还得判断用户是不是强制使用了输出设备。

switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {

case AudioSystem::FORCE_BT_SCO:

if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {

device = mAvailableOutputDevices &

AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;

if (device) break;

}

device = mAvailableOutputDevices &

AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;

if (device) break;

device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;

if (device) break;

// if SCO device is requested but no SCO device is available, fall back to default

// case

// FALL THROUGH

//我们还记得强制设置那里吗?对了,此时都是FORCE_NONE

//而且,mAvailableOutputDevices是0X3 (外放|耳机)

default:// FORCE_NONE

device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;

if (device) break;

device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;

if (device) break;

//看,下面这句会成立。啥意思?如果有耳机的话,那么输出设备就是耳机

//太正确了。实际手机是不是就是这样的呢?

device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;

break;

//再验证下我们刚才说的,如果强制使用外放的话,

case AudioSystem::FORCE_SPEAKER:

if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {

device = mAvailableOutputDevices &

AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;

if (device) break;

}

//果然,会强制使用外放。

device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;

break;

}

break;

case STRATEGY_SONIFICATION://分析方法同上,我不说了。

if (mPhoneState == AudioSystem::MODE_IN_CALL) {

device = getDeviceForStrategy(STRATEGY_PHONE, false);

break;

}

device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;

//同样没有break,说明SONIFICATION受MEDIA策略影响。

case STRATEGY_MEDIA: {

uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;

if (device2 == 0) {

device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;

}

if (device2 == 0) {

device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;

}

//可惜,上面那些高级设备我们都没有

if (device2 == 0) {

device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;

}

//假设我们没有从SONIFICATION下来,那么device最终会= DEVICE_OUT_SPEAKER。

//假设我们从SONIFICATION下来,那么device还是等于DEVICE_OUT_SPEAKER

//奇怪,如果有耳机的话为何会走外放呢?普通耳机和线控耳机还能区分?

device |= device2;

} break;

default:

break;

}

return device;

}

好了,回到

[---->AudioPolicyManagerBase::updateDeviceForStrategy()]

void AudioPolicyManagerBase::updateDeviceForStrategy()

{

for (int i = 0; i < NUM_STRATEGIES; i++) {

mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false);

}

}

这个函数完了,表明各种策略下使用的对应设备也准备好了。

真爽,一路回去,APS的构造就完了。

留个纪念:

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)

{

....

updateDeviceForStrategy();

}

AudioPolicyService::AudioPolicyService()

: BnAudioPolicyService() , mpPolicyManager(NULL)

{

#if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST)

mpPolicyManager = new AudioPolicyManagerBase(this);

LOGV("build for GENERIC_AUDIO - using generic audio policy");

...

#endif

property_get("ro.camera.sound.forced", value, "0");

mpPolicyManager->setSystemProperty("ro.camera.sound.forced", value);

}

2.4总结

总结下吧,AF,APS都创建完了,得到什么了吗?下面按先后顺序说说。

lAF创建了一个代表HAL对象的东西

lAPS创建了两个AudioCommandThread,一个用来处理命令,一个用来播放tone。我们还没看。

lAPS同时会创建AudioManagerBase,做为系统默认的音频管理

lAMB集中管理了策略上面的事情,同时会在AF的openOutput中创建一个混音线程。同时,AMB会更新一些策略上的安排。

另外,我们分析的AMB是Generic的,但不同厂商可以实现自己的策略。例如我可以设置只要有耳机,所有类型声音都从耳机出。

上面关于AMB方面,我们还只是看了看它的代码,还没有一个实际例子来体会。



更多相关文章

  1. Android 多线程编程 一个游戏程序员的学习资料
  2. Android查看网页源码与开启子线程
  3. Android的Handler机制详解3_Looper.looper()不会卡死主线程
  4. Android异步加载图像小结 (含线程池,缓存方法)
  5. Android异步线程OkHttp Post请求Json数据并解析
  6. Android 中的 Looper 对象
  7. 线程池的封装和使用(二)
  8. Android studio 简单的多线程

随机推荐

  1. Android应用开发商业模式学习
  2. Android中集成QQ登陆和QQ好友分享及QQ空
  3. 右下角android sdk content loader 加载
  4. Android实现倒计时效果(天-时-分-秒)
  5. android ndk 相关工具安装
  6. Android(安卓)Lint 检查规则列表
  7. 增加Android模拟器的内存
  8. [置顶] Android(安卓)L中的RecyclerView
  9. android binder 机制二(client和普通serv
  10. Android开发之颜色选择器