[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