void voice_source_outputs_may_move(pa_source *s, pa_bool_t move) { pa_source_output *i; uint32_t idx; for (i = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); i; i = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) { if (move) i->flags &= ~PA_SOURCE_OUTPUT_DONT_MOVE; else i->flags |= PA_SOURCE_OUTPUT_DONT_MOVE; } }
static pa_hook_result_t process(struct userdata *u, pa_object *o, pa_bool_t is_sink_input) { const char *want; pa_proplist *pl, *parent_pl; if (is_sink_input) { pl = PA_SINK_INPUT(o)->proplist; parent_pl = PA_SINK_INPUT(o)->sink->proplist; } else { pl = PA_SOURCE_OUTPUT(o)->proplist; parent_pl = PA_SOURCE_OUTPUT(o)->source->proplist; } /* If the stream already specifies what it must have, then let it be. */ if (!pa_proplist_gets(pl, PA_PROP_FILTER_HEURISTICS) && pa_proplist_gets(pl, PA_PROP_FILTER_APPLY)) return PA_HOOK_OK; /* On phone sinks, make sure we're not applying echo cancellation */ if (pa_str_in_list_spaces(pa_proplist_gets(parent_pl, PA_PROP_DEVICE_INTENDED_ROLES), "phone")) { const char *apply = pa_proplist_gets(pl, PA_PROP_FILTER_APPLY); if (apply && pa_streq(apply, "echo-cancel")) { pa_proplist_unset(pl, PA_PROP_FILTER_APPLY); pa_proplist_unset(pl, PA_PROP_FILTER_HEURISTICS); } return PA_HOOK_OK; } want = pa_proplist_gets(pl, PA_PROP_FILTER_WANT); if (want) { /* There's a filter that we want, ask module-filter-apply to apply it, and remember that we're managing filter.apply */ pa_proplist_sets(pl, PA_PROP_FILTER_APPLY, want); pa_proplist_sets(pl, PA_PROP_FILTER_HEURISTICS, "1"); } return PA_HOOK_OK; }
/* Called from I/O thread context */ static int source_output_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u; pa_assert_se(u = PA_SOURCE_OUTPUT(o)->userdata); switch (code) { case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY: *((pa_usec_t*) data) = pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &u->source_output->sample_spec); /* Fall through, the default handler will add in the extra * latency added by the resampler */ break; } return pa_source_output_process_msg(o, code, data, offset, chunk); }
/* Called from IO thread context, except when it is not */ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk* chunk) { pa_source_output *o = PA_SOURCE_OUTPUT(mo); pa_source_output_assert_ref(o); switch (code) { case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY: { pa_usec_t *r = userdata; r[0] += pa_bytes_to_usec(pa_memblockq_get_length(o->thread_info.delay_memblockq), &o->source->sample_spec); r[1] += pa_source_get_latency_within_thread(o->source); return 0; } case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE: o->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata); pa_resampler_set_output_rate(o->thread_info.resampler, PA_PTR_TO_UINT(userdata)); return 0; case PA_SOURCE_OUTPUT_MESSAGE_SET_STATE: pa_source_output_set_state_within_thread(o, PA_PTR_TO_UINT(userdata)); return 0; case PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY: { pa_usec_t *usec = userdata; *usec = pa_source_output_set_requested_latency_within_thread(o, *usec); return 0; } case PA_SOURCE_OUTPUT_MESSAGE_GET_REQUESTED_LATENCY: { pa_usec_t *r = userdata; *r = o->thread_info.requested_source_latency; return 0; } } return -PA_ERR_NOTIMPLEMENTED; }
/* Called from output thread context */ static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata; switch (code) { case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: { size_t length; length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq); u->latency_snapshot.send_counter = u->send_counter; u->latency_snapshot.source_output_buffer = u->source_output->thread_info.resampler ? pa_resampler_result(u->source_output->thread_info.resampler, length) : length; u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source); return 0; } } return pa_source_output_process_msg(obj, code, data, offset, chunk); }
/* Called from output thread context */ static int source_output_process_msg_cb(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SOURCE_OUTPUT(obj)->userdata; switch (code) { case SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT: { size_t length; length = pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq); u->latency_snapshot.send_counter = u->send_counter; /* Add content of delay memblockq to the source latency */ u->latency_snapshot.source_latency = pa_source_get_latency_within_thread(u->source_output->source) + pa_bytes_to_usec(length, &u->source_output->source->sample_spec); u->latency_snapshot.source_timestamp = pa_rtclock_now(); return 0; } } return pa_source_output_process_msg(obj, code, data, offset, chunk); }
/* 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); }