[alsa-devel] Question about hw_param with Ctrl-Z + fg
Hi ALSA SoC ML
We noticed that 2nd hw_param on ALSA SoC isn't called if we used Ctrl-Z + fg on aplay. hw_param is necessary especially if we use sampling rate converter (it depends on .be_hw_params_fixup). Ctrl-Z will use notmal STOP, and fg will use normal START, thus it is impossible to distinction Ctrl-C (stop) or Ctrl-Z (temporary suspension). Is this aplay issue ? or kernel issue ?
start/stop case - aplay xxx.wav => - hw_param - SNDRV_PCM_TRIGGER_START - Ctrl-C (stop) - SNDRV_PCM_TRIGGER_STOP
Ctrl-Z case - aplay xxx.wav => - hw_param - SNDRV_PCM_TRIGGER_START - Ctrl-Z - SNDRV_PCM_TRIGGER_STOP - fg => - ## no hw_param here - SNDRV_PCM_TRIGGER_START - Ctrl-C (stop) - SNDRV_PCM_TRIGGER_STOP
Best regards --- Kuninori Morimoto
Hi,
On Apr 4 2017 09:54, Kuninori Morimoto wrote:
Is this aplay issue ? or kernel issue ? ... Ctrl-Z case
- aplay xxx.wav
=> - hw_param
- SNDRV_PCM_TRIGGER_START
- Ctrl-Z
- SNDRV_PCM_TRIGGER_STOP
- fg
=> - ## no hw_param here
- SNDRV_PCM_TRIGGER_START
- Ctrl-C (stop)
- SNDRV_PCM_TRIGGER_STOP
No issues.
I think it better to implement what you want in any .prepare callbacks, instead of the .be_hw_params_fixup callback, because in this case, PCM substream lapses into XRUN state in call graph from your hw IRQ handler. Typical applications recover from this state by calling ioctl(PREPARE), without any call of ioctl(HW_PARAMS).
Actually, you can see applications call ioctl(PREPARE), before you see call of 'struct snd_pcm_ops.trigger(START)'.
Regards
Takashi Sakamoto
Hi Sakamoto-san, Mark
Thank you for your feedback
Ctrl-Z case
- aplay xxx.wav
=> - hw_param
- SNDRV_PCM_TRIGGER_START
- Ctrl-Z
- SNDRV_PCM_TRIGGER_STOP
- fg
=> - ## no hw_param here
- SNDRV_PCM_TRIGGER_START
- Ctrl-C (stop)
- SNDRV_PCM_TRIGGER_STOP
No issues.
I think it better to implement what you want in any .prepare callbacks, instead of the .be_hw_params_fixup callback, because in this case, PCM substream lapses into XRUN state in call graph from your hw IRQ handler. Typical applications recover from this state by calling ioctl(PREPARE), without any call of ioctl(HW_PARAMS).
Actually, you can see applications call ioctl(PREPARE), before you see call of 'struct snd_pcm_ops.trigger(START)'.
Hmm... Above .be_hw_params_fixup is used to convert sampling rate or channel number or some other related things between SoC / Codec as DPCM feature. Thus, I can't switch to .be_hw_params_fixup to .prepare I guess. But Mark, am I misunderstanding ?
Best regards --- Kuninori Morimoto
On Apr 4 2017 14:57, Kuninori Morimoto wrote:
Ctrl-Z case
- aplay xxx.wav
=> - hw_param
- SNDRV_PCM_TRIGGER_START
- Ctrl-Z
- SNDRV_PCM_TRIGGER_STOP
- fg
=> - ## no hw_param here
- SNDRV_PCM_TRIGGER_START
- Ctrl-C (stop)
- SNDRV_PCM_TRIGGER_STOP
No issues.
I think it better to implement what you want in any .prepare callbacks, instead of the .be_hw_params_fixup callback, because in this case, PCM substream lapses into XRUN state in call graph from your hw IRQ handler. Typical applications recover from this state by calling ioctl(PREPARE), without any call of ioctl(HW_PARAMS).
Actually, you can see applications call ioctl(PREPARE), before you see call of 'struct snd_pcm_ops.trigger(START)'.
Hmm... Above .be_hw_params_fixup is used to convert sampling rate or channel number or some other related things between SoC / Codec as DPCM feature. Thus, I can't switch to .be_hw_params_fixup to .prepare I guess. But Mark, am I misunderstanding ?
In 'struct snd_pcm_ops.prepare' callback, configured parameters of PCM substream are available via members of 'struct snd_pcm_runtime'. The runtime is a member of 'struct snd_pcm_substream'. It's available in any of .prepare callbacks in ALSA SoC part.
Regards
Takashi Sakamoto
Hi Sakamoto-san, Mark
Hmm... Above .be_hw_params_fixup is used to convert sampling rate or channel number or some other related things between SoC / Codec as DPCM feature. Thus, I can't switch to .be_hw_params_fixup to .prepare I guess. But Mark, am I misunderstanding ?
In 'struct snd_pcm_ops.prepare' callback, configured parameters of PCM substream are available via members of 'struct snd_pcm_runtime'. The runtime is a member of 'struct snd_pcm_substream'. It's available in any of .prepare callbacks in ALSA SoC part.
Thank you for detail explain. I investigated this, and I tried to use .prepare with below system.
[44.1kHz] -> CPU -> .be_hw_params_fixup[44.1kHz -> 48kHz] -> Codec
This means, CPU converts 44.1kHz to 48kHz, and Codec want to receive 48kHz as parameter. On CPU/Codec both side, these got 44.1kHz from runtime.
static int cpu/codec_prepare(struct snd_pcm_substream *substream) { /* * In 44.1kHz -> 48kHz convert case, * .be_hw_params_fixup() do convert magic. * but here .prepare, it still receive 44.1kHz */ printk("rate = %d\n", substream->runtime->rate); }
On CPU side, I could get converted parameter somehow (see below), but it has zero chance to get converted parameter on Codec side .prepare ? Converted rate is located only struct snd_pcm_hw_params in my system (= simple-scu-card). Current .be_hw_params_fixup() is saving converted rate/channel in struct snd_interval, but it should save it to struct snd_soc_pcm_runtime ?
void asoc_simple_card_convert_fixup(... struct snd_pcm_hw_params *hw_params) { struct snd_interval *rate = hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_CHANNELS); printk("------fixup\n"); if (data->convert_rate) rate->min = rate->max = data->convert_rate;
if (data->convert_channels) channels->min = channels->max = data->convert_channels; }
---- CPU could get converted rate -------------------------- static int cpu_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = substream->private_data;
/* substream->runtime->rate is still 44.1kHz here */
if (fe->dai_link->dynamic) { int stream = substream->stream; struct snd_soc_dpcm *dpcm; struct snd_pcm_hw_params *be_params;
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { be_params = &dpcm->hw_params;
/* * I could receive 48kHz here as params_rate(be_params) */ } }
return 0; }
Best regards --- Kuninori Morimoto
Hi Sakamoto-san, again
Thanks you for your help. I think I could find my issue on my system. I will post patch, soon
Hmm... Above .be_hw_params_fixup is used to convert sampling rate or channel number or some other related things between SoC / Codec as DPCM feature. Thus, I can't switch to .be_hw_params_fixup to .prepare I guess. But Mark, am I misunderstanding ?
In 'struct snd_pcm_ops.prepare' callback, configured parameters of PCM substream are available via members of 'struct snd_pcm_runtime'. The runtime is a member of 'struct snd_pcm_substream'. It's available in any of .prepare callbacks in ALSA SoC part.
Thank you for detail explain. I investigated this, and I tried to use .prepare with below system.
[44.1kHz] -> CPU -> .be_hw_params_fixup[44.1kHz -> 48kHz] -> Codec
This means, CPU converts 44.1kHz to 48kHz, and Codec want to receive 48kHz as parameter. On CPU/Codec both side, these got 44.1kHz from runtime.
static int cpu/codec_prepare(struct snd_pcm_substream *substream) { /* * In 44.1kHz -> 48kHz convert case, * .be_hw_params_fixup() do convert magic. * but here .prepare, it still receive 44.1kHz */ printk("rate = %d\n", substream->runtime->rate); }
On CPU side, I could get converted parameter somehow (see below), but it has zero chance to get converted parameter on Codec side .prepare ? Converted rate is located only struct snd_pcm_hw_params in my system (= simple-scu-card). Current .be_hw_params_fixup() is saving converted rate/channel in struct snd_interval, but it should save it to struct snd_soc_pcm_runtime ?
void asoc_simple_card_convert_fixup(... struct snd_pcm_hw_params *hw_params) { struct snd_interval *rate = hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_CHANNELS); printk("------fixup\n"); if (data->convert_rate) rate->min = rate->max = data->convert_rate;
if (data->convert_channels) channels->min = channels->max = data->convert_channels; }
---- CPU could get converted rate -------------------------- static int cpu_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *fe = substream->private_data;
/* substream->runtime->rate is still 44.1kHz here */
if (fe->dai_link->dynamic) { int stream = substream->stream; struct snd_soc_dpcm *dpcm; struct snd_pcm_hw_params *be_params;
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { be_params = &dpcm->hw_params; /* * I could receive 48kHz here as params_rate(be_params) */ }
}
return 0; }
Best regards
Kuninori Morimoto
participants (2)
-
Kuninori Morimoto
-
Takashi Sakamoto