[03/10] alsa sink/source: Allow alsa to use alternative smoother code

Submitted by Georg Chini on April 9, 2018, 4:57 p.m.

Details

Message ID 20180409165748.17459-4-georg@chini.tk
State New
Series "pulsecore: Add new time smoother"
Headers show

Commit Message

Georg Chini April 9, 2018, 4:57 p.m.
---
 src/modules/alsa/alsa-sink.c   | 86 ++++++++++++++++++++++++++++++++++++++++--
 src/modules/alsa/alsa-source.c | 67 ++++++++++++++++++++++++++++++--
 2 files changed, 146 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index eb79a444..d2e495e6 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -51,7 +51,12 @@ 
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+
+#ifdef USE_SMOOTHER_2
+#include <pulsecore/time-smoother_2.h>
+#else
 #include <pulsecore/time-smoother.h>
+#endif
 
 #include <modules/reserve-wrap.h>
 
@@ -77,11 +82,15 @@ 
 #define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC)                /* 10ms  -- Sleep at least 10ms on each iteration */
 #define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC)                /* 4ms   -- Wakeup at least this long before the buffer runs empty*/
 
+#ifdef USE_SMOOTHER_2
+#define SMOOTHER_WINDOW_USEC  (15*PA_USEC_PER_SEC)                 /* 15s   -- smoother windows size */
+#else
 #define SMOOTHER_WINDOW_USEC  (10*PA_USEC_PER_SEC)                 /* 10s   -- smoother windows size */
 #define SMOOTHER_ADJUST_USEC  (1*PA_USEC_PER_SEC)                  /* 1s    -- smoother adjust time */
 
 #define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC)                 /* 2ms   -- min smoother update interval */
 #define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC)               /* 200ms -- max smoother update interval */
+#endif
 
 #define VOLUME_ACCURACY (PA_VOLUME_NORM/100)  /* don't require volume adjustments to be perfectly correct. don't necessarily extend granularity in software unless the differences get greater than this level */
 
