static pa_hook_result_t sink_input_state_changed_hook_cb(pa_core *c, pa_sink_input *s, struct userdata *u) { struct device_info *d; pa_sink_input_state_t state; pa_assert(c); pa_sink_input_assert_ref(s); pa_assert(u); state = pa_sink_input_get_state(s); if (state == PA_SINK_INPUT_RUNNING || state == PA_SINK_INPUT_DRAINED) if ((d = pa_hashmap_get(u->device_infos, s->sink))) resume(d); return PA_HOOK_OK; }
char *pa_sink_input_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink_input *i; uint32_t idx = PA_IDXSET_INVALID; static const char* const state_table[] = { [PA_SINK_INPUT_RUNNING] = "RUNNING", [PA_SINK_INPUT_DRAINED] = "DRAINED", [PA_SINK_INPUT_CORKED] = "CORKED", [PA_SINK_INPUT_UNLINKED] = "UNLINKED" }; pa_assert(c); s = pa_strbuf_new(); pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_assert(i->sink); pa_strbuf_printf( s, " index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" "\tflags: %s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsink: <%u> '%s'\n" "\tvolume: <%s>\n" "\tmute: <%i>\n" "\tlatency: <%0.0f usec>\n" "\tsample spec: <%s>\n" "\tchannel map: <%s>\n" "\tresample method: %s\n", i->index, i->name, i->driver, i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "", i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "", i->flags & PA_SINK_INPUT_NO_REMAP ? "NO_REMAP " : "", i->flags & PA_SINK_INPUT_NO_REMIX ? "NO_REMIX " : "", i->flags & PA_SINK_INPUT_FIX_FORMAT ? "FIX_FORMAT " : "", i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "", i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", state_table[pa_sink_input_get_state(i)], i->sink->index, i->sink->name, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), !!pa_sink_input_get_mute(i), (double) pa_sink_input_get_latency(i), pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); if (i->module) pa_strbuf_printf(s, "\tmodule: <%u>\n", i->module->index); if (i->client) pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name); } return pa_strbuf_tostring_free(s); }
char *pa_sink_input_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink_input *i; uint32_t idx = PA_IDXSET_INVALID; static const char* const state_table[] = { [PA_SINK_INPUT_INIT] = "INIT", [PA_SINK_INPUT_RUNNING] = "RUNNING", [PA_SINK_INPUT_DRAINED] = "DRAINED", [PA_SINK_INPUT_CORKED] = "CORKED", [PA_SINK_INPUT_UNLINKED] = "UNLINKED" }; pa_assert(c); s = pa_strbuf_new(); pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28]; pa_usec_t cl; const char *cmn; pa_cvolume v; char *volume_str = NULL; cmn = pa_channel_map_to_pretty_name(&i->channel_map); if ((cl = pa_sink_input_get_requested_latency(i)) == (pa_usec_t) -1) pa_snprintf(clt, sizeof(clt), "n/a"); else pa_snprintf(clt, sizeof(clt), "%0.2f ms", (double) cl / PA_USEC_PER_MSEC); pa_assert(i->sink); if (pa_sink_input_is_volume_readable(i)) { pa_sink_input_get_volume(i, &v, TRUE); volume_str = pa_sprintf_malloc("%s\n\t %s\n\t balance %0.2f", pa_cvolume_snprint(cv, sizeof(cv), &v), pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v), pa_cvolume_get_balance(&v, &i->channel_map)); } else volume_str = pa_xstrdup("n/a"); pa_strbuf_printf( s, " index: %u\n" "\tdriver: <%s>\n" "\tflags: %s%s%s%s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsink: %u <%s>\n" "\tvolume: %s\n" "\tmuted: %s\n" "\tcurrent latency: %0.2f ms\n" "\trequested latency: %s\n" "\tsample spec: %s\n" "\tchannel map: %s%s%s\n" "\tresample method: %s\n", i->index, i->driver, i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "", i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "", i->flags & PA_SINK_INPUT_START_CORKED ? "START_CORKED " : "", i->flags & PA_SINK_INPUT_NO_REMAP ? "NO_REMAP " : "", i->flags & PA_SINK_INPUT_NO_REMIX ? "NO_REMIX " : "", i->flags & PA_SINK_INPUT_FIX_FORMAT ? "FIX_FORMAT " : "", i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "", i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "", i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "", i->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_SUSPEND " : "", i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "", state_table[pa_sink_input_get_state(i)], i->sink->index, i->sink->name, volume_str, pa_yes_no(pa_sink_input_get_mute(i)), (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC, clt, pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), cmn ? "\n\t " : "", cmn ? cmn : "", pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); pa_xfree(volume_str); if (i->module) pa_strbuf_printf(s, "\tmodule: %u\n", i->module->index); if (i->client) pa_strbuf_printf(s, "\tclient: %u <%s>\n", i->client->index, pa_strnull(pa_proplist_gets(i->client->proplist, PA_PROP_APPLICATION_NAME))); t = pa_proplist_to_string_sep(i->proplist, "\n\t\t"); pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t); pa_xfree(t); } return pa_strbuf_tostring_free(s); }
/* 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; }