1 From a98e78ccc4f12d6efad2832a09202651e2a8b6cd Mon Sep 17 00:00:00 2001
2 From: Sangchul Lee <sangchul1011@gmail.com>
3 Date: Sat, 27 Aug 2016 21:33:19 +0900
4 Subject: [PATCH 5/6] sink-input, volume: Add support for volume ramp factor
6 Previously, using pa_sink_input_set_volume_ramp() is hard to manage
7 if there are several callers. These new volume ramp factor APIs make it
8 easy for caller to use and to set more than one volume ramp factor.
9 New volume ramp factor will be applied by the multiplication of the other
10 ramp factors that have been already set.
12 APIs are added as below.
13 - pa_sink_input_add_volume_ramp_factor()
14 - pa_sink_input_remove_volume_ramp_factor()
15 - pa_cvolume_ramp_compatible()
16 - pa_sw_cvolume_ramp_multiply()
17 - pa_cvolume_ramp_valid()
19 Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
22 src/pulse/volume.c | 44 ++++++++++++++++++
23 src/pulse/volume.h | 9 ++++
24 src/pulsecore/sink-input.c | 108 +++++++++++++++++++++++++++++++++++++++++++++
25 src/pulsecore/sink-input.h | 5 +++
26 5 files changed, 169 insertions(+)
28 diff --git a/src/map-file b/src/map-file
29 index ef9b57d..7577c14 100644
32 @@ -142,6 +142,8 @@ pa_cvolume_ramp_equal;
35 pa_cvolume_ramp_channel_ramp_set;
36 +pa_cvolume_ramp_compatible;
37 +pa_cvolume_ramp_valid;
40 pa_cvolume_scale_mask;
41 @@ -344,6 +346,7 @@ pa_sw_cvolume_divide_scalar;
42 pa_sw_cvolume_multiply;
43 pa_sw_cvolume_multiply_scalar;
44 pa_sw_cvolume_snprint_dB;
45 +pa_sw_cvolume_ramp_multiply;
48 pa_sw_volume_from_linear;
49 diff --git a/src/pulse/volume.c b/src/pulse/volume.c
50 index 85072c1..8d99150 100644
51 --- a/src/pulse/volume.c
52 +++ b/src/pulse/volume.c
53 @@ -1049,3 +1049,47 @@ pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigne
58 +int pa_cvolume_ramp_compatible(const pa_cvolume_ramp *ramp, const pa_sample_spec *ss) {
63 + pa_return_val_if_fail(pa_cvolume_ramp_valid(ramp), 0);
64 + pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
66 + return ramp->channels == ss->channels;
69 +pa_cvolume_ramp *pa_sw_cvolume_ramp_multiply(pa_cvolume_ramp *dest, const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) {
76 + pa_return_val_if_fail(pa_cvolume_ramp_valid(a), NULL);
77 + pa_return_val_if_fail(pa_cvolume_ramp_valid(b), NULL);
79 + for (i = 0; i < a->channels && i < b->channels; i++)
80 + dest->ramps[i].target = pa_sw_volume_multiply(a->ramps[i].target, b->ramps[i].target);
82 + dest->channels = (uint8_t) i;
87 +int pa_cvolume_ramp_valid(const pa_cvolume_ramp *ramp) {
92 + if (!pa_channels_valid(ramp->channels))
95 + for (c = 0; c < ramp->channels; c++)
96 + if (!PA_VOLUME_IS_VALID(ramp->ramps[c].target))
101 diff --git a/src/pulse/volume.h b/src/pulse/volume.h
102 index 2ae3451..65fcb08 100644
103 --- a/src/pulse/volume.h
104 +++ b/src/pulse/volume.h
105 @@ -458,12 +458,21 @@ int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b);
106 /** Init volume ramp struct */
107 pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp);
109 +/** Set the volume ramp of the first n channels to PA_VOLUME_NORM */
110 +#define pa_cvolume_ramp_reset(a, n, t, l) pa_cvolume_ramp_set((a), (n), (t), (l), PA_VOLUME_NORM)
112 /** Set first n channels of ramp struct to certain value */
113 pa_cvolume_ramp* pa_cvolume_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol);
115 /** Set individual channel in the channel struct */
116 pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigned channel, pa_volume_ramp_type_t type, long time, pa_volume_t vol);
118 +int pa_cvolume_ramp_compatible(const pa_cvolume_ramp *ramp, const pa_sample_spec *ss);
120 +int pa_cvolume_ramp_valid(const pa_cvolume_ramp *ramp);
122 +pa_cvolume_ramp *pa_sw_cvolume_ramp_multiply(pa_cvolume_ramp *dest, const pa_cvolume_ramp *a, const pa_cvolume_ramp *b);
127 diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
128 index e1968e0..6f89aa1 100644
129 --- a/src/pulsecore/sink-input.c
130 +++ b/src/pulsecore/sink-input.c
131 @@ -53,6 +53,11 @@ struct volume_factor_entry {
135 +struct volume_ramp_factor_entry {
137 + pa_cvolume_ramp ramp;
140 static struct volume_factor_entry *volume_factor_entry_new(const char *key, const pa_cvolume *volume) {
141 struct volume_factor_entry *entry;
143 @@ -83,6 +88,37 @@ static void volume_factor_from_hashmap(pa_cvolume *v, pa_hashmap *items, uint8_t
144 pa_sw_cvolume_multiply(v, v, &entry->volume);
147 +static struct volume_ramp_factor_entry *volume_ramp_factor_entry_new(const char *key, const pa_cvolume_ramp *ramp) {
148 + struct volume_ramp_factor_entry *entry;
153 + entry = pa_xnew(struct volume_ramp_factor_entry, 1);
154 + entry->key = pa_xstrdup(key);
156 + entry->ramp = *ramp;
161 +static void volume_ramp_factor_entry_free(struct volume_ramp_factor_entry *ramp_entry) {
162 + pa_assert(ramp_entry);
164 + pa_xfree(ramp_entry->key);
165 + pa_xfree(ramp_entry);
168 +static void volume_ramp_factor_from_hashmap(pa_cvolume_ramp *r, pa_hashmap *items, uint8_t channels, pa_volume_ramp_type_t type, long length) {
169 + struct volume_ramp_factor_entry *entry;
170 + void *state = NULL;
172 + pa_cvolume_ramp_reset(r, channels, type, length);
173 + PA_HASHMAP_FOREACH(entry, items, state)
174 + pa_sw_cvolume_ramp_multiply(r, r, &entry->ramp);
178 static void sink_input_free(pa_object *o);
179 static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v);
181 @@ -500,6 +536,8 @@ int pa_sink_input_new(
182 i->volume_factor_sink_items = data->volume_factor_sink_items;
183 data->volume_factor_sink_items = NULL;
184 volume_factor_from_hashmap(&i->volume_factor_sink, i->volume_factor_sink_items, i->sink->sample_spec.channels);
185 + i->ramp_factor_items = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
186 + (pa_free_cb_t) volume_ramp_factor_entry_free);
188 i->real_ratio = i->reference_ratio = data->volume;
189 pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels);
190 @@ -764,6 +802,9 @@ static void sink_input_free(pa_object *o) {
191 if (i->volume_factor_sink_items)
192 pa_hashmap_free(i->volume_factor_sink_items);
194 + if (i->ramp_factor_items)
195 + pa_hashmap_free(i->ramp_factor_items);
200 @@ -1367,6 +1408,73 @@ int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key) {
204 +void pa_sink_input_add_volume_ramp_factor(pa_sink_input *i, const char *key, const pa_cvolume_ramp *ramp_factor, bool send_msg) {
205 + struct volume_ramp_factor_entry *r;
207 + pa_sink_input_assert_ref(i);
208 + pa_assert_ctl_context();
209 + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
210 + pa_assert(ramp_factor);
212 + pa_assert(pa_cvolume_ramp_valid(ramp_factor));
213 + pa_assert(ramp_factor->channels == 1 || pa_cvolume_ramp_compatible(ramp_factor, &i->sample_spec));
215 + r = volume_ramp_factor_entry_new(key, ramp_factor);
216 + if (!pa_cvolume_ramp_compatible(ramp_factor, &i->sample_spec))
217 + pa_cvolume_ramp_set(&r->ramp, i->sample_spec.channels, ramp_factor->ramps[0].type, ramp_factor->ramps[0].length, ramp_factor->ramps[0].target);
219 + pa_assert_se(pa_hashmap_put(i->ramp_factor_items, r->key, r) >= 0);
220 + if (pa_hashmap_size(i->ramp_factor_items) == 1)
221 + pa_cvolume_ramp_set(&i->ramp_factor, i->sample_spec.channels, r->ramp.ramps[0].type, r->ramp.ramps[0].length, r->ramp.ramps[0].target);
223 + pa_sw_cvolume_ramp_multiply(&i->ramp_factor, &i->ramp_factor, &r->ramp);
225 + pa_cvolume_ramp_convert(&i->ramp_factor, &i->ramp, i->sample_spec.rate);
228 + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, NULL, 0, NULL) == 0);
233 +/* Returns 0 if an entry was removed and -1 if no entry for the given key was
235 +int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, bool send_msg) {
236 + struct volume_ramp_factor_entry *r;
238 + pa_sink_input_assert_ref(i);
240 + pa_assert_ctl_context();
241 + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
243 + r = pa_hashmap_remove(i->ramp_factor_items, key);
247 + switch (pa_hashmap_size(i->ramp_factor_items)) {
249 + pa_cvolume_ramp_reset(&i->ramp_factor, i->sample_spec.channels, r->ramp.ramps[0].type, r->ramp.ramps[0].length);
252 + struct volume_ramp_factor_entry *rf;
253 + rf = pa_hashmap_first(i->ramp_factor_items);
254 + pa_cvolume_ramp_set(&i->ramp_factor, i->sample_spec.channels, r->ramp.ramps[0].type, r->ramp.ramps[0].length, rf->ramp.ramps[0].target);
258 + volume_ramp_factor_from_hashmap(&i->ramp_factor, i->ramp_factor_items, i->ramp_factor.channels, i->ramp_factor.ramps[0].type, i->ramp_factor.ramps[0].length);
261 + volume_ramp_factor_entry_free(r);
263 + pa_cvolume_ramp_convert(&i->ramp_factor, &i->ramp, i->sample_spec.rate);
266 + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME_RAMP, NULL, 0, NULL) == 0);
271 /* Called from main thread */
272 void pa_sink_input_set_volume_ramp(
274 diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
275 index 92f61c3..5430d53 100644
276 --- a/src/pulsecore/sink-input.h
277 +++ b/src/pulsecore/sink-input.h
278 @@ -113,6 +113,9 @@ struct pa_sink_input {
279 pa_cvolume volume_factor_sink; /* A second volume factor in format of the sink this stream is connected to. */
280 pa_hashmap *volume_factor_sink_items;
282 + pa_cvolume_ramp ramp_factor;
283 + pa_hashmap *ramp_factor_items;
285 bool volume_writable:1;
288 @@ -379,6 +382,8 @@ void pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa
289 int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key);
290 pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute);
291 void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg);
292 +void pa_sink_input_add_volume_ramp_factor(pa_sink_input *i, const char *key, const pa_cvolume_ramp *ramp_factor, bool send_msg);
293 +int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, bool send_msg);
295 void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save);