summaryrefslogtreecommitdiffstats
path: root/meta-agl-profile-core/recipes-multimedia/pulseaudio/pulseaudio/0005-sink-input-volume-Add-support-for-volume-ramp-factor.patch
blob: e371b7ec59bc1edf6325c9235344a69eeb8fe429 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
From a98e78ccc4f12d6efad2832a09202651e2a8b6cd Mon Sep 17 00:00:00 2001
From: Sangchul Lee <sangchul1011@gmail.com>
Date: Sat, 27 Aug 2016 21:33:19 +0900
Subject: [PATCH 5/6] sink-input, volume: Add support for volume ramp factor

Previously, using pa_sink_input_set_volume_ramp() is hard to manage
if there are several callers. These new volume ramp factor APIs make it
easy for caller to use and to set more than one volume ramp factor.
New volume ramp factor will be applied by the multiplication of the other
ramp factors that have been already set.

APIs are added as below.
 - pa_sink_input_add_volume_ramp_factor()
 - pa_sink_input_remove_volume_ramp_factor()
 - pa_cvolume_ramp_compatible()
 - pa_sw_cvolume_ramp_multiply()
 - pa_cvolume_ramp_valid()

Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
---
 src/map-file               |   3 ++
 src/pulse/volume.c         |  44 ++++++++++++++++++
 src/pulse/volume.h         |   9 ++++
 src/pulsecore/sink-input.c | 108 +++++++++++++++++++++++++++++++++++++++++++++
 src/pulsecore/sink-input.h |   5 +++
 5 files changed, 169 insertions(+)

diff --git a/src/map-file b/src/map-file
index ef9b57d..7577c14 100644
--- a/src/map-file
+++ b/src/map-file
@@ -142,6 +142,8 @@ pa_cvolume_ramp_equal;
 pa_cvolume_ramp_init;
 pa_cvolume_ramp_set;
 pa_cvolume_ramp_channel_ramp_set;
+pa_cvolume_ramp_compatible;
+pa_cvolume_ramp_valid;
 pa_cvolume_remap;
 pa_cvolume_scale;
 pa_cvolume_scale_mask;
@@ -344,6 +346,7 @@ pa_sw_cvolume_divide_scalar;
 pa_sw_cvolume_multiply;
 pa_sw_cvolume_multiply_scalar;
 pa_sw_cvolume_snprint_dB;
+pa_sw_cvolume_ramp_multiply;
 pa_sw_volume_divide;
 pa_sw_volume_from_dB;
 pa_sw_volume_from_linear;
diff --git a/src/pulse/volume.c b/src/pulse/volume.c
index 85072c1..8d99150 100644
--- a/src/pulse/volume.c
+++ b/src/pulse/volume.c
@@ -1049,3 +1049,47 @@ pa_cvolume_ramp* pa_cvolume_ramp_channel_ramp_set(pa_cvolume_ramp *ramp, unsigne
 
     return ramp;
 }
+
+int pa_cvolume_ramp_compatible(const pa_cvolume_ramp *ramp, const pa_sample_spec *ss) {
+
+    pa_assert(ramp);
+    pa_assert(ss);
+
+    pa_return_val_if_fail(pa_cvolume_ramp_valid(ramp), 0);
+    pa_return_val_if_fail(pa_sample_spec_valid(ss), 0);
+
+    return ramp->channels == ss->channels;
+}
+
+pa_cvolume_ramp *pa_sw_cvolume_ramp_multiply(pa_cvolume_ramp *dest, const pa_cvolume_ramp *a, const pa_cvolume_ramp *b) {
+    unsigned i;
+
+    pa_assert(dest);
+    pa_assert(a);
+    pa_assert(b);
+
+    pa_return_val_if_fail(pa_cvolume_ramp_valid(a), NULL);
+    pa_return_val_if_fail(pa_cvolume_ramp_valid(b), NULL);
+
+    for (i = 0; i < a->channels && i < b->channels; i++)
+        dest->ramps[i].target = pa_sw_volume_multiply(a->ramps[i].target, b->ramps[i].target);
+
+    dest->channels = (uint8_t) i;
+
+    return dest;
+}
+
+int pa_cvolume_ramp_valid(const pa_cvolume_ramp *ramp) {
+    unsigned c;
+
+    pa_assert(ramp);
+
+    if (!pa_channels_valid(ramp->channels))
+        return 0;
+
+    for (c = 0; c < ramp->channels; c++)
+        if (!PA_VOLUME_IS_VALID(ramp->ramps[c].target))
+            return 0;
+
+    return 1;
+}
diff --git a/src/pulse/volume.h b/src/pulse/volume.h
index 2ae3451..65fcb08 100644
--- a/src/pulse/volume.h
+++ b/src/pulse/volume.h
@@ -458,12 +458,21 @@ int pa_cvolume_ramp_equal(const pa_cvolume_ramp *a, const pa_cvolume_ramp *b);
 /** Init volume ramp struct */
 pa_cvolume_ramp* pa_cvolume_ramp_init(pa_cvolume_ramp *ramp);
 
