]> code.delx.au - pulseaudio/blob - src/modules/module-equalizer-sink.c
module-equalizer-sink.c
[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/aupdate.h>
44 #include <pulsecore/core-error.h>
45 #include <pulsecore/namereg.h>
46 #include <pulsecore/sink.h>
47 #include <pulsecore/module.h>
48 #include <pulsecore/core-util.h>
49 #include <pulsecore/modargs.h>
50 #include <pulsecore/log.h>
51 #include <pulsecore/thread.h>
52 #include <pulsecore/thread-mq.h>
53 #include <pulsecore/rtpoll.h>
54 #include <pulsecore/sample-util.h>
55 #include <pulsecore/shared.h>
56 #include <pulsecore/idxset.h>
57 #include <pulsecore/strlist.h>
58 #include <pulsecore/database.h>
59 #include <pulsecore/protocol-dbus.h>
60 #include <pulsecore/dbus-util.h>
61
62 #include <stdint.h>
63 #include <time.h>
64
65
66 //#undef __SSE2__
67 #ifdef __SSE2__
68 #include <xmmintrin.h>
69 #include <emmintrin.h>
70 #endif
71
72
73
74 #include "module-equalizer-sink-symdef.h"
75
76 PA_MODULE_AUTHOR("Jason Newton");
77 PA_MODULE_DESCRIPTION(_("General Purpose Equalizer"));
78 PA_MODULE_VERSION(PACKAGE_VERSION);
79 PA_MODULE_LOAD_ONCE(FALSE);
80 PA_MODULE_USAGE(_("sink=<sink to connect to> "));
81
82 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
83
84
85 struct userdata {
86 pa_module *module;
87 pa_sink *sink;
88 pa_sink_input *sink_input;
89 char *name;
90
91 size_t channels;
92 size_t fft_size;//length (res) of fft
93 size_t window_size;/*
94 *sliding window size
95 *effectively chooses R
96 */
97 size_t R;/* the hop size between overlapping windows
98 * the latency of the filter, calculated from window_size
99 * based on constraints of COLA and window function
100 */
101 size_t latency;//Really just R but made into it's own variable
102 //for twiddling with pulseaudio
103 size_t overlap_size;//window_size-R
104 size_t samples_gathered;
105 //message
106 float *H;//frequency response filter (magnitude based)
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 *Hs[2];//thread updatable copies
114 pa_aupdate *a_H;
115 pa_memchunk conv_buffer;
116 pa_memblockq *input_q;
117 pa_bool_t first_iteration;
118
119 pa_dbus_protocol *dbus_protocol;
120 char *dbus_path;
121
122 pa_database *database;
123 };
124
125 static const char* const valid_modargs[] = {
126 "sink_name",
127 "sink_properties",
128 "master",
129 "format",
130 "rate",
131 "channels",
132 "channel_map",
133 NULL
134 };
135
136
137 #define v_size 4
138 #define mround(x, y) ((x + y - 1) / y) * y
139 #define SINKLIST "equalized_sinklist"
140 #define EQDB "equalizer_db"
141 static void dbus_init(struct userdata *u);
142 static void dbus_done(struct userdata *u);
143
144 static void hanning_window(float *W, size_t window_size){
145 //h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2
146 for(size_t i=0; i < window_size;++i){
147 W[i] = (float).5*(1-cos(2*M_PI*i/(window_size+1)));
148 }
149 }
150
151 static void fix_filter(float *H, size_t fft_size){
152 //divide out the fft gain
153 for(size_t i = 0; i < fft_size / 2 + 1; ++i){
154 H[i] /= fft_size;
155 }
156 }
157
158 static void interpolate(float *signal, size_t length, uint32_t *xs, float *ys, size_t n_points){
159 //Note that xs must be monotonically increasing!
160 float x_range_lower, x_range_upper, c0;
161 pa_assert_se(n_points>=2);
162 pa_assert_se(xs[0] == 0);
163 pa_assert_se(xs[n_points - 1] == length - 1);
164 for(size_t x = 0, x_range_lower_i = 0; x < length-1; ++x){
165 pa_assert(x_range_lower_i < n_points-1);
166 x_range_lower = (float) (xs[x_range_lower_i]);
167 x_range_upper = (float) (xs[x_range_lower_i+1]);
168 pa_assert_se(x_range_lower < x_range_upper);
169 pa_assert_se(x >= x_range_lower);
170 pa_assert_se(x <= x_range_upper);
171 //bilinear-interpolation of coefficients specified
172 c0 = (x-x_range_lower)/(x_range_upper-x_range_lower);
173 pa_assert_se(c0 >= 0&&c0 <= 1.0);
174 signal[x] = ((1.0f - c0) * ys[x_range_lower_i] + c0 * ys[x_range_lower_i + 1]);
175 while(x >= xs[x_range_lower_i + 1]){
176 x_range_lower_i++;
177 }
178 }
179 signal[length-1]=ys[n_points-1];
180 }
181
182 static int is_monotonic(const uint32_t *xs,size_t length){
183 if(length<2){
184 return 1;
185 }
186 for(size_t i = 1; i < length; ++i){
187 if(xs[i]<=xs[i-1]){
188 return 0;
189 }
190 }
191 return 1;
192 }
193
194
195 /* Called from I/O thread context */
196 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
197 struct userdata *u = PA_SINK(o)->userdata;
198
199 switch (code) {
200
201 case PA_SINK_MESSAGE_GET_LATENCY: {
202 size_t fs=pa_frame_size(&u->sink->sample_spec);
203
204 /* The sink is _put() before the sink input is, so let's
205 * make sure we don't access it in that time. Also, the
206 * sink input is first shut down, the sink second. */
207 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
208 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) {
209 *((pa_usec_t*) data) = 0;
210 return 0;
211 }
212
213 *((pa_usec_t*) data) =
214 /* Get the latency of the master sink */
215 pa_sink_get_latency_within_thread(u->sink_input->sink) +
216
217 /* Add the latency internal to our sink input on top */
218 pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec) +
219 pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec);
220 //+ pa_bytes_to_usec(u->latency * fs, ss)
221 //+ pa_bytes_to_usec(pa_memblockq_get_length(u->input_q), ss);
222 return 0;
223 }
224 }
225
226 return pa_sink_process_msg(o, code, data, offset, chunk);
227 }
228
229
230 /* Called from main context */
231 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
232 struct userdata *u;
233
234 pa_sink_assert_ref(s);
235 pa_assert_se(u = s->userdata);
236
237 if (!PA_SINK_IS_LINKED(state) ||
238 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
239 return 0;
240
241 pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
242 return 0;
243 }
244
245 /* Called from I/O thread context */
246 static void sink_request_rewind(pa_sink *s) {
247 struct userdata *u;
248
249 pa_sink_assert_ref(s);
250 pa_assert_se(u = s->userdata);
251
252 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
253 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
254 return;
255
256 /* Just hand this one over to the master sink */
257 pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes+pa_memblockq_get_length(u->input_q), TRUE, FALSE, FALSE);
258 }
259
260 /* Called from I/O thread context */
261 static void sink_update_requested_latency(pa_sink *s) {
262 struct userdata *u;
263
264 pa_sink_assert_ref(s);
265 pa_assert_se(u = s->userdata);
266
267 if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
268 !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
269 return;
270
271 /* Just hand this one over to the master sink */
272 pa_sink_input_set_requested_latency_within_thread(
273 u->sink_input,
274 pa_sink_get_requested_latency_within_thread(s));
275 }
276
277 typedef float v4sf __attribute__ ((__aligned__(v_size * sizeof(float))));
278 typedef union float_vector {
279 float f[v_size];
280 v4sf v;
281 #ifdef __SSE2__
282 __m128 m;
283 #endif
284 } float_vector_t;
285
286 //reference implementation
287 static void dsp_logic(
288 float * restrict dst,//used as a temp array too, needs to be fft_length!
289 float * restrict src,/*input data w/ overlap at start,
290 *automatically cycled in routine
291 */
292 float * restrict overlap,//The size of the overlap
293 const float * restrict H,//The freq. magnitude scalers filter
294 const float * restrict W,//The windowing function
295 fftwf_complex * restrict output_window,//The transformed window'd src
296 struct userdata *u){
297 //use a linear-phase sliding STFT and overlap-add method (for each channel)
298 //zero padd the data
299 memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float));
300 //window the data
301 for(size_t j = 0;j < u->window_size; ++j){
302 dst[j] = W[j] * src[j];
303 }
304 //Processing is done here!
305 //do fft
306 fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
307 //perform filtering
308 for(size_t j = 0; j < u->fft_size / 2 + 1; ++j){
309 u->output_window[j][0] *= u->H[j];
310 u->output_window[j][1] *= u->H[j];
311 }
312 //inverse fft
313 fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
314 ////debug: tests overlaping add
315 ////and negates ALL PREVIOUS processing
316 ////yields a perfect reconstruction if COLA is held
317 //for(size_t j = 0; j < u->window_size; ++j){
318 // u->work_buffer[j] = u->W[j] * u->input[c][j];
319 //}
320
321 //overlap add and preserve overlap component from this window (linear phase)
322 for(size_t j = 0;j < u->overlap_size; ++j){
323 u->work_buffer[j] += overlap[j];
324 overlap[j] = dst[u->R+j];
325 }
326 ////debug: tests if basic buffering works
327 ////shouldn't modify the signal AT ALL (beyond roundoff)
328 //for(size_t j = 0; j < u->window_size;++j){
329 // u->work_buffer[j] = u->input[c][j];
330 //}
331
332 //preseve the needed input for the next window's overlap
333 memmove(src, src+u->R,
334 ((u->overlap_size + u->samples_gathered) - u->R)*sizeof(float)
335 );
336 }
337
338 ////regardless of sse enabled, the loops in here assume
339 ////16 byte aligned addresses and memory allocations divisible by v_size
340 //void dsp_logic(
341 // float * restrict dst,//used as a temp array too, needs to be fft_length!
342 // float * restrict src,/*input data w/ overlap at start,
343 // *automatically cycled in routine
344 // */
345 // float * restrict overlap,//The size of the overlap
346 // const float * restrict H,//The freq. magnitude scalers filter
347 // const float * restrict W,//The windowing function
348 // fftwf_complex * restrict output_window,//The transformed window'd src
349 // struct userdata *u){//Collection of constants
350 //
351 // const size_t window_size = mround(u->window_size,v_size);
352 // const size_t fft_h = mround(u->fft_size / 2 + 1, v_size / 2);
353 // //const size_t R = mround(u->R, v_size);
354 // const size_t overlap_size = mround(u->overlap_size, v_size);
355 //
356 // //assert(u->samples_gathered >= u->R);
357 // //zero out the bit beyond the real overlap so we don't add garbage
358 // for(size_t j = overlap_size; j > u->overlap_size; --j){
359 // overlap[j-1] = 0;
360 // }
361 // //use a linear-phase sliding STFT and overlap-add method
362 // //zero padd the data
363 // memset(dst + u->window_size, 0, (u->fft_size - u->window_size)*sizeof(float));
364 // //window the data
365 // for(size_t j = 0; j < window_size; j += v_size){
366 // //dst[j] = W[j]*src[j];
367 // float_vector_t *d = (float_vector_t*) (dst+j);
368 // float_vector_t *w = (float_vector_t*) (W+j);
369 // float_vector_t *s = (float_vector_t*) (src+j);
370 //#if __SSE2__
371 // d->m = _mm_mul_ps(w->m, s->m);
372 //#else
373 // d->v = w->v * s->v;
374 //#endif
375 // }
376 // //Processing is done here!
377 // //do fft
378 // fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
379 //
380 //
381 // //perform filtering - purely magnitude based
382 // for(size_t j = 0;j < fft_h; j+=v_size/2){
383 // //output_window[j][0]*=H[j];
384 // //output_window[j][1]*=H[j];
385 // float_vector_t *d = (float_vector_t*)(output_window+j);
386 // float_vector_t h;
387 // h.f[0] = h.f[1] = H[j];
388 // h.f[2] = h.f[3] = H[j+1];
389 //#if __SSE2__
390 // d->m = _mm_mul_ps(d->m, h.m);
391 //#else
392 // d->v = d->v*h->v;
393 //#endif
394 // }
395 // //inverse fft
396 // fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
397 //
398 // ////debug: tests overlaping add
399 // ////and negates ALL PREVIOUS processing
400 // ////yields a perfect reconstruction if COLA is held
401 // //for(size_t j = 0; j < u->window_size; ++j){
402 // // dst[j] = W[j]*src[j];
403 // //}
404 //
405 // //overlap add and preserve overlap component from this window (linear phase)
406 // for(size_t j = 0; j < overlap_size; j+=v_size){
407 // //dst[j]+=overlap[j];
408 // //overlap[j]+=dst[j+R];
409 // float_vector_t *d = (float_vector_t*)(dst+j);
410 // float_vector_t *o = (float_vector_t*)(overlap+j);
411 //#if __SSE2__
412 // d->m = _mm_add_ps(d->m, o->m);
413 // o->m = ((float_vector_t*)(dst+u->R+j))->m;
414 //#else
415 // d->v = d->v+o->v;
416 // o->v = ((float_vector_t*)(dst+u->R+j))->v;
417 //#endif
418 // }
419 // //memcpy(overlap, dst+u->R, u->overlap_size*sizeof(float));
420 //
421 // //////debug: tests if basic buffering works
422 // //////shouldn't modify the signal AT ALL (beyond roundoff)
423 // //for(size_t j = 0; j < u->window_size; ++j){
424 // // dst[j] = src[j];
425 // //}
426 //
427 // //preseve the needed input for the next window's overlap
428 // memmove(src, src+u->R,
429 // ((u->overlap_size+u->samples_gathered)+-u->R)*sizeof(float)
430 // );
431 //}
432
433 static void process_samples(struct userdata *u, pa_memchunk *tchunk){
434 size_t fs=pa_frame_size(&(u->sink->sample_spec));
435 float *dst;
436 pa_assert(u->samples_gathered >= u->R);
437 tchunk->index = 0;
438 tchunk->length = u->R * fs;
439 tchunk->memblock = pa_memblock_new(u->sink->core->mempool, tchunk->length);
440 dst = ((float*)pa_memblock_acquire(tchunk->memblock));
441 for(size_t c=0;c < u->channels; c++) {
442 dsp_logic(
443 u->work_buffer,
444 u->input[c],
445 u->overlap_accum[c],
446 u->H,
447 u->W,
448 u->output_window,
449 u
450 );
451 if(u->first_iteration){
452 /* The windowing function will make the audio ramped in, as a cheap fix we can
453 * undo the windowing (for non-zero window values)
454 */
455 for(size_t i = 0;i < u->overlap_size; ++i){
456 u->work_buffer[i] = u->W[i] <= FLT_EPSILON ? u->work_buffer[i] : u->work_buffer[i] / u->W[i];
457 }
458 }
459 pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst + c, fs, u->work_buffer, sizeof(float), u->R);
460 }
461 pa_memblock_release(tchunk->memblock);
462 u->samples_gathered -= u->R;
463 }
464
465 static void initialize_buffer(struct userdata *u, pa_memchunk *in){
466 size_t fs = pa_frame_size(&u->sink->sample_spec);
467 size_t samples = in->length / fs;
468 float *src = (float*) ((uint8_t*) pa_memblock_acquire(in->memblock) + in->index);
469 pa_assert_se(u->samples_gathered + samples <= u->window_size);
470 for(size_t c = 0; c < u->channels; c++) {
471 //buffer with an offset after the overlap from previous
472 //iterations
473 pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c] + u->samples_gathered, sizeof(float), src + c, fs, samples);
474 }
475 u->samples_gathered += samples;
476 pa_memblock_release(in->memblock);
477 }
478
479 static void input_buffer(struct userdata *u, pa_memchunk *in){
480 size_t fs = pa_frame_size(&(u->sink->sample_spec));
481 size_t samples = in->length/fs;
482 float *src = (float*) ((uint8_t*) pa_memblock_acquire(in->memblock) + in->index);
483 pa_assert_se(samples <= u->window_size - u->samples_gathered);
484 for(size_t c = 0; c < u->channels; c++) {
485 //buffer with an offset after the overlap from previous
486 //iterations
487 pa_assert_se(
488 u->input[c]+u->samples_gathered+samples <= u->input[c]+u->window_size
489 );
490 pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c]+u->overlap_size+u->samples_gathered, sizeof(float), src + c, fs, samples);
491 }
492 u->samples_gathered += samples;
493 pa_memblock_release(in->memblock);
494 }
495
496 /* Called from I/O thread context */
497 static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
498 struct userdata *u;
499 size_t fs;
500 struct timeval start, end;
501 pa_memchunk tchunk;
502 pa_sink_input_assert_ref(i);
503 pa_assert_se(u = i->userdata);
504 pa_assert(chunk);
505 pa_assert(u->sink);
506 fs = pa_frame_size(&(u->sink->sample_spec));
507 chunk->memblock = NULL;
508
509 /* Hmm, process any rewind request that might be queued up */
510 pa_sink_process_rewind(u->sink, 0);
511
512 //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);
513 pa_timeval_load(&start);
514 do{
515 size_t input_remaining = u->window_size - u->samples_gathered;
516 pa_assert(input_remaining > 0);
517 //collect samples
518
519 //buffer = &u->conv_buffer;
520 //buffer->length = input_remaining*fs;
521 //buffer->index = 0;
522 //pa_memblock_ref(buffer->memblock);
523 //pa_sink_render_into(u->sink, buffer);
524 while(pa_memblockq_peek(u->input_q, &tchunk) < 0){
525 pa_sink_render(u->sink, input_remaining*fs, &tchunk);
526 pa_assert(tchunk.memblock);
527 pa_memblockq_push(u->input_q, &tchunk);
528 pa_memblock_unref(tchunk.memblock);
529 }
530 pa_assert(tchunk.memblock);
531 tchunk.length = PA_MIN(input_remaining * fs, tchunk.length);
532 pa_memblockq_drop(u->input_q, tchunk.length);
533 //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);
534 /* copy new input */
535 //pa_timeval_load(start);
536 if(u->first_iteration){
537 initialize_buffer(u, &tchunk);
538 }else{
539 input_buffer(u, &tchunk);
540 }
541 //pa_timeval_load(&end);
542 //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);
543 pa_memblock_unref(tchunk.memblock);
544 }while(u->samples_gathered < u->window_size);
545 pa_timeval_load(&end);
546 pa_log_debug("Took %0.6f seconds to get data", pa_timeval_diff(&end, &start) / (double) PA_USEC_PER_SEC);
547
548 pa_assert(u->fft_size >= u->window_size);
549 pa_assert(u->R < u->window_size);
550 /* set the H filter */
551 u->H = u->Hs[pa_aupdate_read_begin(u->a_H)];
552 pa_timeval_load(&start);
553 /* process a block */
554 process_samples(u, chunk);
555 pa_timeval_load(&end);
556 pa_log_debug("Took %0.6f seconds to process", pa_timeval_diff(&end, &start) / (double) PA_USEC_PER_SEC);
557 pa_aupdate_read_end(u->a_H);
558
559 pa_assert(chunk->memblock);
560 //pa_log_debug("gave %ld", chunk->length/fs);
561 //pa_log_debug("end pop");
562 if(u->first_iteration){
563 u->first_iteration = FALSE;
564 }
565 return 0;
566 }
567
568 static void reset_filter(struct userdata *u){
569 u->samples_gathered = 0;
570 for(size_t i = 0;i < u->channels; ++i){
571 memset(u->overlap_accum[i], 0, u->overlap_size * sizeof(float));
572 }
573 u->first_iteration = TRUE;
574 }
575
576 /* Called from I/O thread context */
577 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
578 struct userdata *u;
579 size_t amount = 0;
580
581 pa_log_debug("Rewind callback!");
582 pa_sink_input_assert_ref(i);
583 pa_assert_se(u = i->userdata);
584
585 if (u->sink->thread_info.rewind_nbytes > 0) {
586 size_t max_rewrite;
587
588 //max_rewrite = nbytes;
589 max_rewrite = nbytes + pa_memblockq_get_length(u->input_q);
590 //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes);
591 amount = PA_MIN(u->sink->thread_info.rewind_nbytes, max_rewrite);
592 u->sink->thread_info.rewind_nbytes = 0;
593
594 if (amount > 0) {
595 //pa_sample_spec *ss = &u->sink->sample_spec;
596 //invalidate the output q
597 pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
598 //pa_memblockq_drop(u->input_q, pa_memblockq_get_length(u->input_q));
599 //pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
600 pa_log("Resetting filter");
601 reset_filter(u);
602 }
603 }
604
605 pa_sink_process_rewind(u->sink, amount);
606 pa_memblockq_rewind(u->input_q, nbytes);
607 }
608
609 /* Called from I/O thread context */
610 static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
611 struct userdata *u;
612
613 pa_sink_input_assert_ref(i);
614 pa_assert_se(u = i->userdata);
615
616 pa_memblockq_set_maxrewind(u->input_q, nbytes);
617 pa_sink_set_max_rewind_within_thread(u->sink, nbytes);
618 }
619
620 /* Called from I/O thread context */
621 static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
622 struct userdata *u;
623 size_t fs;
624 pa_sink_input_assert_ref(i);
625 pa_assert_se(u = i->userdata);
626
627 fs = pa_frame_size(&(u->sink->sample_spec));
628 //pa_sink_set_max_request_within_thread(u->sink, nbytes);
629 //pa_sink_set_max_request_within_thread(u->sink, u->R*fs);
630 pa_sink_set_max_request_within_thread(u->sink, ((nbytes+u->R*fs-1)/(u->R*fs))*(u->R*fs));
631 }
632
633 /* Called from I/O thread context */
634 static void sink_input_update_sink_latency_range_cb(pa_sink_input *i) {
635 struct userdata *u;
636
637 pa_sink_input_assert_ref(i);
638 pa_assert_se(u = i->userdata);
639
640 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
641 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs );
642 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
643 }
644
645 /* Called from I/O thread context */
646 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) {
647 struct userdata *u;
648
649 pa_sink_input_assert_ref(i);
650 pa_assert_se(u = i->userdata);
651
652 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
653 }
654
655 /* Called from I/O thread context */
656 static void sink_input_detach_cb(pa_sink_input *i) {
657 struct userdata *u;
658
659 pa_sink_input_assert_ref(i);
660 pa_assert_se(u = i->userdata);
661
662 pa_sink_detach_within_thread(u->sink);
663
664 pa_sink_set_rtpoll(u->sink, NULL);
665 }
666
667 /* Called from I/O thread context */
668 static void sink_input_attach_cb(pa_sink_input *i) {
669 struct userdata *u;
670 size_t fs;
671 pa_sink_input_assert_ref(i);
672 pa_assert_se(u = i->userdata);
673
674 pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll);
675 pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
676
677 pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency);
678 fs = pa_frame_size(&(u->sink->sample_spec));
679 pa_sink_attach_within_thread(u->sink);
680 pa_sink_set_max_request_within_thread(u->sink, mround(pa_sink_input_get_max_request(i), u->R*fs));
681
682 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs);
683 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->master->thread_info.max_latency);
684 //TODO: setting this guy minimizes drop outs but doesn't get rid
685 //of them completely, figure out why
686 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
687 //TODO: this guy causes dropouts constantly+rewinds, it's unusable
688 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->master->thread_info.max_latency);
689 }
690
691 /* Called from main context */
692 static void sink_input_kill_cb(pa_sink_input *i) {
693 struct userdata *u;
694
695 pa_sink_input_assert_ref(i);
696 pa_assert_se(u = i->userdata);
697
698 /* The order here matters! We first kill the sink input, followed
699 * by the sink. That means the sink callbacks must be protected
700 * against an unconnected sink input! */
701 pa_sink_input_unlink(u->sink_input);
702 pa_sink_unlink(u->sink);
703
704 pa_sink_input_unref(u->sink_input);
705 u->sink_input = NULL;
706
707 pa_sink_unref(u->sink);
708 u->sink = NULL;
709
710 pa_module_unload_request(u->module, TRUE);
711 }
712
713 /* Called from IO thread context */
714 static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) {
715 struct userdata *u;
716
717 pa_sink_input_assert_ref(i);
718 pa_assert_se(u = i->userdata);
719
720 /* If we are added for the first time, ask for a rewinding so that
721 * we are heard right-away. */
722 if (PA_SINK_INPUT_IS_LINKED(state) &&
723 i->thread_info.state == PA_SINK_INPUT_INIT) {
724 pa_log_debug("Requesting rewind due to state change.");
725 pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
726 }
727 }
728
729 static void save_profile(struct userdata *u, char *name){
730 float *H_n = pa_xmalloc((u->fft_size / 2 + 1) * sizeof(float));
731 const float *H = u->Hs[pa_aupdate_read_begin(u->a_H)];
732 pa_datum key, data;
733 for(size_t i = 0 ; i <= u->fft_size / 2 + 1; ++i){
734 //H_n[i] = H[i] * u->fft_size;
735 H_n[i] = H[i];
736 }
737 pa_aupdate_read_end(u->a_H);
738 key.data=name;
739 key.size = strlen(key.data);
740 data.data = H_n;
741 data.size = (u->fft_size / 2 + 1) * sizeof(float);
742 pa_database_set(u->database, &key, &data, TRUE);
743 pa_database_sync(u->database);
744 }
745
746 static void save_state(struct userdata *u){
747 char *state_name = pa_sprintf_malloc("%s-previous-state", u->name);
748 save_profile(u, state_name);
749 pa_xfree(state_name);
750 }
751
752 static void remove_profile(pa_core *c, char *name){
753 pa_datum key;
754 pa_database *database;
755 key.data = name;
756 key.size = strlen(key.data);
757 pa_assert_se(database = pa_shared_get(c, EQDB));
758 pa_database_unset(database, &key);
759 pa_database_sync(database);
760 }
761
762 static const char* load_profile(struct userdata *u, char *name){
763 pa_datum key,value;
764 key.data = name;
765 key.size = strlen(key.data);
766 if(pa_database_get(u->database, &key, &value) != NULL){
767 if(value.size == (u->fft_size / 2 + 1) * sizeof(float)){
768 float *H=u->Hs[pa_aupdate_write_begin(u->a_H)];
769 memcpy(H, value.data, value.size);
770 pa_aupdate_write_end(u->a_H);
771 }else{
772 return "incompatible size";
773 }
774 pa_datum_free(&value);
775 }else{
776 return "profile doesn't exist";
777 }
778 return NULL;
779 //fix_filter(u->H, u->fft_size);
780 }
781
782 static void load_state(struct userdata *u){
783 char *state_name=pa_sprintf_malloc("%s-previous-state", u->name);
784 load_profile(u,state_name);
785 pa_xfree(state_name);
786 }
787
788 /* Called from main context */
789 static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) {
790 struct userdata *u;
791
792 pa_sink_input_assert_ref(i);
793 pa_assert_se(u = i->userdata);
794
795 return u->sink != dest;
796 }
797
798 /* Called from main context */
799 static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
800 struct userdata *u;
801
802 pa_sink_input_assert_ref(i);
803 pa_assert_se(u = i->userdata);
804
805 pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq);
806 pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags);
807 }
808
809 //ensure's memory allocated is a multiple of v_size
810 //and aligned
811 static void * alloc(size_t x,size_t s){
812 size_t f = mround(x*s, sizeof(float)*v_size);
813 float *t;
814 pa_assert(f >= x*s);
815 //printf("requested %ld floats=%ld bytes, rem=%ld\n", x, x*sizeof(float), x*sizeof(float)%16);
816 //printf("giving %ld floats=%ld bytes, rem=%ld\n", f, f*sizeof(float), f*sizeof(float)%16);
817 t = fftwf_malloc(f);
818 memset(t, 0, f);
819 return t;
820 }
821
822 int pa__init(pa_module*m) {
823 struct userdata *u;
824 pa_sample_spec ss;
825 pa_channel_map map;
826 pa_modargs *ma;
827 const char *z;
828 pa_sink *master;
829 pa_sink_input_new_data sink_input_data;
830 pa_sink_new_data sink_data;
831 pa_bool_t *use_default = NULL;
832 size_t fs;
833 float *H;
834
835 pa_assert(m);
836
837 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
838 pa_log("Failed to parse module arguments.");
839 goto fail;
840 }
841
842 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK))) {
843 pa_log("Master sink not found");
844 goto fail;
845 }
846
847 ss = master->sample_spec;
848 ss.format = PA_SAMPLE_FLOAT32;
849 map = master->channel_map;
850 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
851 pa_log("Invalid sample format specification or channel map");
852 goto fail;
853 }
854 fs = pa_frame_size(&ss);
855
856 u = pa_xnew0(struct userdata, 1);
857 u->module = m;
858 m->userdata = u;
859
860 u->channels = ss.channels;
861 u->fft_size = pow(2, ceil(log(ss.rate)/log(2)));
862 pa_log_debug("fft size: %ld", u->fft_size);
863 u->window_size = 15999;
864 u->R = (u->window_size + 1) / 2;
865 u->overlap_size = u->window_size - u->R;
866 u->samples_gathered = 0;
867 u->a_H = pa_aupdate_new();
868 u->latency = u->window_size - u->R;
869 for(size_t i = 0; i < 2; ++i){
870 u->Hs[i] = alloc((u->fft_size / 2 + 1), sizeof(float));
871 }
872 u->W = alloc(u->window_size, sizeof(float));
873 u->work_buffer = alloc(u->fft_size, sizeof(float));
874 memset(u->work_buffer, 0, u->fft_size*sizeof(float));
875 u->input = pa_xnew0(float *, u->channels);
876 u->overlap_accum = pa_xnew0(float *, u->channels);
877 for(size_t c = 0; c < u->channels; ++c){
878 u->input[c] = alloc(u->window_size, sizeof(float));
879 memset(u->input[c], 0, (u->window_size)*sizeof(float));
880 u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float));
881 memset(u->overlap_accum[c], 0, u->overlap_size*sizeof(float));
882 }
883 u->output_window = alloc((u->fft_size / 2 + 1), sizeof(fftwf_complex));
884 u->forward_plan = fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE);
885 u->inverse_plan = fftwf_plan_dft_c2r_1d(u->fft_size, u->output_window, u->work_buffer, FFTW_ESTIMATE);
886
887 hanning_window(u->W, u->window_size);
888 u->first_iteration = TRUE;
889
890 /* Create sink */
891 pa_sink_new_data_init(&sink_data);
892 sink_data.driver = __FILE__;
893 sink_data.module = m;
894 if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL))))
895 sink_data.name = pa_sprintf_malloc("%s.equalizer", master->name);
896 pa_sink_new_data_set_sample_spec(&sink_data, &ss);
897 pa_sink_new_data_set_channel_map(&sink_data, &map);
898 z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
899 pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "FFT based equalizer on %s",z? z: master->name);
900 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
901 pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
902
903 if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
904 pa_log("Invalid properties");
905 pa_sink_new_data_done(&sink_data);
906 goto fail;
907 }
908
909 u->sink = pa_sink_new(m->core, &sink_data, master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY));
910 pa_sink_new_data_done(&sink_data);
911
912 if (!u->sink) {
913 pa_log("Failed to create sink.");
914 goto fail;
915 }
916 u->name=pa_xstrdup(u->sink->name);
917 u->sink->parent.process_msg = sink_process_msg;
918 u->sink->set_state = sink_set_state;
919 u->sink->update_requested_latency = sink_update_requested_latency;
920 u->sink->request_rewind = sink_request_rewind;
921 u->sink->userdata = u;
922 u->input_q = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, fs, 1, 1, 0, &u->sink->silence);
923
924 pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq);
925 //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss));
926
927 /* Create sink input */
928 pa_sink_input_new_data_init(&sink_input_data);
929 sink_input_data.driver = __FILE__;
930 sink_input_data.module = m;
931 sink_input_data.sink = master;
932 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Equalized Stream");
933 pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
934 pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss);
935 pa_sink_input_new_data_set_channel_map(&sink_input_data, &map);
936
937 pa_sink_input_new(&u->sink_input, m->core, &sink_input_data, 0);
938 pa_sink_input_new_data_done(&sink_input_data);
939
940 if (!u->sink_input)
941 goto fail;
942
943 u->sink_input->pop = sink_input_pop_cb;
944 u->sink_input->process_rewind = sink_input_process_rewind_cb;
945 u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
946 u->sink_input->update_max_request = sink_input_update_max_request_cb;
947 u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb;
948 u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb;
949 u->sink_input->kill = sink_input_kill_cb;
950 u->sink_input->attach = sink_input_attach_cb;
951 u->sink_input->detach = sink_input_detach_cb;
952 u->sink_input->state_change = sink_input_state_change_cb;
953 u->sink_input->may_move_to = sink_input_may_move_to_cb;
954 u->sink_input->moving = sink_input_moving_cb;
955 u->sink_input->userdata = u;
956
957 pa_sink_put(u->sink);
958 pa_sink_input_put(u->sink_input);
959
960 pa_modargs_free(ma);
961
962 pa_xfree(use_default);
963
964 dbus_init(u);
965
966 //default filter to these
967 H=u->Hs[pa_aupdate_write_begin(u->a_H)];
968 for(size_t i = 0; i < u->fft_size / 2 + 1; ++i){
969 H[i] = 1.0 / sqrtf(2.0f);
970 }
971 fix_filter(H, u->fft_size);
972 pa_aupdate_write_end(u->a_H);
973 //load old parameters
974 load_state(u);
975
976 return 0;
977
978 fail:
979 if (ma)
980 pa_modargs_free(ma);
981
982 pa_xfree(use_default);
983
984 pa__done(m);
985
986 return -1;
987 }
988
989 int pa__get_n_used(pa_module *m) {
990 struct userdata *u;
991
992 pa_assert(m);
993 pa_assert_se(u = m->userdata);
994
995 return pa_sink_linked_by(u->sink);
996 }
997
998 void pa__done(pa_module*m) {
999 struct userdata *u;
1000
1001 pa_assert(m);
1002
1003 if (!(u = m->userdata))
1004 return;
1005
1006 save_state(u);
1007
1008 dbus_done(u);
1009
1010 /* See comments in sink_input_kill_cb() above regarding
1011 * destruction order! */
1012
1013 if (u->sink_input)
1014 pa_sink_input_unlink(u->sink_input);
1015
1016 if (u->sink)
1017 pa_sink_unlink(u->sink);
1018
1019 if (u->sink_input)
1020 pa_sink_input_unref(u->sink_input);
1021
1022 if (u->sink)
1023 pa_sink_unref(u->sink);
1024
1025 pa_aupdate_free(u->a_H);
1026 pa_memblockq_free(u->input_q);
1027
1028 fftwf_destroy_plan(u->inverse_plan);
1029 fftwf_destroy_plan(u->forward_plan);
1030 pa_xfree(u->output_window);
1031 for(size_t c=0; c < u->channels; ++c){
1032 pa_xfree(u->overlap_accum[c]);
1033 pa_xfree(u->input[c]);
1034 }
1035 pa_xfree(u->overlap_accum);
1036 pa_xfree(u->input);
1037 pa_xfree(u->work_buffer);
1038 pa_xfree(u->W);
1039 for(size_t i = 0; i < 2; ++i){
1040 pa_xfree(u->Hs[i]);
1041 }
1042
1043 pa_xfree(u->name);
1044
1045 pa_xfree(u);
1046 }
1047
1048 /*
1049 * DBus Routines and Callbacks
1050 */
1051 #define EXTNAME "org.PulseAudio.Ext.Equalizing1"
1052 #define MANAGER_PATH "/org/pulseaudio/equalizing1"
1053 #define MANAGER_IFACE EXTNAME ".Manager"
1054 #define EQUALIZER_IFACE EXTNAME ".Equalizer"
1055 static void manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u);
1056 static void get_sinks(pa_core *u, char ***names, unsigned *n_sinks);
1057 static void manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u);
1058 static void get_profiles(pa_core *u, char ***names, unsigned *n_sinks);
1059 static void manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u);
1060 static void manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u);
1061 static void manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1062 static void equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u);
1063 static void equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u);
1064 static void equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u);
1065 static void equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u);
1066 static void equalizer_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1067 static void equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u);
1068 static void equalizer_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1069 static void equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u);
1070 static void equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u);
1071 static void equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1072 static void equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u);
1073 static void get_filter(struct userdata *u, double **H_);
1074 static void set_filter(struct userdata *u, double **H_);
1075 enum manager_method_index {
1076 MANAGER_METHOD_REMOVE_PROFILE,
1077 MANAGER_METHOD_MAX
1078 };
1079
1080 pa_dbus_arg_info remove_profile_args[]={
1081 {"name", "s","in"},
1082 };
1083
1084 static pa_dbus_method_handler manager_methods[MANAGER_METHOD_MAX]={
1085 [MANAGER_METHOD_REMOVE_PROFILE]{
1086 .method_name="RemoveProfile",
1087 .arguments=remove_profile_args,
1088 .n_arguments=sizeof(remove_profile_args)/sizeof(pa_dbus_arg_info),
1089 .receive_cb=manager_handle_remove_profile}
1090 };
1091
1092 enum manager_handler_index {
1093 MANAGER_HANDLER_REVISION,
1094 MANAGER_HANDLER_EQUALIZED_SINKS,
1095 MANAGER_HANDLER_PROFILES,
1096 MANAGER_HANDLER_MAX
1097 };
1098
1099 static pa_dbus_property_handler manager_handlers[MANAGER_HANDLER_MAX]={
1100 [MANAGER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=manager_get_revision,.set_cb=NULL},
1101 [MANAGER_HANDLER_EQUALIZED_SINKS]={.property_name="EqualizedSinks",.type="ao",.get_cb=manager_get_sinks,.set_cb=NULL},
1102 [MANAGER_HANDLER_PROFILES]={.property_name="Profiles",.type="as",.get_cb=manager_get_profiles,.set_cb=NULL}
1103 };
1104
1105 pa_dbus_arg_info sink_args[]={
1106 {"sink", "o", NULL}
1107 };
1108
1109 enum manager_signal_index{
1110 MANAGER_SIGNAL_SINK_ADDED,
1111 MANAGER_SIGNAL_SINK_REMOVED,
1112 MANAGER_SIGNAL_PROFILES_CHANGED,
1113 MANAGER_SIGNAL_MAX
1114 };
1115
1116 static pa_dbus_signal_info manager_signals[MANAGER_SIGNAL_MAX]={
1117 [MANAGER_SIGNAL_SINK_ADDED]={.name="SinkAdded", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)},
1118 [MANAGER_SIGNAL_SINK_REMOVED]={.name="SinkRemoved", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)},
1119 [MANAGER_SIGNAL_PROFILES_CHANGED]={.name="ProfilesChanged", .arguments=NULL, .n_arguments=0}
1120 };
1121
1122 static pa_dbus_interface_info manager_info={
1123 .name=MANAGER_IFACE,
1124 .method_handlers=manager_methods,
1125 .n_method_handlers=MANAGER_METHOD_MAX,
1126 .property_handlers=manager_handlers,
1127 .n_property_handlers=MANAGER_HANDLER_MAX,
1128 .get_all_properties_cb=manager_get_all,
1129 .signals=manager_signals,
1130 .n_signals=MANAGER_SIGNAL_MAX
1131 };
1132
1133 enum equalizer_method_index {
1134 EQUALIZER_METHOD_FILTER_POINTS,
1135 EQUALIZER_METHOD_SEED_FILTER,
1136 EQUALIZER_METHOD_SAVE_PROFILE,
1137 EQUALIZER_METHOD_LOAD_PROFILE,
1138 EQUALIZER_METHOD_MAX
1139 };
1140
1141 enum equalizer_handler_index {
1142 EQUALIZER_HANDLER_REVISION,
1143 EQUALIZER_HANDLER_SAMPLERATE,
1144 EQUALIZER_HANDLER_FILTERSAMPLERATE,
1145 EQUALIZER_HANDLER_N_COEFS,
1146 EQUALIZER_HANDLER_FILTER,
1147 EQUALIZER_HANDLER_MAX
1148 };
1149
1150 pa_dbus_arg_info filter_points_args[]={
1151 {"xs", "au","in"},
1152 {"ys", "ad","out"},
1153 };
1154 pa_dbus_arg_info seed_filter_args[]={
1155 {"xs", "au","in"},
1156 {"ys", "ad","in"},
1157 };
1158 pa_dbus_arg_info save_profile_args[]={
1159 {"name", "s","in"},
1160 };
1161 pa_dbus_arg_info load_profile_args[]={
1162 {"name", "s","in"},
1163 };
1164
1165 static pa_dbus_method_handler equalizer_methods[EQUALIZER_METHOD_MAX]={
1166 [EQUALIZER_METHOD_SEED_FILTER]{
1167 .method_name="SeedFilter",
1168 .arguments=seed_filter_args,
1169 .n_arguments=sizeof(seed_filter_args)/sizeof(pa_dbus_arg_info),
1170 .receive_cb=equalizer_handle_seed_filter},
1171 [EQUALIZER_METHOD_FILTER_POINTS]{
1172 .method_name="FilterAtPoints",
1173 .arguments=filter_points_args,
1174 .n_arguments=sizeof(filter_points_args)/sizeof(pa_dbus_arg_info),
1175 .receive_cb=equalizer_handle_get_filter_points},
1176 [EQUALIZER_METHOD_SAVE_PROFILE]{
1177 .method_name="SaveProfile",
1178 .arguments=save_profile_args,
1179 .n_arguments=sizeof(save_profile_args)/sizeof(pa_dbus_arg_info),
1180 .receive_cb=equalizer_handle_save_profile},
1181 [EQUALIZER_METHOD_LOAD_PROFILE]{
1182 .method_name="LoadProfile",
1183 .arguments=load_profile_args,
1184 .n_arguments=sizeof(load_profile_args)/sizeof(pa_dbus_arg_info),
1185 .receive_cb=equalizer_handle_load_profile},
1186 };
1187
1188 static pa_dbus_property_handler equalizer_handlers[EQUALIZER_HANDLER_MAX]={
1189 [EQUALIZER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=equalizer_get_revision,.set_cb=NULL},
1190 [EQUALIZER_HANDLER_SAMPLERATE]{.property_name="SampleRate",.type="u",.get_cb=equalizer_get_sample_rate,.set_cb=NULL},
1191 [EQUALIZER_HANDLER_FILTERSAMPLERATE]{.property_name="FilterSampleRate",.type="u",.get_cb=equalizer_get_filter_rate,.set_cb=NULL},
1192 [EQUALIZER_HANDLER_N_COEFS]{.property_name="NFilterCoefficients",.type="u",.get_cb=equalizer_get_n_coefs,.set_cb=NULL},
1193 [EQUALIZER_HANDLER_FILTER]{.property_name="Filter",.type="ad",.get_cb=equalizer_get_filter,.set_cb=equalizer_set_filter},
1194 };
1195
1196 enum equalizer_signal_index{
1197 EQUALIZER_SIGNAL_FILTER_CHANGED,
1198 EQUALIZER_SIGNAL_SINK_RECONFIGURED,
1199 EQUALIZER_SIGNAL_MAX
1200 };
1201
1202 static pa_dbus_signal_info equalizer_signals[EQUALIZER_SIGNAL_MAX]={
1203 [EQUALIZER_SIGNAL_FILTER_CHANGED]={.name="FilterChanged", .arguments=NULL, .n_arguments=0},
1204 [EQUALIZER_SIGNAL_SINK_RECONFIGURED]={.name="SinkReconfigured", .arguments=NULL, .n_arguments=0},
1205 };
1206
1207 static pa_dbus_interface_info equalizer_info={
1208 .name=EQUALIZER_IFACE,
1209 .method_handlers=equalizer_methods,
1210 .n_method_handlers=EQUALIZER_METHOD_MAX,
1211 .property_handlers=equalizer_handlers,
1212 .n_property_handlers=EQUALIZER_HANDLER_MAX,
1213 .get_all_properties_cb=equalizer_get_all,
1214 .signals=equalizer_signals,
1215 .n_signals=EQUALIZER_SIGNAL_MAX
1216 };
1217
1218 static void dbus_init(struct userdata *u){
1219 uint32_t dummy;
1220 DBusMessage *signal = NULL;
1221 pa_idxset *sink_list = NULL;
1222 u->dbus_protocol=pa_dbus_protocol_get(u->sink->core);
1223 u->dbus_path=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u->sink->index);
1224
1225 pa_dbus_protocol_add_interface(u->dbus_protocol, u->dbus_path, &equalizer_info, u);
1226 sink_list = pa_shared_get(u->sink->core, SINKLIST);
1227 u->database=pa_shared_get(u->sink->core, EQDB);
1228 if(sink_list==NULL){
1229 char *dbname;
1230 sink_list=pa_idxset_new(&pa_idxset_trivial_hash_func, &pa_idxset_trivial_compare_func);
1231 pa_shared_set(u->sink->core, SINKLIST, sink_list);
1232 pa_assert_se(dbname = pa_state_path("equalizers", TRUE));
1233 pa_assert_se(u->database = pa_database_open(dbname, TRUE));
1234 pa_xfree(dbname);
1235 pa_shared_set(u->sink->core,EQDB,u->database);
1236 pa_dbus_protocol_add_interface(u->dbus_protocol, MANAGER_PATH, &manager_info, u->sink->core);
1237 pa_dbus_protocol_register_extension(u->dbus_protocol, EXTNAME);
1238 }
1239 pa_idxset_put(sink_list, u, &dummy);
1240
1241 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_ADDED].name)));
1242 dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID);
1243 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1244 dbus_message_unref(signal);
1245 }
1246
1247 static void dbus_done(struct userdata *u){
1248 pa_idxset *sink_list;
1249 uint32_t dummy;
1250
1251 DBusMessage *signal = NULL;
1252 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_REMOVED].name)));
1253 dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID);
1254 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1255 dbus_message_unref(signal);
1256
1257 pa_assert_se(sink_list=pa_shared_get(u->sink->core,SINKLIST));
1258 pa_idxset_remove_by_data(sink_list,u,&dummy);
1259 if(pa_idxset_size(sink_list)==0){
1260 pa_dbus_protocol_unregister_extension(u->dbus_protocol, EXTNAME);
1261 pa_dbus_protocol_remove_interface(u->dbus_protocol, MANAGER_PATH, manager_info.name);
1262 pa_shared_remove(u->sink->core, EQDB);
1263 pa_database_close(u->database);
1264 pa_shared_remove(u->sink->core, SINKLIST);
1265 pa_xfree(sink_list);
1266 }
1267 pa_dbus_protocol_remove_interface(u->dbus_protocol, u->dbus_path, equalizer_info.name);
1268 pa_xfree(u->dbus_path);
1269 pa_dbus_protocol_unref(u->dbus_protocol);
1270 }
1271
1272 static void manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
1273 DBusError error;
1274 pa_core *c = (pa_core *)_u;
1275 DBusMessage *signal = NULL;
1276 pa_dbus_protocol *dbus_protocol;
1277 char *name;
1278 pa_assert(conn);
1279 pa_assert(msg);
1280 pa_assert(c);
1281 dbus_error_init(&error);
1282 if(!dbus_message_get_args(msg, &error,
1283 DBUS_TYPE_STRING, &name,
1284 DBUS_TYPE_INVALID)){
1285 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1286 dbus_error_free(&error);
1287 return;
1288 }
1289 remove_profile(c,name);
1290 pa_dbus_send_empty_reply(conn, msg);
1291
1292 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name)));
1293 dbus_protocol = pa_dbus_protocol_get(c);
1294 pa_dbus_protocol_send_signal(dbus_protocol, signal);
1295 pa_dbus_protocol_unref(dbus_protocol);
1296 dbus_message_unref(signal);
1297 }
1298
1299 static void manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u){
1300 uint32_t rev=1;
1301 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev);
1302 }
1303
1304 static void get_sinks(pa_core *u, char ***names, unsigned *n_sinks){
1305 void *iter = NULL;
1306 struct userdata *sink_u = NULL;
1307 uint32_t dummy;
1308 pa_idxset *sink_list;
1309 pa_assert(u);
1310 pa_assert(names);
1311 pa_assert(n_sinks);
1312
1313 pa_assert_se(sink_list = pa_shared_get(u, SINKLIST));
1314 *n_sinks = (unsigned) pa_idxset_size(sink_list);
1315 *names = *n_sinks > 0 ? pa_xnew0(char *,*n_sinks) : NULL;
1316 for(uint32_t i = 0; i < *n_sinks; ++i){
1317 sink_u = (struct userdata *) pa_idxset_iterate(sink_list, &iter, &dummy);
1318 (*names)[i] = pa_xstrdup(sink_u->dbus_path);
1319 }
1320 }
1321
1322 static void manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u){
1323 unsigned n;
1324 char **names = NULL;
1325 pa_assert(conn);
1326 pa_assert(msg);
1327 pa_assert(_u);
1328
1329 get_sinks((pa_core *) _u, &names, &n);
1330 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, names, n);
1331 for(unsigned i = 0; i < n; ++i){
1332 pa_xfree(names[i]);
1333 }
1334 pa_xfree(names);
1335 }
1336
1337 static void get_profiles(pa_core *c, char ***names, unsigned *n){
1338 char *name;
1339 pa_database *database;
1340 pa_datum key, next_key;
1341 pa_strlist *head=NULL, *iter;
1342 pa_bool_t done;
1343 pa_assert_se(database = pa_shared_get(c, EQDB));
1344
1345 pa_assert(c);
1346 pa_assert(names);
1347 pa_assert(n);
1348 done = !pa_database_first(database, &key, NULL);
1349 *n = 0;
1350 while(!done){
1351 done = !pa_database_next(database, &key, &next_key, NULL);
1352 name=pa_xmalloc(key.size + 1);
1353 memcpy(name, key.data, key.size);
1354 name[key.size] = '\0';
1355 pa_datum_free(&key);
1356 head = pa_strlist_prepend(head, name);
1357 pa_xfree(name);
1358 key = next_key;
1359 (*n)++;
1360 }
1361 (*names) = *n > 0 ? pa_xnew0(char *, *n) : NULL;
1362 iter=head;
1363 for(unsigned i = 0; i < *n; ++i){
1364 (*names)[*n - 1 - i] = pa_xstrdup(pa_strlist_data(iter));
1365 iter = pa_strlist_next(iter);
1366 }
1367 pa_strlist_free(head);
1368 }
1369
1370 static void manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u){
1371 char **names;
1372 unsigned n;
1373 pa_assert(conn);
1374 pa_assert(msg);
1375 pa_assert(_u);
1376
1377 get_profiles((pa_core *)_u, &names, &n);
1378 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_STRING, names, n);
1379 for(unsigned i = 0; i < n; ++i){
1380 pa_xfree(names[i]);
1381 }
1382 pa_xfree(names);
1383 }
1384
1385 static void manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u){
1386 pa_core *c;
1387 char **names = NULL;
1388 unsigned n;
1389 DBusMessage *reply = NULL;
1390 DBusMessageIter msg_iter, dict_iter;
1391 uint32_t rev;
1392 pa_assert(conn);
1393 pa_assert(msg);
1394 pa_assert_se(c = _u);
1395
1396 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1397 dbus_message_iter_init_append(reply, &msg_iter);
1398 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
1399
1400 rev = 1;
1401 pa_dbus_append_basic_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev);
1402
1403 get_sinks(c, &names, &n);
1404 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter,manager_handlers[MANAGER_HANDLER_EQUALIZED_SINKS].property_name, DBUS_TYPE_OBJECT_PATH, names, n);
1405 for(unsigned i = 0; i < n; ++i){
1406 pa_xfree(names[i]);
1407 }
1408 pa_xfree(names);
1409
1410 get_profiles(c, &names, &n);
1411 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_PROFILES].property_name, DBUS_TYPE_STRING, names, n);
1412 for(unsigned i = 0; i < n; ++i){
1413 pa_xfree(names[i]);
1414 }
1415 pa_xfree(names);
1416 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1417 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1418 dbus_message_unref(reply);
1419 }
1420
1421 static void equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u) {
1422 struct userdata *u=(struct userdata *) _u;
1423 DBusError error;
1424 DBusMessage *signal = NULL;
1425 float *ys;
1426 uint32_t *xs;
1427 double *_ys;
1428 unsigned x_npoints, y_npoints;
1429 float *H;
1430 pa_bool_t points_good = TRUE;
1431 pa_assert(conn);
1432 pa_assert(msg);
1433 pa_assert(u);
1434
1435 dbus_error_init(&error);
1436
1437 if(!dbus_message_get_args(msg, &error,
1438 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints,
1439 DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &_ys, &y_npoints,
1440 DBUS_TYPE_INVALID)){
1441 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1442 dbus_error_free(&error);
1443 return;
1444 }
1445 for(size_t i = 0; i < x_npoints; ++i){
1446 if(xs[i] >= u->fft_size / 2 + 1){
1447 points_good = FALSE;
1448 break;
1449 }
1450 }
1451 if(!is_monotonic(xs, x_npoints) || !points_good){
1452 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs must be monotonic and 0<=x<=%ld", u->fft_size / 2);
1453 dbus_error_free(&error);
1454 return;
1455
1456 }else if(x_npoints != y_npoints || x_npoints < 2 || x_npoints > u->fft_size / 2 +1 ){
1457 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs and ys must be the same length and 2<=l<=%ld!", u->fft_size / 2 + 1);
1458 dbus_error_free(&error);
1459 return;
1460 }else if(xs[0] != 0 || xs[x_npoints - 1] != u->fft_size / 2){
1461 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs[0] must be 0 and xs[-1]=fft_size/2");
1462 dbus_error_free(&error);
1463 return;
1464 }
1465
1466 ys = pa_xmalloc(x_npoints * sizeof(float));
1467 for(uint32_t i = 0; i < x_npoints; ++i){
1468 ys[i] = (float) _ys[i];
1469 }
1470
1471 H = u->Hs[pa_aupdate_write_begin(u->a_H)];
1472 interpolate(H, u->fft_size / 2 + 1, xs, ys, x_npoints);
1473 fix_filter(H, u->fft_size);
1474 pa_aupdate_write_end(u->a_H);
1475 pa_xfree(ys);
1476
1477 //Stupid for IO reasons? Add a save signal to dbus instead
1478 //save_state(u);
1479
1480 pa_dbus_send_empty_reply(conn, msg);
1481
1482 pa_assert_se((signal = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
1483 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1484 dbus_message_unref(signal);
1485 }
1486
1487 static void equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u) {
1488 struct userdata *u = (struct userdata *) _u;
1489 DBusError error;
1490 uint32_t *xs;
1491 double *ys;
1492 unsigned x_npoints;
1493 float *H;
1494 pa_bool_t points_good=TRUE;
1495
1496 pa_assert(conn);
1497 pa_assert(msg);
1498 pa_assert(u);
1499
1500 dbus_error_init(&error);
1501
1502 if(!dbus_message_get_args(msg, &error,
1503 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints,
1504 DBUS_TYPE_INVALID)){
1505 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1506 dbus_error_free(&error);
1507 return;
1508 }
1509 for(size_t i = 0; i < x_npoints; ++i){
1510 if(xs[i] >= u->fft_size / 2 + 1){
1511 points_good=FALSE;
1512 break;
1513 }
1514 }
1515
1516 if(x_npoints > u->fft_size / 2 +1 || !points_good){
1517 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs indices/length must be <= %ld!", u->fft_size / 2 + 1);
1518 dbus_error_free(&error);
1519 return;
1520 }
1521
1522 ys = pa_xmalloc(x_npoints * sizeof(double));
1523 H = u->Hs[pa_aupdate_read_begin(u->a_H)];
1524 for(uint32_t i = 0; i < x_npoints; ++i){
1525 ys[i] = H[xs[i]] * u->fft_size;
1526 }
1527 pa_aupdate_read_end(u->a_H);
1528
1529 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_DOUBLE, ys, x_npoints);
1530 pa_xfree(ys);
1531 }
1532
1533 static void equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
1534 struct userdata *u = (struct userdata *) _u;
1535 char *name;
1536 DBusMessage *signal = NULL;
1537 DBusError error;
1538 pa_assert(conn);
1539 pa_assert(msg);
1540 pa_assert(u);
1541 dbus_error_init(&error);
1542
1543 if(!dbus_message_get_args(msg, &error,
1544 DBUS_TYPE_STRING, &name,
1545 DBUS_TYPE_INVALID)){
1546 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1547 dbus_error_free(&error);
1548 return;
1549 }
1550 save_profile(u,name);
1551 pa_dbus_send_empty_reply(conn, msg);
1552
1553 pa_assert_se((signal = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name)));
1554 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1555 dbus_message_unref(signal);
1556 }
1557
1558 static void equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u) {
1559 struct userdata *u=(struct userdata *) _u;
1560 char *name;
1561 DBusError error;
1562 const char *err_msg = NULL;
1563 DBusMessage *signal = NULL;
1564
1565 pa_assert(conn);
1566 pa_assert(msg);
1567 pa_assert(u);
1568 dbus_error_init(&error);
1569
1570 if(!dbus_message_get_args(msg, &error,
1571 DBUS_TYPE_STRING, &name,
1572 DBUS_TYPE_INVALID)){
1573 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
1574 dbus_error_free(&error);
1575 return;
1576 }
1577 err_msg = load_profile(u,name);
1578 if(err_msg != NULL){
1579 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "error loading profile %s: %s", name, err_msg);
1580 dbus_error_free(&error);
1581 return;
1582 }
1583 pa_dbus_send_empty_reply(conn, msg);
1584
1585 pa_assert_se((signal = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
1586 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1587 dbus_message_unref(signal);
1588 }
1589
1590 static void equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u){
1591 uint32_t rev=1;
1592 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev);
1593 }
1594
1595 static void equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u){
1596 struct userdata *u;
1597 uint32_t n_coefs;
1598 pa_assert_se(u = (struct userdata *) _u);
1599 pa_assert(conn);
1600 pa_assert(msg);
1601
1602 n_coefs = (uint32_t) (u->fft_size / 2 + 1);
1603 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &n_coefs);
1604 }
1605
1606 static void equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u){
1607 struct userdata *u;
1608 uint32_t rate;
1609 pa_assert_se(u = (struct userdata *) _u);
1610 pa_assert(conn);
1611 pa_assert(msg);
1612
1613 rate = (uint32_t) u->sink->sample_spec.rate;
1614 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &rate);
1615 }
1616
1617 static void equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u){
1618 struct userdata *u;
1619 uint32_t fft_size;
1620 pa_assert_se(u = (struct userdata *) _u);
1621 pa_assert(conn);
1622 pa_assert(msg);
1623
1624 fft_size = (uint32_t) u->fft_size;
1625 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &fft_size);
1626 }
1627
1628 static void get_filter(struct userdata *u, double **H_){
1629 float *H;
1630 *H_ = pa_xnew0(double, u->fft_size / 2 + 1);
1631 H = u->Hs[pa_aupdate_read_begin(u->a_H)];
1632 for(size_t i = 0;i < u->fft_size / 2 + 1; ++i){
1633 (*H_)[i] = H[i] * u->fft_size;
1634 }
1635 pa_aupdate_read_end(u->a_H);
1636 }
1637
1638 static void equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u){
1639 struct userdata *u;
1640 DBusMessage *reply = NULL;
1641 DBusMessageIter msg_iter, dict_iter;
1642 uint32_t rev, n_coefs, rate, fft_size;
1643 double *H;
1644 pa_assert_se(u = (struct userdata *) _u);
1645 pa_assert(msg);
1646
1647 rev = 1;
1648 n_coefs = (uint32_t) (u->fft_size / 2 + 1);
1649 rate = (uint32_t) u->sink->sample_spec.rate;
1650 fft_size = (uint32_t) u->fft_size;
1651
1652 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1653 dbus_message_iter_init_append(reply, &msg_iter);
1654 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
1655
1656 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev);
1657 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_SAMPLERATE].property_name, DBUS_TYPE_UINT32, &rate);
1658 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_FILTERSAMPLERATE].property_name, DBUS_TYPE_UINT32, &fft_size);
1659 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_N_COEFS].property_name, DBUS_TYPE_UINT32, &n_coefs);
1660 get_filter(u, &H);
1661 pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_FILTER].property_name, DBUS_TYPE_UINT32, &H);
1662 pa_xfree(H);
1663
1664 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
1665 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1666 dbus_message_unref(reply);
1667 }
1668
1669 static void equalizer_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u){
1670 struct userdata *u;
1671 unsigned n_coefs;
1672 double *H_;
1673 pa_assert_se(u = (struct userdata *) _u);
1674
1675 n_coefs = u->fft_size / 2 + 1;
1676 pa_assert(conn);
1677 pa_assert(msg);
1678 get_filter(u, &H_);
1679 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_DOUBLE, H_, n_coefs);
1680 pa_xfree(H_);
1681 }
1682
1683 static void set_filter(struct userdata *u, double **H_){
1684 float *H = u->Hs[pa_aupdate_write_begin(u->a_H)];
1685 for(size_t i = 0; i < u->fft_size / 2 + 1; ++i){
1686 H[i] = (float) (*H_)[i];
1687 }
1688 fix_filter(H, u->fft_size);
1689 pa_aupdate_write_end(u->a_H);
1690 }
1691
1692 static void equalizer_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u){
1693 struct userdata *u;
1694 double *H;
1695 unsigned _n_coefs;
1696 DBusMessage *signal = NULL;
1697 pa_assert_se(u = (struct userdata *) _u);
1698 pa_assert(conn);
1699 pa_assert(msg);
1700
1701 if(pa_dbus_get_fixed_array_set_property_arg(conn, msg, DBUS_TYPE_DOUBLE, &H, &_n_coefs)){
1702 return;
1703 }
1704 if(_n_coefs!=u->fft_size / 2 + 1){
1705 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "This filter takes exactly %ld coefficients, you gave %d", u->fft_size / 2 + 1, _n_coefs);
1706 return;
1707 }
1708 set_filter(u, &H);
1709 //Stupid for IO reasons? Add a save signal to dbus instead
1710 //save_state(u);
1711
1712 pa_dbus_send_empty_reply(conn, msg);
1713
1714 pa_assert_se((signal = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name)));
1715 pa_dbus_protocol_send_signal(u->dbus_protocol, signal);
1716 dbus_message_unref(signal);
1717 }