[alsa-devel] ASoC: multicodec: No matching channels with system with DACs and ADCs on same bus
Hi again, I have a system that has separate DACs and ADCs, as opposed to bidirectional CODECS.
The ADCs have a snd_soc_dai_driver structure that have a .capture field defined with a .rates parameter, and the DACs have a snd_soc_dai_driver structure that have a .playback field defined with a .rates parameter.
However, the ADCs have no .playback.rates, and the DACs have no .capture.rates. Even though the ADC can record at a given rate and the DAC can play at that same rate, the soc_pcm_init_runtime_hw function calculates the rates in this loop:
------------------------------ /* first calculate min/max only for CODECs in the DAI link */ for (i = 0; i < rtd->num_codecs; i++) { codec_dai_drv = rtd->codec_dais[i]->driver; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else codec_stream = &codec_dai_drv->capture; chan_min = max(chan_min, codec_stream->channels_min); chan_max = min(chan_max, codec_stream->channels_max); rate_min = max(rate_min, codec_stream->rate_min); rate_max = min_not_zero(rate_max, codec_stream->rate_max); formats &= codec_stream->formats; rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates); } ------------------------------
which can't work out that one side is play only and the other is record only, yet they do in fact have matching rates. So, I get a "no matching channels" error.
Here are my example drivers declarations: for the ADC: ---------------------- static struct snd_soc_dai_driver cs53l30_dai = { .name = "cs53l30-hifi", .capture = { .stream_name = "Capture", .channels_min = 4, .channels_max = 16, .rates = SNDRV_PCM_RATE_16000, .formats =SNDRV_PCM_FMTBIT_S16_LE, }, }; --------------------
and for the DAC
---------------------- static struct snd_soc_dai_driver tlv320dac3100_dai = { .name = "tlv320dac3100-hifi", .playback = { .stream_name = "Playback", .channels_min = 2, .channels_max = 16, .rates = SNDRV_PCM_RATE_16000, .formats =SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &tlv320dac3100_dai_ops, }; ------------------------------
I was able to fake it out by adding a .playback field to my ADC with 0 channels, and a .capture field to my DAC with 0 channels.
My question is: what's the right way to manage this? I assume we should probably tweak soc_pcm_init_runtime_hw, right?
Thanks, -Caleb
On Tue, 2015-11-10 at 09:12 -0800, Caleb Crome wrote:
Hi again, I have a system that has separate DACs and ADCs, as opposed to bidirectional CODECS.
The ADCs have a snd_soc_dai_driver structure that have a .capture field defined with a .rates parameter, and the DACs have a snd_soc_dai_driver structure that have a .playback field defined with a .rates parameter.
However, the ADCs have no .playback.rates, and the DACs have no .capture.rates. Even though the ADC can record at a given rate and the DAC can play at that same rate, the soc_pcm_init_runtime_hw function calculates the rates in this loop:
/* first calculate min/max only for CODECs in the DAI link */ for (i = 0; i < rtd->num_codecs; i++) { codec_dai_drv = rtd->codec_dais[i]->driver; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else codec_stream = &codec_dai_drv->capture; chan_min = max(chan_min, codec_stream->channels_min); chan_max = min(chan_max, codec_stream->channels_max); rate_min = max(rate_min, codec_stream->rate_min); rate_max = min_not_zero(rate_max, codec_stream->rate_max); formats &= codec_stream->formats; rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates); }
which can't work out that one side is play only and the other is record only, yet they do in fact have matching rates. So, I get a "no matching channels" error.
Here are my example drivers declarations: for the ADC:
static struct snd_soc_dai_driver cs53l30_dai = { .name = "cs53l30-hifi", .capture = { .stream_name = "Capture", .channels_min = 4, .channels_max = 16, .rates = SNDRV_PCM_RATE_16000, .formats =SNDRV_PCM_FMTBIT_S16_LE, }, };
and for the DAC
static struct snd_soc_dai_driver tlv320dac3100_dai = { .name = "tlv320dac3100-hifi", .playback = { .stream_name = "Playback", .channels_min = 2, .channels_max = 16, .rates = SNDRV_PCM_RATE_16000, .formats =SNDRV_PCM_FMTBIT_S16_LE, }, .ops = &tlv320dac3100_dai_ops, };
I was able to fake it out by adding a .playback field to my ADC with 0 channels, and a .capture field to my DAC with 0 channels.
My question is: what's the right way to manage this? I assume we should probably tweak soc_pcm_init_runtime_hw, right?
Not sure why this is not working for you. There are other DAI drivers upstream that are unidirectional and work fine.
Are you combining both unidirectional DAIs above into a single bidirectional DAI ?
Liam
On 11/10/2015 06:12 PM, Caleb Crome wrote:
Hi again, I have a system that has separate DACs and ADCs, as opposed to bidirectional CODECS.
The ADCs have a snd_soc_dai_driver structure that have a .capture field defined with a .rates parameter, and the DACs have a snd_soc_dai_driver structure that have a .playback field defined with a .rates parameter.
However, the ADCs have no .playback.rates, and the DACs have no .capture.rates. Even though the ADC can record at a given rate and the DAC can play at that same rate, the soc_pcm_init_runtime_hw function calculates the rates in this loop:
/* first calculate min/max only for CODECs in the DAI link */ for (i = 0; i < rtd->num_codecs; i++) { codec_dai_drv = rtd->codec_dais[i]->driver; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else codec_stream = &codec_dai_drv->capture; chan_min = max(chan_min, codec_stream->channels_min); chan_max = min(chan_max, codec_stream->channels_max); rate_min = max(rate_min, codec_stream->rate_min); rate_max = min_not_zero(rate_max, codec_stream->rate_max); formats &= codec_stream->formats; rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates); }
which can't work out that one side is play only and the other is record only, yet they do in fact have matching rates. So, I get a "no matching channels" error.
[...]
Try the latest asoc/for-next kernel. There is a patch[1] that addresses the issue.
- Lars
[1] http://git.kernel.org/cgit/linux/kernel/git/broonie/sound.git/commit/sound/s...
Ah, that looks like the one!
Thanks, -Caleb
On Tue, Nov 10, 2015 at 10:30 AM, Lars-Peter Clausen lars@metafoo.de wrote:
On 11/10/2015 06:12 PM, Caleb Crome wrote:
Hi again, I have a system that has separate DACs and ADCs, as opposed to bidirectional CODECS.
The ADCs have a snd_soc_dai_driver structure that have a .capture field defined with a .rates parameter, and the DACs have a snd_soc_dai_driver structure that have a .playback field defined with a .rates parameter.
However, the ADCs have no .playback.rates, and the DACs have no .capture.rates. Even though the ADC can record at a given rate and the DAC can play at that same rate, the soc_pcm_init_runtime_hw function calculates the rates in this loop:
/* first calculate min/max only for CODECs in the DAI link */ for (i = 0; i < rtd->num_codecs; i++) { codec_dai_drv = rtd->codec_dais[i]->driver; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else codec_stream = &codec_dai_drv->capture; chan_min = max(chan_min, codec_stream->channels_min); chan_max = min(chan_max, codec_stream->channels_max); rate_min = max(rate_min, codec_stream->rate_min); rate_max = min_not_zero(rate_max, codec_stream->rate_max); formats &= codec_stream->formats; rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates); }
which can't work out that one side is play only and the other is record only, yet they do in fact have matching rates. So, I get a "no matching channels" error.
[...]
Try the latest asoc/for-next kernel. There is a patch[1] that addresses the issue.
- Lars
[1] http://git.kernel.org/cgit/linux/kernel/git/broonie/sound.git/commit/sound/s...
On Tue, 10 Nov 2015, Caleb Crome wrote:
I have a system that has separate DACs and ADCs, as opposed to bidirectional CODECS.
The ADCs have a snd_soc_dai_driver structure that have a .capture field defined with a .rates parameter, and the DACs have a snd_soc_dai_driver structure that have a .playback field defined with a .rates parameter.
However, the ADCs have no .playback.rates, and the DACs have no .capture.rates. Even though the ADC can record at a given rate and the DAC can play at that same rate, the soc_pcm_init_runtime_hw function calculates the rates in this loop: ...
I had the same problem earlier this year. I submitted a patch which takes care of this that was applied a little over a month ago:
http://mailman.alsa-project.org/pipermail/alsa-devel/2015-September/097729.h...
/Ricard
On Tue, Nov 10, 2015 at 11:38 PM, Ricard Wanderlof < ricard.wanderlof@axis.com> wrote:
On Tue, 10 Nov 2015, Caleb Crome wrote:
I have a system that has separate DACs and ADCs, as opposed to bidirectional CODECS.
The ADCs have a snd_soc_dai_driver structure that have a .capture field defined with a .rates parameter, and the DACs have a snd_soc_dai_driver structure that have a .playback field defined with a .rates parameter.
However, the ADCs have no .playback.rates, and the DACs have no .capture.rates. Even though the ADC can record at a given rate and the DAC can play at that same rate, the soc_pcm_init_runtime_hw function calculates the rates in this loop: ...
I had the same problem earlier this year. I submitted a patch which takes care of this that was applied a little over a month ago:
http://mailman.alsa-project.org/pipermail/alsa-devel/2015-September/097729.h...
/Ricard
-- Ricard Wolf Wanderlöf ricardw(at)axis.com Axis Communications AB, Lund, Sweden www.axis.com Phone +46 46 272 2016 Fax +46 46 13 61 30
Yep, perfect. Thanks, -Caleb
participants (4)
-
Caleb Crome
-
Lars-Peter Clausen
-
Liam Girdwood
-
Ricard Wanderlof