/* 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; }
size_t pa_context_get_tile_size(pa_context *c, const pa_sample_spec *ss) { size_t fs, mbs; pa_assert(c); pa_assert(PA_REFCNT_VALUE(c) >= 1); PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1); PA_CHECK_VALIDITY_RETURN_ANY(c, !ss || pa_sample_spec_valid(ss), PA_ERR_INVALID, (size_t) -1); fs = ss ? pa_frame_size(ss) : 1; mbs = PA_ROUND_DOWN(pa_mempool_block_size_max(c->mempool), fs); return PA_MAX(mbs, fs); }
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; }
static pa_memblock *silence_memblock_new(pa_mempool *pool, uint8_t c) { pa_memblock *b; size_t length; void *data; pa_assert(pool); length = PA_MIN(pa_mempool_block_size_max(pool), PA_SILENCE_MAX); b = pa_memblock_new(pool, length); data = pa_memblock_acquire(b); memset(data, c, length); pa_memblock_release(b); pa_memblock_set_is_silence(b, true); return b; }
void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq) { size_t l; unsigned gcd, n; void *p; pa_memchunk_reset(c); gcd = pa_gcd(rate, freq); n = rate / gcd; l = pa_mempool_block_size_max(pool) / sizeof(float); l /= n; if (l <= 0) l = 1; l *= n; c->length = l * sizeof(float); c->memblock = pa_memblock_new(pool, c->length); p = pa_memblock_acquire(c->memblock); calc_sine(p, c->length, freq * l / rate); pa_memblock_release(c->memblock); }
/* 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; }
int pa__init(pa_module*m) { struct userdata *u; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma; char *t; pa_sink *master; pa_sink_input_new_data sink_input_data; pa_sink_new_data sink_data; const char *plugin, *label, *input_ladspaport_map, *output_ladspaport_map; LADSPA_Descriptor_Function descriptor_func; unsigned long input_ladspaport[PA_CHANNELS_MAX], output_ladspaport[PA_CHANNELS_MAX]; const char *e, *cdata; const LADSPA_Descriptor *d; unsigned long p, h, j, n_control, c; pa_bool_t *use_default = NULL; pa_assert(m); pa_assert_cc(sizeof(LADSPA_Data) == sizeof(float)); 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; } ss = master->sample_spec; ss.format = PA_SAMPLE_FLOAT32; map = master->channel_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; } if (!(plugin = pa_modargs_get_value(ma, "plugin", NULL))) { pa_log("Missing LADSPA plugin name"); goto fail; } if (!(label = pa_modargs_get_value(ma, "label", NULL))) { pa_log("Missing LADSPA plugin label"); goto fail; } if (!(input_ladspaport_map = pa_modargs_get_value(ma, "input_ladspaport_map", NULL))) pa_log_debug("Using default input ladspa port mapping"); if (!(output_ladspaport_map = pa_modargs_get_value(ma, "output_ladspaport_map", NULL))) pa_log_debug("Using default output ladspa port mapping"); cdata = pa_modargs_get_value(ma, "control", NULL); u = pa_xnew0(struct userdata, 1); u->module = m; m->userdata = u; u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL); u->max_ladspaport_count = 1; /*to avoid division by zero etc. in pa__done when failing before this value has been set*/ u->channels = 0; u->input = NULL; u->output = NULL; if (!(e = getenv("LADSPA_PATH"))) e = LADSPA_PATH; /* FIXME: This is not exactly thread safe */ t = pa_xstrdup(lt_dlgetsearchpath()); lt_dlsetsearchpath(e); m->dl = lt_dlopenext(plugin); lt_dlsetsearchpath(t); pa_xfree(t); if (!m->dl) { pa_log("Failed to load LADSPA plugin: %s", lt_dlerror()); goto fail; } if (!(descriptor_func = (LADSPA_Descriptor_Function) pa_load_sym(m->dl, NULL, "ladspa_descriptor"))) { pa_log("LADSPA module lacks ladspa_descriptor() symbol."); goto fail; } for (j = 0;; j++) { if (!(d = descriptor_func(j))) { pa_log("Failed to find plugin label '%s' in plugin '%s'.", label, plugin); goto fail; } if (strcmp(d->Label, label) == 0) break; } u->descriptor = d; pa_log_debug("Module: %s", plugin); pa_log_debug("Label: %s", d->Label); pa_log_debug("Unique ID: %lu", d->UniqueID); pa_log_debug("Name: %s", d->Name); pa_log_debug("Maker: %s", d->Maker); pa_log_debug("Copyright: %s", d->Copyright); n_control = 0; u->channels = ss.channels; /* * Enumerate ladspa ports * Default mapping is in order given by the plugin */ for (p = 0; p < d->PortCount; p++) { if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) { if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) { pa_log_debug("Port %lu is input: %s", p, d->PortNames[p]); input_ladspaport[u->input_count] = p; u->input_count++; } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) { pa_log_debug("Port %lu is output: %s", p, d->PortNames[p]); output_ladspaport[u->output_count] = p; u->output_count++; } } else if (LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) { pa_log_debug("Port %lu is control: %s", p, d->PortNames[p]); n_control++; } else pa_log_debug("Ignored port %s", d->PortNames[p]); /* XXX: Has anyone ever seen an in-place plugin with non-equal number of input and output ports? */ /* Could be if the plugin is for up-mixing stereo to 5.1 channels */ /* Or if the plugin is down-mixing 5.1 to two channel stereo or binaural encoded signal */ if (u->input_count > u->max_ladspaport_count) u->max_ladspaport_count = u->input_count; else u->max_ladspaport_count = u->output_count; } if (u->channels % u->max_ladspaport_count) { pa_log("Cannot handle non-integral number of plugins required for given number of channels"); goto fail; } pa_log_debug("Will run %lu plugin instances", u->channels / u->max_ladspaport_count); /* Parse data for input ladspa port map */ if (input_ladspaport_map) { const char *state = NULL; char *pname; c = 0; while ((pname = pa_split(input_ladspaport_map, ",", &state))) { if (c == u->input_count) { pa_log("Too many ports in input ladspa port map"); goto fail; } for (p = 0; p < d->PortCount; p++) { if (strcmp(d->PortNames[p], pname) == 0) { if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) { input_ladspaport[c] = p; } else { pa_log("Port %s is not an audio input ladspa port", pname); pa_xfree(pname); goto fail; } } } c++; pa_xfree(pname); } } /* Parse data for output port map */ if (output_ladspaport_map) { const char *state = NULL; char *pname; c = 0; while ((pname = pa_split(output_ladspaport_map, ",", &state))) { if (c == u->output_count) { pa_log("Too many ports in output ladspa port map"); goto fail; } for (p = 0; p < d->PortCount; p++) { if (strcmp(d->PortNames[p], pname) == 0) { if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) { output_ladspaport[c] = p; } else { pa_log("Port %s is not an output ladspa port", pname); pa_xfree(pname); goto fail; } } } c++; pa_xfree(pname); } } u->block_size = pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss); /* Create buffers */ if (LADSPA_IS_INPLACE_BROKEN(d->Properties)) { u->input = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->input_count); for (c = 0; c < u->input_count; c++) u->input[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size); u->output = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->output_count); for (c = 0; c < u->output_count; c++) u->output[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size); } else {
int pa__init(pa_module*m) { struct userdata *u; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma; char *t; pa_sink *master; pa_sink_input_new_data sink_input_data; pa_sink_new_data sink_data; const char *plugin, *label; LADSPA_Descriptor_Function descriptor_func; const char *e, *cdata; const LADSPA_Descriptor *d; unsigned long input_port, output_port, p, j, n_control; unsigned c; pa_bool_t *use_default = NULL; pa_assert(m); pa_assert_cc(sizeof(LADSPA_Data) == sizeof(float)); 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; } ss = master->sample_spec; ss.format = PA_SAMPLE_FLOAT32; map = master->channel_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; } if (!(plugin = pa_modargs_get_value(ma, "plugin", NULL))) { pa_log("Missing LADSPA plugin name"); goto fail; } if (!(label = pa_modargs_get_value(ma, "label", NULL))) { pa_log("Missing LADSPA plugin label"); goto fail; } cdata = pa_modargs_get_value(ma, "control", NULL); u = pa_xnew0(struct userdata, 1); u->module = m; m->userdata = u; u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL); if (!(e = getenv("LADSPA_PATH"))) e = LADSPA_PATH; /* FIXME: This is not exactly thread safe */ t = pa_xstrdup(lt_dlgetsearchpath()); lt_dlsetsearchpath(e); m->dl = lt_dlopenext(plugin); lt_dlsetsearchpath(t); pa_xfree(t); if (!m->dl) { pa_log("Failed to load LADSPA plugin: %s", lt_dlerror()); goto fail; } if (!(descriptor_func = (LADSPA_Descriptor_Function) pa_load_sym(m->dl, NULL, "ladspa_descriptor"))) { pa_log("LADSPA module lacks ladspa_descriptor() symbol."); goto fail; } for (j = 0;; j++) { if (!(d = descriptor_func(j))) { pa_log("Failed to find plugin label '%s' in plugin '%s'.", label, plugin); goto fail; } if (strcmp(d->Label, label) == 0) break; } u->descriptor = d; pa_log_debug("Module: %s", plugin); pa_log_debug("Label: %s", d->Label); pa_log_debug("Unique ID: %lu", d->UniqueID); pa_log_debug("Name: %s", d->Name); pa_log_debug("Maker: %s", d->Maker); pa_log_debug("Copyright: %s", d->Copyright); input_port = output_port = (unsigned long) -1; n_control = 0; for (p = 0; p < d->PortCount; p++) { if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) { if (strcmp(d->PortNames[p], "Input") == 0) { pa_assert(input_port == (unsigned long) -1); input_port = p; } else { pa_log("Found audio input port on plugin we cannot handle: %s", d->PortNames[p]); goto fail; } } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) { if (strcmp(d->PortNames[p], "Output") == 0) { pa_assert(output_port == (unsigned long) -1); output_port = p; } else { pa_log("Found audio output port on plugin we cannot handle: %s", d->PortNames[p]); goto fail; } } else if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])) n_control++; else { pa_assert(LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p]) && LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])); pa_log_debug("Ignored control output port \"%s\".", d->PortNames[p]); } } if ((input_port == (unsigned long) -1) || (output_port == (unsigned long) -1)) { pa_log("Failed to identify input and output ports. " "Right now this module can only deal with plugins which provide an 'Input' and an 'Output' audio port. " "Patches welcome!"); goto fail; } u->block_size = pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss); u->input = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size); if (LADSPA_IS_INPLACE_BROKEN(d->Properties)) u->output = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size); else u->output = u->input; u->channels = ss.channels; for (c = 0; c < ss.channels; c++) { if (!(u->handle[c] = d->instantiate(d, ss.rate))) { pa_log("Failed to instantiate plugin %s with label %s for channel %i", plugin, d->Label, c); goto fail; } d->connect_port(u->handle[c], input_port, u->input); d->connect_port(u->handle[c], output_port, u->output); } if (!cdata && n_control > 0) { pa_log("This plugin requires specification of %lu control parameters.", n_control); goto fail; } if (n_control > 0) { const char *state = NULL; char *k; unsigned long h; u->control = pa_xnew(LADSPA_Data, (unsigned) n_control); use_default = pa_xnew(pa_bool_t, (unsigned) n_control); p = 0; while ((k = pa_split(cdata, ",", &state)) && p < n_control) { double f; if (*k == 0) { use_default[p++] = TRUE; pa_xfree(k); continue; } if (pa_atod(k, &f) < 0) { pa_log("Failed to parse control value '%s'", k); pa_xfree(k); goto fail; } pa_xfree(k); use_default[p] = FALSE; u->control[p++] = (LADSPA_Data) f; } /* The previous loop doesn't take the last control value into account if it is left empty, so we do it here. */ if (*cdata == 0 || cdata[strlen(cdata) - 1] == ',') { if (p < n_control) use_default[p] = TRUE; p++; } if (p > n_control || k) { pa_log("Too many control values passed, %lu expected.", n_control); pa_xfree(k); goto fail; } if (p < n_control) { pa_log("Not enough control values passed, %lu expected, %lu passed.", n_control, p); goto fail; } h = 0; for (p = 0; p < d->PortCount; p++) { LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor; if (!LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p])) continue; if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) { for (c = 0; c < ss.channels; c++) d->connect_port(u->handle[c], p, &u->control_out); continue; } pa_assert(h < n_control); if (use_default[h]) { LADSPA_Data lower, upper; if (!LADSPA_IS_HINT_HAS_DEFAULT(hint)) { pa_log("Control port value left empty but plugin defines no default."); goto fail; } lower = d->PortRangeHints[p].LowerBound; upper = d->PortRangeHints[p].UpperBound; if (LADSPA_IS_HINT_SAMPLE_RATE(hint)) { lower *= (LADSPA_Data) ss.rate; upper *= (LADSPA_Data) ss.rate; } switch (hint & LADSPA_HINT_DEFAULT_MASK) { case LADSPA_HINT_DEFAULT_MINIMUM: u->control[h] = lower; break; case LADSPA_HINT_DEFAULT_MAXIMUM: u->control[h] = upper; break; case LADSPA_HINT_DEFAULT_LOW: if (LADSPA_IS_HINT_LOGARITHMIC(hint)) u->control[h] = (LADSPA_Data) exp(log(lower) * 0.75 + log(upper) * 0.25); else u->control[h] = (LADSPA_Data) (lower * 0.75 + upper * 0.25); break; case LADSPA_HINT_DEFAULT_MIDDLE: if (LADSPA_IS_HINT_LOGARITHMIC(hint)) u->control[h] = (LADSPA_Data) exp(log(lower) * 0.5 + log(upper) * 0.5); else u->control[h] = (LADSPA_Data) (lower * 0.5 + upper * 0.5); break; case LADSPA_HINT_DEFAULT_HIGH: if (LADSPA_IS_HINT_LOGARITHMIC(hint)) u->control[h] = (LADSPA_Data) exp(log(lower) * 0.25 + log(upper) * 0.75); else u->control[h] = (LADSPA_Data) (lower * 0.25 + upper * 0.75); break; case LADSPA_HINT_DEFAULT_0: u->control[h] = 0; break; case LADSPA_HINT_DEFAULT_1: u->control[h] = 1; break; case LADSPA_HINT_DEFAULT_100: u->control[h] = 100; break; case LADSPA_HINT_DEFAULT_440: u->control[h] = 440; break; default: pa_assert_not_reached(); } } if (LADSPA_IS_HINT_INTEGER(hint)) u->control[h] = roundf(u->control[h]); pa_log_debug("Binding %f to port %s", u->control[h], d->PortNames[p]); for (c = 0; c < ss.channels; c++) d->connect_port(u->handle[c], p, &u->control[h]); h++; } pa_assert(h == n_control); } if (d->activate) for (c = 0; c < u->channels; c++) d->activate(u->handle[c]); /* 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.ladspa", 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.ladspa.module", plugin); pa_proplist_sets(sink_data.proplist, "device.ladspa.label", d->Label); pa_proplist_sets(sink_data.proplist, "device.ladspa.name", d->Name); pa_proplist_sets(sink_data.proplist, "device.ladspa.maker", d->Maker); pa_proplist_sets(sink_data.proplist, "device.ladspa.copyright", d->Copyright); pa_proplist_setf(sink_data.proplist, "device.ladspa.unique_id", "%lu", (unsigned long) d->UniqueID); 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, "LADSPA Plugin %s on %s", d->Name, z ? z : master->name); } u->sink = pa_sink_new(m->core, &sink_data, PA_SINK_HW_MUTE_CTRL|PA_SINK_HW_VOLUME_CTRL|PA_SINK_DECIBEL_VOLUME| (master->flags & (PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY))); 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; u->sink->set_volume = sink_set_volume_cb; u->sink->set_mute = sink_set_mute_cb; 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; sink_input_data.sink = master; pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_NAME, "LADSPA Stream"); pa_proplist_sets(sink_input_data.proplist, PA_PROP_MEDIA_ROLE, "filter"); pa_sink_input_new_data_set_sample_spec(&sink_input_data, &ss); pa_sink_input_new_data_set_channel_map(&sink_input_data, &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->may_move_to = sink_input_may_move_to_cb; u->sink_input->moving = sink_input_moving_cb; u->sink_input->volume_changed = sink_input_volume_changed_cb; u->sink_input->mute_changed = sink_input_mute_changed_cb; u->sink_input->userdata = u; pa_sink_put(u->sink); pa_sink_input_put(u->sink_input); pa_modargs_free(ma); pa_xfree(use_default); return 0; fail: if (ma) pa_modargs_free(ma); pa_xfree(use_default); pa__done(m); return -1; }
static void thread_func(void *userdata) { struct userdata *u = userdata; bool timer_elapsed = false; size_t max_block_size; pa_assert(u); pa_log_debug("Thread starting up"); if (u->core->realtime_scheduling) pa_thread_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); max_block_size = pa_frame_align(pa_mempool_block_size_max(u->core->mempool), &u->source->sample_spec); u->timestamp = pa_rtclock_now(); for (;;) { int ret; /* Generate some null data */ if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) { pa_usec_t now; pa_memchunk chunk; now = pa_rtclock_now(); if (timer_elapsed && (chunk.length = pa_usec_to_bytes(now - u->timestamp, &u->source->sample_spec)) > 0) { chunk.length = PA_MIN(max_block_size, chunk.length); chunk.memblock = pa_memblock_new(u->core->mempool, chunk.length); chunk.index = 0; pa_silence_memchunk(&chunk, &u->source->sample_spec); pa_source_post(u->source, &chunk); pa_memblock_unref(chunk.memblock); u->timestamp += pa_bytes_to_usec(chunk.length, &u->source->sample_spec); } pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp + u->block_usec); } else pa_rtpoll_set_timer_disabled(u->rtpoll); /* Hmm, nothing to do. Let's sleep */ if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) goto fail; timer_elapsed = pa_rtpoll_timer_elapsed(u->rtpoll); if (ret == 0) goto finish; } fail: /* If this was no regular exit from the loop we have to continue * processing messages until we received PA_MESSAGE_SHUTDOWN */ pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); finish: pa_log_debug("Thread shutting down"); }