]> code.delx.au - pulseaudio/commitdiff
alsa: rework buffer/period configuration
authorLennart Poettering <lennart@poettering.net>
Wed, 9 Sep 2009 02:28:52 +0000 (04:28 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 9 Sep 2009 02:28:52 +0000 (04:28 +0200)
- 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.

src/modules/alsa/alsa-sink.c
src/modules/alsa/alsa-source.c
src/modules/alsa/alsa-util.c
src/modules/alsa/alsa-util.h

index 883b32a7a2c2c4c9201a3b9a9ae47cf19ea55c4d..c4ff10de2153caa2cda1028aba9052f8b8534204 100644 (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);
index 64f89806175681a9911fb9899b1c140572d74653..5f89d88c4ba6d3cc4e93cb542adc5923324ebeaa 100644 (file)
@@ -111,8 +111,6 @@ struct userdata {
 
     pa_usec_t watermark_dec_not_before;
 
-    unsigned nfragments;
-
     char *device_name;
     char *control_device;
 
@@ -891,8 +889,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);
@@ -909,12 +906,12 @@ static int unsuspend(struct userdata *u) {
     }
 
     ss = u->source->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;
     }
@@ -929,10 +926,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;
     }
 
@@ -1483,8 +1481,8 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     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_source_new_data data;
@@ -1518,7 +1516,10 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
         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) {
@@ -1584,7 +1585,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
                       &u->device_name,
                       &ss, &map,
                       SND_PCM_STREAM_CAPTURE,
-                      &nfrags, &period_frames, tsched_frames,
+                      &period_frames, &buffer_frames, tsched_frames,
                       &b, &d, mapping)))
             goto fail;
 
@@ -1598,7 +1599,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
                       &u->device_name,
                       &ss, &map,
                       SND_PCM_STREAM_CAPTURE,
-                      &nfrags, &period_frames, tsched_frames,
+                      &period_frames, &buffer_frames, tsched_frames,
                       &b, &d, profile_set, &mapping)))
             goto fail;
 
@@ -1609,7 +1610,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
                       &u->device_name,
                       &ss, &map,
                       SND_PCM_STREAM_CAPTURE,
-                      &nfrags, &period_frames, tsched_frames,
+                      &period_frames, &buffer_frames, tsched_frames,
                       &b, &d, FALSE)))
             goto fail;
     }
@@ -1661,7 +1662,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 
     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"));
 