@@ -144,11 +153,18 @@  struct userdata {
 
     pa_rtpoll_item *alsa_rtpoll_item;
 
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2 *smoother;
+#else
     pa_smoother *smoother;
+#endif
     uint64_t write_count;
     uint64_t since_start;
+
+#ifndef USE_SMOOTHER_2
     pa_usec_t smoother_interval;
     pa_usec_t last_smoother_update;
+#endif
 
     pa_idxset *formats;
 
@@ -870,7 +886,10 @@  static void update_smoother(struct userdata *u) {
     snd_pcm_sframes_t delay = 0;
     int64_t position;
     int err;
-    pa_usec_t now1 = 0, now2;
+    pa_usec_t now1 = 0;
+#ifndef USE_SMOOTHER_2
+    pa_usec_t now2;
+#endif
     snd_pcm_status_t *status;
     snd_htimestamp_t htstamp = { 0, 0 };
 
@@ -893,13 +912,16 @@  static void update_smoother(struct userdata *u) {
     if (now1 <= 0)
         now1 = pa_rtclock_now();
 
+    position = (int64_t) u->write_count - ((int64_t) delay * (int64_t) u->frame_size);
+
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2_put(u->smoother, now1, position);
+#else
     /* check if the time since the last update is bigger than the interval */
     if (u->last_smoother_update > 0)
         if (u->last_smoother_update + u->smoother_interval > now1)
             return;
 
-    position = (int64_t) u->write_count - ((int64_t) delay * (int64_t) u->frame_size);
-
     if (PA_UNLIKELY(position < 0))
         position = 0;
 
@@ -910,18 +932,26 @@  static void update_smoother(struct userdata *u) {
     u->last_smoother_update = now1;
     /* exponentially increase the update interval up to the MAX limit */
     u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL);
+#endif
 }
 
 static int64_t sink_get_latency(struct userdata *u) {
     int64_t delay;
-    pa_usec_t now1, now2;
+    pa_usec_t now1;
+#ifndef USE_SMOOTHER_2
+    pa_usec_t now2;
+#endif
 
     pa_assert(u);
 
     now1 = pa_rtclock_now();
+#ifdef USE_SMOOTHER_2
+    delay = pa_smoother_2_get_delay(u->smoother, now1, u->write_count);
+#else
     now2 = pa_smoother_get(u->smoother, now1);
 
     delay = (int64_t) pa_bytes_to_usec(u->write_count, &u->sink->sample_spec) - (int64_t) now2;
+#endif
 
     if (u->memchunk.memblock)
         delay += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec);
@@ -947,7 +977,11 @@  static void suspend(struct userdata *u) {
     pa_assert(u);
     pa_assert(u->pcm_handle);
 
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2_pause(u->smoother, pa_rtclock_now());
+#else
     pa_smoother_pause(u->smoother, pa_rtclock_now());
+#endif
 
     /* Let's suspend -- we don't call snd_pcm_drain() here since that might
      * take awfully long with our long buffer sizes today. */
@@ -1145,9 +1179,13 @@  static int unsuspend(struct userdata *u) {
         goto fail;
 
     u->write_count = 0;
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2_reset(u->smoother, pa_rtclock_now());
+#else
     pa_smoother_reset(u->smoother, pa_rtclock_now(), true);
     u->smoother_interval = SMOOTHER_MIN_INTERVAL;
     u->last_smoother_update = 0;
+#endif
 
     u->first = true;
     u->since_start = 0;
@@ -1693,6 +1731,9 @@  static int sink_reconfigure_cb(pa_sink *s, pa_sample_spec *spec, bool passthroug
     if (!PA_SINK_IS_OPENED(s->state)) {
         pa_log_info("Updating rate for device %s, new rate is %d", u->device_name, spec->rate);
         u->sink->sample_spec.rate = spec->rate;
+#ifdef USE_SMOOTHER_2
+        pa_smoother_2_set_rate(u->smoother, pa_rtclock_now(), spec->rate);
+#endif
         return 0;
     }
 
@@ -1819,7 +1860,11 @@  static void thread_func(void *userdata) {
                     pa_log_info("Starting playback.");
                     snd_pcm_start(u->pcm_handle);
 
+#ifdef USE_SMOOTHER_2
+                    pa_smoother_2_resume(u->smoother, pa_rtclock_now());
+#else
                     pa_smoother_resume(u->smoother, pa_rtclock_now(), true);
+#endif
 
                     u->first = false;
                 }
@@ -1853,7 +1898,11 @@  static void thread_func(void *userdata) {
 
                 /* Convert from the sound card time domain to the
                  * system time domain */
+#ifdef USE_SMOOTHER_2
+                cusec = pa_smoother_2_translate(u->smoother, sleep_usec);
+#else
                 cusec = pa_smoother_translate(u->smoother, pa_rtclock_now(), sleep_usec);
+#endif
 
 #ifdef DEBUG_TIMING
                 pa_log_debug("Waking up in %0.2fms (system clock).", (double) cusec / PA_USEC_PER_MSEC);
@@ -2106,6 +2155,10 @@  pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     bool mute_is_set;
     pa_alsa_profile_set *profile_set = NULL;
     void *state = NULL;
+#ifdef USE_SMOOTHER_2
+    snd_pcm_info_t* pcm_info;
+    const char *id;
+#endif
 
     pa_assert(m);
     pa_assert(ma);
@@ -2211,6 +2264,7 @@  pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
         goto fail;
     }
 
+#ifndef USE_SMOOTHER_2
     u->smoother = pa_smoother_new(
             SMOOTHER_ADJUST_USEC,
             SMOOTHER_WINDOW_USEC,
@@ -2220,6 +2274,7 @@  pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
             pa_rtclock_now(),
             true);
     u->smoother_interval = SMOOTHER_MIN_INTERVAL;
+#endif
 
     /* use ucm */
     if (mapping && mapping->ucm_context.ucm)
@@ -2413,6 +2468,25 @@  pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
         goto fail;
     }
 
+#ifdef USE_SMOOTHER_2
+    u->smoother = pa_smoother_2_new(SMOOTHER_WINDOW_USEC, pa_rtclock_now(), frame_size, u->sink->sample_spec.rate);
+
+    /* Check if this is an USB device, see alsa-util.c
+     * USB devices unfortunately need some special handling */
+    snd_pcm_info_alloca(&pcm_info);
+    if (snd_pcm_info(u->pcm_handle, pcm_info) == 0 &&
+        (id = snd_pcm_info_get_id(pcm_info))) {
+        if (pa_streq(id, "USB Audio")) {
+            uint32_t hack_threshold;
+            /* USB device, set hack parameter */
+            hack_threshold = 2000;
+            if (!u->use_tsched)
+                hack_threshold = 1000;
+            pa_smoother_2_usb_hack_enable(u->smoother, true, hack_threshold);
+        }
+    }
+#endif
+
     if (pa_modargs_get_value_u32(ma, "deferred_volume_safety_margin",
                                  &u->sink->thread_info.volume_change_safety_margin) < 0) {
         pa_log("Failed to parse deferred_volume_safety_margin parameter");
@@ -2607,7 +2681,11 @@  static void userdata_free(struct userdata *u) {
         snd_mixer_close(u->mixer_handle);
 
     if (u->smoother)
+#ifdef USE_SMOOTHER_2
+        pa_smoother_2_free(u->smoother);
+#else
         pa_smoother_free(u->smoother);
+#endif
 
     if (u->formats)
         pa_idxset_free(u->formats, (pa_free_cb_t) pa_format_info_free);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index ca85968e..11d9910a 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -46,7 +46,12 @@ 
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/rtpoll.h>
+
+#ifdef USE_SMOOTHER_2
+#include <pulsecore/time-smoother_2.h>
+#else
 #include <pulsecore/time-smoother.h>
+#endif
 
 #include <modules/reserve-wrap.h>
 
@@ -70,11 +75,15 @@ 
 #define TSCHED_MIN_SLEEP_USEC (10*PA_USEC_PER_MSEC)                /* 10ms */
 #define TSCHED_MIN_WAKEUP_USEC (4*PA_USEC_PER_MSEC)                /* 4ms */
 
+#ifdef USE_SMOOTHER_2
+#define SMOOTHER_WINDOW_USEC  (15*PA_USEC_PER_SEC)                 /* 15s */
+#else
 #define SMOOTHER_WINDOW_USEC  (10*PA_USEC_PER_SEC)                 /* 10s */
 #define SMOOTHER_ADJUST_USEC  (1*PA_USEC_PER_SEC)                  /* 1s */
 
 #define SMOOTHER_MIN_INTERVAL (2*PA_USEC_PER_MSEC)                 /* 2ms */
 #define SMOOTHER_MAX_INTERVAL (200*PA_USEC_PER_MSEC)               /* 200ms */
+#endif
 
 #define VOLUME_ACCURACY (PA_VOLUME_NORM/100)
 
@@ -129,10 +138,17 @@  struct userdata {
 
     pa_rtpoll_item *alsa_rtpoll_item;
 
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2 *smoother;
+#else
     pa_smoother *smoother;
+#endif
     uint64_t read_count;
+
+#ifndef USE_SMOOTHER_2
     pa_usec_t smoother_interval;
     pa_usec_t last_smoother_update;
+#endif
 
     pa_reserve_wrapper *reserve;
     pa_hook_slot *reserve_slot;
@@ -775,7 +791,10 @@  static void update_smoother(struct userdata *u) {
     snd_pcm_sframes_t delay = 0;
     uint64_t position;
     int err;
-    pa_usec_t now1 = 0, now2;
+    pa_usec_t now1 = 0;
+#ifndef USE_SMOOTHER_2
+    pa_usec_t now2;
+#endif
     snd_pcm_status_t *status;
     snd_htimestamp_t htstamp = { 0, 0 };
 
@@ -798,12 +817,16 @@  static void update_smoother(struct userdata *u) {
     if (now1 <= 0)
         now1 = pa_rtclock_now();
 
+    position = u->read_count + ((uint64_t) delay * (uint64_t) u->frame_size);
+
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2_put(u->smoother, now1, position);
+#else
     /* check if the time since the last update is bigger than the interval */
     if (u->last_smoother_update > 0)
         if (u->last_smoother_update + u->smoother_interval > now1)
             return;
 
-    position = u->read_count + ((uint64_t) delay * (uint64_t) u->frame_size);
     now2 = pa_bytes_to_usec(position, &u->source->sample_spec);
 
     pa_smoother_put(u->smoother, now1, now2);
@@ -811,18 +834,27 @@  static void update_smoother(struct userdata *u) {
     u->last_smoother_update = now1;
     /* exponentially increase the update interval up to the MAX limit */
     u->smoother_interval = PA_MIN (u->smoother_interval * 2, SMOOTHER_MAX_INTERVAL);
+#endif
 }
 
 static int64_t source_get_latency(struct userdata *u) {
     int64_t delay;
-    pa_usec_t now1, now2;
+    pa_usec_t now1;
+#ifndef USE_SMOOTHER_2
+    pa_usec_t now2;
+#endif
 
     pa_assert(u);
 
     now1 = pa_rtclock_now();
+
+#ifdef USE_SMOOTHER_2
+    delay = - pa_smoother_2_get_delay(u->smoother, now1, u->read_count);
+#else
     now2 = pa_smoother_get(u->smoother, now1);
 
     delay = (int64_t) now2 - (int64_t) pa_bytes_to_usec(u->read_count, &u->source->sample_spec);
+#endif
 
     return delay;
 }
@@ -845,7 +877,11 @@  static void suspend(struct userdata *u) {
     pa_assert(u);
     pa_assert(u->pcm_handle);
 
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2_pause(u->smoother, pa_rtclock_now());
+#else
     pa_smoother_pause(u->smoother, pa_rtclock_now());
+#endif
 
     /* Let's suspend */
     snd_pcm_close(u->pcm_handle);
@@ -1004,9 +1040,13 @@  static int unsuspend(struct userdata *u) {
     /* FIXME: We need to reload the volume somehow */
 
     u->read_count = 0;
+#ifdef USE_SMOOTHER_2
+    pa_smoother_2_reset(u->smoother, pa_rtclock_now());
+#else
     pa_smoother_reset(u->smoother, pa_rtclock_now(), true);
     u->smoother_interval = SMOOTHER_MIN_INTERVAL;
     u->last_smoother_update = 0;
+#endif
 
     u->first = true;
 
@@ -1489,6 +1529,9 @@  static int source_reconfigure_cb(pa_source *s, pa_sample_spec *spec, bool passth
     if (!PA_SOURCE_IS_OPENED(s->state)) {
         pa_log_info("Updating rate for device %s, new rate is %d", u->device_name, spec->rate);
         u->source->sample_spec.rate = spec->rate;
+#ifdef USE_SMOOTHER_2
+        pa_smoother_2_set_rate(u->smoother, pa_rtclock_now(), spec->rate);
+#endif
         return 0;
     }
 
@@ -1526,7 +1569,11 @@  static void thread_func(void *userdata) {
                 pa_log_info("Starting capture.");
                 snd_pcm_start(u->pcm_handle);
 
+#ifdef USE_SMOOTHER_2
+                pa_smoother_2_resume(u->smoother, pa_rtclock_now());
+#else
                 pa_smoother_resume(u->smoother, pa_rtclock_now(), true);
+#endif
 
                 u->first = false;
             }
@@ -1554,7 +1601,11 @@  static void thread_func(void *userdata) {
 
                 /* Convert from the sound card time domain to the
                  * system time domain */
+#ifdef USE_SMOOTHER_2
+                cusec = pa_smoother_2_translate(u->smoother, sleep_usec);
+#else
                 cusec = pa_smoother_translate(u->smoother, pa_rtclock_now(), sleep_usec);
+#endif
 
 /*                 pa_log_debug("Waking up in %0.2fms (system clock).", (double) cusec / PA_USEC_PER_MSEC); */
 
@@ -1898,6 +1949,7 @@  pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
         goto fail;
     }
 
+#ifndef USE_SMOOTHER_2
     u->smoother = pa_smoother_new(
             SMOOTHER_ADJUST_USEC,
             SMOOTHER_WINDOW_USEC,
@@ -1907,6 +1959,7 @@  pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
             pa_rtclock_now(),
             true);
     u->smoother_interval = SMOOTHER_MIN_INTERVAL;
+#endif
 
     /* use ucm */
     if (mapping && mapping->ucm_context.ucm)
@@ -2089,6 +2142,10 @@  pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
         goto fail;
     }
 
+#ifdef USE_SMOOTHER_2
+    u->smoother = pa_smoother_2_new(SMOOTHER_WINDOW_USEC, pa_rtclock_now(), frame_size, u->source->sample_spec.rate);
+#endif
+
     if (pa_modargs_get_value_u32(ma, "deferred_volume_safety_margin",
                                  &u->source->thread_info.volume_change_safety_margin) < 0) {
         pa_log("Failed to parse deferred_volume_safety_margin parameter");
@@ -2241,7 +2298,11 @@  static void userdata_free(struct userdata *u) {
         snd_mixer_close(u->mixer_handle);
 
     if (u->smoother)
+#ifdef USE_SMOOTHER_2
+        pa_smoother_2_free(u->smoother);
+#else
         pa_smoother_free(u->smoother);
+#endif
 
     if (u->rates)
         pa_xfree(u->rates);