[pulseaudio-commits] 7 commits - src/modules src/pulsecore

Arun Raghavan arun at kemper.freedesktop.org
Mon Nov 7 10:37:08 PST 2011


 src/modules/echo-cancel/echo-cancel.h        |   10 ++
 src/modules/echo-cancel/module-echo-cancel.c |   99 ++++++++++++++++++---
 src/modules/echo-cancel/webrtc.cc            |   35 +++++--
 src/pulsecore/sink-input.c                   |  127 +++++++++++++++------------
 src/pulsecore/sink-input.h                   |    1 
 src/pulsecore/sink.c                         |   10 +-
 src/pulsecore/source-output.c                |  124 +++++++++++++++-----------
 src/pulsecore/source-output.h                |    1 
 src/pulsecore/source.c                       |    9 +
 9 files changed, 287 insertions(+), 129 deletions(-)

New commits:
commit cc89b4aff1ad90078967eed4956664939c4b2c8b
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Mon Nov 7 19:35:28 2011 +0530

    echo-cancel: Make WebRTC the default canceller
    
    Works pretty well, and isn't a CPU hog, so let's use it!

diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 05ebde3..c72c217 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -89,7 +89,7 @@ typedef enum {
 #endif
 } pa_echo_canceller_method_t;
 
-#define DEFAULT_ECHO_CANCELLER "speex"
+#define DEFAULT_ECHO_CANCELLER "webrtc"
 
 static const pa_echo_canceller ec_table[] = {
     {

commit c3d714693c2bad728f976a4a56644f9f3895a8bd
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Mon Nov 7 19:35:05 2011 +0530

    echo-cancel: Turn WebRTC analog gain control on by default
    
    Seems to be pretty well-behaved.

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 28d6852..c4ec7da 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -42,8 +42,8 @@ PA_C_DECL_END
 
 #define DEFAULT_HIGH_PASS_FILTER TRUE
 #define DEFAULT_NOISE_SUPPRESSION TRUE
-#define DEFAULT_ANALOG_GAIN_CONTROL FALSE
-#define DEFAULT_DIGITAL_GAIN_CONTROL TRUE
+#define DEFAULT_ANALOG_GAIN_CONTROL TRUE
+#define DEFAULT_DIGITAL_GAIN_CONTROL FALSE
 #define DEFAULT_MOBILE FALSE
 #define DEFAULT_ROUTING_MODE "speakerphone"
 #define DEFAULT_COMFORT_NOISE TRUE

commit fb02d50fe387fffb582ab981e2a71fbb6aa37440
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Nov 4 16:38:30 2011 +0530

    echo-cancel: Hook up WebRTC analog gain control

diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index 8a38298..bc1aab1 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -58,6 +58,7 @@ struct pa_echo_canceller_params {
             void *apm;
             uint32_t blocksize;
             pa_sample_spec sample_spec;
+            pa_bool_t agc;
         } webrtc;
 #endif
         /* each canceller-specific structure goes here */
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index df4d34d..28d6852 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -110,7 +110,7 @@ pa_bool_t pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         goto fail;
     }
 
-    dgc = DEFAULT_DIGITAL_GAIN_CONTROL;
+    dgc = agc ? FALSE : DEFAULT_DIGITAL_GAIN_CONTROL;
     if (pa_modargs_get_value_boolean(ma, "digital_gain_control", &dgc) < 0) {
         pa_log("Failed to parse digital_gain_control value");
         goto fail;
@@ -193,15 +193,20 @@ pa_bool_t pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     }
 
     if (agc || dgc) {
-        if (mobile && rm <= webrtc::EchoControlMobile::kEarpiece)
+        if (mobile && rm <= webrtc::EchoControlMobile::kEarpiece) {
             /* Maybe this should be a knob, but we've got a lot of knobs already */
             apm->gain_control()->set_mode(webrtc::GainControl::kFixedDigital);
-        else if (dgc)
-            apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
-        else {
-            /* FIXME: Hook up for analog AGC */
-            pa_log("Analog gain control isn't implemented yet -- using ditital gain control.");
+            ec->params.priv.webrtc.agc = FALSE;
+        } else if (dgc) {
             apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
+            ec->params.priv.webrtc.agc = FALSE;
+        } else {
+            apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveAnalog);
+            if (apm->gain_control()->set_analog_level_limits(0, PA_VOLUME_NORM-1) != apm->kNoError) {
+                pa_log("Failed to initialise AGC");
+                goto fail;
+            }
+            ec->params.priv.webrtc.agc = TRUE;
         }
 
         apm->gain_control()->Enable(true);
@@ -242,15 +247,27 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
     webrtc::AudioFrame out_frame;
     const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
+    pa_cvolume v;
 
     out_frame._audioChannel = ss->channels;
     out_frame._frequencyInHz = ss->rate;
     out_frame._payloadDataLengthInSamples = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
     memcpy(out_frame._payloadData, rec, ec->params.priv.webrtc.blocksize);
 
+    if (ec->params.priv.webrtc.agc) {
+        pa_cvolume_init(&v);
+        pa_echo_canceller_get_capture_volume(ec, &v);
+        apm->gain_control()->set_stream_analog_level(pa_cvolume_avg(&v));
+    }
+
     apm->set_stream_delay_ms(0);
     apm->ProcessStream(&out_frame);
 
+    if (ec->params.priv.webrtc.agc) {
+        pa_cvolume_set(&v, ss->channels, apm->gain_control()->stream_analog_level());
+        pa_echo_canceller_set_capture_volume(ec, &v);
+    }
+
     memcpy(out, out_frame._payloadData, ec->params.priv.webrtc.blocksize);
 }
 

commit 3d2f2424eb0740cbaa250867fc7280225e4d1c88
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Fri Nov 4 16:17:26 2011 +0530

    echo-cancel: Add infrastructure for cancellers to do AGC
    
    This adds some infrastructure for canceller implementations to also
    perform acoustic gain control. Cancellers now have a couple of new API
    calls that allow them to get/set capture volume.
    
    This is made slightly complex by the fact that cancellation happens in
    thread context while most volume mangling needs to be done in main
    context. To deal with this, while getting the volume we save source
    volume updates as they are propagated to thread context and use this
    cached value for queries. To set the volume, we send an async message to
    main context and let that set the source volume.

diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index 799631b..8a38298 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -37,6 +37,8 @@
 
 /* Common data structures */
 
+typedef struct pa_echo_canceller_msg pa_echo_canceller_msg;
+
 typedef struct pa_echo_canceller_params pa_echo_canceller_params;
 
 struct pa_echo_canceller_params {
@@ -109,8 +111,15 @@ struct pa_echo_canceller {
 
     /* Structure with common and engine-specific canceller parameters. */
     pa_echo_canceller_params params;
+
+    /* msgobject that can be used to send messages back to the main thread */
+    pa_echo_canceller_msg *msg;
 };
 
+/* Functions to be used by the canceller analog gain control routines */
+void pa_echo_canceller_get_capture_volume(pa_echo_canceller *ec, pa_cvolume *v);
+void pa_echo_canceller_set_capture_volume(pa_echo_canceller *ec, pa_cvolume *v);
+
 /* Speex canceller functions */
 pa_bool_t pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
                            pa_sample_spec *source_ss, pa_channel_map *source_map,
diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 9b69f82..05ebde3 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -159,6 +159,16 @@ static const pa_echo_canceller ec_table[] = {
  *    don't give enough accuracy to be able to do that right now.
  */
 
+struct userdata;
+
+struct pa_echo_canceller_msg {
+    pa_msgobject parent;
+    struct userdata *userdata;
+};
+
+PA_DEFINE_PRIVATE_CLASS(pa_echo_canceller_msg, pa_msgobject);
+#define PA_ECHO_CANCELLER_MSG(o) (pa_echo_canceller_msg_cast(o))
+
 struct snapshot {
     pa_usec_t sink_now;
     pa_usec_t sink_latency;
@@ -218,6 +228,12 @@ struct userdata {
     FILE *played_file;
     FILE *canceled_file;
     FILE *drift_file;
+
+    pa_bool_t use_volume_sharing;
+
+    struct {
+        pa_cvolume current_volume;
+    } thread_info;
 };
 
 static void source_output_snapshot_within_thread(struct userdata *u, struct snapshot *snapshot);
@@ -254,6 +270,10 @@ enum {
     SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT
 };
 
+enum {
+    ECHO_CANCELLER_MESSAGE_SET_VOLUME,
+};
+
 static int64_t calc_diff(struct userdata *u, struct snapshot *snapshot) {
     int64_t buffer, diff_time, buffer_latency;
 
@@ -378,6 +398,9 @@ static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t
 
             return 0;
 
+        case PA_SOURCE_MESSAGE_SET_VOLUME_SYNCED:
+            u->thread_info.current_volume = u->source->reference_volume;
+            break;
     }
 
     return pa_source_process_msg(o, code, data, offset, chunk);
@@ -1466,6 +1489,51 @@ static void sink_input_mute_changed_cb(pa_sink_input *i) {
     pa_sink_mute_changed(u->sink, i->muted);
 }
 
+/* Called from main context */
+static int canceller_process_msg_cb(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+    struct pa_echo_canceller_msg *msg;
+    struct userdata *u;
+
+    pa_assert(o);
+
+    msg = PA_ECHO_CANCELLER_MSG(o);
+    u = msg->userdata;
+
+    switch (code) {
+        case ECHO_CANCELLER_MESSAGE_SET_VOLUME: {
+            pa_cvolume *v = (pa_cvolume *) userdata;
+
+            if (u->use_volume_sharing)
+                pa_source_set_volume(u->source, v, TRUE, FALSE);
+            else
+                pa_source_output_set_volume(u->source_output, v, FALSE, TRUE);
+
+            break;
+        }
+
+        default:
+            pa_assert_not_reached();
+            break;
+    }
+
+    return 0;
+}
+
+/* Called by the canceller, so thread context */
+void pa_echo_canceller_get_capture_volume(pa_echo_canceller *ec, pa_cvolume *v) {
+    *v = ec->msg->userdata->thread_info.current_volume;
+}
+
+/* Called by the canceller, so thread context */
+void pa_echo_canceller_set_capture_volume(pa_echo_canceller *ec, pa_cvolume *v) {
+    if (!pa_cvolume_equal(&ec->msg->userdata->thread_info.current_volume, v)) {
+        pa_cvolume *vol = pa_xnewdup(pa_cvolume, v, 1);
+
+        pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(ec->msg), ECHO_CANCELLER_MESSAGE_SET_VOLUME, vol, 0, NULL,
+                pa_xfree);
+    }
+}
+
 static pa_echo_canceller_method_t get_ec_method_from_string(const char *method) {
     if (pa_streq(method, "speex"))
         return PA_ECHO_CANCELLER_SPEEX;
@@ -1526,7 +1594,6 @@ int pa__init(pa_module*m) {
     pa_sink_new_data sink_data;
     pa_memchunk silence;
     uint32_t temp;
-    pa_bool_t use_volume_sharing = TRUE;
 
     pa_assert(m);
 
@@ -1560,11 +1627,6 @@ int pa__init(pa_module*m) {
     sink_ss = sink_master->sample_spec;
     sink_map = sink_master->channel_map;
 
-    if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
-        pa_log("use_volume_sharing= expects a boolean argument");
-        goto fail;
-    }
-
     u = pa_xnew0(struct userdata, 1);
     if (!u) {
         pa_log("Failed to alloc userdata");
@@ -1575,6 +1637,12 @@ int pa__init(pa_module*m) {
     m->userdata = u;
     u->dead = FALSE;
 
+    u->use_volume_sharing = TRUE;
+    if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &u->use_volume_sharing) < 0) {
+        pa_log("use_volume_sharing= expects a boolean argument");
+        goto fail;
+    }
+
     temp = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
     if (pa_modargs_get_value_u32(ma, "adjust_time", &temp) < 0) {
         pa_log("Failed to parse adjust_time value");
@@ -1653,7 +1721,7 @@ int pa__init(pa_module*m) {
     }
 
     u->source = pa_source_new(m->core, &source_data, (source_master->flags & (PA_SOURCE_LATENCY | PA_SOURCE_DYNAMIC_LATENCY))
-                                                     | (use_volume_sharing ? PA_SOURCE_SHARE_VOLUME_WITH_MASTER : 0));
+                                                     | (u->use_volume_sharing ? PA_SOURCE_SHARE_VOLUME_WITH_MASTER : 0));
     pa_source_new_data_done(&source_data);
 
     if (!u->source) {
@@ -1666,7 +1734,7 @@ int pa__init(pa_module*m) {
     u->source->update_requested_latency = source_update_requested_latency_cb;
     pa_source_set_get_mute_callback(u->source, source_get_mute_cb);
     pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
-    if (!use_volume_sharing) {
+    if (!u->use_volume_sharing) {
         pa_source_set_get_volume_callback(u->source, source_get_volume_cb);
         pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
         pa_source_enable_decibel_volume(u->source, TRUE);
@@ -1703,7 +1771,7 @@ int pa__init(pa_module*m) {
     }
 
     u->sink = pa_sink_new(m->core, &sink_data, (sink_master->flags & (PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY))
-                                               | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
+                                               | (u->use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
     pa_sink_new_data_done(&sink_data);
 
     if (!u->sink) {
@@ -1716,7 +1784,7 @@ int pa__init(pa_module*m) {
     u->sink->update_requested_latency = sink_update_requested_latency_cb;
     u->sink->request_rewind = sink_request_rewind_cb;
     pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
-    if (!use_volume_sharing) {
+    if (!u->use_volume_sharing) {
         pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
         pa_sink_enable_decibel_volume(u->sink, TRUE);
     }
@@ -1793,7 +1861,7 @@ int pa__init(pa_module*m) {
     u->sink_input->state_change = sink_input_state_change_cb;
     u->sink_input->may_move_to = sink_input_may_move_to_cb;
     u->sink_input->moving = sink_input_moving_cb;
-    if (!use_volume_sharing)
+    if (!u->use_volume_sharing)
         u->sink_input->volume_changed = sink_input_volume_changed_cb;
     u->sink_input->mute_changed = sink_input_mute_changed_cb;
     u->sink_input->userdata = u;
@@ -1841,12 +1909,17 @@ int pa__init(pa_module*m) {
         }
     }
 
+    u->ec->msg = pa_msgobject_new(pa_echo_canceller_msg);
+    u->ec->msg->parent.process_msg = canceller_process_msg_cb;
+    u->ec->msg->userdata = u;
+
+    u->thread_info.current_volume = u->source->reference_volume;
+
     pa_sink_put(u->sink);
     pa_source_put(u->source);
 
     pa_sink_input_put(u->sink_input);
     pa_source_output_put(u->source_output);
-
     pa_modargs_free(ma);
 
     return 0;

commit a813e85503355496c7ea6397e39072fd8ffedcff
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Sun Nov 6 19:12:19 2011 +0530

    sink,source: Update sample rate if possible on stream uncork
    
    If a stream is being uncorked and no other stream is running, we try to
    update the sink/source sample rate to match it and avoid resampling.

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index fbede01..d57ad77 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -556,6 +556,12 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
     if (i->state == state)
         return;
 
+    if (i->state == PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_RUNNING && pa_sink_used_by(i->sink) == 0) {
+        /* We were uncorked and the sink was not playing anything -- let's try
+         * to update the sample rate to avoid resampling */
+        pa_sink_update_rate(i->sink, i->sample_spec.rate, pa_sink_input_is_passthrough(i));
+    }
+
     pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
 
     update_n_corked(i, state);
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 47b93a9..7b0cb84 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -515,6 +515,12 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_
     if (o->state == state)
         return;
 
+    if (o->state == PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_RUNNING && pa_source_used_by(o->source) == 0) {
+        /* We were uncorked and the source was not playing anything -- let's try
+         * to update the sample rate to avoid resampling */
+        pa_source_update_rate(o->source, o->sample_spec.rate, pa_source_output_is_passthrough(o));
+    }
+
     pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
 
     update_n_corked(o, state);

commit 993d73d330e2b773bd9b95e1214767c6c35f5f6b
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Mon Nov 7 15:01:25 2011 +0530

    sink,source: Allow sample rate switching with corked streams
    
    This updates corked streams' resamplers when switching sample rates on a
    sink/source, which means the restriction of allowing sample rate updates
    only when no streams are attached to a sink/source is now relaxed to
    preventing updates only when there is a running stream attached.

diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 99acb2f..9cad937 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -1339,6 +1339,8 @@ pa_bool_t pa_sink_update_rate(pa_sink *s, uint32_t rate, pa_bool_t passthrough)
         uint32_t desired_rate = rate;
         uint32_t default_rate = s->default_sample_rate;
         uint32_t alternate_rate = s->alternate_sample_rate;
+        uint32_t idx;
+        pa_sink_input *i;
         pa_bool_t use_alternate = FALSE;
 
         if (PA_UNLIKELY(default_rate == alternate_rate)) {
@@ -1385,7 +1387,7 @@ pa_bool_t pa_sink_update_rate(pa_sink *s, uint32_t rate, pa_bool_t passthrough)
             desired_rate = rate; /* use stream sampling rate, discard default/alternate settings */
         }
 
-        if (!passthrough && pa_sink_linked_by(s) > 0)
+        if (!passthrough && pa_sink_used_by(s) > 0)
             return FALSE;
 
         pa_sink_suspend(s, TRUE, PA_SUSPEND_IDLE); /* needed before rate update, will be resumed automatically */
@@ -1395,6 +1397,12 @@ pa_bool_t pa_sink_update_rate(pa_sink *s, uint32_t rate, pa_bool_t passthrough)
             if (s->monitor_source && !passthrough)
                 pa_source_update_rate(s->monitor_source, desired_rate, FALSE);
             pa_log_info("Changed sampling rate successfully");
+
+            PA_IDXSET_FOREACH(i, s->inputs, idx) {
+                if (i->state == PA_SINK_INPUT_CORKED)
+                    pa_sink_input_update_rate(i);
+            }
+
             return TRUE;
         }
     }
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index ac81492..33f4c73 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -933,6 +933,8 @@ pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate, pa_bool_t passthrou
         uint32_t desired_rate = rate;
         uint32_t default_rate = s->default_sample_rate;
         uint32_t alternate_rate = s->alternate_sample_rate;
+        uint32_t idx;
+        pa_source_output *o;
         pa_bool_t use_alternate = FALSE;
 
         if (PA_UNLIKELY(default_rate == alternate_rate)) {
@@ -972,13 +974,18 @@ pa_bool_t pa_source_update_rate(pa_source *s, uint32_t rate, pa_bool_t passthrou
             desired_rate = rate; /* use stream sampling rate, discard default/alternate settings */
         }
 
-        if (!passthrough && pa_source_linked_by(s) > 0)
+        if (!passthrough && pa_source_used_by(s) > 0)
             return FALSE;
 
         pa_source_suspend(s, TRUE, PA_SUSPEND_IDLE); /* needed before rate update, will be resumed automatically */
 
         if (s->update_rate(s, desired_rate) == TRUE) {
             pa_log_info("Changed sampling rate successfully ");
+
+            PA_IDXSET_FOREACH(o, s->outputs, idx) {
+                if (o->state == PA_SOURCE_OUTPUT_CORKED)
+                    pa_source_output_update_rate(o);
+            }
             return TRUE;
         }
     }

commit 8616f82a67fa031ba224c6d23fa70c31724ef853
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date:   Sun Nov 6 18:20:01 2011 +0530

    sink-input,source-output: Add an update_rate() function
    
    This factors out the resampler updating code from finish_move() and
    makes a separate function for use from other points.

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index a64defa..fbede01 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -1596,8 +1596,6 @@ static void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
 
 /* Called from main context */
 int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
-    pa_resampler *new_resampler;
-
     pa_sink_input_assert_ref(i);
     pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
@@ -1633,34 +1631,6 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
                         dest->sample_spec.rate);
     }
 
-    if (i->thread_info.resampler &&
-        pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &dest->sample_spec) &&
-        pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &dest->channel_map))
-
-        /* Try to reuse the old resampler if possible */
-        new_resampler = i->thread_info.resampler;
-
-    else if (!pa_sink_input_is_passthrough(i) &&
-             ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
-              !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) ||
-              !pa_channel_map_equal(&i->channel_map, &dest->channel_map))) {
-
-        /* Okay, we need a new resampler for the new sink */
-
-        if (!(new_resampler = pa_resampler_new(
-                      i->core->mempool,
-                      &i->sample_spec, &i->channel_map,
-                      &dest->sample_spec, &dest->channel_map,
-                      i->requested_resample_method,
-                      ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
-                      ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
-                      (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
-            pa_log_warn("Unsupported resampling operation.");
-            return -PA_ERR_NOTSUPPORTED;
-        }
-    } else
-        new_resampler = NULL;
-
     if (i->moving)
         i->moving(i, dest);
 
@@ -1673,30 +1643,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
     if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
         i->sink->n_corked++;
 
-    /* Replace resampler and render queue */
-    if (new_resampler != i->thread_info.resampler) {
-        char *memblockq_name;
-
-        if (i->thread_info.resampler)
-            pa_resampler_free(i->thread_info.resampler);
-        i->thread_info.resampler = new_resampler;
-
-        pa_memblockq_free(i->thread_info.render_memblockq);
-
-        memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
-        i->thread_info.render_memblockq = pa_memblockq_new(
-                memblockq_name,
-                0,
-                MEMBLOCKQ_MAXLENGTH,
-                0,
-                &i->sink->sample_spec,
-                0,
-                1,
-                0,
-                &i->sink->silence);
-        pa_xfree(memblockq_name);
-        i->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
-    }
+    pa_sink_input_update_rate(i);
 
     pa_sink_update_status(dest);
 
@@ -2043,3 +1990,69 @@ finish:
     if (pl)
         pa_proplist_free(pl);
 }
+
+/* Called from main context */
+/* Updates the sink input's resampler with whatever the current sink requires
+ * -- useful when the underlying sink's rate might have changed */
+int pa_sink_input_update_rate(pa_sink_input *i) {
+    pa_resampler *new_resampler;
+    char *memblockq_name;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
+
+    if (i->thread_info.resampler &&
+        pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &i->sink->sample_spec) &&
+        pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &i->sink->channel_map))
+
+        new_resampler = i->thread_info.resampler;
+
+    else if (!pa_sink_input_is_passthrough(i) &&
+        ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
+         !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec) ||
+         !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map))) {
+
+        new_resampler = pa_resampler_new(i->core->mempool,
+                                     &i->sample_spec, &i->channel_map,
+                                     &i->sink->sample_spec, &i->sink->channel_map,
+                                     i->requested_resample_method,
+                                     ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
+                                     ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
+                                     (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0));
+
+        if (!new_resampler) {
+            pa_log_warn("Unsupported resampling operation.");
+            return -PA_ERR_NOTSUPPORTED;
+        }
+    } else
+        new_resampler = NULL;
+
+    if (new_resampler == i->thread_info.resampler)
+        return 0;
+
+    if (i->thread_info.resampler)
+        pa_resampler_free(i->thread_info.resampler);
+
+    i->thread_info.resampler = new_resampler;
+
+    pa_memblockq_free(i->thread_info.render_memblockq);
+
+    memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
+    i->thread_info.render_memblockq = pa_memblockq_new(
+            memblockq_name,
+            0,
+            MEMBLOCKQ_MAXLENGTH,
+            0,
+            &i->sink->sample_spec,
+            0,
+            1,
+            0,
+            &i->sink->silence);
+    pa_xfree(memblockq_name);
+
+    i->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
+
+    pa_log_debug("Updated resmpler for sink input %d", i->index);
+
+    return 0;
+}
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 8d286da..af2177a 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -338,6 +338,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, pa_bool_t rew
 void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b);
 
 int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
+int pa_sink_input_update_rate(pa_sink_input *i);
 
 /* This returns the sink's fields converted into out sample type */
 size_t pa_sink_input_get_max_rewind(pa_sink_input *i);
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 21e8da9..47b93a9 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -1376,8 +1376,6 @@ static void update_volume_due_to_moving(pa_source_output *o, pa_source *dest) {
 
 /* Called from main context */
 int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save) {
-    pa_resampler *new_resampler;
-
     pa_source_output_assert_ref(o);
     pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
@@ -1413,34 +1411,6 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
                         dest->sample_spec.rate);
     }
 
-    if (o->thread_info.resampler &&
-        pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) &&
-        pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map))
-
-        /* Try to reuse the old resampler if possible */
-        new_resampler = o->thread_info.resampler;
-
-    else if (!pa_source_output_is_passthrough(o) &&
-             ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
-              !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
-              !pa_channel_map_equal(&o->channel_map, &dest->channel_map))) {
-
-        /* Okay, we need a new resampler for the new source */
-
-        if (!(new_resampler = pa_resampler_new(
-                      o->core->mempool,
-                      &dest->sample_spec, &dest->channel_map,
-                      &o->sample_spec, &o->channel_map,
-                      o->requested_resample_method,
-                      ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
-                      ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
-                      (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
-            pa_log_warn("Unsupported resampling operation.");
-            return -PA_ERR_NOTSUPPORTED;
-        }
-    } else
-        new_resampler = NULL;
-
     if (o->moving)
         o->moving(o, dest);
 
@@ -1453,27 +1423,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
     if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED)
         o->source->n_corked++;
 
-    /* Replace resampler */
-    if (new_resampler != o->thread_info.resampler) {
-
-        if (o->thread_info.resampler)
-            pa_resampler_free(o->thread_info.resampler);
-        o->thread_info.resampler = new_resampler;
-
-        pa_memblockq_free(o->thread_info.delay_memblockq);
-
-        o->thread_info.delay_memblockq = pa_memblockq_new(
-                "source output delay_memblockq",
-                0,
-                MEMBLOCKQ_MAXLENGTH,
-                0,
-                &o->source->sample_spec,
-                0,
-                1,
-                0,
-                &o->source->silence);
-        o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
-    }
+    pa_source_output_update_rate(o);
 
     pa_source_update_status(dest);
 
@@ -1646,3 +1596,69 @@ finish:
     if (pl)
         pa_proplist_free(pl);
 }
+
+/* Called from main context */
+/* Updates the source output's resampler with whatever the current source
+ * requires -- useful when the underlying source's rate might have changed */
+int pa_source_output_update_rate(pa_source_output *o) {
+    pa_resampler *new_resampler;
+    char *memblockq_name;
+
+    pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
+
+    if (o->thread_info.resampler &&
+        pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &o->source->sample_spec) &&
+        pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &o->source->channel_map))
+
+        new_resampler = o->thread_info.resampler;
+
+    else if (!pa_source_output_is_passthrough(o) &&
+        ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
+         !pa_sample_spec_equal(&o->sample_spec, &o->source->sample_spec) ||
+         !pa_channel_map_equal(&o->channel_map, &o->source->channel_map))) {
+
+        new_resampler = pa_resampler_new(o->core->mempool,
+                                     &o->source->sample_spec, &o->source->channel_map,
+                                     &o->sample_spec, &o->channel_map,
+                                     o->requested_resample_method,
+                                     ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
+                                     ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
+                                     (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0));
+
+        if (!new_resampler) {
+            pa_log_warn("Unsupported resampling operation.");
+            return -PA_ERR_NOTSUPPORTED;
+        }
+    } else
+        new_resampler = NULL;
+
+    if (new_resampler == o->thread_info.resampler)
+        return 0;
+
+    if (o->thread_info.resampler)
+        pa_resampler_free(o->thread_info.resampler);
+
+    o->thread_info.resampler = new_resampler;
+
+    pa_memblockq_free(o->thread_info.delay_memblockq);
+
+    memblockq_name = pa_sprintf_malloc("source output delay_memblockq [%u]", o->index);
+    o->thread_info.delay_memblockq = pa_memblockq_new(
+            memblockq_name,
+            0,
+            MEMBLOCKQ_MAXLENGTH,
+            0,
+            &o->source->sample_spec,
+            0,
+            1,
+            0,
+            &o->source->silence);
+    pa_xfree(memblockq_name);
+
+    o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
+
+    pa_log_debug("Updated resmpler for source output %d", o->index);
+
+    return 0;
+}
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 31263d4..e60430f 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -301,6 +301,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
 void pa_source_output_cork(pa_source_output *o, pa_bool_t b);
 
 int pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
+int pa_source_output_update_rate(pa_source_output *o);
 
 size_t pa_source_output_get_max_rewind(pa_source_output *o);
 



More information about the pulseaudio-commits mailing list