+/** Set the volume ramp of the first n channels to PA_VOLUME_NORM */
+#define pa_cvolume_ramp_reset(a, n, t, l) pa_cvolume_ramp_set((a), (n), (t), (l), PA_VOLUME_NORM)
+
 /** Set first n channels of ramp struct to certain value */
 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);
 
 /** Set individual channel in the channel struct */
 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);
 
+int pa_cvolume_ramp_compatible(const pa_cvolume_ramp *ramp, const pa_sample_spec *ss);
+
+int pa_cvolume_ramp_valid(const pa_cvolume_ramp *ramp);
+
+pa_cvolume_ramp *pa_sw_cvolume_ramp_multiply(pa_cvolume_ramp *dest, const pa_cvolume_ramp *a, const pa_cvolume_ramp *b);
+
 PA_C_DECL_END
 
 #endif
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index e1968e0..6f89aa1 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -53,6 +53,11 @@ struct volume_factor_entry {
     pa_cvolume volume;
 };
 
+struct volume_ramp_factor_entry {
+    char *key;
+    pa_cvolume_ramp ramp;
+};
+
 static struct volume_factor_entry *volume_factor_entry_new(const char *key, const pa_cvolume *volume) {
     struct volume_factor_entry *entry;
 
@@ -83,6 +88,37 @@ static void volume_factor_from_hashmap(pa_cvolume *v, pa_hashmap *items, uint8_t
         pa_sw_cvolume_multiply(v, v, &entry->volume);
 }
 
+static struct volume_ramp_factor_entry *volume_ramp_factor_entry_new(const char *key, const pa_cvolume_ramp *ramp) {
+    struct volume_ramp_factor_entry *entry;
+
+    pa_assert(key);
+    pa_assert(ramp);
+
+    entry = pa_xnew(struct volume_ramp_factor_entry, 1);
+    entry->key = pa_xstrdup(key);
+
+    entry->ramp = *ramp;
+
+    return entry;
+}
+
+static void volume_ramp_factor_entry_free(struct volume_ramp_factor_entry *ramp_entry) {
+    pa_assert(ramp_entry);
+
+    pa_xfree(ramp_entry->key);
+    pa_xfree(ramp_entry);
+}
+
+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) {
+    struct volume_ramp_factor_entry *entry;
+    void *state = NULL;
+
+    pa_cvolume_ramp_reset(r, channels, type, length);
+    PA_HASHMAP_FOREACH(entry, items, state)
+        pa_sw_cvolume_ramp_multiply(r, r, &entry->ramp);
+
+}
+
 static void sink_input_free(pa_object *o);
 static void set_real_ratio(pa_sink_input *i, const pa_cvolume *v);
 
@@ -500,6 +536,8 @@ int pa_sink_input_new(
     i->volume_factor_sink_items = data->volume_factor_sink_items;
     data->volume_factor_sink_items = NULL;
     volume_factor_from_hashmap(&i->volume_factor_sink, i->volume_factor_sink_items, i->sink->sample_spec.channels);
+    i->ramp_factor_items = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
+                                                    (pa_free_cb_t) volume_ramp_factor_entry_free);
 
     i->real_ratio = i->reference_ratio = data->volume;
     pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels);
