动态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驱动程序。
请考虑以下手机音频子系统。这将在本文档中用于所有示例: -
| 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。
音频正在播放到耳机。一段时间后,用户移除耳机,音频继续在扬声器上播放。
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 *************
音频驱动程序按如下方式处理: -
在此示例中,机器驱动程序或用户空间音频HAL可以改变路由,然后DPCM将负责管理DAI PCM操作以使链接上行或下行。在此过渡期间,音频播放不会停止。
启用DPCM的ASoC机器驱动程序与普通机器驱动程序类似,但我们还必须:
| 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 *************
对于上面的示例,我们必须定义4个FE DAI链接和6个BE DAI链接。FE DAI链接定义如下: -
static struct snd_soc_dai_link machine_dais[] = { { .name = "PCM0 System", .stream_name = "System Playback", .cpu_dai_name = "System Pin", .platform_name = "dsp-audio", .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dpcm_playback = 1, }, .....< other FE and BE DAI links here > };
这个FE DAI链接非常类似于常规DAI链接,除了我们还将DAI链接设置为DPCM FE 。还应使用和 标志设置支持的FE流方向。还可以选择为每个FE指定触发器调用的顺序。这允许ASoC内核在其他组件之前或之后触发DSP(因为某些DSP对订购DAI / DSP启动和停止序列有强烈要求)。dynamic = 1
dpcm_playback
dpcm_capture
上面的FE DAI将编解码器和代码DAI设置为虚拟设备,因为BE是动态的,并且将根据运行时配置而改变。
BE DAI配置如下: -
static struct snd_soc_dai_link machine_dais[] = { .....< FE DAI links here > { .name = "Codec Headset", .cpu_dai_name = "ssp-dai.0", .platform_name = "snd-soc-dummy", .no_pcm = 1, .codec_name = "rt5640.0-001c", .codec_dai_name = "rt5640-aif1", .ignore_suspend = 1, .ignore_pmdown_time = 1, .be_hw_params_fixup = hswult_ssp0_fixup, .ops = &haswell_ops, .dpcm_playback = 1, .dpcm_capture = 1, }, .....< other BE DAI links here > };
此BE DAI链接将DAI0连接到编解码器(在本例中为RT5460 AIF1)。它设置no_pcm
标志以标记它具有BE并使用dpcm_playback
及dpcm_capture
以上设置支持的流方向的标志。
BE还设置了用于忽略暂停和PM停机时间的标志。这允许BE在无主机模式下工作,其中主机CPU不像BT电话那样传输数据: -
************* PCM0 <------------> * * <----DAI0-----> Codec Headset * * PCM1 <------------> * * <----DAI1-----> Codec Speakers * DSP * PCM2 <------------> * * <====DAI2=====> MODEM * * PCM3 <------------> * * <====DAI3=====> BT * * * * <----DAI4-----> DMIC * * * * <----DAI5-----> FM *************
这允许主机CPU休眠,而DSP,MODEM DAI和BT DAI仍在运行。
如果代码是外部管理的设备,BE DAI链接还可以将编解码器设置为虚拟设备。
同样,如果CPU DAI由DSP固件管理,BE DAI也可以设置虚拟CPU DAI。
上面的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 covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; /* set DAI0 to 16 bit */ snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - SNDRV_PCM_HW_PARAM_FIRST_MASK], SNDRV_PCM_FORMAT_S16_LE); return 0; }
其他PCM操作与常规DAI链接相同。必要时使用。
BEIO链路通常在初始化时由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驱动程序看起来很像标准平台级ASoC驱动程序,与编解码器类驱动程序中的元素相结合。DSP平台驱动程序必须实现: -
第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流是不通过主机CPU路由的流。一个例子是从手机到调制解调器的电话。
************* PCM0 <------------> * * <----DAI0-----> Codec Headset * * PCM1 <------------> * * <====DAI1=====> Codec Speakers/Mic * DSP * PCM2 <------------> * * <====DAI2=====> MODEM * * PCM3 <------------> * * <----DAI3-----> BT * * * * <----DAI4-----> DMIC * * * * <----DAI5-----> FM *************
在这种情况下,PCM数据通过DSP路由。此用例中的主机CPU仅用于控制,并且可以在流的运行时期间休眠。
主持人可以通过以下方式控制无主机链接: -
- 将链接配置为CODEC < - > CODEC样式链接。在这种情况下,链接由DAPM图的状态启用或禁用。这通常意味着有一个混音器控件可用于连接或断开两个DAI之间的路径。
- 无主的FE。此FE与DAPM图上的BE DAI链接具有虚拟连接。然后由FE执行控制作为常规PCM操作。此方法可以更好地控制DAI链接,但需要更多用户空间代码来控制链接。建议使用CODEC < - > CODEC,除非您的硬件需要更精细的PCM操作顺序排序。
当DAPM在DAPM图中检测到有效路径时,将启用此DAI链接。机器驱动程序为DAI链接设置一些附加参数,即
static const struct snd_soc_pcm_stream dai_params = { .formats = SNDRV_PCM_FMTBIT_S32_LE, .rate_min = 8000, .rate_max = 8000, .channels_min = 2, .channels_max = 2, }; static struct snd_soc_dai_link dais[] = { < ... more DAI links above ... > { .name = "MODEM", .stream_name = "MODEM", .cpu_dai_name = "dai2", .codec_dai_name = "modem-aif1", .codec_name = "modem", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, .params = &dai_params, } < ... more DAI links here ... >
这些参数用于在DAPM检测到有效路径时配置DAI hw_params(),然后调用PCM操作以启动链接。当路径不再有效时,DAPM还将调用适当的PCM操作来禁用DAI。
DAI链接由不读取或写入任何PCM数据的FE启用。这意味着创建一个与两个DAI链接的虚拟路径相连的新FE。当FE PCM启动时,DAI链接将启动,当FE PCM停止时,将启动DAI链接。请注意,FE PCM无法在此配置中读取或写入数据。