static void append_port_list(pa_strbuf *s, pa_hashmap *ports) { pa_device_port *p; void *state; if (!ports) return; pa_strbuf_puts(s, "\tports:\n"); PA_HASHMAP_FOREACH(p, ports, state) pa_strbuf_printf(s, "\t\t%s: %s (priority %u, available: %s)\n", p->name, p->description, p->priority, port_available_to_string(p->available)); }
static void inotify_cb( pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata) { struct { struct inotify_event e; char name[NAME_MAX]; } buf; struct userdata *u = userdata; static int type = 0; bool deleted = false; struct device *d; void *state; for (;;) { ssize_t r; struct inotify_event *event; pa_zero(buf); if ((r = pa_read(fd, &buf, sizeof(buf), &type)) <= 0) { if (r < 0 && errno == EAGAIN) break; pa_log("read() from inotify failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF"); goto fail; } event = &buf.e; while (r > 0) { size_t len; if ((size_t) r < sizeof(struct inotify_event)) { pa_log("read() too short."); goto fail; } len = sizeof(struct inotify_event) + event->len; if ((size_t) r < len) { pa_log("Payload missing."); goto fail; } /* From udev we get the guarantee that the control * device's ACL is changed last. To avoid races when ACLs * are changed we hence watch only the control device */ if (((event->mask & IN_ATTRIB) && pa_startswith(event->name, "controlC"))) PA_HASHMAP_FOREACH(d, u->devices, state) if (control_node_belongs_to_device(d, event->name)) d->need_verify = true; /* ALSA doesn't really give us any guarantee on the closing * order, so let's simply hope */ if (((event->mask & IN_CLOSE_WRITE) && pa_startswith(event->name, "pcmC"))) PA_HASHMAP_FOREACH(d, u->devices, state) if (pcm_node_belongs_to_device(d, event->name)) d->need_verify = true; /* /dev/snd/ might have been removed */ if ((event->mask & (IN_DELETE_SELF|IN_MOVE_SELF))) deleted = true; event = (struct inotify_event*) ((uint8_t*) event + len); r -= len; } } PA_HASHMAP_FOREACH(d, u->devices, state) if (d->need_verify) { d->need_verify = false; verify_access(u, d); } if (!deleted) return; fail: if (u->inotify_io) { a->io_free(u->inotify_io); u->inotify_io = NULL; } if (u->inotify_fd >= 0) { pa_close(u->inotify_fd); u->inotify_fd = -1; } }
char *pa_card_list_to_string(pa_core *c) { pa_strbuf *s; pa_card *card; uint32_t idx = PA_IDXSET_INVALID; pa_assert(c); s = pa_strbuf_new(); pa_strbuf_printf(s, "%u card(s) available.\n", pa_idxset_size(c->cards)); for (card = pa_idxset_first(c->cards, &idx); card; card = pa_idxset_next(c->cards, &idx)) { char *t; pa_sink *sink; pa_source *source; uint32_t sidx; pa_strbuf_printf( s, " index: %u\n" "\tname: <%s>\n" "\tdriver: <%s>\n", card->index, card->name, card->driver); if (card->module) pa_strbuf_printf(s, "\towner module: %u\n", card->module->index); t = pa_proplist_to_string_sep(card->proplist, "\n\t\t"); pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t); pa_xfree(t); if (card->profiles) { pa_card_profile *p; void *state; pa_strbuf_puts(s, "\tprofiles:\n"); PA_HASHMAP_FOREACH(p, card->profiles, state) pa_strbuf_printf(s, "\t\t%s: %s (priority %u)\n", p->name, p->description, p->priority); } if (card->active_profile) pa_strbuf_printf( s, "\tactive profile: <%s>\n", card->active_profile->name); if (!pa_idxset_isempty(card->sinks)) { pa_strbuf_puts(s, "\tsinks:\n"); for (sink = pa_idxset_first(card->sinks, &sidx); sink; sink = pa_idxset_next(card->sinks, &sidx)) pa_strbuf_printf(s, "\t\t%s/#%u: %s\n", sink->name, sink->index, pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION))); } if (!pa_idxset_isempty(card->sources)) { pa_strbuf_puts(s, "\tsources:\n"); for (source = pa_idxset_first(card->sources, &sidx); source; source = pa_idxset_next(card->sources, &sidx)) pa_strbuf_printf(s, "\t\t%s/#%u: %s\n", source->name, source->index, pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION))); } append_port_list(s, card->ports); } return pa_strbuf_tostring_free(s); }