Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #5
0
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;
}
Example #6
0
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;
    }
  }
}
Example #7
0
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;
}