@@ -1702,13 +1703,15 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     pa_source_set_rtpoll(u->source, 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->source->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);
 
     if (u->use_tsched) {
index 4d75c63c36ecc6646faf648005518c7074aec49b..91474527fd45a39849cda44c662c36042a338589 100644 (file)
@@ -93,6 +93,7 @@ static int set_format(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, pa_s
     int ret;
 
     pa_assert(pcm_handle);
+    pa_assert(hwparams);
     pa_assert(f);
 
     if ((ret = snd_pcm_hw_params_set_format(pcm_handle, hwparams, format_trans[*f])) >= 0)
@@ -148,33 +149,71 @@ try_auto:
     return -1;
 }
 
+static int set_period_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
+    snd_pcm_uframes_t s;
+    int d, ret;
+
+    pa_assert(pcm_handle);
+    pa_assert(hwparams);
+
+    s = size;
+    d = 0;
+    if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
+        s = size;
+        d = -1;
+        if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d) < 0) {
+            s = size;
+            d = 1;
+            if ((ret = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &s, &d)) < 0) {
+                pa_log_info("snd_pcm_hw_params_set_period_size_near() failed: %s", pa_alsa_strerror(ret));
+                return ret;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int set_buffer_size(snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hwparams, snd_pcm_uframes_t size) {
+    int ret;
+
+    pa_assert(pcm_handle);
+    pa_assert(hwparams);
+
+    if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &size)) < 0) {
+        pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
+        return ret;
+    }
+
+    return 0;
+}
+
 /* Set the hardware parameters of the given ALSA device. Returns the
  * selected fragment settings in *period and *period_size */
 int pa_alsa_set_hw_params(
         snd_pcm_t *pcm_handle,
         pa_sample_spec *ss,
-        uint32_t *periods,
         snd_pcm_uframes_t *period_size,
+        snd_pcm_uframes_t *buffer_size,
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,
         pa_bool_t *use_tsched,
         pa_bool_t require_exact_channel_number) {
 
     int ret = -1;
+    snd_pcm_hw_params_t *hwparams, *hwparams_copy;
+    int dir;
     snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
-    unsigned int _periods = periods ? *periods : 0;
-    unsigned int r = ss->rate;
-    unsigned int c = ss->channels;
-    pa_sample_format_t f = ss->format;
-    snd_pcm_hw_params_t *hwparams;
+    snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
     pa_bool_t _use_mmap = use_mmap && *use_mmap;
     pa_bool_t _use_tsched = use_tsched && *use_tsched;
-    int dir;
+    pa_sample_spec _ss = *ss;
 
     pa_assert(pcm_handle);
     pa_assert(ss);
 
     snd_pcm_hw_params_alloca(&hwparams);
+    snd_pcm_hw_params_alloca(&hwparams_copy);
 
     if ((ret = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
         pa_log_debug("snd_pcm_hw_params_any() failed: %s", pa_alsa_strerror(ret));
@@ -208,114 +247,140 @@ int pa_alsa_set_hw_params(
     if (!_use_mmap)
         _use_tsched = FALSE;
 
-    if ((ret = set_format(pcm_handle, hwparams, &f)) < 0)
+    if ((ret = set_format(pcm_handle, hwparams, &_ss.format)) < 0)
         goto finish;
 
-    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &r, NULL)) < 0) {
+    if ((ret = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &_ss.rate, NULL)) < 0) {
         pa_log_debug("snd_pcm_hw_params_set_rate_near() failed: %s", pa_alsa_strerror(ret));
         goto finish;
     }
 
     if (require_exact_channel_number) {
-        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, c)) < 0) {
-            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", c, pa_alsa_strerror(ret));
+        if ((ret = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, _ss.channels)) < 0) {
+            pa_log_debug("snd_pcm_hw_params_set_channels(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
             goto finish;
         }
     } else {
+        unsigned int c = _ss.channels;
+
         if ((ret = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) {
-            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", c, pa_alsa_strerror(ret));
+            pa_log_debug("snd_pcm_hw_params_set_channels_near(%u) failed: %s", _ss.channels, pa_alsa_strerror(ret));
             goto finish;
         }
-    }
 
-    if ((ret = snd_pcm_hw_params_set_periods_integer(pcm_handle, hwparams)) < 0) {
-        pa_log_debug("snd_pcm_hw_params_set_periods_integer() failed: %s", pa_alsa_strerror(ret));
-        goto finish;
+        _ss.channels = c;
     }
 
-    if (_period_size > 0 && tsched_size > 0 && _periods > 0) {
-        snd_pcm_uframes_t buffer_size;
-        unsigned int p;
+    if (_use_tsched && tsched_size > 0) {
+        _buffer_size = pa_convert_size(tsched_size, ss, &_ss);
+        _period_size = _buffer_size;
+    } else {
+        _period_size = pa_convert_size(_period_size, ss, &_ss);
+        _buffer_size = pa_convert_size(_buffer_size, ss, &_ss);
+    }
 
-        /* Adjust the buffer sizes, if we didn't get the rate we were asking for */
-        _period_size = (snd_pcm_uframes_t) (((uint64_t) _period_size * r) / ss->rate);
-        tsched_size = (snd_pcm_uframes_t) (((uint64_t) tsched_size * r) / ss->rate);
+    if (_buffer_size > 0 || _period_size > 0) {
+        snd_pcm_uframes_t max_frames = 0;
 
-        if (_use_tsched) {
-            buffer_size = 0;
+        if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &max_frames)) < 0)
+            pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
+        else
+            pa_log_debug("Maximum hw buffer size is %lu ms", (long unsigned) max_frames * PA_MSEC_PER_SEC / _ss.rate);
 
-            if ((ret = snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size)) < 0)
-                pa_log_warn("snd_pcm_hw_params_get_buffer_size_max() failed: %s", pa_alsa_strerror(ret));
-            else
-                pa_log_debug("Maximum hw buffer size is %u ms", (unsigned) buffer_size * 1000 / r);
+        /* Some ALSA drivers really don't like if we set the buffer
+         * size first and the number of periods second. (which would
+         * make a lot more sense to me) So, try a few combinations
+         * before we give up. */
+
+        if (_buffer_size > 0 && _period_size > 0) {
+            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
+
+            /* First try: set buffer size first, followed by period size */
+            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
+                set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
+                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
+                pa_log_debug("Set buffer size first, period size second.");
+                goto success;
+            }
 
