AudioTrack学习笔记

来源:互联网 发布:家具木工制图软件 编辑:程序博客网 时间:2024/06/03 16:56

1.AudioTrackThread

  threadLoop函数里会调用
   nsecs_t ns = mReceiver.processAudioBuffer();
 mReceiver就是一个AudioTrack,接收者?天知道为嘛这么叫。
 咱们先不说这个很重要的函数 processAudioBuffer,先来看看AudioTrackThread是在哪使用的。

2.AudioTrack类成员变量:

``sp<AudioTrackThread>    mAudioTrackThread;``

  在AudioTrack::set()函数中:

    if (cbf != NULL) {        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);        // thread begins in paused state, and will not reference us until start()    }

  callback存在的话,就new它,然后run之。但是注释都说了,start()之后,这个AudioTrackThread才会真正run起来,
因为:

sp<AudioTrackThread> t = mAudioTrackThread;    if (t != 0) {        if (previousState == STATE_STOPPING) {            mProxy->interrupt();        } else {            t->resume();        }    }

3.综上,也就是说AudioTrack::start的时候会有 mAudioTrackThread运行起来,不断调用 processAudioBuffer()方法。

4. processAudioBuffer()方法:

  里头循环调用了
   status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
  然后
   mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
  即获得buffer,然后,谁创建了AudioTrack,并且设置了回调(在AudioTrack构造函数中传入参数,构造函数会调用set进行赋值),就和谁要数据。比如说nuplayer。要数据的时候就把经过解码的pcm数据传下来。

5. obtainBuffer()

  真正干活的也不是这。干活的是:
    status = proxy->obtainBuffer(&buffer, requested, elapsed);
  实现在AudioTrackShare.cpp里头。
  (某一种情况)这个地方取到buffer的地址,然后通过
   mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
  把数据取回来,由于取到的这个buffer,audioFlinger那边也能访问,所以。。。

6.还是说说set函数吧(上面说过了,在构造函数中会调用)

  这里头有一个很重要的调用:createTrack_l(),这个函数在凡平老师的书里也说到了。AudioTrack和 AudioFlinger的联系啊简直是。
  这里头又调用了以前经常见到的一个函数AudioSystem::getOutputForAttr,这个函数一路下调到apm里头,现在暂且略过不表。
  createTrack_l()函数中经过了很复杂的流程,以及获取,设置了好多参数之后(其实是没看懂,一笔带过),调用了

  sp<IAudioTrack> track = audioFlinger->createTrack(streamType, mSampleRate,mFormat,mChannelMask,&temp,&trackFlags,mSharedBuffer,output,tid,&mSessionId,(mClientPid << 16) |mClientUid,&status);

  通过AudioFlinger的createTrack函数,返回了一个 sp<IAudioTrack>,我记得这个东西对应
  的就是TrackHandle类(AudioFlinger里头一个小小的内部类)。
再之后,贯穿AudioTrack类其中的mAudioTrack变量就是从这来的。
mAudioTrack = track;
很多AudioTrack的操作,都是调用TrackHandle类。最终由playbackThread的track类完成实际工作。
这还涉及到了共享内存,共享buffer等内容。略过先。
还是先继续瞅瞅createTrack函数吧。

7.AudioFlinger::createTrack()

    track = thread->createTrack_l(client, streamType, sampleRate, format,channelMask,         frameCount,sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus);         //妈蛋的,你瞅瞅,还要接着往下走,这个地方返回的track类型是啥呢?        sp<PlaybackThread::Track>  track;        // return handle to client        trackHandle = new TrackHandle(track);
  最终AudioFlinger的createTrack函数是这么返回的:  用PlaybackThread::createTrack_l()函数返回一个PlaybackThread::Track对象,然后用这个对象作为参数,构造一个TrackHandle对象,然后返回。  言归正传,接下来
            if (!isTimed) {              track = new Track(this, client, streamType, sampleRate, format,                channelMask, frameCount, NULL, sharedBuffer,sessionId, uid, *flags,                    TrackBase::TYPE_DEFAULT);            } else {              track = TimedTrack::create(this, client, streamType, sampleRate, format,              channelMask, frameCount, sharedBuffer, sessionId, uid);        }
          TimedTrack是什么鬼,说普通的吧:

8.AudioFlinger::PlaybackThread::Track::Track()

  PlaybackThread内部类Track又是什么鬼?
  这他妈应该是真正干活的了吧,再往下好像还有proxy.我要吐了。看到这边audioflinger,才发现,audiotrack的内容实在是太少了。