@@ -764,6 +802,9 @@ static void sink_input_free(pa_object *o) {
     if (i->volume_factor_sink_items)
         pa_hashmap_free(i->volume_factor_sink_items);
 
+    if (i->ramp_factor_items)
+        pa_hashmap_free(i->ramp_factor_items);
+
     pa_xfree(i->driver);
     pa_xfree(i);
 }
@@ -1367,6 +1408,73 @@ int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key) {
     return 0;
 }
 
+void pa_sink_input_add_volume_ramp_factor(pa_sink_input *i, const char *key, const pa_cvolume_ramp *ramp_factor, bool send_msg) {
+    struct volume_ramp_factor_entry *r;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
+    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+    pa_assert(ramp_factor);
+    pa_assert(key);
+    pa_assert(pa_cvolume_ramp_valid(ramp_factor));
+    pa_assert(ramp_factor->channels == 1 || pa_cvolume_ramp_compatible(ramp_factor, &i->sample_spec));
+
+    r = volume_ramp_factor_entry_new(key, ramp_factor);
+    if (!pa_cvolume_ramp_compatible(ramp_factor, &i->sample_spec))
+        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);
+
+    pa_assert_se(pa_hashmap_put(i->ramp_factor_items, r->key, r) >= 0);
+    if (pa_hashmap_size(i->ramp_factor_items) == 1)
+        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);
+    else
+        pa_sw_cvolume_ramp_multiply(&i->ramp_factor, &i->ramp_factor, &r->ramp);
+
+    pa_cvolume_ramp_convert(&i->ramp_factor, &i->ramp, i->sample_spec.rate);
+
+    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);
+
+    return 0;
+}
+
+/* Returns 0 if an entry was removed and -1 if no entry for the given key was
+ * found. */
+int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, bool send_msg) {
+    struct volume_ramp_factor_entry *r;
+
+    pa_sink_input_assert_ref(i);
+    pa_assert(key);
+    pa_assert_ctl_context();
+    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+
+    r = pa_hashmap_remove(i->ramp_factor_items, key);
+    if (!r)
+        return -1;
+
+    switch (pa_hashmap_size(i->ramp_factor_items)) {
+        case 0:
+            pa_cvolume_ramp_reset(&i->ramp_factor, i->sample_spec.channels, r->ramp.ramps[0].type, r->ramp.ramps[0].length);
+            break;
+        case 1: {
+            struct volume_ramp_factor_entry *rf;
+            rf = pa_hashmap_first(i->ramp_factor_items);
+            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);
+            break;
+        }
+        default:
+            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);
+    }
+
+    volume_ramp_factor_entry_free(r);
+
+    pa_cvolume_ramp_convert(&i->ramp_factor, &i->ramp, i->sample_spec.rate);
+
+    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);
+
+    return 0;
+}
+
 /* Called from main thread */
 void pa_sink_input_set_volume_ramp(
         pa_sink_input *i,
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 92f61c3..5430d53 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -113,6 +113,9 @@ struct pa_sink_input {
     pa_cvolume volume_factor_sink; /* A second volume factor in format of the sink this stream is connected to. */
     pa_hashmap *volume_factor_sink_items;
 
+    pa_cvolume_ramp ramp_factor;
+    pa_hashmap *ramp_factor_items;
+
     bool volume_writable:1;
 
     bool muted:1;
@@ -379,6 +382,8 @@ void pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa
 int pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key);
 pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute);
 void pa_sink_input_set_volume_ramp(pa_sink_input *i, const pa_cvolume_ramp *ramp, bool send_msg);
+void pa_sink_input_add_volume_ramp_factor(pa_sink_input *i, const char *key, const pa_cvolume_ramp *ramp_factor, bool send_msg);
+int pa_sink_input_remove_volume_ramp_factor(pa_sink_input *i, const char *key, bool send_msg);
 
 void pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save);
 
-- 
1.9.1