动态 PCM

描述

动态 PCM 允许 ALSA PCM 设备在 PCM 流运行时将其 PCM 音频数字路由到各种数字端点。例如,PCM0 可以将数字音频路由到 I2S DAI0、I2S DAI1 或 PDM DAI2。这对于公开多个 ALSA PCM 并可以路由到多个 DAI 的片上系统 DSP 驱动程序非常有用。

DPCM 运行时路由由 ALSA 混音器设置确定,方式与 ASoC 编解码器驱动程序中模拟信号的路由方式相同。DPCM 使用表示 DSP 内部音频路径的 DAPM 图,并使用混音器设置来确定每个 ALSA PCM 使用的路径。

DPCM 重用所有现有的组件编解码器、平台和 DAI 驱动程序,无需任何修改。

基于片上系统的 DSP 的手机音频系统

考虑以下手机音频子系统。本文档中的所有示例都将使用此子系统:-

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

                    *************
PCM0 <------------> *           * <----DAI0-----> Codec Headset
                    *           *
PCM1 <------------> *           * <----DAI1-----> Codec Speakers
                    *   DSP     *
PCM2 <------------> *           * <----DAI2-----> MODEM
                    *           *
PCM3 <------------> *           * <----DAI3-----> BT
                    *           *
                    *           * <----DAI4-----> DMIC
                    *           *
                    *           * <----DAI5-----> FM
                    *************

此图显示了一个简单的智能手机音频子系统。它支持蓝牙、FM 数字收音机、扬声器、耳机插孔、数字麦克风和蜂窝调制解调器。此声卡公开 4 个 DSP 前端 (FE) ALSA PCM 设备,并支持 6 个后端 (BE) DAI。每个 FE PCM 可以将音频数据数字路由到任何 BE DAI。FE PCM 设备还可以将音频路由到多个 BE DAI。

示例 - 将播放从 DAI0 切换到 DAI1 的 DPCM

正在耳机上播放音频。过了一会儿,用户取下耳机,音频继续在扬声器上播放。

在 PCM0 上播放到耳机会是这样:-

                    *************
PCM0 <============> *           * <====DAI0=====> Codec Headset
                    *           *
PCM1 <------------> *           * <----DAI1-----> Codec Speakers
                    *   DSP     *
PCM2 <------------> *           * <----DAI2-----> MODEM
                    *           *
PCM3 <------------> *           * <----DAI3-----> BT
                    *           *
                    *           * <----DAI4-----> DMIC
                    *           *
                    *           * <----DAI5-----> FM
                    *************

用户从插孔上取下耳机,因此现在必须使用扬声器:-

                    *************
PCM0 <============> *           * <----DAI0-----> Codec Headset
                    *           *
PCM1 <------------> *           * <====DAI1=====> Codec Speakers
                    *   DSP     *
PCM2 <------------> *           * <----DAI2-----> MODEM
                    *           *
PCM3 <------------> *           * <----DAI3-----> BT
                    *           *
                    *           * <----DAI4-----> DMIC
                    *           *
                    *           * <----DAI5-----> FM
                    *************

音频驱动程序按如下方式处理:-

  1. 机器驱动程序接收到插孔移除事件。

  2. 机器驱动程序或音频 HAL 禁用耳机路径。

  3. DPCM 对耳机上的 DAI0 运行 PCM 触发(停止)、hw_free()、shutdown() 操作,因为该路径现已禁用。

  4. 机器驱动程序或音频 HAL 启用扬声器路径。

  5. DPCM 对扬声器的 DAI1 运行 startup()、hw_params()、prepare() 和 trigger(start) 等 PCM 操作,因为该路径已启用。

在此示例中,机器驱动程序或用户空间音频 HAL 可以更改路由,然后 DPCM 将负责管理 DAI PCM 操作以启动或关闭链接。音频播放在此转换期间不会停止。

DPCM 机器驱动程序

启用 DPCM 的 ASoC 机器驱动程序与普通的机器驱动程序类似,只是我们还必须:-

  1. 定义 FE 和 BE DAI 链接。

  2. 定义任何 FE/BE PCM 操作。

  3. 定义小部件图连接。

FE/BE PCM 操作

上面的 BE 还导出了一些 PCM 操作和一个 fixup 回调。机器驱动程序使用 fixup 回调根据 FE hw 参数(重新)配置 DAI。例如,DSP 可以执行从 FE 到 BE 的 SRC 或 ASRC。

