On Sun, Oct 20, 2024 at 09:37:06AM -0700, anish kumar wrote: > Updated documentation to provide more details > for codec-to-codec connection. > > Signed-off-by: anish kumar <yesanishhere@xxxxxxxxx> > --- The patch doesn't seem to apply cleanly for me, my system doesn't seem to like: Content-Type: text/plain; charset="y" Not sure if that is a problem on my end or yours, but I am not familiar with that encoding. > v2: Fixed the compilation error reported by Sphinx > Documentation/sound/soc/codec-to-codec.rst | 296 +++++++++++++-------- > 1 file changed, 190 insertions(+), 106 deletions(-) > > diff --git a/Documentation/sound/soc/codec-to-codec.rst b/Documentation/sound/soc/codec-to-codec.rst > index 0418521b6e03..9d65fc74856a 100644 > --- a/Documentation/sound/soc/codec-to-codec.rst > +++ b/Documentation/sound/soc/codec-to-codec.rst > @@ -1,115 +1,199 @@ > -============================================== > -Creating codec to codec dai link for ALSA dapm > -============================================== > +Codec-to-Codec Connections in ALSA > +==================================== > > -Mostly the flow of audio is always from CPU to codec so your system > -will look as below: > -:: > +An ALSA-based audio system typically involves playback and capture > +functionalities, where users may require audio file playback through functionality would probably parse slightly better. > +speakers or recording from microphones. However, certain systems > +necessitate audio data routing directly between components, such as FM > +radio to speakers, without CPU involvement. For such scenarios, ALSA It would probably be more accurate to say "ASoC provides", I mean I guess ASoC is a part of ALSA but this is definitely an ASoC level feature. > +provides a mechanism known as codec-to-codec connections, leveraging > +the Dynamic Audio Power Management (DAPM) framework to facilitate > +direct data transfers between codecs. > > - --------- --------- > - | | dai | | > - CPU -------> codec > - | | | | > - --------- --------- > +Introduction > +------------ > > -In case your system looks as below: > -:: > +In most audio systems, audio data flows from the CPU to the codec. In > +specific configurations, such as those involving Bluetooth codecs, > +audio can be transmitted directly between codecs without CPU > +intervention. ALSA supports both architectures, and for systems that > +do not involve the CPU, it utilizes codec-to-codec digital audio > +interface (DAI) connections. This document discusses the procedure > +for establishing codec-to-codec DAI links to enable such > +functionalities. > > +Audio Data Flow Paths > +---------------------- > + > +In a typical configuration, audio flow can be visualized as follows: > + > +.. code-block:: text > + > + --------- --------- > + | | dai | | > + CPU -------> codec > + | | | | > + --------- --------- > + > +In more intricate setups, the system may not involve the CPU but > +instead utilizes multiple codecs as shown below. For instance, > +Codec-2 acts as a cellular modem, while Codec-3 connects to a > +speaker. Audio data can be received by Codec-2 and transmitted to > +Codec-3 without CPU intervention, demonstrating the ideal conditions > +for establishing a codec-to-codec DAI connection. > + > +.. code-block:: text > + > + --------- > + | | > + codec-1 <---cellular modem > + | | > --------- > - | | > - codec-2 > - | | > - --------- > - | > - dai-2 > - | > - ---------- --------- > - | | dai-1 | | > - CPU -------> codec-1 > - | | | | > - ---------- --------- > - | > - dai-3 > - | > - --------- > - | | > - codec-3 > - | | > + | > + dai-1 > + ↓ > + ---------- --------- > + | |cpu_dai | | > + dummy CPU -------> codec-2 Bringing the "dummy" into this is quite misleading, that really relates to DPCM setups. DPCM lets one select any number of back ends to service a given front end PCM, and often are abused to achieve things that should really be implemented as C2C links. > + | | | | > + ---------- --------- > + | > + dai-3 > + ↓ > + --------- > + | | > + codec-3 ---->speaker > + | | > --------- > > -Suppose codec-2 is a bluetooth chip and codec-3 is connected to > -a speaker and you have a below scenario: > -codec-2 will receive the audio data and the user wants to play that > -audio through codec-3 without involving the CPU.This > -aforementioned case is the ideal case when codec to codec > -connection should be used. > - > -Your dai_link should appear as below in your machine > -file: > -:: > - > - /* > - * this pcm stream only supports 24 bit, 2 channel and > - * 48k sampling rate. > - */ > - static const struct snd_soc_pcm_stream dsp_codec_params = { > - .formats = SNDRV_PCM_FMTBIT_S24_LE, > - .rate_min = 48000, > - .rate_max = 48000, > - .channels_min = 2, > - .channels_max = 2, > - }; > - > - { > - .name = "CPU-DSP", > - .stream_name = "CPU-DSP", > - .cpu_dai_name = "samsung-i2s.0", > - .codec_name = "codec-2, > - .codec_dai_name = "codec-2-dai_name", > - .platform_name = "samsung-i2s.0", > - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > - | SND_SOC_DAIFMT_CBM_CFM, > - .ignore_suspend = 1, > - .c2c_params = &dsp_codec_params, > - .num_c2c_params = 1, > - }, > - { > - .name = "DSP-CODEC", > - .stream_name = "DSP-CODEC", > - .cpu_dai_name = "wm0010-sdi2", > - .codec_name = "codec-3, > - .codec_dai_name = "codec-3-dai_name", > - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > - | SND_SOC_DAIFMT_CBM_CFM, > - .ignore_suspend = 1, > - .c2c_params = &dsp_codec_params, > - .num_c2c_params = 1, > - }, > - > -Above code snippet is motivated from sound/soc/samsung/speyside.c. > - > -Note the "c2c_params" callback which lets the dapm know that this > -dai_link is a codec to codec connection. > - > -In dapm core a route is created between cpu_dai playback widget > -and codec_dai capture widget for playback path and vice-versa is > -true for capture path. In order for this aforementioned route to get > -triggered, DAPM needs to find a valid endpoint which could be either > -a sink or source widget corresponding to playback and capture path > +Creating Codec-to-Codec Connections in ALSA > +---------------------------------------------- > + > +To create a codec-to-codec DAI in ALSA, a ``snd_soc_dai_link`` must be > +added to the machine driver before registering the sound card. > +During this registration, the core checks for the presence of > +``c2c_params`` within the ``snd_soc_dai_link``, determining whether > +to classify the DAI link as codec-to-codec. > + > +While establishing the PCM node, the ALSA core inspects this > +parameter. Instead of generating a user-space PCM node, it creates > +an internal PCM node utilized by kernel drivers. Consequently, I am not sure I like the description of this as an internal PCM node, I guess in some ways the core does use the same structures it would for a PCM node, but it isn't really a PCM node. I do like that you have added the additional note this will not be visible through procfs though. > +running ``cat /proc/asound/pcm`` will yield no visible PCM nodes. > + > +After this setup, the ALSA core invokes the DAPM core to connect a Again really ASoC core here. > +single ``cpu_dai`` with both ``codec_dais``. Boot-up logs will > +display messages similar to: That is definitely not what should be happening with a C2C link. In the system you showed the diagram for above there should be a connection between the CPU and codec-2, then two separate links between codec-2 and codecs 1 and 3. No links should be present between the CPU and codecs 1 or 3. > + > +.. code-block:: bash > + > + ASoC: registered pcm #0 codec2codec(Playback Codec) > + multicodec <-> cpu_dai mapping ok > + connected DAI link Dummy-CPU:cpu_dai -> codec-1:dai_1 > + connected DAI link Dummy-CPU:cpu_dai -> codec-2:dai_2 > + Yeah this is definitely mixing in a fair amount of DPCM stuff and does not match the rest of the description. > +To trigger this DAI link, a control interface is established by the > +DAPM core during internal DAI creation. This interface links to > +the ``snd_soc_dai_link_event`` function, which is invoked when a > +path connects in the DAPM core. A mixer must be created to trigger > +the connection, prompting the DAPM core to evaluate path > +connections and call the ``snd_soc_dai_link_event`` callback with > +relevant events. > + > +It is important to note that not all operations defined in > +``snd_soc_dai_ops`` are invoked as codec-to-codec connections offer > +limited control over DAI configuration. For greater control, a > +hostless configuration is recommended. The operations typically It is not clear to me what a "hostless configuration" is here. > +executed in codec-to-codec setups include startup, ``hw_params``, > +``hw_free``, digital mute, and shutdown from the > +``snd_soc_dai_ops`` structure. > + > +Code Changes for Codec-to-Codec > +---------------------------------- > + > +The DAI link configuration in the machine file should resemble the > +following code snippet: > + > +.. code-block:: c > + > + /* > + * This PCM stream only supports 24-bit, 2 channels, and > + * 48kHz sampling rate. > + */ > + static const struct snd_soc_pcm_stream dsp_codec_params = { > + .formats = SNDRV_PCM_FMTBIT_S24_LE, > + .rate_min = 48000, > + .rate_max = 48000, > + .channels_min = 2, > + .channels_max = 2, > + }; > + > + static struct snd_soc_dai_link dai_links[] = { > + { > + .name = "CPU-DSP", > + .stream_name = "CPU-DSP", > + .cpu_dai_name = "samsung-i2s.0", > + .codec_name = "codec-2", > + .codec_dai_name = "codec-2-dai_name", > + .platform_name = "samsung-i2s.0", > + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > + | SND_SOC_DAIFMT_CBM_CFM, > + .ignore_suspend = 1, > + .c2c_params = &dsp_codec_params, > + .num_c2c_params = 1, > + }, > + { > + .name = "DSP-CODEC", > + .stream_name = "DSP-CODEC", > + .cpu_dai_name = "wm0010-sdi2", > + .codec_name = "codec-3", > + .codec_dai_name = "codec-3-dai_name", > + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF > + | SND_SOC_DAIFMT_CBM_CFM, > + .ignore_suspend = 1, > + .c2c_params = &dsp_codec_params, > + .num_c2c_params = 1, > + }, > + }; > + > +This snippet draws inspiration from the configuration found in > +``sound/soc/samsung/speyside.c``. The inclusion of the > +``c2c_params`` indicates to the DAPM core that the DAI link is a > +codec-to-codec connection. > + > +In the DAPM core, a route is established between the CPU DAI > +playback widget and the codec DAI capture widget for playback, with > +the reverse applying to the capture path. To trigger these routes, > +DAPM requires valid endpoints, which can be either sink or source > +widgets corresponding to the playback and capture paths, > respectively. > > -In order to trigger this dai_link widget, a thin codec driver for > -the speaker amp can be created as demonstrated in wm8727.c file, it > -sets appropriate constraints for the device even if it needs no control. > - > -Make sure to name your corresponding cpu and codec playback and capture > -dai names ending with "Playback" and "Capture" respectively as dapm core > -will link and power those dais based on the name. > - > -A dai_link in a "simple-audio-card" will automatically be detected as > -codec to codec when all DAIs on the link belong to codec components. > -The dai_link will be initialized with the subset of stream parameters > -(channels, format, sample rate) supported by all DAIs on the link. Since > -there is no way to provide these parameters in the device tree, this is > -mostly useful for communication with simple fixed-function codecs, such > -as a Bluetooth controller or cellular modem. > +To activate this DAI link widget, a lightweight codec driver for > +the speaker amplifier can be implemented, following a similar > +strategy to that in ``wm8727.c``. This driver should set the > +necessary constraints for the device, even with minimal control > +requirements. Would actually be nice to include the note that any codec driver should be fine, the original text does kinda give the impression one would have to write a "thin codec driver" but if you already have a driver thin or otherwise that would be fine. Perhaps better to rephrase as a codec driver being required. > + > +It's crucial to append “Playback” and “Capture” suffixes to the > +respective CPU and codec DAI names for playback and capture, as > +the DAPM core links and powers these DAIs based on their naming > +conventions. Are you sure this is true? I could be wrong but I don't expect the naming is critical in hooking up a c2c DAI. > + > +In a codec-to-codec scenario involving multiple codecs (above > +bootup logs are for multicodec scenario), it is not feasible to > +control individual codecs using dummy kcontrols or DAPM widgets. I really am not sure what this means. What are we controlling using dummy kcontrols? Why are we not using the real kcontrols from the codec to control the codec? > +This limitation arises because the CPU DAI is statically > +connected to all codecs. Consequently, when a path is enabled, Which it shouldn't be? > +the DAPM core does not verify all the widgets that may be linked > +to the mixer widget. It’s important to note that the mixer widget > +serves as the trigger for these paths. > + > +Simple-audio-card configuration > +---------------------------------- > +A dai_link in a "simple-audio-card" will automatically be > +detected as codec-to-codec when all DAIs on the link belong to > +codec components. The dai_link will be initialized with the > +subset of stream parameters (channels, format, sample rate) > +supported by all DAIs on the link. Since there is no way to > +provide these parameters in the device tree, this is mostly useful > +for communication with simple fixed-function codecs, such as a > +Bluetooth controller or cellular modem. > -- > 2.39.3 (Apple Git-146) > > Thanks, Charles