diff mbox series

[v0] ASoC: rsnd: core: Check convert rate in rsnd_hw_params

Message ID 1615870055-13954-1-git-send-email-mikhail_durnev@mentor.com (mailing list archive)
State Accepted
Commit 19c6a63ced5e07e40f3a5255cb1f0fe0d3be7b14
Headers show
Series [v0] ASoC: rsnd: core: Check convert rate in rsnd_hw_params | expand

Commit Message

mdurnev@gmail.com March 16, 2021, 4:47 a.m. UTC
From: Mikhail Durnev <mikhail_durnev@mentor.com>

snd_pcm_hw_params_set_rate_near can return incorrect sample rate in
some cases, e.g. when the backend output rate is set to some value higher
than 48000 Hz and the input rate is 8000 Hz. So passing the value returned
by snd_pcm_hw_params_set_rate_near to snd_pcm_hw_params will result in
"FSO/FSI ratio error" and playing no audio at all while the userland
is not properly notified about the issue.

If SRC is unable to convert the requested sample rate to the sample rate
the backend is using, then the requested sample rate should be adjusted in
rsnd_hw_params. The userland will be notified about that change in the
returned hw_params structure.

Signed-off-by: Mikhail Durnev <mikhail_durnev@mentor.com>
---
 sound/soc/sh/rcar/core.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

Comments

Kuninori Morimoto March 16, 2021, 5:09 a.m. UTC | #1
Hi Mikhail

> From: Mikhail Durnev <mikhail_durnev@mentor.com>
> 
> snd_pcm_hw_params_set_rate_near can return incorrect sample rate in
> some cases, e.g. when the backend output rate is set to some value higher
> than 48000 Hz and the input rate is 8000 Hz. So passing the value returned
> by snd_pcm_hw_params_set_rate_near to snd_pcm_hw_params will result in
> "FSO/FSI ratio error" and playing no audio at all while the userland
> is not properly notified about the issue.
> 
> If SRC is unable to convert the requested sample rate to the sample rate
> the backend is using, then the requested sample rate should be adjusted in
> rsnd_hw_params. The userland will be notified about that change in the
> returned hw_params structure.
> 
> Signed-off-by: Mikhail Durnev <mikhail_durnev@mentor.com>

Thank you for your patch.
Indeed it needs this kind of filter.
Maybe we need to care more in the future, but it is enough so far I think.

	Acked-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

Thank you for your help !!

Best regards
---
Kuninori Morimoto
Mark Brown March 16, 2021, 5:59 p.m. UTC | #2
On Tue, 16 Mar 2021 14:47:35 +1000, mdurnev@gmail.com wrote:
> snd_pcm_hw_params_set_rate_near can return incorrect sample rate in
> some cases, e.g. when the backend output rate is set to some value higher
> than 48000 Hz and the input rate is 8000 Hz. So passing the value returned
> by snd_pcm_hw_params_set_rate_near to snd_pcm_hw_params will result in
> "FSO/FSI ratio error" and playing no audio at all while the userland
> is not properly notified about the issue.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[1/1] ASoC: rsnd: core: Check convert rate in rsnd_hw_params
      commit: 19c6a63ced5e07e40f3a5255cb1f0fe0d3be7b14

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark
diff mbox series

Patch

diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index d1612d3..8696a99 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1424,8 +1424,75 @@  static int rsnd_hw_params(struct snd_soc_component *component,
 		}
 		if (io->converted_chan)
 			dev_dbg(dev, "convert channels = %d\n", io->converted_chan);
-		if (io->converted_rate)
+		if (io->converted_rate) {
+			/*
+			 * SRC supports convert rates from params_rate(hw_params)/k_down
+			 * to params_rate(hw_params)*k_up, where k_up is always 6, and
+			 * k_down depends on number of channels and SRC unit.
+			 * So all SRC units can upsample audio up to 6 times regardless
+			 * its number of channels. And all SRC units can downsample
+			 * 2 channel audio up to 6 times too.
+			 */
+			int k_up = 6;
+			int k_down = 6;
+			int channel;
+			struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
+
 			dev_dbg(dev, "convert rate     = %d\n", io->converted_rate);
+
+			channel = io->converted_chan ? io->converted_chan :
+				  params_channels(hw_params);
+
+			switch (rsnd_mod_id(src_mod)) {
+			/*
+			 * SRC0 can downsample 4, 6 and 8 channel audio up to 4 times.
+			 * SRC1, SRC3 and SRC4 can downsample 4 channel audio
+			 * up to 4 times.
+			 * SRC1, SRC3 and SRC4 can downsample 6 and 8 channel audio
+			 * no more than twice.
+			 */
+			case 1:
+			case 3:
+			case 4:
+				if (channel > 4) {
+					k_down = 2;
+					break;
+				}
+				fallthrough;
+			case 0:
+				if (channel > 2)
+					k_down = 4;
+				break;
+
+			/* Other SRC units do not support more than 2 channels */
+			default:
+				if (channel > 2)
+					return -EINVAL;
+			}
+
+			if (params_rate(hw_params) > io->converted_rate * k_down) {
+				hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
+					io->converted_rate * k_down;
+				hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
+					io->converted_rate * k_down;
+				hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
+			} else if (params_rate(hw_params) * k_up < io->converted_rate) {
+				hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->min =
+					(io->converted_rate + k_up - 1) / k_up;
+				hw_param_interval(hw_params, SNDRV_PCM_HW_PARAM_RATE)->max =
+					(io->converted_rate + k_up - 1) / k_up;
+				hw_params->cmask |= SNDRV_PCM_HW_PARAM_RATE;
+			}
+
+			/*
+			 * TBD: Max SRC input and output rates also depend on number
+			 * of channels and SRC unit:
+			 * SRC1, SRC3 and SRC4 do not support more than 128kHz
+			 * for 6 channel and 96kHz for 8 channel audio.
+			 * Perhaps this function should return EINVAL if the input or
+			 * the output rate exceeds the limitation.
+			 */
+		}
 	}
 
 	return rsnd_dai_call(hw_params, io, substream, hw_params);