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