Пример #1
0
pa_fdsem *pa_fdsem_new(void) {
    pa_fdsem *f;

    f = pa_xmalloc(PA_ALIGN(sizeof(pa_fdsem)) + PA_ALIGN(sizeof(pa_fdsem_data)));

#ifdef HAVE_SYS_EVENTFD_H
    if ((f->efd = eventfd(0, EFD_CLOEXEC)) >= 0)
        f->fds[0] = f->fds[1] = -1;
    else
#endif
    {
        if (pa_pipe_cloexec(f->fds) < 0) {
            pa_xfree(f);
            return NULL;
        }
    }

    f->data = (pa_fdsem_data*) ((uint8_t*) f + PA_ALIGN(sizeof(pa_fdsem)));

    pa_atomic_store(&f->data->waiting, 0);
    pa_atomic_store(&f->data->signalled, 0);
    pa_atomic_store(&f->data->in_pipe, 0);

    return f;
}
Пример #2
0
pa_flist *pa_flist_new_with_name(unsigned size, const char *name) {
    pa_flist *l;
    unsigned i;
    pa_assert(name);

    if (!size)
        size = FLIST_SIZE;

    l = pa_xmalloc0(sizeof(pa_flist) + sizeof(pa_flist_elem) * size);

    l->name = pa_xstrdup(name);
    l->size = size;

    while (1 << l->tag_shift < (int) size)
        l->tag_shift++;
    l->index_mask = (1 << l->tag_shift) - 1;
    l->tag_mask = INT_MAX - l->index_mask;

    pa_atomic_store(&l->stored, -1);
    pa_atomic_store(&l->empty, -1);
    for (i=0; i < size; i++) {
        stack_push(l, &l->empty, &l->table[i]);
    }
    return l;
}
Пример #3
0
pa_fdsem *pa_fdsem_new_shm(pa_fdsem_data *data, int* event_fd) {
    pa_fdsem *f = NULL;

    pa_assert(data);
    pa_assert(event_fd);

#ifdef HAVE_SYS_EVENTFD_H

    f = pa_xnew(pa_fdsem, 1);

    if ((f->efd = eventfd(0, EFD_CLOEXEC)) < 0) {
        pa_xfree(f);
        return NULL;
    }

    f->fds[0] = f->fds[1] = -1;
    f->data = data;

    pa_atomic_store(&f->data->waiting, 0);
    pa_atomic_store(&f->data->signalled, 0);
    pa_atomic_store(&f->data->in_pipe, 0);

#endif

    return f;
}
Пример #4
0
/* No lock necessary */
pa_memblock *pa_memblock_new_user(pa_mempool *p, void *d, size_t length, pa_free_cb_t free_cb, bool read_only) {
    pa_memblock *b;

    pa_assert(p);
    pa_assert(d);
    pa_assert(length);
    pa_assert(length != (size_t) -1);
    pa_assert(free_cb);

    if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
        b = pa_xnew(pa_memblock, 1);

    PA_REFCNT_INIT(b);
    b->pool = p;
    b->type = PA_MEMBLOCK_USER;
    b->read_only = read_only;
    b->is_silence = false;
    pa_atomic_ptr_store(&b->data, d);
    b->length = length;
    pa_atomic_store(&b->n_acquired, 0);
    pa_atomic_store(&b->please_signal, 0);

    b->per_type.user.free_cb = free_cb;

    stat_add(b);
    return b;
}
Пример #5
0
/* No lock necessary */
pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) {
    pa_memblock *b = NULL;
    struct mempool_slot *slot;
    static int mempool_disable = 0;

    pa_assert(p);
    pa_assert(length);

    if (mempool_disable == 0)
        mempool_disable = getenv("PULSE_MEMPOOL_DISABLE") ? 1 : -1;

    if (mempool_disable > 0)
        return NULL;

    /* If -1 is passed as length we choose the size for the caller: we
     * take the largest size that fits in one of our slots. */

    if (length == (size_t) -1)
        length = pa_mempool_block_size_max(p);

    if (p->block_size >= PA_ALIGN(sizeof(pa_memblock)) + length) {

        if (!(slot = mempool_allocate_slot(p)))
            return NULL;

        b = mempool_slot_data(slot);
        b->type = PA_MEMBLOCK_POOL;
        pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock)));

    } else if (p->block_size >= length) {

        if (!(slot = mempool_allocate_slot(p)))
            return NULL;

        if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
            b = pa_xnew(pa_memblock, 1);

        b->type = PA_MEMBLOCK_POOL_EXTERNAL;
        pa_atomic_ptr_store(&b->data, mempool_slot_data(slot));

    } else {
        pa_log_debug("Memory block too large for pool: %lu > %lu", (unsigned long) length, (unsigned long) p->block_size);
        pa_atomic_inc(&p->stat.n_too_large_for_pool);
        return NULL;
    }

    PA_REFCNT_INIT(b);
    b->pool = p;
    b->read_only = b->is_silence = false;
    b->length = length;
    pa_atomic_store(&b->n_acquired, 0);
    pa_atomic_store(&b->please_signal, 0);

    stat_add(b);
    return b;
}
Пример #6
0
/* Self-locked */
pa_memblock* pa_memimport_get(pa_memimport *i, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size) {
    pa_memblock *b = NULL;
    pa_memimport_segment *seg;

    pa_assert(i);

    pa_mutex_lock(i->mutex);

    if ((b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(block_id)))) {
        pa_memblock_ref(b);
        goto finish;
    }

    if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX)
        goto finish;

    if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id))))
        if (!(seg = segment_attach(i, shm_id)))
            goto finish;

    if (offset+size > seg->memory.size)
        goto finish;

    if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
        b = pa_xnew(pa_memblock, 1);

    PA_REFCNT_INIT(b);
    b->pool = i->pool;
    b->type = PA_MEMBLOCK_IMPORTED;
    b->read_only = true;
    b->is_silence = false;
    pa_atomic_ptr_store(&b->data, (uint8_t*) seg->memory.ptr + offset);
    b->length = size;
    pa_atomic_store(&b->n_acquired, 0);
    pa_atomic_store(&b->please_signal, 0);
    b->per_type.imported.id = block_id;
    b->per_type.imported.segment = seg;

    pa_hashmap_put(i->blocks, PA_UINT32_TO_PTR(block_id), b);

    seg->n_blocks++;

    stat_add(b);

