audiotrack分析

首先总结一下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来做介绍。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 是的,AudioTrack构造器已经过时,推荐使用AudioTrack.Builder进行创建AudioTrack对象。\[2\] 使用AudioTrack.Builder可以更方便地设置音频属性和格式,并且可以使用链式调用来设置各种参数。例如,可以使用setAudioAttributes方法设置音频的用途和内容类型,使用setAudioFormat方法设置音频的编码格式、采样率和声道配置。最后,使用setBufferSizeInBytes方法设置缓冲区的大小,并通过build方法构建AudioTrack对象。\[2\] 在底层,AudioTrack会通过调用AudioFlinger来获取一个IAudioTrack对象,其中包含了重要的数据结构audio_track_cblk_t,该数据结构包括缓冲区地址、进程间同步内容和数据位置等信息。\[3\] 因此,使用新的AudioTrack.Builder可以更好地管理和控制音频播放。 #### 引用[.reference_title] - *1* *3* [Android深入浅出之Audio 第一部分 AudioTrack分析](https://blog.csdn.net/sadamoo/article/details/17377023)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Android 音频开发——AudioTrack播放](https://blog.csdn.net/VNanyesheshou/article/details/114703133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值