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