finish:
    pa_mutex_unlock(i->mutex);

    return b;
}
Пример #7
0
pa_mempool* pa_mempool_new(int shared) {
    pa_mempool *p;

    p = pa_xnew(pa_mempool, 1);

    p->mutex = pa_mutex_new(TRUE, TRUE);
    p->semaphore = pa_semaphore_new(0);

    p->block_size = PA_PAGE_ALIGN(PA_MEMPOOL_SLOT_SIZE);
    if (p->block_size < PA_PAGE_SIZE)
        p->block_size = PA_PAGE_SIZE;

    p->n_blocks = PA_MEMPOOL_SLOTS_MAX;

    pa_assert(p->block_size > PA_ALIGN(sizeof(struct mempool_slot)));

    if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) {
        pa_xfree(p);
        return NULL;
    }

    memset(&p->stat, 0, sizeof(p->stat));
    pa_atomic_store(&p->n_init, 0);

    PA_LLIST_HEAD_INIT(pa_memimport, p->imports);
    PA_LLIST_HEAD_INIT(pa_memexport, p->exports);

    p->free_slots = pa_flist_new(p->n_blocks*2);

    return p;
}
Пример #8
0
pa_flist *pa_flist_new(unsigned size) {
    pa_flist *l;

    if (!size)
        size = FLIST_SIZE;

    pa_assert(pa_is_power_of_two(size));

    l = pa_xmalloc0(PA_ALIGN(sizeof(pa_flist)) + (sizeof(pa_atomic_ptr_t) * size));

    l->size = size;

    pa_atomic_store(&l->read_idx, 0);
    pa_atomic_store(&l->write_idx, 0);
    pa_atomic_store(&l->length, 0);

    return l;
}
Пример #9
0
pa_aupdate *pa_aupdate_new(void) {
    pa_aupdate *a;

    a = pa_xnew(pa_aupdate, 1);
    pa_atomic_store(&a->read_lock, 0);
    a->write_lock = pa_mutex_new(false, false);
    a->semaphore = pa_semaphore_new(0);

    return a;
}
Пример #10
0
/* No lock necessary */
pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, int read_only) {
    pa_memblock *b;

    pa_assert(p);
    pa_assert(d);
    pa_assert(length != (size_t) -1);
    pa_assert(length > 0);

    if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
        b = pa_xnew(pa_memblock, 1);
    PA_REFCNT_INIT(b);
    b->pool = p;
    b->type = PA_MEMBLOCK_FIXED;
    b->read_only = read_only;
    pa_atomic_ptr_store(&b->data, d);
    b->length = length;
    pa_atomic_store(&b->n_acquired, 0);
    pa_atomic_store(&b->please_signal, 0);

    stat_add(b);
    return b;
}
Пример #11
0
/* Lock free push to linked list stack */
static void stack_push(pa_flist *flist, pa_atomic_t *list, pa_flist_elem *new_elem) {
    int tag, newindex, next;
    pa_assert(list);

    tag = pa_atomic_inc(&flist->current_tag);
    newindex = new_elem - flist->table;
    pa_assert(newindex >= 0 && newindex < (int) flist->size);
    newindex |= (tag << flist->tag_shift) & flist->tag_mask;

    do {
        next = pa_atomic_load(list);
        pa_atomic_store(&new_elem->next, next);
    } while (!pa_atomic_cmpxchg(list, next, newindex));
}
Пример #12
0
/* No lock necessary */
static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) {
    pa_memblock *b;

    pa_assert(p);
    pa_assert(length);

    /* If -1 is passed as length we choose the size for the caller. */

    if (length == (size_t) -1)
        length = pa_mempool_block_size_max(p);

    b = pa_xmalloc(PA_ALIGN(sizeof(pa_memblock)) + length);
    PA_REFCNT_INIT(b);
    b->pool = p;
    b->type = PA_MEMBLOCK_APPENDED;
    b->read_only = b->is_silence = false;
    pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock)));
    b->length = length;
    pa_atomic_store(&b->n_acquired, 0);
    pa_atomic_store(&b->please_signal, 0);

    stat_add(b);
    return b;
}
Пример #13
0
pa_mempool* pa_mempool_new(bool shared, size_t size) {
    pa_mempool *p;
    char t1[PA_BYTES_SNPRINT_MAX], t2[PA_BYTES_SNPRINT_MAX];

    p = pa_xnew(pa_mempool, 1);

    p->block_size = PA_PAGE_ALIGN(PA_MEMPOOL_SLOT_SIZE);
    if (p->block_size < PA_PAGE_SIZE)
        p->block_size = PA_PAGE_SIZE;

    if (size <= 0)
        p->n_blocks = PA_MEMPOOL_SLOTS_MAX;
    else {
        p->n_blocks = (unsigned) (size / p->block_size);

        if (p->n_blocks < 2)
            p->n_blocks = 2;
    }

    if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) {
        pa_xfree(p);
        return NULL;
    }

    pa_log_debug("Using %s memory pool with %u slots of size %s each, total size is %s, maximum usable slot size is %lu",
                 p->memory.shared ? "shared" : "private",
                 p->n_blocks,
                 pa_bytes_snprint(t1, sizeof(t1), (unsigned) p->block_size),
                 pa_bytes_snprint(t2, sizeof(t2), (unsigned) (p->n_blocks * p->block_size)),
                 (unsigned long) pa_mempool_block_size_max(p));

    memset(&p->stat, 0, sizeof(p->stat));
    pa_atomic_store(&p->n_init, 0);

    PA_LLIST_HEAD_INIT(pa_memimport, p->imports);
    PA_LLIST_HEAD_INIT(pa_memexport, p->exports);

    p->mutex = pa_mutex_new(true, true);
    p->semaphore = pa_semaphore_new(0);

    p->free_slots = pa_flist_new(p->n_blocks);

    return p;
}
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;
}
Пример #15
0
/* Generic sink state change logic. Used by raw_sink and voip_sink */
int voice_sink_set_state(pa_sink *s, pa_sink *other, pa_sink_state_t state) {
    struct userdata *u;
    pa_sink *om_sink;

    pa_sink_assert_ref(s);
    pa_assert_se(u = s->userdata);
    if (!other) {
        pa_log_debug("other sink not initialized or freed");
        return 0;
    }
    pa_sink_assert_ref(other);
    om_sink = u->master_sink;

    if (u->hw_sink_input && PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->hw_sink_input))) {
        if (pa_sink_input_get_state(u->hw_sink_input) == PA_SINK_INPUT_CORKED) {
            if (PA_SINK_IS_OPENED(state) ||
                PA_SINK_IS_OPENED(pa_sink_get_state(other)) ||
                pa_atomic_load(&u->cmt_connection.dl_state) == CMT_DL_ACTIVE) {
                pa_sink_input_cork(u->hw_sink_input, FALSE);
                pa_log_debug("hw_sink_input uncorked");
            }
        }
        else {
            if (state == PA_SINK_SUSPENDED &&
                pa_sink_get_state(other) == PA_SINK_SUSPENDED &&
                pa_atomic_load(&u->cmt_connection.dl_state) != CMT_DL_ACTIVE) {
                pa_sink_input_cork(u->hw_sink_input, TRUE);
                pa_log_debug("hw_sink_input corked");
            }
        }
    }

    if (om_sink == NULL) {
        pa_log_info("No master sink, assuming primary mixer tuning.\n");
        pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI);
    }
    else if (pa_atomic_load(&u->cmt_connection.dl_state) == CMT_DL_ACTIVE ||
            (pa_sink_get_state(u->voip_sink) <= PA_SINK_SUSPENDED &&
             voice_voip_sink_used_by(u))) {
        if (pa_atomic_load(&u->mixer_state) == PROP_MIXER_TUNING_PRI) {
             pa_proplist *p = pa_proplist_new();
             pa_assert(p);
             pa_proplist_sets(p, PROP_MIXER_TUNING_MODE, PROP_MIXER_TUNING_ALT_S);
             pa_sink_update_proplist(om_sink, PA_UPDATE_REPLACE, p);
             pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_ALT);
             pa_proplist_free(p);
             if (u->sidetone_enable)
                 voice_enable_sidetone(u,1);
        }
    }
    else {
        if (pa_atomic_load(&u->mixer_state) == PROP_MIXER_TUNING_ALT) {
            pa_proplist *p = pa_proplist_new();
            pa_assert(p);
            pa_proplist_sets(p, PROP_MIXER_TUNING_MODE, PROP_MIXER_TUNING_PRI_S);
            pa_sink_update_proplist(om_sink, PA_UPDATE_REPLACE, p);
            pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI);
            pa_proplist_free(p);
            voice_enable_sidetone(u,0);

        }
    }

    return 0;
}
Пример #16
0
static int sharedmem_create(pa_shm *m, pa_mem_type_t type, size_t size, mode_t mode) {
#if defined(HAVE_SHM_OPEN) || defined(HAVE_MEMFD)
    char fn[32];
    int fd = -1;
    struct shm_marker *marker;
    bool do_unlink = false;

    /* Each time we create a new SHM area, let's first drop all stale
     * ones */
    pa_shm_cleanup();

    pa_random(&m->id, sizeof(m->id));

    switch (type) {
#ifdef HAVE_SHM_OPEN
    case PA_MEM_TYPE_SHARED_POSIX:
        segment_name(fn, sizeof(fn), m->id);
        fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode);
        do_unlink = true;
        break;
#endif
#ifdef HAVE_MEMFD
    case PA_MEM_TYPE_SHARED_MEMFD:
        fd = memfd_create("pulseaudio", MFD_ALLOW_SEALING);
        break;
#endif
    default:
        goto fail;
    }

    if (fd < 0) {
        pa_log("%s open() failed: %s", pa_mem_type_to_string(type), pa_cstrerror(errno));
        goto fail;
    }

    m->type = type;
    m->size = size + shm_marker_size(type);
    m->do_unlink = do_unlink;

    if (ftruncate(fd, (off_t) m->size) < 0) {
        pa_log("ftruncate() failed: %s", pa_cstrerror(errno));
        goto fail;
    }

