153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci This module is based off Lennart Poettering's LADSPA sink and swaps out 553a5a1b3Sopenharmony_ci LADSPA functionality for a dbus-aware STFT OLA based digital equalizer. 653a5a1b3Sopenharmony_ci All new work is published under PulseAudio's original license. 753a5a1b3Sopenharmony_ci 853a5a1b3Sopenharmony_ci Copyright 2009 Jason Newton <nevion@gmail.com> 953a5a1b3Sopenharmony_ci 1053a5a1b3Sopenharmony_ci Original Author: 1153a5a1b3Sopenharmony_ci Copyright 2004-2008 Lennart Poettering 1253a5a1b3Sopenharmony_ci 1353a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 1453a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 1553a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 1653a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1753a5a1b3Sopenharmony_ci 1853a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1953a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 2053a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2153a5a1b3Sopenharmony_ci General Public License for more details. 2253a5a1b3Sopenharmony_ci 2353a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 2453a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 2553a5a1b3Sopenharmony_ci***/ 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2853a5a1b3Sopenharmony_ci#include <config.h> 2953a5a1b3Sopenharmony_ci#endif 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include <stdlib.h> 3253a5a1b3Sopenharmony_ci#include <stdio.h> 3353a5a1b3Sopenharmony_ci#include <float.h> 3453a5a1b3Sopenharmony_ci#include <math.h> 3553a5a1b3Sopenharmony_ci#include <string.h> 3653a5a1b3Sopenharmony_ci#include <stdint.h> 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci//#undef __SSE2__ 3953a5a1b3Sopenharmony_ci#ifdef __SSE2__ 4053a5a1b3Sopenharmony_ci#include <xmmintrin.h> 4153a5a1b3Sopenharmony_ci#include <emmintrin.h> 4253a5a1b3Sopenharmony_ci#endif 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci#include <fftw3.h> 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 4753a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h> 5053a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h> 5153a5a1b3Sopenharmony_ci#include <pulsecore/aupdate.h> 5253a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h> 5353a5a1b3Sopenharmony_ci#include <pulsecore/sink.h> 5453a5a1b3Sopenharmony_ci#include <pulsecore/module.h> 5553a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 5653a5a1b3Sopenharmony_ci#include <pulsecore/modargs.h> 5753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 5853a5a1b3Sopenharmony_ci#include <pulsecore/rtpoll.h> 5953a5a1b3Sopenharmony_ci#include <pulsecore/sample-util.h> 6053a5a1b3Sopenharmony_ci#include <pulsecore/shared.h> 6153a5a1b3Sopenharmony_ci#include <pulsecore/idxset.h> 6253a5a1b3Sopenharmony_ci#include <pulsecore/strlist.h> 6353a5a1b3Sopenharmony_ci#include <pulsecore/database.h> 6453a5a1b3Sopenharmony_ci#include <pulsecore/protocol-dbus.h> 6553a5a1b3Sopenharmony_ci#include <pulsecore/dbus-util.h> 6653a5a1b3Sopenharmony_ci 6753a5a1b3Sopenharmony_ciPA_MODULE_AUTHOR("Jason Newton"); 6853a5a1b3Sopenharmony_ciPA_MODULE_DESCRIPTION(_("General Purpose Equalizer")); 6953a5a1b3Sopenharmony_ciPA_MODULE_VERSION(PACKAGE_VERSION); 7053a5a1b3Sopenharmony_ciPA_MODULE_LOAD_ONCE(false); 7153a5a1b3Sopenharmony_ciPA_MODULE_USAGE( 7253a5a1b3Sopenharmony_ci _("sink_name=<name of the sink> " 7353a5a1b3Sopenharmony_ci "sink_properties=<properties for the sink> " 7453a5a1b3Sopenharmony_ci "sink_master=<sink to connect to> " 7553a5a1b3Sopenharmony_ci "format=<sample format> " 7653a5a1b3Sopenharmony_ci "rate=<sample rate> " 7753a5a1b3Sopenharmony_ci "channels=<number of channels> " 7853a5a1b3Sopenharmony_ci "channel_map=<channel map> " 7953a5a1b3Sopenharmony_ci "autoloaded=<set if this module is being loaded automatically> " 8053a5a1b3Sopenharmony_ci "use_volume_sharing=<yes or no> " 8153a5a1b3Sopenharmony_ci )); 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci#define MEMBLOCKQ_MAXLENGTH (16*1024*1024) 8453a5a1b3Sopenharmony_ci#define DEFAULT_AUTOLOADED false 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_cistruct userdata { 8753a5a1b3Sopenharmony_ci pa_module *module; 8853a5a1b3Sopenharmony_ci pa_sink *sink; 8953a5a1b3Sopenharmony_ci pa_sink_input *sink_input; 9053a5a1b3Sopenharmony_ci bool autoloaded; 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_ci size_t channels; 9353a5a1b3Sopenharmony_ci size_t fft_size;//length (res) of fft 9453a5a1b3Sopenharmony_ci size_t window_size;/* 9553a5a1b3Sopenharmony_ci *sliding window size 9653a5a1b3Sopenharmony_ci *effectively chooses R 9753a5a1b3Sopenharmony_ci */ 9853a5a1b3Sopenharmony_ci size_t R;/* the hop size between overlapping windows 9953a5a1b3Sopenharmony_ci * the latency of the filter, calculated from window_size 10053a5a1b3Sopenharmony_ci * based on constraints of COLA and window function 10153a5a1b3Sopenharmony_ci */ 10253a5a1b3Sopenharmony_ci //for twiddling with pulseaudio 10353a5a1b3Sopenharmony_ci size_t overlap_size;//window_size-R 10453a5a1b3Sopenharmony_ci size_t samples_gathered; 10553a5a1b3Sopenharmony_ci size_t input_buffer_max; 10653a5a1b3Sopenharmony_ci //message 10753a5a1b3Sopenharmony_ci float *W;//windowing function (time domain) 10853a5a1b3Sopenharmony_ci float *work_buffer, **input, **overlap_accum; 10953a5a1b3Sopenharmony_ci fftwf_complex *output_window; 11053a5a1b3Sopenharmony_ci fftwf_plan forward_plan, inverse_plan; 11153a5a1b3Sopenharmony_ci //size_t samplings; 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci float **Xs; 11453a5a1b3Sopenharmony_ci float ***Hs;//thread updatable copies of the freq response filters (magnitude based) 11553a5a1b3Sopenharmony_ci pa_aupdate **a_H; 11653a5a1b3Sopenharmony_ci pa_memblockq *input_q; 11753a5a1b3Sopenharmony_ci char *output_buffer; 11853a5a1b3Sopenharmony_ci size_t output_buffer_length; 11953a5a1b3Sopenharmony_ci size_t output_buffer_max_length; 12053a5a1b3Sopenharmony_ci pa_memblockq *output_q; 12153a5a1b3Sopenharmony_ci bool first_iteration; 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci pa_dbus_protocol *dbus_protocol; 12453a5a1b3Sopenharmony_ci char *dbus_path; 12553a5a1b3Sopenharmony_ci 12653a5a1b3Sopenharmony_ci pa_database *database; 12753a5a1b3Sopenharmony_ci char **base_profiles; 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci bool automatic_description; 13053a5a1b3Sopenharmony_ci}; 13153a5a1b3Sopenharmony_ci 13253a5a1b3Sopenharmony_cistatic const char* const valid_modargs[] = { 13353a5a1b3Sopenharmony_ci "sink_name", 13453a5a1b3Sopenharmony_ci "sink_properties", 13553a5a1b3Sopenharmony_ci "sink_master", 13653a5a1b3Sopenharmony_ci "format", 13753a5a1b3Sopenharmony_ci "rate", 13853a5a1b3Sopenharmony_ci "channels", 13953a5a1b3Sopenharmony_ci "channel_map", 14053a5a1b3Sopenharmony_ci "autoloaded", 14153a5a1b3Sopenharmony_ci "use_volume_sharing", 14253a5a1b3Sopenharmony_ci NULL 14353a5a1b3Sopenharmony_ci}; 14453a5a1b3Sopenharmony_ci 14553a5a1b3Sopenharmony_ci#define v_size 4 14653a5a1b3Sopenharmony_ci#define SINKLIST "equalized_sinklist" 14753a5a1b3Sopenharmony_ci#define EQDB "equalizer_db" 14853a5a1b3Sopenharmony_ci#define EQ_STATE_DB "equalizer-state" 14953a5a1b3Sopenharmony_ci#define FILTER_SIZE(u) ((u)->fft_size / 2 + 1) 15053a5a1b3Sopenharmony_ci#define CHANNEL_PROFILE_SIZE(u) (FILTER_SIZE(u) + 1) 15153a5a1b3Sopenharmony_ci#define FILTER_STATE_SIZE(u) (CHANNEL_PROFILE_SIZE(u) * (u)->channels) 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_cistatic void dbus_init(struct userdata *u); 15453a5a1b3Sopenharmony_cistatic void dbus_done(struct userdata *u); 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_cistatic void hanning_window(float *W, size_t window_size) { 15753a5a1b3Sopenharmony_ci /* h=.5*(1-cos(2*pi*j/(window_size+1)), COLA for R=(M+1)/2 */ 15853a5a1b3Sopenharmony_ci for (size_t i = 0; i < window_size; ++i) 15953a5a1b3Sopenharmony_ci W[i] = (float).5 * (1 - cos(2*M_PI*i / (window_size+1))); 16053a5a1b3Sopenharmony_ci} 16153a5a1b3Sopenharmony_ci 16253a5a1b3Sopenharmony_cistatic void fix_filter(float *H, size_t fft_size) { 16353a5a1b3Sopenharmony_ci /* divide out the fft gain */ 16453a5a1b3Sopenharmony_ci for (size_t i = 0; i < fft_size / 2 + 1; ++i) 16553a5a1b3Sopenharmony_ci H[i] /= fft_size; 16653a5a1b3Sopenharmony_ci} 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_cistatic void interpolate(float *samples, size_t length, uint32_t *xs, float *ys, size_t n_points) { 16953a5a1b3Sopenharmony_ci /* Note that xs must be monotonically increasing! */ 17053a5a1b3Sopenharmony_ci float x_range_lower, x_range_upper, c0; 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci pa_assert(n_points >= 2); 17353a5a1b3Sopenharmony_ci pa_assert(xs[0] == 0); 17453a5a1b3Sopenharmony_ci pa_assert(xs[n_points - 1] == length - 1); 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci for (size_t x = 0, x_range_lower_i = 0; x < length-1; ++x) { 17753a5a1b3Sopenharmony_ci pa_assert(x_range_lower_i < n_points-1); 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci x_range_lower = (float) xs[x_range_lower_i]; 18053a5a1b3Sopenharmony_ci x_range_upper = (float) xs[x_range_lower_i+1]; 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci pa_assert_se(x_range_lower < x_range_upper); 18353a5a1b3Sopenharmony_ci pa_assert_se(x >= x_range_lower); 18453a5a1b3Sopenharmony_ci pa_assert_se(x <= x_range_upper); 18553a5a1b3Sopenharmony_ci 18653a5a1b3Sopenharmony_ci /* bilinear-interpolation of coefficients specified */ 18753a5a1b3Sopenharmony_ci c0 = (x-x_range_lower) / (x_range_upper-x_range_lower); 18853a5a1b3Sopenharmony_ci pa_assert(c0 >= 0 && c0 <= 1.0); 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_ci samples[x] = ((1.0f - c0) * ys[x_range_lower_i] + c0 * ys[x_range_lower_i + 1]); 19153a5a1b3Sopenharmony_ci while(x >= xs[x_range_lower_i + 1]) 19253a5a1b3Sopenharmony_ci x_range_lower_i++; 19353a5a1b3Sopenharmony_ci } 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci samples[length-1] = ys[n_points-1]; 19653a5a1b3Sopenharmony_ci} 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_cistatic bool is_monotonic(const uint32_t *xs, size_t length) { 19953a5a1b3Sopenharmony_ci pa_assert(xs); 20053a5a1b3Sopenharmony_ci 20153a5a1b3Sopenharmony_ci if (length < 2) 20253a5a1b3Sopenharmony_ci return true; 20353a5a1b3Sopenharmony_ci 20453a5a1b3Sopenharmony_ci for(size_t i = 1; i < length; ++i) 20553a5a1b3Sopenharmony_ci if (xs[i] <= xs[i-1]) 20653a5a1b3Sopenharmony_ci return false; 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci return true; 20953a5a1b3Sopenharmony_ci} 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci/* ensures memory allocated is a multiple of v_size and aligned */ 21253a5a1b3Sopenharmony_cistatic void * alloc(size_t x, size_t s) { 21353a5a1b3Sopenharmony_ci size_t f; 21453a5a1b3Sopenharmony_ci float *t; 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci f = PA_ROUND_UP(x*s, sizeof(float)*v_size); 21753a5a1b3Sopenharmony_ci pa_assert_se(t = fftwf_malloc(f)); 21853a5a1b3Sopenharmony_ci pa_memzero(t, f); 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci return t; 22153a5a1b3Sopenharmony_ci} 22253a5a1b3Sopenharmony_ci 22353a5a1b3Sopenharmony_cistatic void alloc_input_buffers(struct userdata *u, size_t min_buffer_length) { 22453a5a1b3Sopenharmony_ci if (min_buffer_length <= u->input_buffer_max) 22553a5a1b3Sopenharmony_ci return; 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci pa_assert(min_buffer_length >= u->window_size); 22853a5a1b3Sopenharmony_ci for (size_t c = 0; c < u->channels; ++c) { 22953a5a1b3Sopenharmony_ci float *tmp = alloc(min_buffer_length, sizeof(float)); 23053a5a1b3Sopenharmony_ci if (u->input[c]) { 23153a5a1b3Sopenharmony_ci if (!u->first_iteration) 23253a5a1b3Sopenharmony_ci memcpy(tmp, u->input[c], u->overlap_size * sizeof(float)); 23353a5a1b3Sopenharmony_ci fftwf_free(u->input[c]); 23453a5a1b3Sopenharmony_ci } 23553a5a1b3Sopenharmony_ci u->input[c] = tmp; 23653a5a1b3Sopenharmony_ci } 23753a5a1b3Sopenharmony_ci u->input_buffer_max = min_buffer_length; 23853a5a1b3Sopenharmony_ci} 23953a5a1b3Sopenharmony_ci 24053a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 24153a5a1b3Sopenharmony_cistatic int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 24253a5a1b3Sopenharmony_ci struct userdata *u = PA_SINK(o)->userdata; 24353a5a1b3Sopenharmony_ci 24453a5a1b3Sopenharmony_ci switch (code) { 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ci case PA_SINK_MESSAGE_GET_LATENCY: { 24753a5a1b3Sopenharmony_ci //size_t fs=pa_frame_size(&u->sink->sample_spec); 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_ci /* The sink is _put() before the sink input is, so let's 25053a5a1b3Sopenharmony_ci * make sure we don't access it in that time. Also, the 25153a5a1b3Sopenharmony_ci * sink input is first shut down, the sink second. */ 25253a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || 25353a5a1b3Sopenharmony_ci !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) { 25453a5a1b3Sopenharmony_ci *((int64_t*) data) = 0; 25553a5a1b3Sopenharmony_ci return 0; 25653a5a1b3Sopenharmony_ci } 25753a5a1b3Sopenharmony_ci 25853a5a1b3Sopenharmony_ci *((int64_t*) data) = 25953a5a1b3Sopenharmony_ci /* Get the latency of the master sink */ 26053a5a1b3Sopenharmony_ci pa_sink_get_latency_within_thread(u->sink_input->sink, true) + 26153a5a1b3Sopenharmony_ci 26253a5a1b3Sopenharmony_ci /* Add the latency internal to our sink input on top */ 26353a5a1b3Sopenharmony_ci pa_bytes_to_usec(pa_memblockq_get_length(u->output_q) + 26453a5a1b3Sopenharmony_ci pa_memblockq_get_length(u->input_q), &u->sink_input->sink->sample_spec) + 26553a5a1b3Sopenharmony_ci pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->sink_input->sink->sample_spec); 26653a5a1b3Sopenharmony_ci // pa_bytes_to_usec(u->samples_gathered * fs, &u->sink->sample_spec); 26753a5a1b3Sopenharmony_ci //+ pa_bytes_to_usec(u->latency * fs, ss) 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci /* Add resampler latency */ 27053a5a1b3Sopenharmony_ci *((int64_t*) data) += pa_resampler_get_delay_usec(u->sink_input->thread_info.resampler); 27153a5a1b3Sopenharmony_ci return 0; 27253a5a1b3Sopenharmony_ci } 27353a5a1b3Sopenharmony_ci } 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci return pa_sink_process_msg(o, code, data, offset, chunk); 27653a5a1b3Sopenharmony_ci} 27753a5a1b3Sopenharmony_ci 27853a5a1b3Sopenharmony_ci/* Called from main context */ 27953a5a1b3Sopenharmony_cistatic int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) { 28053a5a1b3Sopenharmony_ci struct userdata *u; 28153a5a1b3Sopenharmony_ci 28253a5a1b3Sopenharmony_ci pa_sink_assert_ref(s); 28353a5a1b3Sopenharmony_ci pa_assert_se(u = s->userdata); 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(state) || 28653a5a1b3Sopenharmony_ci !PA_SINK_INPUT_IS_LINKED(u->sink_input->state)) 28753a5a1b3Sopenharmony_ci return 0; 28853a5a1b3Sopenharmony_ci 28953a5a1b3Sopenharmony_ci pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED); 29053a5a1b3Sopenharmony_ci return 0; 29153a5a1b3Sopenharmony_ci} 29253a5a1b3Sopenharmony_ci 29353a5a1b3Sopenharmony_ci/* Called from the IO thread. */ 29453a5a1b3Sopenharmony_cistatic int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { 29553a5a1b3Sopenharmony_ci struct userdata *u; 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci pa_assert(s); 29853a5a1b3Sopenharmony_ci pa_assert_se(u = s->userdata); 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_ci /* When set to running or idle for the first time, request a rewind 30153a5a1b3Sopenharmony_ci * of the master sink to make sure we are heard immediately */ 30253a5a1b3Sopenharmony_ci if (PA_SINK_IS_OPENED(new_state) && s->thread_info.state == PA_SINK_INIT) { 30353a5a1b3Sopenharmony_ci pa_log_debug("Requesting rewind due to state change."); 30453a5a1b3Sopenharmony_ci pa_sink_input_request_rewind(u->sink_input, 0, false, true, true); 30553a5a1b3Sopenharmony_ci } 30653a5a1b3Sopenharmony_ci 30753a5a1b3Sopenharmony_ci return 0; 30853a5a1b3Sopenharmony_ci} 30953a5a1b3Sopenharmony_ci 31053a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 31153a5a1b3Sopenharmony_cistatic void sink_request_rewind_cb(pa_sink *s) { 31253a5a1b3Sopenharmony_ci struct userdata *u; 31353a5a1b3Sopenharmony_ci 31453a5a1b3Sopenharmony_ci pa_sink_assert_ref(s); 31553a5a1b3Sopenharmony_ci pa_assert_se(u = s->userdata); 31653a5a1b3Sopenharmony_ci 31753a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || 31853a5a1b3Sopenharmony_ci !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) 31953a5a1b3Sopenharmony_ci return; 32053a5a1b3Sopenharmony_ci 32153a5a1b3Sopenharmony_ci /* Just hand this one over to the master sink */ 32253a5a1b3Sopenharmony_ci pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes+pa_memblockq_get_length(u->input_q), true, false, false); 32353a5a1b3Sopenharmony_ci} 32453a5a1b3Sopenharmony_ci 32553a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 32653a5a1b3Sopenharmony_cistatic void sink_update_requested_latency_cb(pa_sink *s) { 32753a5a1b3Sopenharmony_ci struct userdata *u; 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci pa_sink_assert_ref(s); 33053a5a1b3Sopenharmony_ci pa_assert_se(u = s->userdata); 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) || 33353a5a1b3Sopenharmony_ci !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state)) 33453a5a1b3Sopenharmony_ci return; 33553a5a1b3Sopenharmony_ci 33653a5a1b3Sopenharmony_ci /* Just hand this one over to the master sink */ 33753a5a1b3Sopenharmony_ci pa_sink_input_set_requested_latency_within_thread( 33853a5a1b3Sopenharmony_ci u->sink_input, 33953a5a1b3Sopenharmony_ci pa_sink_get_requested_latency_within_thread(s)); 34053a5a1b3Sopenharmony_ci} 34153a5a1b3Sopenharmony_ci 34253a5a1b3Sopenharmony_ci/* Called from main context */ 34353a5a1b3Sopenharmony_cistatic void sink_set_volume_cb(pa_sink *s) { 34453a5a1b3Sopenharmony_ci struct userdata *u; 34553a5a1b3Sopenharmony_ci 34653a5a1b3Sopenharmony_ci pa_sink_assert_ref(s); 34753a5a1b3Sopenharmony_ci pa_assert_se(u = s->userdata); 34853a5a1b3Sopenharmony_ci 34953a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(s->state) || 35053a5a1b3Sopenharmony_ci !PA_SINK_INPUT_IS_LINKED(u->sink_input->state)) 35153a5a1b3Sopenharmony_ci return; 35253a5a1b3Sopenharmony_ci 35353a5a1b3Sopenharmony_ci pa_sink_input_set_volume(u->sink_input, &s->real_volume, s->save_volume, true); 35453a5a1b3Sopenharmony_ci} 35553a5a1b3Sopenharmony_ci 35653a5a1b3Sopenharmony_ci/* Called from main context */ 35753a5a1b3Sopenharmony_cistatic void sink_set_mute_cb(pa_sink *s) { 35853a5a1b3Sopenharmony_ci struct userdata *u; 35953a5a1b3Sopenharmony_ci 36053a5a1b3Sopenharmony_ci pa_sink_assert_ref(s); 36153a5a1b3Sopenharmony_ci pa_assert_se(u = s->userdata); 36253a5a1b3Sopenharmony_ci 36353a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(s->state) || 36453a5a1b3Sopenharmony_ci !PA_SINK_INPUT_IS_LINKED(u->sink_input->state)) 36553a5a1b3Sopenharmony_ci return; 36653a5a1b3Sopenharmony_ci 36753a5a1b3Sopenharmony_ci pa_sink_input_set_mute(u->sink_input, s->muted, s->save_muted); 36853a5a1b3Sopenharmony_ci} 36953a5a1b3Sopenharmony_ci 37053a5a1b3Sopenharmony_ci#if 1 37153a5a1b3Sopenharmony_ci//reference implementation 37253a5a1b3Sopenharmony_cistatic void dsp_logic( 37353a5a1b3Sopenharmony_ci float * restrict dst,//used as a temp array too, needs to be fft_length! 37453a5a1b3Sopenharmony_ci float * restrict src,/*input data w/ overlap at start, 37553a5a1b3Sopenharmony_ci *automatically cycled in routine 37653a5a1b3Sopenharmony_ci */ 37753a5a1b3Sopenharmony_ci float * restrict overlap, 37853a5a1b3Sopenharmony_ci const float X,//multiplier 37953a5a1b3Sopenharmony_ci const float * restrict H,//The freq. magnitude scalers filter 38053a5a1b3Sopenharmony_ci const float * restrict W,//The windowing function 38153a5a1b3Sopenharmony_ci fftwf_complex * restrict output_window,//The transformed windowed src 38253a5a1b3Sopenharmony_ci struct userdata *u) { 38353a5a1b3Sopenharmony_ci 38453a5a1b3Sopenharmony_ci //use a linear-phase sliding STFT and overlap-add method (for each channel) 38553a5a1b3Sopenharmony_ci //window the data 38653a5a1b3Sopenharmony_ci for(size_t j = 0; j < u->window_size; ++j) { 38753a5a1b3Sopenharmony_ci dst[j] = X * W[j] * src[j]; 38853a5a1b3Sopenharmony_ci } 38953a5a1b3Sopenharmony_ci //zero pad the remaining fft window 39053a5a1b3Sopenharmony_ci memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float)); 39153a5a1b3Sopenharmony_ci //Processing is done here! 39253a5a1b3Sopenharmony_ci //do fft 39353a5a1b3Sopenharmony_ci fftwf_execute_dft_r2c(u->forward_plan, dst, output_window); 39453a5a1b3Sopenharmony_ci //perform filtering 39553a5a1b3Sopenharmony_ci for(size_t j = 0; j < FILTER_SIZE(u); ++j) { 39653a5a1b3Sopenharmony_ci u->output_window[j][0] *= H[j]; 39753a5a1b3Sopenharmony_ci u->output_window[j][1] *= H[j]; 39853a5a1b3Sopenharmony_ci } 39953a5a1b3Sopenharmony_ci //inverse fft 40053a5a1b3Sopenharmony_ci fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst); 40153a5a1b3Sopenharmony_ci ////debug: tests overlapping add 40253a5a1b3Sopenharmony_ci ////and negates ALL PREVIOUS processing 40353a5a1b3Sopenharmony_ci ////yields a perfect reconstruction if COLA is held 40453a5a1b3Sopenharmony_ci //for(size_t j = 0; j < u->window_size; ++j) { 40553a5a1b3Sopenharmony_ci // u->work_buffer[j] = u->W[j] * u->input[c][j]; 40653a5a1b3Sopenharmony_ci //} 40753a5a1b3Sopenharmony_ci 40853a5a1b3Sopenharmony_ci //overlap add and preserve overlap component from this window (linear phase) 40953a5a1b3Sopenharmony_ci for(size_t j = 0; j < u->overlap_size; ++j) { 41053a5a1b3Sopenharmony_ci u->work_buffer[j] += overlap[j]; 41153a5a1b3Sopenharmony_ci overlap[j] = dst[u->R + j]; 41253a5a1b3Sopenharmony_ci } 41353a5a1b3Sopenharmony_ci ////debug: tests if basic buffering works 41453a5a1b3Sopenharmony_ci ////shouldn't modify the signal AT ALL (beyond roundoff) 41553a5a1b3Sopenharmony_ci //for(size_t j = 0; j < u->window_size;++j) { 41653a5a1b3Sopenharmony_ci // u->work_buffer[j] = u->input[c][j]; 41753a5a1b3Sopenharmony_ci //} 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ci //preserve the needed input for the next window's overlap 42053a5a1b3Sopenharmony_ci memmove(src, src + u->R, 42153a5a1b3Sopenharmony_ci (u->samples_gathered - u->R) * sizeof(float) 42253a5a1b3Sopenharmony_ci ); 42353a5a1b3Sopenharmony_ci} 42453a5a1b3Sopenharmony_ci#else 42553a5a1b3Sopenharmony_citypedef float v4sf __attribute__ ((__aligned__(v_size * sizeof(float)))); 42653a5a1b3Sopenharmony_citypedef union float_vector { 42753a5a1b3Sopenharmony_ci float f[v_size]; 42853a5a1b3Sopenharmony_ci v4sf v; 42953a5a1b3Sopenharmony_ci __m128 m; 43053a5a1b3Sopenharmony_ci} float_vector_t; 43153a5a1b3Sopenharmony_ci 43253a5a1b3Sopenharmony_ci//regardless of sse enabled, the loops in here assume 43353a5a1b3Sopenharmony_ci//16 byte aligned addresses and memory allocations divisible by v_size 43453a5a1b3Sopenharmony_cistatic void dsp_logic( 43553a5a1b3Sopenharmony_ci float * restrict dst,//used as a temp array too, needs to be fft_length! 43653a5a1b3Sopenharmony_ci float * restrict src,/*input data w/ overlap at start, 43753a5a1b3Sopenharmony_ci *automatically cycled in routine 43853a5a1b3Sopenharmony_ci */ 43953a5a1b3Sopenharmony_ci float * restrict overlap,//The size of the overlap 44053a5a1b3Sopenharmony_ci const float X,//multiplier 44153a5a1b3Sopenharmony_ci const float * restrict H,//The freq. magnitude scalers filter 44253a5a1b3Sopenharmony_ci const float * restrict W,//The windowing function 44353a5a1b3Sopenharmony_ci fftwf_complex * restrict output_window,//The transformed windowed src 44453a5a1b3Sopenharmony_ci struct userdata *u) {//Collection of constants 44553a5a1b3Sopenharmony_ci const size_t overlap_size = PA_ROUND_UP(u->overlap_size, v_size); 44653a5a1b3Sopenharmony_ci float_vector_t x; 44753a5a1b3Sopenharmony_ci x.f[0] = x.f[1] = x.f[2] = x.f[3] = X; 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci //assert(u->samples_gathered >= u->R); 45053a5a1b3Sopenharmony_ci //use a linear-phase sliding STFT and overlap-add method 45153a5a1b3Sopenharmony_ci for(size_t j = 0; j < u->window_size; j += v_size) { 45253a5a1b3Sopenharmony_ci //dst[j] = W[j] * src[j]; 45353a5a1b3Sopenharmony_ci float_vector_t *d = (float_vector_t*) (dst + j); 45453a5a1b3Sopenharmony_ci float_vector_t *w = (float_vector_t*) (W + j); 45553a5a1b3Sopenharmony_ci float_vector_t *s = (float_vector_t*) (src + j); 45653a5a1b3Sopenharmony_ci//#if __SSE2__ 45753a5a1b3Sopenharmony_ci d->m = _mm_mul_ps(x.m, _mm_mul_ps(w->m, s->m)); 45853a5a1b3Sopenharmony_ci// d->v = x->v * w->v * s->v; 45953a5a1b3Sopenharmony_ci//#endif 46053a5a1b3Sopenharmony_ci } 46153a5a1b3Sopenharmony_ci //zero pad the remaining fft window 46253a5a1b3Sopenharmony_ci memset(dst + u->window_size, 0, (u->fft_size - u->window_size) * sizeof(float)); 46353a5a1b3Sopenharmony_ci 46453a5a1b3Sopenharmony_ci //Processing is done here! 46553a5a1b3Sopenharmony_ci //do fft 46653a5a1b3Sopenharmony_ci fftwf_execute_dft_r2c(u->forward_plan, dst, output_window); 46753a5a1b3Sopenharmony_ci //perform filtering - purely magnitude based 46853a5a1b3Sopenharmony_ci for(size_t j = 0; j < FILTER_SIZE; j += v_size / 2) { 46953a5a1b3Sopenharmony_ci //output_window[j][0]*=H[j]; 47053a5a1b3Sopenharmony_ci //output_window[j][1]*=H[j]; 47153a5a1b3Sopenharmony_ci float_vector_t *d = (float_vector_t*)( ((float *) output_window) + 2 * j); 47253a5a1b3Sopenharmony_ci float_vector_t h; 47353a5a1b3Sopenharmony_ci h.f[0] = h.f[1] = H[j]; 47453a5a1b3Sopenharmony_ci h.f[2] = h.f[3] = H[j + 1]; 47553a5a1b3Sopenharmony_ci//#if __SSE2__ 47653a5a1b3Sopenharmony_ci d->m = _mm_mul_ps(d->m, h.m); 47753a5a1b3Sopenharmony_ci//#else 47853a5a1b3Sopenharmony_ci// d->v = d->v * h.v; 47953a5a1b3Sopenharmony_ci//#endif 48053a5a1b3Sopenharmony_ci } 48153a5a1b3Sopenharmony_ci 48253a5a1b3Sopenharmony_ci //inverse fft 48353a5a1b3Sopenharmony_ci fftwf_execute_dft_c2r(u->inverse_plan, output_window, dst); 48453a5a1b3Sopenharmony_ci 48553a5a1b3Sopenharmony_ci ////debug: tests overlapping add 48653a5a1b3Sopenharmony_ci ////and negates ALL PREVIOUS processing 48753a5a1b3Sopenharmony_ci ////yields a perfect reconstruction if COLA is held 48853a5a1b3Sopenharmony_ci //for(size_t j = 0; j < u->window_size; ++j) { 48953a5a1b3Sopenharmony_ci // dst[j] = W[j] * src[j]; 49053a5a1b3Sopenharmony_ci //} 49153a5a1b3Sopenharmony_ci 49253a5a1b3Sopenharmony_ci //overlap add and preserve overlap component from this window (linear phase) 49353a5a1b3Sopenharmony_ci for(size_t j = 0; j < overlap_size; j += v_size) { 49453a5a1b3Sopenharmony_ci //dst[j]+=overlap[j]; 49553a5a1b3Sopenharmony_ci //overlap[j]+=dst[j+R]; 49653a5a1b3Sopenharmony_ci float_vector_t *d = (float_vector_t*)(dst + j); 49753a5a1b3Sopenharmony_ci float_vector_t *o = (float_vector_t*)(overlap + j); 49853a5a1b3Sopenharmony_ci//#if __SSE2__ 49953a5a1b3Sopenharmony_ci d->m = _mm_add_ps(d->m, o->m); 50053a5a1b3Sopenharmony_ci o->m = ((float_vector_t*)(dst + u->R + j))->m; 50153a5a1b3Sopenharmony_ci//#else 50253a5a1b3Sopenharmony_ci// d->v = d->v + o->v; 50353a5a1b3Sopenharmony_ci// o->v = ((float_vector_t*)(dst + u->R + j))->v; 50453a5a1b3Sopenharmony_ci//#endif 50553a5a1b3Sopenharmony_ci } 50653a5a1b3Sopenharmony_ci //memcpy(overlap, dst+u->R, u->overlap_size * sizeof(float)); //overlap preserve (debug) 50753a5a1b3Sopenharmony_ci //zero out the bit beyond the real overlap so we don't add garbage next iteration 50853a5a1b3Sopenharmony_ci memset(overlap + u->overlap_size, 0, overlap_size - u->overlap_size); 50953a5a1b3Sopenharmony_ci 51053a5a1b3Sopenharmony_ci ////debug: tests if basic buffering works 51153a5a1b3Sopenharmony_ci ////shouldn't modify the signal AT ALL (beyond roundoff) 51253a5a1b3Sopenharmony_ci //for(size_t j = 0; j < u->window_size; ++j) { 51353a5a1b3Sopenharmony_ci // dst[j] = src[j]; 51453a5a1b3Sopenharmony_ci //} 51553a5a1b3Sopenharmony_ci 51653a5a1b3Sopenharmony_ci //preserve the needed input for the next window's overlap 51753a5a1b3Sopenharmony_ci memmove(src, src + u->R, 51853a5a1b3Sopenharmony_ci (u->samples_gathered - u->R) * sizeof(float) 51953a5a1b3Sopenharmony_ci ); 52053a5a1b3Sopenharmony_ci} 52153a5a1b3Sopenharmony_ci#endif 52253a5a1b3Sopenharmony_ci 52353a5a1b3Sopenharmony_cistatic void flatten_to_memblockq(struct userdata *u) { 52453a5a1b3Sopenharmony_ci size_t mbs = pa_mempool_block_size_max(u->sink->core->mempool); 52553a5a1b3Sopenharmony_ci pa_memchunk tchunk; 52653a5a1b3Sopenharmony_ci char *dst; 52753a5a1b3Sopenharmony_ci size_t i = 0; 52853a5a1b3Sopenharmony_ci while(i < u->output_buffer_length) { 52953a5a1b3Sopenharmony_ci tchunk.index = 0; 53053a5a1b3Sopenharmony_ci tchunk.length = PA_MIN((u->output_buffer_length - i), mbs); 53153a5a1b3Sopenharmony_ci tchunk.memblock = pa_memblock_new(u->sink->core->mempool, tchunk.length); 53253a5a1b3Sopenharmony_ci //pa_log_debug("pushing %ld into the q", tchunk.length); 53353a5a1b3Sopenharmony_ci dst = pa_memblock_acquire(tchunk.memblock); 53453a5a1b3Sopenharmony_ci memcpy(dst, u->output_buffer + i, tchunk.length); 53553a5a1b3Sopenharmony_ci pa_memblock_release(tchunk.memblock); 53653a5a1b3Sopenharmony_ci pa_memblockq_push(u->output_q, &tchunk); 53753a5a1b3Sopenharmony_ci pa_memblock_unref(tchunk.memblock); 53853a5a1b3Sopenharmony_ci i += tchunk.length; 53953a5a1b3Sopenharmony_ci } 54053a5a1b3Sopenharmony_ci} 54153a5a1b3Sopenharmony_ci 54253a5a1b3Sopenharmony_cistatic void process_samples(struct userdata *u) { 54353a5a1b3Sopenharmony_ci size_t fs = pa_frame_size(&(u->sink->sample_spec)); 54453a5a1b3Sopenharmony_ci unsigned a_i; 54553a5a1b3Sopenharmony_ci float *H, X; 54653a5a1b3Sopenharmony_ci size_t iterations, offset; 54753a5a1b3Sopenharmony_ci pa_assert(u->samples_gathered >= u->window_size); 54853a5a1b3Sopenharmony_ci iterations = (u->samples_gathered - u->overlap_size) / u->R; 54953a5a1b3Sopenharmony_ci //make sure there is enough buffer memory allocated 55053a5a1b3Sopenharmony_ci if (iterations * u->R * fs > u->output_buffer_max_length) { 55153a5a1b3Sopenharmony_ci u->output_buffer_max_length = iterations * u->R * fs; 55253a5a1b3Sopenharmony_ci pa_xfree(u->output_buffer); 55353a5a1b3Sopenharmony_ci u->output_buffer = pa_xmalloc(u->output_buffer_max_length); 55453a5a1b3Sopenharmony_ci } 55553a5a1b3Sopenharmony_ci u->output_buffer_length = iterations * u->R * fs; 55653a5a1b3Sopenharmony_ci 55753a5a1b3Sopenharmony_ci for(size_t iter = 0; iter < iterations; ++iter) { 55853a5a1b3Sopenharmony_ci offset = iter * u->R * fs; 55953a5a1b3Sopenharmony_ci for(size_t c = 0;c < u->channels; c++) { 56053a5a1b3Sopenharmony_ci a_i = pa_aupdate_read_begin(u->a_H[c]); 56153a5a1b3Sopenharmony_ci X = u->Xs[c][a_i]; 56253a5a1b3Sopenharmony_ci H = u->Hs[c][a_i]; 56353a5a1b3Sopenharmony_ci dsp_logic( 56453a5a1b3Sopenharmony_ci u->work_buffer, 56553a5a1b3Sopenharmony_ci u->input[c], 56653a5a1b3Sopenharmony_ci u->overlap_accum[c], 56753a5a1b3Sopenharmony_ci X, 56853a5a1b3Sopenharmony_ci H, 56953a5a1b3Sopenharmony_ci u->W, 57053a5a1b3Sopenharmony_ci u->output_window, 57153a5a1b3Sopenharmony_ci u 57253a5a1b3Sopenharmony_ci ); 57353a5a1b3Sopenharmony_ci pa_aupdate_read_end(u->a_H[c]); 57453a5a1b3Sopenharmony_ci if (u->first_iteration) { 57553a5a1b3Sopenharmony_ci /* The windowing function will make the audio ramped in, as a cheap fix we can 57653a5a1b3Sopenharmony_ci * undo the windowing (for non-zero window values) 57753a5a1b3Sopenharmony_ci */ 57853a5a1b3Sopenharmony_ci for(size_t i = 0; i < u->overlap_size; ++i) { 57953a5a1b3Sopenharmony_ci u->work_buffer[i] = u->W[i] <= FLT_EPSILON ? u->work_buffer[i] : u->work_buffer[i] / u->W[i]; 58053a5a1b3Sopenharmony_ci } 58153a5a1b3Sopenharmony_ci } 58253a5a1b3Sopenharmony_ci pa_sample_clamp(PA_SAMPLE_FLOAT32NE, (uint8_t *) (((float *)u->output_buffer) + c) + offset, fs, u->work_buffer, sizeof(float), u->R); 58353a5a1b3Sopenharmony_ci } 58453a5a1b3Sopenharmony_ci if (u->first_iteration) { 58553a5a1b3Sopenharmony_ci u->first_iteration = false; 58653a5a1b3Sopenharmony_ci } 58753a5a1b3Sopenharmony_ci u->samples_gathered -= u->R; 58853a5a1b3Sopenharmony_ci } 58953a5a1b3Sopenharmony_ci flatten_to_memblockq(u); 59053a5a1b3Sopenharmony_ci} 59153a5a1b3Sopenharmony_ci 59253a5a1b3Sopenharmony_cistatic void input_buffer(struct userdata *u, pa_memchunk *in) { 59353a5a1b3Sopenharmony_ci size_t fs = pa_frame_size(&(u->sink->sample_spec)); 59453a5a1b3Sopenharmony_ci size_t samples = in->length/fs; 59553a5a1b3Sopenharmony_ci float *src = pa_memblock_acquire_chunk(in); 59653a5a1b3Sopenharmony_ci pa_assert(u->samples_gathered + samples <= u->input_buffer_max); 59753a5a1b3Sopenharmony_ci for(size_t c = 0; c < u->channels; c++) { 59853a5a1b3Sopenharmony_ci //buffer with an offset after the overlap from previous 59953a5a1b3Sopenharmony_ci //iterations 60053a5a1b3Sopenharmony_ci pa_assert_se( 60153a5a1b3Sopenharmony_ci u->input[c] + u->samples_gathered + samples <= u->input[c] + u->input_buffer_max 60253a5a1b3Sopenharmony_ci ); 60353a5a1b3Sopenharmony_ci pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input[c] + u->samples_gathered, sizeof(float), src + c, fs, samples); 60453a5a1b3Sopenharmony_ci } 60553a5a1b3Sopenharmony_ci u->samples_gathered += samples; 60653a5a1b3Sopenharmony_ci pa_memblock_release(in->memblock); 60753a5a1b3Sopenharmony_ci} 60853a5a1b3Sopenharmony_ci 60953a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 61053a5a1b3Sopenharmony_cistatic int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { 61153a5a1b3Sopenharmony_ci struct userdata *u; 61253a5a1b3Sopenharmony_ci size_t fs, target_samples; 61353a5a1b3Sopenharmony_ci size_t mbs; 61453a5a1b3Sopenharmony_ci //struct timeval start, end; 61553a5a1b3Sopenharmony_ci pa_memchunk tchunk; 61653a5a1b3Sopenharmony_ci 61753a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 61853a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 61953a5a1b3Sopenharmony_ci pa_assert(chunk); 62053a5a1b3Sopenharmony_ci pa_assert(u->sink); 62153a5a1b3Sopenharmony_ci 62253a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(u->sink->thread_info.state)) 62353a5a1b3Sopenharmony_ci return -1; 62453a5a1b3Sopenharmony_ci 62553a5a1b3Sopenharmony_ci /* FIXME: Please clean this up. I see more commented code lines 62653a5a1b3Sopenharmony_ci * than uncommented code lines. I am sorry, but I am too dumb to 62753a5a1b3Sopenharmony_ci * understand this. */ 62853a5a1b3Sopenharmony_ci 62953a5a1b3Sopenharmony_ci fs = pa_frame_size(&(u->sink->sample_spec)); 63053a5a1b3Sopenharmony_ci mbs = pa_mempool_block_size_max(u->sink->core->mempool); 63153a5a1b3Sopenharmony_ci if (pa_memblockq_get_length(u->output_q) > 0) { 63253a5a1b3Sopenharmony_ci //pa_log_debug("qsize is %ld", pa_memblockq_get_length(u->output_q)); 63353a5a1b3Sopenharmony_ci goto END; 63453a5a1b3Sopenharmony_ci } 63553a5a1b3Sopenharmony_ci //nbytes = PA_MIN(nbytes, pa_mempool_block_size_max(u->sink->core->mempool)); 63653a5a1b3Sopenharmony_ci target_samples = PA_ROUND_UP(nbytes / fs, u->R); 63753a5a1b3Sopenharmony_ci ////pa_log_debug("vanilla mbs = %ld",mbs); 63853a5a1b3Sopenharmony_ci //mbs = PA_ROUND_DOWN(mbs / fs, u->R); 63953a5a1b3Sopenharmony_ci //mbs = PA_MAX(mbs, u->R); 64053a5a1b3Sopenharmony_ci //target_samples = PA_MAX(target_samples, mbs); 64153a5a1b3Sopenharmony_ci //pa_log_debug("target samples: %ld", target_samples); 64253a5a1b3Sopenharmony_ci if (u->first_iteration) { 64353a5a1b3Sopenharmony_ci //allocate request_size 64453a5a1b3Sopenharmony_ci target_samples = PA_MAX(target_samples, u->window_size); 64553a5a1b3Sopenharmony_ci }else{ 64653a5a1b3Sopenharmony_ci //allocate request_size + overlap 64753a5a1b3Sopenharmony_ci target_samples += u->overlap_size; 64853a5a1b3Sopenharmony_ci } 64953a5a1b3Sopenharmony_ci alloc_input_buffers(u, target_samples); 65053a5a1b3Sopenharmony_ci //pa_log_debug("post target samples: %ld", target_samples); 65153a5a1b3Sopenharmony_ci chunk->memblock = NULL; 65253a5a1b3Sopenharmony_ci 65353a5a1b3Sopenharmony_ci /* Hmm, process any rewind request that might be queued up */ 65453a5a1b3Sopenharmony_ci pa_sink_process_rewind(u->sink, 0); 65553a5a1b3Sopenharmony_ci 65653a5a1b3Sopenharmony_ci //pa_log_debug("start output-buffered %ld, input-buffered %ld, requested %ld",buffered_samples,u->samples_gathered,samples_requested); 65753a5a1b3Sopenharmony_ci //pa_rtclock_get(&start); 65853a5a1b3Sopenharmony_ci do{ 65953a5a1b3Sopenharmony_ci size_t input_remaining = target_samples - u->samples_gathered; 66053a5a1b3Sopenharmony_ci // pa_log_debug("input remaining %ld samples", input_remaining); 66153a5a1b3Sopenharmony_ci pa_assert(input_remaining > 0); 66253a5a1b3Sopenharmony_ci while (pa_memblockq_peek(u->input_q, &tchunk) < 0) { 66353a5a1b3Sopenharmony_ci //pa_sink_render(u->sink, input_remaining * fs, &tchunk); 66453a5a1b3Sopenharmony_ci pa_sink_render_full(u->sink, PA_MIN(input_remaining * fs, mbs), &tchunk); 66553a5a1b3Sopenharmony_ci pa_memblockq_push(u->input_q, &tchunk); 66653a5a1b3Sopenharmony_ci pa_memblock_unref(tchunk.memblock); 66753a5a1b3Sopenharmony_ci } 66853a5a1b3Sopenharmony_ci pa_assert(tchunk.memblock); 66953a5a1b3Sopenharmony_ci 67053a5a1b3Sopenharmony_ci tchunk.length = PA_MIN(input_remaining * fs, tchunk.length); 67153a5a1b3Sopenharmony_ci 67253a5a1b3Sopenharmony_ci pa_memblockq_drop(u->input_q, tchunk.length); 67353a5a1b3Sopenharmony_ci //pa_log_debug("asked for %ld input samples, got %ld samples",input_remaining,buffer->length/fs); 67453a5a1b3Sopenharmony_ci /* copy new input */ 67553a5a1b3Sopenharmony_ci //pa_rtclock_get(start); 67653a5a1b3Sopenharmony_ci // pa_log_debug("buffering %ld bytes", tchunk.length); 67753a5a1b3Sopenharmony_ci input_buffer(u, &tchunk); 67853a5a1b3Sopenharmony_ci //pa_rtclock_get(&end); 67953a5a1b3Sopenharmony_ci //pa_log_debug("Took %0.5f seconds to setup", pa_timeval_diff(end, start) / (double) PA_USEC_PER_SEC); 68053a5a1b3Sopenharmony_ci pa_memblock_unref(tchunk.memblock); 68153a5a1b3Sopenharmony_ci } while(u->samples_gathered < target_samples); 68253a5a1b3Sopenharmony_ci 68353a5a1b3Sopenharmony_ci //pa_rtclock_get(&end); 68453a5a1b3Sopenharmony_ci //pa_log_debug("Took %0.6f seconds to get data", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC); 68553a5a1b3Sopenharmony_ci 68653a5a1b3Sopenharmony_ci pa_assert(u->fft_size >= u->window_size); 68753a5a1b3Sopenharmony_ci pa_assert(u->R < u->window_size); 68853a5a1b3Sopenharmony_ci //pa_rtclock_get(&start); 68953a5a1b3Sopenharmony_ci /* process a block */ 69053a5a1b3Sopenharmony_ci process_samples(u); 69153a5a1b3Sopenharmony_ci //pa_rtclock_get(&end); 69253a5a1b3Sopenharmony_ci //pa_log_debug("Took %0.6f seconds to process", (double) pa_timeval_diff(&end, &start) / PA_USEC_PER_SEC); 69353a5a1b3Sopenharmony_ciEND: 69453a5a1b3Sopenharmony_ci pa_assert_se(pa_memblockq_peek(u->output_q, chunk) >= 0); 69553a5a1b3Sopenharmony_ci pa_assert(chunk->memblock); 69653a5a1b3Sopenharmony_ci pa_memblockq_drop(u->output_q, chunk->length); 69753a5a1b3Sopenharmony_ci 69853a5a1b3Sopenharmony_ci //pa_log_debug("gave %ld", chunk->length/fs); 69953a5a1b3Sopenharmony_ci //pa_log_debug("end pop"); 70053a5a1b3Sopenharmony_ci return 0; 70153a5a1b3Sopenharmony_ci} 70253a5a1b3Sopenharmony_ci 70353a5a1b3Sopenharmony_ci/* Called from main context */ 70453a5a1b3Sopenharmony_cistatic void sink_input_volume_changed_cb(pa_sink_input *i) { 70553a5a1b3Sopenharmony_ci struct userdata *u; 70653a5a1b3Sopenharmony_ci 70753a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 70853a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 70953a5a1b3Sopenharmony_ci 71053a5a1b3Sopenharmony_ci pa_sink_volume_changed(u->sink, &i->volume); 71153a5a1b3Sopenharmony_ci} 71253a5a1b3Sopenharmony_ci 71353a5a1b3Sopenharmony_ci/* Called from main context */ 71453a5a1b3Sopenharmony_cistatic void sink_input_mute_changed_cb(pa_sink_input *i) { 71553a5a1b3Sopenharmony_ci struct userdata *u; 71653a5a1b3Sopenharmony_ci 71753a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 71853a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 71953a5a1b3Sopenharmony_ci 72053a5a1b3Sopenharmony_ci pa_sink_mute_changed(u->sink, i->muted); 72153a5a1b3Sopenharmony_ci} 72253a5a1b3Sopenharmony_ci 72353a5a1b3Sopenharmony_ci#if 0 72453a5a1b3Sopenharmony_cistatic void reset_filter(struct userdata *u) { 72553a5a1b3Sopenharmony_ci size_t fs = pa_frame_size(&u->sink->sample_spec); 72653a5a1b3Sopenharmony_ci size_t max_request; 72753a5a1b3Sopenharmony_ci 72853a5a1b3Sopenharmony_ci u->samples_gathered = 0; 72953a5a1b3Sopenharmony_ci 73053a5a1b3Sopenharmony_ci for(size_t i = 0; i < u->channels; ++i) 73153a5a1b3Sopenharmony_ci pa_memzero(u->overlap_accum[i], u->overlap_size * sizeof(float)); 73253a5a1b3Sopenharmony_ci 73353a5a1b3Sopenharmony_ci u->first_iteration = true; 73453a5a1b3Sopenharmony_ci //set buffer size to max request, no overlap copy 73553a5a1b3Sopenharmony_ci max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs , u->R); 73653a5a1b3Sopenharmony_ci max_request = PA_MAX(max_request, u->window_size); 73753a5a1b3Sopenharmony_ci pa_sink_set_max_request_within_thread(u->sink, max_request * fs); 73853a5a1b3Sopenharmony_ci} 73953a5a1b3Sopenharmony_ci#endif 74053a5a1b3Sopenharmony_ci 74153a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 74253a5a1b3Sopenharmony_cistatic void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { 74353a5a1b3Sopenharmony_ci struct userdata *u; 74453a5a1b3Sopenharmony_ci size_t amount = 0; 74553a5a1b3Sopenharmony_ci 74653a5a1b3Sopenharmony_ci pa_log_debug("Rewind callback!"); 74753a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 74853a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 74953a5a1b3Sopenharmony_ci 75053a5a1b3Sopenharmony_ci /* If the sink is not yet linked, there is nothing to rewind */ 75153a5a1b3Sopenharmony_ci if (!PA_SINK_IS_LINKED(u->sink->thread_info.state)) 75253a5a1b3Sopenharmony_ci return; 75353a5a1b3Sopenharmony_ci 75453a5a1b3Sopenharmony_ci if (u->sink->thread_info.rewind_nbytes > 0) { 75553a5a1b3Sopenharmony_ci size_t max_rewrite; 75653a5a1b3Sopenharmony_ci 75753a5a1b3Sopenharmony_ci //max_rewrite = nbytes; 75853a5a1b3Sopenharmony_ci max_rewrite = nbytes + pa_memblockq_get_length(u->input_q); 75953a5a1b3Sopenharmony_ci //PA_MIN(pa_memblockq_get_length(u->input_q), nbytes); 76053a5a1b3Sopenharmony_ci amount = PA_MIN(u->sink->thread_info.rewind_nbytes, max_rewrite); 76153a5a1b3Sopenharmony_ci u->sink->thread_info.rewind_nbytes = 0; 76253a5a1b3Sopenharmony_ci 76353a5a1b3Sopenharmony_ci if (amount > 0) { 76453a5a1b3Sopenharmony_ci //invalidate the output q 76553a5a1b3Sopenharmony_ci pa_memblockq_seek(u->input_q, - (int64_t) amount, PA_SEEK_RELATIVE, true); 76653a5a1b3Sopenharmony_ci pa_log("Resetting filter"); 76753a5a1b3Sopenharmony_ci //reset_filter(u); //this is the "proper" thing to do... 76853a5a1b3Sopenharmony_ci } 76953a5a1b3Sopenharmony_ci } 77053a5a1b3Sopenharmony_ci 77153a5a1b3Sopenharmony_ci pa_sink_process_rewind(u->sink, amount); 77253a5a1b3Sopenharmony_ci pa_memblockq_rewind(u->input_q, nbytes); 77353a5a1b3Sopenharmony_ci} 77453a5a1b3Sopenharmony_ci 77553a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 77653a5a1b3Sopenharmony_cistatic void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) { 77753a5a1b3Sopenharmony_ci struct userdata *u; 77853a5a1b3Sopenharmony_ci 77953a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 78053a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 78153a5a1b3Sopenharmony_ci 78253a5a1b3Sopenharmony_ci /* FIXME: Too small max_rewind: 78353a5a1b3Sopenharmony_ci * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */ 78453a5a1b3Sopenharmony_ci pa_memblockq_set_maxrewind(u->input_q, nbytes); 78553a5a1b3Sopenharmony_ci pa_sink_set_max_rewind_within_thread(u->sink, nbytes); 78653a5a1b3Sopenharmony_ci} 78753a5a1b3Sopenharmony_ci 78853a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 78953a5a1b3Sopenharmony_cistatic void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) { 79053a5a1b3Sopenharmony_ci struct userdata *u; 79153a5a1b3Sopenharmony_ci size_t fs; 79253a5a1b3Sopenharmony_ci 79353a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 79453a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 79553a5a1b3Sopenharmony_ci 79653a5a1b3Sopenharmony_ci fs = pa_frame_size(&u->sink_input->sample_spec); 79753a5a1b3Sopenharmony_ci pa_sink_set_max_request_within_thread(u->sink, PA_ROUND_UP(nbytes / fs, u->R) * fs); 79853a5a1b3Sopenharmony_ci} 79953a5a1b3Sopenharmony_ci 80053a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 80153a5a1b3Sopenharmony_cistatic void sink_input_update_sink_latency_range_cb(pa_sink_input *i) { 80253a5a1b3Sopenharmony_ci struct userdata *u; 80353a5a1b3Sopenharmony_ci 80453a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 80553a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 80653a5a1b3Sopenharmony_ci 80753a5a1b3Sopenharmony_ci pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); 80853a5a1b3Sopenharmony_ci} 80953a5a1b3Sopenharmony_ci 81053a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 81153a5a1b3Sopenharmony_cistatic void sink_input_update_sink_fixed_latency_cb(pa_sink_input *i) { 81253a5a1b3Sopenharmony_ci struct userdata *u; 81353a5a1b3Sopenharmony_ci 81453a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 81553a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 81653a5a1b3Sopenharmony_ci 81753a5a1b3Sopenharmony_ci pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency); 81853a5a1b3Sopenharmony_ci} 81953a5a1b3Sopenharmony_ci 82053a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 82153a5a1b3Sopenharmony_cistatic void sink_input_detach_cb(pa_sink_input *i) { 82253a5a1b3Sopenharmony_ci struct userdata *u; 82353a5a1b3Sopenharmony_ci 82453a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 82553a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 82653a5a1b3Sopenharmony_ci 82753a5a1b3Sopenharmony_ci if (PA_SINK_IS_LINKED(u->sink->thread_info.state)) 82853a5a1b3Sopenharmony_ci pa_sink_detach_within_thread(u->sink); 82953a5a1b3Sopenharmony_ci 83053a5a1b3Sopenharmony_ci pa_sink_set_rtpoll(u->sink, NULL); 83153a5a1b3Sopenharmony_ci} 83253a5a1b3Sopenharmony_ci 83353a5a1b3Sopenharmony_ci/* Called from I/O thread context */ 83453a5a1b3Sopenharmony_cistatic void sink_input_attach_cb(pa_sink_input *i) { 83553a5a1b3Sopenharmony_ci struct userdata *u; 83653a5a1b3Sopenharmony_ci size_t fs, max_request; 83753a5a1b3Sopenharmony_ci 83853a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 83953a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 84053a5a1b3Sopenharmony_ci 84153a5a1b3Sopenharmony_ci pa_sink_set_rtpoll(u->sink, i->sink->thread_info.rtpoll); 84253a5a1b3Sopenharmony_ci pa_sink_set_latency_range_within_thread(u->sink, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency); 84353a5a1b3Sopenharmony_ci pa_sink_set_fixed_latency_within_thread(u->sink, i->sink->thread_info.fixed_latency); 84453a5a1b3Sopenharmony_ci 84553a5a1b3Sopenharmony_ci fs = pa_frame_size(&u->sink_input->sample_spec); 84653a5a1b3Sopenharmony_ci /* set buffer size to max request, no overlap copy */ 84753a5a1b3Sopenharmony_ci max_request = PA_ROUND_UP(pa_sink_input_get_max_request(u->sink_input) / fs, u->R); 84853a5a1b3Sopenharmony_ci max_request = PA_MAX(max_request, u->window_size); 84953a5a1b3Sopenharmony_ci 85053a5a1b3Sopenharmony_ci pa_sink_set_max_request_within_thread(u->sink, max_request * fs); 85153a5a1b3Sopenharmony_ci 85253a5a1b3Sopenharmony_ci /* FIXME: Too small max_rewind: 85353a5a1b3Sopenharmony_ci * https://bugs.freedesktop.org/show_bug.cgi?id=53709 */ 85453a5a1b3Sopenharmony_ci pa_sink_set_max_rewind_within_thread(u->sink, pa_sink_input_get_max_rewind(i)); 85553a5a1b3Sopenharmony_ci 85653a5a1b3Sopenharmony_ci if (PA_SINK_IS_LINKED(u->sink->thread_info.state)) 85753a5a1b3Sopenharmony_ci pa_sink_attach_within_thread(u->sink); 85853a5a1b3Sopenharmony_ci} 85953a5a1b3Sopenharmony_ci 86053a5a1b3Sopenharmony_ci/* Called from main context */ 86153a5a1b3Sopenharmony_cistatic void sink_input_kill_cb(pa_sink_input *i) { 86253a5a1b3Sopenharmony_ci struct userdata *u; 86353a5a1b3Sopenharmony_ci 86453a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 86553a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 86653a5a1b3Sopenharmony_ci 86753a5a1b3Sopenharmony_ci /* The order here matters! We first kill the sink so that streams 86853a5a1b3Sopenharmony_ci * can properly be moved away while the sink input is still connected 86953a5a1b3Sopenharmony_ci * to the master. */ 87053a5a1b3Sopenharmony_ci pa_sink_input_cork(u->sink_input, true); 87153a5a1b3Sopenharmony_ci pa_sink_unlink(u->sink); 87253a5a1b3Sopenharmony_ci pa_sink_input_unlink(u->sink_input); 87353a5a1b3Sopenharmony_ci 87453a5a1b3Sopenharmony_ci pa_sink_input_unref(u->sink_input); 87553a5a1b3Sopenharmony_ci u->sink_input = NULL; 87653a5a1b3Sopenharmony_ci 87753a5a1b3Sopenharmony_ci /* Leave u->sink alone for now, it will be cleaned up on module 87853a5a1b3Sopenharmony_ci * unload (and it is needed during unload as well). */ 87953a5a1b3Sopenharmony_ci 88053a5a1b3Sopenharmony_ci pa_module_unload_request(u->module, true); 88153a5a1b3Sopenharmony_ci} 88253a5a1b3Sopenharmony_ci 88353a5a1b3Sopenharmony_cistatic void pack(char **strs, size_t len, char **packed, size_t *length) { 88453a5a1b3Sopenharmony_ci size_t t_len = 0; 88553a5a1b3Sopenharmony_ci size_t headers = (1+len) * sizeof(uint16_t); 88653a5a1b3Sopenharmony_ci char *p; 88753a5a1b3Sopenharmony_ci for(size_t i = 0; i < len; ++i) { 88853a5a1b3Sopenharmony_ci t_len += strlen(strs[i]); 88953a5a1b3Sopenharmony_ci } 89053a5a1b3Sopenharmony_ci *length = headers + t_len; 89153a5a1b3Sopenharmony_ci p = *packed = pa_xmalloc0(*length); 89253a5a1b3Sopenharmony_ci *((uint16_t *) p) = (uint16_t) len; 89353a5a1b3Sopenharmony_ci p += sizeof(uint16_t); 89453a5a1b3Sopenharmony_ci for(size_t i = 0; i < len; ++i) { 89553a5a1b3Sopenharmony_ci uint16_t l = strlen(strs[i]); 89653a5a1b3Sopenharmony_ci *((uint16_t *) p) = (uint16_t) l; 89753a5a1b3Sopenharmony_ci p += sizeof(uint16_t); 89853a5a1b3Sopenharmony_ci memcpy(p, strs[i], l); 89953a5a1b3Sopenharmony_ci p += l; 90053a5a1b3Sopenharmony_ci } 90153a5a1b3Sopenharmony_ci} 90253a5a1b3Sopenharmony_cistatic void unpack(char *str, size_t length, char ***strs, size_t *len) { 90353a5a1b3Sopenharmony_ci char *p = str; 90453a5a1b3Sopenharmony_ci *len = *((uint16_t *) p); 90553a5a1b3Sopenharmony_ci p += sizeof(uint16_t); 90653a5a1b3Sopenharmony_ci *strs = pa_xnew(char *, *len); 90753a5a1b3Sopenharmony_ci 90853a5a1b3Sopenharmony_ci for(size_t i = 0; i < *len; ++i) { 90953a5a1b3Sopenharmony_ci size_t l = *((uint16_t *) p); 91053a5a1b3Sopenharmony_ci p += sizeof(uint16_t); 91153a5a1b3Sopenharmony_ci (*strs)[i] = pa_xnew(char, l + 1); 91253a5a1b3Sopenharmony_ci memcpy((*strs)[i], p, l); 91353a5a1b3Sopenharmony_ci (*strs)[i][l] = '\0'; 91453a5a1b3Sopenharmony_ci p += l; 91553a5a1b3Sopenharmony_ci } 91653a5a1b3Sopenharmony_ci} 91753a5a1b3Sopenharmony_cistatic void save_profile(struct userdata *u, size_t channel, char *name) { 91853a5a1b3Sopenharmony_ci unsigned a_i; 91953a5a1b3Sopenharmony_ci const size_t profile_size = CHANNEL_PROFILE_SIZE(u) * sizeof(float); 92053a5a1b3Sopenharmony_ci float *H_n, *profile; 92153a5a1b3Sopenharmony_ci const float *H; 92253a5a1b3Sopenharmony_ci pa_datum key, data; 92353a5a1b3Sopenharmony_ci profile = pa_xnew0(float, profile_size); 92453a5a1b3Sopenharmony_ci a_i = pa_aupdate_read_begin(u->a_H[channel]); 92553a5a1b3Sopenharmony_ci profile[0] = u->Xs[a_i][channel]; 92653a5a1b3Sopenharmony_ci H = u->Hs[channel][a_i]; 92753a5a1b3Sopenharmony_ci H_n = profile + 1; 92853a5a1b3Sopenharmony_ci for(size_t i = 0 ; i < FILTER_SIZE(u); ++i) { 92953a5a1b3Sopenharmony_ci H_n[i] = H[i] * u->fft_size; 93053a5a1b3Sopenharmony_ci //H_n[i] = H[i]; 93153a5a1b3Sopenharmony_ci } 93253a5a1b3Sopenharmony_ci pa_aupdate_read_end(u->a_H[channel]); 93353a5a1b3Sopenharmony_ci key.data=name; 93453a5a1b3Sopenharmony_ci key.size = strlen(key.data); 93553a5a1b3Sopenharmony_ci data.data = profile; 93653a5a1b3Sopenharmony_ci data.size = profile_size; 93753a5a1b3Sopenharmony_ci pa_database_set(u->database, &key, &data, true); 93853a5a1b3Sopenharmony_ci pa_database_sync(u->database); 93953a5a1b3Sopenharmony_ci if (u->base_profiles[channel]) { 94053a5a1b3Sopenharmony_ci pa_xfree(u->base_profiles[channel]); 94153a5a1b3Sopenharmony_ci } 94253a5a1b3Sopenharmony_ci u->base_profiles[channel] = pa_xstrdup(name); 94353a5a1b3Sopenharmony_ci} 94453a5a1b3Sopenharmony_ci 94553a5a1b3Sopenharmony_cistatic void save_state(struct userdata *u) { 94653a5a1b3Sopenharmony_ci unsigned a_i; 94753a5a1b3Sopenharmony_ci const size_t filter_state_size = FILTER_STATE_SIZE(u) * sizeof(float); 94853a5a1b3Sopenharmony_ci float *H_n, *state; 94953a5a1b3Sopenharmony_ci float *H; 95053a5a1b3Sopenharmony_ci pa_datum key, data; 95153a5a1b3Sopenharmony_ci pa_database *database; 95253a5a1b3Sopenharmony_ci char *state_path; 95353a5a1b3Sopenharmony_ci char *packed; 95453a5a1b3Sopenharmony_ci size_t packed_length; 95553a5a1b3Sopenharmony_ci 95653a5a1b3Sopenharmony_ci pack(u->base_profiles, u->channels, &packed, &packed_length); 95753a5a1b3Sopenharmony_ci state = (float *) pa_xmalloc0(filter_state_size + packed_length); 95853a5a1b3Sopenharmony_ci memcpy(state + FILTER_STATE_SIZE(u), packed, packed_length); 95953a5a1b3Sopenharmony_ci pa_xfree(packed); 96053a5a1b3Sopenharmony_ci 96153a5a1b3Sopenharmony_ci for(size_t c = 0; c < u->channels; ++c) { 96253a5a1b3Sopenharmony_ci a_i = pa_aupdate_read_begin(u->a_H[c]); 96353a5a1b3Sopenharmony_ci state[c * CHANNEL_PROFILE_SIZE(u)] = u->Xs[c][a_i]; 96453a5a1b3Sopenharmony_ci H = u->Hs[c][a_i]; 96553a5a1b3Sopenharmony_ci H_n = &state[c * CHANNEL_PROFILE_SIZE(u) + 1]; 96653a5a1b3Sopenharmony_ci memcpy(H_n, H, FILTER_SIZE(u) * sizeof(float)); 96753a5a1b3Sopenharmony_ci pa_aupdate_read_end(u->a_H[c]); 96853a5a1b3Sopenharmony_ci } 96953a5a1b3Sopenharmony_ci 97053a5a1b3Sopenharmony_ci key.data = u->sink->name; 97153a5a1b3Sopenharmony_ci key.size = strlen(key.data); 97253a5a1b3Sopenharmony_ci data.data = state; 97353a5a1b3Sopenharmony_ci data.size = filter_state_size + packed_length; 97453a5a1b3Sopenharmony_ci //thread safety for 0.9.17? 97553a5a1b3Sopenharmony_ci pa_assert_se(state_path = pa_state_path(NULL, false)); 97653a5a1b3Sopenharmony_ci pa_assert_se(database = pa_database_open(state_path, EQ_STATE_DB, false, true)); 97753a5a1b3Sopenharmony_ci pa_xfree(state_path); 97853a5a1b3Sopenharmony_ci 97953a5a1b3Sopenharmony_ci pa_database_set(database, &key, &data, true); 98053a5a1b3Sopenharmony_ci pa_database_sync(database); 98153a5a1b3Sopenharmony_ci pa_database_close(database); 98253a5a1b3Sopenharmony_ci pa_xfree(state); 98353a5a1b3Sopenharmony_ci} 98453a5a1b3Sopenharmony_ci 98553a5a1b3Sopenharmony_cistatic void remove_profile(pa_core *c, char *name) { 98653a5a1b3Sopenharmony_ci pa_datum key; 98753a5a1b3Sopenharmony_ci pa_database *database; 98853a5a1b3Sopenharmony_ci key.data = name; 98953a5a1b3Sopenharmony_ci key.size = strlen(key.data); 99053a5a1b3Sopenharmony_ci pa_assert_se(database = pa_shared_get(c, EQDB)); 99153a5a1b3Sopenharmony_ci pa_database_unset(database, &key); 99253a5a1b3Sopenharmony_ci pa_database_sync(database); 99353a5a1b3Sopenharmony_ci} 99453a5a1b3Sopenharmony_ci 99553a5a1b3Sopenharmony_cistatic const char* load_profile(struct userdata *u, size_t channel, char *name) { 99653a5a1b3Sopenharmony_ci unsigned a_i; 99753a5a1b3Sopenharmony_ci pa_datum key, value; 99853a5a1b3Sopenharmony_ci const size_t profile_size = CHANNEL_PROFILE_SIZE(u) * sizeof(float); 99953a5a1b3Sopenharmony_ci key.data = name; 100053a5a1b3Sopenharmony_ci key.size = strlen(key.data); 100153a5a1b3Sopenharmony_ci if (pa_database_get(u->database, &key, &value) != NULL) { 100253a5a1b3Sopenharmony_ci if (value.size == profile_size) { 100353a5a1b3Sopenharmony_ci float *profile = (float *) value.data; 100453a5a1b3Sopenharmony_ci a_i = pa_aupdate_write_begin(u->a_H[channel]); 100553a5a1b3Sopenharmony_ci u->Xs[channel][a_i] = profile[0]; 100653a5a1b3Sopenharmony_ci memcpy(u->Hs[channel][a_i], profile + 1, FILTER_SIZE(u) * sizeof(float)); 100753a5a1b3Sopenharmony_ci fix_filter(u->Hs[channel][a_i], u->fft_size); 100853a5a1b3Sopenharmony_ci pa_aupdate_write_end(u->a_H[channel]); 100953a5a1b3Sopenharmony_ci pa_xfree(u->base_profiles[channel]); 101053a5a1b3Sopenharmony_ci u->base_profiles[channel] = pa_xstrdup(name); 101153a5a1b3Sopenharmony_ci }else{ 101253a5a1b3Sopenharmony_ci return "incompatible size"; 101353a5a1b3Sopenharmony_ci } 101453a5a1b3Sopenharmony_ci pa_datum_free(&value); 101553a5a1b3Sopenharmony_ci }else{ 101653a5a1b3Sopenharmony_ci return "profile doesn't exist"; 101753a5a1b3Sopenharmony_ci } 101853a5a1b3Sopenharmony_ci return NULL; 101953a5a1b3Sopenharmony_ci} 102053a5a1b3Sopenharmony_ci 102153a5a1b3Sopenharmony_cistatic void load_state(struct userdata *u) { 102253a5a1b3Sopenharmony_ci unsigned a_i; 102353a5a1b3Sopenharmony_ci float *H; 102453a5a1b3Sopenharmony_ci pa_datum key, value; 102553a5a1b3Sopenharmony_ci pa_database *database; 102653a5a1b3Sopenharmony_ci char *state_path; 102753a5a1b3Sopenharmony_ci pa_assert_se(state_path = pa_state_path(NULL, false)); 102853a5a1b3Sopenharmony_ci database = pa_database_open(state_path, EQ_STATE_DB, false, false); 102953a5a1b3Sopenharmony_ci pa_xfree(state_path); 103053a5a1b3Sopenharmony_ci if (!database) { 103153a5a1b3Sopenharmony_ci pa_log("No resume state"); 103253a5a1b3Sopenharmony_ci return; 103353a5a1b3Sopenharmony_ci } 103453a5a1b3Sopenharmony_ci 103553a5a1b3Sopenharmony_ci key.data = u->sink->name; 103653a5a1b3Sopenharmony_ci key.size = strlen(key.data); 103753a5a1b3Sopenharmony_ci 103853a5a1b3Sopenharmony_ci if (pa_database_get(database, &key, &value) != NULL) { 103953a5a1b3Sopenharmony_ci if (value.size > FILTER_STATE_SIZE(u) * sizeof(float) + sizeof(uint16_t)) { 104053a5a1b3Sopenharmony_ci float *state = (float *) value.data; 104153a5a1b3Sopenharmony_ci size_t n_profs; 104253a5a1b3Sopenharmony_ci char **names; 104353a5a1b3Sopenharmony_ci for(size_t c = 0; c < u->channels; ++c) { 104453a5a1b3Sopenharmony_ci a_i = pa_aupdate_write_begin(u->a_H[c]); 104553a5a1b3Sopenharmony_ci H = state + c * CHANNEL_PROFILE_SIZE(u) + 1; 104653a5a1b3Sopenharmony_ci u->Xs[c][a_i] = state[c * CHANNEL_PROFILE_SIZE(u)]; 104753a5a1b3Sopenharmony_ci memcpy(u->Hs[c][a_i], H, FILTER_SIZE(u) * sizeof(float)); 104853a5a1b3Sopenharmony_ci pa_aupdate_write_end(u->a_H[c]); 104953a5a1b3Sopenharmony_ci } 105053a5a1b3Sopenharmony_ci unpack(((char *)value.data) + FILTER_STATE_SIZE(u) * sizeof(float), value.size - FILTER_STATE_SIZE(u) * sizeof(float), &names, &n_profs); 105153a5a1b3Sopenharmony_ci n_profs = PA_MIN(n_profs, u->channels); 105253a5a1b3Sopenharmony_ci for(size_t c = 0; c < n_profs; ++c) { 105353a5a1b3Sopenharmony_ci pa_xfree(u->base_profiles[c]); 105453a5a1b3Sopenharmony_ci u->base_profiles[c] = names[c]; 105553a5a1b3Sopenharmony_ci } 105653a5a1b3Sopenharmony_ci pa_xfree(names); 105753a5a1b3Sopenharmony_ci } 105853a5a1b3Sopenharmony_ci pa_datum_free(&value); 105953a5a1b3Sopenharmony_ci }else{ 106053a5a1b3Sopenharmony_ci pa_log("resume state exists but is wrong size!"); 106153a5a1b3Sopenharmony_ci } 106253a5a1b3Sopenharmony_ci pa_database_close(database); 106353a5a1b3Sopenharmony_ci} 106453a5a1b3Sopenharmony_ci 106553a5a1b3Sopenharmony_ci/* Called from main context */ 106653a5a1b3Sopenharmony_cistatic bool sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { 106753a5a1b3Sopenharmony_ci struct userdata *u; 106853a5a1b3Sopenharmony_ci 106953a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 107053a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 107153a5a1b3Sopenharmony_ci 107253a5a1b3Sopenharmony_ci return u->sink != dest; 107353a5a1b3Sopenharmony_ci} 107453a5a1b3Sopenharmony_ci 107553a5a1b3Sopenharmony_ci/* Called from main context */ 107653a5a1b3Sopenharmony_cistatic void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { 107753a5a1b3Sopenharmony_ci struct userdata *u; 107853a5a1b3Sopenharmony_ci 107953a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 108053a5a1b3Sopenharmony_ci pa_assert_se(u = i->userdata); 108153a5a1b3Sopenharmony_ci 108253a5a1b3Sopenharmony_ci if (u->autoloaded) { 108353a5a1b3Sopenharmony_ci /* We were autoloaded, and don't support moving. Let's unload ourselves. */ 108453a5a1b3Sopenharmony_ci pa_log_debug("Can't move autoloaded stream, unloading"); 108553a5a1b3Sopenharmony_ci pa_module_unload_request(u->module, true); 108653a5a1b3Sopenharmony_ci } 108753a5a1b3Sopenharmony_ci 108853a5a1b3Sopenharmony_ci if (dest) { 108953a5a1b3Sopenharmony_ci pa_sink_set_asyncmsgq(u->sink, dest->asyncmsgq); 109053a5a1b3Sopenharmony_ci pa_sink_update_flags(u->sink, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY, dest->flags); 109153a5a1b3Sopenharmony_ci 109253a5a1b3Sopenharmony_ci if (u->automatic_description) { 109353a5a1b3Sopenharmony_ci const char *master_description; 109453a5a1b3Sopenharmony_ci char *new_description; 109553a5a1b3Sopenharmony_ci 109653a5a1b3Sopenharmony_ci master_description = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION); 109753a5a1b3Sopenharmony_ci new_description = pa_sprintf_malloc(_("FFT based equalizer on %s"), 109853a5a1b3Sopenharmony_ci master_description ? master_description : dest->name); 109953a5a1b3Sopenharmony_ci pa_sink_set_description(u->sink, new_description); 110053a5a1b3Sopenharmony_ci pa_xfree(new_description); 110153a5a1b3Sopenharmony_ci } 110253a5a1b3Sopenharmony_ci } else 110353a5a1b3Sopenharmony_ci pa_sink_set_asyncmsgq(u->sink, NULL); 110453a5a1b3Sopenharmony_ci} 110553a5a1b3Sopenharmony_ci 110653a5a1b3Sopenharmony_ciint pa__init(pa_module*m) { 110753a5a1b3Sopenharmony_ci struct userdata *u; 110853a5a1b3Sopenharmony_ci pa_sample_spec ss; 110953a5a1b3Sopenharmony_ci pa_channel_map map; 111053a5a1b3Sopenharmony_ci pa_modargs *ma; 111153a5a1b3Sopenharmony_ci pa_sink *master; 111253a5a1b3Sopenharmony_ci pa_sink_input_new_data sink_input_data; 111353a5a1b3Sopenharmony_ci pa_sink_new_data sink_data; 111453a5a1b3Sopenharmony_ci size_t i; 111553a5a1b3Sopenharmony_ci unsigned c; 111653a5a1b3Sopenharmony_ci float *H; 111753a5a1b3Sopenharmony_ci unsigned a_i; 111853a5a1b3Sopenharmony_ci bool use_volume_sharing = true; 111953a5a1b3Sopenharmony_ci 112053a5a1b3Sopenharmony_ci pa_assert(m); 112153a5a1b3Sopenharmony_ci 112253a5a1b3Sopenharmony_ci pa_log_warn("module-equalizer-sink is currently unsupported, and can sometimes cause " 112353a5a1b3Sopenharmony_ci "PulseAudio crashes, increased latency or audible artifacts."); 112453a5a1b3Sopenharmony_ci pa_log_warn("If you're facing audio problems, try unloading this module as a potential workaround."); 112553a5a1b3Sopenharmony_ci 112653a5a1b3Sopenharmony_ci if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { 112753a5a1b3Sopenharmony_ci pa_log("Failed to parse module arguments."); 112853a5a1b3Sopenharmony_ci goto fail; 112953a5a1b3Sopenharmony_ci } 113053a5a1b3Sopenharmony_ci 113153a5a1b3Sopenharmony_ci if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "sink_master", NULL), PA_NAMEREG_SINK))) { 113253a5a1b3Sopenharmony_ci pa_log("Master sink not found"); 113353a5a1b3Sopenharmony_ci goto fail; 113453a5a1b3Sopenharmony_ci } 113553a5a1b3Sopenharmony_ci 113653a5a1b3Sopenharmony_ci ss = master->sample_spec; 113753a5a1b3Sopenharmony_ci ss.format = PA_SAMPLE_FLOAT32; 113853a5a1b3Sopenharmony_ci map = master->channel_map; 113953a5a1b3Sopenharmony_ci if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { 114053a5a1b3Sopenharmony_ci pa_log("Invalid sample format specification or channel map"); 114153a5a1b3Sopenharmony_ci goto fail; 114253a5a1b3Sopenharmony_ci } 114353a5a1b3Sopenharmony_ci 114453a5a1b3Sopenharmony_ci //fs = pa_frame_size(&ss); 114553a5a1b3Sopenharmony_ci 114653a5a1b3Sopenharmony_ci if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) { 114753a5a1b3Sopenharmony_ci pa_log("use_volume_sharing= expects a boolean argument"); 114853a5a1b3Sopenharmony_ci goto fail; 114953a5a1b3Sopenharmony_ci } 115053a5a1b3Sopenharmony_ci 115153a5a1b3Sopenharmony_ci u = pa_xnew0(struct userdata, 1); 115253a5a1b3Sopenharmony_ci u->module = m; 115353a5a1b3Sopenharmony_ci m->userdata = u; 115453a5a1b3Sopenharmony_ci 115553a5a1b3Sopenharmony_ci u->channels = ss.channels; 115653a5a1b3Sopenharmony_ci u->fft_size = pow(2, ceil(log(ss.rate) / log(2)));//probably unstable near corner cases of powers of 2 115753a5a1b3Sopenharmony_ci pa_log_debug("fft size: %zd", u->fft_size); 115853a5a1b3Sopenharmony_ci u->window_size = 15999; 115953a5a1b3Sopenharmony_ci if (u->window_size % 2 == 0) 116053a5a1b3Sopenharmony_ci u->window_size--; 116153a5a1b3Sopenharmony_ci u->R = (u->window_size + 1) / 2; 116253a5a1b3Sopenharmony_ci u->overlap_size = u->window_size - u->R; 116353a5a1b3Sopenharmony_ci u->samples_gathered = 0; 116453a5a1b3Sopenharmony_ci u->input_buffer_max = 0; 116553a5a1b3Sopenharmony_ci 116653a5a1b3Sopenharmony_ci u->a_H = pa_xnew0(pa_aupdate *, u->channels); 116753a5a1b3Sopenharmony_ci u->Xs = pa_xnew0(float *, u->channels); 116853a5a1b3Sopenharmony_ci u->Hs = pa_xnew0(float **, u->channels); 116953a5a1b3Sopenharmony_ci 117053a5a1b3Sopenharmony_ci for (c = 0; c < u->channels; ++c) { 117153a5a1b3Sopenharmony_ci u->Xs[c] = pa_xnew0(float, 2); 117253a5a1b3Sopenharmony_ci u->Hs[c] = pa_xnew0(float *, 2); 117353a5a1b3Sopenharmony_ci for (i = 0; i < 2; ++i) 117453a5a1b3Sopenharmony_ci u->Hs[c][i] = alloc(FILTER_SIZE(u), sizeof(float)); 117553a5a1b3Sopenharmony_ci } 117653a5a1b3Sopenharmony_ci 117753a5a1b3Sopenharmony_ci u->W = alloc(u->window_size, sizeof(float)); 117853a5a1b3Sopenharmony_ci u->work_buffer = alloc(u->fft_size, sizeof(float)); 117953a5a1b3Sopenharmony_ci u->input = pa_xnew0(float *, u->channels); 118053a5a1b3Sopenharmony_ci u->overlap_accum = pa_xnew0(float *, u->channels); 118153a5a1b3Sopenharmony_ci for (c = 0; c < u->channels; ++c) { 118253a5a1b3Sopenharmony_ci u->a_H[c] = pa_aupdate_new(); 118353a5a1b3Sopenharmony_ci u->input[c] = NULL; 118453a5a1b3Sopenharmony_ci u->overlap_accum[c] = alloc(u->overlap_size, sizeof(float)); 118553a5a1b3Sopenharmony_ci } 118653a5a1b3Sopenharmony_ci u->output_window = alloc(FILTER_SIZE(u), sizeof(fftwf_complex)); 118753a5a1b3Sopenharmony_ci u->forward_plan = fftwf_plan_dft_r2c_1d(u->fft_size, u->work_buffer, u->output_window, FFTW_ESTIMATE); 118853a5a1b3Sopenharmony_ci u->inverse_plan = fftwf_plan_dft_c2r_1d(u->fft_size, u->output_window, u->work_buffer, FFTW_ESTIMATE); 118953a5a1b3Sopenharmony_ci 119053a5a1b3Sopenharmony_ci hanning_window(u->W, u->window_size); 119153a5a1b3Sopenharmony_ci u->first_iteration = true; 119253a5a1b3Sopenharmony_ci 119353a5a1b3Sopenharmony_ci u->base_profiles = pa_xnew0(char *, u->channels); 119453a5a1b3Sopenharmony_ci for (c = 0; c < u->channels; ++c) 119553a5a1b3Sopenharmony_ci u->base_profiles[c] = pa_xstrdup("default"); 119653a5a1b3Sopenharmony_ci 119753a5a1b3Sopenharmony_ci /* Create sink */ 119853a5a1b3Sopenharmony_ci pa_sink_new_data_init(&sink_data); 119953a5a1b3Sopenharmony_ci sink_data.driver = __FILE__; 120053a5a1b3Sopenharmony_ci sink_data.module = m; 120153a5a1b3Sopenharmony_ci if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) 120253a5a1b3Sopenharmony_ci sink_data.name = pa_sprintf_malloc("%s.equalizer", master->name); 120353a5a1b3Sopenharmony_ci pa_sink_new_data_set_sample_spec(&sink_data, &ss); 120453a5a1b3Sopenharmony_ci pa_sink_new_data_set_channel_map(&sink_data, &map); 120553a5a1b3Sopenharmony_ci 120653a5a1b3Sopenharmony_ci pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name); 120753a5a1b3Sopenharmony_ci pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter"); 120853a5a1b3Sopenharmony_ci 120953a5a1b3Sopenharmony_ci if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) { 121053a5a1b3Sopenharmony_ci pa_log("Invalid properties"); 121153a5a1b3Sopenharmony_ci pa_sink_new_data_done(&sink_data); 121253a5a1b3Sopenharmony_ci goto fail; 121353a5a1b3Sopenharmony_ci } 121453a5a1b3Sopenharmony_ci 121553a5a1b3Sopenharmony_ci if (!pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION)) { 121653a5a1b3Sopenharmony_ci const char *master_description; 121753a5a1b3Sopenharmony_ci 121853a5a1b3Sopenharmony_ci master_description = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); 121953a5a1b3Sopenharmony_ci pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, 122053a5a1b3Sopenharmony_ci _("FFT based equalizer on %s"), master_description ? master_description : master->name); 122153a5a1b3Sopenharmony_ci u->automatic_description = true; 122253a5a1b3Sopenharmony_ci } 122353a5a1b3Sopenharmony_ci 122453a5a1b3Sopenharmony_ci u->autoloaded = DEFAULT_AUTOLOADED; 122553a5a1b3Sopenharmony_ci if (pa_modargs_get_value_boolean(ma, "autoloaded", &u->autoloaded) < 0) { 122653a5a1b3Sopenharmony_ci pa_log("Failed to parse autoloaded value"); 122753a5a1b3Sopenharmony_ci goto fail; 122853a5a1b3Sopenharmony_ci } 122953a5a1b3Sopenharmony_ci 123053a5a1b3Sopenharmony_ci u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY)) 123153a5a1b3Sopenharmony_ci | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0)); 123253a5a1b3Sopenharmony_ci pa_sink_new_data_done(&sink_data); 123353a5a1b3Sopenharmony_ci 123453a5a1b3Sopenharmony_ci if (!u->sink) { 123553a5a1b3Sopenharmony_ci pa_log("Failed to create sink."); 123653a5a1b3Sopenharmony_ci goto fail; 123753a5a1b3Sopenharmony_ci } 123853a5a1b3Sopenharmony_ci 123953a5a1b3Sopenharmony_ci u->sink->parent.process_msg = sink_process_msg_cb; 124053a5a1b3Sopenharmony_ci u->sink->set_state_in_main_thread = sink_set_state_in_main_thread_cb; 124153a5a1b3Sopenharmony_ci u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb; 124253a5a1b3Sopenharmony_ci u->sink->update_requested_latency = sink_update_requested_latency_cb; 124353a5a1b3Sopenharmony_ci u->sink->request_rewind = sink_request_rewind_cb; 124453a5a1b3Sopenharmony_ci pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb); 124553a5a1b3Sopenharmony_ci if (!use_volume_sharing) { 124653a5a1b3Sopenharmony_ci pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb); 124753a5a1b3Sopenharmony_ci pa_sink_enable_decibel_volume(u->sink, true); 124853a5a1b3Sopenharmony_ci } 124953a5a1b3Sopenharmony_ci u->sink->userdata = u; 125053a5a1b3Sopenharmony_ci 125153a5a1b3Sopenharmony_ci u->input_q = pa_memblockq_new("module-equalizer-sink input_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, &u->sink->silence); 125253a5a1b3Sopenharmony_ci u->output_q = pa_memblockq_new("module-equalizer-sink output_q", 0, MEMBLOCKQ_MAXLENGTH, 0, &ss, 1, 1, 0, NULL); 125353a5a1b3Sopenharmony_ci u->output_buffer = NULL; 125453a5a1b3Sopenharmony_ci u->output_buffer_length = 0; 125553a5a1b3Sopenharmony_ci u->output_buffer_max_length = 0; 125653a5a1b3Sopenharmony_ci 125753a5a1b3Sopenharmony_ci pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); 125853a5a1b3Sopenharmony_ci //pa_sink_set_fixed_latency(u->sink, pa_bytes_to_usec(u->R*fs, &ss)); 125953a5a1b3Sopenharmony_ci 126053a5a1b3Sopenharmony_ci /* Create sink input */ 126153a5a1b3Sopenharmony_ci pa_sink_input_new_data_init(&sink_input_data); 126253a5a1b3Sopenharmony_ci sink_input_data.driver = __FILE__; 126353a5a1b3Sopenharmony_ci sink_input_data.module = m; 126453a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_sink(&sink_input_data, master, false, true); 126553a5a1b3Sopenharmony_ci sink_input_data.origin_sink = u->sink; 126653a5a1b3Sopenharmony_ci pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Equalized Stream"); 126753a5a1b3Sopenharmony_ci pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); 126853a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); 126953a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_channel_map(&sink_input_data, &map); 127053a5a1b3Sopenharmony_ci sink_input_data.flags |= PA_SINK_INPUT_START_CORKED; 127153a5a1b3Sopenharmony_ci 127253a5a1b3Sopenharmony_ci pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); 127353a5a1b3Sopenharmony_ci pa_sink_input_new_data_done(&sink_input_data); 127453a5a1b3Sopenharmony_ci 127553a5a1b3Sopenharmony_ci if (!u->sink_input) 127653a5a1b3Sopenharmony_ci goto fail; 127753a5a1b3Sopenharmony_ci 127853a5a1b3Sopenharmony_ci u->sink_input->pop = sink_input_pop_cb; 127953a5a1b3Sopenharmony_ci u->sink_input->process_rewind = sink_input_process_rewind_cb; 128053a5a1b3Sopenharmony_ci u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; 128153a5a1b3Sopenharmony_ci u->sink_input->update_max_request = sink_input_update_max_request_cb; 128253a5a1b3Sopenharmony_ci u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; 128353a5a1b3Sopenharmony_ci u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; 128453a5a1b3Sopenharmony_ci u->sink_input->kill = sink_input_kill_cb; 128553a5a1b3Sopenharmony_ci u->sink_input->attach = sink_input_attach_cb; 128653a5a1b3Sopenharmony_ci u->sink_input->detach = sink_input_detach_cb; 128753a5a1b3Sopenharmony_ci u->sink_input->may_move_to = sink_input_may_move_to_cb; 128853a5a1b3Sopenharmony_ci u->sink_input->moving = sink_input_moving_cb; 128953a5a1b3Sopenharmony_ci if (!use_volume_sharing) 129053a5a1b3Sopenharmony_ci u->sink_input->volume_changed = sink_input_volume_changed_cb; 129153a5a1b3Sopenharmony_ci u->sink_input->mute_changed = sink_input_mute_changed_cb; 129253a5a1b3Sopenharmony_ci u->sink_input->userdata = u; 129353a5a1b3Sopenharmony_ci 129453a5a1b3Sopenharmony_ci u->sink->input_to_master = u->sink_input; 129553a5a1b3Sopenharmony_ci 129653a5a1b3Sopenharmony_ci dbus_init(u); 129753a5a1b3Sopenharmony_ci 129853a5a1b3Sopenharmony_ci /* default filter to these */ 129953a5a1b3Sopenharmony_ci for (c = 0; c< u->channels; ++c) { 130053a5a1b3Sopenharmony_ci a_i = pa_aupdate_write_begin(u->a_H[c]); 130153a5a1b3Sopenharmony_ci H = u->Hs[c][a_i]; 130253a5a1b3Sopenharmony_ci u->Xs[c][a_i] = 1.0f; 130353a5a1b3Sopenharmony_ci 130453a5a1b3Sopenharmony_ci for(i = 0; i < FILTER_SIZE(u); ++i) 130553a5a1b3Sopenharmony_ci H[i] = 1.0 / sqrtf(2.0f); 130653a5a1b3Sopenharmony_ci 130753a5a1b3Sopenharmony_ci fix_filter(H, u->fft_size); 130853a5a1b3Sopenharmony_ci pa_aupdate_write_end(u->a_H[c]); 130953a5a1b3Sopenharmony_ci } 131053a5a1b3Sopenharmony_ci 131153a5a1b3Sopenharmony_ci /* load old parameters */ 131253a5a1b3Sopenharmony_ci load_state(u); 131353a5a1b3Sopenharmony_ci 131453a5a1b3Sopenharmony_ci /* The order here is important. The input must be put first, 131553a5a1b3Sopenharmony_ci * otherwise streams might attach to the sink before the sink 131653a5a1b3Sopenharmony_ci * input is attached to the master. */ 131753a5a1b3Sopenharmony_ci pa_sink_input_put(u->sink_input); 131853a5a1b3Sopenharmony_ci pa_sink_put(u->sink); 131953a5a1b3Sopenharmony_ci pa_sink_input_cork(u->sink_input, false); 132053a5a1b3Sopenharmony_ci 132153a5a1b3Sopenharmony_ci pa_modargs_free(ma); 132253a5a1b3Sopenharmony_ci 132353a5a1b3Sopenharmony_ci return 0; 132453a5a1b3Sopenharmony_ci 132553a5a1b3Sopenharmony_cifail: 132653a5a1b3Sopenharmony_ci if (ma) 132753a5a1b3Sopenharmony_ci pa_modargs_free(ma); 132853a5a1b3Sopenharmony_ci 132953a5a1b3Sopenharmony_ci pa__done(m); 133053a5a1b3Sopenharmony_ci 133153a5a1b3Sopenharmony_ci return -1; 133253a5a1b3Sopenharmony_ci} 133353a5a1b3Sopenharmony_ci 133453a5a1b3Sopenharmony_ciint pa__get_n_used(pa_module *m) { 133553a5a1b3Sopenharmony_ci struct userdata *u; 133653a5a1b3Sopenharmony_ci 133753a5a1b3Sopenharmony_ci pa_assert(m); 133853a5a1b3Sopenharmony_ci pa_assert_se(u = m->userdata); 133953a5a1b3Sopenharmony_ci 134053a5a1b3Sopenharmony_ci return pa_sink_linked_by(u->sink); 134153a5a1b3Sopenharmony_ci} 134253a5a1b3Sopenharmony_ci 134353a5a1b3Sopenharmony_civoid pa__done(pa_module*m) { 134453a5a1b3Sopenharmony_ci struct userdata *u; 134553a5a1b3Sopenharmony_ci unsigned c; 134653a5a1b3Sopenharmony_ci 134753a5a1b3Sopenharmony_ci pa_assert(m); 134853a5a1b3Sopenharmony_ci 134953a5a1b3Sopenharmony_ci if (!(u = m->userdata)) 135053a5a1b3Sopenharmony_ci return; 135153a5a1b3Sopenharmony_ci 135253a5a1b3Sopenharmony_ci save_state(u); 135353a5a1b3Sopenharmony_ci 135453a5a1b3Sopenharmony_ci dbus_done(u); 135553a5a1b3Sopenharmony_ci 135653a5a1b3Sopenharmony_ci for(c = 0; c < u->channels; ++c) 135753a5a1b3Sopenharmony_ci pa_xfree(u->base_profiles[c]); 135853a5a1b3Sopenharmony_ci pa_xfree(u->base_profiles); 135953a5a1b3Sopenharmony_ci 136053a5a1b3Sopenharmony_ci /* See comments in sink_input_kill_cb() above regarding 136153a5a1b3Sopenharmony_ci * destruction order! */ 136253a5a1b3Sopenharmony_ci 136353a5a1b3Sopenharmony_ci if (u->sink_input) 136453a5a1b3Sopenharmony_ci pa_sink_input_cork(u->sink_input, true); 136553a5a1b3Sopenharmony_ci 136653a5a1b3Sopenharmony_ci if (u->sink) 136753a5a1b3Sopenharmony_ci pa_sink_unlink(u->sink); 136853a5a1b3Sopenharmony_ci 136953a5a1b3Sopenharmony_ci if (u->sink_input) { 137053a5a1b3Sopenharmony_ci pa_sink_input_unlink(u->sink_input); 137153a5a1b3Sopenharmony_ci pa_sink_input_unref(u->sink_input); 137253a5a1b3Sopenharmony_ci} 137353a5a1b3Sopenharmony_ci 137453a5a1b3Sopenharmony_ci if (u->sink) 137553a5a1b3Sopenharmony_ci pa_sink_unref(u->sink); 137653a5a1b3Sopenharmony_ci 137753a5a1b3Sopenharmony_ci pa_xfree(u->output_buffer); 137853a5a1b3Sopenharmony_ci pa_memblockq_free(u->output_q); 137953a5a1b3Sopenharmony_ci pa_memblockq_free(u->input_q); 138053a5a1b3Sopenharmony_ci 138153a5a1b3Sopenharmony_ci fftwf_destroy_plan(u->inverse_plan); 138253a5a1b3Sopenharmony_ci fftwf_destroy_plan(u->forward_plan); 138353a5a1b3Sopenharmony_ci fftwf_free(u->output_window); 138453a5a1b3Sopenharmony_ci for (c = 0; c < u->channels; ++c) { 138553a5a1b3Sopenharmony_ci pa_aupdate_free(u->a_H[c]); 138653a5a1b3Sopenharmony_ci fftwf_free(u->overlap_accum[c]); 138753a5a1b3Sopenharmony_ci fftwf_free(u->input[c]); 138853a5a1b3Sopenharmony_ci } 138953a5a1b3Sopenharmony_ci pa_xfree(u->a_H); 139053a5a1b3Sopenharmony_ci pa_xfree(u->overlap_accum); 139153a5a1b3Sopenharmony_ci pa_xfree(u->input); 139253a5a1b3Sopenharmony_ci fftwf_free(u->work_buffer); 139353a5a1b3Sopenharmony_ci fftwf_free(u->W); 139453a5a1b3Sopenharmony_ci for (c = 0; c < u->channels; ++c) { 139553a5a1b3Sopenharmony_ci pa_xfree(u->Xs[c]); 139653a5a1b3Sopenharmony_ci for (size_t i = 0; i < 2; ++i) 139753a5a1b3Sopenharmony_ci fftwf_free(u->Hs[c][i]); 139853a5a1b3Sopenharmony_ci fftwf_free(u->Hs[c]); 139953a5a1b3Sopenharmony_ci } 140053a5a1b3Sopenharmony_ci pa_xfree(u->Xs); 140153a5a1b3Sopenharmony_ci pa_xfree(u->Hs); 140253a5a1b3Sopenharmony_ci 140353a5a1b3Sopenharmony_ci pa_xfree(u); 140453a5a1b3Sopenharmony_ci} 140553a5a1b3Sopenharmony_ci 140653a5a1b3Sopenharmony_ci/* 140753a5a1b3Sopenharmony_ci * DBus Routines and Callbacks 140853a5a1b3Sopenharmony_ci */ 140953a5a1b3Sopenharmony_ci#define EXTNAME "org.PulseAudio.Ext.Equalizing1" 141053a5a1b3Sopenharmony_ci#define MANAGER_PATH "/org/pulseaudio/equalizing1" 141153a5a1b3Sopenharmony_ci#define MANAGER_IFACE EXTNAME ".Manager" 141253a5a1b3Sopenharmony_ci#define EQUALIZER_IFACE EXTNAME ".Equalizer" 141353a5a1b3Sopenharmony_cistatic void manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u); 141453a5a1b3Sopenharmony_cistatic void manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u); 141553a5a1b3Sopenharmony_cistatic void manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u); 141653a5a1b3Sopenharmony_cistatic void manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u); 141753a5a1b3Sopenharmony_cistatic void manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u); 141853a5a1b3Sopenharmony_cistatic void equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u); 141953a5a1b3Sopenharmony_cistatic void equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u); 142053a5a1b3Sopenharmony_cistatic void equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u); 142153a5a1b3Sopenharmony_cistatic void equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u); 142253a5a1b3Sopenharmony_cistatic void equalizer_get_n_channels(DBusConnection *conn, DBusMessage *msg, void *_u); 142353a5a1b3Sopenharmony_cistatic void equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u); 142453a5a1b3Sopenharmony_cistatic void equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u); 142553a5a1b3Sopenharmony_cistatic void equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u); 142653a5a1b3Sopenharmony_cistatic void equalizer_handle_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u); 142753a5a1b3Sopenharmony_cistatic void equalizer_handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u); 142853a5a1b3Sopenharmony_cistatic void equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u); 142953a5a1b3Sopenharmony_cistatic void equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u); 143053a5a1b3Sopenharmony_cistatic void equalizer_handle_save_state(DBusConnection *conn, DBusMessage *msg, void *_u); 143153a5a1b3Sopenharmony_cistatic void equalizer_handle_get_profile_name(DBusConnection *conn, DBusMessage *msg, void *_u); 143253a5a1b3Sopenharmony_cienum manager_method_index { 143353a5a1b3Sopenharmony_ci MANAGER_METHOD_REMOVE_PROFILE, 143453a5a1b3Sopenharmony_ci MANAGER_METHOD_MAX 143553a5a1b3Sopenharmony_ci}; 143653a5a1b3Sopenharmony_ci 143753a5a1b3Sopenharmony_cipa_dbus_arg_info remove_profile_args[]={ 143853a5a1b3Sopenharmony_ci {"name", "s","in"}, 143953a5a1b3Sopenharmony_ci}; 144053a5a1b3Sopenharmony_ci 144153a5a1b3Sopenharmony_cistatic pa_dbus_method_handler manager_methods[MANAGER_METHOD_MAX]={ 144253a5a1b3Sopenharmony_ci [MANAGER_METHOD_REMOVE_PROFILE]={ 144353a5a1b3Sopenharmony_ci .method_name="RemoveProfile", 144453a5a1b3Sopenharmony_ci .arguments=remove_profile_args, 144553a5a1b3Sopenharmony_ci .n_arguments=sizeof(remove_profile_args)/sizeof(pa_dbus_arg_info), 144653a5a1b3Sopenharmony_ci .receive_cb=manager_handle_remove_profile} 144753a5a1b3Sopenharmony_ci}; 144853a5a1b3Sopenharmony_ci 144953a5a1b3Sopenharmony_cienum manager_handler_index { 145053a5a1b3Sopenharmony_ci MANAGER_HANDLER_REVISION, 145153a5a1b3Sopenharmony_ci MANAGER_HANDLER_EQUALIZED_SINKS, 145253a5a1b3Sopenharmony_ci MANAGER_HANDLER_PROFILES, 145353a5a1b3Sopenharmony_ci MANAGER_HANDLER_MAX 145453a5a1b3Sopenharmony_ci}; 145553a5a1b3Sopenharmony_ci 145653a5a1b3Sopenharmony_cistatic pa_dbus_property_handler manager_handlers[MANAGER_HANDLER_MAX]={ 145753a5a1b3Sopenharmony_ci [MANAGER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=manager_get_revision,.set_cb=NULL}, 145853a5a1b3Sopenharmony_ci [MANAGER_HANDLER_EQUALIZED_SINKS]={.property_name="EqualizedSinks",.type="ao",.get_cb=manager_get_sinks,.set_cb=NULL}, 145953a5a1b3Sopenharmony_ci [MANAGER_HANDLER_PROFILES]={.property_name="Profiles",.type="as",.get_cb=manager_get_profiles,.set_cb=NULL} 146053a5a1b3Sopenharmony_ci}; 146153a5a1b3Sopenharmony_ci 146253a5a1b3Sopenharmony_cipa_dbus_arg_info sink_args[]={ 146353a5a1b3Sopenharmony_ci {"sink", "o", NULL} 146453a5a1b3Sopenharmony_ci}; 146553a5a1b3Sopenharmony_ci 146653a5a1b3Sopenharmony_cienum manager_signal_index{ 146753a5a1b3Sopenharmony_ci MANAGER_SIGNAL_SINK_ADDED, 146853a5a1b3Sopenharmony_ci MANAGER_SIGNAL_SINK_REMOVED, 146953a5a1b3Sopenharmony_ci MANAGER_SIGNAL_PROFILES_CHANGED, 147053a5a1b3Sopenharmony_ci MANAGER_SIGNAL_MAX 147153a5a1b3Sopenharmony_ci}; 147253a5a1b3Sopenharmony_ci 147353a5a1b3Sopenharmony_cistatic pa_dbus_signal_info manager_signals[MANAGER_SIGNAL_MAX]={ 147453a5a1b3Sopenharmony_ci [MANAGER_SIGNAL_SINK_ADDED]={.name="SinkAdded", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)}, 147553a5a1b3Sopenharmony_ci [MANAGER_SIGNAL_SINK_REMOVED]={.name="SinkRemoved", .arguments=sink_args, .n_arguments=sizeof(sink_args)/sizeof(pa_dbus_arg_info)}, 147653a5a1b3Sopenharmony_ci [MANAGER_SIGNAL_PROFILES_CHANGED]={.name="ProfilesChanged", .arguments=NULL, .n_arguments=0} 147753a5a1b3Sopenharmony_ci}; 147853a5a1b3Sopenharmony_ci 147953a5a1b3Sopenharmony_cistatic pa_dbus_interface_info manager_info={ 148053a5a1b3Sopenharmony_ci .name=MANAGER_IFACE, 148153a5a1b3Sopenharmony_ci .method_handlers=manager_methods, 148253a5a1b3Sopenharmony_ci .n_method_handlers=MANAGER_METHOD_MAX, 148353a5a1b3Sopenharmony_ci .property_handlers=manager_handlers, 148453a5a1b3Sopenharmony_ci .n_property_handlers=MANAGER_HANDLER_MAX, 148553a5a1b3Sopenharmony_ci .get_all_properties_cb=manager_get_all, 148653a5a1b3Sopenharmony_ci .signals=manager_signals, 148753a5a1b3Sopenharmony_ci .n_signals=MANAGER_SIGNAL_MAX 148853a5a1b3Sopenharmony_ci}; 148953a5a1b3Sopenharmony_ci 149053a5a1b3Sopenharmony_cienum equalizer_method_index { 149153a5a1b3Sopenharmony_ci EQUALIZER_METHOD_FILTER_POINTS, 149253a5a1b3Sopenharmony_ci EQUALIZER_METHOD_SEED_FILTER, 149353a5a1b3Sopenharmony_ci EQUALIZER_METHOD_SAVE_PROFILE, 149453a5a1b3Sopenharmony_ci EQUALIZER_METHOD_LOAD_PROFILE, 149553a5a1b3Sopenharmony_ci EQUALIZER_METHOD_SET_FILTER, 149653a5a1b3Sopenharmony_ci EQUALIZER_METHOD_GET_FILTER, 149753a5a1b3Sopenharmony_ci EQUALIZER_METHOD_SAVE_STATE, 149853a5a1b3Sopenharmony_ci EQUALIZER_METHOD_GET_PROFILE_NAME, 149953a5a1b3Sopenharmony_ci EQUALIZER_METHOD_MAX 150053a5a1b3Sopenharmony_ci}; 150153a5a1b3Sopenharmony_ci 150253a5a1b3Sopenharmony_cienum equalizer_handler_index { 150353a5a1b3Sopenharmony_ci EQUALIZER_HANDLER_REVISION, 150453a5a1b3Sopenharmony_ci EQUALIZER_HANDLER_SAMPLERATE, 150553a5a1b3Sopenharmony_ci EQUALIZER_HANDLER_FILTERSAMPLERATE, 150653a5a1b3Sopenharmony_ci EQUALIZER_HANDLER_N_COEFS, 150753a5a1b3Sopenharmony_ci EQUALIZER_HANDLER_N_CHANNELS, 150853a5a1b3Sopenharmony_ci EQUALIZER_HANDLER_MAX 150953a5a1b3Sopenharmony_ci}; 151053a5a1b3Sopenharmony_ci 151153a5a1b3Sopenharmony_cipa_dbus_arg_info filter_points_args[]={ 151253a5a1b3Sopenharmony_ci {"channel", "u","in"}, 151353a5a1b3Sopenharmony_ci {"xs", "au","in"}, 151453a5a1b3Sopenharmony_ci {"ys", "ad","out"}, 151553a5a1b3Sopenharmony_ci {"preamp", "d","out"} 151653a5a1b3Sopenharmony_ci}; 151753a5a1b3Sopenharmony_cipa_dbus_arg_info seed_filter_args[]={ 151853a5a1b3Sopenharmony_ci {"channel", "u","in"}, 151953a5a1b3Sopenharmony_ci {"xs", "au","in"}, 152053a5a1b3Sopenharmony_ci {"ys", "ad","in"}, 152153a5a1b3Sopenharmony_ci {"preamp", "d","in"} 152253a5a1b3Sopenharmony_ci}; 152353a5a1b3Sopenharmony_ci 152453a5a1b3Sopenharmony_cipa_dbus_arg_info set_filter_args[]={ 152553a5a1b3Sopenharmony_ci {"channel", "u","in"}, 152653a5a1b3Sopenharmony_ci {"ys", "ad","in"}, 152753a5a1b3Sopenharmony_ci {"preamp", "d","in"} 152853a5a1b3Sopenharmony_ci}; 152953a5a1b3Sopenharmony_cipa_dbus_arg_info get_filter_args[]={ 153053a5a1b3Sopenharmony_ci {"channel", "u","in"}, 153153a5a1b3Sopenharmony_ci {"ys", "ad","out"}, 153253a5a1b3Sopenharmony_ci {"preamp", "d","out"} 153353a5a1b3Sopenharmony_ci}; 153453a5a1b3Sopenharmony_ci 153553a5a1b3Sopenharmony_cipa_dbus_arg_info save_profile_args[]={ 153653a5a1b3Sopenharmony_ci {"channel", "u","in"}, 153753a5a1b3Sopenharmony_ci {"name", "s","in"} 153853a5a1b3Sopenharmony_ci}; 153953a5a1b3Sopenharmony_cipa_dbus_arg_info load_profile_args[]={ 154053a5a1b3Sopenharmony_ci {"channel", "u","in"}, 154153a5a1b3Sopenharmony_ci {"name", "s","in"} 154253a5a1b3Sopenharmony_ci}; 154353a5a1b3Sopenharmony_cipa_dbus_arg_info base_profile_name_args[]={ 154453a5a1b3Sopenharmony_ci {"channel", "u","in"}, 154553a5a1b3Sopenharmony_ci {"name", "s","out"} 154653a5a1b3Sopenharmony_ci}; 154753a5a1b3Sopenharmony_ci 154853a5a1b3Sopenharmony_cistatic pa_dbus_method_handler equalizer_methods[EQUALIZER_METHOD_MAX]={ 154953a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_SEED_FILTER]={ 155053a5a1b3Sopenharmony_ci .method_name="SeedFilter", 155153a5a1b3Sopenharmony_ci .arguments=seed_filter_args, 155253a5a1b3Sopenharmony_ci .n_arguments=sizeof(seed_filter_args)/sizeof(pa_dbus_arg_info), 155353a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_seed_filter}, 155453a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_FILTER_POINTS]={ 155553a5a1b3Sopenharmony_ci .method_name="FilterAtPoints", 155653a5a1b3Sopenharmony_ci .arguments=filter_points_args, 155753a5a1b3Sopenharmony_ci .n_arguments=sizeof(filter_points_args)/sizeof(pa_dbus_arg_info), 155853a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_get_filter_points}, 155953a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_SET_FILTER]={ 156053a5a1b3Sopenharmony_ci .method_name="SetFilter", 156153a5a1b3Sopenharmony_ci .arguments=set_filter_args, 156253a5a1b3Sopenharmony_ci .n_arguments=sizeof(set_filter_args)/sizeof(pa_dbus_arg_info), 156353a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_set_filter}, 156453a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_GET_FILTER]={ 156553a5a1b3Sopenharmony_ci .method_name="GetFilter", 156653a5a1b3Sopenharmony_ci .arguments=get_filter_args, 156753a5a1b3Sopenharmony_ci .n_arguments=sizeof(get_filter_args)/sizeof(pa_dbus_arg_info), 156853a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_get_filter}, 156953a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_SAVE_PROFILE]={ 157053a5a1b3Sopenharmony_ci .method_name="SaveProfile", 157153a5a1b3Sopenharmony_ci .arguments=save_profile_args, 157253a5a1b3Sopenharmony_ci .n_arguments=sizeof(save_profile_args)/sizeof(pa_dbus_arg_info), 157353a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_save_profile}, 157453a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_LOAD_PROFILE]={ 157553a5a1b3Sopenharmony_ci .method_name="LoadProfile", 157653a5a1b3Sopenharmony_ci .arguments=load_profile_args, 157753a5a1b3Sopenharmony_ci .n_arguments=sizeof(load_profile_args)/sizeof(pa_dbus_arg_info), 157853a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_load_profile}, 157953a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_SAVE_STATE]={ 158053a5a1b3Sopenharmony_ci .method_name="SaveState", 158153a5a1b3Sopenharmony_ci .arguments=NULL, 158253a5a1b3Sopenharmony_ci .n_arguments=0, 158353a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_save_state}, 158453a5a1b3Sopenharmony_ci [EQUALIZER_METHOD_GET_PROFILE_NAME]={ 158553a5a1b3Sopenharmony_ci .method_name="BaseProfile", 158653a5a1b3Sopenharmony_ci .arguments=base_profile_name_args, 158753a5a1b3Sopenharmony_ci .n_arguments=sizeof(base_profile_name_args)/sizeof(pa_dbus_arg_info), 158853a5a1b3Sopenharmony_ci .receive_cb=equalizer_handle_get_profile_name} 158953a5a1b3Sopenharmony_ci}; 159053a5a1b3Sopenharmony_ci 159153a5a1b3Sopenharmony_cistatic pa_dbus_property_handler equalizer_handlers[EQUALIZER_HANDLER_MAX]={ 159253a5a1b3Sopenharmony_ci [EQUALIZER_HANDLER_REVISION]={.property_name="InterfaceRevision",.type="u",.get_cb=equalizer_get_revision,.set_cb=NULL}, 159353a5a1b3Sopenharmony_ci [EQUALIZER_HANDLER_SAMPLERATE]={.property_name="SampleRate",.type="u",.get_cb=equalizer_get_sample_rate,.set_cb=NULL}, 159453a5a1b3Sopenharmony_ci [EQUALIZER_HANDLER_FILTERSAMPLERATE]={.property_name="FilterSampleRate",.type="u",.get_cb=equalizer_get_filter_rate,.set_cb=NULL}, 159553a5a1b3Sopenharmony_ci [EQUALIZER_HANDLER_N_COEFS]={.property_name="NFilterCoefficients",.type="u",.get_cb=equalizer_get_n_coefs,.set_cb=NULL}, 159653a5a1b3Sopenharmony_ci [EQUALIZER_HANDLER_N_CHANNELS]={.property_name="NChannels",.type="u",.get_cb=equalizer_get_n_channels,.set_cb=NULL}, 159753a5a1b3Sopenharmony_ci}; 159853a5a1b3Sopenharmony_ci 159953a5a1b3Sopenharmony_cienum equalizer_signal_index{ 160053a5a1b3Sopenharmony_ci EQUALIZER_SIGNAL_FILTER_CHANGED, 160153a5a1b3Sopenharmony_ci EQUALIZER_SIGNAL_SINK_RECONFIGURED, 160253a5a1b3Sopenharmony_ci EQUALIZER_SIGNAL_MAX 160353a5a1b3Sopenharmony_ci}; 160453a5a1b3Sopenharmony_ci 160553a5a1b3Sopenharmony_cistatic pa_dbus_signal_info equalizer_signals[EQUALIZER_SIGNAL_MAX]={ 160653a5a1b3Sopenharmony_ci [EQUALIZER_SIGNAL_FILTER_CHANGED]={.name="FilterChanged", .arguments=NULL, .n_arguments=0}, 160753a5a1b3Sopenharmony_ci [EQUALIZER_SIGNAL_SINK_RECONFIGURED]={.name="SinkReconfigured", .arguments=NULL, .n_arguments=0}, 160853a5a1b3Sopenharmony_ci}; 160953a5a1b3Sopenharmony_ci 161053a5a1b3Sopenharmony_cistatic pa_dbus_interface_info equalizer_info={ 161153a5a1b3Sopenharmony_ci .name=EQUALIZER_IFACE, 161253a5a1b3Sopenharmony_ci .method_handlers=equalizer_methods, 161353a5a1b3Sopenharmony_ci .n_method_handlers=EQUALIZER_METHOD_MAX, 161453a5a1b3Sopenharmony_ci .property_handlers=equalizer_handlers, 161553a5a1b3Sopenharmony_ci .n_property_handlers=EQUALIZER_HANDLER_MAX, 161653a5a1b3Sopenharmony_ci .get_all_properties_cb=equalizer_get_all, 161753a5a1b3Sopenharmony_ci .signals=equalizer_signals, 161853a5a1b3Sopenharmony_ci .n_signals=EQUALIZER_SIGNAL_MAX 161953a5a1b3Sopenharmony_ci}; 162053a5a1b3Sopenharmony_ci 162153a5a1b3Sopenharmony_civoid dbus_init(struct userdata *u) { 162253a5a1b3Sopenharmony_ci uint32_t dummy; 162353a5a1b3Sopenharmony_ci DBusMessage *message = NULL; 162453a5a1b3Sopenharmony_ci pa_idxset *sink_list = NULL; 162553a5a1b3Sopenharmony_ci u->dbus_protocol=pa_dbus_protocol_get(u->sink->core); 162653a5a1b3Sopenharmony_ci u->dbus_path=pa_sprintf_malloc("/org/pulseaudio/core1/sink%d", u->sink->index); 162753a5a1b3Sopenharmony_ci 162853a5a1b3Sopenharmony_ci pa_assert_se(pa_dbus_protocol_add_interface(u->dbus_protocol, u->dbus_path, &equalizer_info, u) >= 0); 162953a5a1b3Sopenharmony_ci sink_list = pa_shared_get(u->sink->core, SINKLIST); 163053a5a1b3Sopenharmony_ci u->database = pa_shared_get(u->sink->core, EQDB); 163153a5a1b3Sopenharmony_ci if (sink_list == NULL) { 163253a5a1b3Sopenharmony_ci char *state_path; 163353a5a1b3Sopenharmony_ci sink_list=pa_idxset_new(&pa_idxset_trivial_hash_func, &pa_idxset_trivial_compare_func); 163453a5a1b3Sopenharmony_ci pa_shared_set(u->sink->core, SINKLIST, sink_list); 163553a5a1b3Sopenharmony_ci pa_assert_se(state_path = pa_state_path(NULL, false)); 163653a5a1b3Sopenharmony_ci pa_assert_se(u->database = pa_database_open(state_path, "equalizer-presets", false, true)); 163753a5a1b3Sopenharmony_ci pa_xfree(state_path); 163853a5a1b3Sopenharmony_ci pa_shared_set(u->sink->core, EQDB, u->database); 163953a5a1b3Sopenharmony_ci pa_dbus_protocol_add_interface(u->dbus_protocol, MANAGER_PATH, &manager_info, u->sink->core); 164053a5a1b3Sopenharmony_ci pa_dbus_protocol_register_extension(u->dbus_protocol, EXTNAME); 164153a5a1b3Sopenharmony_ci } 164253a5a1b3Sopenharmony_ci pa_idxset_put(sink_list, u, &dummy); 164353a5a1b3Sopenharmony_ci 164453a5a1b3Sopenharmony_ci pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_ADDED].name))); 164553a5a1b3Sopenharmony_ci dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID); 164653a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(u->dbus_protocol, message); 164753a5a1b3Sopenharmony_ci dbus_message_unref(message); 164853a5a1b3Sopenharmony_ci} 164953a5a1b3Sopenharmony_ci 165053a5a1b3Sopenharmony_civoid dbus_done(struct userdata *u) { 165153a5a1b3Sopenharmony_ci pa_idxset *sink_list; 165253a5a1b3Sopenharmony_ci uint32_t dummy; 165353a5a1b3Sopenharmony_ci 165453a5a1b3Sopenharmony_ci DBusMessage *message = NULL; 165553a5a1b3Sopenharmony_ci pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_SINK_REMOVED].name))); 165653a5a1b3Sopenharmony_ci dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &u->dbus_path, DBUS_TYPE_INVALID); 165753a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(u->dbus_protocol, message); 165853a5a1b3Sopenharmony_ci dbus_message_unref(message); 165953a5a1b3Sopenharmony_ci 166053a5a1b3Sopenharmony_ci pa_assert_se(sink_list=pa_shared_get(u->sink->core,SINKLIST)); 166153a5a1b3Sopenharmony_ci pa_idxset_remove_by_data(sink_list,u,&dummy); 166253a5a1b3Sopenharmony_ci if (pa_idxset_size(sink_list) == 0) { 166353a5a1b3Sopenharmony_ci pa_dbus_protocol_unregister_extension(u->dbus_protocol, EXTNAME); 166453a5a1b3Sopenharmony_ci pa_dbus_protocol_remove_interface(u->dbus_protocol, MANAGER_PATH, manager_info.name); 166553a5a1b3Sopenharmony_ci pa_shared_remove(u->sink->core, EQDB); 166653a5a1b3Sopenharmony_ci pa_database_close(u->database); 166753a5a1b3Sopenharmony_ci pa_shared_remove(u->sink->core, SINKLIST); 166853a5a1b3Sopenharmony_ci pa_xfree(sink_list); 166953a5a1b3Sopenharmony_ci } 167053a5a1b3Sopenharmony_ci pa_dbus_protocol_remove_interface(u->dbus_protocol, u->dbus_path, equalizer_info.name); 167153a5a1b3Sopenharmony_ci pa_xfree(u->dbus_path); 167253a5a1b3Sopenharmony_ci pa_dbus_protocol_unref(u->dbus_protocol); 167353a5a1b3Sopenharmony_ci} 167453a5a1b3Sopenharmony_ci 167553a5a1b3Sopenharmony_civoid manager_handle_remove_profile(DBusConnection *conn, DBusMessage *msg, void *_u) { 167653a5a1b3Sopenharmony_ci DBusError error; 167753a5a1b3Sopenharmony_ci pa_core *c = (pa_core *)_u; 167853a5a1b3Sopenharmony_ci DBusMessage *message = NULL; 167953a5a1b3Sopenharmony_ci pa_dbus_protocol *dbus_protocol; 168053a5a1b3Sopenharmony_ci char *name; 168153a5a1b3Sopenharmony_ci pa_assert(conn); 168253a5a1b3Sopenharmony_ci pa_assert(msg); 168353a5a1b3Sopenharmony_ci pa_assert(c); 168453a5a1b3Sopenharmony_ci dbus_error_init(&error); 168553a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 168653a5a1b3Sopenharmony_ci DBUS_TYPE_STRING, &name, 168753a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 168853a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 168953a5a1b3Sopenharmony_ci dbus_error_free(&error); 169053a5a1b3Sopenharmony_ci return; 169153a5a1b3Sopenharmony_ci } 169253a5a1b3Sopenharmony_ci remove_profile(c,name); 169353a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 169453a5a1b3Sopenharmony_ci 169553a5a1b3Sopenharmony_ci pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name))); 169653a5a1b3Sopenharmony_ci dbus_protocol = pa_dbus_protocol_get(c); 169753a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(dbus_protocol, message); 169853a5a1b3Sopenharmony_ci pa_dbus_protocol_unref(dbus_protocol); 169953a5a1b3Sopenharmony_ci dbus_message_unref(message); 170053a5a1b3Sopenharmony_ci} 170153a5a1b3Sopenharmony_ci 170253a5a1b3Sopenharmony_civoid manager_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u) { 170353a5a1b3Sopenharmony_ci uint32_t rev=1; 170453a5a1b3Sopenharmony_ci pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev); 170553a5a1b3Sopenharmony_ci} 170653a5a1b3Sopenharmony_ci 170753a5a1b3Sopenharmony_cistatic void get_sinks(pa_core *u, char ***names, unsigned *n_sinks) { 170853a5a1b3Sopenharmony_ci void *iter = NULL; 170953a5a1b3Sopenharmony_ci struct userdata *sink_u = NULL; 171053a5a1b3Sopenharmony_ci uint32_t dummy; 171153a5a1b3Sopenharmony_ci pa_idxset *sink_list; 171253a5a1b3Sopenharmony_ci pa_assert(u); 171353a5a1b3Sopenharmony_ci pa_assert(names); 171453a5a1b3Sopenharmony_ci pa_assert(n_sinks); 171553a5a1b3Sopenharmony_ci 171653a5a1b3Sopenharmony_ci pa_assert_se(sink_list = pa_shared_get(u, SINKLIST)); 171753a5a1b3Sopenharmony_ci *n_sinks = (unsigned) pa_idxset_size(sink_list); 171853a5a1b3Sopenharmony_ci *names = *n_sinks > 0 ? pa_xnew0(char *,*n_sinks) : NULL; 171953a5a1b3Sopenharmony_ci for(uint32_t i = 0; i < *n_sinks; ++i) { 172053a5a1b3Sopenharmony_ci sink_u = (struct userdata *) pa_idxset_iterate(sink_list, &iter, &dummy); 172153a5a1b3Sopenharmony_ci (*names)[i] = pa_xstrdup(sink_u->dbus_path); 172253a5a1b3Sopenharmony_ci } 172353a5a1b3Sopenharmony_ci} 172453a5a1b3Sopenharmony_ci 172553a5a1b3Sopenharmony_civoid manager_get_sinks(DBusConnection *conn, DBusMessage *msg, void *_u) { 172653a5a1b3Sopenharmony_ci unsigned n; 172753a5a1b3Sopenharmony_ci char **names = NULL; 172853a5a1b3Sopenharmony_ci pa_assert(conn); 172953a5a1b3Sopenharmony_ci pa_assert(msg); 173053a5a1b3Sopenharmony_ci pa_assert(_u); 173153a5a1b3Sopenharmony_ci 173253a5a1b3Sopenharmony_ci get_sinks((pa_core *) _u, &names, &n); 173353a5a1b3Sopenharmony_ci pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, names, n); 173453a5a1b3Sopenharmony_ci for(unsigned i = 0; i < n; ++i) { 173553a5a1b3Sopenharmony_ci pa_xfree(names[i]); 173653a5a1b3Sopenharmony_ci } 173753a5a1b3Sopenharmony_ci pa_xfree(names); 173853a5a1b3Sopenharmony_ci} 173953a5a1b3Sopenharmony_ci 174053a5a1b3Sopenharmony_cistatic void get_profiles(pa_core *c, char ***names, unsigned *n) { 174153a5a1b3Sopenharmony_ci char *name; 174253a5a1b3Sopenharmony_ci pa_database *database; 174353a5a1b3Sopenharmony_ci pa_datum key, next_key; 174453a5a1b3Sopenharmony_ci pa_strlist *head=NULL, *iter; 174553a5a1b3Sopenharmony_ci bool done; 174653a5a1b3Sopenharmony_ci pa_assert_se(database = pa_shared_get(c, EQDB)); 174753a5a1b3Sopenharmony_ci 174853a5a1b3Sopenharmony_ci pa_assert(c); 174953a5a1b3Sopenharmony_ci pa_assert(names); 175053a5a1b3Sopenharmony_ci pa_assert(n); 175153a5a1b3Sopenharmony_ci done = !pa_database_first(database, &key, NULL); 175253a5a1b3Sopenharmony_ci *n = 0; 175353a5a1b3Sopenharmony_ci while(!done) { 175453a5a1b3Sopenharmony_ci done = !pa_database_next(database, &key, &next_key, NULL); 175553a5a1b3Sopenharmony_ci name=pa_xmalloc(key.size + 1); 175653a5a1b3Sopenharmony_ci memcpy(name, key.data, key.size); 175753a5a1b3Sopenharmony_ci name[key.size] = '\0'; 175853a5a1b3Sopenharmony_ci pa_datum_free(&key); 175953a5a1b3Sopenharmony_ci head = pa_strlist_prepend(head, name); 176053a5a1b3Sopenharmony_ci pa_xfree(name); 176153a5a1b3Sopenharmony_ci key = next_key; 176253a5a1b3Sopenharmony_ci (*n)++; 176353a5a1b3Sopenharmony_ci } 176453a5a1b3Sopenharmony_ci (*names) = *n > 0 ? pa_xnew0(char *, *n) : NULL; 176553a5a1b3Sopenharmony_ci iter=head; 176653a5a1b3Sopenharmony_ci for(unsigned i = 0; i < *n; ++i) { 176753a5a1b3Sopenharmony_ci (*names)[*n - 1 - i] = pa_xstrdup(pa_strlist_data(iter)); 176853a5a1b3Sopenharmony_ci iter = pa_strlist_next(iter); 176953a5a1b3Sopenharmony_ci } 177053a5a1b3Sopenharmony_ci pa_strlist_free(head); 177153a5a1b3Sopenharmony_ci} 177253a5a1b3Sopenharmony_ci 177353a5a1b3Sopenharmony_civoid manager_get_profiles(DBusConnection *conn, DBusMessage *msg, void *_u) { 177453a5a1b3Sopenharmony_ci char **names; 177553a5a1b3Sopenharmony_ci unsigned n; 177653a5a1b3Sopenharmony_ci pa_assert(conn); 177753a5a1b3Sopenharmony_ci pa_assert(msg); 177853a5a1b3Sopenharmony_ci pa_assert(_u); 177953a5a1b3Sopenharmony_ci 178053a5a1b3Sopenharmony_ci get_profiles((pa_core *)_u, &names, &n); 178153a5a1b3Sopenharmony_ci pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_STRING, names, n); 178253a5a1b3Sopenharmony_ci for(unsigned i = 0; i < n; ++i) { 178353a5a1b3Sopenharmony_ci pa_xfree(names[i]); 178453a5a1b3Sopenharmony_ci } 178553a5a1b3Sopenharmony_ci pa_xfree(names); 178653a5a1b3Sopenharmony_ci} 178753a5a1b3Sopenharmony_ci 178853a5a1b3Sopenharmony_civoid manager_get_all(DBusConnection *conn, DBusMessage *msg, void *_u) { 178953a5a1b3Sopenharmony_ci pa_core *c; 179053a5a1b3Sopenharmony_ci char **names = NULL; 179153a5a1b3Sopenharmony_ci unsigned n; 179253a5a1b3Sopenharmony_ci DBusMessage *reply = NULL; 179353a5a1b3Sopenharmony_ci DBusMessageIter msg_iter, dict_iter; 179453a5a1b3Sopenharmony_ci uint32_t rev; 179553a5a1b3Sopenharmony_ci pa_assert(conn); 179653a5a1b3Sopenharmony_ci pa_assert(msg); 179753a5a1b3Sopenharmony_ci pa_assert_se(c = _u); 179853a5a1b3Sopenharmony_ci 179953a5a1b3Sopenharmony_ci pa_assert_se((reply = dbus_message_new_method_return(msg))); 180053a5a1b3Sopenharmony_ci dbus_message_iter_init_append(reply, &msg_iter); 180153a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 180253a5a1b3Sopenharmony_ci 180353a5a1b3Sopenharmony_ci rev = 1; 180453a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev); 180553a5a1b3Sopenharmony_ci 180653a5a1b3Sopenharmony_ci get_sinks(c, &names, &n); 180753a5a1b3Sopenharmony_ci pa_dbus_append_basic_array_variant_dict_entry(&dict_iter,manager_handlers[MANAGER_HANDLER_EQUALIZED_SINKS].property_name, DBUS_TYPE_OBJECT_PATH, names, n); 180853a5a1b3Sopenharmony_ci for(unsigned i = 0; i < n; ++i) { 180953a5a1b3Sopenharmony_ci pa_xfree(names[i]); 181053a5a1b3Sopenharmony_ci } 181153a5a1b3Sopenharmony_ci pa_xfree(names); 181253a5a1b3Sopenharmony_ci 181353a5a1b3Sopenharmony_ci get_profiles(c, &names, &n); 181453a5a1b3Sopenharmony_ci pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, manager_handlers[MANAGER_HANDLER_PROFILES].property_name, DBUS_TYPE_STRING, names, n); 181553a5a1b3Sopenharmony_ci for(unsigned i = 0; i < n; ++i) { 181653a5a1b3Sopenharmony_ci pa_xfree(names[i]); 181753a5a1b3Sopenharmony_ci } 181853a5a1b3Sopenharmony_ci pa_xfree(names); 181953a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 182053a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_send(conn, reply, NULL)); 182153a5a1b3Sopenharmony_ci dbus_message_unref(reply); 182253a5a1b3Sopenharmony_ci} 182353a5a1b3Sopenharmony_ci 182453a5a1b3Sopenharmony_civoid equalizer_handle_seed_filter(DBusConnection *conn, DBusMessage *msg, void *_u) { 182553a5a1b3Sopenharmony_ci struct userdata *u = _u; 182653a5a1b3Sopenharmony_ci DBusError error; 182753a5a1b3Sopenharmony_ci DBusMessage *message = NULL; 182853a5a1b3Sopenharmony_ci float *ys; 182953a5a1b3Sopenharmony_ci uint32_t *xs, channel, r_channel; 183053a5a1b3Sopenharmony_ci double *_ys, preamp; 183153a5a1b3Sopenharmony_ci unsigned x_npoints, y_npoints, a_i; 183253a5a1b3Sopenharmony_ci float *H; 183353a5a1b3Sopenharmony_ci bool points_good = true; 183453a5a1b3Sopenharmony_ci 183553a5a1b3Sopenharmony_ci pa_assert(conn); 183653a5a1b3Sopenharmony_ci pa_assert(msg); 183753a5a1b3Sopenharmony_ci pa_assert(u); 183853a5a1b3Sopenharmony_ci 183953a5a1b3Sopenharmony_ci dbus_error_init(&error); 184053a5a1b3Sopenharmony_ci 184153a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 184253a5a1b3Sopenharmony_ci DBUS_TYPE_UINT32, &channel, 184353a5a1b3Sopenharmony_ci DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints, 184453a5a1b3Sopenharmony_ci DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &_ys, &y_npoints, 184553a5a1b3Sopenharmony_ci DBUS_TYPE_DOUBLE, &preamp, 184653a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 184753a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 184853a5a1b3Sopenharmony_ci dbus_error_free(&error); 184953a5a1b3Sopenharmony_ci return; 185053a5a1b3Sopenharmony_ci } 185153a5a1b3Sopenharmony_ci if (channel > u->channels) { 185253a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel); 185353a5a1b3Sopenharmony_ci dbus_error_free(&error); 185453a5a1b3Sopenharmony_ci return; 185553a5a1b3Sopenharmony_ci } 185653a5a1b3Sopenharmony_ci for(size_t i = 0; i < x_npoints; ++i) { 185753a5a1b3Sopenharmony_ci if (xs[i] >= FILTER_SIZE(u)) { 185853a5a1b3Sopenharmony_ci points_good = false; 185953a5a1b3Sopenharmony_ci break; 186053a5a1b3Sopenharmony_ci } 186153a5a1b3Sopenharmony_ci } 186253a5a1b3Sopenharmony_ci if (!is_monotonic(xs, x_npoints) || !points_good) { 186353a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs must be monotonic and 0<=x<=%zd", u->fft_size / 2); 186453a5a1b3Sopenharmony_ci dbus_error_free(&error); 186553a5a1b3Sopenharmony_ci return; 186653a5a1b3Sopenharmony_ci }else if (x_npoints != y_npoints || x_npoints < 2 || x_npoints > FILTER_SIZE(u)) { 186753a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs and ys must be the same length and 2<=l<=%zd!", FILTER_SIZE(u)); 186853a5a1b3Sopenharmony_ci dbus_error_free(&error); 186953a5a1b3Sopenharmony_ci return; 187053a5a1b3Sopenharmony_ci }else if (xs[0] != 0 || xs[x_npoints - 1] != u->fft_size / 2) { 187153a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs[0] must be 0 and xs[-1]=fft_size/2"); 187253a5a1b3Sopenharmony_ci dbus_error_free(&error); 187353a5a1b3Sopenharmony_ci return; 187453a5a1b3Sopenharmony_ci } 187553a5a1b3Sopenharmony_ci 187653a5a1b3Sopenharmony_ci ys = pa_xmalloc(x_npoints * sizeof(float)); 187753a5a1b3Sopenharmony_ci for(uint32_t i = 0; i < x_npoints; ++i) { 187853a5a1b3Sopenharmony_ci ys[i] = (float) _ys[i]; 187953a5a1b3Sopenharmony_ci } 188053a5a1b3Sopenharmony_ci r_channel = channel == u->channels ? 0 : channel; 188153a5a1b3Sopenharmony_ci a_i = pa_aupdate_write_begin(u->a_H[r_channel]); 188253a5a1b3Sopenharmony_ci H = u->Hs[r_channel][a_i]; 188353a5a1b3Sopenharmony_ci u->Xs[r_channel][a_i] = preamp; 188453a5a1b3Sopenharmony_ci interpolate(H, FILTER_SIZE(u), xs, ys, x_npoints); 188553a5a1b3Sopenharmony_ci fix_filter(H, u->fft_size); 188653a5a1b3Sopenharmony_ci if (channel == u->channels) { 188753a5a1b3Sopenharmony_ci for(size_t c = 1; c < u->channels; ++c) { 188853a5a1b3Sopenharmony_ci unsigned b_i = pa_aupdate_write_begin(u->a_H[c]); 188953a5a1b3Sopenharmony_ci float *H_p = u->Hs[c][b_i]; 189053a5a1b3Sopenharmony_ci u->Xs[c][b_i] = preamp; 189153a5a1b3Sopenharmony_ci memcpy(H_p, H, FILTER_SIZE(u) * sizeof(float)); 189253a5a1b3Sopenharmony_ci pa_aupdate_write_end(u->a_H[c]); 189353a5a1b3Sopenharmony_ci } 189453a5a1b3Sopenharmony_ci } 189553a5a1b3Sopenharmony_ci pa_aupdate_write_end(u->a_H[r_channel]); 189653a5a1b3Sopenharmony_ci pa_xfree(ys); 189753a5a1b3Sopenharmony_ci 189853a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 189953a5a1b3Sopenharmony_ci 190053a5a1b3Sopenharmony_ci pa_assert_se((message = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name))); 190153a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(u->dbus_protocol, message); 190253a5a1b3Sopenharmony_ci dbus_message_unref(message); 190353a5a1b3Sopenharmony_ci} 190453a5a1b3Sopenharmony_ci 190553a5a1b3Sopenharmony_civoid equalizer_handle_get_filter_points(DBusConnection *conn, DBusMessage *msg, void *_u) { 190653a5a1b3Sopenharmony_ci struct userdata *u = (struct userdata *) _u; 190753a5a1b3Sopenharmony_ci uint32_t *xs, channel, r_channel; 190853a5a1b3Sopenharmony_ci double *ys, preamp; 190953a5a1b3Sopenharmony_ci unsigned x_npoints, a_i; 191053a5a1b3Sopenharmony_ci float *H; 191153a5a1b3Sopenharmony_ci bool points_good=true; 191253a5a1b3Sopenharmony_ci DBusMessage *reply = NULL; 191353a5a1b3Sopenharmony_ci DBusMessageIter msg_iter; 191453a5a1b3Sopenharmony_ci DBusError error; 191553a5a1b3Sopenharmony_ci 191653a5a1b3Sopenharmony_ci pa_assert(conn); 191753a5a1b3Sopenharmony_ci pa_assert(msg); 191853a5a1b3Sopenharmony_ci pa_assert(u); 191953a5a1b3Sopenharmony_ci 192053a5a1b3Sopenharmony_ci dbus_error_init(&error); 192153a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 192253a5a1b3Sopenharmony_ci DBUS_TYPE_UINT32, &channel, 192353a5a1b3Sopenharmony_ci DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &xs, &x_npoints, 192453a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 192553a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 192653a5a1b3Sopenharmony_ci dbus_error_free(&error); 192753a5a1b3Sopenharmony_ci return; 192853a5a1b3Sopenharmony_ci } 192953a5a1b3Sopenharmony_ci if (channel > u->channels) { 193053a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel); 193153a5a1b3Sopenharmony_ci dbus_error_free(&error); 193253a5a1b3Sopenharmony_ci return; 193353a5a1b3Sopenharmony_ci } 193453a5a1b3Sopenharmony_ci 193553a5a1b3Sopenharmony_ci for(size_t i = 0; i < x_npoints; ++i) { 193653a5a1b3Sopenharmony_ci if (xs[i] >= FILTER_SIZE(u)) { 193753a5a1b3Sopenharmony_ci points_good=false; 193853a5a1b3Sopenharmony_ci break; 193953a5a1b3Sopenharmony_ci } 194053a5a1b3Sopenharmony_ci } 194153a5a1b3Sopenharmony_ci 194253a5a1b3Sopenharmony_ci if (x_npoints > FILTER_SIZE(u) || !points_good) { 194353a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "xs indices/length must be <= %zd!", FILTER_SIZE(u)); 194453a5a1b3Sopenharmony_ci dbus_error_free(&error); 194553a5a1b3Sopenharmony_ci return; 194653a5a1b3Sopenharmony_ci } 194753a5a1b3Sopenharmony_ci 194853a5a1b3Sopenharmony_ci r_channel = channel == u->channels ? 0 : channel; 194953a5a1b3Sopenharmony_ci ys = pa_xmalloc(x_npoints * sizeof(double)); 195053a5a1b3Sopenharmony_ci a_i = pa_aupdate_read_begin(u->a_H[r_channel]); 195153a5a1b3Sopenharmony_ci H = u->Hs[r_channel][a_i]; 195253a5a1b3Sopenharmony_ci preamp = u->Xs[r_channel][a_i]; 195353a5a1b3Sopenharmony_ci for(uint32_t i = 0; i < x_npoints; ++i) { 195453a5a1b3Sopenharmony_ci ys[i] = H[xs[i]] * u->fft_size; 195553a5a1b3Sopenharmony_ci } 195653a5a1b3Sopenharmony_ci pa_aupdate_read_end(u->a_H[r_channel]); 195753a5a1b3Sopenharmony_ci 195853a5a1b3Sopenharmony_ci pa_assert_se((reply = dbus_message_new_method_return(msg))); 195953a5a1b3Sopenharmony_ci dbus_message_iter_init_append(reply, &msg_iter); 196053a5a1b3Sopenharmony_ci 196153a5a1b3Sopenharmony_ci pa_dbus_append_basic_array(&msg_iter, DBUS_TYPE_DOUBLE, ys, x_npoints); 196253a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_DOUBLE, &preamp); 196353a5a1b3Sopenharmony_ci 196453a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_send(conn, reply, NULL)); 196553a5a1b3Sopenharmony_ci dbus_message_unref(reply); 196653a5a1b3Sopenharmony_ci pa_xfree(ys); 196753a5a1b3Sopenharmony_ci} 196853a5a1b3Sopenharmony_ci 196953a5a1b3Sopenharmony_cistatic void get_filter(struct userdata *u, size_t channel, double **H_, double *preamp) { 197053a5a1b3Sopenharmony_ci float *H; 197153a5a1b3Sopenharmony_ci unsigned a_i; 197253a5a1b3Sopenharmony_ci size_t r_channel = channel == u->channels ? 0 : channel; 197353a5a1b3Sopenharmony_ci *H_ = pa_xnew0(double, FILTER_SIZE(u)); 197453a5a1b3Sopenharmony_ci a_i = pa_aupdate_read_begin(u->a_H[r_channel]); 197553a5a1b3Sopenharmony_ci H = u->Hs[r_channel][a_i]; 197653a5a1b3Sopenharmony_ci for(size_t i = 0;i < FILTER_SIZE(u); ++i) { 197753a5a1b3Sopenharmony_ci (*H_)[i] = H[i] * u->fft_size; 197853a5a1b3Sopenharmony_ci } 197953a5a1b3Sopenharmony_ci *preamp = u->Xs[r_channel][a_i]; 198053a5a1b3Sopenharmony_ci 198153a5a1b3Sopenharmony_ci pa_aupdate_read_end(u->a_H[r_channel]); 198253a5a1b3Sopenharmony_ci} 198353a5a1b3Sopenharmony_ci 198453a5a1b3Sopenharmony_civoid equalizer_handle_get_filter(DBusConnection *conn, DBusMessage *msg, void *_u) { 198553a5a1b3Sopenharmony_ci struct userdata *u; 198653a5a1b3Sopenharmony_ci unsigned n_coefs; 198753a5a1b3Sopenharmony_ci uint32_t channel; 198853a5a1b3Sopenharmony_ci double *H_, preamp; 198953a5a1b3Sopenharmony_ci DBusMessage *reply = NULL; 199053a5a1b3Sopenharmony_ci DBusMessageIter msg_iter; 199153a5a1b3Sopenharmony_ci DBusError error; 199253a5a1b3Sopenharmony_ci pa_assert_se(u = (struct userdata *) _u); 199353a5a1b3Sopenharmony_ci pa_assert(conn); 199453a5a1b3Sopenharmony_ci pa_assert(msg); 199553a5a1b3Sopenharmony_ci 199653a5a1b3Sopenharmony_ci dbus_error_init(&error); 199753a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 199853a5a1b3Sopenharmony_ci DBUS_TYPE_UINT32, &channel, 199953a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 200053a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 200153a5a1b3Sopenharmony_ci dbus_error_free(&error); 200253a5a1b3Sopenharmony_ci return; 200353a5a1b3Sopenharmony_ci } 200453a5a1b3Sopenharmony_ci if (channel > u->channels) { 200553a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel); 200653a5a1b3Sopenharmony_ci dbus_error_free(&error); 200753a5a1b3Sopenharmony_ci return; 200853a5a1b3Sopenharmony_ci } 200953a5a1b3Sopenharmony_ci 201053a5a1b3Sopenharmony_ci n_coefs = CHANNEL_PROFILE_SIZE(u); 201153a5a1b3Sopenharmony_ci pa_assert(conn); 201253a5a1b3Sopenharmony_ci pa_assert(msg); 201353a5a1b3Sopenharmony_ci get_filter(u, channel, &H_, &preamp); 201453a5a1b3Sopenharmony_ci pa_assert_se((reply = dbus_message_new_method_return(msg))); 201553a5a1b3Sopenharmony_ci dbus_message_iter_init_append(reply, &msg_iter); 201653a5a1b3Sopenharmony_ci 201753a5a1b3Sopenharmony_ci pa_dbus_append_basic_array(&msg_iter, DBUS_TYPE_DOUBLE, H_, n_coefs); 201853a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_DOUBLE, &preamp); 201953a5a1b3Sopenharmony_ci 202053a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_send(conn, reply, NULL)); 202153a5a1b3Sopenharmony_ci dbus_message_unref(reply); 202253a5a1b3Sopenharmony_ci pa_xfree(H_); 202353a5a1b3Sopenharmony_ci} 202453a5a1b3Sopenharmony_ci 202553a5a1b3Sopenharmony_cistatic void set_filter(struct userdata *u, size_t channel, double *H_, double preamp) { 202653a5a1b3Sopenharmony_ci unsigned a_i; 202753a5a1b3Sopenharmony_ci size_t r_channel = channel == u->channels ? 0 : channel; 202853a5a1b3Sopenharmony_ci float *H; 202953a5a1b3Sopenharmony_ci //all channels 203053a5a1b3Sopenharmony_ci a_i = pa_aupdate_write_begin(u->a_H[r_channel]); 203153a5a1b3Sopenharmony_ci u->Xs[r_channel][a_i] = (float) preamp; 203253a5a1b3Sopenharmony_ci H = u->Hs[r_channel][a_i]; 203353a5a1b3Sopenharmony_ci for(size_t i = 0; i < FILTER_SIZE(u); ++i) { 203453a5a1b3Sopenharmony_ci H[i] = (float) H_[i]; 203553a5a1b3Sopenharmony_ci } 203653a5a1b3Sopenharmony_ci fix_filter(H, u->fft_size); 203753a5a1b3Sopenharmony_ci if (channel == u->channels) { 203853a5a1b3Sopenharmony_ci for(size_t c = 1; c < u->channels; ++c) { 203953a5a1b3Sopenharmony_ci unsigned b_i = pa_aupdate_write_begin(u->a_H[c]); 204053a5a1b3Sopenharmony_ci u->Xs[c][b_i] = u->Xs[r_channel][a_i]; 204153a5a1b3Sopenharmony_ci memcpy(u->Hs[c][b_i], u->Hs[r_channel][a_i], FILTER_SIZE(u) * sizeof(float)); 204253a5a1b3Sopenharmony_ci pa_aupdate_write_end(u->a_H[c]); 204353a5a1b3Sopenharmony_ci } 204453a5a1b3Sopenharmony_ci } 204553a5a1b3Sopenharmony_ci pa_aupdate_write_end(u->a_H[r_channel]); 204653a5a1b3Sopenharmony_ci} 204753a5a1b3Sopenharmony_ci 204853a5a1b3Sopenharmony_civoid equalizer_handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *_u) { 204953a5a1b3Sopenharmony_ci struct userdata *u; 205053a5a1b3Sopenharmony_ci double *H, preamp; 205153a5a1b3Sopenharmony_ci uint32_t channel; 205253a5a1b3Sopenharmony_ci unsigned _n_coefs; 205353a5a1b3Sopenharmony_ci DBusMessage *message = NULL; 205453a5a1b3Sopenharmony_ci DBusError error; 205553a5a1b3Sopenharmony_ci pa_assert_se(u = (struct userdata *) _u); 205653a5a1b3Sopenharmony_ci pa_assert(conn); 205753a5a1b3Sopenharmony_ci pa_assert(msg); 205853a5a1b3Sopenharmony_ci 205953a5a1b3Sopenharmony_ci dbus_error_init(&error); 206053a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 206153a5a1b3Sopenharmony_ci DBUS_TYPE_UINT32, &channel, 206253a5a1b3Sopenharmony_ci DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &H, &_n_coefs, 206353a5a1b3Sopenharmony_ci DBUS_TYPE_DOUBLE, &preamp, 206453a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 206553a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 206653a5a1b3Sopenharmony_ci dbus_error_free(&error); 206753a5a1b3Sopenharmony_ci return; 206853a5a1b3Sopenharmony_ci } 206953a5a1b3Sopenharmony_ci if (channel > u->channels) { 207053a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel); 207153a5a1b3Sopenharmony_ci dbus_error_free(&error); 207253a5a1b3Sopenharmony_ci return; 207353a5a1b3Sopenharmony_ci } 207453a5a1b3Sopenharmony_ci if (_n_coefs != FILTER_SIZE(u)) { 207553a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "This filter takes exactly %zd coefficients, you gave %d", FILTER_SIZE(u), _n_coefs); 207653a5a1b3Sopenharmony_ci return; 207753a5a1b3Sopenharmony_ci } 207853a5a1b3Sopenharmony_ci set_filter(u, channel, H, preamp); 207953a5a1b3Sopenharmony_ci 208053a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 208153a5a1b3Sopenharmony_ci 208253a5a1b3Sopenharmony_ci pa_assert_se((message = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name))); 208353a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(u->dbus_protocol, message); 208453a5a1b3Sopenharmony_ci dbus_message_unref(message); 208553a5a1b3Sopenharmony_ci} 208653a5a1b3Sopenharmony_ci 208753a5a1b3Sopenharmony_civoid equalizer_handle_save_profile(DBusConnection *conn, DBusMessage *msg, void *_u) { 208853a5a1b3Sopenharmony_ci struct userdata *u = (struct userdata *) _u; 208953a5a1b3Sopenharmony_ci char *name; 209053a5a1b3Sopenharmony_ci uint32_t channel, r_channel; 209153a5a1b3Sopenharmony_ci DBusMessage *message = NULL; 209253a5a1b3Sopenharmony_ci DBusError error; 209353a5a1b3Sopenharmony_ci pa_assert(conn); 209453a5a1b3Sopenharmony_ci pa_assert(msg); 209553a5a1b3Sopenharmony_ci pa_assert(u); 209653a5a1b3Sopenharmony_ci dbus_error_init(&error); 209753a5a1b3Sopenharmony_ci 209853a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 209953a5a1b3Sopenharmony_ci DBUS_TYPE_UINT32, &channel, 210053a5a1b3Sopenharmony_ci DBUS_TYPE_STRING, &name, 210153a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 210253a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 210353a5a1b3Sopenharmony_ci dbus_error_free(&error); 210453a5a1b3Sopenharmony_ci return; 210553a5a1b3Sopenharmony_ci } 210653a5a1b3Sopenharmony_ci if (channel > u->channels) { 210753a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel); 210853a5a1b3Sopenharmony_ci dbus_error_free(&error); 210953a5a1b3Sopenharmony_ci return; 211053a5a1b3Sopenharmony_ci } 211153a5a1b3Sopenharmony_ci r_channel = channel == u->channels ? 0 : channel; 211253a5a1b3Sopenharmony_ci save_profile(u, r_channel, name); 211353a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 211453a5a1b3Sopenharmony_ci 211553a5a1b3Sopenharmony_ci pa_assert_se((message = dbus_message_new_signal(MANAGER_PATH, MANAGER_IFACE, manager_signals[MANAGER_SIGNAL_PROFILES_CHANGED].name))); 211653a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(u->dbus_protocol, message); 211753a5a1b3Sopenharmony_ci dbus_message_unref(message); 211853a5a1b3Sopenharmony_ci} 211953a5a1b3Sopenharmony_ci 212053a5a1b3Sopenharmony_civoid equalizer_handle_load_profile(DBusConnection *conn, DBusMessage *msg, void *_u) { 212153a5a1b3Sopenharmony_ci struct userdata *u = (struct userdata *) _u; 212253a5a1b3Sopenharmony_ci char *name; 212353a5a1b3Sopenharmony_ci DBusError error; 212453a5a1b3Sopenharmony_ci uint32_t channel, r_channel; 212553a5a1b3Sopenharmony_ci const char *err_msg = NULL; 212653a5a1b3Sopenharmony_ci DBusMessage *message = NULL; 212753a5a1b3Sopenharmony_ci 212853a5a1b3Sopenharmony_ci pa_assert(conn); 212953a5a1b3Sopenharmony_ci pa_assert(msg); 213053a5a1b3Sopenharmony_ci pa_assert(u); 213153a5a1b3Sopenharmony_ci dbus_error_init(&error); 213253a5a1b3Sopenharmony_ci 213353a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 213453a5a1b3Sopenharmony_ci DBUS_TYPE_UINT32, &channel, 213553a5a1b3Sopenharmony_ci DBUS_TYPE_STRING, &name, 213653a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 213753a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 213853a5a1b3Sopenharmony_ci dbus_error_free(&error); 213953a5a1b3Sopenharmony_ci return; 214053a5a1b3Sopenharmony_ci } 214153a5a1b3Sopenharmony_ci if (channel > u->channels) { 214253a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel); 214353a5a1b3Sopenharmony_ci dbus_error_free(&error); 214453a5a1b3Sopenharmony_ci return; 214553a5a1b3Sopenharmony_ci } 214653a5a1b3Sopenharmony_ci r_channel = channel == u->channels ? 0 : channel; 214753a5a1b3Sopenharmony_ci 214853a5a1b3Sopenharmony_ci err_msg = load_profile(u, r_channel, name); 214953a5a1b3Sopenharmony_ci if (err_msg != NULL) { 215053a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "error loading profile %s: %s", name, err_msg); 215153a5a1b3Sopenharmony_ci dbus_error_free(&error); 215253a5a1b3Sopenharmony_ci return; 215353a5a1b3Sopenharmony_ci } 215453a5a1b3Sopenharmony_ci if (channel == u->channels) { 215553a5a1b3Sopenharmony_ci for(uint32_t c = 1; c < u->channels; ++c) { 215653a5a1b3Sopenharmony_ci load_profile(u, c, name); 215753a5a1b3Sopenharmony_ci } 215853a5a1b3Sopenharmony_ci } 215953a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 216053a5a1b3Sopenharmony_ci 216153a5a1b3Sopenharmony_ci pa_assert_se((message = dbus_message_new_signal(u->dbus_path, EQUALIZER_IFACE, equalizer_signals[EQUALIZER_SIGNAL_FILTER_CHANGED].name))); 216253a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(u->dbus_protocol, message); 216353a5a1b3Sopenharmony_ci dbus_message_unref(message); 216453a5a1b3Sopenharmony_ci} 216553a5a1b3Sopenharmony_ci 216653a5a1b3Sopenharmony_civoid equalizer_handle_save_state(DBusConnection *conn, DBusMessage *msg, void *_u) { 216753a5a1b3Sopenharmony_ci struct userdata *u = (struct userdata *) _u; 216853a5a1b3Sopenharmony_ci pa_assert(conn); 216953a5a1b3Sopenharmony_ci pa_assert(msg); 217053a5a1b3Sopenharmony_ci pa_assert(u); 217153a5a1b3Sopenharmony_ci 217253a5a1b3Sopenharmony_ci save_state(u); 217353a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 217453a5a1b3Sopenharmony_ci} 217553a5a1b3Sopenharmony_ci 217653a5a1b3Sopenharmony_civoid equalizer_handle_get_profile_name(DBusConnection *conn, DBusMessage *msg, void *_u) { 217753a5a1b3Sopenharmony_ci struct userdata *u = (struct userdata *) _u; 217853a5a1b3Sopenharmony_ci DBusError error; 217953a5a1b3Sopenharmony_ci uint32_t channel, r_channel; 218053a5a1b3Sopenharmony_ci 218153a5a1b3Sopenharmony_ci pa_assert(conn); 218253a5a1b3Sopenharmony_ci pa_assert(msg); 218353a5a1b3Sopenharmony_ci pa_assert(u); 218453a5a1b3Sopenharmony_ci dbus_error_init(&error); 218553a5a1b3Sopenharmony_ci 218653a5a1b3Sopenharmony_ci if (!dbus_message_get_args(msg, &error, 218753a5a1b3Sopenharmony_ci DBUS_TYPE_UINT32, &channel, 218853a5a1b3Sopenharmony_ci DBUS_TYPE_INVALID)) { 218953a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); 219053a5a1b3Sopenharmony_ci dbus_error_free(&error); 219153a5a1b3Sopenharmony_ci return; 219253a5a1b3Sopenharmony_ci } 219353a5a1b3Sopenharmony_ci if (channel > u->channels) { 219453a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "invalid channel: %d", channel); 219553a5a1b3Sopenharmony_ci dbus_error_free(&error); 219653a5a1b3Sopenharmony_ci return; 219753a5a1b3Sopenharmony_ci } 219853a5a1b3Sopenharmony_ci r_channel = channel == u->channels ? 0 : channel; 219953a5a1b3Sopenharmony_ci pa_assert(u->base_profiles[r_channel]); 220053a5a1b3Sopenharmony_ci pa_dbus_send_basic_value_reply(conn,msg, DBUS_TYPE_STRING, &u->base_profiles[r_channel]); 220153a5a1b3Sopenharmony_ci} 220253a5a1b3Sopenharmony_ci 220353a5a1b3Sopenharmony_civoid equalizer_get_revision(DBusConnection *conn, DBusMessage *msg, void *_u) { 220453a5a1b3Sopenharmony_ci uint32_t rev=1; 220553a5a1b3Sopenharmony_ci pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &rev); 220653a5a1b3Sopenharmony_ci} 220753a5a1b3Sopenharmony_ci 220853a5a1b3Sopenharmony_civoid equalizer_get_n_channels(DBusConnection *conn, DBusMessage *msg, void *_u) { 220953a5a1b3Sopenharmony_ci struct userdata *u; 221053a5a1b3Sopenharmony_ci uint32_t channels; 221153a5a1b3Sopenharmony_ci pa_assert_se(u = (struct userdata *) _u); 221253a5a1b3Sopenharmony_ci pa_assert(conn); 221353a5a1b3Sopenharmony_ci pa_assert(msg); 221453a5a1b3Sopenharmony_ci 221553a5a1b3Sopenharmony_ci channels = (uint32_t) u->channels; 221653a5a1b3Sopenharmony_ci pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &channels); 221753a5a1b3Sopenharmony_ci} 221853a5a1b3Sopenharmony_ci 221953a5a1b3Sopenharmony_civoid equalizer_get_n_coefs(DBusConnection *conn, DBusMessage *msg, void *_u) { 222053a5a1b3Sopenharmony_ci struct userdata *u; 222153a5a1b3Sopenharmony_ci uint32_t n_coefs; 222253a5a1b3Sopenharmony_ci pa_assert_se(u = (struct userdata *) _u); 222353a5a1b3Sopenharmony_ci pa_assert(conn); 222453a5a1b3Sopenharmony_ci pa_assert(msg); 222553a5a1b3Sopenharmony_ci 222653a5a1b3Sopenharmony_ci n_coefs = (uint32_t) CHANNEL_PROFILE_SIZE(u); 222753a5a1b3Sopenharmony_ci pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &n_coefs); 222853a5a1b3Sopenharmony_ci} 222953a5a1b3Sopenharmony_ci 223053a5a1b3Sopenharmony_civoid equalizer_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *_u) { 223153a5a1b3Sopenharmony_ci struct userdata *u; 223253a5a1b3Sopenharmony_ci uint32_t rate; 223353a5a1b3Sopenharmony_ci pa_assert_se(u = (struct userdata *) _u); 223453a5a1b3Sopenharmony_ci pa_assert(conn); 223553a5a1b3Sopenharmony_ci pa_assert(msg); 223653a5a1b3Sopenharmony_ci 223753a5a1b3Sopenharmony_ci rate = (uint32_t) u->sink->sample_spec.rate; 223853a5a1b3Sopenharmony_ci pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &rate); 223953a5a1b3Sopenharmony_ci} 224053a5a1b3Sopenharmony_ci 224153a5a1b3Sopenharmony_civoid equalizer_get_filter_rate(DBusConnection *conn, DBusMessage *msg, void *_u) { 224253a5a1b3Sopenharmony_ci struct userdata *u; 224353a5a1b3Sopenharmony_ci uint32_t fft_size; 224453a5a1b3Sopenharmony_ci pa_assert_se(u = (struct userdata *) _u); 224553a5a1b3Sopenharmony_ci pa_assert(conn); 224653a5a1b3Sopenharmony_ci pa_assert(msg); 224753a5a1b3Sopenharmony_ci 224853a5a1b3Sopenharmony_ci fft_size = (uint32_t) u->fft_size; 224953a5a1b3Sopenharmony_ci pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &fft_size); 225053a5a1b3Sopenharmony_ci} 225153a5a1b3Sopenharmony_ci 225253a5a1b3Sopenharmony_civoid equalizer_get_all(DBusConnection *conn, DBusMessage *msg, void *_u) { 225353a5a1b3Sopenharmony_ci struct userdata *u; 225453a5a1b3Sopenharmony_ci DBusMessage *reply = NULL; 225553a5a1b3Sopenharmony_ci DBusMessageIter msg_iter, dict_iter; 225653a5a1b3Sopenharmony_ci uint32_t rev, n_coefs, rate, fft_size, channels; 225753a5a1b3Sopenharmony_ci 225853a5a1b3Sopenharmony_ci pa_assert_se(u = _u); 225953a5a1b3Sopenharmony_ci pa_assert(msg); 226053a5a1b3Sopenharmony_ci 226153a5a1b3Sopenharmony_ci rev = 1; 226253a5a1b3Sopenharmony_ci n_coefs = (uint32_t) CHANNEL_PROFILE_SIZE(u); 226353a5a1b3Sopenharmony_ci rate = (uint32_t) u->sink->sample_spec.rate; 226453a5a1b3Sopenharmony_ci fft_size = (uint32_t) u->fft_size; 226553a5a1b3Sopenharmony_ci channels = (uint32_t) u->channels; 226653a5a1b3Sopenharmony_ci 226753a5a1b3Sopenharmony_ci pa_assert_se((reply = dbus_message_new_method_return(msg))); 226853a5a1b3Sopenharmony_ci dbus_message_iter_init_append(reply, &msg_iter); 226953a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 227053a5a1b3Sopenharmony_ci 227153a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_REVISION].property_name, DBUS_TYPE_UINT32, &rev); 227253a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_SAMPLERATE].property_name, DBUS_TYPE_UINT32, &rate); 227353a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_FILTERSAMPLERATE].property_name, DBUS_TYPE_UINT32, &fft_size); 227453a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_N_COEFS].property_name, DBUS_TYPE_UINT32, &n_coefs); 227553a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, equalizer_handlers[EQUALIZER_HANDLER_N_CHANNELS].property_name, DBUS_TYPE_UINT32, &channels); 227653a5a1b3Sopenharmony_ci 227753a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 227853a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_send(conn, reply, NULL)); 227953a5a1b3Sopenharmony_ci dbus_message_unref(reply); 228053a5a1b3Sopenharmony_ci} 2281