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