Qualcomm Audio HAL 音频通路设置

1. 音频框图概述

| Front End PCMs    |  SoC DSP  | Back End DAIs | Audio devices |

                    *************
PCM0 <------------> *           * <----DAI0-----> Codec Headset
                    *           *
PCM1 <------------> *           * <----DAI1-----> Codec Speakers/Earpiece
                    *   DSP     *
PCM2 <------------> *           * <----DAI2-----> MODEM
                    *           *
PCM3 <------------> *           * <----DAI3-----> BT
                    *           *
                    *           * <----DAI4-----> DMIC
                    *           *
                    *           * <----DAI5-----> FM
                    *************
  • Front End PCMs:音频前端,一个前端对应着一个 PCM 设备
  • Back End DAIs:音频后端,一个后端对应着一个 DAI 接口,一个 FE PCM 能够连接到一个或多个 BE DAI
  • Audio Device:有 headset、speaker、earpiece、mic、bt、modem 等;不同的设备可能与不同的 DAI 接口连接,也可能与同一个 DAI 接口连接(如上图,Speaker 和 Earpiece 都连接到 DAI1)
  • Soc DSP:本文范围内实现路由功能:连接 FE PCMs 和 BE DAIs,例如连接 PCM0 与 DAI1:
                    *************
PCM0 <============> *<====++    * <----DAI0-----> Codec Headset
                    *     ||    *
PCM1 <------------> *     ++===>* <====DAI1=====> Codec Speakers/Earpiece
                    *           *
PCM2 <------------> *           * <----DAI2-----> MODEM
                    *    DSP    *
PCM3 <------------> *           * <----DAI3-----> BT
                    *           *
                    *           * <----DAI4-----> DMIC
                    *           *
                    *           * <----DAI5-----> FM
                    *************

高通 MSM8996 音频框图:
MSM8996_Audio

  • FE PCMs

    • deep_buffer
    • low_latency
    • mutil_channel
    • compress_offload
    • audio_record
    • usb_audio
    • a2dp_audio
    • voice_call
  • BE DAIs

    • SLIM_BUS
    • Aux_PCM
    • Primary_MI2S
    • Secondary_MI2S
    • Tertiary_MI2S
    • Quatermary_MI2S

2. HAL 中的 usecase 和 device

usecase 通俗表示音频场景,对应着音频前端,比如:

  • low_latency:按键音、触摸音、游戏背景音等低延时的放音场景
  • deep_buffer:音乐、视频等对时延要求不高的放音场景
  • compress_offload:mp3、flac、aac等格式的音源播放场景,这种音源不需要软件解码,直接把数据送到硬件解码器(aDSP),由硬件解码器(aDSP)进行解码
  • record:普通录音场景
  • record_low_latency:低延时的录音场景
  • voice_call:语音通话场景
  • voip_call:网络通话场景
/* These are the supported use cases by the hardware.
 * Each usecase is mapped to a specific PCM device.
 * Refer to pcm_device_table[].
 */
enum {
   
   
    USECASE_INVALID = -1,
    /* Playback usecases */
    USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0,
    USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
    USECASE_AUDIO_PLAYBACK_MULTI_CH,
    USECASE_AUDIO_PLAYBACK_OFFLOAD,
    USECASE_AUDIO_PLAYBACK_ULL,

    /* FM usecase */
    USECASE_AUDIO_PLAYBACK_FM,

    /* HFP Use case*/
    USECASE_AUDIO_HFP_SCO,
    USECASE_AUDIO_HFP_SCO_WB,

    /* Capture usecases */
    USECASE_AUDIO_RECORD,
    USECASE_AUDIO_RECORD_COMPRESS,
    USECASE_AUDIO_RECORD_LOW_LATENCY,
    USECASE_AUDIO_RECORD_FM_VIRTUAL,

    /* Voice usecase */
    USECASE_VOICE_CALL,

    /* Voice extension usecases */
    USECASE_VOICE2_CALL,
    USECASE_VOLTE_CALL,
    USECASE_QCHAT_CALL,
    USECASE_VOWLAN_CALL,
    USECASE_VOICEMMODE1_CALL,
    USECASE_VOICEMMODE2_CALL,
    USECASE_COMPRESS_VOIP_CALL,

    USECASE_INCALL_REC_UPLINK,
    USECASE_INCALL_REC_DOWNLINK,
    USECASE_INCALL_REC_UPLINK_AND_DOWNLINK,

    USECASE_AUDIO_PLAYBACK_AFE_PROXY,
    USECASE_AUDIO_RECORD_AFE_PROXY,

    USECASE_AUDIO_PLAYBACK_EXT_DISP_SILENCE,

    AUDIO_USECASE_MAX
};

