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