[pulseaudio-discuss] [PATCH 2/4] volume ramp: adding volume ramping to sink-input

Jaska Uimonen jaska.uimonen at helsinki.fi
Wed Aug 8 01:14:38 PDT 2012


From: Jaska Uimonen <jaska.uimonen at helsinki.fi>

---
 src/pulsecore/sink-input.c |   87 ++++++++++++++++++++++++++++++++++++++++++++
 src/pulsecore/sink-input.h |   11 +++++-
 2 files changed, 97 insertions(+), 1 deletions(-)

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index f6f93b8..6384f1b 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -477,6 +477,27 @@ int pa_sink_input_new(
     reset_callbacks(i);
     i->userdata = NULL;
 
+    if (data->flags & PA_SINK_INPUT_START_RAMP_MUTED) {
+	i->ramp.type = PA_VOLUME_RAMP_TYPE_LINEAR;
+	i->ramp.length = 0;
+	i->ramp.left = 0;
+	i->ramp.start = 0.0;
+	i->ramp.end = 0.0;
+	i->ramp.curr = 0.0;
+	pa_cvolume_reset(&i->ramp.end_mapped, data->sample_spec.channels);
+	pa_cvolume_set(&i->ramp.end_mapped, data->sample_spec.channels, PA_VOLUME_MUTED);
+    }
+    else {
+	i->ramp.type = PA_VOLUME_RAMP_TYPE_LINEAR;
+	i->ramp.length = 0;
+	i->ramp.left = 0;
+	i->ramp.start = 1.0;
+	i->ramp.end = 1.0;
+	i->ramp.curr = 1.0;
+	pa_cvolume_reset(&i->ramp.end_mapped, data->sample_spec.channels);
+	pa_cvolume_set(&i->ramp.end_mapped, data->sample_spec.channels, PA_VOLUME_NORM);
+    }
+
     i->thread_info.state = i->state;
     i->thread_info.attached = FALSE;
     pa_atomic_store(&i->thread_info.drained, 1);
@@ -492,6 +513,8 @@ int pa_sink_input_new(
     i->thread_info.playing_for = 0;
     i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
+    i->thread_info.ramp = i->ramp;
+
     pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
     pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0);
 
@@ -894,6 +917,18 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
                     pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &i->volume_factor_sink);
                 }
 
+		/* check for possible volume ramp */
+		if (i->thread_info.ramp.left > 0) {
+		    pa_cvolume volume_adj;
+                    pa_memchunk_make_writable(&wchunk, 0);
+		    volume_adj.channels = i->sample_spec.channels;
+		    pa_cvolume_set(&volume_adj, i->sample_spec.channels, PA_VOLUME_NORM);
+		    pa_volume_ramp_memchunk(&wchunk, &i->sample_spec, &(i->thread_info.ramp), &volume_adj);
+		} else if (!pa_cvolume_is_norm(&(i->thread_info.ramp.end_mapped))) {
+                    pa_memchunk_make_writable(&wchunk, 0);
+		    pa_volume_memchunk(&wchunk, &i->sample_spec, &(i->thread_info.ramp.end_mapped));
+		}
+
                 pa_memblockq_push_align(i->thread_info.render_memblockq, &wchunk);
             } else {
                 pa_memchunk rchunk;
@@ -910,6 +945,18 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
                         pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink);
                     }
 
+		    /* check for possible volume ramp */
+		    if (i->thread_info.ramp.left > 0) {
+			pa_cvolume volume_adj;
+			pa_memchunk_make_writable(&rchunk, 0);
+			volume_adj.channels = i->sample_spec.channels;
+			pa_cvolume_set(&volume_adj, i->sample_spec.channels, PA_VOLUME_NORM);
+			pa_volume_ramp_memchunk(&rchunk, &i->sample_spec, &(i->thread_info.ramp), &volume_adj);
+		    } else if (!pa_cvolume_is_norm(&(i->thread_info.ramp.end_mapped))) {
+			pa_memchunk_make_writable(&rchunk, 0);
+			pa_volume_memchunk(&rchunk, &i->sample_spec, &(i->thread_info.ramp.end_mapped));
+		    }
+
                     pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk);
                     pa_memblock_unref(rchunk.memblock);
                 }
@@ -1204,6 +1251,39 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
     pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
 }
 
+/* Called from main thread */
+void pa_sink_input_set_volume_ramp(
+        pa_sink_input *i,
+        const pa_cvolume *volume,
+	uint32_t time,
+	uint8_t type,
+        pa_bool_t send_msg,
+        pa_bool_t save) {
+
+    float temp;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
+    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+    pa_assert(!volume || pa_cvolume_valid(volume));
+    pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec));
+
+    i->ramp.type = type;
+    i->ramp.length = time * i->sink->default_sample_rate / 1000;
+    i->ramp.left = i->ramp.length;
+    i->ramp.start = i->ramp.end;
+    i->ramp.end_mapped = *volume;
+    /* scale to pulse internal mapping */
+    temp = volume->values[0] / (float)0x10000U;
+    i->ramp.end = temp * temp * temp;
+
+    pa_log_debug("ramp length is %d ms, in samples %ld", time, i->ramp.length);
+
+    /* This tells the sink that volume ramp changed */
+    if (send_msg)
+        pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, NULL, 0, NULL) == 0);
+}
+
 /* Called from main context */
 static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) {
     pa_sink_input_assert_ref(i);
@@ -1811,6 +1891,13 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
             }
             return 0;
 
+        case PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP:
+	    /* we have ongoing ramp where we take current start values */
+	    if (i->thread_info.ramp.left > 0)
+		    i->ramp.start = i->thread_info.ramp.curr;
+	    i->thread_info.ramp = i->ramp;
+	    return 0;
+
         case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE:
             if (i->thread_info.muted != i->muted) {
                 i->thread_info.muted = i->muted;
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index af2177a..b0165da 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -61,7 +61,8 @@ typedef enum pa_sink_input_flags {
     PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256,
     PA_SINK_INPUT_NO_CREATE_ON_SUSPEND = 512,
     PA_SINK_INPUT_KILL_ON_SUSPEND = 1024,
-    PA_SINK_INPUT_PASSTHROUGH = 2048
+    PA_SINK_INPUT_PASSTHROUGH = 2048,
+    PA_SINK_INPUT_START_RAMP_MUTED = 4096,
 } pa_sink_input_flags_t;
 
 struct pa_sink_input {
@@ -115,6 +116,9 @@ struct pa_sink_input {
      * this.*/
     pa_bool_t save_sink:1, save_volume:1, save_muted:1;
 
+    /* for volume ramps */
+    pa_volume_ramp ramp;
+
     pa_resample_method_t requested_resample_method, actual_resample_method;
 
     /* Returns the chunk of audio data and drops it from the
@@ -237,6 +241,8 @@ struct pa_sink_input {
         pa_usec_t requested_sink_latency;
 
         pa_hashmap *direct_outputs;
+
+	pa_volume_ramp ramp;
     } thread_info;
 
     void *userdata;
@@ -253,6 +259,7 @@ enum {
     PA_SINK_INPUT_MESSAGE_SET_STATE,
     PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY,
     PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY,
+    PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP,
     PA_SINK_INPUT_MESSAGE_MAX
 };
 
@@ -359,6 +366,8 @@ pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bo
 void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save);
 pa_bool_t pa_sink_input_get_mute(pa_sink_input *i);
 
+void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume *volume, uint32_t time, uint8_t type, pa_bool_t send_msg, pa_bool_t save);
+
 void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p);
 
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i);
-- 
1.7.7.6



More information about the pulseaudio-discuss mailing list