pcm: linear, route: handle linear formats with 20-bit sample on 4 bytes

The previous patch has added 20-bit PCM formats SND_PCM_FORMAT_{S,U}20 to
alsa-lib.
We need to extend the linear format conversion code with handling of these
sample formats so they can also be utilized by applications that only
recognize the more typical ones like SND_PCM_FORMAT_S16.

Since the conversion arrays are indexed by a format bit width divided by 8
the easiest way to handle these formats is to treat them like they were
40-bit wide (the next free integer multiple of 8 bits).
This doesn't create a collision risk with a future format since there can't
really be a 40-bit sample format that occupies 4 bytes.

Make sure we use the getput conversion method for these formats since a
direct conversion from / to them is not supported.

Signed-off-by: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Maciej S. Szmigiero 2017-12-14 14:53:41 +01:00 committed by Takashi Iwai
parent d67e42c139
commit 0c081ebbed
3 changed files with 61 additions and 9 deletions

View file

@ -100,8 +100,11 @@ int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
default:
width = 2; break;
}
return width * 4 + endian * 2 + sign + 16;
return width * 4 + endian * 2 + sign + 20;
} else {
if (width == 20)
width = 40;
width = width / 8 - 1;
return width * 4 + endian * 2 + sign;
}
@ -131,8 +134,11 @@ int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f
default:
width = 2; break;
}
return width * 4 + endian * 2 + sign + 16;
return width * 4 + endian * 2 + sign + 20;
} else {
if (width == 20)
width = 40;
width = width / 8 - 1;
return width * 4 + endian * 2 + sign;
}
@ -303,7 +309,9 @@ static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
if (err < 0)
return err;
linear->use_getput = (snd_pcm_format_physical_width(format) == 24 ||
snd_pcm_format_physical_width(linear->sformat) == 24);
snd_pcm_format_physical_width(linear->sformat) == 24 ||
snd_pcm_format_width(format) == 20 ||
snd_pcm_format_width(linear->sformat) == 20);
if (linear->use_getput) {
if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
linear->get_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S32);