]> code.delx.au - pulseaudio/blob - src/modules/module-equalizer-sink.c
505e60b7618961fb21b69d1eac2b6b3c58ca1c2e
[pulseaudio] / src / modules / module-equalizer-sink.c
1 /***
2 This file is part of PulseAudio.
3
4 This module is based off Lennart Poettering's LADSPA sink and swaps out
5 LADSPA functionality for a dbus-aware STFT OLA based digital equalizer.
6 All new work is published under PulseAudio's original license.
7
8 Copyright 2009 Jason Newton <nevion@gmail.com>
9
10 Original Author:
11 Copyright 2004-2008 Lennart Poettering
12
13 PulseAudio is free software; you can redistribute it and/or modify
14 it under the terms of the GNU Lesser General Public License as
15 published by the Free Software Foundation; either version 2.1 of the
16 License, or (at your option) any later version.
17
18 PulseAudio is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU Lesser General Public
24 License along with PulseAudio; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 USA.
27 ***/
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <float.h>
36 #include <math.h>
37 #include <string.h>
38 #include <stdint.h>
39
40 //#undef __SSE2__
41 #ifdef __SSE2__
42 #include <xmmintrin.h>
43 #include <emmintrin.h>
44 #endif
45
46 #include <fftw3.h>
47
48 #include <pulse/xmalloc.h>
49 #include <pulse/timeval.h>
50
51 #include <pulsecore/core-rtclock.h>
52 #include <pulsecore/i18n.h>
53 #include <pulsecore/aupdate.h>
54 #include <pulsecore/namereg.h>
55 #include <pulsecore/sink.h>
56 #include <pulsecore/module.h>
57 #include <pulsecore/core-util.h>
58 #include <pulsecore/modargs.h>
59 #include <pulsecore/log.h>
60 #include <pulsecore/rtpoll.h>
61 #include <pulsecore/sample-util.h>
62 #include <pulsecore/shared.h>
63 #include <pulsecore/idxset.h>
64 #include <pulsecore/strlist.h>
65 #include <pulsecore/database.h>
66 #include <pulsecore/protocol-dbus.h>
67 #include <pulsecore/dbus-util.h>
68
69 #include "module-equalizer-sink-symdef.h"
70
71 PA_MODULE_AUTHOR("Jason Newton");
72 PA_MODULE_DESCRIPTION(_("General Purpose Equalizer"));
73 PA_MODULE_VERSION(PACKAGE_VERSION);
74 PA_MODULE_LOAD_ONCE(FALSE);
75 PA_MODULE_USAGE(
76 _("sink_name=<name of the sink> "
77 "sink_properties=<properties for the sink> "
78 "sink_master=<sink to connect to> "
79 "format=<sample format> "
80 "rate=<sample rate> "
81 "channels=<number of channels> "
82 "channel_map=<channel map> "
83 "autoloaded=<set if this module is being loaded automatically> "
84 "use_volume_sharing=<yes or no> "
85 ));
86
87 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
88 #define DEFAULT_AUTOLOADED FALSE
89
90 struct userdata {
91 pa_module *module;
92 pa_sink *sink;
93 pa_sink_input *sink_input;
94 pa_bool_t autoloaded;
95
96 size_t channels;
97 size_t fft_size;//length (res) of fft
98 size_t window_size;/*
99 *sliding window size
100 *effectively chooses R
101 */
102 size_t R;/* the hop size between overlapping windows
103 * the latency of the filter, calculated from window_size
104 * based on constraints of COLA and window function
105 */
106 //for twiddling with pulseaudio
107 size_t overlap_size;//window_size-R
108 size_t samples_gathered;
109 size_t input_buffer_max;
110 //message
111 float *W;//windowing function (time domain)
112 float *work_buffer, **input, **overlap_accum;
113 fftwf_complex *output_window;
114 fftwf_plan forward_plan, inverse_plan;
115 //size_t samplings;
116
117 float **Xs;
118 float ***Hs;//thread updatable copies of the freq response filters (magnitude based)
119 pa_aupdate **a_H;
120 pa_memblockq *input_q;
121 char *output_buffer;
122 size_t output_buffer_length;
123 size_t output_buffer_max_length;
124 pa_memblockq *output_q;
125 pa_bool_t first_iteration;
126
127 pa_dbus_protocol *dbus_protocol;
128 char *dbus_path;
129
130 pa_database *database;
131 char **base_profiles;
132 };
133
134 static const char* const valid_modargs[] = {
135 "sink_name",
136 "sink_properties",
137 "sink_master",
138 "format",
139 "rate",
140 "channels",
141 "channel_map",
142 "autoloaded",
143 "use_volume_sharing",
144 NULL
145 };
146
147 #define v_size 4
148 #define SINKLIST "equalized_sinklist"
149 #define EQDB "equalizer_db"
150 #define EQ_STATE_DB "equalizer-state"
151 #define FILTER_SIZE(u) ((u)->fft_size / 2 + 1)
152 #define CHANNEL_PROFILE_SIZE(u) (FILTER_SIZE(u) + 1)
153 #define FILTER_STATE_SIZE(u) (CHANNEL_PROFILE_SIZE(u) * (u)->channels)
154
155 static void dbus_init(struct userdata *u);
156 static void dbus_done(struct userdata *u);
157
158 static void hanning_window(float *W, size_t window_size) {
159 /* h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2 */
160 for (size_t i = 0; i < window_size; ++i)
161 W[i] = (float).5 * (1 - cos(2*M_PI*i / (window_size+1)));
162 }
163
164 static void fix_filter(float *H, size_t fft_size) {
165 /* divide out the fft gain */
166 for (size_t i = 0; i < fft_size / 2 + 1; ++i)
167 H[i] /= fft_size;
168 }
169
170 static void interpolate(float *samples, size_t length, uint32_t *xs, float *ys, size_t n_points) {
171 /* Note that xs must be monotonically increasing! */
172 float x_range_lower, x_range_upper, c0;
173
174 pa_assert(n_points >= 2);
175 pa_assert(xs[0] == 0);
176 pa_assert(xs[n_points - 1] == length - 1);
177
178 for (size_t x = 0, x_range_lower_i = 0; x < length-1; ++x) {
179 pa_assert(x_range_lower_i < n_points-1);
180
181 x_range_lower = (float) xs[x_range_lower_i];
182 x_range_upper = (float) xs[x_range_lower_i+1];
183
184 pa_assert_se(x_range_lower < x_range_upper);
185 pa_assert_se(x >= x_range_lower);
186 pa_assert_se(x <= x_range_upper);
187
188 /* bilinear-interpolation of coefficients specified */
189 c0 = (x-x_range_lower) / (x_range_upper-x_range_lower);
190 pa_assert(c0 >= 0 && c0 <= 1.0);
191
192 samples[x] = ((1.0f - c0) * ys[x_range_lower_i] + c0 * ys[x_range_lower_i + 1]);
193 while(x >= xs[x_range_lower_i + 1])
194 x_range_lower_i++;
195 }
196
197 samples[length-1] = ys[n_points-1];
198 }
199
200 static pa_bool_t is_monotonic(const uint32_t *xs, size_t length) {
201 pa_assert(xs);
202
203 if (length < 2)
204 return TRUE;
205
206 for(size_t i = 1; i < length; ++i)
207 if (xs[i] <= xs[i-1])
208 return FALSE;
209
210 return TRUE;
211 }
212
213 /* ensures memory allocated is a multiple of v_size and aligned */
214 static void * alloc(size_t x, size_t s) {
215 size_t f;
216 float *t;
217
218 f = PA_ROUND_UP(x*s, sizeof(float)*v_size);
219 pa_assert_se(t = fftwf_malloc(f));
220 pa_memzero(t, f);
221
222 return t;
223 }
224
225 static void alloc_input_buffers(struct userdata *u, size_t min_buffer_length) {
226 if (min_buffer_length <= u->input_buffer_max)
227 return;
228
229 pa_assert(min_buffer_length >= u->window_size);
230 for (size_t c = 0; c < u->channels; ++c) {
231 float *tmp = alloc(min_buffer_length, sizeof(float));
232 if (u->input[c]) {
233 if (!u->first_iteration)
234 memcpy(tmp, u->input[c], u->overlap_size * sizeof(float));
235 free(u->input[c]);
236 }
237 u->input[c] = tmp;
238 }
239 u->input_buffer_max = min_buffer_length;
240 }
241
242 /* Called from I/O thread context */
243 static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
244 struct userdata *u = PA_SINK(o)->userdata;
245
246 switch (code) {
247
248 case PA_SINK_MESSAGE_GET_LATENCY: {
249 //size_t fs=pa_frame_size(&u->sink->sample_spec);
250
251 /* The sink is _put() before the sink input is, so let's
252 * make sure we don't access it in that time. Also, the
253 * sink input is first shut down, the sink second. */
254 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
255 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) {
256 *((pa_usec_t*) data) = 0;
257 return 0;
258 }
259
260 *((pa_usec_t*) data) =
261 /* Get the latency of the master sink */
262 pa_sink_get_latency_within_thread(u->sink_input->sink) +
263
264 /* Add the latency internal to our sink input on top */
265 pa_bytes_to_usec(pa_memblockq_get_length(u->output_q) +
266 pa_memblockq_get_length(u->input_q), &u->sink_input->sink->sample_spec) +
267 pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec);
268 // pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec);
269 //+ pa_bytes_to_usec(u->latency * fs, ss)
270 return 0;
271 }
272 }
273
274 return pa_sink_process_msg(o, code, data, offset, chunk);
275 }
276
277
278 /* Called from main context */
279 static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
280 struct userdata *u;
281
282 pa_sink_assert_ref(s);
283 pa_assert_se(u = s->userdata);
284
285 if (!PA_SINK_IS_LINKED(state) ||
286 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
287 return 0;
288
289 pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
290 return 0;
291 }
292
293 /* Called from I/O thread context */
294 static void sink_request_rewind_cb(pa_sink *s) {
295 struct userdata *u;
296
297 pa_sink_assert_ref(s);
298 pa_assert_se(u = s->userdata);
299
300 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
301 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
302 return;
303
304 /* Just hand this one over to the master sink */
305 pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes+pa_memblockq_get_length(u->input_q), TRUE, FALSE, FALSE);
306 }
307
308 /* Called from I/O thread context */
309 static void sink_update_requested_latency_cb(pa_sink *s) {
310 struct userdata *u;
311
312 pa_sink_assert_ref(s);
313 pa_assert_se(u = s->userdata);
314
315 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
316 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
317 return;
318
319 /* Just hand this one over to the master sink */
320 pa_sink_input_set_requested_latency_within_thread(
321 u->sink_input,
322 pa_sink_get_requested_latency_within_thread(s));
323 }
324
325 /* Called from main context */
326 static void sink_set_volume_cb(pa_sink *s) {
327 struct userdata *u;
328
329 pa_sink_assert_ref(s);
330 pa_assert_se(u = s->userdata);
331
332 if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
333 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
334 return;
335
336 pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, TRUE);
337 }
338
339 /* Called from main context */
340 static void sink_set_mute_cb(pa_sink *s) {
341 struct userdata *u;
342
343 pa_sink_assert_ref(s);
344 pa_assert_se(u = s->userdata);
345
346 if (!PA_SINK_IS_LINKED(pa_sink_get_state(s)) ||
347 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
348 return;
349
350 pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted);
351 }
352
353 #if 1
354 //reference implementation
355 static void dsp_logic(
356 float * restrict dst,//used as a temp array too, needs to be fft_length!
357 float * restrict src,/*input data w/ overlap at start,
358 *automatically cycled in routine
359 */
360 float * restrict overlap,
361 const float X,//multiplier
362 const float * restrict H,//The freq. magnitude scalers filter
363 const float * restrict W,//The windowing function
364 fftwf_complex * restrict output_window,//The transformed windowed src
365 struct userdata *u) {
366
367 //use a linear-phase sliding STFT and overlap-add method (for each channel)
368 //window the data
369 for(size_t j = 0; j < u->window_size; ++j) {
370 dst[j] = X * W[j] * src[j];
371 }
372 //zero pad the remaining fft window
373 memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
374 //Processing is done here!
375 //do fft
376 fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
377 //perform filtering
378 for(size_t j = 0; j < FILTER_SIZE(u); ++j) {
379 u->output_window[j][0] *= H[j];
380 u->output_window[j][1] *= H[j];
381 }
382 //inverse fft
383 fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
384 ////debug: tests overlapping add
385 ////and negates ALL PREVIOUS processing
386 ////yields a perfect reconstruction if COLA is held
387 //for(size_t j = 0; j < u->window_size; ++j) {
388 // u->work_buffer[j] = u->W[j] * u->input[c][j];
389 //}
390
391 //overlap add and preserve overlap component from this window (linear phase)
392 for(size_t j = 0; j < u->overlap_size; ++j) {
393 u->work_buffer[j] += overlap[j];
394 overlap[j] = dst[u->R + j];
395 }
396 ////debug: tests if basic buffering works
397 ////shouldn't modify the signal AT ALL (beyond roundoff)
398 //for(size_t j = 0; j < u->window_size;++j) {
399 // u->work_buffer[j] = u->input[c][j];
400 //}
401
402 //preserve the needed input for the next window's overlap
403 memmove(src, src + u->R,
404 (u->samples_gathered - u->R) * sizeof(float)
405 );
406 }
407 #else
408 typedef float v4sf __attribute__ ((__aligned__(v_size * sizeof(float))));
409 typedef union float_vector {
410 float f[v_size];
411 v4sf v;
412 __m128 m;
413 } float_vector_t;
414
415 //regardless of sse enabled, the loops in here assume
416 //16 byte aligned addresses and memory allocations divisible by v_size
417 static void dsp_logic(
418 float * restrict dst,//used as a temp array too, needs to be fft_length!
419 float * restrict src,/*input data w/ overlap at start,
420 *automatically cycled in routine
421 */
422 float * restrict overlap,//The size of the overlap
423 const float X,//multiplier
424 const float * restrict H,//The freq. magnitude scalers filter
425 const float * restrict W,//The windowing function
426 fftwf_complex * restrict output_window,//The transformed windowed src
427 struct userdata *u) {//Collection of constants
428 const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size);
429 float_vector_t x;
430 x.f[0] = x.f[1] = x.f[2] = x.f[3] = X;
431
432 //assert(u->samples_gathered >= u->R);
433 //use a linear-phase sliding STFT and overlap-add method
434 for(size_t j = 0; j < u->window_size; j += v_size) {
435 //dst[j] = W[j] * src[j];
436 float_vector_t *d = (float_vector_t*) (dst + j);
437 float_vector_t *w = (float_vector_t*) (W + j);
438 float_vector_t *s = (float_vector_t*) (src + j);
439 //#if __SSE2__
440 d->m = _mm_mul_ps(x.m, _mm_mul_ps(w->m, s->m));
441 // d->v = x->v * w->v * s->v;
442 //#endif
443 }
444 //zero pad the remaining fft window
445 memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
446
447 //Processing is done here!
448 //do fft
449 fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
450 //perform filtering - purely magnitude based
451 for(size_t j = 0; j < FILTER_SIZE; j += v_size / 2) {
452 //output_window[j][0]*=H[j];
453 //output_window[j][1]*=H[j];
454 float_vector_t *d = (float_vector_t*)( ((float *) output_window) + 2 * j);
455 float_vector_t h;
456 h.f[0] = h.f[1] = H[j];
457 h.f[2] = h.f[3] = H[j + 1];
458 //#if __SSE2__
459 d->m = _mm_mul_ps(d->m, h.m);
460 //#else
461 // d->v = d->v * h.v;
462 //#endif
463 }
464
465 //inverse fft
466 fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
467
468 ////debug: tests overlapping add
469 ////and negates ALL PREVIOUS processing
470 ////yields a perfect reconstruction if COLA is held
471 //for(size_t j = 0; j < u->window_size; ++j) {
472 // dst[j] = W[j] * src[j];
473 //}
474
475 //overlap add and preserve overlap component from this window (linear phase)
476 for(size_t j = 0; j < overlap_size; j += v_size) {
477 //dst[j]+=overlap[j];
478 //overlap[j]+=dst[j+R];
479 float_vector_t *d = (float_vector_t*)(dst + j);
480 float_vector_t *o = (float_vector_t*)(overlap + j);
481 //#if __SSE2__
482 d->m = _mm_add_ps(d->m, o->m);
483 o->m = ((float_vector_t*)(dst + u->R + j))->m;
484 //#else
485 // d->v = d->v + o->v;
486 // o->v = ((float_vector_t*)(dst + u->R + j))->v;
487 //#endif
488 }
489 //memcpy(overlap, dst+u->R, u->overlap_size * sizeof(float)); //overlap preserve (debug)
490 //zero out the bit beyond the real overlap so we don't add garbage next iteration
491 memset(overlap + u->overlap_size, 0, overlap_size - u->overlap_size);
492
493 ////debug: tests if basic buffering works
494 ////shouldn't modify the signal AT ALL (beyond roundoff)
495 //for(size_t j = 0; j < u->window_size; ++j) {
496 // dst[j] = src[j];
497 //}
498
499 //preserve the needed input for the next window's overlap
500 memmove(src, src + u->R,
501 (u->samples_gathered - u->R) * sizeof(float)
502 );
503 }
504 #endif
505
506 static void flatten_to_memblockq(struct userdata *u) {
507 size_t mbs = pa_mempool_block_size_max(u->sink->core->mempool);
508 pa_memchunk tchunk;
509 char *dst;
510 size_t i = 0;
511 while(i < u->output_buffer_length) {
512 tchunk.index = 0;
513 tchunk.length = PA_MIN((u->output_buffer_length - i), mbs);
514 tchunk.memblock = pa_memblock_new(u->sink->core->mempool, tchunk.length);
515 //pa_log_debug("pushing %ld into the q", tchunk.length);
516 dst = pa_memblock_acquire(tchunk.memblock);
517 memcpy(dst, u->output_buffer + i, tchunk.length);
518 pa_memblock_release(tchunk.memblock);
519 pa_memblockq_push(u->output_q, &tchunk);
520 pa_memblock_unref(tchunk.memblock);
521 i += tchunk.length;
522 }
523 }
524
525 static void process_samples(struct userdata *u) {
526 size_t fs = pa_frame_size(&(u->sink->sample_spec));
527 unsigned a_i;
528 float *H, X;
529 size_t iterations, offset;
530 pa_assert(u->samples_gathered >= u->window_size);
531 iterations = (u->samples_gathered - u->overlap_size) / u->R;
532 //make sure there is enough buffer memory allocated
533 if (iterations * u->R * fs > u->output_buffer_max_length) {
534 u->output_buffer_max_length = iterations * u->R * fs;
535 pa_xfree(u->output_buffer);
536 u->output_buffer = pa_xmalloc(u->output_buffer_max_length);
537 }
538 u->output_buffer_length = iterations * u->R * fs;
539
540 for(size_t iter = 0; iter < iterations; ++iter) {
541 offset = iter * u->R * fs;
542 for(size_t c = 0;c < u->channels; c++) {
543 a_i = pa_aupdate_read_begin(u->a_H[c]);
544 X = u->Xs[c][a_i];
545 H = u->Hs[c][a_i];
546 dsp_logic(
547 u->work_buffer,
548 u->input[c],
549 u->overlap_accum[c],
550 X,
551 H,
552 u->W,
553 u->output_window,
554 u
555 );
556 pa_aupdate_read_end(u->a_H[c]);
557 if (u->first_iteration) {
558 /* The windowing function will make the audio ramped in, as a cheap fix we can
559 * undo the windowing (for non-zero window values)
560 */
561 for(size_t i = 0; i < u->overlap_size; ++i) {
562 u->work_buffer[i] = u->W[i] <= FLT_EPSILON ? u->work_buffer[i] : u->work_buffer[i] / u->W[i];
563 }
564 }
565 pa_sample_clamp(PA_SAMPLE_FLOAT32NE, (uint8_t *) (((float *)u->output_buffer) + c) + offset, fs, u->work_buffer, sizeof(float), u->R);
566 }
567 if (u->first_iteration) {
568 u->first_iteration = FALSE;
569 }
570 u->samples_gathered -= u->R;
571 }
572 flatten_to_memblockq(u);
573 }
574
575 static void input_buffer(struct userdata *u, pa_memchunk *in) {
576 size_t fs = pa_frame_size(&(u->sink->sample_spec));
577 size_t samples = in->length/fs;
578 float *src = pa_memblock_acquire_chunk(in);
579 pa_assert(u->samples_gathered + samples <= u->input_buffer_max);
580 for(size_t c = 0; c < u->channels; c++) {
581 //buffer with an offset after the overlap from previous
582 //iterations
583 pa_assert_se(
584 u->input[c] + u->samples_gathered + samples <= u->input[c] + u->input_buffer_max
585 );
586 pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c] + u->samples_gathered, sizeof(float), src + c, fs, samples);
587 }
588 u->samples_gathered += samples;
589 pa_memblock_release(in->memblock);
590 }
591
592 /* Called from I/O thread context */
593 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
594 struct userdata *u;
595 size_t fs, target_samples;
596 size_t mbs;
597 //struct timeval start, end;
598 pa_memchunk tchunk;
599
600 pa_sink_input_assert_ref(i);
601 pa_assert_se(u = i->userdata);
602 pa_assert(chunk);
603 pa_assert(u->sink);
604
605 /* FIXME: Please clean this up. I see more commented code lines
606 * than uncommented code lines. I am sorry, but I am too dumb to
607 * understand this. */
608
609 fs = pa_frame_size(&(u->sink->sample_spec));
610 mbs = pa_mempool_block_size_max(u->sink->core->mempool);
611 if (pa_memblockq_get_length(u->output_q) > 0) {
612 //pa_log_debug("qsize is %ld", pa_memblockq_get_length(u->output_q));
613 goto END;
614 }
615 //nbytes = PA_MIN(nbytes, pa_mempool_block_size_max(u->sink->core->mempool));
616 target_samples = PA_ROUND_UP(nbytes / fs, u->R);
617 ////pa_log_debug("vanilla mbs = %ld",mbs);
618 //mbs = PA_ROUND_DOWN(mbs / fs, u->R);
619 //mbs = PA_MAX(mbs, u->R);
620 //target_samples = PA_MAX(target_samples, mbs);
621 //pa_log_debug("target samples: %ld", target_samples);
622 if (u->first_iteration) {
623 //allocate request_size
624 target_samples = PA_MAX(target_samples, u->window_size);
625 }else{
626 //allocate request_size + overlap
627 target_samples += u->overlap_size;
628 }
629 alloc_input_buffers(u, target_samples);
630 //pa_log_debug("post target samples: %ld", target_samples);
631 chunk->memblock = NULL;
632
633 /* Hmm, process any rewind request that might be queued up */
634 pa_sink_process_rewind(u->sink, 0);
635
636 //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);
637 //pa_rtclock_get(&start);
638 do{
639 size_t input_remaining = target_samples - u->samples_gathered;
640 // pa_log_debug("input remaining %ld samples", input_remaining);
641 pa_assert(input_remaining > 0);
642 while (pa_memblockq_peek(u->input_q, &tchunk) < 0) {
643 //pa_sink_render(u->sink, input_remaining * fs, &tchunk);
644 pa_sink_render_full(u->sink, PA_MIN(input_remaining * fs, mbs), &tchunk);
645 pa_memblockq_push(u->input_q, &tchunk);
646 pa_memblock_unref(tchunk.memblock);
647 }
648 pa_assert(tchunk.memblock);
649
650 tchunk.length = PA_MIN(input_remaining * fs, tchunk.length);
651
652 pa_memblockq_drop(u->input_q, tchunk.length);
653 //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);
654 /* copy new input */
655 //pa_rtclock_get(start);
656 // pa_log_debug("buffering %ld bytes", tchunk.length);
657 input_buffer(u, &tchunk);
658 //pa_rtclock_get(&end);
659 //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);
660 pa_memblock_unref(tchunk.memblock);
661 } while(u->samples_gathered < target_samples);
662
663 //pa_rtclock_get(&end);
664 //pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC);
665
666 pa_assert(u->fft_size >= u->window_size);
667 pa_assert(u->R < u->window_size);
668 //pa_rtclock_get(&start);
669 /* process a block */
670 process_samples(u);
671 //pa_rtclock_get(&end);
672 //pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC);
673 END:
674 pa_assert_se(pa_memblockq_peek(u->output_q, chunk) >= 0);
675 pa_assert(chunk->memblock);
676 pa_memblockq_drop(u->output_q, chunk->length);
677
678 /** FIXME: Uh? you need to unref the chunk here! */
679
680 //pa_log_debug("gave %ld", chunk->length/fs);
681 //pa_log_debug("end pop");
682 return 0;
683 }
684
685 /* Called from main context */
686 static void sink_input_volume_changed_cb(pa_sink_input *i) {
687 struct userdata *u;
688
689 pa_sink_input_assert_ref(i);
690 pa_assert_se(u = i->userdata);
691
692 pa_sink_volume_changed(u->sink, &i->volume);
693 }
694
695 /* Called from main context */
696 static void sink_input_mute_changed_cb(pa_sink_input *i) {
697 struct userdata *u;
698
699 pa_sink_input_assert_ref(i);
700 pa_assert_se(u = i->userdata);
701
702 pa_sink_mute_changed(u->sink, i->muted);
703 }
704
705 #if 0
706 static void reset_filter(struct userdata *u) {
707 size_t fs = pa_frame_size(&u->sink->sample_spec);
708 size_t max_request;
709
710 u->samples_gathered = 0;
711
712 for(size_t i = 0; i < u->channels; ++i)
713 pa_memzero(u->overlap_accum[i], u->overlap_size * sizeof(float));
714
715 u->first_iteration = TRUE;
716 //set buffer size to max request, no overlap copy
717 max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs , u->R);
718 max_request = PA_MAX(max_request, u->window_size);
719 pa_sink_set_max_request_within_thread(u->sink, max_request * fs);
720 }
721 #endif
722
723 /* Called from I/O thread context */
724 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
725 struct userdata *u;
726 size_t amount = 0;
727
728 pa_log_debug("Rewind callback!");
729 pa_sink_input_assert_ref(i);
730 pa_assert_se(u = i->userdata);
731
732 if (u->sink->thread_info.rewind_nbytes > 0) {
733 size_t max_rewrite;
734
735 //max_rewrite = nbytes;
736 max_rewrite = nbytes + pa_memblockq_get_length(u->input_q);
737 //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes);
738 amount = PA_MIN(u->sink->thread_info.rewind_nbytes, max_rewrite);
739 u->sink->thread_info.rewind_nbytes = 0;
740
741 if (amount > 0) {
742 //invalidate the output q
743 pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
744 pa_log("Resetting filter");
745 //reset_filter(u); //this is the "proper" thing to do...
746 }
747 }
748
749 pa_sink_process_rewind(u->sink, amount);
750 pa_memblockq_rewind(u->input_q, nbytes);
751 }
752
753 /* Called from I/O thread context */
754 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
755 struct userdata *u;
756
757 pa_sink_input_assert_ref(i);
758 pa_assert_se(u = i->userdata);
759
760 /* FIXME: Too small max_rewind:
761 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
762 pa_memblockq_set_maxrewind(u->input_q, nbytes);
763 pa_sink_set_max_rewind_within_thread(u->sink, nbytes);
764 }
765
766 /* Called from I/O thread context */
767 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
768 struct userdata *u;
769 size_t fs;
770
771 pa_sink_input_assert_ref(i);
772 pa_assert_se(u = i->userdata);
773
774 fs = pa_frame_size(&u->sink_input->sample_spec);
775 pa_sink_set_max_request_within_thread(u->sink, PA_ROUND_UP(nbytes / fs, u->R) * fs);
776 }
777
778 /* Called from I/O thread context */
779 static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
780 struct userdata *u;
781
782 pa_sink_input_assert_ref(i);
783 pa_assert_se(u = i->userdata);
784
785 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
786 }
787
788 /* Called from I/O thread context */
789 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) {
790 struct userdata *u;
791
792 pa_sink_input_assert_ref(i);
793 pa_assert_se(u = i->userdata);
794
795 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
796 }
797
798 /* Called from I/O thread context */
799 static void sink_input_detach_cb(pa_sink_input *i) {
800 struct userdata *u;
801
802 pa_sink_input_assert_ref(i);
803 pa_assert_se(u = i->userdata);
804
805 pa_sink_detach_within_thread(u->sink);
806
807 pa_sink_set_rtpoll(u->sink, NULL);
808 }
809
810 /* Called from I/O thread context */
811 static void sink_input_attach_cb(pa_sink_input *i) {
812 struct userdata *u;
813 size_t fs, max_request;
814
815 pa_sink_input_assert_ref(i);
816 pa_assert_se(u = i->userdata);
817
818 pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll);
819 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
820 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
821
822 fs = pa_frame_size(&u->sink_input->sample_spec);
823 /* set buffer size to max request, no overlap copy */
824 max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs, u->R);
825 max_request = PA_MAX(max_request, u->window_size);
826
827 pa_sink_set_max_request_within_thread(u->sink, max_request * fs);
828
829 /* FIXME: Too small max_rewind:
830 * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */
831 pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i));
832
833 pa_sink_attach_within_thread(u->sink);
834 }
835
836 /* Called from main context */
837 static void sink_input_kill_cb(pa_sink_input *i) {
838 struct userdata *u;
839
840 pa_sink_input_assert_ref(i);
841 pa_assert_se(u = i->userdata);
842
843 /* The order here matters! We first kill the sink input, followed
844 * by the sink. That means the sink callbacks must be protected
845 * against an unconnected sink input! */
846 pa_sink_input_unlink(u->sink_input);
847 pa_sink_unlink(u->sink);
848
849 pa_sink_input_unref(u->sink_input);
850 u->sink_input = NULL;
851
852 /* Leave u->sink alone for now, it will be cleaned up on module
853 * unload (and it is needed during unload as well). */
854
855 pa_module_unload_request(u->module, TRUE);
856 }
857
858 /* Called from IO thread context */
859 static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) {
860 struct userdata *u;
861
862 pa_sink_input_assert_ref(i);
863 pa_assert_se(u = i->userdata);
864
865 /* If we are added for the first time, ask for a rewinding so that
866 * we are heard right-away. */
867 if (PA_SINK_INPUT_IS_LINKED(state) &&
868 i->thread_info.state == PA_SINK_INPUT_INIT) {
869 pa_log_debug("Requesting rewind due to state change.");
870 pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
871 }
872 }
873
874 static void pack(char **strs, size_t len, char **packed, size_t *length) {
875 size_t t_len = 0;
876 size_t headers = (1+len) * sizeof(uint16_t);
877 char *p;
878 for(size_t i = 0; i < len; ++i) {
879 t_len += strlen(strs[i]);
880 }
881 *length = headers + t_len;
882 p = *packed = pa_xmalloc0(*length);
883 *((uint16_t *) p) = (uint16_t) len;
884 p += sizeof(uint16_t);
885 for(size_t i = 0; i < len; ++i) {
886 uint16_t l = strlen(strs[i]);
887 *((uint16_t *) p) = (uint16_t) l;
888 p += sizeof(uint16_t);
889 memcpy(p, strs[i], l);
890 p += l;
891 }
892 }
893 static void unpack(char *str, size_t length, char ***strs, size_t *len) {
894 char *p = str;
895 *len = *((uint16_t *) p);
896 p += sizeof(uint16_t);
897 *strs = pa_xnew(char *, *len);
898
899 for(size_t i = 0; i < *len; ++i) {
900 size_t l = *((uint16_t *) p);
901 p += sizeof(uint16_t);
902 (*strs)[i] = pa_xnew(char, l + 1);
903 memcpy((*strs)[i], p, l);
904 (*strs)[i][l] = '\0';
905 p += l;
906 }
907 }
908 static void save_profile(struct userdata *u, size_t channel, char *name) {
909 unsigned a_i;
910 const size_t profile_size = CHANNEL_PROFILE_SIZE(u) * sizeof(float);
911 float *H_n, *profile;
912 const float *H;
913 pa_datum key, data;
914 profile = pa_xnew0(float, profile_size);
915 a_i = pa_aupdate_read_begin(u->a_H[channel]);
916 profile[0] = u->Xs[a_i][channel];
917 H = u->Hs[channel][a_i];
918 H_n = profile + 1;
919 for(size_t i = 0 ; i < FILTER_SIZE(u); ++i) {
920 H_n[i] = H[i] * u->fft_size;
921 //H_n[i] = H[i];
922 }
923 pa_aupdate_read_end(u->a_H[channel]);
924 key.data=name;
925 key.size = strlen(key.data);
926 data.data = profile;
927 data.size = profile_size;
928 pa_database_set(u->database, &key, &data, TRUE);
929 pa_database_sync(u->database);
930 if (u->base_profiles[channel]) {
931 pa_xfree(u->base_profiles[channel]);
932 }
933 u->base_profiles[channel] = pa_xstrdup(name);
934 }
935
936 static void save_state(struct userdata *u) {
937 unsigned a_i;
938 const size_t filter_state_size = FILTER_STATE_SIZE(u) * sizeof(float);
939 float *H_n, *state;
940 float *H;
941 pa_datum key, data;
942 pa_database *database;
943 char *dbname;
944 char *packed;
945 size_t packed_length;
946
947 pack(u->base_profiles, u->channels, &packed, &packed_length);
948 state = (float *) pa_xmalloc0(filter_state_size + packed_length);
949 memcpy(state + FILTER_STATE_SIZE(u), packed, packed_length);
950 pa_xfree(packed);
951
952 for(size_t c = 0; c < u->channels; ++c) {
953 a_i = pa_aupdate_read_begin(u->a_H[c]);
954 state[c * CHANNEL_PROFILE_SIZE(u)] = u->Xs[c][a_i];
955 H = u->Hs[c][a_i];
956 H_n = &state[c * CHANNEL_PROFILE_SIZE(u) + 1];
957 memcpy(H_n, H, FILTER_SIZE(u) * sizeof(float));
958 pa_aupdate_read_end(u->a_H[c]);
959 }
960
961 key.data = u->sink->name;
962 key.size = strlen(key.data);
963 data.data = state;
964 data.size = filter_state_size + packed_length;
965 //thread safety for 0.9.17?
966 pa_assert_se(dbname = pa_state_path(EQ_STATE_DB, FALSE));
967 pa_assert_se(database = pa_database_open(dbname, TRUE));
968 pa_xfree(dbname);
969
970 pa_database_set(database, &key, &data, TRUE);
971 pa_database_sync(database);
972 pa_database_close(database);
973 pa_xfree(state);
974 }
975
976 static void remove_profile(pa_core *c, char *name) {
977 pa_datum key;
978 pa_database *database;
979 key.data = name;
980 key.size = strlen(key.data);
981 pa_assert_se(database = pa_shared_get(c, EQDB));
982 pa_database_unset(database, &key);
983 pa_database_sync(database);
984 }
985
986 static const char* load_profile(struct userdata *u, size_t channel, char *name) {
987 unsigned a_i;
988 pa_datum key, value;
989 const size_t profile_size = CHANNEL_PROFILE_SIZE(u) * sizeof(float);
990 key.data = name;
991 key.size = strlen(key.data);
992 if (pa_database_get(u->database, &key, &value) != NULL) {
993 if (value.size == profile_size) {
994 float *profile = (float *) value.data;
995 a_i = pa_aupdate_write_begin(u->a_H[channel]);
996 u->Xs[channel][a_i] = profile[0];
997 memcpy(u->Hs[channel][a_i], profile + 1, FILTER_SIZE(u) * sizeof(float));
998 fix_filter(u->Hs[channel][a_i], u->fft_size);
999 pa_aupdate_write_end(u->a_H[channel]);
1000 pa_xfree(u->base_profiles[channel]);
1001 u->base_profiles[channel] = pa_xstrdup(name);
1002 }else{
1003 return "incompatible size";
1004 }
1005 pa_datum_free(&value);
1006 }else{
1007 return "profile doesn't exist";
1008 }
1009 return NULL;
1010 }
1011
1012 static void load_state(struct userdata *u) {
1013 unsigned a_i;
1014 float *H;
1015 pa_datum key, value;
1016 pa_database *database;
1017 char *dbname;
1018 pa_assert_se(dbname = pa_state_path(EQ_STATE_DB, FALSE));
1019 database = pa_database_open(dbname, FALSE);
1020 pa_xfree(dbname);
1021 if (!database) {
1022 pa_log("No resume state");
1023 return;
1024 }
1025
1026 key.data = u->sink->name;
1027 key.size = strlen(key.data);
1028
1029 if (pa_database_get(database, &key, &value) != NULL) {
1030 if (value.size > FILTER_STATE_SIZE(u) * sizeof(float) + sizeof(uint16_t)) {
1031 float *state = (float *) value.data;
1032 size_t n_profs;
1033 char **names;
1034 for(size_t c = 0; c < u->channels; ++c) {
1035 a_i = pa_aupdate_write_begin(u->a_H[c]);
1036 H = state + c * CHANNEL_PROFILE_SIZE(u) + 1;
1037 u->Xs[c][a_i] = state[c * CHANNEL_PROFILE_SIZE(u)];
1038 memcpy(u->Hs[c][a_i], H, FILTER_SIZE(u) * sizeof(float));
1039 pa_aupdate_write_end(u->a_H[c]);
1040 }
1041 unpack(((char *)value.data) + FILTER_STATE_SIZE(u) * sizeof(float), value.size - FILTER_STATE_SIZE(u) * sizeof(float), &names, &n_profs);
1042 n_profs = PA_MIN(n_profs, u->channels);
1043 for(size_t c = 0; c < n_profs; ++c) {
1044 pa_xfree(u->base_profiles[c]);
1045 u->base_profiles[c] = names[c];
1046 }
1047 pa_xfree(names);
1048 }
1049 pa_datum_free(&value);
1050 }else{
1051 pa_log("resume state exists but is wrong size!");
1052 }
1053 pa_database_close(database);
1054 }
1055
1056 /* Called from main context */
1057 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
1058 struct userdata *u;
1059
1060 pa_sink_input_assert_ref(i);
1061 pa_assert_se(u = i->userdata);
1062
1063 if (u->autoloaded)
1064 return FALSE;
1065
1066 return u->sink != dest;
1067 }
1068
1069 /* Called from main context */
1070 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
1071 struct userdata *u;
1072
1073 pa_sink_input_assert_ref(i);
1074 pa_assert_se(u = i->userdata);
1075
1076 if (dest) {
1077 pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq);
1078 pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);
1079 } else
1080 pa_sink_set_asyncmsgq(u->sink, NULL);
1081 }
1082
1083 int pa__init(pa_module*m) {
1084 struct userdata *u;
1085 pa_sample_spec ss;
1086 pa_channel_map map;
1087 pa_modargs *ma;
1088 const char *z;
1089 pa_sink *master;
1090 pa_sink_input_new_data sink_input_data;
1091 pa_sink_new_data sink_data;
1092 size_t i;
1093 unsigned c;
1094 float *H;
1095 unsigned a_i;
1096 pa_bool_t use_volume_sharing = TRUE;
1097
1098 pa_assert(m);
1099
1100 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1101 pa_log("Failed to parse module arguments.");
1102 goto fail;
1103 }
1104
1105 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink_master", NULL), PA_NAMEREG_SINK))) {
1106 pa_log("Master sink not found");
1107 goto fail;
1108 }
1109
1110 ss = master->sample_spec;
1111 ss.format = PA_SAMPLE_FLOAT32;
1112 map = master->channel_map;
1113 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
1114 pa_log("Invalid sample format specification or channel map");
1115 goto fail;
1116 }
1117
1118 //fs = pa_frame_size(&ss);
1119
1120 if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) {
1121 pa_log("use_volume_sharing= expects a boolean argument");
1122 goto fail;
1123 }
1124
1125 u = pa_xnew0(struct userdata, 1);
1126 u->module = m;
1127 m->userdata = u;
1128
1129 u->channels = ss.channels;
1130 u->fft_size = pow(2, ceil(log(ss.rate) / log(2)));//probably unstable near corner cases of powers of 2
1131 pa_log_debug("fft size: %zd", u->fft_size);
1132 u->window_size = 15999;
1133 if (u->window_size % 2 == 0)
1134 u->window_size--;
1135 u->R = (u->window_size + 1) / 2;
1136 u->overlap_size = u->window_size - u->R;
1137 u->samples_gathered = 0;
1138 u->input_buffer_max = 0;
1139
1140 u->a_H = pa_xnew0(pa_aupdate *, u->channels);
1141 u->Xs = pa_xnew0(float *, u->channels);
1142 u->Hs = pa_xnew0(float **, u->channels);
1143
1144 for (c = 0; c < u->channels; ++c) {
1145 u->Xs[c] = pa_xnew0(float, 2);
1146 u->Hs[c] = pa_xnew0(float *, 2);
1147 for (i = 0; i < 2; ++i)
1148 u->Hs[c][i] = alloc(FILTER_SIZE(u), sizeof(float));
1149 }
1150
1151 u->W = alloc(u->window_size, sizeof(float));
1152 u->work_buffer = alloc(u->fft_size, sizeof(float));
1153 u->input = pa_xnew0(float *, u->channels);
1154 u->overlap_accum = pa_xnew0(float *, u->channels);
1155 for (c = 0; c < u->channels; ++c) {
1156 u->a_H[c] = pa_aupdate_new();
1157 u->input[c] = NULL;
1158 u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float));
1159 }
1160 u->output_window = alloc(FILTER_SIZE(u), sizeof(fftwf_complex));
1161 u->forward_plan = fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE);
1162 u->inverse_plan = fftwf_plan_dft_c2r_1d(u->fft_size, u->output_window, u->work_buffer, FFTW_ESTIMATE);
1163
1164 hanning_window(u->W, u->window_size);
1165 u->first_iteration = TRUE;
1166
1167 u->base_profiles = pa_xnew0(char *, u->channels);
1168 for (c = 0; c < u->channels; ++c)
1169 u->base_profiles[c] = pa_xstrdup("default");
1170
1171 /* Create sink */
1172 pa_sink_new_data_init(&sink_data);
1173 sink_data.driver = __FILE__;
1174 sink_data.module = m;
1175 if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL))))
1176 sink_data.name = pa_sprintf_malloc("%s.equalizer", master->name);
1177 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
1178 pa_sink_new_data_set_channel_map(&sink_data, &map);
1179
1180 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
1181 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "FFT based equalizer on %s", z ? z : master->name);
1182
1183 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
1184 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
1185
1186 if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
1187 pa_log("Invalid properties");
1188 pa_sink_new_data_done(&sink_data);
1189 goto fail;
1190 }
1191
1192 u->autoloaded = DEFAULT_AUTOLOADED;
1193 if (pa_modargs_get_value_boolean(ma, "autoloaded", &u->autoloaded) < 0) {
1194 pa_log("Failed to parse autoloaded value");
1195 goto fail;
1196 }
1197
1198 u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY))
1199 | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0));
1200 pa_sink_new_data_done(&sink_data);
1201
1202 if (!u->sink) {
1203 pa_log("Failed to create sink.");
1204 goto fail;
1205 }
1206
1207 u->sink->parent.process_msg = sink_process_msg_cb;
1208 u->sink->set_state = sink_set_state_cb;
1209 u->sink->update_requested_latency = sink_update_requested_latency_cb;
1210 u->sink->request_rewind = sink_request_rewind_cb;
1211 pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb);
1212 if (!use_volume_sharing) {
1213 pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
1214 pa_sink_enable_decibel_volume(u->sink, TRUE);
1215 }
1216 u->sink->userdata = u;
1217
1218 u->input_q = pa_memblockq_new("module-equalizer-sink input_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &u->sink->silence);
1219 u->output_q = pa_memblockq_new("module-equalizer-sink output_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL);
1220 u->output_buffer = NULL;
1221 u->output_buffer_length = 0;
1222 u->output_buffer_max_length = 0;
1223
1224 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
1225 //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss));
1226
1227 /* Create sink input */
1228 pa_sink_input_new_data_init(&sink_input_data);
1229 sink_input_data.driver = __FILE__;
1230 sink_input_data.module = m;
1231 pa_sink_input_new_data_set_sink(&sink_input_data, master, FALSE);
1232 sink_input_data.origin_sink = u->sink;
1233 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Equalized Stream");
1234 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
1235 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
1236 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
1237
1238 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data);
1239 pa_sink_input_new_data_done(&sink_input_data);
1240
1241 if (!u->sink_input)
1242 goto fail;
1243
1244 u->sink_input->pop = sink_input_pop_cb;
1245 u->sink_input->process_rewind = sink_input_process_rewind_cb;
1246 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
1247 u->sink_input->update_max_request = sink_input_update_max_request_cb;
1248 u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
1249 u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb;
1250 u->sink_input->kill = sink_input_kill_cb;
1251 u->sink_input->attach = sink_input_attach_cb;
1252 u->sink_input->detach = sink_input_detach_cb;
1253 u->sink_input->state_change = sink_input_state_change_cb;
1254 u->sink_input->may_move_to = sink_input_may_move_to_cb;
1255 u->sink_input->moving = sink_input_moving_cb;
1256 if (!use_volume_sharing)
1257 u->sink_input->volume_changed = sink_input_volume_changed_cb;
1258 u->sink_input->mute_changed = sink_input_mute_changed_cb;
1259 u->sink_input->userdata = u;
1260
1261 u->sink->input_to_master = u->sink_input;
1262
1263 dbus_init(u);
1264
1265 /* default filter to these */
1266 for (c = 0; c< u->channels; ++c) {
1267 a_i = pa_aupdate_write_begin(u->a_H[c]);
1268 H = u->Hs[c][a_i];
1269 u->Xs[c][a_i] = 1.0f;
1270
1271 for(i = 0; i < FILTER_SIZE(u); ++i)
1272 H[i] = 1.0 / sqrtf(2.0f);
1273
1274 fix_filter(H, u->fft_size);
1275 pa_aupdate_write_end(u->a_H[c]);
1276 }
1277
1278 /* load old parameters */
1279 load_state(u);
1280
1281 pa_sink_put(u->sink);
1282 pa_sink_input_put(u->sink_input);
1283
1284 pa_modargs_free(ma);
1285
1286 return 0;
1287
1288 fail:
1289 if (ma)
1290 pa_modargs_free(ma);
1291
1292 pa__done(m);
1293
1294 return -1;
1295 }
1296
1297 int pa__get_n_used(pa_module *m) {
1298 struct userdata *u;
1299
1300 pa_assert(m);
1301 pa_assert_se(u = m->userdata);
1302
1303 return pa_sink_linked_by(u->sink);
1304 }
1305
1306 void pa__done(pa_module*m) {
1307 struct userdata *u;
1308 unsigned c;
1309
1310 pa_assert(m);
1311
1312 if (!(u = m->userdata))
1313 return;
1314
1315 save_state(u);
1316
1317 dbus_done(u);
1318
1319 for(c = 0; c < u->channels; ++c)
1320 pa_xfree(u->base_profiles[c]);
1321 pa_xfree(u->base_profiles);
1322
1323 /* See comments in sink_input_kill_cb() above regarding
1324 * destruction order! */
1325
1326 if (u->sink_input)
1327 pa_sink_input_unlink(u->sink_input);
1328
1329 if (u->sink)
1330 pa_sink_unlink(u->sink);
1331
1332 if (u->sink_input)
1333 pa_sink_input_unref(u->sink_input);
1334
1335 if (u->sink)
1336 pa_sink_unref(u->sink);
1337
1338 pa_xfree(u->output_buffer);
1339 pa_memblockq_free(u->output_q);
1340 pa_memblockq_free(u->input_q);
1341
1342 fftwf_destroy_plan(u->inverse_plan);
1343 fftwf_destroy_plan(u->forward_plan);
1344 pa_xfree(u->output_window);
1345 for (c = 0; c < u->channels; ++c) {
1346 pa_aupdate_free(u->a_H[c]);
1347 pa_xfree(u->overlap_accum[c]);
1348 pa_xfree(u->input[c]);
1349 }
1350 pa_xfree(u->a_H);
1351 pa_xfree(u->overlap_accum);
1352 pa_xfree(u->input);
1353 pa_xfree(u->work_buffer);
1354 pa_xfree(u->W);
1355 for (c = 0; c < u->channels; ++c) {
1356 pa_xfree(u->Xs[c]);
1357 for (size_t i = 0; i < 2; ++i)
1358 pa_xfree(u->Hs[c][i]);
1359 pa_xfree(u->Hs[c]);
1360 }
1361 pa_xfree(u->Xs);
1362 pa_xfree(u->Hs);
1363
1364 pa_xfree(u);
1365 }
1366
1367 /*
1368 * DBus Routines and Callbacks
1369 */
1370 #define EXTNAME "org.PulseAudio.Ext.Equalizing1"
1371 #define MANAGER_PATH "/org/pulseaudio/equalizing1"
1372 #define MANAGER_IFACE EXTNAME ".Manager"
1373 #define EQUALIZER_IFACE EXTNAME ".Equalizer"
1374 static void manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u);
1375 static void manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u);
1376 static void manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u);
1377 static void manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u);
1378 static void manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1379 static void equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u);
1380 static void equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u);
1381 static void equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u);
1382 static void equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u);
1383 static void equalizer_get_n_channels(DBusConnection *conn, DBusMessage *msg, void *_u);
1384 static void equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u);
1385 static void equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1386 static void equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u);
1387 static void equalizer_handle_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1388 static void equalizer_handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1389 static void equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1390 static void equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1391 static void equalizer_handle_save_state(DBusConnection *conn, DBusMessage *msg, void *_u);
1392 static void equalizer_handle_get_profile_name(DBusConnection *conn, DBusMessage *msg, void *_u);
1393 enum manager_method_index {
1394 MANAGER_METHOD_REMOVE_PROFILE,
1395 MANAGER_METHOD_MAX
1396 };
1397
1398 pa_dbus_arg_info remove_profile_args[]={
1399 {"name", "s","in"},
1400 };
1401
1402 static pa_dbus_method_handler manager_methods[MANAGER_METHOD_MAX]={
1403 [MANAGER_METHOD_REMOVE_PROFILE]={
1404 .method_name="RemoveProfile",
1405 .arguments=remove_profile_args,
1406 .n_arguments=sizeof(remove_profile_args)/sizeof(pa_dbus_arg_info),
1407 .receive_cb=manager_handle_remove_profile}
1408 };
1409
1410 enum manager_handler_index {
1411 MANAGER_HANDLER_REVISION,
1412 MANAGER_HANDLER_EQUALIZED_SINKS,
1413 MANAGER_HANDLER_PROFILES,
1414 MANAGER_HANDLER_MAX
1415 };
1416
1417 static pa_dbus_property_handler manager_handlers[MANAGER_HANDLER_MAX]={
1418 [MANAGER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=manager_get_revision,.set_cb=NULL},
1419 [MANAGER_HANDLER_EQUALIZED_SINKS]={.property_name="EqualizedSinks",.type="ao",.get_cb=manager_get_sinks,.set_cb=NULL},
1420 [MANAGER_HANDLER_PROFILES]={.property_name="Profiles",.type="as",.get_cb=manager_get_profiles,.set_cb=NULL}
1421 };
1422
1423 pa_dbus_arg_info sink_args[]={
1424 {"sink", "o", NULL}
1425 };
1426
1427 enum manager_signal_index{
1428 MANAGER_SIGNAL_SINK_ADDED,
1429 MANAGER_SIGNAL_SINK_REMOVED,
1430 MANAGER_SIGNAL_PROFILES_CHANGED,
1431 MANAGER_SIGNAL_MAX
1432 };
1433
1434 static pa_dbus_signal_info manager_signals[MANAGER_SIGNAL_MAX]={
1435 [MANAGER_SIGNAL_SINK_ADDED]={.name="SinkAdded", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)},
1436 [MANAGER_SIGNAL_SINK_REMOVED]={.name="SinkRemoved", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)},
1437 [MANAGER_SIGNAL_PROFILES_CHANGED]={.name="ProfilesChanged", .arguments=NULL, .n_arguments=0}
1438 };
1439
1440 static pa_dbus_interface_info manager_info={
1441 .name=MANAGER_IFACE,
1442 .method_handlers=manager_methods,
1443 .n_method_handlers=MANAGER_METHOD_MAX,
1444 .property_handlers=manager_handlers,
1445 .n_property_handlers=MANAGER_HANDLER_MAX,
1446 .get_all_properties_cb=manager_get_all,
1447 .signals=manager_signals,
1448 .n_signals=MANAGER_SIGNAL_MAX
1449 };
1450
1451 enum equalizer_method_index {
1452 EQUALIZER_METHOD_FILTER_POINTS,
1453 EQUALIZER_METHOD_SEED_FILTER,
1454 EQUALIZER_METHOD_SAVE_PROFILE,
1455 EQUALIZER_METHOD_LOAD_PROFILE,
1456 EQUALIZER_METHOD_SET_FILTER,
1457 EQUALIZER_METHOD_GET_FILTER,
1458 EQUALIZER_METHOD_SAVE_STATE,
1459 EQUALIZER_METHOD_GET_PROFILE_NAME,
1460 EQUALIZER_METHOD_MAX
1461 };
1462
1463 enum equalizer_handler_index {
1464 EQUALIZER_HANDLER_REVISION,
1465 EQUALIZER_HANDLER_SAMPLERATE,
1466 EQUALIZER_HANDLER_FILTERSAMPLERATE,
1467 EQUALIZER_HANDLER_N_COEFS,
1468 EQUALIZER_HANDLER_N_CHANNELS,
1469 EQUALIZER_HANDLER_MAX
1470 };
1471
1472 pa_dbus_arg_info filter_points_args[]={
1473 {"channel", "u","in"},
1474 {"xs", "au","in"},
1475 {"ys", "ad","out"},
1476 {"preamp", "d","out"}
1477 };
1478 pa_dbus_arg_info seed_filter_args[]={
1479 {"channel", "u","in"},
1480 {"xs", "au","in"},
1481 {"ys", "ad","in"},
1482 {"preamp", "d","in"}
1483 };
1484
1485 pa_dbus_arg_info set_filter_args[]={
1486 {"channel", "u","in"},
1487 {"ys", "ad","in"},
1488 {"preamp", "d","in"}
1489 };
1490 pa_dbus_arg_info get_filter_args[]={
1491 {"channel", "u","in"},
1492 {"ys", "ad","out"},
1493 {"preamp", "d","out"}
1494 };
1495
1496 pa_dbus_arg_info save_profile_args[]={
1497 {"channel", "u","in"},
1498 {"name", "s","in"}
1499 };
1500 pa_dbus_arg_info load_profile_args[]={
1501 {"channel", "u","in"},
1502 {"name", "s","in"}
1503 };
1504 pa_dbus_arg_info base_profile_name_args[]={
1505 {"channel", "u","in"},
1506 {"name", "s","out"}
1507 };
1508
1509 static pa_dbus_method_handler equalizer_methods[EQUALIZER_METHOD_MAX]={
1510 [EQUALIZER_METHOD_SEED_FILTER]={
1511 .method_name="SeedFilter",
1512 .arguments=seed_filter_args,
1513 .n_arguments=sizeof(seed_filter_args)/sizeof(pa_dbus_arg_info),
1514 .receive_cb=equalizer_handle_seed_filter},
1515 [EQUALIZER_METHOD_FILTER_POINTS]={
1516 .method_name="FilterAtPoints",
1517 .arguments=filter_points_args,
1518 .n_arguments=sizeof(filter_points_args)/sizeof(pa_dbus_arg_info),
1519 .receive_cb=equalizer_handle_get_filter_points},
1520 [EQUALIZER_METHOD_SET_FILTER]={
1521 .method_name="SetFilter",
1522 .arguments=set_filter_args,
1523 .n_arguments=sizeof(set_filter_args)/sizeof(pa_dbus_arg_info),
1524 .receive_cb=equalizer_handle_set_filter},
1525 [EQUALIZER_METHOD_GET_FILTER]={
1526 .method_name="GetFilter",
1527 .arguments=get_filter_args,
1528 .n_arguments=sizeof(get_filter_args)/sizeof(pa_dbus_arg_info),
1529 .receive_cb=equalizer_handle_get_filter},
1530 [EQUALIZER_METHOD_SAVE_PROFILE]={
1531 .method_name="SaveProfile",
1532 .arguments=save_profile_args,
1533 .n_arguments=sizeof(save_profile_args)/sizeof(pa_dbus_arg_info),
1534 .receive_cb=equalizer_handle_save_profile},
1535 [EQUALIZER_METHOD_LOAD_PROFILE]={
1536 .method_name="LoadProfile",
1537 .arguments=load_profile_args,
1538 .n_arguments=sizeof(load_profile_args)/sizeof(pa_dbus_arg_info),
1539 .receive_cb=equalizer_handle_load_profile},
1540 [EQUALIZER_METHOD_SAVE_STATE]={
1541 .method_name="SaveState",
1542 .arguments=NULL,
1543 .n_arguments=0,
1544 .receive_cb=equalizer_handle_save_state},
1545 [EQUALIZER_METHOD_GET_PROFILE_NAME]={
1546 .method_name="BaseProfile",
1547 .arguments=base_profile_name_args,
1548 .n_arguments=sizeof(base_profile_name_args)/sizeof(pa_dbus_arg_info),
1549 .receive_cb=equalizer_handle_get_profile_name}
1550 };
1551
1552 static pa_dbus_property_handler equalizer_handlers[EQUALIZER_HANDLER_MAX]={
1553 [EQUALIZER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=equalizer_get_revision,.set_cb=NULL},
1554 [EQUALIZER_HANDLER_SAMPLERATE]={.property_name="SampleRate",.type="u",.get_cb=equalizer_get_sample_rate,.set_cb=NULL},
1555 [EQUALIZER_HANDLER_FILTERSAMPLERATE]={.property_name="FilterSampleRate",.type="u",.get_cb=equalizer_get_filter_rate,.set_cb=NULL},
1556 [EQUALIZER_HANDLER_N_COEFS]={.property_name="NFilterCoefficients",.type="u",.get_cb=equalizer_get_n_coefs,.set_cb=NULL},
1557 [EQUALIZER_HANDLER_N_CHANNELS]={.property_name="NChannels",.type="u",.get_cb=equalizer_get_n_channels,.set_cb=NULL},
1558 };
1559
1560 enum equalizer_signal_index{
1561 EQUALIZER_SIGNAL_FILTER_CHANGED,
1562 EQUALIZER_SIGNAL_SINK_RECONFIGURED,
1563 EQUALIZER_SIGNAL_MAX
1564 };
1565
1566 static pa_dbus_signal_info equalizer_signals[EQUALIZER_SIGNAL_MAX]={
1567 [EQUALIZER_SIGNAL_FILTER_CHANGED]={.name="FilterChanged", .arguments=NULL, .n_arguments=0},
1568 [EQUALIZER_SIGNAL_SINK_RECONFIGURED]={.name="SinkReconfigured", .arguments=NULL, .n_arguments=0},
1569 };
1570
1571 static pa_dbus_interface_info equalizer_info={
1572 .name=EQUALIZER_IFACE,
1573 .method_handlers=equalizer_methods,
1574 .n_method_handlers=EQUALIZER_METHOD_MAX,
1575 .property_handlers=equalizer_handlers,
1576 .n_property_handlers=EQUALIZER_HANDLER_MAX,
1577 .get_all_properties_cb=equalizer_get_all,
1578 .signals=equalizer_signals,
1579 .n_signals=EQUALIZER_SIGNAL_MAX
1580 };
1581
1582 void dbus_init(struct userdata *u) {
1583 uint32_t dummy;
1584 DBusMessage *message = NULL;
1585 pa_idxset *sink_list = NULL;
1586 u->dbus_protocol=pa_dbus_protocol_get(u->sink->core);
1587 u->dbus_path=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u->sink->index);
1588
1589 pa_dbus_protocol_add_interface(u->dbus_protocol, u->dbus_path, &equalizer_info, u);
1590 sink_list = pa_shared_get(u->sink->core, SINKLIST);
1591 u->database = pa_shared_get(u->sink->core, EQDB);
1592 if (sink_list == NULL) {
1593 char *dbname;
1594 sink_list=pa_idxset_new(&pa_idxset_trivial_hash_func, &pa_idxset_trivial_compare_func);
1595 pa_shared_set(u->sink->core, SINKLIST, sink_list);
1596 pa_assert_se(dbname = pa_state_path("equalizer-presets", FALSE));
1597 pa_assert_se(u->database = pa_database_open(dbname, TRUE));
1598 pa_xfree(dbname);
1599 pa_shared_set(u->sink->core, EQDB, u->database);
1600 pa_dbus_protocol_add_interface(u->dbus_protocol, MANAGER_PATH, &manager_info, u->sink->core);
1601 pa_dbus_protocol_register_extension(u->dbus_protocol, EXTNAME);
1602 }
1603 pa_idxset_put(sink_list, u, &dummy);
1604
1605 pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_ADDED].name)));
1606 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID);
1607 pa_dbus_protocol_send_signal(u->dbus_protocol, message);
1608 dbus_message_unref(message);
1609 }
1610
1611 void dbus_done(struct userdata *u) {
1612 pa_idxset *sink_list;
1613 uint32_t dummy;
1614
1615 DBusMessage *message = NULL;
1616 pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_REMOVED].name)));
1617 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID);
1618 pa_dbus_protocol_send_signal(u->dbus_protocol, message);
1619 dbus_message_unref(message);
1620
1621 pa_assert_se(sink_list=pa_shared_get(u->sink->core,SINKLIST));
1622 pa_idxset_remove_by_data(sink_list,u,&dummy);
1623 if (pa_idxset_size(sink_list)==0) {
1624 pa_dbus_protocol_unregister_extension(u->dbus_protocol, EXTNAME);
1625 pa_dbus_protocol_remove_interface(u->dbus_protocol, MANAGER_PATH, manager_info.name);
1626 pa_shared_remove(u->sink->core, EQDB);
1627 pa_database_close(u->database);
1628 pa_shared_remove(u->sink->core, SINKLIST);
1629 pa_xfree(sink_list);
1630 }
1631 pa_dbus_protocol_remove_interface(u->dbus_protocol, u->dbus_path, equalizer_info.name);
1632 pa_xfree(u->dbus_path);
1633 pa_dbus_protocol_unref(u->dbus_protocol);
1634 }
1635
1636 void manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
1637 DBusError error;
1638 pa_core *c = (pa_core *)_u;
1639 DBusMessage *message = NULL;
1640 pa_dbus_protocol *dbus_protocol;
1641 char *name;
1642 pa_assert(conn);
1643 pa_assert(msg);
1644 pa_assert(c);
1645 dbus_error_init(&error);
1646 if (!dbus_message_get_args(msg, &error,
1647 DBUS_TYPE_STRING, &name,
1648 DBUS_TYPE_INVALID)) {
1649 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1650 dbus_error_free(&error);
1651 return;
1652 }
1653 remove_profile(c,name);
1654 pa_dbus_send_empty_reply(conn, msg);
1655
1656 pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name)));
1657 dbus_protocol = pa_dbus_protocol_get(c);
1658 pa_dbus_protocol_send_signal(dbus_protocol, message);
1659 pa_dbus_protocol_unref(dbus_protocol);
1660 dbus_message_unref(message);
1661 }
1662
1663 void manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u) {
1664 uint32_t rev=1;
1665 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev);
1666 }
1667
1668 static void get_sinks(pa_core *u, char ***names, unsigned *n_sinks) {
1669 void *iter = NULL;
1670 struct userdata *sink_u = NULL;
1671 uint32_t dummy;
1672 pa_idxset *sink_list;
1673 pa_assert(u);
1674 pa_assert(names);
1675 pa_assert(n_sinks);
1676
1677 pa_assert_se(sink_list = pa_shared_get(u, SINKLIST));
1678 *n_sinks = (unsigned) pa_idxset_size(sink_list);
1679 *names = *n_sinks > 0 ? pa_xnew0(char *,*n_sinks) : NULL;
1680 for(uint32_t i = 0; i < *n_sinks; ++i) {
1681 sink_u = (struct userdata *) pa_idxset_iterate(sink_list, &iter, &dummy);
1682 (*names)[i] = pa_xstrdup(sink_u->dbus_path);
1683 }
1684 }
1685
1686 void manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u) {
1687 unsigned n;
1688 char **names = NULL;
1689 pa_assert(conn);
1690 pa_assert(msg);
1691 pa_assert(_u);
1692
1693 get_sinks((pa_core *) _u, &names, &n);
1694 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, names, n);
1695 for(unsigned i = 0; i < n; ++i) {
1696 pa_xfree(names[i]);
1697 }
1698 pa_xfree(names);
1699 }
1700
1701 static void get_profiles(pa_core *c, char ***names, unsigned *n) {
1702 char *name;
1703 pa_database *database;
1704 pa_datum key, next_key;
1705 pa_strlist *head=NULL, *iter;
1706 pa_bool_t done;
1707 pa_assert_se(database = pa_shared_get(c, EQDB));
1708
1709 pa_assert(c);
1710 pa_assert(names);
1711 pa_assert(n);
1712 done = !pa_database_first(database, &key, NULL);
1713 *n = 0;
1714 while(!done) {
1715 done = !pa_database_next(database, &key, &next_key, NULL);
1716 name=pa_xmalloc(key.size + 1);
1717 memcpy(name, key.data, key.size);
1718 name[key.size] = '\0';
1719 pa_datum_free(&key);
1720 head = pa_strlist_prepend(head, name);
1721 pa_xfree(name);
1722 key = next_key;
1723 (*n)++;
1724 }
1725 (*names) = *n > 0 ? pa_xnew0(char *, *n) : NULL;
1726 iter=head;
1727 for(unsigned i = 0; i < *n; ++i) {
1728 (*names)[*n - 1 - i] = pa_xstrdup(pa_strlist_data(iter));
1729 iter = pa_strlist_next(iter);
1730 }
1731 pa_strlist_free(head);
1732 }
1733
1734 void manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u) {
1735 char **names;
1736 unsigned n;
1737 pa_assert(conn);
1738 pa_assert(msg);
1739 pa_assert(_u);
1740
1741 get_profiles((pa_core *)_u, &names, &n);
1742 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_STRING, names, n);
1743 for(unsigned i = 0; i < n; ++i) {
1744 pa_xfree(names[i]);
1745 }
1746 pa_xfree(names);
1747 }
1748
1749 void manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u) {
1750 pa_core *c;
1751 char **names = NULL;
1752 unsigned n;
1753 DBusMessage *reply = NULL;
1754 DBusMessageIter msg_iter, dict_iter;
1755 uint32_t rev;
1756 pa_assert(conn);
1757 pa_assert(msg);
1758 pa_assert_se(c = _u);
1759
1760 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1761 dbus_message_iter_init_append(reply, &msg_iter);
1762 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
1763
1764 rev = 1;
1765 pa_dbus_append_basic_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev);
1766
1767 get_sinks(c, &names, &n);
1768 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter,manager_handlers[MANAGER_HANDLER_EQUALIZED_SINKS].property_name, DBUS_TYPE_OBJECT_PATH, names, n);
1769 for(unsigned i = 0; i < n; ++i) {
1770 pa_xfree(names[i]);
1771 }
1772 pa_xfree(names);
1773
1774 get_profiles(c, &names, &n);
1775 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_PROFILES].property_name, DBUS_TYPE_STRING, names, n);
1776 for(unsigned i = 0; i < n; ++i) {
1777 pa_xfree(names[i]);
1778 }
1779 pa_xfree(names);
1780 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1781 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1782 dbus_message_unref(reply);
1783 }
1784
1785 void equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u) {
1786 struct userdata *u = _u;
1787 DBusError error;
1788 DBusMessage *message = NULL;
1789 float *ys;
1790 uint32_t *xs, channel, r_channel;
1791 double *_ys, preamp;
1792 unsigned x_npoints, y_npoints, a_i;
1793 float *H;
1794 pa_bool_t points_good = TRUE;
1795
1796 pa_assert(conn);
1797 pa_assert(msg);
1798 pa_assert(u);
1799
1800 dbus_error_init(&error);
1801
1802 if (!dbus_message_get_args(msg, &error,
1803 DBUS_TYPE_UINT32, &channel,
1804 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints,
1805 DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &_ys, &y_npoints,
1806 DBUS_TYPE_DOUBLE, &preamp,
1807 DBUS_TYPE_INVALID)) {
1808 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1809 dbus_error_free(&error);
1810 return;
1811 }
1812 if (channel > u->channels) {
1813 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
1814 dbus_error_free(&error);
1815 return;
1816 }
1817 for(size_t i = 0; i < x_npoints; ++i) {
1818 if (xs[i] >= FILTER_SIZE(u)) {
1819 points_good = FALSE;
1820 break;
1821 }
1822 }
1823 if (!is_monotonic(xs, x_npoints) || !points_good) {
1824 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs must be monotonic and 0<=x<=%zd", u->fft_size / 2);
1825 dbus_error_free(&error);
1826 return;
1827 }else if (x_npoints != y_npoints || x_npoints < 2 || x_npoints > FILTER_SIZE(u)) {
1828 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs and ys must be the same length and 2<=l<=%zd!", FILTER_SIZE(u));
1829 dbus_error_free(&error);
1830 return;
1831 }else if (xs[0] != 0 || xs[x_npoints - 1] != u->fft_size / 2) {
1832 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs[0] must be 0 and xs[-1]=fft_size/2");
1833 dbus_error_free(&error);
1834 return;
1835 }
1836
1837 ys = pa_xmalloc(x_npoints * sizeof(float));
1838 for(uint32_t i = 0; i < x_npoints; ++i) {
1839 ys[i] = (float) _ys[i];
1840 }
1841 r_channel = channel == u->channels ? 0 : channel;
1842 a_i = pa_aupdate_write_begin(u->a_H[r_channel]);
1843 H = u->Hs[r_channel][a_i];
1844 u->Xs[r_channel][a_i] = preamp;
1845 interpolate(H, FILTER_SIZE(u), xs, ys, x_npoints);
1846 fix_filter(H, u->fft_size);
1847 if (channel == u->channels) {
1848 for(size_t c = 1; c < u->channels; ++c) {
1849 unsigned b_i = pa_aupdate_write_begin(u->a_H[c]);
1850 float *H_p = u->Hs[c][b_i];
1851 u->Xs[c][b_i] = preamp;
1852 memcpy(H_p, H, FILTER_SIZE(u) * sizeof(float));
1853 pa_aupdate_write_end(u->a_H[c]);
1854 }
1855 }
1856 pa_aupdate_write_end(u->a_H[r_channel]);
1857 pa_xfree(ys);
1858
1859
1860 pa_dbus_send_empty_reply(conn, msg);
1861
1862 pa_assert_se((message = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
1863 pa_dbus_protocol_send_signal(u->dbus_protocol, message);
1864 dbus_message_unref(message);
1865 }
1866
1867 void equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u) {
1868 struct userdata *u = (struct userdata *) _u;
1869 uint32_t *xs, channel, r_channel;
1870 double *ys, preamp;
1871 unsigned x_npoints, a_i;
1872 float *H;
1873 pa_bool_t points_good=TRUE;
1874 DBusMessage *reply = NULL;
1875 DBusMessageIter msg_iter;
1876 DBusError error;
1877
1878 pa_assert(conn);
1879 pa_assert(msg);
1880 pa_assert(u);
1881
1882 dbus_error_init(&error);
1883 if (!dbus_message_get_args(msg, &error,
1884 DBUS_TYPE_UINT32, &channel,
1885 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints,
1886 DBUS_TYPE_INVALID)) {
1887 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1888 dbus_error_free(&error);
1889 return;
1890 }
1891 if (channel > u->channels) {
1892 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
1893 dbus_error_free(&error);
1894 return;
1895 }
1896
1897 for(size_t i = 0; i < x_npoints; ++i) {
1898 if (xs[i] >= FILTER_SIZE(u)) {
1899 points_good=FALSE;
1900 break;
1901 }
1902 }
1903
1904 if (x_npoints > FILTER_SIZE(u) || !points_good) {
1905 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs indices/length must be <= %zd!", FILTER_SIZE(u));
1906 dbus_error_free(&error);
1907 return;
1908 }
1909
1910 r_channel = channel == u->channels ? 0 : channel;
1911 ys = pa_xmalloc(x_npoints * sizeof(double));
1912 a_i = pa_aupdate_read_begin(u->a_H[r_channel]);
1913 H = u->Hs[r_channel][a_i];
1914 preamp = u->Xs[r_channel][a_i];
1915 for(uint32_t i = 0; i < x_npoints; ++i) {
1916 ys[i] = H[xs[i]] * u->fft_size;
1917 }
1918 pa_aupdate_read_end(u->a_H[r_channel]);
1919
1920 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1921 dbus_message_iter_init_append(reply, &msg_iter);
1922
1923 pa_dbus_append_basic_array(&msg_iter, DBUS_TYPE_DOUBLE, ys, x_npoints);
1924 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_DOUBLE, &preamp);
1925
1926 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1927 dbus_message_unref(reply);
1928 pa_xfree(ys);
1929 }
1930
1931 static void get_filter(struct userdata *u, size_t channel, double **H_, double *preamp) {
1932 float *H;
1933 unsigned a_i;
1934 size_t r_channel = channel == u->channels ? 0 : channel;
1935 *H_ = pa_xnew0(double, FILTER_SIZE(u));
1936 a_i = pa_aupdate_read_begin(u->a_H[r_channel]);
1937 H = u->Hs[r_channel][a_i];
1938 for(size_t i = 0;i < FILTER_SIZE(u); ++i) {
1939 (*H_)[i] = H[i] * u->fft_size;
1940 }
1941 *preamp = u->Xs[r_channel][a_i];
1942
1943 pa_aupdate_read_end(u->a_H[r_channel]);
1944 }
1945
1946 void equalizer_handle_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u) {
1947 struct userdata *u;
1948 unsigned n_coefs;
1949 uint32_t channel;
1950 double *H_, preamp;
1951 DBusMessage *reply = NULL;
1952 DBusMessageIter msg_iter;
1953 DBusError error;
1954 pa_assert_se(u = (struct userdata *) _u);
1955 pa_assert(conn);
1956 pa_assert(msg);
1957
1958 dbus_error_init(&error);
1959 if (!dbus_message_get_args(msg, &error,
1960 DBUS_TYPE_UINT32, &channel,
1961 DBUS_TYPE_INVALID)) {
1962 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1963 dbus_error_free(&error);
1964 return;
1965 }
1966 if (channel > u->channels) {
1967 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
1968 dbus_error_free(&error);
1969 return;
1970 }
1971
1972 n_coefs = CHANNEL_PROFILE_SIZE(u);
1973 pa_assert(conn);
1974 pa_assert(msg);
1975 get_filter(u, channel, &H_, &preamp);
1976 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1977 dbus_message_iter_init_append(reply, &msg_iter);
1978
1979 pa_dbus_append_basic_array(&msg_iter, DBUS_TYPE_DOUBLE, H_, n_coefs);
1980 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_DOUBLE, &preamp);
1981
1982 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1983 dbus_message_unref(reply);
1984 pa_xfree(H_);
1985 }
1986
1987 static void set_filter(struct userdata *u, size_t channel, double *H_, double preamp) {
1988 unsigned a_i;
1989 size_t r_channel = channel == u->channels ? 0 : channel;
1990 float *H;
1991 //all channels
1992 a_i = pa_aupdate_write_begin(u->a_H[r_channel]);
1993 u->Xs[r_channel][a_i] = (float) preamp;
1994 H = u->Hs[r_channel][a_i];
1995 for(size_t i = 0; i < FILTER_SIZE(u); ++i) {
1996 H[i] = (float) H_[i];
1997 }
1998 fix_filter(H, u->fft_size);
1999 if (channel == u->channels) {
2000 for(size_t c = 1; c < u->channels; ++c) {
2001 unsigned b_i = pa_aupdate_write_begin(u->a_H[c]);
2002 u->Xs[c][b_i] = u->Xs[r_channel][a_i];
2003 memcpy(u->Hs[c][b_i], u->Hs[r_channel][a_i], FILTER_SIZE(u) * sizeof(float));
2004 pa_aupdate_write_end(u->a_H[c]);
2005 }
2006 }
2007 pa_aupdate_write_end(u->a_H[r_channel]);
2008 }
2009
2010 void equalizer_handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u) {
2011 struct userdata *u;
2012 double *H, preamp;
2013 uint32_t channel;
2014 unsigned _n_coefs;
2015 DBusMessage *message = NULL;
2016 DBusError error;
2017 pa_assert_se(u = (struct userdata *) _u);
2018 pa_assert(conn);
2019 pa_assert(msg);
2020
2021 dbus_error_init(&error);
2022 if (!dbus_message_get_args(msg, &error,
2023 DBUS_TYPE_UINT32, &channel,
2024 DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &H, &_n_coefs,
2025 DBUS_TYPE_DOUBLE, &preamp,
2026 DBUS_TYPE_INVALID)) {
2027 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2028 dbus_error_free(&error);
2029 return;
2030 }
2031 if (channel > u->channels) {
2032 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2033 dbus_error_free(&error);
2034 return;
2035 }
2036 if (_n_coefs != FILTER_SIZE(u)) {
2037 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "This filter takes exactly %zd coefficients, you gave %d", FILTER_SIZE(u), _n_coefs);
2038 return;
2039 }
2040 set_filter(u, channel, H, preamp);
2041
2042 pa_dbus_send_empty_reply(conn, msg);
2043
2044 pa_assert_se((message = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
2045 pa_dbus_protocol_send_signal(u->dbus_protocol, message);
2046 dbus_message_unref(message);
2047 }
2048
2049 void equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
2050 struct userdata *u = (struct userdata *) _u;
2051 char *name;
2052 uint32_t channel, r_channel;
2053 DBusMessage *message = NULL;
2054 DBusError error;
2055 pa_assert(conn);
2056 pa_assert(msg);
2057 pa_assert(u);
2058 dbus_error_init(&error);
2059
2060 if (!dbus_message_get_args(msg, &error,
2061 DBUS_TYPE_UINT32, &channel,
2062 DBUS_TYPE_STRING, &name,
2063 DBUS_TYPE_INVALID)) {
2064 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2065 dbus_error_free(&error);
2066 return;
2067 }
2068 if (channel > u->channels) {
2069 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2070 dbus_error_free(&error);
2071 return;
2072 }
2073 r_channel = channel == u->channels ? 0 : channel;
2074 save_profile(u, r_channel, name);
2075 pa_dbus_send_empty_reply(conn, msg);
2076
2077 pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name)));
2078 pa_dbus_protocol_send_signal(u->dbus_protocol, message);
2079 dbus_message_unref(message);
2080 }
2081
2082 void equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
2083 struct userdata *u = (struct userdata *) _u;
2084 char *name;
2085 DBusError error;
2086 uint32_t channel, r_channel;
2087 const char *err_msg = NULL;
2088 DBusMessage *message = NULL;
2089
2090 pa_assert(conn);
2091 pa_assert(msg);
2092 pa_assert(u);
2093 dbus_error_init(&error);
2094
2095 if (!dbus_message_get_args(msg, &error,
2096 DBUS_TYPE_UINT32, &channel,
2097 DBUS_TYPE_STRING, &name,
2098 DBUS_TYPE_INVALID)) {
2099 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2100 dbus_error_free(&error);
2101 return;
2102 }
2103 if (channel > u->channels) {
2104 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2105 dbus_error_free(&error);
2106 return;
2107 }
2108 r_channel = channel == u->channels ? 0 : channel;
2109
2110 err_msg = load_profile(u, r_channel, name);
2111 if (err_msg != NULL) {
2112 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "error loading profile %s: %s", name, err_msg);
2113 dbus_error_free(&error);
2114 return;
2115 }
2116 if (channel == u->channels) {
2117 for(uint32_t c = 1; c < u->channels; ++c) {
2118 load_profile(u, c, name);
2119 }
2120 }
2121 pa_dbus_send_empty_reply(conn, msg);
2122
2123 pa_assert_se((message = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
2124 pa_dbus_protocol_send_signal(u->dbus_protocol, message);
2125 dbus_message_unref(message);
2126 }
2127
2128 void equalizer_handle_save_state(DBusConnection *conn, DBusMessage *msg, void *_u) {
2129 struct userdata *u = (struct userdata *) _u;
2130 pa_assert(conn);
2131 pa_assert(msg);
2132 pa_assert(u);
2133
2134 save_state(u);
2135 pa_dbus_send_empty_reply(conn, msg);
2136 }
2137
2138 void equalizer_handle_get_profile_name(DBusConnection *conn, DBusMessage *msg, void *_u) {
2139 struct userdata *u = (struct userdata *) _u;
2140 DBusError error;
2141 uint32_t channel, r_channel;
2142
2143 pa_assert(conn);
2144 pa_assert(msg);
2145 pa_assert(u);
2146 dbus_error_init(&error);
2147
2148 if (!dbus_message_get_args(msg, &error,
2149 DBUS_TYPE_UINT32, &channel,
2150 DBUS_TYPE_INVALID)) {
2151 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
2152 dbus_error_free(&error);
2153 return;
2154 }
2155 if (channel > u->channels) {
2156 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel);
2157 dbus_error_free(&error);
2158 return;
2159 }
2160 r_channel = channel == u->channels ? 0 : channel;
2161 pa_assert(u->base_profiles[r_channel]);
2162 pa_dbus_send_basic_value_reply(conn,msg, DBUS_TYPE_STRING, &u->base_profiles[r_channel]);
2163 }
2164
2165 void equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u) {
2166 uint32_t rev=1;
2167 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev);
2168 }
2169
2170 void equalizer_get_n_channels(DBusConnection *conn, DBusMessage *msg, void *_u) {
2171 struct userdata *u;
2172 uint32_t channels;
2173 pa_assert_se(u = (struct userdata *) _u);
2174 pa_assert(conn);
2175 pa_assert(msg);
2176
2177 channels = (uint32_t) u->channels;
2178 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &channels);
2179 }
2180
2181 void equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u) {
2182 struct userdata *u;
2183 uint32_t n_coefs;
2184 pa_assert_se(u = (struct userdata *) _u);
2185 pa_assert(conn);
2186 pa_assert(msg);
2187
2188 n_coefs = (uint32_t) CHANNEL_PROFILE_SIZE(u);
2189 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &n_coefs);
2190 }
2191
2192 void equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u) {
2193 struct userdata *u;
2194 uint32_t rate;
2195 pa_assert_se(u = (struct userdata *) _u);
2196 pa_assert(conn);
2197 pa_assert(msg);
2198
2199 rate = (uint32_t) u->sink->sample_spec.rate;
2200 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &rate);
2201 }
2202
2203 void equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u) {
2204 struct userdata *u;
2205 uint32_t fft_size;
2206 pa_assert_se(u = (struct userdata *) _u);
2207 pa_assert(conn);
2208 pa_assert(msg);
2209
2210 fft_size = (uint32_t) u->fft_size;
2211 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &fft_size);
2212 }
2213
2214 void equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u) {
2215 struct userdata *u;
2216 DBusMessage *reply = NULL;
2217 DBusMessageIter msg_iter, dict_iter;
2218 uint32_t rev, n_coefs, rate, fft_size, channels;
2219
2220 pa_assert_se(u = _u);
2221 pa_assert(msg);
2222
2223 rev = 1;
2224 n_coefs = (uint32_t) CHANNEL_PROFILE_SIZE(u);
2225 rate = (uint32_t) u->sink->sample_spec.rate;
2226 fft_size = (uint32_t) u->fft_size;
2227 channels = (uint32_t) u->channels;
2228
2229 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2230 dbus_message_iter_init_append(reply, &msg_iter);
2231 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
2232
2233 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev);
2234 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_SAMPLERATE].property_name, DBUS_TYPE_UINT32, &rate);
2235 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_FILTERSAMPLERATE].property_name, DBUS_TYPE_UINT32, &fft_size);
2236 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_N_COEFS].property_name, DBUS_TYPE_UINT32, &n_coefs);
2237 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_N_CHANNELS].property_name, DBUS_TYPE_UINT32, &channels);
2238
2239 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
2240 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2241 dbus_message_unref(reply);
2242 }