[alsa] Set quality in device_open() (possible fix for issue #720)

This commit is contained in:
ejurgensen 2019-04-12 19:40:33 +02:00
parent 4dcbb2f24f
commit c7b8b94163
1 changed files with 50 additions and 20 deletions

View File

@ -158,6 +158,19 @@ dump_config(struct alsa_session *as)
} }
} }
static snd_pcm_format_t
bps2format(int bits_per_sample)
{
if (bits_per_sample == 16)
return SND_PCM_FORMAT_S16_LE;
else if (bits_per_sample == 24)
return SND_PCM_FORMAT_S24_LE;
else if (bits_per_sample == 32)
return SND_PCM_FORMAT_S32_LE;
else
return SND_PCM_FORMAT_UNKNOWN;
}
static int static int
mixer_open(struct alsa_session *as) mixer_open(struct alsa_session *as)
{ {
@ -293,6 +306,31 @@ device_open(struct alsa_session *as)
goto out_fail; goto out_fail;
} }
// Some devices (like the allo Boss DAC on RPi) fail to open w/o quality set
ret = snd_pcm_hw_params_set_format(as->hdl, hw_params, bps2format(alsa_fallback_quality.bits_per_sample));
if (ret < 0)
{
DPRINTF(E_LOG, L_LAUDIO, "Could not set format (bits per sample %d): %s\n", alsa_fallback_quality.bits_per_sample, snd_strerror(ret));
goto out_fail;
}
ret = snd_pcm_hw_params_set_channels(as->hdl, hw_params, alsa_fallback_quality.channels);
if (ret < 0)
{
DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo output: %s\n", snd_strerror(ret));
goto out_fail;
}
ret = snd_pcm_hw_params_set_rate(as->hdl, hw_params, alsa_fallback_quality.sample_rate, 0);
if (ret < 0)
{
DPRINTF(E_LOG, L_LAUDIO, "Hardware doesn't support %u Hz: %s\n", alsa_fallback_quality.sample_rate, snd_strerror(ret));
goto out_fail;
}
ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize); ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize);
if (ret < 0) if (ret < 0)
{ {
@ -310,7 +348,7 @@ device_open(struct alsa_session *as)
ret = snd_pcm_hw_params(as->hdl, hw_params); ret = snd_pcm_hw_params(as->hdl, hw_params);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params: %s\n", snd_strerror(ret)); DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params in device_open(): %s\n", snd_strerror(ret));
goto out_fail; goto out_fail;
} }
@ -340,7 +378,6 @@ static int
device_quality_set(struct alsa_session *as, struct media_quality *quality, char **errmsg) device_quality_set(struct alsa_session *as, struct media_quality *quality, char **errmsg)
{ {
snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_t *hw_params;
snd_pcm_format_t format;
int ret; int ret;
ret = snd_pcm_hw_params_malloc(&hw_params); ret = snd_pcm_hw_params_malloc(&hw_params);
@ -357,6 +394,15 @@ device_quality_set(struct alsa_session *as, struct media_quality *quality, char
goto free_params; goto free_params;
} }
// Some devices, e.g. the RPi1, require this to be set again, even though it
// is also set by device_open()
ret = snd_pcm_hw_params_set_access(as->hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (ret < 0)
{
*errmsg = safe_asprintf("Could not set access method: %s\n", snd_strerror(ret));
goto free_params;
}
ret = snd_pcm_hw_params_set_rate(as->hdl, hw_params, quality->sample_rate, 0); ret = snd_pcm_hw_params_set_rate(as->hdl, hw_params, quality->sample_rate, 0);
if (ret < 0) if (ret < 0)
{ {
@ -364,23 +410,7 @@ device_quality_set(struct alsa_session *as, struct media_quality *quality, char
goto free_params; goto free_params;
} }
switch (quality->bits_per_sample) ret = snd_pcm_hw_params_set_format(as->hdl, hw_params, bps2format(quality->bits_per_sample));
{
case 16:
format = SND_PCM_FORMAT_S16_LE;
break;
case 24:
format = SND_PCM_FORMAT_S24_LE;
break;
case 32:
format = SND_PCM_FORMAT_S32_LE;
break;
default:
*errmsg = safe_asprintf("Unrecognized number of bits per sample: %d", quality->bits_per_sample);
goto free_params;
}
ret = snd_pcm_hw_params_set_format(as->hdl, hw_params, format);
if (ret < 0) if (ret < 0)
{ {
*errmsg = safe_asprintf("Could not set %d bits per sample: %s", quality->bits_per_sample, snd_strerror(ret)); *errmsg = safe_asprintf("Could not set %d bits per sample: %s", quality->bits_per_sample, snd_strerror(ret));
@ -397,7 +427,7 @@ device_quality_set(struct alsa_session *as, struct media_quality *quality, char
ret = snd_pcm_hw_params(as->hdl, hw_params); ret = snd_pcm_hw_params(as->hdl, hw_params);
if (ret < 0) if (ret < 0)
{ {
*errmsg = safe_asprintf("Could not set hw params: %s\n", snd_strerror(ret)); *errmsg = safe_asprintf("Could not set hw params in device_quality_set(): %s\n", snd_strerror(ret));
goto free_params; goto free_params;
} }