动态 PCM

描述

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

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

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

基于 SoC 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。

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

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

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 trigger(stop)、hw_free()、shutdown() 操作。

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

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

在此示例中,机器驱动程序或用户空间音频 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、16bit、立体声的固定速率运行,用于 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 链路提供更多控制,但需要更多的用户空间代码来控制链路。除非您的硬件需要更精细的 PCM 操作序列,否则建议使用 CODEC<->CODEC。

无主机 FE

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