Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
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;
}
Пример #5
0
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;
}
Пример #6
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;
}
Пример #7
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;
}
Пример #8
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;
}
Пример #9
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;
}
Пример #10
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;
}
Пример #11
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;
}
Пример #12
0
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;
}
Пример #13
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;
}
Пример #14
0
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;
}
Пример #15
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;
}