void pa__done(pa_module*m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) return; /* See comments in source_output_kill_cb() above regarding * destruction order! */ if (u->source_output) pa_source_output_unlink(u->source_output); if (u->source) pa_source_unlink(u->source); if (u->source_output) pa_source_output_unref(u->source_output); if (u->source) pa_source_unref(u->source); if (u->sink) pa_sink_unref(u->sink); if (u->memblockq) pa_memblockq_free(u->memblockq); if (u->sink_memblockq) pa_memblockq_free(u->sink_memblockq); pa_xfree(u); }
static void connection_free(pa_object *o) { connection *c = CONNECTION(o); pa_assert(c); if (c->playback.current_memblock) pa_memblock_unref(c->playback.current_memblock); if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) pa_memblockq_free(c->output_memblockq); pa_xfree(c); }
int pa_play_memchunk( pa_sink *sink, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, pa_cvolume *volume, pa_proplist *p, uint32_t *sink_input_index) { pa_memblockq *q; int r; pa_memchunk silence; pa_assert(sink); pa_assert(ss); pa_assert(chunk); pa_silence_memchunk_get(&sink->core->silence_cache, sink->core->mempool, &silence, ss, 0); q = pa_memblockq_new(0, chunk->length, 0, pa_frame_size(ss), 1, 1, 0, &silence); pa_memblock_unref(silence.memblock); pa_assert_se(pa_memblockq_push(q, chunk) >= 0); if ((r = pa_play_memblockq(sink, ss, map, q, volume, p, sink_input_index)) < 0) { pa_memblockq_free(q); return r; } return 0; }
void pa__done(pa_module*m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) return; if (u->sap_event) m->core->mainloop->time_free(u->sap_event); if (u->source_output) { pa_source_output_unlink(u->source_output); pa_source_output_unref(u->source_output); } pa_rtp_context_destroy(&u->rtp_context); pa_sap_send(&u->sap_context, 1); pa_sap_context_destroy(&u->sap_context); if (u->memblockq) pa_memblockq_free(u->memblockq); pa_xfree(u); }
int pa_play_memchunk( pa_sink *sink, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, pa_cvolume *volume, pa_proplist *p, uint32_t *sink_input_index) { pa_memblockq *q; int r; pa_assert(sink); pa_assert(ss); pa_assert(chunk); q = pa_memblockq_new(0, chunk->length, 0, pa_frame_size(ss), 1, 1, 0, NULL); pa_assert_se(pa_memblockq_push(q, chunk) >= 0); if ((r = pa_play_memblockq(sink, ss, map, q, volume, p, sink_input_index)) < 0) { pa_memblockq_free(q); return r; } return 0; }
static void memblockq_stream_free(pa_object *o) { memblockq_stream *u = MEMBLOCKQ_STREAM(o); pa_assert(u); if (u->memblockq) pa_memblockq_free(u->memblockq); pa_xfree(u); }
/* Called from main context */ static void file_stream_free(pa_object *o) { file_stream *u = FILE_STREAM(o); pa_assert(u); if (u->memblockq) pa_memblockq_free(u->memblockq); if (u->sndfile) sf_close(u->sndfile); pa_xfree(u); }
void pa_memblockq_sink_input_set_queue(pa_sink_input *i, pa_memblockq *q) { memblockq_stream *u; pa_sink_input_assert_ref(i); u = MEMBLOCKQ_STREAM(i->userdata); memblockq_stream_assert_ref(u); if (u->memblockq) pa_memblockq_free(u->memblockq); if ((u->memblockq = q)) { pa_memblockq_set_prebuf(q, 0); pa_memblockq_set_silence(q, NULL); pa_memblockq_willneed(q); } }
void pa__done(pa_module*m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) return; teardown(u); if (u->memblockq) pa_memblockq_free(u->memblockq); if (u->asyncmsgq) pa_asyncmsgq_unref(u->asyncmsgq); pa_xfree(u); }
void pa__done(pa_module*m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) return; if (u->unload_de) { u->core->mainloop->defer_free(u->unload_de); u->unload_de = NULL; } cmtspeech_dbus_unload(u); cmtspeech_connection_unload(u); cmtspeech_delete_source_output(u); cmtspeech_delete_sink_input(u); if (u->mainloop_handler) { u->mainloop_handler->parent.free((pa_object *)u->mainloop_handler); u->mainloop_handler = NULL; } if (u->local_sideinfoq) { pa_queue_free(u->local_sideinfoq, NULL); u->local_sideinfoq = NULL; } if (u->dl_memblockq) { pa_memblockq_free(u->dl_memblockq); u->dl_memblockq = NULL; } if (u->sink_name) pa_xfree(u->sink_name); if (u->source_name) pa_xfree(u->source_name); pa_xfree(u); }
void pa__done(pa_module*m) { struct userdata *u; unsigned c; pa_assert(m); if (!(u = m->userdata)) return; /* See comments in sink_input_kill_cb() above regarding * destruction order! */ if (u->sink_input) pa_sink_input_unlink(u->sink_input); if (u->sink) pa_sink_unlink(u->sink); if (u->sink_input) pa_sink_input_unref(u->sink_input); if (u->sink) pa_sink_unref(u->sink); for (c = 0; c < u->channels; c++) if (u->handle[c]) { if (u->descriptor->deactivate) u->descriptor->deactivate(u->handle[c]); u->descriptor->cleanup(u->handle[c]); } if (u->output != u->input) pa_xfree(u->output); if (u->memblockq) pa_memblockq_free(u->memblockq); pa_xfree(u->input); pa_xfree(u->control); pa_xfree(u); }
void pa__done(pa_module*m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) return; /* See comments in sink_input_kill_cb() above regarding * destruction order! */ if (u->sink_input) pa_sink_input_unlink(u->sink_input); if (u->sink) pa_sink_unlink(u->sink); if (u->sink_input) pa_sink_input_unref(u->sink_input); if (u->sink) pa_sink_unref(u->sink); if (u->memblockq) pa_memblockq_free(u->memblockq); if (u->hrir_data) pa_xfree(u->hrir_data); if (u->input_buffer) pa_xfree(u->input_buffer); if (u->mapping_left) pa_xfree(u->mapping_left); if (u->mapping_right) pa_xfree(u->mapping_right); pa_xfree(u); }
static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { memblockq_stream *u; pa_sink_input_assert_ref(i); pa_assert(chunk); u = MEMBLOCKQ_STREAM(i->userdata); memblockq_stream_assert_ref(u); if (!u->memblockq) return -1; if (pa_memblockq_peek(u->memblockq, chunk) < 0) { if (pa_sink_input_safe_to_remove(i)) { pa_memblockq_free(u->memblockq); u->memblockq = NULL; pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMBLOCKQ_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL); } return -1; } /* If there's no memblock, there's going to be data in the memblockq after * a gap with length chunk->length. Drop the the gap and peek the actual * data. There should always be some data coming - hence the assert. The * gap will occur if the memblockq is rewound beyond index 0.*/ if (!chunk->memblock) { pa_memblockq_drop(u->memblockq, chunk->length); pa_assert_se(pa_memblockq_peek(u->memblockq, chunk) >= 0); } chunk->length = PA_MIN(chunk->length, nbytes); pa_memblockq_drop(u->memblockq, chunk->length); return 0; }
/* Called from main context */ static void source_output_free(pa_object* mo) { pa_source_output *o = PA_SOURCE_OUTPUT(mo); pa_assert(o); pa_assert_ctl_context(); pa_assert(pa_source_output_refcnt(o) == 0); if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) pa_source_output_unlink(o); pa_log_info("Freeing output %u \"%s\"", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME))); if (o->thread_info.delay_memblockq) pa_memblockq_free(o->thread_info.delay_memblockq); if (o->thread_info.resampler) pa_resampler_free(o->thread_info.resampler); if (o->proplist) pa_proplist_free(o->proplist); pa_xfree(o->driver); pa_xfree(o); }
/*** Deallocate stuff ***/ void voice_clear_up(struct userdata *u) { pa_assert(u); if (u->mainloop_handler) { u->mainloop_handler->parent.free((pa_object *)u->mainloop_handler); u->mainloop_handler = NULL; } if (u->hw_sink_input) { pa_sink_input_unlink(u->hw_sink_input); pa_sink_input_unref(u->hw_sink_input); u->hw_sink_input = NULL; } if (u->raw_sink) { pa_sink_unlink(u->raw_sink); pa_sink_unref(u->raw_sink); u->raw_sink = NULL; } if (u->dl_memblockq) { pa_memblockq_free(u->dl_memblockq); u->dl_memblockq = NULL; } if (u->voip_sink) { pa_sink_unlink(u->voip_sink); pa_sink_unref(u->voip_sink); u->voip_sink = NULL; } if (u->hw_source_output) { pa_source_output_unlink(u->hw_source_output); pa_source_output_unref(u->hw_source_output); u->hw_source_output = NULL; } if (u->voip_source) { pa_source_unlink(u->voip_source); pa_source_unref(u->voip_source); u->voip_source = NULL; } if (u->raw_source) { pa_source_unlink(u->raw_source); pa_source_unref(u->raw_source); u->raw_source = NULL; } if (u->hw_source_memblockq) { pa_memblockq_free(u->hw_source_memblockq); u->hw_source_memblockq = NULL; } if (u->ul_memblockq) { pa_memblockq_free(u->ul_memblockq); u->ul_memblockq = NULL; } if (u->dl_sideinfo_queue) { pa_queue_free(u->dl_sideinfo_queue, NULL, u); u->dl_sideinfo_queue = NULL; } voice_aep_ear_ref_unload(u); if (u->aep_silence_memchunk.memblock) { pa_memblock_unref(u->aep_silence_memchunk.memblock); pa_memchunk_reset(&u->aep_silence_memchunk); } if (u->sink_temp_buff) { pa_xfree(u->sink_temp_buff); u->sink_temp_buff = NULL; } if (u->sink_subscription) { pa_subscription_free(u->sink_subscription); u->sink_subscription = NULL; } if (u->sink_proplist_changed_slot) { pa_hook_slot_free(u->sink_proplist_changed_slot); u->sink_proplist_changed_slot = NULL; } if (u->source_proplist_changed_slot) { pa_hook_slot_free(u->source_proplist_changed_slot); u->source_proplist_changed_slot = NULL; } voice_convert_free(u); voice_memchunk_pool_unload(u); voice_unload_event_forwarder(u); }
/* Called from main context */ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t save) { pa_resampler *new_resampler; pa_source_output_assert_ref(o); pa_assert_ctl_context(); pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state)); pa_assert(!o->source); pa_source_assert_ref(dest); if (!pa_source_output_may_move_to(o, dest)) return -1; if (o->thread_info.resampler && pa_sample_spec_equal(pa_resampler_input_sample_spec(o->thread_info.resampler), &dest->sample_spec) && pa_channel_map_equal(pa_resampler_input_channel_map(o->thread_info.resampler), &dest->channel_map)) /* Try to reuse the old resampler if possible */ new_resampler = o->thread_info.resampler; else if ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) || !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) || !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) { /* Okey, we need a new resampler for the new source */ if (!(new_resampler = pa_resampler_new( o->core->mempool, &dest->sample_spec, &dest->channel_map, &o->sample_spec, &o->channel_map, o->requested_resample_method, ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) | ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) | (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) { pa_log_warn("Unsupported resampling operation."); return -PA_ERR_NOTSUPPORTED; } } else new_resampler = NULL; if (o->moving) o->moving(o, dest); o->source = dest; o->save_source = save; pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL); if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) o->source->n_corked++; /* Replace resampler */ if (new_resampler != o->thread_info.resampler) { if (o->thread_info.resampler) pa_resampler_free(o->thread_info.resampler); o->thread_info.resampler = new_resampler; pa_memblockq_free(o->thread_info.delay_memblockq); o->thread_info.delay_memblockq = pa_memblockq_new( 0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&o->source->sample_spec), 0, 1, 0, &o->source->silence); o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID; } pa_source_update_status(dest); pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL) == 0); pa_log_debug("Successfully moved source output %i to %s.", o->index, dest->name); /* Notify everyone */ pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], o); pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index); return 0; }
/* Called from IO thread context */ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { file_stream *u; pa_sink_input_assert_ref(i); pa_assert(chunk); u = FILE_STREAM(i->userdata); file_stream_assert_ref(u); if (!u->memblockq) return -1; for (;;) { pa_memchunk tchunk; size_t fs; void *p; sf_count_t n; if (pa_memblockq_peek(u->memblockq, chunk) >= 0) { chunk->length = PA_MIN(chunk->length, length); pa_memblockq_drop(u->memblockq, chunk->length); return 0; } if (!u->sndfile) break; tchunk.memblock = pa_memblock_new(i->sink->core->mempool, length); tchunk.index = 0; p = pa_memblock_acquire(tchunk.memblock); if (u->readf_function) { fs = pa_frame_size(&i->sample_spec); n = u->readf_function(u->sndfile, p, (sf_count_t) (length/fs)); } else { fs = 1; n = sf_read_raw(u->sndfile, p, (sf_count_t) length); } pa_memblock_release(tchunk.memblock); if (n <= 0) { pa_memblock_unref(tchunk.memblock); sf_close(u->sndfile); u->sndfile = NULL; break; } tchunk.length = (size_t) n * fs; pa_memblockq_push(u->memblockq, &tchunk); pa_memblock_unref(tchunk.memblock); } if (pa_sink_input_safe_to_remove(i)) { pa_memblockq_free(u->memblockq); u->memblockq = NULL; pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), FILE_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL); } return -1; }
int main(int argc, char *argv[]) { int ret; pa_mempool *p; pa_memblockq *bq; pa_memchunk chunk1, chunk2, chunk3, chunk4; pa_memchunk silence; pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 48000, .channels = 1 }; pa_log_set_level(PA_LOG_DEBUG); p = pa_mempool_new(FALSE, 0); pa_assert_se(silence.memblock = pa_memblock_new_fixed(p, (char*) "__", 2, 1)); silence.index = 0; silence.length = pa_memblock_get_length(silence.memblock); pa_assert_se(bq = pa_memblockq_new("test memblockq", 0, 200, 10, &ss, 4, 4, 40, &silence)); pa_assert_se(chunk1.memblock = pa_memblock_new_fixed(p, (char*) "11", 2, 1)); chunk1.index = 0; chunk1.length = 2; pa_assert_se(chunk2.memblock = pa_memblock_new_fixed(p, (char*) "XX22", 4, 1)); chunk2.index = 2; chunk2.length = 2; pa_assert_se(chunk3.memblock = pa_memblock_new_fixed(p, (char*) "3333", 4, 1)); chunk3.index = 0; chunk3.length = 4; pa_assert_se(chunk4.memblock = pa_memblock_new_fixed(p, (char*) "44444444", 8, 1)); chunk4.index = 0; chunk4.length = 8; ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); ret = pa_memblockq_push(bq, &chunk2); assert(ret == 0); ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); ret = pa_memblockq_push(bq, &chunk4); assert(ret == 0); pa_memblockq_seek(bq, -6, 0, TRUE); ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); pa_memblockq_seek(bq, -2, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); pa_memblockq_seek(bq, -10, 0, TRUE); ret = pa_memblockq_push(bq, &chunk4); assert(ret == 0); pa_memblockq_seek(bq, 10, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); pa_memblockq_seek(bq, -6, 0, TRUE); ret = pa_memblockq_push(bq, &chunk2); assert(ret == 0); /* Test splitting */ pa_memblockq_seek(bq, -12, 0, TRUE); ret = pa_memblockq_push(bq, &chunk1); assert(ret == 0); pa_memblockq_seek(bq, 20, 0, TRUE); /* Test merging */ ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); pa_memblockq_seek(bq, -2, 0, TRUE); chunk3.index += 2; chunk3.length -= 2; ret = pa_memblockq_push(bq, &chunk3); assert(ret == 0); pa_memblockq_seek(bq, 30, PA_SEEK_RELATIVE, TRUE); dump(bq); pa_memblockq_rewind(bq, 52); dump(bq); pa_memblockq_free(bq); pa_memblock_unref(silence.memblock); pa_memblock_unref(chunk1.memblock); pa_memblock_unref(chunk2.memblock); pa_memblock_unref(chunk3.memblock); pa_memblock_unref(chunk4.memblock); pa_mempool_free(p); return 0; }