device 表示音频端点设备,包括输出端点(如 speaker、headphone、earpiece)和输入端点(如 headset-mic、builtin-mic)。高通 HAL 对音频设备做了扩展,比如 speaker 分为:

  • SND_DEVICE_OUT_SPEAKER:普通的外放设备
  • SND_DEVICE_OUT_SPEAKER_PROTECTED:带保护的外放设备
  • SND_DEVICE_OUT_VOICE_SPEAKER:普通的通话免提设备
  • SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED:带保护的通话免提设备

类似还有很多,详见 platform.h 音频设备定义,下面仅列举一部分:

/* Sound devices specific to the platform
 * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
 * devices to enable corresponding mixer paths
 */
enum {
   
   
    SND_DEVICE_NONE = 0,

    /* Playback devices */
    SND_DEVICE_MIN,
    SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
    SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
    SND_DEVICE_OUT_SPEAKER,
    SND_DEVICE_OUT_HEADPHONES,
    SND_DEVICE_OUT_HEADPHONES_DSD,
    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
    SND_DEVICE_OUT_SPEAKER_AND_LINE,
    SND_DEVICE_OUT_VOICE_HANDSET,
    SND_DEVICE_OUT_VOICE_SPEAKER,
    SND_DEVICE_OUT_VOICE_HEADPHONES,
    SND_DEVICE_OUT_VOICE_LINE,
    SND_DEVICE_OUT_HDMI,
    SND_DEVICE_OUT_DISPLAY_PORT,
    SND_DEVICE_OUT_BT_SCO,
    SND_DEVICE_OUT_BT_A2DP,
    SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP,
    SND_DEVICE_OUT_AFE_PROXY,
    SND_DEVICE_OUT_USB_HEADSET,
    SND_DEVICE_OUT_USB_HEADPHONES,
    SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
    SND_DEVICE_OUT_SPEAKER_PROTECTED,
    SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
    SND_DEVICE_OUT_END,

    /* Capture devices */
    SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
    SND_DEVICE_IN_HANDSET_MIC  = SND_DEVICE_IN_BEGIN, // 58
    SND_DEVICE_IN_SPEAKER_MIC,
    SND_DEVICE_IN_HEADSET_MIC,
    SND_DEVICE_IN_VOICE_SPEAKER_MIC,
    SND_DEVICE_IN_VOICE_HEADSET_MIC,
    SND_DEVICE_IN_BT_SCO_MIC,
    SND_DEVICE_IN_CAMCORDER_MIC,
    SND_DEVICE_IN_END,

    SND_DEVICE_MAX = SND_DEVICE_IN_END,
};

扩展这么多是为了方便设置 acdb id,比如外放和通话免提虽然都用了同样的喇叭设备,但是这两种情景会使用不同的算法,因此需要设置不同的 acdb id 到 aDSP,区分 SND_DEVICE_OUT_SPEAKER 和 SND_DEVICE_OUT_VOICE_SPEAKER 是为了匹配到各自的 acdb id。

由于高通 HAL 定义的音频设备与 Android Framework 定义的不一致,所以在高通 HAL 中会根据音频场景对框架层传入的音频设备进行转换,详见:

  • platform_get_output_snd_device()
  • platform_get_input_snd_device()

在高通 HAL 中,我们只看到 usecase(即 FE PCM)和 device,那么上一个节中提到的 BE DAI 为什么没有被提及?很简单,device 和 BE DAI 是“多对一”的关系,device 连接着唯一的 BE DAI(反过来就不成立了,BE DAI 可能连接着多个 device),所以确定了 device 也就能确定所连接的 BE DAI。

3. 音频通路连接

简单描述下高通 HAL 层音频通路的连接流程。如 音频框图概述 所示,音频通路分为三大块:FE PCMs、BE DAIs、Devices,这三块均需要打开并串联起来才能完成一个音频通路的设置。

FE_PCMs <=> BE_DAIs <=> Devices

3.1. 打开 FE PCM

FE PCMs 是在音频流打开时设置的,我们首先要了解一个音频流对应着一个 usecase,具体细节请参考:Android 音频系统:从 AudioTrack 到 AudioFlinger

AudioTrack、AudioFlinger Threads、AudioHAL Usecases、AudioDriver PCMs 的关系如下图所示:

AudioUsecase

start_output_stream() 代码分析:

// 根据 usecase 找到对应 FE PCM id
<think>好的,我现在要解决用户在ThinkCMF 5中引入第三方类库的问题。首先,我需要仔细阅读用户提供的引用内容,特别是引用3、4、5,因为这些可能直接相关。 用户提供的引用3提到ThinkPHP5中第三方类库可以放在extend目录下,并且使用命名空间。引用4则指出在ThinkCMF中,第三方类库应该放在simplewind/Core/Library/Vendor/下,比如Zend的例子。但ThinkCMF是基于ThinkPHP的,所以可能两种方式都适用?需要确认ThinkCMF5的结构是否与ThinkPHP5一致。 用户的问题是关于ThinkCMF5的,所以引用4可能更相关,但引用4中的路径是simplewind/Core/Library/Vendor/,这可能是旧版本的结构?比如ThinkCMF5是否仍然使用这样的目录?或者是否改用了类似TP5的extend目录? 另外,用户提供的引用5展示了在Util命名空间下的类,如何引入。引用3中提到了三种方法:直接实例化、use命名空间、或者使用Loader::import。但在TP5中,Loader类可能已经被替换,或者方法不同? 现在需要综合这些信息,给出ThinkCMF5的正确方法。可能的步骤包括: 1. 确定第三方类库的位置:根据引用4,可能在Vendor目录下,但根据引用3,TP5推荐extend目录。需要确认ThinkCMF5是否沿用了TP5的结构,或者有自己的规范。例如,ThinkCMF可能推荐将第三方类库放在Vendor目录下,如引用4中的路径,或者应用根目录的extend目录? 2. 类库的命名空间和文件路径是否遵循PSR-4标准。例如,如果类库有命名空间,需要目录结构对应。 3. 如何引入这些类库:自动加载、使用import方法,或者直接实例化。 可能存在的混淆点:ThinkCMF是基于TP5开发的,所以应该遵循TP5的类库引入方法。而引用3中的TP5方法指出第三方类库应放在extend目录,并正确使用命名空间。但引用4中的ThinkCMF例子却放在Vendor下,所以可能存在两种方式? 需要进一步确认:在ThinkCMF5中,是否更推荐将第三方类库放在extend目录,或者Vendor目录下? 假设用户使用的是最新的ThinkCMF5,可能基于TP5,因此参考引用3的TP5方法。所以正确方法应该是将第三方类库放在应用根目录的extend目录下,并正确设置命名空间。例如,如果类库的命名空间是first\second,则文件路径为extend/first/second/Foo.php,然后使用use语句或直接实例化。 但引用4提到的路径可能针对的是核心类库中的Vendor目录,比如引入如Zend等库时。而用户自己的第三方类库应该放在extend目录下? 需要区分两种情况:引入Composer管理的类库和手动引入的第三方类库。用户的问题应该是手动引入的情况,所以应指导他们将类库放在extend目录,并正确使用命名空间,然后通过自动加载或Loader类来引入。 此外,用户提供的引用5中,类位于Util命名空间,文件路径可能对应extend/Util/Work.php,然后通过new \Util\Work()来实例化。 所以,综合以上,步骤应该是: 1. 将第三方类库文件放置在extend目录下的相应子目录,根据命名空间结构。 2. 在代码中使用命名空间引入类,或者直接实例化。 此外,可能需要检查ThinkCMF5的文档,确认是否有特殊要求,但用户提供的引用中,引用4提到的是ThinkCMF的Vendor路径,但可能该路径是针对核心Vendor库,而用户自己的第三方库应放在应用extend目录。 因此,回答应结合TP5的方法,建议将第三方类库放在extend目录,正确命名空间,并使用use或直接实例化。</think>在ThinkCMF 5中引入第三方类库的方法主要遵循ThinkPHP 5的规范,以下是具体步骤: ### 一、类库存放位置 1. **extend目录**(推荐): 将第三方类库文件放置在应用根目录的`extend`目录下,目录结构需与命名空间对应。例如类`first\second\Foo`应存放于: ``` extend/first/second/Foo.php ``` 这是ThinkPHP 5官方推荐的扩展类库目录[^3]。 2. **Vendor目录**(可选): 若类库属于公共组件(如Zend等),可放在`simplewind/Core/Library/Vendor/`下,例如: ``` simplewind/Core/Library/Vendor/Zend/Server.php ``` 引用时需使用完整命名空间[^4]。 --- ### 二、命名规范 - 类需遵循**PSR-4**规范,命名空间与目录层级严格匹配。 - 避免与系统命名空间(如`think`、`app`)冲突[^3]。 --- ### 三、引入方法 #### 方法1:直接实例化 ```php $foo = new \first\second\Foo(); ``` #### 方法2:通过`use`引入命名空间 ```php use first\second\Foo; $foo = new Foo(); ``` #### 方法3:无命名空间类库(需手动导入) ```php use think\Loader; Loader::import('first.second.Foo'); $foo = new \Foo(); ``` --- ### 四、示例 假设需引入一个工具类`Util\Work`,文件路径为`extend/Util/Work.php`: ```php namespace Util; class Work { public function run() { return "Working"; } } ``` 在控制器中调用: ```php use Util\Work; public function index() { $work = new Work(); echo $work->run(); // 输出 "Working" } ``` --- ### 五、注意事项 1. **自动加载**:ThinkCMF 5默认支持PSR-4自动加载,无需手动引入文件。 2. **Composer类库**:若类库通过Composer安装,直接通过命名空间调用即可。 ---
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值