void pa_policy_context_add_property_action(struct pa_policy_context_rule *rule, int lineno, enum pa_policy_object_type obj_type, enum pa_classify_method obj_classify, const char *obj_name, const char *prop_name, enum pa_policy_value_type value_type, ... /* value_arg */) { union pa_policy_context_action *action; struct pa_policy_set_property *setprop; va_list value_arg; action = pa_xmalloc0(sizeof(*action)); setprop = &action->setprop; setprop->type = pa_policy_set_property; setprop->lineno = lineno; setprop->object.type = obj_type; match_setup(&setprop->object.match, obj_classify, obj_name, NULL); setprop->property = pa_xstrdup(prop_name); va_start(value_arg, value_type); value_setup(&setprop->value, value_type, value_arg); va_end(value_arg); append_action(&rule->actions, action); }
static struct pa_policy_context_variable *add_variable(struct pa_policy_context *ctx, const char *name) { struct pa_policy_context_variable *var; struct pa_policy_context_variable *last; for (last = (struct pa_policy_context_variable *)&ctx->variables; last->next != NULL; last = last->next) { var = last->next; if (!strcmp(name, var->name)) return var; } var = pa_xmalloc0(sizeof(*var)); var->name = pa_xstrdup(name); var->value = pa_xstrdup(""); last->next = var; pa_log_debug("created context variable '%s'", var->name); return var; }
pa_asyncq *pa_asyncq_new(unsigned size) { pa_asyncq *l; if (!size) size = ASYNCQ_SIZE; pa_assert(pa_is_power_of_two(size)); l = pa_xmalloc0(PA_ALIGN(sizeof(pa_asyncq)) + (sizeof(pa_atomic_ptr_t) * size)); l->size = size; PA_LLIST_HEAD_INIT(struct localq, l->localq); l->last_localq = NULL; l->waiting_for_post = FALSE; if (!(l->read_fdsem = pa_fdsem_new())) { pa_xfree(l); return NULL; } if (!(l->write_fdsem = pa_fdsem_new())) { pa_fdsem_free(l->read_fdsem); pa_xfree(l); return NULL; } return l; }
static struct pa_policy_activity_variable *get_activity_variable(struct userdata *u, struct pa_policy_context *ctx, const char *device) { struct pa_policy_activity_variable *var; struct pa_policy_activity_variable *last; for (last = (struct pa_policy_activity_variable *)&ctx->activities; last->next != NULL; last = last->next) { var = last->next; if (!strcmp(device, var->device)) return var; } var = pa_xmalloc0(sizeof(*var)); var->device = pa_xstrdup(device); var->userdata = u; var->default_state = -1; last->next = var; pa_log_debug("created context activity variable '%s'", var->device); return var; }
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; }
static struct pa_policy_context_rule * add_rule(struct pa_policy_context_rule **rules, enum pa_classify_method method, const char *arg) { struct pa_policy_context_rule *rule = pa_xmalloc0(sizeof(*rule)); struct pa_policy_context_rule *last; enum pa_classify_method method_status; if (!match_setup(&rule->match, method, arg, &method_status)) { pa_log("%s: invalid rule definition (method %s)", __FUNCTION__, pa_classify_method_str(method_status)); pa_xfree(rule); return NULL; }; for (last = (struct pa_policy_context_rule *)rules; last->next != NULL; last = last->next) ; last->next = rule; return rule; }
static void handle_new_sink_input(struct userdata *u, struct pa_sink_input *sinp) { struct pa_policy_group *group = NULL; struct pa_sink_input_ext *ext; uint32_t idx; const char *sinp_name; uint32_t flags; if (sinp && u) { idx = sinp->index; sinp_name = sink_input_ext_get_name(sinp->proplist); pa_assert_se((group = get_group_or_classify(u, sinp, &flags))); ext = pa_xmalloc0(sizeof(struct pa_sink_input_ext)); ext->local.route = (flags & PA_POLICY_LOCAL_ROUTE) ? TRUE : FALSE; ext->local.mute = (flags & PA_POLICY_LOCAL_MUTE ) ? TRUE : FALSE; pa_index_hash_add(u->hsi, idx, ext); pa_policy_context_register(u, pa_policy_object_sink_input, sinp_name, sinp); pa_policy_group_insert_sink_input(u, group->name, sinp, flags); pa_log_debug("new sink_input %s (idx=%u) (group=%s)", sinp_name, idx, group->name); } }
struct pa_policy_context *pa_policy_context_new(struct userdata *u) { struct pa_policy_context *ctx; ctx = pa_xmalloc0(sizeof(*ctx)); return ctx; }
pa_srbchannel* pa_srbchannel_new(pa_mainloop_api *m, pa_mempool *p) { int capacity; int readfd; struct srbheader *srh; pa_srbchannel* sr = pa_xmalloc0(sizeof(pa_srbchannel)); sr->mainloop = m; sr->memblock = pa_memblock_new_pool(p, -1); if (!sr->memblock) goto fail; srh = pa_memblock_acquire(sr->memblock); pa_zero(*srh); sr->rb_read.memory = (uint8_t*) srh + PA_ALIGN(sizeof(*srh)); srh->readbuf_offset = sr->rb_read.memory - (uint8_t*) srh; capacity = (pa_memblock_get_length(sr->memblock) - srh->readbuf_offset) / 2; sr->rb_write.memory = PA_ALIGN_PTR(sr->rb_read.memory + capacity); srh->writebuf_offset = sr->rb_write.memory - (uint8_t*) srh; capacity = PA_MIN(capacity, srh->writebuf_offset - srh->readbuf_offset); pa_log_debug("SHM block is %d bytes, ringbuffer capacity is 2 * %d bytes", (int) pa_memblock_get_length(sr->memblock), capacity); srh->capacity = sr->rb_read.capacity = sr->rb_write.capacity = capacity; sr->rb_read.count = &srh->read_count; sr->rb_write.count = &srh->write_count; sr->sem_read = pa_fdsem_new_shm(&srh->read_semdata); if (!sr->sem_read) goto fail; sr->sem_write = pa_fdsem_new_shm(&srh->write_semdata); if (!sr->sem_write) goto fail; readfd = pa_fdsem_get(sr->sem_read); #ifdef DEBUG_SRBCHANNEL pa_log("Enabling io event on fd %d", readfd); #endif sr->read_event = m->io_new(m, readfd, PA_IO_EVENT_INPUT, semread_cb, sr); m->io_enable(sr->read_event, PA_IO_EVENT_INPUT); return sr; fail: pa_srbchannel_free(sr); return NULL; }
void voice_memchunk_pool_load(struct userdata *u) { int i; pa_assert(0 == offsetof(voice_memchunk_pool, chunk)); pa_atomic_ptr_store(&u->memchunk_pool, NULL); voice_memchunk_pool_table = pa_xmalloc0(sizeof(voice_memchunk_pool)*VOICE_MEMCHUNK_POOL_SIZE); pa_assert(voice_memchunk_pool_table); for (i = 0; i<VOICE_MEMCHUNK_POOL_SIZE; i++) voice_memchunk_pool_free(u, (pa_memchunk *)&voice_memchunk_pool_table[i]); }
pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) { pa_idxset *s; s = pa_xmalloc0(PA_ALIGN(sizeof(pa_idxset)) + NBUCKETS*2*sizeof(struct idxset_entry*)); s->hash_func = hash_func ? hash_func : pa_idxset_trivial_hash_func; s->compare_func = compare_func ? compare_func : pa_idxset_trivial_compare_func; s->current_index = 0; s->n_entries = 0; s->iterate_list_head = s->iterate_list_tail = NULL; return s; }
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; }
pa_srbchannel* pa_srbchannel_new_from_template(pa_mainloop_api *m, pa_srbchannel_template *t) { int temp; struct srbheader *srh; pa_srbchannel* sr = pa_xmalloc0(sizeof(pa_srbchannel)); sr->mainloop = m; sr->memblock = t->memblock; pa_memblock_ref(sr->memblock); srh = pa_memblock_acquire(sr->memblock); sr->rb_read.capacity = sr->rb_write.capacity = srh->capacity; sr->rb_read.count = &srh->read_count; sr->rb_write.count = &srh->write_count; sr->rb_read.memory = (uint8_t*) srh + srh->readbuf_offset; sr->rb_write.memory = (uint8_t*) srh + srh->writebuf_offset; sr->sem_read = pa_fdsem_open_shm(&srh->read_semdata, t->readfd); if (!sr->sem_read) goto fail; sr->sem_write = pa_fdsem_open_shm(&srh->write_semdata, t->writefd); if (!sr->sem_write) goto fail; pa_srbchannel_swap(sr); temp = t->readfd; t->readfd = t->writefd; t->writefd = temp; #ifdef DEBUG_SRBCHANNEL pa_log("Enabling io event on fd %d", t->readfd); #endif sr->read_event = m->io_new(m, t->readfd, PA_IO_EVENT_INPUT, semread_cb, sr); m->io_enable(sr->read_event, PA_IO_EVENT_INPUT); return sr; fail: pa_srbchannel_free(sr); return NULL; }
void pa_policy_context_set_default_action(struct pa_policy_context_rule *rule, int lineno, struct userdata *u, const char *activity_group, int default_state) { union pa_policy_context_action *action; struct pa_policy_set_default *setdef; action = pa_xmalloc0(sizeof(*action)); setdef = &action->setdef; setdef->type = pa_policy_set_default; setdef->lineno = lineno; pa_assert_se((setdef->var = get_activity_variable(u, u->context, activity_group))); setdef->default_state = default_state; append_action(&rule->actions, action); }
void pa_policy_context_delete_property_action(struct pa_policy_context_rule *rule, int lineno, enum pa_policy_object_type obj_type, enum pa_classify_method obj_classify, const char *obj_name, const char *prop_name) { union pa_policy_context_action *action; struct pa_policy_del_property *delprop; action = pa_xmalloc0(sizeof(*action)); delprop = &action->delprop; delprop->type = pa_policy_delete_property; delprop->lineno = lineno; delprop->object.type = obj_type; match_setup(&delprop->object.match, obj_classify, obj_name, NULL); delprop->property = pa_xstrdup(prop_name); append_action(&rule->actions, action); }
int pa__init(pa_module*m) { struct userdata *u; pa_sample_spec ss, sink_input_ss; pa_channel_map map, sink_input_map; pa_modargs *ma; pa_sink *master=NULL; pa_sink_input_new_data sink_input_data; pa_sink_new_data sink_data; bool use_volume_sharing = true; bool force_flat_volume = false; pa_memchunk silence; const char *hrir_file; unsigned i, j, found_channel_left, found_channel_right; float *hrir_data; pa_sample_spec hrir_ss; pa_channel_map hrir_map; pa_sample_spec hrir_temp_ss; pa_memchunk hrir_temp_chunk, hrir_temp_chunk_resampled; pa_resampler *resampler; size_t hrir_copied_length, hrir_total_length; hrir_temp_chunk.memblock = NULL; hrir_temp_chunk_resampled.memblock = NULL; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments."); goto fail; } if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK))) { pa_log("Master sink not found"); goto fail; } pa_assert(master); u = pa_xnew0(struct userdata, 1); u->module = m; m->userdata = u; /* Initialize hrir and input buffer */ /* this is the hrir file for the left ear! */ if (!(hrir_file = pa_modargs_get_value(ma, "hrir", NULL))) { pa_log("The mandatory 'hrir' module argument is missing."); goto fail; } if (pa_sound_file_load(master->core->mempool, hrir_file, &hrir_temp_ss, &hrir_map, &hrir_temp_chunk, NULL) < 0) { pa_log("Cannot load hrir file."); goto fail; } /* sample spec / map of hrir */ hrir_ss.format = PA_SAMPLE_FLOAT32; hrir_ss.rate = master->sample_spec.rate; hrir_ss.channels = hrir_temp_ss.channels; /* sample spec of sink */ ss = hrir_ss; map = hrir_map; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("Invalid sample format specification or channel map"); goto fail; } ss.format = PA_SAMPLE_FLOAT32; hrir_ss.rate = ss.rate; u->channels = ss.channels; if (pa_modargs_get_value_boolean(ma, "use_volume_sharing", &use_volume_sharing) < 0) { pa_log("use_volume_sharing= expects a boolean argument"); goto fail; } if (pa_modargs_get_value_boolean(ma, "force_flat_volume", &force_flat_volume) < 0) { pa_log("force_flat_volume= expects a boolean argument"); goto fail; } if (use_volume_sharing && force_flat_volume) { pa_log("Flat volume can't be forced when using volume sharing."); goto fail; } /* sample spec / map of sink input */ pa_channel_map_init_stereo(&sink_input_map); sink_input_ss.channels = 2; sink_input_ss.format = PA_SAMPLE_FLOAT32; sink_input_ss.rate = ss.rate; u->sink_fs = pa_frame_size(&ss); u->fs = pa_frame_size(&sink_input_ss); /* Create sink */ pa_sink_new_data_init(&sink_data); sink_data.driver = __FILE__; sink_data.module = m; if (!(sink_data.name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) sink_data.name = pa_sprintf_malloc("%s.vsurroundsink", master->name); pa_sink_new_data_set_sample_spec(&sink_data, &ss); pa_sink_new_data_set_channel_map(&sink_data, &map); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name); pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "filter"); pa_proplist_sets(sink_data.proplist, "device.vsurroundsink.name", sink_data.name); if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_sink_new_data_done(&sink_data); goto fail; } if ((u->auto_desc = !pa_proplist_contains(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) { const char *z; z = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION); pa_proplist_setf(sink_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Virtual Surround Sink %s on %s", sink_data.name, z ? z : master->name); } u->sink = pa_sink_new(m->core, &sink_data, (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY)) | (use_volume_sharing ? PA_SINK_SHARE_VOLUME_WITH_MASTER : 0)); pa_sink_new_data_done(&sink_data); if (!u->sink) { pa_log("Failed to create sink."); goto fail; } u->sink->parent.process_msg = sink_process_msg_cb; u->sink->set_state = sink_set_state_cb; u->sink->update_requested_latency = sink_update_requested_latency_cb; u->sink->request_rewind = sink_request_rewind_cb; pa_sink_set_set_mute_callback(u->sink, sink_set_mute_cb); if (!use_volume_sharing) { pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb); pa_sink_enable_decibel_volume(u->sink, true); } /* Normally this flag would be enabled automatically be we can force it. */ if (force_flat_volume) u->sink->flags |= PA_SINK_FLAT_VOLUME; u->sink->userdata = u; pa_sink_set_asyncmsgq(u->sink, master->asyncmsgq); /* Create sink input */ pa_sink_input_new_data_init(&sink_input_data); sink_input_data.driver = __FILE__; sink_input_data.module = m; pa_sink_input_new_data_set_sink(&sink_input_data, master, false); sink_input_data.origin_sink = u->sink; pa_proplist_setf(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "Virtual Surround Sink Stream from %s", pa_proplist_gets(u->sink->proplist, PA_PROP_DEVICE_DESCRIPTION)); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &sink_input_ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &sink_input_map); pa_sink_input_new(&u->sink_input, m->core, &sink_input_data); pa_sink_input_new_data_done(&sink_input_data); if (!u->sink_input) goto fail; u->sink_input->pop = sink_input_pop_cb; u->sink_input->process_rewind = sink_input_process_rewind_cb; u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; u->sink_input->update_max_request = sink_input_update_max_request_cb; u->sink_input->update_sink_latency_range = sink_input_update_sink_latency_range_cb; u->sink_input->update_sink_fixed_latency = sink_input_update_sink_fixed_latency_cb; u->sink_input->kill = sink_input_kill_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; u->sink_input->state_change = sink_input_state_change_cb; u->sink_input->moving = sink_input_moving_cb; u->sink_input->volume_changed = use_volume_sharing ? NULL : sink_input_volume_changed_cb; u->sink_input->mute_changed = sink_input_mute_changed_cb; u->sink_input->userdata = u; u->sink->input_to_master = u->sink_input; pa_sink_input_get_silence(u->sink_input, &silence); u->memblockq = pa_memblockq_new("module-virtual-surround-sink memblockq", 0, MEMBLOCKQ_MAXLENGTH, 0, &sink_input_ss, 1, 1, 0, &silence); pa_memblock_unref(silence.memblock); /* resample hrir */ resampler = pa_resampler_new(u->sink->core->mempool, &hrir_temp_ss, &hrir_map, &hrir_ss, &hrir_map, PA_RESAMPLER_SRC_SINC_BEST_QUALITY, PA_RESAMPLER_NO_REMAP); u->hrir_samples = hrir_temp_chunk.length / pa_frame_size(&hrir_temp_ss) * hrir_ss.rate / hrir_temp_ss.rate; if (u->hrir_samples > 64) { u->hrir_samples = 64; pa_log("The (resampled) hrir contains more than 64 samples. Only the first 64 samples will be used to limit processor usage."); } hrir_total_length = u->hrir_samples * pa_frame_size(&hrir_ss); u->hrir_channels = hrir_ss.channels; u->hrir_data = (float *) pa_xmalloc(hrir_total_length); hrir_copied_length = 0; /* add silence to the hrir until we get enough samples out of the resampler */ while (hrir_copied_length < hrir_total_length) { pa_resampler_run(resampler, &hrir_temp_chunk, &hrir_temp_chunk_resampled); if (hrir_temp_chunk.memblock != hrir_temp_chunk_resampled.memblock) { /* Silence input block */ pa_silence_memblock(hrir_temp_chunk.memblock, &hrir_temp_ss); } if (hrir_temp_chunk_resampled.memblock) { /* Copy hrir data */ hrir_data = (float *) pa_memblock_acquire(hrir_temp_chunk_resampled.memblock); if (hrir_total_length - hrir_copied_length >= hrir_temp_chunk_resampled.length) { memcpy(u->hrir_data + hrir_copied_length, hrir_data, hrir_temp_chunk_resampled.length); hrir_copied_length += hrir_temp_chunk_resampled.length; } else { memcpy(u->hrir_data + hrir_copied_length, hrir_data, hrir_total_length - hrir_copied_length); hrir_copied_length = hrir_total_length; } pa_memblock_release(hrir_temp_chunk_resampled.memblock); pa_memblock_unref(hrir_temp_chunk_resampled.memblock); hrir_temp_chunk_resampled.memblock = NULL; } } pa_resampler_free(resampler); pa_memblock_unref(hrir_temp_chunk.memblock); hrir_temp_chunk.memblock = NULL; if (hrir_map.channels < map.channels) { pa_log("hrir file does not have enough channels!"); goto fail; } normalize_hrir(u); /* create mapping between hrir and input */ u->mapping_left = (unsigned *) pa_xnew0(unsigned, u->channels); u->mapping_right = (unsigned *) pa_xnew0(unsigned, u->channels); for (i = 0; i < map.channels; i++) { found_channel_left = 0; found_channel_right = 0; for (j = 0; j < hrir_map.channels; j++) { if (hrir_map.map[j] == map.map[i]) { u->mapping_left[i] = j; found_channel_left = 1; } if (hrir_map.map[j] == mirror_channel(map.map[i])) { u->mapping_right[i] = j; found_channel_right = 1; } } if (!found_channel_left) { pa_log("Cannot find mapping for channel %s", pa_channel_position_to_string(map.map[i])); goto fail; } if (!found_channel_right) { pa_log("Cannot find mapping for channel %s", pa_channel_position_to_string(mirror_channel(map.map[i]))); goto fail; } } u->input_buffer = pa_xmalloc0(u->hrir_samples * u->sink_fs); u->input_buffer_offset = 0; pa_sink_put(u->sink); pa_sink_input_put(u->sink_input); pa_modargs_free(ma); return 0; fail: if (hrir_temp_chunk.memblock) pa_memblock_unref(hrir_temp_chunk.memblock); if (hrir_temp_chunk_resampled.memblock) pa_memblock_unref(hrir_temp_chunk_resampled.memblock); if (ma) pa_modargs_free(ma); pa__done(m); return -1; }
static int handle_response(struct userdata *u) { pa_assert(u); switch (u->state) { case STATE_AUTH: pa_assert(u->read_length == sizeof(int32_t)); /* Process auth data */ if (!*(int32_t*) u->read_data) { pa_log("Authentication failed: %s", pa_cstrerror(errno)); return -1; } /* Request latency data */ pa_assert(!u->write_data); *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY; u->write_index = 0; u->state = STATE_LATENCY; /* Space for next response */ pa_assert(u->read_length >= sizeof(int32_t)); u->read_index = 0; u->read_length = sizeof(int32_t); break; case STATE_LATENCY: { int32_t *p; pa_assert(u->read_length == sizeof(int32_t)); /* Process latency info */ u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100); if (u->latency > 10000000) { pa_log_warn("Invalid latency information received from server"); u->latency = 0; } /* Create stream */ pa_assert(!u->write_data); p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX); *(p++) = ESD_PROTO_STREAM_PLAY; *(p++) = u->format; *(p++) = u->rate; pa_strlcpy((char*) p, "PulseAudio Tunnel", ESD_NAME_MAX); u->write_index = 0; u->state = STATE_PREPARE; /* Don't read any further */ pa_xfree(u->read_data); u->read_data = NULL; u->read_index = u->read_length = 0; break; } default: pa_assert_not_reached(); } return 0; }