static void pa_adrian_ec_fixate_spec(pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map) { source_ss->format = PA_SAMPLE_S16NE; source_ss->channels = 1; pa_channel_map_init_mono(source_map); *sink_ss = *source_ss; *sink_map = *source_map; }
static void pa_adrian_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map, pa_sample_spec *play_ss, pa_channel_map *play_map, pa_sample_spec *out_ss, pa_channel_map *out_map) { out_ss->format = PA_SAMPLE_S16NE; out_ss->channels = 1; pa_channel_map_init_mono(out_map); *play_ss = *out_ss; *play_map = *out_map; *rec_ss = *out_ss; *rec_map = *out_map; }
static inline void init_pulse(struct pa_fft *pa_fft) { /* PA spec */ fprintf(stderr, "device = %s\n", pa_fft->dev); if (!pa_fft->dev) { fprintf(stderr, "Warning: no device specified! It's highly possible " "Pulseaudio will attempt to use the microphone!\n"); } pa_fft->ss.format = PA_SAMPLE_FLOAT32LE; pa_fft->ss.rate = 44100; pa_fft->ss.channels = 1; pa_channel_map_init_mono(&pa_fft->map); if (!(pa_fft->s = pa_simple_new(NULL, "pa_fft", PA_STREAM_RECORD, pa_fft->dev, "record", &pa_fft->ss, &pa_fft->map, NULL, &pa_fft->error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(pa_fft->error)); pa_fft->cont = 0; return; } }
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; }
static gboolean gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps) { pa_channel_map channel_map; GstStructure *s; gboolean need_channel_layout = FALSE; GstRingBufferSpec spec; const gchar *name; memset (&spec, 0, sizeof (GstRingBufferSpec)); spec.latency_time = GST_SECOND; if (!gst_ring_buffer_parse_caps (&spec, caps)) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS, ("Can't parse caps."), (NULL)); goto fail; } /* Keep the refcount of the caps at 1 to make them writable */ gst_caps_unref (spec.caps); if (!gst_pulse_fill_sample_spec (&spec, &pulsesrc->sample_spec)) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS, ("Invalid sample specification."), (NULL)); goto fail; } pa_threaded_mainloop_lock (pulsesrc->mainloop); if (!pulsesrc->context) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context"), (NULL)); goto unlock_and_fail; } s = gst_caps_get_structure (caps, 0); if (!gst_structure_has_field (s, "channel-layout") || !gst_pulse_gst_to_channel_map (&channel_map, &spec)) { if (spec.channels == 1) pa_channel_map_init_mono (&channel_map); else if (spec.channels == 2) pa_channel_map_init_stereo (&channel_map); else need_channel_layout = TRUE; } name = "Record Stream"; if (pulsesrc->proplist) { if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context, name, &pulsesrc->sample_spec, (need_channel_layout) ? NULL : &channel_map, pulsesrc->proplist))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } } else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context, name, &pulsesrc->sample_spec, (need_channel_layout) ? NULL : &channel_map))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } if (need_channel_layout) { const pa_channel_map *m = pa_stream_get_channel_map (pulsesrc->stream); gst_pulse_channel_map_to_gst (m, &spec); caps = spec.caps; } GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, caps); pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb, pulsesrc); pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb, pulsesrc); pa_stream_set_underflow_callback (pulsesrc->stream, gst_pulsesrc_stream_underflow_cb, pulsesrc); pa_stream_set_overflow_callback (pulsesrc->stream, gst_pulsesrc_stream_overflow_cb, pulsesrc); pa_stream_set_latency_update_callback (pulsesrc->stream, gst_pulsesrc_stream_latency_update_cb, pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; unlock_and_fail: gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); fail: return FALSE; }
static int pulseaudio_audio_reconfig(audio_decoder_t *ad) { decoder_t *d = (decoder_t *)ad; int i; pa_threaded_mainloop_lock(mainloop); if(pulseaudio_make_context_ready()) { pa_threaded_mainloop_unlock(mainloop); return -1; } if(d->s) { pa_stream_disconnect(d->s); pa_stream_unref(d->s); } pa_channel_map map; ad->ad_out_sample_rate = ad->ad_in_sample_rate; d->ss.rate = ad->ad_in_sample_rate; switch(ad->ad_in_sample_format) { case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_S32P: ad->ad_out_sample_format = AV_SAMPLE_FMT_S32; d->ss.format = PA_SAMPLE_S32NE; d->framesize = sizeof(int32_t); break; case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S16P: ad->ad_out_sample_format = AV_SAMPLE_FMT_S16; d->ss.format = PA_SAMPLE_S16NE; d->framesize = sizeof(int16_t); break; default: ad->ad_out_sample_format = AV_SAMPLE_FMT_FLT; d->ss.format = PA_SAMPLE_FLOAT32NE; d->framesize = sizeof(float); break; } switch(ad->ad_in_channel_layout) { case AV_CH_LAYOUT_MONO: d->ss.channels = 1; ad->ad_out_channel_layout = AV_CH_LAYOUT_MONO; pa_channel_map_init_mono(&map); break; case AV_CH_LAYOUT_STEREO: d->ss.channels = 2; ad->ad_out_channel_layout = AV_CH_LAYOUT_STEREO; pa_channel_map_init_stereo(&map); default: pa_channel_map_init(&map); for(i = 0; i < sizeof(av2pa_map) / sizeof(av2pa_map[0]); i++) { if(ad->ad_in_channel_layout & av2pa_map[i].avmask) { ad->ad_out_channel_layout |= av2pa_map[i].avmask; map.map[map.channels++] = av2pa_map[i].papos; } } d->ss.channels = map.channels; break; } d->framesize *= d->ss.channels; ad->ad_tile_size = pa_context_get_tile_size(ctx, &d->ss) / d->framesize; char buf[100]; char buf2[PA_CHANNEL_MAP_SNPRINT_MAX]; TRACE(TRACE_DEBUG, "PA", "Created stream %s [%s] (tilesize=%d)", pa_sample_spec_snprint(buf, sizeof(buf), &d->ss), pa_channel_map_snprint(buf2, sizeof(buf2), &map), ad->ad_tile_size); #if PA_API_VERSION >= 12 pa_proplist *pl = pa_proplist_new(); media_pipe_t *mp = ad->ad_mp; if(mp->mp_flags & MP_VIDEO) pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "video"); else pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "music"); d->s = pa_stream_new_with_proplist(ctx, "Showtime playback", &d->ss, &map, pl); pa_proplist_free(pl); #else d->s = pa_stream_new(ctx, "Showtime playback", &ss, &map); #endif int flags = 0; pa_stream_set_state_callback(d->s, stream_state_callback, d); pa_stream_set_write_callback(d->s, stream_write_callback, d); flags |= PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING; pa_stream_connect_playback(d->s, NULL, NULL, flags, NULL, NULL); while(1) { switch(pa_stream_get_state(d->s)) { case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); continue; case PA_STREAM_READY: pa_threaded_mainloop_unlock(mainloop); return 0; case PA_STREAM_TERMINATED: case PA_STREAM_FAILED: pa_threaded_mainloop_unlock(mainloop); return 1; } } }
static gboolean gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps ** caps) { pa_channel_map channel_map; const pa_channel_map *m; GstStructure *s; gboolean need_channel_layout = FALSE; GstAudioRingBufferSpec spec; const gchar *name; s = gst_caps_get_structure (*caps, 0); gst_structure_get_int (s, "channels", &spec.info.channels); if (!gst_structure_has_field (s, "channel-mask")) { if (spec.info.channels == 1) { pa_channel_map_init_mono (&channel_map); } else if (spec.info.channels == 2) { gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) | GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT), NULL); pa_channel_map_init_stereo (&channel_map); } else { need_channel_layout = TRUE; gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL); } } memset (&spec, 0, sizeof (GstAudioRingBufferSpec)); spec.latency_time = GST_SECOND; if (!gst_audio_ring_buffer_parse_caps (&spec, *caps)) goto invalid_caps; /* Keep the refcount of the caps at 1 to make them writable */ gst_caps_unref (spec.caps); if (!need_channel_layout && !gst_pulse_gst_to_channel_map (&channel_map, &spec)) { need_channel_layout = TRUE; gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL); memset (spec.info.position, 0xff, sizeof (spec.info.position)); } if (!gst_pulse_fill_sample_spec (&spec, &pulsesrc->sample_spec)) goto invalid_spec; pa_threaded_mainloop_lock (pulsesrc->mainloop); if (!pulsesrc->context) goto bad_context; name = "Record Stream"; if (pulsesrc->proplist) { if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context, name, &pulsesrc->sample_spec, (need_channel_layout) ? NULL : &channel_map, pulsesrc->proplist))) goto create_failed; } else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context, name, &pulsesrc->sample_spec, (need_channel_layout) ? NULL : &channel_map))) goto create_failed; m = pa_stream_get_channel_map (pulsesrc->stream); gst_pulse_channel_map_to_gst (m, &spec); gst_audio_channel_positions_to_valid_order (spec.info.position, spec.info.channels); gst_caps_unref (*caps); *caps = gst_audio_info_to_caps (&spec.info); GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, *caps); pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb, pulsesrc); pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb, pulsesrc); pa_stream_set_underflow_callback (pulsesrc->stream, gst_pulsesrc_stream_underflow_cb, pulsesrc); pa_stream_set_overflow_callback (pulsesrc->stream, gst_pulsesrc_stream_overflow_cb, pulsesrc); pa_stream_set_latency_update_callback (pulsesrc->stream, gst_pulsesrc_stream_latency_update_cb, pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; /* ERRORS */ invalid_caps: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS, ("Can't parse caps."), (NULL)); goto fail; } invalid_spec: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS, ("Invalid sample specification."), (NULL)); goto fail; } bad_context: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context"), (NULL)); goto unlock_and_fail; } create_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: { gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); fail: return 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 = NULL; struct userdata *u; const char *sink_name, *source_name, *dbus_type; pa_sink *sink = NULL; pa_source *source = NULL; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log_error("Failed to parse module arguments"); goto fail; } sink_name = pa_modargs_get_value(ma, "sink", NULL); source_name = pa_modargs_get_value(ma, "source", NULL); dbus_type = pa_modargs_get_value(ma, "dbus_type", "session"); pa_log_debug("Got arguments: sink=\"%s\" source=\"%s\" dbus_type=\"%s\"", sink_name, source_name, dbus_type); u = pa_xnew0(struct userdata, 1); m->userdata = u; u->core = m->core; u->module = m; u->ss.format = PA_SAMPLE_S16NE; u->ss.rate = CMTSPEECH_SAMPLERATE; u->ss.channels = 1; pa_channel_map_init_mono(&u->map); /* The result is rounded down incorrectly thus +1 */ u->dl_frame_size = pa_usec_to_bytes(VOICE_SINK_FRAMESIZE+1, &u->ss); u->ul_frame_size = pa_usec_to_bytes(VOICE_SOURCE_FRAMESIZE+1, &u->ss); if (!(source = pa_namereg_get(m->core, source_name, PA_NAMEREG_SOURCE))) { pa_log_error("Source \"%s\" not found", source_name); goto fail; } if (!(sink = pa_namereg_get(m->core, sink_name, PA_NAMEREG_SINK))) { pa_log_error("Sink \"%s\" not found", sink_name); goto fail; } u->sink_name = pa_xstrdup(sink_name); u->source_name = pa_xstrdup(source_name); if (cmtspeech_check_source_api(source)) goto fail; if (cmtspeech_check_sink_api(sink)) goto fail; u->sink_input = NULL; u->source_output = NULL; u->local_sideinfoq = pa_queue_new(); u->voice_sideinfoq = NULL; u->continuous_dl_stream = false, u->dl_memblockq = pa_memblockq_new("cmtspeech dl_memblockq", 0, 4*u->dl_frame_size, 0, &u->ss, 0, 0, 0, NULL); u->mainloop_handler = cmtspeech_mainloop_handler_new(u); if (cmtspeech_dbus_init(u, dbus_type)) goto fail; if (cmtspeech_connection_init(u)) goto fail; pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; }