-            _period_size = tsched_size;
-            _periods = 1;
+            /* Second try: set period size first, followed by buffer size */
+            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
+                set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
+                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
+                pa_log_debug("Set period size first, buffer size second.");
+                goto success;
+            }
         }
 
-        /* Some ALSA drivers really don't like if we set the buffer
-         * size first and the number of periods second. (which would
-         * make a lot more sense to me) So, follow this rule and
-         * adjust the periods first and the buffer size second */
-
-        /* First we pass 0 as direction to get exactly what we
-         * asked for. That this is necessary is presumably a bug
-         * in ALSA. All in all this is mostly a hint to ALSA, so
-         * we don't care if this fails. */
-
-        p = _periods;
-        dir = 0;
-        if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) {
-            p = _periods;
-            dir = 1;
-            if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir) < 0) {
-                p = _periods;
-                dir = -1;
-                if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &p, &dir)) < 0)
-                    pa_log_info("snd_pcm_hw_params_set_periods_near() failed: %s", pa_alsa_strerror(ret));
+        if (_buffer_size > 0) {
+            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
+
+            /* Third try: set only buffer size */
+            if (set_buffer_size(pcm_handle, hwparams_copy, _buffer_size) >= 0 &&
+                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
+                pa_log_debug("Set only buffer size second.");
+                goto success;
             }
         }
 
-        /* Now set the buffer size */
-        buffer_size = _periods * _period_size;
-        if ((ret = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size)) < 0)
-            pa_log_info("snd_pcm_hw_params_set_buffer_size_near() failed: %s", pa_alsa_strerror(ret));
+        if (_period_size > 0) {
+            snd_pcm_hw_params_copy(hwparams_copy, hwparams);
+
+            /* Fourth try: set only period size */
+            if (set_period_size(pcm_handle, hwparams_copy, _period_size) >= 0 &&
+                snd_pcm_hw_params(pcm_handle, hwparams_copy) >= 0) {
+                pa_log_debug("Set only period size second.");
+                goto success;
+            }
+        }
     }
 
-    if  ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
+    pa_log_debug("Set neither period nor buffer size.");
+
+    /* Last chance, set nothing */
+    if  ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
+        pa_log_info("snd_pcm_hw_params failed: %s", pa_alsa_strerror(ret));
         goto finish;
+    }
+
+success:
 
-    if (ss->rate != r)
-        pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, r);
+    if (ss->rate != _ss.rate)
+        pa_log_info("Device %s doesn't support %u Hz, changed to %u Hz.", snd_pcm_name(pcm_handle), ss->rate, _ss.rate);
 
-    if (ss->channels != c)
-        pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, c);
+    if (ss->channels != _ss.channels)
+        pa_log_info("Device %s doesn't support %u channels, changed to %u.", snd_pcm_name(pcm_handle), ss->channels, _ss.channels);
 
-    if (ss->format != f)
-        pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(f));
+    if (ss->format != _ss.format)
+        pa_log_info("Device %s doesn't support sample format %s, changed to %s.", snd_pcm_name(pcm_handle), pa_sample_format_to_string(ss->format), pa_sample_format_to_string(_ss.format));
 
     if ((ret = snd_pcm_prepare(pcm_handle)) < 0) {
         pa_log_info("snd_pcm_prepare() failed: %s", pa_alsa_strerror(ret));
         goto finish;
     }
 
