static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { #ifdef HAVE_SYS_RESOURCE_H struct pa_rlimit *r = data; pa_assert(filename); pa_assert(lvalue); pa_assert(rvalue); pa_assert(r); if (rvalue[strspn(rvalue, "\t ")] == 0) { /* Empty string */ r->is_set = 0; r->value = 0; } else { int32_t k; if (pa_atoi(rvalue, &k) < 0) { pa_log(_("[%s:%u] Invalid rlimit '%s'."), filename, line, rvalue); return -1; } r->is_set = k >= 0; r->value = k >= 0 ? (rlim_t) k : 0; } #else pa_log_warn(_("[%s:%u] rlimit not supported on this platform."), filename, line); #endif return 0; }
static int parse_rtprio(pa_config_parser_state *state) { #if !defined(OS_IS_WIN32) && defined(HAVE_SCHED_H) pa_daemon_conf *c; int32_t rtprio; #endif pa_assert(state); #ifdef OS_IS_WIN32 pa_log("[%s:%u] Realtime priority not available on win32.", state->filename, state->lineno); #else # ifdef HAVE_SCHED_H c = state->data; if (pa_atoi(state->rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) { pa_log("[%s:%u] Invalid realtime priority '%s'.", state->filename, state->lineno, state->rvalue); return -1; } c->realtime_priority = (int) rtprio; # endif #endif /* OS_IS_WIN32 */ return 0; }
int mv_parse_single_steps(struct mv_volume_steps *steps, const char *step_string) { int len; int count = 0; int i = 0; pa_assert(steps); if (!step_string) return 0; len = strlen(step_string); while (i < len && count < MAX_STEPS) { char step[16]; int value; size_t start, value_len; /* search for next step:value separator */ for (; i < len && step_string[i] != ':'; i++); /* invalid syntax in step string, bail out */ if (i == len) return -1; /* increment i by one to get to the start of value */ i++; /* search for next step:value pair separator to determine value string length */ start = i; for (; i < len && step_string[i] != ','; i++); value_len = i - start; if (value_len < 1 || value_len > sizeof(step)-1) return -1; /* copy value string part to step string and convert to integer */ memcpy(step, &step_string[start], value_len); step[value_len] = '\0'; if (pa_atoi(step, &value)) { return -1; } steps->step[count] = value; count++; } steps->n_steps = count; steps->current_step = 0; return count; }
static pa_hook_result_t device_new_hook_cb(pa_core *c, pa_object *o, struct userdata *u) { struct device_info *d; pa_source *source; pa_sink *sink; const char *timeout_str; int32_t timeout; bool timeout_valid; pa_assert(c); pa_object_assert_ref(o); pa_assert(u); source = pa_source_isinstance(o) ? PA_SOURCE(o) : NULL; sink = pa_sink_isinstance(o) ? PA_SINK(o) : NULL; /* Never suspend monitors */ if (source && source->monitor_of) return PA_HOOK_OK; pa_assert(source || sink); timeout_str = pa_proplist_gets(sink ? sink->proplist : source->proplist, "module-suspend-on-idle.timeout"); if (timeout_str && pa_atoi(timeout_str, &timeout) >= 0) timeout_valid = true; else timeout_valid = false; if (timeout_valid && timeout < 0) return PA_HOOK_OK; d = pa_xnew(struct device_info, 1); d->userdata = u; d->source = source ? pa_source_ref(source) : NULL; d->sink = sink ? pa_sink_ref(sink) : NULL; d->time_event = pa_core_rttime_new(c, PA_USEC_INVALID, timeout_cb, d); if (timeout_valid) d->timeout = timeout * PA_USEC_PER_SEC; else d->timeout = d->userdata->timeout; pa_hashmap_put(u->device_infos, o, d); if ((d->sink && pa_sink_check_suspend(d->sink) <= 0) || (d->source && pa_source_check_suspend(d->source) <= 0)) restart(d); return PA_HOOK_OK; }
static int parse_nice_level(pa_config_parser_state *state) { pa_daemon_conf *c; int32_t level; pa_assert(state); c = state->data; if (pa_atoi(state->rvalue, &level) < 0 || level < -20 || level > 19) { pa_log(_("[%s:%u] Invalid nice level '%s'."), state->filename, state->lineno, state->rvalue); return -1; } c->nice_level = (int) level; return 0; }
static int parse_fragment_size_msec(pa_config_parser_state *state) { pa_daemon_conf *c; int32_t n; pa_assert(state); c = state->data; if (pa_atoi(state->rvalue, &n) < 0 || n < 1) { pa_log(_("[%s:%u] Invalid fragment size '%s'."), state->filename, state->lineno, state->rvalue); return -1; } c->default_fragment_size_msec = (unsigned) n; return 0; }
static int parse_sample_channels(pa_config_parser_state *state) { struct channel_conf_info *i; int32_t n; pa_assert(state); i = state->data; if (pa_atoi(state->rvalue, &n) < 0 || !pa_channels_valid(n)) { pa_log(_("[%s:%u] Invalid sample channels '%s'."), state->filename, state->lineno, state->rvalue); return -1; } i->conf->default_sample_spec.channels = (uint8_t) n; i->default_sample_spec_set = true; return 0; }
static int parse_rtprio(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { pa_daemon_conf *c = data; int32_t rtprio; pa_assert(filename); pa_assert(lvalue); pa_assert(rvalue); pa_assert(data); if (pa_atoi(rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) { pa_log("[%s:%u] Invalid realtime priority '%s'.", filename, line, rvalue); return -1; } c->realtime_priority = (int) rtprio; return 0; }
static int parse_nice_level(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { pa_daemon_conf *c = data; int32_t level; pa_assert(filename); pa_assert(lvalue); pa_assert(rvalue); pa_assert(data); if (pa_atoi(rvalue, &level) < 0 || level < -20 || level > 19) { pa_log(_("[%s:%u] Invalid nice level '%s'."), filename, line, rvalue); return -1; } c->nice_level = (int) level; return 0; }
static int parse_fragment_size_msec(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { pa_daemon_conf *c = data; int32_t n; pa_assert(filename); pa_assert(lvalue); pa_assert(rvalue); pa_assert(data); if (pa_atoi(rvalue, &n) < 0 || n < 1) { pa_log(_("[%s:%u] Invalid fragment size '%s'."), filename, line, rvalue); return -1; } c->default_fragment_size_msec = (unsigned) n; return 0; }
int voice_parse_aep_steps(struct userdata *u, const char *steps) { char *token; const char *state; int i = -1; int32_t step; int32_t old = 0; for (token = pa_split(steps, ",", &state); token; i ++) { if (i > (int)ARRAY_SIZE(u->aep_volume_steps.steps) - 1) { pa_log_error("Too many elements in aep volume steps table: %d > %d", i + 1, ARRAY_SIZE(u->aep_volume_steps.steps)); pa_xfree(token); goto error; } if (pa_atoi(token, &step)) { pa_xfree(token); goto error; } if (i < 0) old = step; else u->aep_volume_steps.steps[i] = (old + step) / 2; pa_xfree(token); } u->aep_volume_steps.count = i; pa_log_info("AEP volume steps table read, %d steps found", i + 1); return 0; error: pa_log_error("Error near token '%s' when parsing parameter %s: %s", token, PA_NOKIA_PROP_AUDIO_AEP_mB_STEPS, steps); u->aep_volume_steps.count = 0; return -1; }
static int parse_sample_channels(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { struct channel_conf_info *i = data; int32_t n; pa_assert(filename); pa_assert(lvalue); pa_assert(rvalue); pa_assert(data); if (pa_atoi(rvalue, &n) < 0 || n > (int32_t) PA_CHANNELS_MAX || n <= 0) { pa_log(_("[%s:%u] Invalid sample channels '%s'."), filename, line, rvalue); return -1; } i->conf->default_sample_spec.channels = (uint8_t) n; i->default_sample_spec_set = TRUE; return 0; }
bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln, const char *str, bool legacy, uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]) { pa_assert(fn); pa_assert(str); char *entry; const char *state = NULL; uint32_t pos = 0; while ((entry = pa_split(str, value_separator(legacy), &state))) { int32_t val; #if AUDIO_API_VERSION_MAJ >= 3 if (pos == 0 && pa_streq(entry, "dynamic")) { sampling_rates[pos++] = (uint32_t) -1; pa_xfree(entry); break; } #endif if (pos == AUDIO_MAX_SAMPLING_RATES) { pa_log("[%s:%u] Too many sample rate entries (> %d)", fn, ln, AUDIO_MAX_SAMPLING_RATES); pa_xfree(entry); return false; } if (pa_atoi(entry, &val) < 0) { pa_log("[%s:%u] Bad sample rate value %s", fn, ln, entry); pa_xfree(entry); return false; } sampling_rates[pos++] = val; pa_xfree(entry); } sampling_rates[pos] = 0; return true; }
static int parse_rlimit(pa_config_parser_state *state) { struct pa_rlimit *r; pa_assert(state); r = state->data; if (state->rvalue[strspn(state->rvalue, "\t ")] == 0) { /* Empty string */ r->is_set = 0; r->value = 0; } else { int32_t k; if (pa_atoi(state->rvalue, &k) < 0) { pa_log(_("[%s:%u] Invalid rlimit '%s'."), state->filename, state->lineno, state->rvalue); return -1; } r->is_set = k >= 0; r->value = k >= 0 ? (rlim_t) k : 0; } return 0; }
void voice_update_parameters(struct userdata *u) { pa_sink *sink; const char *s; double tmp_d, old_d; int tmp, old; size_t nbytes; const void *data; ENTER(); sink = voice_get_original_master_sink(u); if (!sink) { pa_log_warn("Original master sink not found, parameters not updated."); return; } u->updating_parameters = TRUE; if (!pa_proplist_get(sink->proplist, "x-maemo.xprot.parameters.left", &data, &nbytes)) xprot_change_params(u->xprot, data, nbytes, 0); if (!pa_proplist_get(sink->proplist,"x-maemo.xprot.parameters.right", &data, &nbytes)) xprot_change_params(u->xprot, data, nbytes, 1); s = voice_pa_proplist_gets(sink->proplist, "x-maemo.cmt.ul_timing_advance"); old = u->ul_timing_advance; if (!pa_atoi(s, &tmp) && tmp > -5000 && tmp < 5000) u->ul_timing_advance = tmp; pa_log_debug("cmt_ul_timing_advance \"%s\" %d %d", s, u->ul_timing_advance, old); s = voice_pa_proplist_gets(sink->proplist, "x-maemo.alt_mixer_compensation"); /* CHECKME */ old_d = u->alt_mixer_compensation; if (!pa_atod(s, &tmp_d) && tmp_d > 0.0 && tmp_d <= 60.0) /* < 60.0 ? */ u->alt_mixer_compensation = pa_sw_volume_from_dB(tmp_d); pa_log_debug("alt_mixer_compensation \"%s\" %d %f", s, u->alt_mixer_compensation, old_d); s = voice_pa_proplist_gets(sink->proplist, "x-maemo.ear_ref_padding"); old = u->ear_ref.loop_padding_usec ; if (!pa_atoi(s, &tmp) && tmp > -10000 && tmp < 199999) u->ear_ref.loop_padding_usec = tmp; pa_log_debug("ear_ref_padding \"%s\" %d %d", s, u->ear_ref.loop_padding_usec, old); voice_parse_aep_steps(u, voice_pa_proplist_gets(sink->proplist, "x-maemo.audio_aep_mb_steps")); s = voice_pa_proplist_gets(sink->proplist, "x-maemo.nrec"); u->nrec_enable = pa_parse_boolean(s); if (u->master_source && pa_proplist_gets(u->master_source->proplist, "bluetooth.nrec")) { /* WTF ?!? */ u->sidetone_enable = pa_parse_boolean(s) && u->nrec_enable; } if (!pa_proplist_get(sink->proplist, "x-maemo.aep.switches", (const void **)&data, &nbytes) ) { uint16_t *as = (uint16_t *)data; aep_switches.field_0 = as[0]; aep_switches.field_2 = as[1]; aep_switches.field_4 = 0; if ( aep_switches.field_0 & 0x400 ) aep_switches.field_4 = 0x30; if (aep_switches.field_0 & 1) aep_switches.field_4 |= 0x300u; aep_switches.field_4 |= 0x1800u; } if (!pa_proplist_get(sink->proplist, "x-maemo.aep.parameters", &data, &nbytes)) { const char *argv[7] = { "../execute/d4gnt560", "b-ai-1n------0---u", "/dev/null", "/dev/null", "/dev/null", "/dev/null", "/dev/null", }; if (strlen(aep_runtime_switch) >= strlen(argv[1])) argv[1] = aep_runtime_switch; fprintf(stderr, "AEP runtime switch %s\n", argv[1]); current_aep_tuning = (void *)data; init_main(7, argv); voice_aep_ear_ref_loop_reset(u); } sidetone_write_parameters(u); if (!pa_proplist_get(sink->proplist, "x-maemo.wb_meq.parameters", &data, &nbytes)) iir_eq_change_params(u->wb_mic_iir_eq, data, nbytes); if (!pa_proplist_get(sink->proplist, "x-maemo.nb_meq.parameters", &data, &nbytes) ) iir_eq_change_params(u->nb_mic_iir_eq, data, nbytes); if (!pa_proplist_get(sink->proplist,"x-maemo.wb_eeq.parameters", &data, &nbytes)) fir_eq_change_params(u->wb_ear_iir_eq, data, nbytes); if (!pa_proplist_get(sink->proplist, "x-maemo.nb_eeq.parameters", &data, &nbytes)) iir_eq_change_params(u->nb_ear_iir_eq, data, nbytes); u->aep_enable = voice_pa_proplist_get_bool(sink->proplist, "x-maemo.aep"); u->wb_meq_enable = voice_pa_proplist_get_bool(sink->proplist, "x-maemo.wb_meq"); u->wb_eeq_enable = voice_pa_proplist_get_bool(sink->proplist, "x-maemo.wb_eeq"); u->nb_meq_enable = voice_pa_proplist_get_bool(sink->proplist, "x-maemo.nb_meq"); u->nb_eeq_enable = voice_pa_proplist_get_bool(sink->proplist, "x-maemo.nb_eeq"); u->xprot->displ_limit = voice_pa_proplist_get_bool(sink->proplist, "x-maemo.xprot.displacement"); u->xprot->temp_limit = voice_pa_proplist_get_bool(sink->proplist, "x-maemo.xprot.temperature"); u->xprot_enable = u->xprot->displ_limit || u->xprot->temp_limit; u->updating_parameters = FALSE; }
int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u; const char *master_sink_name; const char *master_source_name; const char *raw_sink_name; const char *raw_source_name; const char *voice_sink_name; const char *voice_source_name; const char *max_hw_frag_size_str; int max_hw_frag_size = 3840; pa_sink *master_sink; pa_source *master_source; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; } master_sink_name = pa_modargs_get_value(ma, "master_sink", NULL); master_source_name = pa_modargs_get_value(ma, "master_source", NULL); raw_sink_name = pa_modargs_get_value(ma, "raw_sink_name", "sink.voice.raw"); raw_source_name = pa_modargs_get_value(ma, "raw_source_name", "source.voice.raw"); voice_sink_name = pa_modargs_get_value(ma, "voice_sink_name", "sink.voice"); voice_source_name = pa_modargs_get_value(ma, "voice_source_name", "source.voice"); max_hw_frag_size_str = pa_modargs_get_value(ma, "max_hw_frag_size", "3840"); pa_log_debug("Got arguments: master_sink=\"%s\" master_source=\"%s\" " "raw_sink_name=\"%s\" raw_source_name=\"%s\" max_hw_frag_size=\"%s\".", master_sink_name, master_source_name, raw_sink_name, raw_source_name, max_hw_frag_size_str); if (!(master_sink = pa_namereg_get(m->core, master_sink_name, PA_NAMEREG_SINK))) { pa_log("Master sink \"%s\" not found", master_sink_name); goto fail; } if (!(master_source = pa_namereg_get(m->core, master_source_name, PA_NAMEREG_SOURCE))) { pa_log("Master source \"%s\" not found", master_source_name); goto fail; } if (master_sink->sample_spec.format != master_source->sample_spec.format && master_sink->sample_spec.rate != master_source->sample_spec.rate && master_sink->sample_spec.channels != master_source->sample_spec.channels) { pa_log("Master source and sink must have same sample spec"); goto fail; } if (pa_atoi(max_hw_frag_size_str, &max_hw_frag_size) < 0 || max_hw_frag_size < 960 || max_hw_frag_size > 128*960) { pa_log("Bad value for max_hw_frag_size: %s", max_hw_frag_size_str); goto fail; } m->userdata = u = pa_xnew0(struct userdata, 1); u->modargs = ma; u->core = m->core; u->module = m; u->master_sink = master_sink; u->master_source = master_source; set_hooks(u); u->mainloop_handler = voice_mainloop_handler_new(u); u->ul_timing_advance = 500; // = 500 micro seconds, seems to be a good default value pa_channel_map_init_mono(&u->mono_map); pa_channel_map_init_stereo(&u->stereo_map); u->hw_sample_spec.format = PA_SAMPLE_S16NE; u->hw_sample_spec.rate = VOICE_SAMPLE_RATE_HW_HZ; u->hw_sample_spec.channels = 2; u->hw_mono_sample_spec.format = PA_SAMPLE_S16NE; u->hw_mono_sample_spec.rate = VOICE_SAMPLE_RATE_HW_HZ; u->hw_mono_sample_spec.channels = 1; u->aep_sample_spec.format = PA_SAMPLE_S16NE; u->aep_sample_spec.rate = VOICE_SAMPLE_RATE_AEP_HZ; u->aep_sample_spec.channels = 1; pa_channel_map_init_mono(&u->aep_channel_map); // The result is rounded down incorrectly thus +1 u->aep_fragment_size = pa_usec_to_bytes(VOICE_PERIOD_AEP_USECS+1, &u->aep_sample_spec); u->aep_hw_fragment_size = pa_usec_to_bytes(VOICE_PERIOD_AEP_USECS+1, &u->hw_sample_spec); u->hw_fragment_size = pa_usec_to_bytes(VOICE_PERIOD_MASTER_USECS+1, &u->hw_sample_spec); u->hw_fragment_size_max = max_hw_frag_size; if (0 != (u->hw_fragment_size_max % u->hw_fragment_size)) u->hw_fragment_size_max += u->hw_fragment_size - (u->hw_fragment_size_max % u->hw_fragment_size); u->aep_hw_mono_fragment_size = pa_usec_to_bytes(VOICE_PERIOD_AEP_USECS+1, &u->hw_mono_sample_spec); u->hw_mono_fragment_size = pa_usec_to_bytes(VOICE_PERIOD_MASTER_USECS+1, &u->hw_mono_sample_spec); u->voice_ul_fragment_size = pa_usec_to_bytes(VOICE_PERIOD_CMT_USECS+1, &u->aep_sample_spec); pa_silence_memchunk_get(&u->core->silence_cache, u->core->mempool, &u->aep_silence_memchunk, & u->aep_sample_spec, u->aep_fragment_size); voice_memchunk_pool_load(u); if (voice_init_raw_sink(u, raw_sink_name)) goto fail; u->call_state_tracker = pa_call_state_tracker_get(m->core); pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI); pa_call_state_tracker_set_active(u->call_state_tracker, FALSE); u->alt_mixer_compensation = PA_VOLUME_NORM; if (voice_init_hw_sink_input(u)) goto fail; /* This must be set before calling pa_sink_put(), because pa_sink_put() has * assertion * "!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || s->flat_sink_input". */ u->raw_sink->flat_sink_input = u->hw_sink_input; /* This must be called before calling voice_init_voip_sink(), because * pa_sink_input_new() has assertion * "PA_SINK_IS_LINKED(pa_sink_get_state(data->sink))". */ pa_sink_put(u->raw_sink); /* This must be called before calling voice_init_aep_sink_input(), because * the flat volume logic will otherwise mess up the aep sink input's volume * when pa_sink_input_put(u->hw_sink_input) is called. */ pa_sink_input_put(u->hw_sink_input); if (voice_init_voip_sink(u, voice_sink_name)) goto fail; if (voice_init_aep_sink_input(u)) goto fail; u->sink_temp_buff = pa_xmalloc(2*u->hw_fragment_size_max); u->sink_temp_buff_len = 2*u->hw_fragment_size_max; if (voice_init_raw_source(u, raw_source_name)) goto fail; pa_source_put(u->raw_source); if (voice_init_voip_source(u, voice_source_name)) goto fail; pa_source_put(u->voip_source); if (voice_init_hw_source_output(u)) goto fail; /* TODO: Guess we should use max_hw_frag_size here */ u->hw_source_memblockq = // 8 * 5ms = 40ms pa_memblockq_new(0, 2*u->hw_fragment_size_max, 0, pa_frame_size(&u->hw_sample_spec), 0, 0, 0, NULL); u->ul_memblockq = pa_memblockq_new(0, 2*u->voice_ul_fragment_size, 0, pa_frame_size(&u->aep_sample_spec), 0, 0, 0, NULL); u->dl_sideinfo_queue = pa_queue_new(); u->ul_deadline = 0; u->linear_q15_master_volume_L = INT16_MAX; u->linear_q15_master_volume_R = INT16_MAX; voice_aep_ear_ref_init(u); if (voice_convert_init(u)) goto fail; /* IHF mode is the default and this initialization is consistent with it. */ u->active_mic_channel = MIC_CH0; meego_parameter_request_updates("voice", (pa_hook_cb_t)voice_parameter_cb, PA_HOOK_NORMAL, FALSE, u); meego_parameter_request_updates("alsa", (pa_hook_cb_t)alsa_parameter_cb, PA_HOOK_NORMAL, FALSE, u); meego_parameter_request_updates("aep", (pa_hook_cb_t)aep_parameter_cb, PA_HOOK_LATE, FALSE, u); /* aep-s-i */ /* voip-sink ---\ hw-sink-input */ /* > optimized mix -------------> master-sink */ /* | */ /* raw-sink */ /* */ /* voip-src <--- hw-source-output */ /* < mux <------------- master-src */ /* raw-src <--- */ u->voip_sink->flat_sink_input = u->aep_sink_input; pa_sink_put(u->voip_sink); pa_source_output_put(u->hw_source_output); pa_sink_input_put(u->aep_sink_input); u->sink_subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SINK_INPUT, master_sink_volume_subscribe_cb, u); u->previous_master_source_state = pa_source_get_state(u->master_source); u->source_change_subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SOURCE, master_source_state_subscribe_cb, u); return 0; fail: pa__done(m); return -1; }
int pa__init(pa_module *m) { pa_modargs *ma; const char *master_sink_name; const char *master_source_name; const char *max_hw_frag_size_str; const char *aep_runtime; pa_source *master_source; struct userdata *u; pa_proplist *p; pa_sink *master_sink; const char *raw_sink_name; const char *raw_source_name; const char *voice_sink_name; const char *voice_source_name; const char *dbus_type; int max_hw_frag_size = 3840; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log_error("Failed to parse module arguments"); goto fail; } voice_turn_sidetone_down(); master_sink_name = pa_modargs_get_value(ma, "master_sink", NULL); master_source_name = pa_modargs_get_value(ma, "master_source", NULL); raw_sink_name = pa_modargs_get_value(ma, "raw_sink_name", "sink.voice.raw"); raw_source_name = pa_modargs_get_value(ma, "raw_source_name", "source.voice.raw"); voice_sink_name = pa_modargs_get_value(ma, "voice_sink_name", "sink.voice"); voice_source_name = pa_modargs_get_value(ma, "voice_source_name", "source.voice"); dbus_type = pa_modargs_get_value(ma, "dbus_type", "session"); max_hw_frag_size_str = pa_modargs_get_value(ma, "max_hw_frag_size", "3840"); aep_runtime = pa_modargs_get_value(ma, "aep_runtime", "bbaid1n-wr0-h9a22b--dbxpb--"); voice_set_aep_runtime_switch(aep_runtime); pa_log_debug("Got arguments: master_sink=\"%s\" master_source=\"%s\" raw_sink_name=\"%s\" raw_source_name=\"%s\" dbus_type=\"%s\" max_hw_frag_size=\"%s\". ", master_sink_name, master_source_name, raw_sink_name, raw_source_name, dbus_type, max_hw_frag_size_str); if (!(master_sink = pa_namereg_get(m->core, master_sink_name, PA_NAMEREG_SINK))) { pa_log("Master sink \"%s\" not found", master_sink_name); goto fail; } if (!(master_source = pa_namereg_get(m->core, master_source_name, PA_NAMEREG_SOURCE))) { pa_log( "Master source \"%s\" not found", master_source_name); goto fail; } if (master_sink->sample_spec.format != master_source->sample_spec.format && master_sink->sample_spec.rate != master_source->sample_spec.rate && master_sink->sample_spec.channels != master_source->sample_spec.channels) { pa_log("Master source and sink must have same sample spec"); goto fail; } if (pa_atoi(max_hw_frag_size_str, &max_hw_frag_size) < 0 || max_hw_frag_size < 960 || max_hw_frag_size > 128*960) { pa_log("Bad value for max_hw_frag_size: %s", max_hw_frag_size_str); goto fail; } m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; u->modargs = ma; u->master_sink = master_sink; u->master_source = master_source; u->mainloop_handler = voice_mainloop_handler_new(u);; u->ul_timing_advance = 500; // = 500 micro seconds, seems to be a good default value pa_channel_map_init_mono(&u->mono_map); pa_channel_map_init_stereo(&u->stereo_map); u->hw_sample_spec.format = PA_SAMPLE_S16NE; u->hw_sample_spec.rate = SAMPLE_RATE_HW_HZ; u->hw_sample_spec.channels = 2; u->hw_mono_sample_spec.format = PA_SAMPLE_S16NE; u->hw_mono_sample_spec.rate = SAMPLE_RATE_HW_HZ; u->hw_mono_sample_spec.channels = 1; u->aep_sample_spec.format = PA_SAMPLE_S16NE; u->aep_sample_spec.rate = SAMPLE_RATE_AEP_HZ; u->aep_sample_spec.channels = 1; pa_channel_map_init_mono(&u->aep_channel_map); // The result is rounded down incorrectly thus +1 u->aep_fragment_size = pa_usec_to_bytes(PERIOD_AEP_USECS+1, &u->aep_sample_spec); u->aep_hw_fragment_size = pa_usec_to_bytes(PERIOD_AEP_USECS+1, &u->hw_sample_spec); u->hw_fragment_size = pa_usec_to_bytes(PERIOD_MASTER_USECS+1, &u->hw_sample_spec); u->hw_fragment_size_max = max_hw_frag_size; if (0 != (u->hw_fragment_size_max % u->hw_fragment_size)) u->hw_fragment_size_max += u->hw_fragment_size - (u->hw_fragment_size_max % u->hw_fragment_size); u->aep_hw_mono_fragment_size = pa_usec_to_bytes(PERIOD_AEP_USECS+1, &u->hw_mono_sample_spec); u->hw_mono_fragment_size = pa_usec_to_bytes(PERIOD_MASTER_USECS+1, &u->hw_mono_sample_spec); u->voice_ul_fragment_size = pa_usec_to_bytes(PERIOD_CMT_USECS+1, &u->aep_sample_spec); pa_silence_memchunk_get(&u->core->silence_cache, u->core->mempool, &u->aep_silence_memchunk, &u->aep_sample_spec, u->aep_fragment_size); voice_memchunk_pool_load(u); if (voice_init_raw_sink(u, raw_sink_name)) goto fail; pa_sink_put(u->raw_sink); if (voice_init_voip_sink(u, voice_sink_name)) goto fail; pa_sink_put(u->voip_sink); if (voice_init_aep_sink_input(u)) goto fail; pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI); u->alt_mixer_compensation = PA_VOLUME_NORM; if (voice_init_hw_sink_input(u)) goto fail; u->sink_temp_buff = pa_xmalloc(2 * u->hw_fragment_size_max); u->sink_temp_buff_len = 2 * u->hw_fragment_size_max; u->dl_memblockq = pa_memblockq_new(0, 2 * u->voice_ul_fragment_size, 0, pa_frame_size(&u->aep_sample_spec), 0, 0, 0, NULL); if (voice_init_raw_source(u, raw_source_name)) goto fail; pa_source_put(u->raw_source); if (voice_init_voip_source(u, voice_source_name)) goto fail; pa_source_put(u->voip_source); if (voice_init_hw_source_output(u)) goto fail; u->hw_source_memblockq = pa_memblockq_new(0, 2 * u->hw_fragment_size_max, 0, pa_frame_size(&u->hw_sample_spec), 0, 0, 0, NULL); u->ul_memblockq = pa_memblockq_new(0, 2 * u->voice_ul_fragment_size, 0, pa_frame_size(&u->aep_sample_spec), 0, 0, 0, NULL); u->cs_call_sink_input = 0; u->dl_sideinfo_queue = pa_queue_new(); u->linear_q15_master_volume_L = INT16_MAX; u->linear_q15_master_volume_R = INT16_MAX; u->field_2CC = 0; voice_aep_ear_ref_init(u); if (voice_convert_init(u)) goto fail; if (voice_init_event_forwarder(u, dbus_type) || voice_init_cmtspeech(u)) goto fail; if (!(u->wb_mic_iir_eq = iir_eq_new(u->hw_fragment_size / 2, master_source->sample_spec.channels))) goto fail; if (!(u->nb_mic_iir_eq = iir_eq_new( u->aep_fragment_size / 2, 1))) goto fail; if (!(u->wb_ear_iir_eq = fir_eq_new(master_sink->sample_spec.rate, master_sink->sample_spec.channels))) goto fail; if (!(u->nb_ear_iir_eq = iir_eq_new(u->aep_fragment_size / 2, 1))) goto fail; u->input_task_active = FALSE; u->xprot_watchdog = TRUE; u->ambient_temp = 30; if (!(u->xprot = xprot_new())) goto fail; u->aep_enable = FALSE; u->wb_meq_enable = FALSE; u->wb_eeq_enable = FALSE; u->nb_meq_enable = FALSE; u->nb_eeq_enable = FALSE; u->xprot_enable = FALSE; u->updating_parameters = FALSE; u->sink_proplist_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], 0, (pa_hook_cb_t)sink_proplist_changed_cb, u);; u->source_proplist_changed_slot = pa_hook_connect( &m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], 0, (pa_hook_cb_t)source_proplist_changed_cb, u); u->mode_accessory_hwid_hash = 0; p = pa_proplist_new(); pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_MODE, "ihf"); pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_ACCESSORY_HWID, ""); pa_sink_update_proplist( master_sink, PA_UPDATE_REPLACE, p); pa_proplist_free(p); pa_source_output_put(u->hw_source_output); pa_sink_input_put(u->hw_sink_input); pa_sink_input_put(u->aep_sink_input); u->sink_subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK, sink_subscribe_cb, u); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; }