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