例如,DSP 将所有 FE hw 参数转换为以 48k、16 位、立体声的固定速率运行 DAI0。这意味着必须在机器驱动程序中固定 DAI0 的所有 FE hw_params,以便 DAI 无论 FE 配置如何都以所需的配置运行。

static int dai0_fixup(struct snd_soc_pcm_runtime *rtd,
                      struct snd_pcm_hw_params *params)
{
      struct snd_interval *rate = hw_param_interval(params,
                      SNDRV_PCM_HW_PARAM_RATE);
      struct snd_interval *channels = hw_param_interval(params,
                                              SNDRV_PCM_HW_PARAM_CHANNELS);

      /* The DSP will convert the FE rate to 48k, stereo */
      rate->min = rate->max = 48000;
      channels->min = channels->max = 2;

      /* set DAI0 to 16 bit */
      params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
      return 0;
}

其他 PCM 操作与常规 DAI 链接相同。根据需要使用。

小部件图连接

BE DAI 链接通常由 ASoC DAPM 核心在初始化时连接到图。但是,如果 BE 编解码器或 BE DAI 是虚拟的,则必须在驱动程序中显式设置:-

/* BE for codec Headset -  DAI0 is dummy and managed by DSP FW */
{"DAI0 CODEC IN", NULL, "AIF1 Capture"},
{"AIF1 Playback", NULL, "DAI0 CODEC OUT"},

编写 DPCM DSP 驱动程序

DPCM DSP 驱动程序看起来很像标准的平台类 ASoC 驱动程序,并结合了编解码器类驱动程序的元素。DSP 平台驱动程序必须实现:-

  1. 前端 PCM DAI - 例如,struct snd_soc_dai_driver。

  2. 显示从 FE DAI 到 BE 的 DSP 音频路由的 DAPM 图。

  3. DSP 图中的 DAPM 小部件。

  4. 用于增益、路由等的混音器。

  5. DMA 配置。

  6. BE AIF 小部件。

第 6 项对于在 DSP 外部路由音频非常重要。需要为每个 BE 和每个流方向定义 AIF。例如,对于上面的 BE DAI0,我们将有:-

SND_SOC_DAPM_AIF_IN("DAI0 RX", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("DAI0 TX", NULL, 0, SND_SOC_NOPM, 0, 0),

BE AIF 用于将 DSP 图连接到其他组件驱动程序(例如,编解码器图)的图。

无主机 PCM 流

无主机 PCM 流是不通过主机 CPU 路由的流。一个例子是从手机到调制解调器的电话呼叫。

                    *************
PCM0 <------------> *           * <----DAI0-----> Codec Headset
                    *           *
PCM1 <------------> *           * <====DAI1=====> Codec Speakers/Mic
                    *   DSP     *
PCM2 <------------> *           * <====DAI2=====> MODEM
                    *           *
PCM3 <------------> *           * <----DAI3-----> BT
                    *           *
                    *           * <----DAI4-----> DMIC
                    *           *
                    *           * <----DAI5-----> FM
                    *************

在这种情况下,PCM 数据通过 DSP 路由。此用例中的主机 CPU 仅用于控制,并且可以在流运行时休眠。

主机可以通过以下方式控制无主机链接:-

  1. 将链接配置为 CODEC <-> CODEC 样式链接。在这种情况下,链接由 DAPM 图的状态启用或禁用。这通常意味着有一个混音器控件可用于连接或断开两个 DAI 之间的路径。

  2. 无主机 FE。此 FE 与 DAPM 图上的 BE DAI 链接具有虚拟连接。然后由 FE 作为常规 PCM 操作执行控制。此方法可以更好地控制 DAI 链接,但需要更多的用户空间代码来控制链接。建议使用 CODEC<->CODEC,除非您的硬件需要更精细的 PCM 操作序列。

无主机 FE

DAI 链接由不读取或写入任何 PCM 数据的 FE 启用。这意味着创建一个新的 FE,该 FE 通过虚拟路径连接到两个 DAI 链接。当启动 FE PCM 时,将启动 DAI 链接,而当停止 FE PCM 时,将停止 DAI 链接。请注意,在此配置中,FE PCM 不能读取或写入数据。