9.现在咱们又绕回去说说AudioTrackThread调用 processAudioBuffer()的那个地方

  nsecs_t ns = mReceiver.processAudioBuffer();
  这个函数返回纳秒,而函数内部return的地方,多是调用了

  framesToNanoseconds()  static inline nsecs_t framesToNanoseconds(ssize_t frames, uint32_t sampleRate, float speed){      return ((double)frames * 1000000000) / ((double)sampleRate * speed);}

  函数的实现也很简单。虽然不是很懂,到应该是s转换成了ns(纳秒)。难道是每次拿到的数据所持续的播放时间?

10.现在回去说说obtainBuffer吧。上面说到,它走到了AudioTrackShare.cpp里。这个文件里头有这么几个类:

  //基类:Proxy
  //Client系列:
   - ClientProxy
   - AudioTrackClientProxy
   - StaticAudioTrackClientProxy
   - AudioRecordClientProxy
  //Server系列:
   - AudioTrackServerProxy
   - StaticAudioTrackServerProxy
   - AudioRecordServerProxy
  继承关系一目了然,从名字大概能猜出来。

  代码的文件名中Share基本能说明,这些类应该和AudioFlinger,或者说给AudioTrack提供数据的一方关系很大。当然AudioTrack肯定是有关系的了。AudioTrack对应Client,AudioFlinger对应server。这两者之间还有一个生产者,消费者的关系(别人说的)。
  话说AudioTrack类的obtainBuffer调用了
   status_t ClientProxy::obtainBuffer
  这里边有个函数
   StaticAudioTrackServerProxy::pollPosition()
  也同样被调用到,然后呢?没看懂呢,先不继续了。。。
  // Proxy used by AudioFlinger server
   class ServerProxy : public Proxy {

  看着没?头文件都说了,AudioFlinger用的!
  费了半天劲,在AudioFlinger找到了一个变量mServerProxy,sourceinsight无法跳转,grep搜索发现,定义在了TrackBase.h里了
  void AudioFlinger::ThreadBase::TrackBase,子类的子类呀!

让我们看看真正的证据吧:
AudioFlinger::PlaybackThread::Track::Track()构造函数里调用了

    if (sharedBuffer == 0) {    mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,                mFrameSize, !isExternalTrack(), sampleRate);    } else {        mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,                mFrameSize);    }
  没错,和我们想的一样,就是用的ServerProxy.  上面的参数,mCblk,mBuffer,等参数在sourceInsight上是黑色的,没法跳转,根据经验,定义在基类里,即TrackBase.h文件里。比如说mBuffers(Track类的)从 StaticAudioTrackServerProxy()构造函数一路传了上去,最终,传到了前面说的Proxy类的mBuffers。  而这个mBuffers基本上就是obtainBuffer取数据的源泉啊。  mBuffers在AudioFlinger构造serverProxy的时候一步步传进来。然后在AudioTrack调用ClientProxy的obtainBuffer(write方式或者是processAudioBuffer方式都会调用)的时候通过参数返回。AudioTrack拿到共有缓冲区的地址之后,就可以往里放数据了也就是说,AudioFlinger和AudioTrack在通过这个mBuffers传递数据呀!这个地方还有一点需要说一下。就是  这个地方为什么有两个类,有一个前面多了一个static.使用场景不一样!static的那个是用在ShareBuffer给定(AudioTrack()那个参数不为空)的情况下,一直去里头取数据即可。所以说是static的。

11.AudioTrack::write函数:

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)上层应用调用这个函数,然后不断往下写经过解码的数据。这里边的buffer就是数据了。
 while (userSize >= mFrameSize) {        //。。。        status_t err = obtainBuffer(&audioBuffer,                blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);      // 。。。        memcpy(audioBuffer.i8, buffer, toWrite);    //。。。        releaseBuffer(&audioBuffer);    }

  其中的这个while循环不断做的事情就是通过obtainBuffer获得和AudioFlinger共享的buffer。然后往里头memcpy上层write的数据。最后releaseBuffer。

12.回调方式

  如果构造AudioTrack的时候,选用的构造函数是带callback_t cbf的那个,并且传入了存在的一个值,在AudioTrack的构造函数里就会调用set函数,把这个cbf传递给AudioTrack的mCbf这个成员变量。只要  ``mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);``

类似这样的调用方式,就会回调到在构造函数里传入的那个地址。比如SoundPool就把process函数作为了回调函数传给了AudioTrack。
  从字面意思看就是,我需要数据,快给我数据!不过soundPool一般是不会回调 EVENT_MORE_DATA的。因为一般数据量都很少,一次就可以搞定。soundPool一般都是回调EVENT_BUFFER_END。通知上层,数据没了。

1 0
原创粉丝点击