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