ref: f5966723abea540e52bc8916576f0fdf045ba100
parent: 0a926392573fd4fad513e53cb330f8aa9e3cf4a9
author: rrt <rrt>
date: Thu Jan 25 14:22:27 EST 2007
Move get_format to the top for clarity. Always try to output 16-bit sound, for better quality. Use a bigger buffer to avoid underruns. Shorten rate limiting calculation.
--- a/src/alsa.c
+++ b/src/alsa.c
@@ -20,8 +20,158 @@
st_size_t buf_size;
} *alsa_priv_t;
-static int get_format(ft_t ft, snd_pcm_format_mask_t *fmask, int *fmt);
+static int get_format(ft_t ft, snd_pcm_format_mask_t *fmask, int *fmt)
+{
+ if (ft->signal.size == -1)
+ ft->signal.size = ST_SIZE_16BIT;
+ if (ft->signal.size != ST_SIZE_16BIT)
+ {
+ st_report("trying for word samples.");
+ ft->signal.size = ST_SIZE_16BIT;
+ }
+
+ if (ft->signal.encoding != ST_ENCODING_SIGN2 &&
+ ft->signal.encoding != ST_ENCODING_UNSIGNED)
+ {
+ if (ft->signal.size == ST_SIZE_16BIT)
+ {
+ st_report("driver only supports signed and unsigned samples. Changing to signed.");
+ ft->signal.encoding = ST_ENCODING_SIGN2;
+ }
+ else
+ {
+ st_report("driver only supports signed and unsigned samples. Changing to unsigned.");
+ ft->signal.encoding = ST_ENCODING_UNSIGNED;
+ }
+ }
+
+ /* Some hardware only wants to work with 8-bit or 16-bit data */
+ if (ft->signal.size == ST_SIZE_BYTE)
+ {
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)) &&
+ !(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
+ {
+ st_report("driver doesn't supported byte samples. Changing to words.");
+ ft->signal.size = ST_SIZE_16BIT;
+ }
+ }
+ else if (ft->signal.size == ST_SIZE_16BIT)
+ {
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)) &&
+ !(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
+ {
+ st_report("driver doesn't supported word samples. Changing to bytes.");
+ ft->signal.size = ST_SIZE_BYTE;
+ }
+ }
+ else
+ {
+ if ((snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)) ||
+ (snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
+ {
+ st_report("driver doesn't supported %s samples. Changing to words.", st_sizes_str[(unsigned char)ft->signal.size]);
+ ft->signal.size = ST_SIZE_16BIT;
+ }
+ else
+ {
+ st_report("driver doesn't supported %s samples. Changing to bytes.", st_sizes_str[(unsigned char)ft->signal.size]);
+ ft->signal.size = ST_SIZE_BYTE;
+ }
+ }
+
+ if (ft->signal.size == ST_SIZE_BYTE) {
+ switch (ft->signal.encoding)
+ {
+ case ST_ENCODING_SIGN2:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
+ {
+ st_report("driver doesn't supported signed byte samples. Changing to unsigned bytes.");
+ ft->signal.encoding = ST_ENCODING_UNSIGNED;
+ }
+ break;
+ case ST_ENCODING_UNSIGNED:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)))
+ {
+ st_report("driver doesn't supported unsigned byte samples. Changing to signed bytes.");
+ ft->signal.encoding = ST_ENCODING_SIGN2;
+ }
+ break;
+ default:
+ break;
+ }
+ switch (ft->signal.encoding)
+ {
+ case ST_ENCODING_SIGN2:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
+ {
+ st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed byte samples");
+ return ST_EOF;
+ }
+ *fmt = SND_PCM_FORMAT_S8;
+ break;
+ case ST_ENCODING_UNSIGNED:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)))
+ {
+ st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned byte samples");
+ return ST_EOF;
+ }
+ *fmt = SND_PCM_FORMAT_U8;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (ft->signal.size == ST_SIZE_16BIT) {
+ switch (ft->signal.encoding)
+ {
+ case ST_ENCODING_SIGN2:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
+ {
+ st_report("driver does not support signed word samples. Changing to unsigned words.");
+ ft->signal.encoding = ST_ENCODING_UNSIGNED;
+ }
+ break;
+ case ST_ENCODING_UNSIGNED:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)))
+ {
+ st_report("driver does not support unsigned word samples. Changing to signed words.");
+ ft->signal.encoding = ST_ENCODING_SIGN2;
+ }
+ break;
+ default:
+ break;
+ }
+ switch (ft->signal.encoding)
+ {
+ case ST_ENCODING_SIGN2:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
+ {
+ st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed word samples");
+ return ST_EOF;
+ }
+ *fmt = SND_PCM_FORMAT_S16_LE;
+ break;
+ case ST_ENCODING_UNSIGNED:
+ if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)))
+ {
+ st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned word samples");
+ return ST_EOF;
+ }
+ *fmt = SND_PCM_FORMAT_U16_LE;
+ break;
+ default:
+ break;
+ }
+ }
+ else {
+ st_fail_errno(ft,ST_EFMT,"ALSA driver does not support %s %s output",
+ st_encodings_str[(unsigned char)ft->signal.encoding], st_sizes_str[(unsigned char)ft->signal.size]);
+ return ST_EOF;
+ }
+ return 0;
+}
+
static int st_alsasetup(ft_t ft, snd_pcm_stream_t mode)
{
int fmt = SND_PCM_FORMAT_S16;
@@ -59,9 +209,7 @@
#if SND_LIB_VERSION >= 0x010009
/* Turn off software resampling */
- rate = 0;
- err = snd_pcm_hw_params_set_rate_resample(alsa->pcm_handle, hw_params,
- rate);
+ err = snd_pcm_hw_params_set_rate_resample(alsa->pcm_handle, hw_params, 0);
if (err < 0) {
st_fail_errno(ft, ST_EPERM, "Resampling setup failed for playback");
goto open_error;
@@ -103,12 +251,10 @@
goto open_error;
}
- rate = ft->signal.rate;
snd_pcm_hw_params_get_rate_min(hw_params, &min_rate, &dir);
snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, &dir);
- rate = max(rate, min_rate);
- rate = min(rate, max_rate);
+ rate = min(max(ft->signal.rate, min_rate), max_rate);
if (rate != ft->signal.rate)
{
st_report("hardware does not support sample-rate %i; changing to %i.", ft->signal.rate, rate);
@@ -143,7 +289,8 @@
goto open_error;
}
- buffer_size = (ST_BUFSIZ / ft->signal.size / ft->signal.channels);
+ /* Have a much larger buffer than ST_BUFSIZ to avoid underruns */
+ buffer_size = ST_BUFSIZ * 8 / ft->signal.size / ft->signal.channels;
if (snd_pcm_hw_params_get_buffer_size_min(hw_params, &buffer_size_min) < 0)
{
@@ -512,167 +659,6 @@
free(alsa->buf);
return ST_SUCCESS;
-}
-
-static int get_format(ft_t ft, snd_pcm_format_mask_t *fmask, int *fmt)
-{
- if (ft->signal.size == -1)
- ft->signal.size = ST_SIZE_16BIT;
-
- if (ft->signal.encoding == ST_ENCODING_UNKNOWN)
- {
- if (ft->signal.size == ST_SIZE_16BIT)
- ft->signal.encoding = ST_ENCODING_SIGN2;
- else
- ft->signal.encoding = ST_ENCODING_UNSIGNED;
- }
-
- if (ft->signal.size != ST_SIZE_16BIT &&
- ft->signal.size != ST_SIZE_BYTE)
- {
- st_report("driver only supports byte and word samples. Changing to word.");
- ft->signal.size = ST_SIZE_16BIT;
- }
-
- if (ft->signal.encoding != ST_ENCODING_SIGN2 &&
- ft->signal.encoding != ST_ENCODING_UNSIGNED)
- {
- if (ft->signal.size == ST_SIZE_16BIT)
- {
- st_report("driver only supports signed and unsigned samples. Changing to signed.");
- ft->signal.encoding = ST_ENCODING_SIGN2;
- }
- else
- {
- st_report("driver only supports signed and unsigned samples. Changing to unsigned.");
- ft->signal.encoding = ST_ENCODING_UNSIGNED;
- }
- }
-
- /* Some hardware only wants to work with 8-bit or 16-bit data */
- if (ft->signal.size == ST_SIZE_BYTE)
- {
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)) &&
- !(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
- {
- st_report("driver doesn't supported byte samples. Changing to words.");
- ft->signal.size = ST_SIZE_16BIT;
- }
- }
- else if (ft->signal.size == ST_SIZE_16BIT)
- {
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)) &&
- !(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
- {
- st_report("driver doesn't supported word samples. Changing to bytes.");
- ft->signal.size = ST_SIZE_BYTE;
- }
- }
- else
- {
- if ((snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)) ||
- (snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
- {
- st_report("driver doesn't supported %s samples. Changing to words.", st_sizes_str[(unsigned char)ft->signal.size]);
- ft->signal.size = ST_SIZE_16BIT;
- }
- else
- {
- st_report("driver doesn't supported %s samples. Changing to bytes.", st_sizes_str[(unsigned char)ft->signal.size]);
- ft->signal.size = ST_SIZE_BYTE;
- }
- }
-
- if (ft->signal.size == ST_SIZE_BYTE) {
- switch (ft->signal.encoding)
- {
- case ST_ENCODING_SIGN2:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
- {
- st_report("driver doesn't supported signed byte samples. Changing to unsigned bytes.");
- ft->signal.encoding = ST_ENCODING_UNSIGNED;
- }
- break;
- case ST_ENCODING_UNSIGNED:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)))
- {
- st_report("driver doesn't supported unsigned byte samples. Changing to signed bytes.");
- ft->signal.encoding = ST_ENCODING_SIGN2;
- }
- break;
- default:
- break;
- }
- switch (ft->signal.encoding)
- {
- case ST_ENCODING_SIGN2:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S8)))
- {
- st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed byte samples");
- return ST_EOF;
- }
- *fmt = SND_PCM_FORMAT_S8;
- break;
- case ST_ENCODING_UNSIGNED:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U8)))
- {
- st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned byte samples");
- return ST_EOF;
- }
- *fmt = SND_PCM_FORMAT_U8;
- break;
- default:
- break;
- }
- }
- else if (ft->signal.size == ST_SIZE_16BIT) {
- switch (ft->signal.encoding)
- {
- case ST_ENCODING_SIGN2:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
- {
- st_report("driver does not support signed word samples. Changing to unsigned words.");
- ft->signal.encoding = ST_ENCODING_UNSIGNED;
- }
- break;
- case ST_ENCODING_UNSIGNED:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)))
- {
- st_report("driver does not support unsigned word samples. Changing to signed words.");
- ft->signal.encoding = ST_ENCODING_SIGN2;
- }
- break;
- default:
- break;
- }
- switch (ft->signal.encoding)
- {
- case ST_ENCODING_SIGN2:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_S16)))
- {
- st_fail_errno(ft,ST_EFMT,"ALSA driver does not support signed word samples");
- return ST_EOF;
- }
- *fmt = SND_PCM_FORMAT_S16_LE;
- break;
- case ST_ENCODING_UNSIGNED:
- if (!(snd_pcm_format_mask_test(fmask, SND_PCM_FORMAT_U16)))
- {
- st_fail_errno(ft,ST_EFMT,"ALSA driver does not support unsigned word samples");
- return ST_EOF;
- }
- *fmt = SND_PCM_FORMAT_U16_LE;
- break;
- default:
- break;
- }
- }
- else {
- st_fail_errno(ft,ST_EFMT,"ALSA driver does not support %s %s output",
- st_encodings_str[(unsigned char)ft->signal.encoding], st_sizes_str[(unsigned char)ft->signal.size]);
- return ST_EOF;
- }
- return 0;
}
static const char *alsanames[] = {