[pulseaudio-discuss] [PATCH v3 09/11] logind: Add seat tracking
Tanu Kaskinen
tanu.kaskinen at linux.intel.com
Thu Dec 4 10:44:52 PST 2014
When running a user PulseAudio instance on top of the system instance,
seat tracking will be useful for filtering out devices in the system
instance that belong to some other user.
---
src/modules/logind/logind.c | 107 ++++++++++++++++++++++++++++++++++++++++++++
src/modules/logind/logind.h | 13 +++++-
2 files changed, 118 insertions(+), 2 deletions(-)
diff --git a/src/modules/logind/logind.c b/src/modules/logind/logind.c
index 1b6923f..99e6eff 100644
--- a/src/modules/logind/logind.c
+++ b/src/modules/logind/logind.c
@@ -30,9 +30,71 @@
#include <pulsecore/dynarray.h>
#include <pulsecore/shared.h>
+static void seat_new(pa_logind *logind, const char *id);
+static void seat_free(pa_logind_seat *seat);
+
static void session_new(pa_logind *logind, const char *id);
static void session_free(pa_logind_session *session);
+static void get_seats(pa_logind *logind) {
+ int r;
+ char **seats;
+ pa_hashmap *old_seats;
+ pa_logind_seat *seat;
+ void *state;
+ pa_dynarray *new_ids;
+ char *id;
+
+ pa_assert(logind);
+
+ r = sd_uid_get_seats(getuid(), 0, &seats);
+ if (r < 0) {
+ pa_log("sd_uid_get_seats() failed: %s", pa_cstrerror(r));
+ return;
+ }
+
+ /* When we iterate over the new seats, we drop the encountered seats from
+ * old_seats. The seats that remain in old_seats in the end will be
+ * removed. */
+ old_seats = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) seat_free);
+ PA_HASHMAP_FOREACH(seat, logind->seats, state)
+ pa_hashmap_put(old_seats, seat->id, seat);
+
+ new_ids = pa_dynarray_new(NULL);
+
+ if (seats) {
+ char **s;
+
+ /* Note that the seats array is allocated with libc's malloc()/free()
+ * calls, hence do not use pa_xfree() to free this here. */
+
+ for (s = seats; *s; s++) {
+ seat = pa_hashmap_remove(old_seats, *s);
+ if (seat)
+ pa_hashmap_put(logind->seats, seat->id, seat);
+ else {
+ /* We don't create the seat yet, because creating the seat
+ * fires a hook, and we want to postpone firing any hooks until
+ * the seats hashmap is fully updated. */
+ pa_dynarray_append(new_ids, pa_xstrdup(*s));
+ }
+
+ free(*s);
+ }
+
+ free(seats);
+ }
+
+ pa_hashmap_free(old_seats);
+
+ while ((id = pa_dynarray_steal_last(new_ids))) {
+ seat_new(logind, id);
+ pa_xfree(id);
+ }
+
+ pa_dynarray_free(new_ids);
+}
+
static void get_sessions(pa_logind *logind) {
int r;
char **sessions;
@@ -100,6 +162,7 @@ static void monitor_cb(pa_mainloop_api *api, pa_io_event* event, int fd, pa_io_e
pa_assert(logind);
sd_login_monitor_flush(logind->monitor);
+ get_seats(logind);
get_sessions(logind);
}
@@ -115,6 +178,7 @@ static void set_up_monitor(pa_logind *logind) {
pa_log("sd_login_monitor_new() failed: %s", pa_cstrerror(r));
return;
}
+ logind->monitor = monitor;
logind->monitor_event = logind->core->mainloop->io_new(logind->core->mainloop, sd_login_monitor_get_fd(monitor),
PA_IO_EVENT_INPUT, monitor_cb, logind);
@@ -142,6 +206,7 @@ static pa_logind *logind_new(pa_core *core) {
logind = pa_xnew0(pa_logind, 1);
logind->core = core;
+ logind->seats = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
logind->sessions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
logind->refcnt = 1;
@@ -153,6 +218,7 @@ static pa_logind *logind_new(pa_core *core) {
goto finish;
set_up_monitor(logind);
+ get_seats(logind);
get_sessions(logind);
finish:
@@ -175,6 +241,13 @@ static void logind_free(pa_logind *logind) {
session_free(session);
}
+ if (logind->seats) {
+ pa_logind_seat *seat;
+
+ while ((seat = pa_hashmap_first(logind->seats)))
+ seat_free(seat);
+ }
+
tear_down_monitor(logind);
for (i = 0; i < PA_LOGIND_HOOK_MAX; i++)
@@ -185,6 +258,11 @@ static void logind_free(pa_logind *logind) {
pa_hashmap_free(logind->sessions);
}
+ if (logind->seats) {
+ pa_assert(pa_hashmap_isempty(logind->seats));
+ pa_hashmap_free(logind->seats);
+ }
+
pa_xfree(logind);
}
@@ -212,6 +290,35 @@ void pa_logind_unref(pa_logind *logind) {
logind_free(logind);
}
+static void seat_new(pa_logind *logind, const char *id) {
+ pa_logind_seat *seat;
+
+ pa_assert(logind);
+ pa_assert(id);
+
+ seat = pa_xnew0(pa_logind_seat, 1);
+ seat->logind = logind;
+ seat->id = pa_xstrdup(id);
+
+ pa_assert_se(pa_hashmap_put(logind->seats, seat->id, seat) >= 0);
+
+ pa_log_debug("Created seat %s.", seat->id);
+
+ pa_hook_fire(&logind->hooks[PA_LOGIND_HOOK_SEAT_ADDED], seat);
+}
+
+static void seat_free(pa_logind_seat *seat) {
+ pa_assert(seat);
+
+ pa_log_debug("Freeing seat %s.", seat->id);
+
+ if (pa_hashmap_remove(seat->logind->seats, seat->id))
+ pa_hook_fire(&seat->logind->hooks[PA_LOGIND_HOOK_SEAT_REMOVED], seat);
+
+ pa_xfree(seat->id);
+ pa_xfree(seat);
+}
+
static void session_new(pa_logind *logind, const char *id) {
pa_logind_session *session;
diff --git a/src/modules/logind/logind.h b/src/modules/logind/logind.h
index 49ef9cf..a3f6f32 100644
--- a/src/modules/logind/logind.h
+++ b/src/modules/logind/logind.h
@@ -27,18 +27,22 @@
#include <systemd/sd-login.h>
typedef struct pa_logind pa_logind;
+typedef struct pa_logind_seat pa_logind_seat;
typedef struct pa_logind_session pa_logind_session;
enum {
+ PA_LOGIND_HOOK_SEAT_ADDED,
+ PA_LOGIND_HOOK_SEAT_REMOVED,
PA_LOGIND_HOOK_SESSION_ADDED,
PA_LOGIND_HOOK_SESSION_REMOVED,
PA_LOGIND_HOOK_MAX,
};
-/* Currently pa_logind doesn't track all sessions in the system, only those
- * that belong to the current user. */
+/* Currently pa_logind doesn't track all seats and sessions in the system, only
+ * those that belong to the current user. */
struct pa_logind {
pa_core *core;
+ pa_hashmap *seats; /* id -> pa_logind_seat */
pa_hashmap *sessions; /* id -> pa_logind_session */
pa_hook hooks[PA_LOGIND_HOOK_MAX];
@@ -50,6 +54,11 @@ struct pa_logind {
pa_logind *pa_logind_get(pa_core *core);
void pa_logind_unref(pa_logind *logind);
+struct pa_logind_seat {
+ pa_logind *logind;
+ char *id;
+};
+
struct pa_logind_session {
pa_logind *logind;
char *id;
--
1.9.3
More information about the pulseaudio-discuss
mailing list