[08/10] loopback: Add low_device_latency parameter

Submitted by Georg Chini on April 9, 2018, 5:17 p.m.

Details

Message ID 20180409171707.17696-9-georg@chini.tk
State New
Headers show
Series "loopback: Optimize latency stabilization" ( rev: 1 ) in PulseAudio

Not browsing as part of any series.

Commit Message

Georg Chini April 9, 2018, 5:17 p.m.
For USB devices the latency jitter strongly depends on device latency. Therefore
a boolean low_device_latency parameter is introduced to half the device latency.
Normally 1/3 of the configured end-to-end latency is used, with the parameter
this is changed to 1/6. In many situations the parameter can improve latency
stability but it will also lead to significantly higher CPU consumption.
---
 src/modules/module-loopback.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index eeb93264..048fe4f9 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -46,6 +46,7 @@  PA_MODULE_USAGE(
         "adjust_time=<how often to readjust rates in s> "
         "latency_msec=<latency in ms> "
         "max_latency_msec=<maximum latency in ms> "
+        "low_device_latency=<boolean, use half of the normal device latency> "
         "adjust_threshold_usec=<threshold for latency adjustment in usec> "
         "format=<sample format> "
         "rate=<sample rate> "
@@ -98,6 +99,7 @@  struct userdata {
     pa_usec_t max_latency;
     pa_usec_t adjust_time;
     uint32_t adjust_threshold;
+    bool low_device_latency;
 
     /* Latency boundaries and current values */
     pa_usec_t min_source_latency;
@@ -189,6 +191,7 @@  static const char* const valid_modargs[] = {
     "adjust_time",
     "latency_msec",
     "max_latency_msec",
+    "low_device_latency",
     "adjust_threshold_usec",
     "format",
     "rate",
@@ -776,11 +779,14 @@  static void update_effective_source_latency(struct userdata *u, pa_source *sourc
  * Set source output latency to one third of the overall latency if possible.
  * The choice of one third is rather arbitrary somewhere between the minimum
  * possible latency which would cause a lot of CPU load and half the configured
- * latency which would quickly lead to underruns */
+ * latency which would quickly lead to underruns. In low device latency mode set
+ * source to one sixth of the overall latency. */
 static void set_source_output_latency(struct userdata *u, pa_source *source) {
     pa_usec_t latency, requested_latency;
 
     requested_latency = u->latency / 3;
+    if (u->low_device_latency)
+        requested_latency = u->latency / 6;
 
     /* Normally we try to configure sink and source latency equally. If the
      * sink latency cannot match the requested source latency try to set the
@@ -1149,11 +1155,14 @@  static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in
  * Set sink input latency to one third of the overall latency if possible.
  * The choice of one third is rather arbitrary somewhere between the minimum
  * possible latency which would cause a lot of CPU load and half the configured
- * latency which would quickly lead to underruns. */
+ * latency which would quickly lead to underruns. In low device latency mode
+ * set sink to one sixth of the overall latency. */
 static void set_sink_input_latency(struct userdata *u, pa_sink *sink) {
      pa_usec_t latency, requested_latency;
 
     requested_latency = u->latency / 3;
+    if (u->low_device_latency)
+        requested_latency = u->latency / 6;
 
     /* Normally we try to configure sink and source latency equally. If the
      * source latency cannot match the requested sink latency try to set the
@@ -1482,6 +1491,7 @@  int pa__init(pa_module *m) {
     uint32_t adjust_time_sec;
     const char *n;
     bool remix = true;
+    bool low_device_latency = false;
 
     pa_assert(m);
 
@@ -1574,6 +1584,11 @@  int pa__init(pa_module *m) {
         max_latency_msec = latency_msec;
     }
 
+    if (pa_modargs_get_value_boolean(ma, "low_device_latency", &low_device_latency) < 0) {
+        pa_log("Invalid boolean device latency parameter");
+        goto fail;
+    }
+
     m->userdata = u = pa_xnew0(struct userdata, 1);
     u->core = m->core;
     u->module = m;
@@ -1594,6 +1609,7 @@  int pa__init(pa_module *m) {
     u->latency_error = 0;
     u->adjust_threshold = adjust_threshold;
     u->target_latency_cross_counter = 0;
+    u->low_device_latency = low_device_latency;
     u->initial_adjust_pending = true;
 
     adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;