#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0
#endif

    if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(m->size), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd, (off_t) 0)) == MAP_FAILED) {
        pa_log("mmap() failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (type == PA_MEM_TYPE_SHARED_POSIX) {
        /* We store our PID at the end of the shm block, so that we
         * can check for dead shm segments later */
        marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - shm_marker_size(type));
        pa_atomic_store(&marker->pid, (int) getpid());
        pa_atomic_store(&marker->marker, SHM_MARKER);
    }

    /* For memfds, we keep the fd open until we pass it
     * to the other PA endpoint over unix domain socket. */
    if (type == PA_MEM_TYPE_SHARED_MEMFD)
        m->fd = fd;
    else {
        pa_assert_se(pa_close(fd) == 0);
        m->fd = -1;
    }

    return 0;

fail:
    if (fd >= 0) {
#ifdef HAVE_SHM_OPEN
        if (type == PA_MEM_TYPE_SHARED_POSIX)
            shm_unlink(fn);
#endif
        pa_close(fd);
    }
#endif /* defined(HAVE_SHM_OPEN) || defined(HAVE_MEMFD) */

    return -1;
}
Пример #17
0
int pa_shm_create_rw(pa_shm *m, size_t size, bool shared, mode_t mode) {
#ifdef HAVE_SHM_OPEN
    char fn[32];
    int fd = -1;
#endif

    pa_assert(m);
    pa_assert(size > 0);
    pa_assert(size <= MAX_SHM_SIZE);
    pa_assert(!(mode & ~0777));
    pa_assert(mode >= 0600);

    /* Each time we create a new SHM area, let's first drop all stale
     * ones */
    pa_shm_cleanup();

    /* Round up to make it page aligned */
    size = PA_PAGE_ALIGN(size);

    if (!shared) {
        m->id = 0;
        m->size = size;

#ifdef MAP_ANONYMOUS
        if ((m->ptr = mmap(NULL, m->size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, (off_t) 0)) == MAP_FAILED) {
            pa_log("mmap() failed: %s", pa_cstrerror(errno));
            goto fail;
        }
#elif defined(HAVE_POSIX_MEMALIGN)
        {
            int r;

            if ((r = posix_memalign(&m->ptr, PA_PAGE_SIZE, size)) < 0) {
                pa_log("posix_memalign() failed: %s", pa_cstrerror(r));
                goto fail;
            }
        }
#else
        m->ptr = pa_xmalloc(m->size);
#endif

        m->do_unlink = false;

    } else {
#ifdef HAVE_SHM_OPEN
        struct shm_marker *marker;

        pa_random(&m->id, sizeof(m->id));
        segment_name(fn, sizeof(fn), m->id);

        if ((fd = shm_open(fn, O_RDWR|O_CREAT|O_EXCL, mode)) < 0) {
            pa_log("shm_open() failed: %s", pa_cstrerror(errno));
            goto fail;
        }

        m->size = size + SHM_MARKER_SIZE;

        if (ftruncate(fd, (off_t) m->size) < 0) {
            pa_log("ftruncate() failed: %s", pa_cstrerror(errno));
            goto fail;
        }

#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0
#endif

        if ((m->ptr = mmap(NULL, PA_PAGE_ALIGN(m->size), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd, (off_t) 0)) == MAP_FAILED) {
            pa_log("mmap() failed: %s", pa_cstrerror(errno));
            goto fail;
        }

        /* We store our PID at the end of the shm block, so that we
         * can check for dead shm segments later */
        marker = (struct shm_marker*) ((uint8_t*) m->ptr + m->size - SHM_MARKER_SIZE);
        pa_atomic_store(&marker->pid, (int) getpid());
        pa_atomic_store(&marker->marker, SHM_MARKER);

        pa_assert_se(pa_close(fd) == 0);
        m->do_unlink = true;
#else
        goto fail;
#endif
    }

    m->shared = shared;

    return 0;

fail:

#ifdef HAVE_SHM_OPEN
    if (fd >= 0) {
        shm_unlink(fn);
        pa_close(fd);
    }
#endif

    return -1;
}
Пример #18
0
void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simple_options *o) {
    connection *c = NULL;
    char pname[128];
    pa_client_new_data client_data;

    pa_assert(p);
    pa_assert(io);
    pa_assert(o);

    if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
        pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
        pa_iochannel_free(io);
        return;
    }

    c = pa_msgobject_new(connection);
    c->parent.parent.free = connection_free;
    c->parent.process_msg = connection_process_msg;
    c->io = io;
    pa_iochannel_set_callback(c->io, io_callback, c);

    c->sink_input = NULL;
    c->source_output = NULL;
    c->input_memblockq = c->output_memblockq = NULL;
    c->protocol = p;
    c->options = pa_simple_options_ref(o);
    c->playback.current_memblock = NULL;
    c->playback.memblock_index = 0;
    c->dead = false;
    c->playback.underrun = true;
    pa_atomic_store(&c->playback.missing, 0);

    pa_client_new_data_init(&client_data);
    client_data.module = o->module;
    client_data.driver = __FILE__;
    pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
    pa_proplist_setf(client_data.proplist, PA_PROP_APPLICATION_NAME, "Simple client (%s)", pname);
    pa_proplist_sets(client_data.proplist, "simple-protocol.peer", pname);
    c->client = pa_client_new(p->core, &client_data);
    pa_client_new_data_done(&client_data);

    if (!c->client)
        goto fail;

    c->client->kill = client_kill_cb;
    c->client->userdata = c;

    if (o->playback) {
        pa_sink_input_new_data data;
        pa_memchunk silence;
        size_t l;
        pa_sink *sink;

        if (!(sink = pa_namereg_get(c->protocol->core, o->default_sink, PA_NAMEREG_SINK))) {
            pa_log("Failed to get sink.");
            goto fail;
        }

        pa_sink_input_new_data_init(&data);
        data.driver = __FILE__;
        data.module = o->module;
        data.client = c->client;
        pa_sink_input_new_data_set_sink(&data, sink, false);
        pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
        pa_sink_input_new_data_set_sample_spec(&data, &o->sample_spec);

        pa_sink_input_new(&c->sink_input, p->core, &data);
        pa_sink_input_new_data_done(&data);

        if (!c->sink_input) {
            pa_log("Failed to create sink input.");
            goto fail;
        }

        c->sink_input->parent.process_msg = sink_input_process_msg;
        c->sink_input->pop = sink_input_pop_cb;
        c->sink_input->process_rewind = sink_input_process_rewind_cb;
        c->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
        c->sink_input->kill = sink_input_kill_cb;
        c->sink_input->userdata = c;

        pa_sink_input_set_requested_latency(c->sink_input, DEFAULT_SINK_LATENCY);

        l = (size_t) ((double) pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS);
        pa_sink_input_get_silence(c->sink_input, &silence);
        c->input_memblockq = pa_memblockq_new(
                "simple protocol connection input_memblockq",
                0,
                l,
                l,
                &o->sample_spec,
                (size_t) -1,
                l/PLAYBACK_BUFFER_FRAGMENTS,
                0,
                &silence);
        pa_memblock_unref(silence.memblock);

        pa_iochannel_socket_set_rcvbuf(io, l);

        pa_atomic_store(&c->playback.missing, (int) pa_memblockq_pop_missing(c->input_memblockq));

        pa_sink_input_put(c->sink_input);
    }

    if (o->record) {
        pa_source_output_new_data data;
        size_t l;
        pa_source *source;

        if (!(source = pa_namereg_get(c->protocol->core, o->default_source, PA_NAMEREG_SOURCE))) {
            pa_log("Failed to get source.");
            goto fail;
        }

        pa_source_output_new_data_init(&data);
        data.driver = __FILE__;
        data.module = o->module;
        data.client = c->client;
        pa_source_output_new_data_set_source(&data, source, false);
        pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
        pa_source_output_new_data_set_sample_spec(&data, &o->sample_spec);

        pa_source_output_new(&c->source_output, p->core, &data);
        pa_source_output_new_data_done(&data);

        if (!c->source_output) {
            pa_log("Failed to create source output.");
            goto fail;
        }
        c->source_output->push = source_output_push_cb;
        c->source_output->kill = source_output_kill_cb;
        c->source_output->get_latency = source_output_get_latency_cb;
        c->source_output->userdata = c;

        pa_source_output_set_requested_latency(c->source_output, DEFAULT_SOURCE_LATENCY);

        l = (size_t) (pa_bytes_per_second(&o->sample_spec)*RECORD_BUFFER_SECONDS);
        c->output_memblockq = pa_memblockq_new(
                "simple protocol connection output_memblockq",
                0,
                l,
                0,
                &o->sample_spec,
                1,
                0,
                0,
                NULL);
        pa_iochannel_socket_set_sndbuf(io, l);

        pa_source_output_put(c->source_output);
    }

    pa_idxset_put(p->connections, c, NULL);

    return;

fail:
    connection_unlink(c);
}
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;
}