audiotrack分析

来源:互联网 发布:linux select c代码 编辑:程序博客网 时间:2024/06/05 06:16
首先总结一下AudioTrack
AudioTrack字面意思是音轨,可以理解为一路音频的来源。
JAVA层也有AudioTrack的概念,但只是简单的封装,这里不介绍了。只介绍Native JNI的AT


AT 向下传送数据,有两种方式:
1,主动push方式,(对AF来说是被动方式)
AT调用write函数把音频数据“push”到AudioTrack中。
2,被动pull方式,(对AF来说是主动方式)
AF调用callback,从AT获取数据

从另外一个维度来看,还有两种方式:
1,static方式,一次性把数据全传送给AF
延时大,简单高效,适用于提示音等操作
2,stream方式,数据一点点的传送给AF,一块一块的传送
延时小,不受文件大小限制。流媒体播放只能用这种。

下面结合代码总结一下AT的初始化,以及运行起来的流程问题。

开始播放时,JAVA层用JNI调用native函数
static int android_media_AudioTrack_native_setup(....){sp<AudioTrack> lpTrack = new AudioTrack();//初始化track对象 switch (memoryMode) {    case MODE_STREAM:        lpTrack->set(   //给track设置好参数            atStreamType,// stream type            sampleRateInHertz,            format,// word length, PCM            nativeChannelMask,            frameCount,            AUDIO_OUTPUT_FLAG_NONE,            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack            0,// shared mem   //stream模式不用共享内存            true,// thread can call Java            sessionId);// audio session ID        break;    case MODE_STATIC:        // AudioTrack is using shared memory        lpTrack->set(            atStreamType,// stream type            sampleRateInHertz,            format,// word length, PCM            nativeChannelMask,            frameCount,            AUDIO_OUTPUT_FLAG_NONE,            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack            lpJniStorage->mMemBase,// shared mem    //static模式使用共享内存            true,// thread can call Java            sessionId);// audio session ID        break;}

static int android_media_AudioTrack_native_setup(....){sp<AudioTrack> lpTrack = new AudioTrack();//初始化track对象 switch (memoryMode) {    case MODE_STREAM:        lpTrack->set(   //给track设置好参数            atStreamType,// stream type            sampleRateInHertz,            format,// word length, PCM            nativeChannelMask,            frameCount,            AUDIO_OUTPUT_FLAG_NONE,            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack            0,// shared mem   //stream模式不用共享内存            true,// thread can call Java            sessionId);// audio session ID        break;    case MODE_STATIC:        // AudioTrack is using shared memory        lpTrack->set(            atStreamType,// stream type            sampleRateInHertz,            format,// word length, PCM            nativeChannelMask,            frameCount,            AUDIO_OUTPUT_FLAG_NONE,            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack            lpJniStorage->mMemBase,// shared mem    //static模式使用共享内存            true,// thread can call Java            sessionId);// audio session ID        break;}

由此可见,AudioTrack::set函数很重要。负责对AT初始化
status_t AudioTrack::set(.... ){ ....参数检查    audio_io_handle_t output = AudioSystem::getOutput(   //根据参数,为这个AT寻找恰当的output输出                                    streamType,                                    sampleRate, format, channelMask,                                    flags,                                    offloadInfo);    if (cbf != NULL) {        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);    }//启动一个AT线程,该线程负责处理callback事件,最主要的就是处理EVENT_MORE_DATA 事件,以便通过pull机制存储数据。    // create the IAudioTrack    status_t status = createTrack_l(streamType,                                  sampleRate,                                  format,                                  frameCount,                                  flags,                                  sharedBuffer,                                  output,                                  0 /*epoch*/);//为AT在AF中创建一个Track实例,Track实例是AF和AT交互的桥梁。其handle是IAudioTrack形式的,存储在成员变量mAudioTrack中}

AT与AF在两个不同进程,其通信依靠的是createTrack_l中创建的位于AF中的Track实例。Track实例在AF中用数组的形式存放。
下面分析一下createTrack_l函数。
status_t AudioTrack::createTrack_l(){    status_t status;    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); //获得AF service    sp<IAudioTrack> track = audioFlinger->createTrack(streamType,  //调用AF接口来在AF里面创建Track实例                                                      sampleRate,                                                      format == AUDIO_FORMAT_PCM_8_BIT ?                                                              AUDIO_FORMAT_PCM_16_BIT : format,                                                      mChannelMask,                                                      frameCount,                                                      &trackFlags,                                                      sharedBuffer,                                                      output,                                                      tid,                                                      &mSessionId,                                                      mName,                                                      mClientUid,                                                      &status);    sp<IMemory> iMem = track->getCblk();    mAudioTrack = track;    mCblkMemory = iMem;    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer());    mCblk = cblk;    //获得Audio data的FIFO地址    size_t temp = cblk->frameCount_;    frameCount = temp;    mAwaitBoost = false;    return NO_ERROR;}

从上面看到,实际是调用了AudioFlinger::createTrack在AF里面创建了Track实例。那么是怎么创建的呢?
sp<IAudioTrack> AudioFlinger::createTrack(...){        Mutex::Autolock _l(mLock);        PlaybackThread *thread = checkPlaybackThread_l(output);//通过前面讲过的获得的output,来获得playbackThread         track = thread->createTrack_l(client, streamType, sampleRate, format,                channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus); //在这个playbackThread里面创建Track        trackHandle = new TrackHandle(track); //提供给AT的handle,是IAudioTrack形式的}

上面我们看到,先利用前面获得的output,来得到output对应的playbackThread,然后在这个playbackThread里面创建了Track,并且为这个Track创建了handle,以提供给AT使用
可以看出,Track的创建,是基于playbackThread的,一个playbackThread可以有多个Track。

前面,我们在AudioTrack::createTrack_l函数里还可以看到audio data的数据区管理部分:
    sp<IMemory> iMem = track->getCblk();
    mAudioTrack = track;
    mCblkMemory = iMem;
    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer());
    mCblk = cblk;    
cblk实际上就是指向了audio buffer. 这样,AT就能用write函数写到这片audio data数据区了。

AF章节中,我们介绍过,AP通过调用AudioFlinger::openOutput函数,open了一个outStream, 创建了一个playbackThread, 并且用audio_io_handle_t id 键值来标记。
而output就是这个audio_io_handle_t id值,这样就能通过这个id,找到对应的playbackThread。然后在这个playback里面创建对应的Track。
如果一个playBackThread里面有多个Track,就需要用到AudioMixer来进行mixer混音操作。在AudioMixer章节,我们会详细介绍。

至此,我们大体介绍了AudioTrack是如何初始化的,如何在AudioFlinger中创建Track的,以及如何获得data buffer的。
很多细节我们放在了AudioFlnger和Audio Mixer来做介绍。

0 0
原创粉丝点击