char *pa_sink_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink *sink; uint32_t idx = PA_IDXSET_INVALID; static const char* const state_table[] = { [PA_SINK_RUNNING] = "RUNNING", [PA_SINK_SUSPENDED] = "SUSPENDED", [PA_SINK_IDLE] = "IDLE", [PA_SINK_UNLINKED] = "UNLINKED" }; pa_assert(c); s = pa_strbuf_new(); pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_strbuf_printf( s, " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" "\tflags: %s%s%s%s\n" "\tstate: %s\n" "\tvolume: <%s>\n" "\tmute: <%i>\n" "\tlatency: <%0.0f usec>\n" "\tmonitor source: <%u>\n" "\tsample spec: <%s>\n" "\tchannel map: <%s>\n" "\tused by: <%u>\n" "\tlinked by: <%u>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, sink->driver, sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", sink->flags & PA_SINK_LATENCY ? "LATENCY " : "", sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "", sink->flags & PA_SINK_NETWORK ? "NETWORK " : "", state_table[pa_sink_get_state(sink)], pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink)), !!pa_sink_get_mute(sink), (double) pa_sink_get_latency(sink), sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map), pa_sink_used_by(sink), pa_sink_linked_by(sink)); if (sink->module) pa_strbuf_printf(s, "\tmodule: <%u>\n", sink->module->index); if (sink->description) pa_strbuf_printf(s, "\tdescription: <%s>\n", sink->description); } return pa_strbuf_tostring_free(s); }
static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) { struct userdata *u = userdata; assert(u); if (u->sink) { pa_sink_get_volume(u->sink); pa_sink_get_mute(u->sink); } if (u->source) pa_source_get_volume(u->source); }
static void sink_subscribe_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = (struct userdata *)userdata; if (t == PA_SUBSCRIPTION_EVENT_CHANGE) { pa_sink *sink = PA_SINK(pa_idxset_get_by_index(c->sinks, idx)); if (sink) { if (u->master_sink == sink) { const pa_cvolume *vol = pa_sink_get_volume(sink, 0, 0); int aep_step; u->linear_q15_master_volume_L = lrint(pa_sw_volume_to_linear(vol->values[0]) * 32767.0); if (vol->channels == 1) u->linear_q15_master_volume_R = lrint(pa_sw_volume_to_linear(vol->values[0]) * 32767.0); else u->linear_q15_master_volume_R = lrint(pa_sw_volume_to_linear(vol->values[1]) * 32767.0); aep_step = voice_pa_vol_to_aep_step(u, vol->values[0]); if (voice_cmt_ul_is_active_iothread(u) || (u->voip_source && PA_SOURCE_IS_LINKED(u->voip_source->state) && pa_source_used_by(u->voip_source))) { if (aep_step <= 0) { voice_update_aep_volume(0); voice_update_sidetone_gain(0); } else { voice_update_aep_volume(aep_step - 1); voice_update_sidetone_gain(aep_step - 1); } } xprot_change_volume(u->xprot, u->linear_q15_master_volume_L, u->linear_q15_master_volume_R); } } } }
static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; pa_assert(io); pa_assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { pa_log("Lost connection to LIRC daemon."); goto fail; } if (events & PA_IO_EVENT_INPUT) { char *c; if (lirc_nextcode(&code) != 0 || !code) { pa_log("lirc_nextcode() failed."); goto fail; } c = pa_xstrdup(code); c[strcspn(c, "\n\r")] = 0; pa_log_debug("Raw IR code '%s'", c); pa_xfree(c); while (lirc_code2char(u->config, code, &name) == 0 && name) { enum { INVALID, UP, DOWN, MUTE, RESET, MUTE_TOGGLE } volchange = INVALID; pa_log_info("Translated IR code '%s'", name); if (strcasecmp(name, "volume-up") == 0) volchange = UP; else if (strcasecmp(name, "volume-down") == 0) volchange = DOWN; else if (strcasecmp(name, "mute") == 0) volchange = MUTE; else if (strcasecmp(name, "mute-toggle") == 0) volchange = MUTE_TOGGLE; else if (strcasecmp(name, "reset") == 0) volchange = RESET; if (volchange == INVALID) pa_log_warn("Received unknown IR code '%s'", name); else { pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK))) pa_log("Failed to get sink '%s'", u->sink_name); else { pa_cvolume cv = *pa_sink_get_volume(s, FALSE); switch (volchange) { case UP: pa_cvolume_inc_clamp(&cv, u->volume_step, u->volume_limit); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case DOWN: pa_cvolume_dec(&cv, u->volume_step); pa_sink_set_volume(s, &cv, TRUE, TRUE); break; case MUTE: pa_sink_set_mute(s, TRUE, TRUE); break; case RESET: pa_sink_set_mute(s, FALSE, TRUE); break; case MUTE_TOGGLE: pa_sink_set_mute(s, !pa_sink_get_mute(s, FALSE), TRUE); break; case INVALID: pa_assert_not_reached(); } } } } } pa_xfree(code); return; fail: u->module->core->mainloop->io_free(u->io); u->io = NULL; pa_module_unload_request(u->module, TRUE); pa_xfree(code); }
static void io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; pa_assert(io); pa_assert(u); if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { pa_log("Lost connection to evdev device."); goto fail; } if (events & PA_IO_EVENT_INPUT) { struct input_event ev; if (pa_loop_read(u->fd, &ev, sizeof(ev), &u->fd_type) <= 0) { pa_log("Failed to read from event device: %s", pa_cstrerror(errno)); goto fail; } if (ev.type == EV_KEY && (ev.value == 1 || ev.value == 2)) { enum { INVALID, UP, DOWN, MUTE_TOGGLE } volchange = INVALID; pa_log_debug("Key code=%u, value=%u", ev.code, ev.value); switch (ev.code) { case KEY_VOLUMEDOWN: volchange = DOWN; break; case KEY_VOLUMEUP: volchange = UP; break; case KEY_MUTE: volchange = MUTE_TOGGLE; break; } if (volchange != INVALID) { pa_sink *s; if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK))) pa_log("Failed to get sink '%s'", u->sink_name); else { pa_cvolume cv = *pa_sink_get_volume(s, false); switch (volchange) { case UP: pa_cvolume_inc_clamp(&cv, u->volume_step, u->volume_limit); pa_sink_set_volume(s, &cv, true, true); break; case DOWN: pa_cvolume_dec(&cv, u->volume_step); pa_sink_set_volume(s, &cv, true, true); break; case MUTE_TOGGLE: pa_sink_set_mute(s, !pa_sink_get_mute(s, false), true); break; case INVALID: pa_assert_not_reached(); } } } } } return; fail: u->module->core->mainloop->io_free(u->io); u->io = NULL; pa_module_unload_request(u->module, true); }
char *pa_sink_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink *sink; uint32_t idx = PA_IDXSET_INVALID; pa_assert(c); s = pa_strbuf_new(); pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], v[PA_VOLUME_SNPRINT_MAX], vdb[PA_SW_VOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t; const char *cmn; cmn = pa_channel_map_to_pretty_name(&sink->channel_map); pa_strbuf_printf( s, " %c index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n" "\tflags: %s%s%s%s%s%s%s%s\n" "\tstate: %s\n" "\tsuspend cause: %s%s%s%s\n" "\tpriority: %u\n" "\tvolume: %s%s%s\n" "\t balance %0.2f\n" "\tbase volume: %s%s%s\n" "\tvolume steps: %u\n" "\tmuted: %s\n" "\tcurrent latency: %0.2f ms\n" "\tmax request: %lu KiB\n" "\tmax rewind: %lu KiB\n" "\tmonitor source: %u\n" "\tsample spec: %s\n" "\tchannel map: %s%s%s\n" "\tused by: %u\n" "\tlinked by: %u\n", sink == c->default_sink ? '*' : ' ', sink->index, sink->name, sink->driver, sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "", sink->flags & PA_SINK_NETWORK ? "NETWORK " : "", sink->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "", sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "", sink->flags & PA_SINK_LATENCY ? "LATENCY " : "", sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "", sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "", sink_state_to_string(pa_sink_get_state(sink)), sink->suspend_cause & PA_SUSPEND_USER ? "USER " : "", sink->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "", sink->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "", sink->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "", sink->priority, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "", pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map), pa_volume_snprint(v, sizeof(v), sink->base_volume), sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "", sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "", sink->n_volume_steps, pa_yes_no(pa_sink_get_mute(sink, FALSE)), (double) pa_sink_get_latency(sink) / (double) PA_USEC_PER_MSEC, (unsigned long) pa_sink_get_max_request(sink) / 1024, (unsigned long) pa_sink_get_max_rewind(sink) / 1024, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map), cmn ? "\n\t " : "", cmn ? cmn : "", pa_sink_used_by(sink), pa_sink_linked_by(sink)); if (sink->flags & PA_SINK_DYNAMIC_LATENCY) { pa_usec_t min_latency, max_latency; pa_sink_get_latency_range(sink, &min_latency, &max_latency); pa_strbuf_printf( s, "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n", (double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC, (double) min_latency / PA_USEC_PER_MSEC, (double) max_latency / PA_USEC_PER_MSEC); } else pa_strbuf_printf( s, "\tfixed latency: %0.2f ms\n", (double) pa_sink_get_fixed_latency(sink) / PA_USEC_PER_MSEC); if (sink->card) pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name); if (sink->module) pa_strbuf_printf(s, "\tmodule: %u\n", sink->module->index); t = pa_proplist_to_string_sep(sink->proplist, "\n\t\t"); pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t); pa_xfree(t); append_port_list(s, sink->ports); if (sink->active_port) pa_strbuf_printf( s, "\tactive port: <%s>\n", sink->active_port->name); } return pa_strbuf_tostring_free(s); }
static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = userdata; struct entry entry, *old; char *name; pa_datum key, data; pa_assert(c); pa_assert(u); if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) && t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) && t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) && t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE)) return; pa_zero(entry); entry.version = ENTRY_VERSION; if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) { pa_sink *sink; if (!(sink = pa_idxset_get_by_index(c->sinks, idx))) return; name = pa_sprintf_malloc("sink:%s", sink->name); if ((old = read_entry(u, name))) entry = *old; if (sink->save_volume) { entry.channel_map = sink->channel_map; entry.volume = *pa_sink_get_volume(sink, FALSE); entry.volume_valid = TRUE; } if (sink->save_muted) { entry.muted = pa_sink_get_mute(sink, FALSE); entry.muted_valid = TRUE; } if (sink->save_port) { pa_strlcpy(entry.port, sink->active_port ? sink->active_port->name : "", sizeof(entry.port)); entry.port_valid = TRUE; } } else { pa_source *source; pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE); if (!(source = pa_idxset_get_by_index(c->sources, idx))) return; name = pa_sprintf_malloc("source:%s", source->name); if ((old = read_entry(u, name))) entry = *old; if (source->save_volume) { entry.channel_map = source->channel_map; entry.volume = *pa_source_get_volume(source, FALSE); entry.volume_valid = TRUE; } if (source->save_muted) { entry.muted = pa_source_get_mute(source, FALSE); entry.muted_valid = TRUE; } if (source->save_port) { pa_strlcpy(entry.port, source->active_port ? source->active_port->name : "", sizeof(entry.port)); entry.port_valid = TRUE; } } if (old) { if (entries_equal(old, &entry)) { pa_xfree(old); pa_xfree(name); return; } pa_xfree(old); } key.data = name; key.size = strlen(name); data.data = &entry; data.size = sizeof(entry); pa_log_info("Storing volume/mute/port for device %s.", name); pa_database_set(u->database, &key, &data, TRUE); pa_xfree(name); trigger_save(u); }