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