• 转载:android audio flinger


    https://blog.csdn.net/innost/article/details/6142812

    https://blog.csdn.net/zyuanyun/article/details/60890534

    Mixer thread: https://www.cnblogs.com/TaigaCon/category/1189652.html

    Audio Effect:https://blog.csdn.net/whshiyun/article/details/79806870

    Audio buffer:https://blog.csdn.net/whshiyun/article/details/79820714

    binder:https://blog.csdn.net/lushengchu_luis/article/details/10960471

    https://blog.csdn.net/coding_glacier/article/details/7520199

    https://blog.csdn.net/carson_ho/article/details/73560642

     android architecture:

    audio java framework(audioTrack.java):

    frameworks/base/media/java/media/

    audio jni(android_media_audioTrack.cpp):

    framework/base/core/jni

    libaudioclient(audioTrack.cpp):

    framework/av/media/libaudioclient/

    framwork/av/include/media

    audio service(audioflinger.cpp,audiopolicy.cpp)

    framework/av/services/audioflinger/

    framework/av/services/audiopolicy/

    libaudiohal

    frameworks/av/media/libaudiohal

    audio hal:

    vendor/xxx/hardware/audio/

    AndioFlinger 作为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程(PlaybackThread 及其派生的子类)和录制线程(RecordThread)进行的,我们简单看看回放线程和录制线程类关系:

     

    ThreadBase:PlaybackThread 和 RecordThread 的基类
    RecordThread:录制线程类,由 ThreadBase 派生
    PlaybackThread:回放线程基类,同由 ThreadBase 派生
    MixerThread:混音回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流,MixerThread 可以把多个音轨的数据混音后再输出
    DirectOutputThread:直输回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_DIRECT 的音频流,这种音频流数据不需要软件混音,直接输出到音频设备即可
    DuplicatingThread:复制回放线程类,由 MixerThread 派生,负责复制音频流数据到其他输出设备,使用场景如主声卡设备、蓝牙耳机设备、USB 声卡设备同时输出
    OffloadThread:硬解回放线程类,由 DirectOutputThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流,这种音频流未经软件解码的(一般是 MP3、AAC 等格式的数据),需要输出到硬件解码器,由硬件解码器解码成 PCM 数据
    PlaybackThread 中有个极为重要的函数 threadLoop(),当 PlaybackThread 被强引用时,threadLoop() 会真正运行起来进入循环主体,处理音频流数据相关事务

    1.threadLoop() 循环的条件是 exitPending() 返回 false,如果想要 PlaybackThread 结束循环,则可以调用 requestExit() 来请求退出;
    2.processConfigEvents_l() :处理配置事件;当有配置改变的事件发生时,需要调用 sendConfigEvent_l() 来通知 PlaybackThread,这样 PlaybackThread 才能及时处理配置事件;常见的配置事件是切换音频通路;
    检查此时此刻是否符合 standby 条件,比如当前并没有 ACTIVE 状态的 Track(mActiveTracks.size() = 0),那么调用 threadLoop_standby() 关闭音频硬件设备以节省能耗;
    3.prepareTracks_l(): 准备音频流和混音器,该函数非常复杂,这里不详细分析了,仅列一下流程要点:
    遍历 mActiveTracks,逐个处理 mActiveTracks 上的 Track,检查该 Track 是否为 ACTIVE 状态;
    如果 Track 设置是 ACTIVE 状态,则再检查该 Track 的数据是否准备就绪了;
    根据音频流的音量值、格式、声道数、音轨的采样率、硬件设备的采样率,配置好混音器参数;
    如果 Track 的状态是 PAUSED 或 STOPPED,则把该 Track 添加到 tracksToRemove 向量中;
    4.threadLoop_mix():读取所有置了 ACTIVE 状态的音频流数据,混音器开始处理这些数据;
    5.threadLoop_write(): 把混音器处理后的数据写到输出流设备;
    6.threadLoop_removeTracks(): 把 tracksToRemove 上的所有 Track 从 mActiveTracks 中移除出来;这样下一次循环时就不会处理这些 Track 了。
    这里说说 PlaybackThread 与输出流设备的关系:PlaybackThread 实例与输出流设备是一一对应的,比方说 OffloadThread 只会将音频数据输出到 compress_offload 设备中,MixerThread(with FastMixer) 只会将音频数据输出到 low_latency 设备中。

    从 Audio HAL 中,我们通常看到如下 4 种输出流设备,分别对应着不同的播放场景:

    primary_out:主输出流设备,用于铃声类声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_PRIMARY 的音频流和一个 MixerThread 回放线程实例
    low_latency:低延迟输出流设备,用于按键音、游戏背景音等对时延要求高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_FAST 的音频流和一个 MixerThread 回放线程实例
    deep_buffer:音乐音轨输出流设备,用于音乐等对时延要求不高的声音输出,对应着标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流和一个 MixerThread 回放线程实例
    compress_offload:硬解输出流设备,用于需要硬件解码的数据输出,对应着标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流和一个 OffloadThread 回放线程实例
    其中 primary_out 设备是必须声明支持的,而且系统启动时就已经打开 primary_out 设备并创建好对应的 MixerThread 实例。其他类型的输出流设备并非必须声明支持的,主要是看硬件上有无这个能力。

    可能有人产生这样的疑问:既然 primary_out 设备一直保持打开,那么能耗岂不是很大?这里阐释一个概念:输出流设备属于逻辑设备,并不是硬件设备。所以即使输出流设备一直保持打开,只要硬件设备不工作,那么就不会影响能耗。那么硬件设备什么时候才会打开呢?答案是 PlaybackThread 将音频数据写入到输出流设备时。

    下图简单描述 AudioTrack、PlaybackThread、输出流设备三者的对应关系:

    我们可以这么说:输出流设备决定了它对应的 PlaybackThread 是什么类型。怎么理解呢?意思是说:只有支持了该类型的输出流设备,那么该类型的 PlaybackThread 才有可能被创建。举个例子:只有硬件上具备硬件解码器,系统才建立 compress_offload 设备,然后播放 mp3 格式的音乐文件时,才会创建 OffloadThread 把数据输出到 compress_offload 设备上;反之,如果硬件上并不具备硬件解码器,系统则不应该建立 compress_offload 设备,那么播放 mp3 格式的音乐文件时,通过 MixerThread 把数据输出到其他输出流设备上。

    那么有无可能出现这种情况:底层并不支持 compress_offload 设备,但偏偏有个标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流送到 AudioFlinger 了呢?这是不可能的。系统启动时,会检查并保存输入输出流设备的支持信息;播放器在播放 mp3 文件时,首先看 compress_offload 设备是否支持了,如果支持,那么不进行软件解码,直接把数据标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;如果不支持,那么先进行软件解码,然后把解码好的数据标识为 AUDIO_OUTPUT_FLAG_DEEP_BUFFER,前提是 deep_buffer 设备是支持了的;如果 deep_buffer 设备也不支持,那么把数据标识为 AUDIO_OUTPUT_FLAG_PRIMARY。

    系统启动时,就已经打开 primary_out、low_latency、deep_buffer 这三种输出流设备,并创建对应的 MixerThread 了;而此时 DirectOutputThread 与 OffloadThread 不会被创建,直到标识为 AUDIO_OUTPUT_FLAG_DIRECT/AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流需要输出时,才开始创建 DirectOutputThread/OffloadThread 和打开 direct_out/compress_offload 设备。

     openOUtput:

    new AudioTrack:

    start:

    write:

    pause:

    audioEffect相关

     在一个音频thread当中,一个session对应一个effectChain,每个effectChain可以对应若干个track,只要这些track具有相同的session值。每个effectChain是否真正执行除了要看该effect module的状态外还依赖于effectChain是否有关联的track,即:mTrackCnt是否为零,其关系如下图所示:

    1. audioEffect的创建位置

    1、对于默认挂载的effect,对应的audioEffect是被AudioPolicyEffects(addOutputSessionEffects)所创建的,个人感觉这也是AudioPolicyEffects最大的作用了…… 

    2、android_media_AudioEffect.cpp,这里是给上层app提供的effect操作的接口了,这其实就是个jni的接口,里面提供了创建effect,设置effect,使能effect等等相关操作,如果app希望启动一个非默认effect或者去设置已经启动了的effect,应该就是从这里入手~这里面所有函数的操作都是通过调用AudioEffect类的对应方法来完成的。

    addOutputSessionEffects调用过程

    addOutputSessionEffects()函数的调用源头在audioPolicyService.cpp提供的对外接口中,这里面的接口最终会被上层应用的api接口所调用,上层调用关系不在这里记录,总之audioPolicyService的主要作用就是音频框架对上提供的一层服务接口。 
    调用过程: 
    1、status_t AudioPolicyService::startOutput()被上层应用调用; 
    2、startOutput()中调用mOutputCommandThread->startOutputCommand(output, stream, session); 
    3、mOutputCommandThread的创建是在AudioPolicyService::onFirstRef()函数中完成,mOutputCommandThread为一个线程
    4、AudioPolicyService::AudioCommandThread::threadLoop()中收到START_OUTPUT命令后,执行svc->doStartOutput()函数,这里的doStartOutput()函数在文件audioPolicyInterfaceImpl.cpp中。 
    5、doStartOutput()函数中调用audioPolicyEffects->addOutputSessionEffects(),创建跟session对应的effects,这些effects就是预置的对应流类型的effects。

    effect挂载及创建过程从new AudioEffect()开始,调用过程如下: 
    AudioEffect() —> audioFlinger->createEffect() —> thread->createEffect_l —> chain->createEffect_l() —> new EffectModule() —> EffectCreate() —> l->desc->create_effect()

    Buffer:

  • 相关阅读:
    Java数据类型
    实验报告三及总结
    第四周课程总结及实验报告二
    第三周课程总结及实验报告一
    第一次Java学习总结
    第十二周作业
    第十一周作业
    第十周作业
    第九周作业
    第八周作业
  • 原文地址:https://www.cnblogs.com/fellow1988/p/10122126.html
Copyright © 2020-2023  润新知