alsa: rework buffer/period configuration

- As discussed on alsa-devel it's probably better to initialize the
  buffer size first, followed by the period size. If that fails try the
  other way round. If that fails try to configure only buffer size. If
  that fails try to configure only period size. Finally, try to
  configure neither.

- Don't require integral periods anymore.

Both of these changes should help improving compatibility with various
weirder sound devices, such as TV cards.
This commit is contained in:
Lennart Poettering 2009-09-09 04:28:52 +02:00
parent 71e066c873
commit 557c429510
4 changed files with 216 additions and 129 deletions

View file

@ -116,7 +116,6 @@ struct userdata {
pa_usec_t watermark_dec_not_before;
unsigned nfragments;
pa_memchunk memchunk;
char *device_name; /* name of the PCM device */
@ -943,8 +942,7 @@ static int unsuspend(struct userdata *u) {
pa_sample_spec ss;
int err;
pa_bool_t b, d;
unsigned nfrags;
snd_pcm_uframes_t period_size;
snd_pcm_uframes_t period_size, buffer_size;
pa_assert(u);
pa_assert(!u->pcm_handle);
@ -961,12 +959,12 @@ static int unsuspend(struct userdata *u) {
}
ss = u->sink->sample_spec;
nfrags = u->nfragments;
period_size = u->fragment_size / u->frame_size;
buffer_size = u->hwbuf_size / u->frame_size;
b = u->use_mmap;
d = u->use_tsched;
if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &nfrags, &period_size, u->hwbuf_size / u->frame_size, &b, &d, TRUE)) < 0) {
if ((err = pa_alsa_set_hw_params(u->pcm_handle, &ss, &period_size, &buffer_size, 0, &b, &d, TRUE)) < 0) {
pa_log("Failed to set hardware parameters: %s", pa_alsa_strerror(err));
goto fail;
}
@ -981,10 +979,11 @@ static int unsuspend(struct userdata *u) {
goto fail;
}
if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) {
pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)",
(unsigned long) u->nfragments, (unsigned long) u->fragment_size,
(unsigned long) nfrags, period_size * u->frame_size);
if (period_size*u->frame_size != u->fragment_size ||
buffer_size*u->frame_size != u->hwbuf_size) {
pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu/%lu, New %lu/%lu)",
(unsigned long) u->hwbuf_size, (unsigned long) u->fragment_size,
(unsigned long) (buffer_size*u->fragment_size), (unsigned long) (period_size*u->frame_size));
goto fail;
}
@ -1638,8 +1637,8 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
const char *dev_id = NULL;
pa_sample_spec ss, requested_ss;
pa_channel_map map;
uint32_t nfrags, frag_size, tsched_size, tsched_watermark;
snd_pcm_uframes_t period_frames, tsched_frames;
uint32_t nfrags, frag_size, buffer_size, tsched_size, tsched_watermark;
snd_pcm_uframes_t period_frames, buffer_frames, tsched_frames;
size_t frame_size;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;
pa_sink_new_data data;
@ -1673,7 +1672,10 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
goto fail;
}
buffer_size = nfrags * frag_size;
period_frames = frag_size/frame_size;
buffer_frames = buffer_size/frame_size;
tsched_frames = tsched_size/frame_size;
if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
@ -1740,7 +1742,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
&u->device_name,
&ss, &map,
SND_PCM_STREAM_PLAYBACK,
&nfrags, &period_frames, tsched_frames,
&period_frames, &buffer_frames, tsched_frames,
&b, &d, mapping)))
goto fail;
@ -1755,7 +1757,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
&u->device_name,
&ss, &map,
SND_PCM_STREAM_PLAYBACK,
&nfrags, &period_frames, tsched_frames,
&period_frames, &buffer_frames, tsched_frames,
&b, &d, profile_set, &mapping)))
goto fail;
@ -1767,7 +1769,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
&u->device_name,
&ss, &map,
SND_PCM_STREAM_PLAYBACK,
&nfrags, &period_frames, tsched_frames,
&period_frames, &buffer_frames, tsched_frames,
&b, &d, FALSE)))
goto fail;
}
@ -1819,7 +1821,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
pa_alsa_init_proplist_pcm(m->core, data.proplist, u->pcm_handle);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (period_frames * frame_size * nfrags));
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (buffer_frames * frame_size));
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (period_frames * frame_size));
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_ACCESS_MODE, u->use_tsched ? "mmap+timer" : (u->use_mmap ? "mmap" : "serial"));
@ -1860,13 +1862,15 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
pa_sink_set_rtpoll(u->sink, u->rtpoll);
u->frame_size = frame_size;
u->fragment_size = frag_size = (uint32_t) (period_frames * frame_size);
u->nfragments = nfrags;
u->hwbuf_size = u->fragment_size * nfrags;
u->fragment_size = frag_size = (size_t) (period_frames * frame_size);
u->hwbuf_size = buffer_size = (size_t) (buffer_frames * frame_size);
pa_cvolume_mute(&u->hardware_volume, u->sink->sample_spec.channels);
pa_log_info("Using %u fragments of size %lu bytes, buffer time is %0.2fms",
nfrags, (long unsigned) u->fragment_size,
pa_log_info("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)",
(double) u->hwbuf_size / (double) u->fragment_size,
(long unsigned) u->fragment_size,
(double) pa_bytes_to_usec(u->fragment_size, &ss) / PA_USEC_PER_MSEC,
(long unsigned) u->hwbuf_size,
(double) pa_bytes_to_usec(u->hwbuf_size, &ss) / PA_USEC_PER_MSEC);
pa_sink_set_max_request(u->sink, u->hwbuf_size);