static void run_basic_tests(struct userdata *u) { /* Subscribe to updates. Note that "alg_b" wants full updates. */ meego_parameter_request_updates("alg_a", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, FALSE, &u->alg_a); meego_parameter_request_updates("alg_b", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, TRUE, &u->alg_b); meego_parameter_request_updates("alg_c", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, FALSE, &u->alg_c); disable_algs(u); /* Shuffle the modes around a bit to verify correct parameters and status enums */ switch_mode(u, "mode_a"); verify(&u->alg_a, "mode_a", "set_a1_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_a", "set_b1_parameters", MEEGO_PARAM_UPDATE); switch_mode(u, "mode_b"); verify(&u->alg_a, "mode_b", "set_a2_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_b", NULL, MEEGO_PARAM_MODE_CHANGE); switch_mode(u, "mode_c"); verify(&u->alg_a, "mode_c", "set_a3_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_c", "set_b2_parameters", MEEGO_PARAM_UPDATE); switch_mode(u, "mode_d"); verify(&u->alg_a, "mode_d", NULL, MEEGO_PARAM_DISABLE); verify(&u->alg_b, "mode_d", NULL, MEEGO_PARAM_DISABLE); verify(&u->alg_c, "mode_d", "set_c1_parameters", MEEGO_PARAM_UPDATE); switch_mode(u, "mode_c"); verify(&u->alg_a, "mode_c", NULL, MEEGO_PARAM_ENABLE); verify(&u->alg_b, "mode_c", NULL, MEEGO_PARAM_ENABLE); verify(&u->alg_c, "mode_c", NULL, MEEGO_PARAM_DISABLE); disable_algs(u); /* -> mode_reset2 */ /* Stop updates to verify that it's really working */ meego_parameter_stop_updates("alg_a", (pa_hook_cb_t)parameters_changed_cb, &u->alg_a); meego_parameter_stop_updates("alg_b", (pa_hook_cb_t)parameters_changed_cb, &u->alg_b); meego_parameter_stop_updates("alg_c", (pa_hook_cb_t)parameters_changed_cb, &u->alg_c); /* This mode switch should now have no effect */ switch_mode(u, "mode_a"); verify(&u->alg_a, "mode_reset2", NULL, MEEGO_PARAM_DISABLE); verify(&u->alg_b, "mode_reset2", NULL, MEEGO_PARAM_DISABLE); verify(&u->alg_c, "mode_reset2", NULL, MEEGO_PARAM_DISABLE); /* This should cause updates to mode_a */ meego_parameter_request_updates("alg_a", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, FALSE, &u->alg_a); meego_parameter_request_updates("alg_b", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, TRUE, &u->alg_b); meego_parameter_request_updates("alg_c", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, FALSE, &u->alg_c); verify(&u->alg_a, "mode_a", "set_a1_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_a", "set_b1_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_c, "mode_a", NULL, MEEGO_PARAM_DISABLE); meego_parameter_stop_updates("alg_a", (pa_hook_cb_t)parameters_changed_cb, &u->alg_a); meego_parameter_stop_updates("alg_b", (pa_hook_cb_t)parameters_changed_cb, &u->alg_b); meego_parameter_stop_updates("alg_c", (pa_hook_cb_t)parameters_changed_cb, &u->alg_c); disable_algs(u); }
static void run_modifier_tests(struct userdata *u) { meego_parameter_modifier modifier_a; meego_parameter_modifier modifier_b; meego_parameter_modifier modifier_c; modifier_a.mode_name = "mode_a"; modifier_a.algorithm_name = "alg_a"; modifier_a.get_parameters = get_parameters_cb; modifier_a.userdata = &u->alg_a; modifier_b.mode_name = "mode_b"; modifier_b.algorithm_name = "alg_b"; modifier_b.get_parameters = failing_get_parameters_cb; modifier_b.userdata = &u->alg_b; /* This modifier doesn't have base parameters in the file system */ modifier_c.mode_name = "mode_c"; modifier_c.algorithm_name = "alg_c"; modifier_c.get_parameters = get_parameters_cb; modifier_c.userdata = &u->alg_c; disable_algs(u); meego_parameter_request_updates("alg_a", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, FALSE, &u->alg_a); meego_parameter_request_updates("alg_b", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, TRUE, &u->alg_b); meego_parameter_request_updates("alg_c", (pa_hook_cb_t)parameters_changed_cb, PA_HOOK_NORMAL, FALSE, &u->alg_c); switch_mode(u, "mode_a"); verify(&u->alg_a, "mode_a", "set_a1_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_a", "set_b1_parameters", MEEGO_PARAM_UPDATE); /* Register the modifiers. This should instantly trigger the modified update for "alg_a" since we're in "mode_a" */ meego_parameter_register_modifier(&modifier_a); meego_parameter_register_modifier(&modifier_b); verify(&u->alg_a, "mode_a", "set_a1_parameters-modified", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_a", "set_b1_parameters", MEEGO_PARAM_UPDATE); /* Unchanged */ switch_mode(u, "mode_b"); verify(&u->alg_a, "mode_b", "set_a2_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_b", NULL, MEEGO_PARAM_MODE_CHANGE); /* The modifier fails, so this is the expected result */ switch_mode(u, "mode_c"); verify(&u->alg_a, "mode_c", "set_a3_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_c", "set_b2_parameters", MEEGO_PARAM_UPDATE); /* Let's unregister the modifiers and see that things work as before */ meego_parameter_unregister_modifier(&modifier_a); meego_parameter_unregister_modifier(&modifier_b); switch_mode(u, "mode_a"); verify(&u->alg_a, "mode_a", "set_a1_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_a", "set_b1_parameters", MEEGO_PARAM_UPDATE); /* Try the modifier that has no base parameters */ meego_parameter_register_modifier(&modifier_c); switch_mode(u, "mode_c"); verify(&u->alg_a, "mode_c", "set_a3_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_c", "set_b2_parameters", MEEGO_PARAM_UPDATE); verify(&u->alg_c, "mode_c", "modified", MEEGO_PARAM_UPDATE); /* Withóut the modifier this would be disabled */ /* Now register a modifier when we're not in the affected mode */ meego_parameter_register_modifier(&modifier_a); /* Switch to the affected mode and verify successful modification */ switch_mode(u, "mode_a"); verify(&u->alg_a, "mode_a", "set_a1_parameters-modified", MEEGO_PARAM_UPDATE); verify(&u->alg_b, "mode_a", "set_b1_parameters", MEEGO_PARAM_UPDATE); meego_parameter_unregister_modifier(&modifier_a); meego_parameter_stop_updates("alg_a", (pa_hook_cb_t)parameters_changed_cb, &u->alg_a); meego_parameter_stop_updates("alg_b", (pa_hook_cb_t)parameters_changed_cb, &u->alg_b); meego_parameter_stop_updates("alg_c", (pa_hook_cb_t)parameters_changed_cb, &u->alg_c); meego_parameter_unregister_modifier(&modifier_c); disable_algs(u); }
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; }