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>
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
39 #include <pulse/xmalloc.h>
40 #include <pulse/i18n.h>
41 #include <pulse/timeval.h>
43 #include <pulsecore/aupdate.h>
44 #include <pulsecore/core-error.h>
45 #include <pulsecore/namereg.h>
46 #include <pulsecore/sink.h>
47 #include <pulsecore/module.h>
48 #include <pulsecore/core-util.h>
49 #include <pulsecore/modargs.h>
50 #include <pulsecore/log.h>
51 #include <pulsecore/thread.h>
52 #include <pulsecore/thread-mq.h>
53 #include <pulsecore/rtpoll.h>
54 #include <pulsecore/sample-util.h>
55 #include <pulsecore/shared.h>
56 #include <pulsecore/idxset.h>
57 #include <pulsecore/strlist.h>
58 #include <pulsecore/database.h>
59 #include <pulsecore/protocol-dbus.h>
60 #include <pulsecore/dbus-util.h>
68 #include <xmmintrin.h>
69 #include <emmintrin.h>
74 #include "module-equalizer-sink-symdef.h"
76 PA_MODULE_AUTHOR("Jason Newton");
77 PA_MODULE_DESCRIPTION(_("General Purpose Equalizer"));
78 PA_MODULE_VERSION(PACKAGE_VERSION
);
79 PA_MODULE_LOAD_ONCE(FALSE
);
80 PA_MODULE_USAGE(_("sink=<sink to connect to> "));
82 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
88 pa_sink_input
*sink_input
;
92 size_t fft_size
;//length (res) of fft
95 *effectively chooses R
97 size_t R
;/* the hop size between overlapping windows
98 * the latency of the filter, calculated from window_size
99 * based on constraints of COLA and window function
101 size_t latency
;//Really just R but made into it's own variable
102 //for twiddling with pulseaudio
103 size_t overlap_size
;//window_size-R
104 size_t samples_gathered
;
106 float *H
;//frequency response filter (magnitude based)
107 float *W
;//windowing function (time domain)
108 float *work_buffer
, **input
, **overlap_accum
;
109 fftwf_complex
*output_window
;
110 fftwf_plan forward_plan
, inverse_plan
;
113 float *Hs
[2];//thread updatable copies
115 pa_memchunk conv_buffer
;
116 pa_memblockq
*input_q
;
117 pa_bool_t first_iteration
;
119 pa_dbus_protocol
*dbus_protocol
;
122 pa_database
*database
;
125 static const char* const valid_modargs
[] = {
138 #define mround(x, y) ((x + y - 1) / y) * y
139 #define SINKLIST "equalized_sinklist"
140 #define EQDB "equalizer_db"
141 static void dbus_init(struct userdata
*u
);
142 static void dbus_done(struct userdata
*u
);
144 static void hanning_window(float *W
, size_t window_size
){
145 //h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2
146 for(size_t i
=0; i
< window_size
;++i
){
147 W
[i
] = (float).5*(1-cos(2*M_PI
*i
/(window_size
+1)));
151 static void fix_filter(float *H
, size_t fft_size
){
152 //divide out the fft gain
153 for(size_t i
= 0; i
< fft_size
/ 2 + 1; ++i
){
158 static void interpolate(float *signal
, size_t length
, uint32_t *xs
, float *ys
, size_t n_points
){
159 //Note that xs must be monotonically increasing!
160 float x_range_lower
, x_range_upper
, c0
;
161 pa_assert_se(n_points
>=2);
162 pa_assert_se(xs
[0] == 0);
163 pa_assert_se(xs
[n_points
- 1] == length
- 1);
164 for(size_t x
= 0, x_range_lower_i
= 0; x
< length
-1; ++x
){
165 pa_assert(x_range_lower_i
< n_points
-1);
166 x_range_lower
= (float) (xs
[x_range_lower_i
]);
167 x_range_upper
= (float) (xs
[x_range_lower_i
+1]);
168 pa_assert_se(x_range_lower
< x_range_upper
);
169 pa_assert_se(x
>= x_range_lower
);
170 pa_assert_se(x
<= x_range_upper
);
171 //bilinear-interpolation of coefficients specified
172 c0
= (x
-x_range_lower
)/(x_range_upper
-x_range_lower
);
173 pa_assert_se(c0
>= 0&&c0
<= 1.0);
174 signal
[x
] = ((1.0f
- c0
) * ys
[x_range_lower_i
] + c0
* ys
[x_range_lower_i
+ 1]);
175 while(x
>= xs
[x_range_lower_i
+ 1]){
179 signal
[length
-1]=ys
[n_points
-1];
182 static int is_monotonic(const uint32_t *xs
,size_t length
){
186 for(size_t i
= 1; i
< length
; ++i
){
195 /* Called from I/O thread context */
196 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
197 struct userdata
*u
= PA_SINK(o
)->userdata
;
201 case PA_SINK_MESSAGE_GET_LATENCY
: {
202 size_t fs
=pa_frame_size(&u
->sink
->sample_spec
);
204 /* The sink is _put() before the sink input is, so let's
205 * make sure we don't access it in that time. Also, the
206 * sink input is first shut down, the sink second. */
207 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
208 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
)) {
209 *((pa_usec_t
*) data
) = 0;
213 *((pa_usec_t
*) data
) =
214 /* Get the latency of the master sink */
215 pa_sink_get_latency_within_thread(u
->sink_input
->sink
) +
217 /* Add the latency internal to our sink input on top */
218 pa_bytes_to_usec(pa_memblockq_get_length(u
->sink_input
->thread_info
.render_memblockq
), &u
->sink_input
->sink
->sample_spec
) +
219 pa_bytes_to_usec(u
->samples_gathered
* fs
, &u
->sink
->sample_spec
);
220 //+ pa_bytes_to_usec(u->latency * fs, ss)
221 //+ pa_bytes_to_usec(pa_memblockq_get_length(u->input_q), ss);
226 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
230 /* Called from main context */
231 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
234 pa_sink_assert_ref(s
);
235 pa_assert_se(u
= s
->userdata
);
237 if (!PA_SINK_IS_LINKED(state
) ||
238 !PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u
->sink_input
)))
241 pa_sink_input_cork(u
->sink_input
, state
== PA_SINK_SUSPENDED
);
245 /* Called from I/O thread context */
246 static void sink_request_rewind(pa_sink
*s
) {
249 pa_sink_assert_ref(s
);
250 pa_assert_se(u
= s
->userdata
);
252 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
253 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
256 /* Just hand this one over to the master sink */
257 pa_sink_input_request_rewind(u
->sink_input
, s
->thread_info
.rewind_nbytes
+pa_memblockq_get_length(u
->input_q
), TRUE
, FALSE
, FALSE
);
260 /* Called from I/O thread context */
261 static void sink_update_requested_latency(pa_sink
*s
) {
264 pa_sink_assert_ref(s
);
265 pa_assert_se(u
= s
->userdata
);
267 if (!PA_SINK_IS_LINKED(u
->sink
->thread_info
.state
) ||
268 !PA_SINK_INPUT_IS_LINKED(u
->sink_input
->thread_info
.state
))
271 /* Just hand this one over to the master sink */
272 pa_sink_input_set_requested_latency_within_thread(
274 pa_sink_get_requested_latency_within_thread(s
));
277 typedef float v4sf
__attribute__ ((__aligned__(v_size
* sizeof(float))));
278 typedef union float_vector
{
286 //reference implementation
287 static void dsp_logic(
288 float * restrict dst
,//used as a temp array too, needs to be fft_length!
289 float * restrict src
,/*input data w/ overlap at start,
290 *automatically cycled in routine
292 float * restrict overlap
,//The size of the overlap
293 const float * restrict H
,//The freq. magnitude scalers filter
294 const float * restrict W
,//The windowing function
295 fftwf_complex
* restrict output_window
,//The transformed window'd src
297 //use a linear-phase sliding STFT and overlap-add method (for each channel)
299 memset(dst
+ u
->window_size
, 0, (u
->fft_size
- u
->window_size
) * sizeof(float));
301 for(size_t j
= 0;j
< u
->window_size
; ++j
){
302 dst
[j
] = W
[j
] * src
[j
];
304 //Processing is done here!
306 fftwf_execute_dft_r2c(u
->forward_plan
, dst
, output_window
);
308 for(size_t j
= 0; j
< u
->fft_size
/ 2 + 1; ++j
){
309 u
->output_window
[j
][0] *= u
->H
[j
];
310 u
->output_window
[j
][1] *= u
->H
[j
];
313 fftwf_execute_dft_c2r(u
->inverse_plan
, output_window
, dst
);
314 ////debug: tests overlaping add
315 ////and negates ALL PREVIOUS processing
316 ////yields a perfect reconstruction if COLA is held
317 //for(size_t j = 0; j < u->window_size; ++j){
318 // u->work_buffer[j] = u->W[j] * u->input[c][j];
321 //overlap add and preserve overlap component from this window (linear phase)
322 for(size_t j
= 0;j
< u
->overlap_size
; ++j
){
323 u
->work_buffer
[j
] += overlap
[j
];
324 overlap
[j
] = dst
[u
->R
+j
];
326 ////debug: tests if basic buffering works
327 ////shouldn't modify the signal AT ALL (beyond roundoff)
328 //for(size_t j = 0; j < u->window_size;++j){
329 // u->work_buffer[j] = u->input[c][j];
332 //preseve the needed input for the next window's overlap
333 memmove(src
, src
+u
->R
,
334 ((u
->overlap_size
+ u
->samples_gathered
) - u
->R
)*sizeof(float)
338 ////regardless of sse enabled, the loops in here assume
339 ////16 byte aligned addresses and memory allocations divisible by v_size
341 // float * restrict dst,//used as a temp array too, needs to be fft_length!
342 // float * restrict src,/*input data w/ overlap at start,
343 // *automatically cycled in routine
345 // float * restrict overlap,//The size of the overlap
346 // const float * restrict H,//The freq. magnitude scalers filter
347 // const float * restrict W,//The windowing function
348 // fftwf_complex * restrict output_window,//The transformed window'd src
349 // struct userdata *u){//Collection of constants
351 // const size_t window_size = mround(u->window_size,v_size);
352 // const size_t fft_h = mround(u->fft_size / 2 + 1, v_size / 2);
353 // //const size_t R = mround(u->R, v_size);
354 // const size_t overlap_size = mround(u->overlap_size, v_size);
356 // //assert(u->samples_gathered >= u->R);
357 // //zero out the bit beyond the real overlap so we don't add garbage
358 // for(size_t j = overlap_size; j > u->overlap_size; --j){
361 // //use a linear-phase sliding STFT and overlap-add method
362 // //zero padd the data
363 // memset(dst + u->window_size, 0, (u->fft_size - u->window_size)*sizeof(float));
365 // for(size_t j = 0; j < window_size; j += v_size){
366 // //dst[j] = W[j]*src[j];
367 // float_vector_t *d = (float_vector_t*) (dst+j);
368 // float_vector_t *w = (float_vector_t*) (W+j);
369 // float_vector_t *s = (float_vector_t*) (src+j);
371 // d->m = _mm_mul_ps(w->m, s->m);
373 // d->v = w->v * s->v;
376 // //Processing is done here!
378 // fftwf_execute_dft_r2c(u->forward_plan, dst, output_window);
381 // //perform filtering - purely magnitude based
382 // for(size_t j = 0;j < fft_h; j+=v_size/2){
383 // //output_window[j][0]*=H[j];
384 // //output_window[j][1]*=H[j];
385 // float_vector_t *d = (float_vector_t*)(output_window+j);
387 // h.f[0] = h.f[1] = H[j];
388 // h.f[2] = h.f[3] = H[j+1];
390 // d->m = _mm_mul_ps(d->m, h.m);
396 // fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst);
398 // ////debug: tests overlaping add
399 // ////and negates ALL PREVIOUS processing
400 // ////yields a perfect reconstruction if COLA is held
401 // //for(size_t j = 0; j < u->window_size; ++j){
402 // // dst[j] = W[j]*src[j];
405 // //overlap add and preserve overlap component from this window (linear phase)
406 // for(size_t j = 0; j < overlap_size; j+=v_size){
407 // //dst[j]+=overlap[j];
408 // //overlap[j]+=dst[j+R];
409 // float_vector_t *d = (float_vector_t*)(dst+j);
410 // float_vector_t *o = (float_vector_t*)(overlap+j);
412 // d->m = _mm_add_ps(d->m, o->m);
413 // o->m = ((float_vector_t*)(dst+u->R+j))->m;
416 // o->v = ((float_vector_t*)(dst+u->R+j))->v;
419 // //memcpy(overlap, dst+u->R, u->overlap_size*sizeof(float));
421 // //////debug: tests if basic buffering works
422 // //////shouldn't modify the signal AT ALL (beyond roundoff)
423 // //for(size_t j = 0; j < u->window_size; ++j){
424 // // dst[j] = src[j];
427 // //preseve the needed input for the next window's overlap
428 // memmove(src, src+u->R,
429 // ((u->overlap_size+u->samples_gathered)+-u->R)*sizeof(float)
433 static void process_samples(struct userdata
*u
, pa_memchunk
*tchunk
){
434 size_t fs
=pa_frame_size(&(u
->sink
->sample_spec
));
436 pa_assert(u
->samples_gathered
>= u
->R
);
438 tchunk
->length
= u
->R
* fs
;
439 tchunk
->memblock
= pa_memblock_new(u
->sink
->core
->mempool
, tchunk
->length
);
440 dst
= ((float*)pa_memblock_acquire(tchunk
->memblock
));
441 for(size_t c
=0;c
< u
->channels
; c
++) {
451 if(u
->first_iteration
){
452 /* The windowing function will make the audio ramped in, as a cheap fix we can
453 * undo the windowing (for non-zero window values)
455 for(size_t i
= 0;i
< u
->overlap_size
; ++i
){
456 u
->work_buffer
[i
] = u
->W
[i
] <= FLT_EPSILON
? u
->work_buffer
[i
] : u
->work_buffer
[i
] / u
->W
[i
];
459 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, dst
+ c
, fs
, u
->work_buffer
, sizeof(float), u
->R
);
461 pa_memblock_release(tchunk
->memblock
);
462 u
->samples_gathered
-= u
->R
;
465 static void initialize_buffer(struct userdata
*u
, pa_memchunk
*in
){
466 size_t fs
= pa_frame_size(&u
->sink
->sample_spec
);
467 size_t samples
= in
->length
/ fs
;
468 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
469 pa_assert_se(u
->samples_gathered
+ samples
<= u
->window_size
);
470 for(size_t c
= 0; c
< u
->channels
; c
++) {
471 //buffer with an offset after the overlap from previous
473 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
] + u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
475 u
->samples_gathered
+= samples
;
476 pa_memblock_release(in
->memblock
);
479 static void input_buffer(struct userdata
*u
, pa_memchunk
*in
){
480 size_t fs
= pa_frame_size(&(u
->sink
->sample_spec
));
481 size_t samples
= in
->length
/fs
;
482 float *src
= (float*) ((uint8_t*) pa_memblock_acquire(in
->memblock
) + in
->index
);
483 pa_assert_se(samples
<= u
->window_size
- u
->samples_gathered
);
484 for(size_t c
= 0; c
< u
->channels
; c
++) {
485 //buffer with an offset after the overlap from previous
488 u
->input
[c
]+u
->samples_gathered
+samples
<= u
->input
[c
]+u
->window_size
490 pa_sample_clamp(PA_SAMPLE_FLOAT32NE
, u
->input
[c
]+u
->overlap_size
+u
->samples_gathered
, sizeof(float), src
+ c
, fs
, samples
);
492 u
->samples_gathered
+= samples
;
493 pa_memblock_release(in
->memblock
);
496 /* Called from I/O thread context */
497 static int sink_input_pop_cb(pa_sink_input
*i
, size_t nbytes
, pa_memchunk
*chunk
) {
500 struct timeval start
, end
;
502 pa_sink_input_assert_ref(i
);
503 pa_assert_se(u
= i
->userdata
);
506 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
507 chunk
->memblock
= NULL
;
509 /* Hmm, process any rewind request that might be queued up */
510 pa_sink_process_rewind(u
->sink
, 0);
512 //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested);
513 pa_timeval_load(&start
);
515 size_t input_remaining
= u
->window_size
- u
->samples_gathered
;
516 pa_assert(input_remaining
> 0);
519 //buffer = &u->conv_buffer;
520 //buffer->length = input_remaining*fs;
522 //pa_memblock_ref(buffer->memblock);
523 //pa_sink_render_into(u->sink, buffer);
524 while(pa_memblockq_peek(u
->input_q
, &tchunk
) < 0){
525 pa_sink_render(u
->sink
, input_remaining
*fs
, &tchunk
);
526 pa_assert(tchunk
.memblock
);
527 pa_memblockq_push(u
->input_q
, &tchunk
);
528 pa_memblock_unref(tchunk
.memblock
);
530 pa_assert(tchunk
.memblock
);
531 tchunk
.length
= PA_MIN(input_remaining
* fs
, tchunk
.length
);
532 pa_memblockq_drop(u
->input_q
, tchunk
.length
);
533 //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs);
535 //pa_timeval_load(start);
536 if(u
->first_iteration
){
537 initialize_buffer(u
, &tchunk
);
539 input_buffer(u
, &tchunk
);
541 //pa_timeval_load(&end);
542 //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC);
543 pa_memblock_unref(tchunk
.memblock
);
544 }while(u
->samples_gathered
< u
->window_size
);
545 pa_timeval_load(&end
);
546 pa_log_debug("Took %0.6f seconds to get data", pa_timeval_diff(&end
, &start
) / (double) PA_USEC_PER_SEC
);
548 pa_assert(u
->fft_size
>= u
->window_size
);
549 pa_assert(u
->R
< u
->window_size
);
550 /* set the H filter */
551 u
->H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
552 pa_timeval_load(&start
);
553 /* process a block */
554 process_samples(u
, chunk
);
555 pa_timeval_load(&end
);
556 pa_log_debug("Took %0.6f seconds to process", pa_timeval_diff(&end
, &start
) / (double) PA_USEC_PER_SEC
);
557 pa_aupdate_read_end(u
->a_H
);
559 pa_assert(chunk
->memblock
);
560 //pa_log_debug("gave %ld", chunk->length/fs);
561 //pa_log_debug("end pop");
562 if(u
->first_iteration
){
563 u
->first_iteration
= FALSE
;
568 static void reset_filter(struct userdata
*u
){
569 u
->samples_gathered
= 0;
570 for(size_t i
= 0;i
< u
->channels
; ++i
){
571 memset(u
->overlap_accum
[i
], 0, u
->overlap_size
* sizeof(float));
573 u
->first_iteration
= TRUE
;
576 /* Called from I/O thread context */
577 static void sink_input_process_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
581 pa_log_debug("Rewind callback!");
582 pa_sink_input_assert_ref(i
);
583 pa_assert_se(u
= i
->userdata
);
585 if (u
->sink
->thread_info
.rewind_nbytes
> 0) {
588 //max_rewrite = nbytes;
589 max_rewrite
= nbytes
+ pa_memblockq_get_length(u
->input_q
);
590 //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes);
591 amount
= PA_MIN(u
->sink
->thread_info
.rewind_nbytes
, max_rewrite
);
592 u
->sink
->thread_info
.rewind_nbytes
= 0;
595 //pa_sample_spec *ss = &u->sink->sample_spec;
596 //invalidate the output q
597 pa_memblockq_seek(u
->input_q
, - (int64_t) amount
, PA_SEEK_RELATIVE
, TRUE
);
598 //pa_memblockq_drop(u->input_q, pa_memblockq_get_length(u->input_q));
599 //pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, TRUE);
600 pa_log("Resetting filter");
605 pa_sink_process_rewind(u
->sink
, amount
);
606 pa_memblockq_rewind(u
->input_q
, nbytes
);
609 /* Called from I/O thread context */
610 static void sink_input_update_max_rewind_cb(pa_sink_input
*i
, size_t nbytes
) {
613 pa_sink_input_assert_ref(i
);
614 pa_assert_se(u
= i
->userdata
);
616 pa_memblockq_set_maxrewind(u
->input_q
, nbytes
);
617 pa_sink_set_max_rewind_within_thread(u
->sink
, nbytes
);
620 /* Called from I/O thread context */
621 static void sink_input_update_max_request_cb(pa_sink_input
*i
, size_t nbytes
) {
624 pa_sink_input_assert_ref(i
);
625 pa_assert_se(u
= i
->userdata
);
627 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
628 //pa_sink_set_max_request_within_thread(u->sink, nbytes);
629 //pa_sink_set_max_request_within_thread(u->sink, u->R*fs);
630 pa_sink_set_max_request_within_thread(u
->sink
, ((nbytes
+u
->R
*fs
-1)/(u
->R
*fs
))*(u
->R
*fs
));
633 /* Called from I/O thread context */
634 static void sink_input_update_sink_latency_range_cb(pa_sink_input
*i
) {
637 pa_sink_input_assert_ref(i
);
638 pa_assert_se(u
= i
->userdata
);
640 //pa_sink_set_latency_range_within_thread(u->sink, u->master->thread_info.min_latency, u->latency*fs);
641 //pa_sink_set_latency_range_within_thread(u->sink, u->latency*fs, u->latency*fs );
642 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
645 /* Called from I/O thread context */
646 static void sink_input_update_sink_fixed_latency_cb(pa_sink_input
*i
) {
649 pa_sink_input_assert_ref(i
);
650 pa_assert_se(u
= i
->userdata
);
652 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
655 /* Called from I/O thread context */
656 static void sink_input_detach_cb(pa_sink_input
*i
) {
659 pa_sink_input_assert_ref(i
);
660 pa_assert_se(u
= i
->userdata
);
662 pa_sink_detach_within_thread(u
->sink
);
664 pa_sink_set_rtpoll(u
->sink
, NULL
);
667 /* Called from I/O thread context */
668 static void sink_input_attach_cb(pa_sink_input
*i
) {
671 pa_sink_input_assert_ref(i
);
672 pa_assert_se(u
= i
->userdata
);
674 pa_sink_set_rtpoll(u
->sink
, i
->sink
->thread_info
.rtpoll
);
675 pa_sink_set_latency_range_within_thread(u
->sink
, i
->sink
->thread_info
.min_latency
, i
->sink
->thread_info
.max_latency
);
677 pa_sink_set_fixed_latency_within_thread(u
->sink
, i
->sink
->thread_info
.fixed_latency
);
678 fs
= pa_frame_size(&(u
->sink
->sample_spec
));
679 pa_sink_attach_within_thread(u
->sink
);
680 pa_sink_set_max_request_within_thread(u
->sink
, mround(pa_sink_input_get_max_request(i
), u
->R
*fs
));
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);
691 /* Called from main context */
692 static void sink_input_kill_cb(pa_sink_input
*i
) {
695 pa_sink_input_assert_ref(i
);
696 pa_assert_se(u
= i
->userdata
);
698 /* The order here matters! We first kill the sink input, followed
699 * by the sink. That means the sink callbacks must be protected
700 * against an unconnected sink input! */
701 pa_sink_input_unlink(u
->sink_input
);
702 pa_sink_unlink(u
->sink
);
704 pa_sink_input_unref(u
->sink_input
);
705 u
->sink_input
= NULL
;
707 pa_sink_unref(u
->sink
);
710 pa_module_unload_request(u
->module
, TRUE
);
713 /* Called from IO thread context */
714 static void sink_input_state_change_cb(pa_sink_input
*i
, pa_sink_input_state_t state
) {
717 pa_sink_input_assert_ref(i
);
718 pa_assert_se(u
= i
->userdata
);
720 /* If we are added for the first time, ask for a rewinding so that
721 * we are heard right-away. */
722 if (PA_SINK_INPUT_IS_LINKED(state
) &&
723 i
->thread_info
.state
== PA_SINK_INPUT_INIT
) {
724 pa_log_debug("Requesting rewind due to state change.");
725 pa_sink_input_request_rewind(i
, 0, FALSE
, TRUE
, TRUE
);
729 static void save_profile(struct userdata
*u
, char *name
){
730 float *H_n
= pa_xmalloc((u
->fft_size
/ 2 + 1) * sizeof(float));
731 const float *H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
733 for(size_t i
= 0 ; i
<= u
->fft_size
/ 2 + 1; ++i
){
734 //H_n[i] = H[i] * u->fft_size;
737 pa_aupdate_read_end(u
->a_H
);
739 key
.size
= strlen(key
.data
);
741 data
.size
= (u
->fft_size
/ 2 + 1) * sizeof(float);
742 pa_database_set(u
->database
, &key
, &data
, TRUE
);
743 pa_database_sync(u
->database
);
746 static void save_state(struct userdata
*u
){
747 char *state_name
= pa_sprintf_malloc("%s-previous-state", u
->name
);
748 save_profile(u
, state_name
);
749 pa_xfree(state_name
);
752 static void remove_profile(pa_core
*c
, char *name
){
754 pa_database
*database
;
756 key
.size
= strlen(key
.data
);
757 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
758 pa_database_unset(database
, &key
);
759 pa_database_sync(database
);
762 static const char* load_profile(struct userdata
*u
, char *name
){
765 key
.size
= strlen(key
.data
);
766 if(pa_database_get(u
->database
, &key
, &value
) != NULL
){
767 if(value
.size
== (u
->fft_size
/ 2 + 1) * sizeof(float)){
768 float *H
=u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
769 memcpy(H
, value
.data
, value
.size
);
770 pa_aupdate_write_end(u
->a_H
);
772 return "incompatible size";
774 pa_datum_free(&value
);
776 return "profile doesn't exist";
779 //fix_filter(u->H, u->fft_size);
782 static void load_state(struct userdata
*u
){
783 char *state_name
=pa_sprintf_malloc("%s-previous-state", u
->name
);
784 load_profile(u
,state_name
);
785 pa_xfree(state_name
);
788 /* Called from main context */
789 static pa_bool_t
sink_input_may_move_to_cb(pa_sink_input
*i
, pa_sink
*dest
) {
792 pa_sink_input_assert_ref(i
);
793 pa_assert_se(u
= i
->userdata
);
795 return u
->sink
!= dest
;
798 /* Called from main context */
799 static void sink_input_moving_cb(pa_sink_input
*i
, pa_sink
*dest
) {
802 pa_sink_input_assert_ref(i
);
803 pa_assert_se(u
= i
->userdata
);
805 pa_sink_set_asyncmsgq(u
->sink
, dest
->asyncmsgq
);
806 pa_sink_update_flags(u
->sink
, PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
, dest
->flags
);
809 //ensure's memory allocated is a multiple of v_size
811 static void * alloc(size_t x
,size_t s
){
812 size_t f
= mround(x
*s
, sizeof(float)*v_size
);
815 //printf("requested %ld floats=%ld bytes, rem=%ld\n", x, x*sizeof(float), x*sizeof(float)%16);
816 //printf("giving %ld floats=%ld bytes, rem=%ld\n", f, f*sizeof(float), f*sizeof(float)%16);
822 int pa__init(pa_module
*m
) {
829 pa_sink_input_new_data sink_input_data
;
830 pa_sink_new_data sink_data
;
831 pa_bool_t
*use_default
= NULL
;
837 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
838 pa_log("Failed to parse module arguments.");
842 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SINK
))) {
843 pa_log("Master sink not found");
847 ss
= master
->sample_spec
;
848 ss
.format
= PA_SAMPLE_FLOAT32
;
849 map
= master
->channel_map
;
850 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
851 pa_log("Invalid sample format specification or channel map");
854 fs
= pa_frame_size(&ss
);
856 u
= pa_xnew0(struct userdata
, 1);
860 u
->channels
= ss
.channels
;
861 u
->fft_size
= pow(2, ceil(log(ss
.rate
)/log(2)));
862 pa_log_debug("fft size: %ld", u
->fft_size
);
863 u
->window_size
= 15999;
864 u
->R
= (u
->window_size
+ 1) / 2;
865 u
->overlap_size
= u
->window_size
- u
->R
;
866 u
->samples_gathered
= 0;
867 u
->a_H
= pa_aupdate_new();
868 u
->latency
= u
->window_size
- u
->R
;
869 for(size_t i
= 0; i
< 2; ++i
){
870 u
->Hs
[i
] = alloc((u
->fft_size
/ 2 + 1), sizeof(float));
872 u
->W
= alloc(u
->window_size
, sizeof(float));
873 u
->work_buffer
= alloc(u
->fft_size
, sizeof(float));
874 memset(u
->work_buffer
, 0, u
->fft_size
*sizeof(float));
875 u
->input
= pa_xnew0(float *, u
->channels
);
876 u
->overlap_accum
= pa_xnew0(float *, u
->channels
);
877 for(size_t c
= 0; c
< u
->channels
; ++c
){
878 u
->input
[c
] = alloc(u
->window_size
, sizeof(float));
879 memset(u
->input
[c
], 0, (u
->window_size
)*sizeof(float));
880 u
->overlap_accum
[c
] = alloc(u
->overlap_size
, sizeof(float));
881 memset(u
->overlap_accum
[c
], 0, u
->overlap_size
*sizeof(float));
883 u
->output_window
= alloc((u
->fft_size
/ 2 + 1), sizeof(fftwf_complex
));
884 u
->forward_plan
= fftwf_plan_dft_r2c_1d(u
->fft_size
, u
->work_buffer
, u
->output_window
, FFTW_ESTIMATE
);
885 u
->inverse_plan
= fftwf_plan_dft_c2r_1d(u
->fft_size
, u
->output_window
, u
->work_buffer
, FFTW_ESTIMATE
);
887 hanning_window(u
->W
, u
->window_size
);
888 u
->first_iteration
= TRUE
;
891 pa_sink_new_data_init(&sink_data
);
892 sink_data
.driver
= __FILE__
;
893 sink_data
.module
= m
;
894 if (!(sink_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "sink_name", NULL
))))
895 sink_data
.name
= pa_sprintf_malloc("%s.equalizer", master
->name
);
896 pa_sink_new_data_set_sample_spec(&sink_data
, &ss
);
897 pa_sink_new_data_set_channel_map(&sink_data
, &map
);
898 z
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
899 pa_proplist_setf(sink_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "FFT based equalizer on %s",z
? z
: master
->name
);
900 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
901 pa_proplist_sets(sink_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
903 if (pa_modargs_get_proplist(ma
, "sink_properties", sink_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
904 pa_log("Invalid properties");
905 pa_sink_new_data_done(&sink_data
);
909 u
->sink
= pa_sink_new(m
->core
, &sink_data
, master
->flags
& (PA_SINK_LATENCY
|PA_SINK_DYNAMIC_LATENCY
));
910 pa_sink_new_data_done(&sink_data
);
913 pa_log("Failed to create sink.");
916 u
->name
=pa_xstrdup(u
->sink
->name
);
917 u
->sink
->parent
.process_msg
= sink_process_msg
;
918 u
->sink
->set_state
= sink_set_state
;
919 u
->sink
->update_requested_latency
= sink_update_requested_latency
;
920 u
->sink
->request_rewind
= sink_request_rewind
;
921 u
->sink
->userdata
= u
;
922 u
->input_q
= pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH
, 0, fs
, 1, 1, 0, &u
->sink
->silence
);
924 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
925 //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss));
927 /* Create sink input */
928 pa_sink_input_new_data_init(&sink_input_data
);
929 sink_input_data
.driver
= __FILE__
;
930 sink_input_data
.module
= m
;
931 sink_input_data
.sink
= master
;
932 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_NAME
, "Equalized Stream");
933 pa_proplist_sets(sink_input_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
934 pa_sink_input_new_data_set_sample_spec(&sink_input_data
, &ss
);
935 pa_sink_input_new_data_set_channel_map(&sink_input_data
, &map
);
937 pa_sink_input_new(&u
->sink_input
, m
->core
, &sink_input_data
, 0);
938 pa_sink_input_new_data_done(&sink_input_data
);
943 u
->sink_input
->pop
= sink_input_pop_cb
;
944 u
->sink_input
->process_rewind
= sink_input_process_rewind_cb
;
945 u
->sink_input
->update_max_rewind
= sink_input_update_max_rewind_cb
;
946 u
->sink_input
->update_max_request
= sink_input_update_max_request_cb
;
947 u
->sink_input
->update_sink_latency_range
= sink_input_update_sink_latency_range_cb
;
948 u
->sink_input
->update_sink_fixed_latency
= sink_input_update_sink_fixed_latency_cb
;
949 u
->sink_input
->kill
= sink_input_kill_cb
;
950 u
->sink_input
->attach
= sink_input_attach_cb
;
951 u
->sink_input
->detach
= sink_input_detach_cb
;
952 u
->sink_input
->state_change
= sink_input_state_change_cb
;
953 u
->sink_input
->may_move_to
= sink_input_may_move_to_cb
;
954 u
->sink_input
->moving
= sink_input_moving_cb
;
955 u
->sink_input
->userdata
= u
;
957 pa_sink_put(u
->sink
);
958 pa_sink_input_put(u
->sink_input
);
962 pa_xfree(use_default
);
966 //default filter to these
967 H
=u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
968 for(size_t i
= 0; i
< u
->fft_size
/ 2 + 1; ++i
){
969 H
[i
] = 1.0 / sqrtf(2.0f
);
971 fix_filter(H
, u
->fft_size
);
972 pa_aupdate_write_end(u
->a_H
);
973 //load old parameters
982 pa_xfree(use_default
);
989 int pa__get_n_used(pa_module
*m
) {
993 pa_assert_se(u
= m
->userdata
);
995 return pa_sink_linked_by(u
->sink
);
998 void pa__done(pa_module
*m
) {
1003 if (!(u
= m
->userdata
))
1010 /* See comments in sink_input_kill_cb() above regarding
1011 * destruction order! */
1014 pa_sink_input_unlink(u
->sink_input
);
1017 pa_sink_unlink(u
->sink
);
1020 pa_sink_input_unref(u
->sink_input
);
1023 pa_sink_unref(u
->sink
);
1025 pa_aupdate_free(u
->a_H
);
1026 pa_memblockq_free(u
->input_q
);
1028 fftwf_destroy_plan(u
->inverse_plan
);
1029 fftwf_destroy_plan(u
->forward_plan
);
1030 pa_xfree(u
->output_window
);
1031 for(size_t c
=0; c
< u
->channels
; ++c
){
1032 pa_xfree(u
->overlap_accum
[c
]);
1033 pa_xfree(u
->input
[c
]);
1035 pa_xfree(u
->overlap_accum
);
1037 pa_xfree(u
->work_buffer
);
1039 for(size_t i
= 0; i
< 2; ++i
){
1049 * DBus Routines and Callbacks
1051 #define EXTNAME "org.PulseAudio.Ext.Equalizing1"
1052 #define MANAGER_PATH "/org/pulseaudio/equalizing1"
1053 #define MANAGER_IFACE EXTNAME ".Manager"
1054 #define EQUALIZER_IFACE EXTNAME ".Equalizer"
1055 static void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1056 static void get_sinks(pa_core
*u
, char ***names
, unsigned *n_sinks
);
1057 static void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1058 static void get_profiles(pa_core
*u
, char ***names
, unsigned *n_sinks
);
1059 static void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1060 static void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1061 static void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1062 static void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1063 static void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1064 static void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1065 static void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1066 static void equalizer_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1067 static void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1068 static void equalizer_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1069 static void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1070 static void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1071 static void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1072 static void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
);
1073 static void get_filter(struct userdata
*u
, double **H_
);
1074 static void set_filter(struct userdata
*u
, double **H_
);
1075 enum manager_method_index
{
1076 MANAGER_METHOD_REMOVE_PROFILE
,
1080 pa_dbus_arg_info remove_profile_args
[]={
1084 static pa_dbus_method_handler manager_methods
[MANAGER_METHOD_MAX
]={
1085 [MANAGER_METHOD_REMOVE_PROFILE
]{
1086 .method_name
="RemoveProfile",
1087 .arguments
=remove_profile_args
,
1088 .n_arguments
=sizeof(remove_profile_args
)/sizeof(pa_dbus_arg_info
),
1089 .receive_cb
=manager_handle_remove_profile
}
1092 enum manager_handler_index
{
1093 MANAGER_HANDLER_REVISION
,
1094 MANAGER_HANDLER_EQUALIZED_SINKS
,
1095 MANAGER_HANDLER_PROFILES
,
1099 static pa_dbus_property_handler manager_handlers
[MANAGER_HANDLER_MAX
]={
1100 [MANAGER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=manager_get_revision
,.set_cb
=NULL
},
1101 [MANAGER_HANDLER_EQUALIZED_SINKS
]={.property_name
="EqualizedSinks",.type
="ao",.get_cb
=manager_get_sinks
,.set_cb
=NULL
},
1102 [MANAGER_HANDLER_PROFILES
]={.property_name
="Profiles",.type
="as",.get_cb
=manager_get_profiles
,.set_cb
=NULL
}
1105 pa_dbus_arg_info sink_args
[]={
1109 enum manager_signal_index
{
1110 MANAGER_SIGNAL_SINK_ADDED
,
1111 MANAGER_SIGNAL_SINK_REMOVED
,
1112 MANAGER_SIGNAL_PROFILES_CHANGED
,
1116 static pa_dbus_signal_info manager_signals
[MANAGER_SIGNAL_MAX
]={
1117 [MANAGER_SIGNAL_SINK_ADDED
]={.name
="SinkAdded", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1118 [MANAGER_SIGNAL_SINK_REMOVED
]={.name
="SinkRemoved", .arguments
=sink_args
, .n_arguments
=sizeof(sink_args
)/sizeof(pa_dbus_arg_info
)},
1119 [MANAGER_SIGNAL_PROFILES_CHANGED
]={.name
="ProfilesChanged", .arguments
=NULL
, .n_arguments
=0}
1122 static pa_dbus_interface_info manager_info
={
1123 .name
=MANAGER_IFACE
,
1124 .method_handlers
=manager_methods
,
1125 .n_method_handlers
=MANAGER_METHOD_MAX
,
1126 .property_handlers
=manager_handlers
,
1127 .n_property_handlers
=MANAGER_HANDLER_MAX
,
1128 .get_all_properties_cb
=manager_get_all
,
1129 .signals
=manager_signals
,
1130 .n_signals
=MANAGER_SIGNAL_MAX
1133 enum equalizer_method_index
{
1134 EQUALIZER_METHOD_FILTER_POINTS
,
1135 EQUALIZER_METHOD_SEED_FILTER
,
1136 EQUALIZER_METHOD_SAVE_PROFILE
,
1137 EQUALIZER_METHOD_LOAD_PROFILE
,
1138 EQUALIZER_METHOD_MAX
1141 enum equalizer_handler_index
{
1142 EQUALIZER_HANDLER_REVISION
,
1143 EQUALIZER_HANDLER_SAMPLERATE
,
1144 EQUALIZER_HANDLER_FILTERSAMPLERATE
,
1145 EQUALIZER_HANDLER_N_COEFS
,
1146 EQUALIZER_HANDLER_FILTER
,
1147 EQUALIZER_HANDLER_MAX
1150 pa_dbus_arg_info filter_points_args
[]={
1154 pa_dbus_arg_info seed_filter_args
[]={
1158 pa_dbus_arg_info save_profile_args
[]={
1161 pa_dbus_arg_info load_profile_args
[]={
1165 static pa_dbus_method_handler equalizer_methods
[EQUALIZER_METHOD_MAX
]={
1166 [EQUALIZER_METHOD_SEED_FILTER
]{
1167 .method_name
="SeedFilter",
1168 .arguments
=seed_filter_args
,
1169 .n_arguments
=sizeof(seed_filter_args
)/sizeof(pa_dbus_arg_info
),
1170 .receive_cb
=equalizer_handle_seed_filter
},
1171 [EQUALIZER_METHOD_FILTER_POINTS
]{
1172 .method_name
="FilterAtPoints",
1173 .arguments
=filter_points_args
,
1174 .n_arguments
=sizeof(filter_points_args
)/sizeof(pa_dbus_arg_info
),
1175 .receive_cb
=equalizer_handle_get_filter_points
},
1176 [EQUALIZER_METHOD_SAVE_PROFILE
]{
1177 .method_name
="SaveProfile",
1178 .arguments
=save_profile_args
,
1179 .n_arguments
=sizeof(save_profile_args
)/sizeof(pa_dbus_arg_info
),
1180 .receive_cb
=equalizer_handle_save_profile
},
1181 [EQUALIZER_METHOD_LOAD_PROFILE
]{
1182 .method_name
="LoadProfile",
1183 .arguments
=load_profile_args
,
1184 .n_arguments
=sizeof(load_profile_args
)/sizeof(pa_dbus_arg_info
),
1185 .receive_cb
=equalizer_handle_load_profile
},
1188 static pa_dbus_property_handler equalizer_handlers
[EQUALIZER_HANDLER_MAX
]={
1189 [EQUALIZER_HANDLER_REVISION
]={.property_name
="InterfaceRevision",.type
="u",.get_cb
=equalizer_get_revision
,.set_cb
=NULL
},
1190 [EQUALIZER_HANDLER_SAMPLERATE
]{.property_name
="SampleRate",.type
="u",.get_cb
=equalizer_get_sample_rate
,.set_cb
=NULL
},
1191 [EQUALIZER_HANDLER_FILTERSAMPLERATE
]{.property_name
="FilterSampleRate",.type
="u",.get_cb
=equalizer_get_filter_rate
,.set_cb
=NULL
},
1192 [EQUALIZER_HANDLER_N_COEFS
]{.property_name
="NFilterCoefficients",.type
="u",.get_cb
=equalizer_get_n_coefs
,.set_cb
=NULL
},
1193 [EQUALIZER_HANDLER_FILTER
]{.property_name
="Filter",.type
="ad",.get_cb
=equalizer_get_filter
,.set_cb
=equalizer_set_filter
},
1196 enum equalizer_signal_index
{
1197 EQUALIZER_SIGNAL_FILTER_CHANGED
,
1198 EQUALIZER_SIGNAL_SINK_RECONFIGURED
,
1199 EQUALIZER_SIGNAL_MAX
1202 static pa_dbus_signal_info equalizer_signals
[EQUALIZER_SIGNAL_MAX
]={
1203 [EQUALIZER_SIGNAL_FILTER_CHANGED
]={.name
="FilterChanged", .arguments
=NULL
, .n_arguments
=0},
1204 [EQUALIZER_SIGNAL_SINK_RECONFIGURED
]={.name
="SinkReconfigured", .arguments
=NULL
, .n_arguments
=0},
1207 static pa_dbus_interface_info equalizer_info
={
1208 .name
=EQUALIZER_IFACE
,
1209 .method_handlers
=equalizer_methods
,
1210 .n_method_handlers
=EQUALIZER_METHOD_MAX
,
1211 .property_handlers
=equalizer_handlers
,
1212 .n_property_handlers
=EQUALIZER_HANDLER_MAX
,
1213 .get_all_properties_cb
=equalizer_get_all
,
1214 .signals
=equalizer_signals
,
1215 .n_signals
=EQUALIZER_SIGNAL_MAX
1218 static void dbus_init(struct userdata
*u
){
1220 DBusMessage
*signal
= NULL
;
1221 pa_idxset
*sink_list
= NULL
;
1222 u
->dbus_protocol
=pa_dbus_protocol_get(u
->sink
->core
);
1223 u
->dbus_path
=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u
->sink
->index
);
1225 pa_dbus_protocol_add_interface(u
->dbus_protocol
, u
->dbus_path
, &equalizer_info
, u
);
1226 sink_list
= pa_shared_get(u
->sink
->core
, SINKLIST
);
1227 u
->database
=pa_shared_get(u
->sink
->core
, EQDB
);
1228 if(sink_list
==NULL
){
1230 sink_list
=pa_idxset_new(&pa_idxset_trivial_hash_func
, &pa_idxset_trivial_compare_func
);
1231 pa_shared_set(u
->sink
->core
, SINKLIST
, sink_list
);
1232 pa_assert_se(dbname
= pa_state_path("equalizers", TRUE
));
1233 pa_assert_se(u
->database
= pa_database_open(dbname
, TRUE
));
1235 pa_shared_set(u
->sink
->core
,EQDB
,u
->database
);
1236 pa_dbus_protocol_add_interface(u
->dbus_protocol
, MANAGER_PATH
, &manager_info
, u
->sink
->core
);
1237 pa_dbus_protocol_register_extension(u
->dbus_protocol
, EXTNAME
);
1239 pa_idxset_put(sink_list
, u
, &dummy
);
1241 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_ADDED
].name
)));
1242 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1243 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1244 dbus_message_unref(signal
);
1247 static void dbus_done(struct userdata
*u
){
1248 pa_idxset
*sink_list
;
1251 DBusMessage
*signal
= NULL
;
1252 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_SINK_REMOVED
].name
)));
1253 dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &u
->dbus_path
, DBUS_TYPE_INVALID
);
1254 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1255 dbus_message_unref(signal
);
1257 pa_assert_se(sink_list
=pa_shared_get(u
->sink
->core
,SINKLIST
));
1258 pa_idxset_remove_by_data(sink_list
,u
,&dummy
);
1259 if(pa_idxset_size(sink_list
)==0){
1260 pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, EXTNAME
);
1261 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, MANAGER_PATH
, manager_info
.name
);
1262 pa_shared_remove(u
->sink
->core
, EQDB
);
1263 pa_database_close(u
->database
);
1264 pa_shared_remove(u
->sink
->core
, SINKLIST
);
1265 pa_xfree(sink_list
);
1267 pa_dbus_protocol_remove_interface(u
->dbus_protocol
, u
->dbus_path
, equalizer_info
.name
);
1268 pa_xfree(u
->dbus_path
);
1269 pa_dbus_protocol_unref(u
->dbus_protocol
);
1272 static void manager_handle_remove_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1274 pa_core
*c
= (pa_core
*)_u
;
1275 DBusMessage
*signal
= NULL
;
1276 pa_dbus_protocol
*dbus_protocol
;
1281 dbus_error_init(&error
);
1282 if(!dbus_message_get_args(msg
, &error
,
1283 DBUS_TYPE_STRING
, &name
,
1284 DBUS_TYPE_INVALID
)){
1285 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1286 dbus_error_free(&error
);
1289 remove_profile(c
,name
);
1290 pa_dbus_send_empty_reply(conn
, msg
);
1292 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1293 dbus_protocol
= pa_dbus_protocol_get(c
);
1294 pa_dbus_protocol_send_signal(dbus_protocol
, signal
);
1295 pa_dbus_protocol_unref(dbus_protocol
);
1296 dbus_message_unref(signal
);
1299 static void manager_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1301 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1304 static void get_sinks(pa_core
*u
, char ***names
, unsigned *n_sinks
){
1306 struct userdata
*sink_u
= NULL
;
1308 pa_idxset
*sink_list
;
1313 pa_assert_se(sink_list
= pa_shared_get(u
, SINKLIST
));
1314 *n_sinks
= (unsigned) pa_idxset_size(sink_list
);
1315 *names
= *n_sinks
> 0 ? pa_xnew0(char *,*n_sinks
) : NULL
;
1316 for(uint32_t i
= 0; i
< *n_sinks
; ++i
){
1317 sink_u
= (struct userdata
*) pa_idxset_iterate(sink_list
, &iter
, &dummy
);
1318 (*names
)[i
] = pa_xstrdup(sink_u
->dbus_path
);
1322 static void manager_get_sinks(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1324 char **names
= NULL
;
1329 get_sinks((pa_core
*) _u
, &names
, &n
);
1330 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1331 for(unsigned i
= 0; i
< n
; ++i
){
1337 static void get_profiles(pa_core
*c
, char ***names
, unsigned *n
){
1339 pa_database
*database
;
1340 pa_datum key
, next_key
;
1341 pa_strlist
*head
=NULL
, *iter
;
1343 pa_assert_se(database
= pa_shared_get(c
, EQDB
));
1348 done
= !pa_database_first(database
, &key
, NULL
);
1351 done
= !pa_database_next(database
, &key
, &next_key
, NULL
);
1352 name
=pa_xmalloc(key
.size
+ 1);
1353 memcpy(name
, key
.data
, key
.size
);
1354 name
[key
.size
] = '\0';
1355 pa_datum_free(&key
);
1356 head
= pa_strlist_prepend(head
, name
);
1361 (*names
) = *n
> 0 ? pa_xnew0(char *, *n
) : NULL
;
1363 for(unsigned i
= 0; i
< *n
; ++i
){
1364 (*names
)[*n
- 1 - i
] = pa_xstrdup(pa_strlist_data(iter
));
1365 iter
= pa_strlist_next(iter
);
1367 pa_strlist_free(head
);
1370 static void manager_get_profiles(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1377 get_profiles((pa_core
*)_u
, &names
, &n
);
1378 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, names
, n
);
1379 for(unsigned i
= 0; i
< n
; ++i
){
1385 static void manager_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1387 char **names
= NULL
;
1389 DBusMessage
*reply
= NULL
;
1390 DBusMessageIter msg_iter
, dict_iter
;
1394 pa_assert_se(c
= _u
);
1396 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1397 dbus_message_iter_init_append(reply
, &msg_iter
);
1398 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1401 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1403 get_sinks(c
, &names
, &n
);
1404 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
,manager_handlers
[MANAGER_HANDLER_EQUALIZED_SINKS
].property_name
, DBUS_TYPE_OBJECT_PATH
, names
, n
);
1405 for(unsigned i
= 0; i
< n
; ++i
){
1410 get_profiles(c
, &names
, &n
);
1411 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, manager_handlers
[MANAGER_HANDLER_PROFILES
].property_name
, DBUS_TYPE_STRING
, names
, n
);
1412 for(unsigned i
= 0; i
< n
; ++i
){
1416 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1417 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1418 dbus_message_unref(reply
);
1421 static void equalizer_handle_seed_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1422 struct userdata
*u
=(struct userdata
*) _u
;
1424 DBusMessage
*signal
= NULL
;
1428 unsigned x_npoints
, y_npoints
;
1430 pa_bool_t points_good
= TRUE
;
1435 dbus_error_init(&error
);
1437 if(!dbus_message_get_args(msg
, &error
,
1438 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1439 DBUS_TYPE_ARRAY
, DBUS_TYPE_DOUBLE
, &_ys
, &y_npoints
,
1440 DBUS_TYPE_INVALID
)){
1441 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1442 dbus_error_free(&error
);
1445 for(size_t i
= 0; i
< x_npoints
; ++i
){
1446 if(xs
[i
] >= u
->fft_size
/ 2 + 1){
1447 points_good
= FALSE
;
1451 if(!is_monotonic(xs
, x_npoints
) || !points_good
){
1452 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs must be monotonic and 0<=x<=%ld", u
->fft_size
/ 2);
1453 dbus_error_free(&error
);
1456 }else if(x_npoints
!= y_npoints
|| x_npoints
< 2 || x_npoints
> u
->fft_size
/ 2 +1 ){
1457 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs and ys must be the same length and 2<=l<=%ld!", u
->fft_size
/ 2 + 1);
1458 dbus_error_free(&error
);
1460 }else if(xs
[0] != 0 || xs
[x_npoints
- 1] != u
->fft_size
/ 2){
1461 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs[0] must be 0 and xs[-1]=fft_size/2");
1462 dbus_error_free(&error
);
1466 ys
= pa_xmalloc(x_npoints
* sizeof(float));
1467 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1468 ys
[i
] = (float) _ys
[i
];
1471 H
= u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
1472 interpolate(H
, u
->fft_size
/ 2 + 1, xs
, ys
, x_npoints
);
1473 fix_filter(H
, u
->fft_size
);
1474 pa_aupdate_write_end(u
->a_H
);
1477 //Stupid for IO reasons? Add a save signal to dbus instead
1480 pa_dbus_send_empty_reply(conn
, msg
);
1482 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1483 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1484 dbus_message_unref(signal
);
1487 static void equalizer_handle_get_filter_points(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1488 struct userdata
*u
= (struct userdata
*) _u
;
1494 pa_bool_t points_good
=TRUE
;
1500 dbus_error_init(&error
);
1502 if(!dbus_message_get_args(msg
, &error
,
1503 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &xs
, &x_npoints
,
1504 DBUS_TYPE_INVALID
)){
1505 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1506 dbus_error_free(&error
);
1509 for(size_t i
= 0; i
< x_npoints
; ++i
){
1510 if(xs
[i
] >= u
->fft_size
/ 2 + 1){
1516 if(x_npoints
> u
->fft_size
/ 2 +1 || !points_good
){
1517 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "xs indices/length must be <= %ld!", u
->fft_size
/ 2 + 1);
1518 dbus_error_free(&error
);
1522 ys
= pa_xmalloc(x_npoints
* sizeof(double));
1523 H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
1524 for(uint32_t i
= 0; i
< x_npoints
; ++i
){
1525 ys
[i
] = H
[xs
[i
]] * u
->fft_size
;
1527 pa_aupdate_read_end(u
->a_H
);
1529 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_DOUBLE
, ys
, x_npoints
);
1533 static void equalizer_handle_save_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1534 struct userdata
*u
= (struct userdata
*) _u
;
1536 DBusMessage
*signal
= NULL
;
1541 dbus_error_init(&error
);
1543 if(!dbus_message_get_args(msg
, &error
,
1544 DBUS_TYPE_STRING
, &name
,
1545 DBUS_TYPE_INVALID
)){
1546 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1547 dbus_error_free(&error
);
1550 save_profile(u
,name
);
1551 pa_dbus_send_empty_reply(conn
, msg
);
1553 pa_assert_se((signal
= dbus_message_new_signal(MANAGER_PATH
, MANAGER_IFACE
, manager_signals
[MANAGER_SIGNAL_PROFILES_CHANGED
].name
)));
1554 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1555 dbus_message_unref(signal
);
1558 static void equalizer_handle_load_profile(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
) {
1559 struct userdata
*u
=(struct userdata
*) _u
;
1562 const char *err_msg
= NULL
;
1563 DBusMessage
*signal
= NULL
;
1568 dbus_error_init(&error
);
1570 if(!dbus_message_get_args(msg
, &error
,
1571 DBUS_TYPE_STRING
, &name
,
1572 DBUS_TYPE_INVALID
)){
1573 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
1574 dbus_error_free(&error
);
1577 err_msg
= load_profile(u
,name
);
1578 if(err_msg
!= NULL
){
1579 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
, "error loading profile %s: %s", name
, err_msg
);
1580 dbus_error_free(&error
);
1583 pa_dbus_send_empty_reply(conn
, msg
);
1585 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1586 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1587 dbus_message_unref(signal
);
1590 static void equalizer_get_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1592 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rev
);
1595 static void equalizer_get_n_coefs(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1598 pa_assert_se(u
= (struct userdata
*) _u
);
1602 n_coefs
= (uint32_t) (u
->fft_size
/ 2 + 1);
1603 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &n_coefs
);
1606 static void equalizer_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1609 pa_assert_se(u
= (struct userdata
*) _u
);
1613 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1614 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &rate
);
1617 static void equalizer_get_filter_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1620 pa_assert_se(u
= (struct userdata
*) _u
);
1624 fft_size
= (uint32_t) u
->fft_size
;
1625 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &fft_size
);
1628 static void get_filter(struct userdata
*u
, double **H_
){
1630 *H_
= pa_xnew0(double, u
->fft_size
/ 2 + 1);
1631 H
= u
->Hs
[pa_aupdate_read_begin(u
->a_H
)];
1632 for(size_t i
= 0;i
< u
->fft_size
/ 2 + 1; ++i
){
1633 (*H_
)[i
] = H
[i
] * u
->fft_size
;
1635 pa_aupdate_read_end(u
->a_H
);
1638 static void equalizer_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1640 DBusMessage
*reply
= NULL
;
1641 DBusMessageIter msg_iter
, dict_iter
;
1642 uint32_t rev
, n_coefs
, rate
, fft_size
;
1644 pa_assert_se(u
= (struct userdata
*) _u
);
1648 n_coefs
= (uint32_t) (u
->fft_size
/ 2 + 1);
1649 rate
= (uint32_t) u
->sink
->sample_spec
.rate
;
1650 fft_size
= (uint32_t) u
->fft_size
;
1652 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
1653 dbus_message_iter_init_append(reply
, &msg_iter
);
1654 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
1656 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_REVISION
].property_name
, DBUS_TYPE_UINT32
, &rev
);
1657 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_SAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &rate
);
1658 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_FILTERSAMPLERATE
].property_name
, DBUS_TYPE_UINT32
, &fft_size
);
1659 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_N_COEFS
].property_name
, DBUS_TYPE_UINT32
, &n_coefs
);
1661 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, equalizer_handlers
[EQUALIZER_HANDLER_FILTER
].property_name
, DBUS_TYPE_UINT32
, &H
);
1664 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
1665 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
1666 dbus_message_unref(reply
);
1669 static void equalizer_get_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1673 pa_assert_se(u
= (struct userdata
*) _u
);
1675 n_coefs
= u
->fft_size
/ 2 + 1;
1679 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_DOUBLE
, H_
, n_coefs
);
1683 static void set_filter(struct userdata
*u
, double **H_
){
1684 float *H
= u
->Hs
[pa_aupdate_write_begin(u
->a_H
)];
1685 for(size_t i
= 0; i
< u
->fft_size
/ 2 + 1; ++i
){
1686 H
[i
] = (float) (*H_
)[i
];
1688 fix_filter(H
, u
->fft_size
);
1689 pa_aupdate_write_end(u
->a_H
);
1692 static void equalizer_set_filter(DBusConnection
*conn
, DBusMessage
*msg
, void *_u
){
1696 DBusMessage
*signal
= NULL
;
1697 pa_assert_se(u
= (struct userdata
*) _u
);
1701 if(pa_dbus_get_fixed_array_set_property_arg(conn
, msg
, DBUS_TYPE_DOUBLE
, &H
, &_n_coefs
)){
1704 if(_n_coefs
!=u
->fft_size
/ 2 + 1){
1705 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "This filter takes exactly %ld coefficients, you gave %d", u
->fft_size
/ 2 + 1, _n_coefs
);
1709 //Stupid for IO reasons? Add a save signal to dbus instead
1712 pa_dbus_send_empty_reply(conn
, msg
);
1714 pa_assert_se((signal
= dbus_message_new_signal(u
->dbus_path
, EQUALIZER_IFACE
, equalizer_signals
[EQUALIZER_SIGNAL_FILTER_CHANGED
].name
)));
1715 pa_dbus_protocol_send_signal(u
->dbus_protocol
, signal
);
1716 dbus_message_unref(signal
);