+    if ((ret = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
+        pa_log_info("snd_pcm_hw_params_current() failed: %s", pa_alsa_strerror(ret));
+        goto finish;
+    }
+
     if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
-        (ret = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0) {
-        pa_log_info("snd_pcm_hw_params_get_period{s|_size}() failed: %s", pa_alsa_strerror(ret));
+        (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
+        pa_log_info("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", pa_alsa_strerror(ret));
         goto finish;
     }
 
     /* If the sample rate deviates too much, we need to resample */
-    if (r < ss->rate*.95 || r > ss->rate*1.05)
-        ss->rate = r;
-    ss->channels = (uint8_t) c;
-    ss->format = f;
+    if (_ss.rate < ss->rate*.95 || _ss.rate > ss->rate*1.05)
+        ss->rate = _ss.rate;
+    ss->channels = _ss.channels;
+    ss->format = _ss.format;
 
-    pa_assert(_periods > 0);
     pa_assert(_period_size > 0);
+    pa_assert(_buffer_size > 0);
 
-    if (periods)
-        *periods = _periods;
+    if (buffer_size)
+        *buffer_size = _buffer_size;
 
     if (period_size)
         *period_size = _period_size;
@@ -393,8 +458,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
         pa_sample_spec *ss,
         pa_channel_map* map,
         int mode,
-        uint32_t *nfrags,
         snd_pcm_uframes_t *period_size,
+        snd_pcm_uframes_t *buffer_size,
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,
         pa_bool_t *use_tsched,
@@ -410,8 +475,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
     pa_assert(dev);
     pa_assert(ss);
     pa_assert(map);
-    pa_assert(nfrags);
-    pa_assert(period_size);
     pa_assert(ps);
 
     /* First we try to find a device string with a superset of the
@@ -433,8 +496,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
                 ss,
                 map,
                 mode,
-                nfrags,
                 period_size,
+                buffer_size,
                 tsched_size,
                 use_mmap,
                 use_tsched,
@@ -460,8 +523,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
                 ss,
                 map,
                 mode,
-                nfrags,
                 period_size,
+                buffer_size,
                 tsched_size,
                 use_mmap,
                 use_tsched,
@@ -478,7 +541,18 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
     /* OK, we didn't find any good device, so let's try the raw hw: stuff */
     d = pa_sprintf_malloc("hw:%s", dev_id);
     pa_log_debug("Trying %s as last resort...", d);
-    pcm_handle = pa_alsa_open_by_device_string(d, dev, ss, map, mode, nfrags, period_size, tsched_size, use_mmap, use_tsched, FALSE);
+    pcm_handle = pa_alsa_open_by_device_string(
+            d,
+            dev,
+            ss,
+            map,
+            mode,
+            period_size,
+            buffer_size,
+            tsched_size,
+            use_mmap,
+            use_tsched,
+            FALSE);
     pa_xfree(d);
 
     if (pcm_handle && mapping)
@@ -493,8 +567,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
         pa_sample_spec *ss,
         pa_channel_map* map,
         int mode,
-        uint32_t *nfrags,
         snd_pcm_uframes_t *period_size,
+        snd_pcm_uframes_t *buffer_size,
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,
         pa_bool_t *use_tsched,
@@ -508,8 +582,6 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
     pa_assert(dev);
     pa_assert(ss);
     pa_assert(map);
-    pa_assert(nfrags);
-    pa_assert(period_size);
     pa_assert(m);
 
     try_ss.channels = m->channel_map.channels;
@@ -524,8 +596,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
             &try_ss,
             &try_map,
             mode,
-            nfrags,
             period_size,
+            buffer_size,
             tsched_size,
             use_mmap,
             use_tsched,
@@ -547,8 +619,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
         pa_sample_spec *ss,
         pa_channel_map* map,
         int mode,
-        uint32_t *nfrags,
         snd_pcm_uframes_t *period_size,
+        snd_pcm_uframes_t *buffer_size,
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,
         pa_bool_t *use_tsched,
@@ -579,7 +651,15 @@ snd_pcm_t *pa_alsa_open_by_device_string(
 
         pa_log_debug("Managed to open %s", d);
 
-        if ((err = pa_alsa_set_hw_params(pcm_handle, ss, nfrags, period_size, tsched_size, use_mmap, use_tsched, require_exact_channel_number)) < 0) {
+        if ((err = pa_alsa_set_hw_params(
+                     pcm_handle,
+                     ss,
+                     period_size,
+                     buffer_size,
+                     tsched_size,
+                     use_mmap,
+                     use_tsched,
+                     require_exact_channel_number)) < 0) {
 
             if (!reformat) {
                 reformat = TRUE;
@@ -632,8 +712,8 @@ snd_pcm_t *pa_alsa_open_by_template(
         pa_sample_spec *ss,
         pa_channel_map* map,
         int mode,
-        uint32_t *nfrags,
         snd_pcm_uframes_t *period_size,
+        snd_pcm_uframes_t *buffer_size,
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,
         pa_bool_t *use_tsched,
@@ -653,8 +733,8 @@ snd_pcm_t *pa_alsa_open_by_template(
                 ss,
                 map,
                 mode,
-                nfrags,
                 period_size,
+                buffer_size,
                 tsched_size,
                 use_mmap,
                 use_tsched,
index 830a922ecef5e3385fa375d2858600d0254c2664..265cd28c05aa12f94b755930a80a7e129e755d93 100644 (file)
@@ -42,8 +42,8 @@
 int pa_alsa_set_hw_params(
         snd_pcm_t *pcm_handle,
         pa_sample_spec *ss,                /* modified at return */
-        uint32_t *periods,                 /* modified at return */
         snd_pcm_uframes_t *period_size,    /* modified at return */
+        snd_pcm_uframes_t *buffer_size,    /* modified at return */
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,               /* modified at return */
         pa_bool_t *use_tsched,             /* modified at return */
@@ -60,8 +60,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto(
         pa_sample_spec *ss,               /* modified at return */
         pa_channel_map* map,              /* modified at return */
         int mode,
-        uint32_t *nfrags,                 /* modified at return */
         snd_pcm_uframes_t *period_size,   /* modified at return */
+        snd_pcm_uframes_t *buffer_size,   /* modified at return */
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,              /* modified at return */
         pa_bool_t *use_tsched,            /* modified at return */
@@ -75,8 +75,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping(
         pa_sample_spec *ss,               /* modified at return */
         pa_channel_map* map,              /* modified at return */
         int mode,
-        uint32_t *nfrags,                 /* modified at return */
         snd_pcm_uframes_t *period_size,   /* modified at return */
+        snd_pcm_uframes_t *buffer_size,   /* modified at return */
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,              /* modified at return */
         pa_bool_t *use_tsched,            /* modified at return */
@@ -89,8 +89,8 @@ snd_pcm_t *pa_alsa_open_by_device_string(
         pa_sample_spec *ss,               /* modified at return */
         pa_channel_map* map,              /* modified at return */
         int mode,
-        uint32_t *nfrags,                 /* modified at return */
         snd_pcm_uframes_t *period_size,   /* modified at return */
+        snd_pcm_uframes_t *buffer_size,   /* modified at return */
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,              /* modified at return */
         pa_bool_t *use_tsched,            /* modified at return */
@@ -104,8 +104,8 @@ snd_pcm_t *pa_alsa_open_by_template(
         pa_sample_spec *ss,               /* modified at return */
         pa_channel_map* map,              /* modified at return */
         int mode,
-        uint32_t *nfrags,                 /* modified at return */
         snd_pcm_uframes_t *period_size,   /* modified at return */
+        snd_pcm_uframes_t *buffer_size,   /* modified at return */
         snd_pcm_uframes_t tsched_size,
         pa_bool_t *use_mmap,              /* modified at return */
         pa_bool_t *use_tsched,            /* modified at return */