summaryrefslogtreecommitdiffstats
path: root/src/modules/module-device-restore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/module-device-restore.c')
-rw-r--r--src/modules/module-device-restore.c191
1 files changed, 130 insertions, 61 deletions
diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c
index 4c31a985..4ef8a24b 100644
--- a/src/modules/module-device-restore.c
+++ b/src/modules/module-device-restore.c
@@ -47,6 +47,7 @@
#include <pulsecore/source-output.h>
#include <pulsecore/namereg.h>
#include <pulsecore/database.h>
+#include <pulsecore/tagstruct.h>
#include "module-device-restore-symdef.h"
@@ -85,16 +86,16 @@ struct userdata {
pa_bool_t restore_port:1;
};
-#define ENTRY_VERSION 2
+#define ENTRY_VERSION 3
struct entry {
uint8_t version;
- pa_bool_t muted_valid:1, volume_valid:1, port_valid:1;
- pa_bool_t muted:1;
+ pa_bool_t muted_valid, volume_valid, port_valid;
+ pa_bool_t muted;
pa_channel_map channel_map;
pa_cvolume volume;
- char port[PA_NAME_MAX];
-} PA_GCC_PACKED;
+ char *port;
+};
static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
struct userdata *u = userdata;
@@ -111,9 +112,24 @@ static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct
pa_log_info("Synced.");
}
-static struct entry* read_entry(struct userdata *u, const char *name) {
+static struct entry* entry_new(void) {
+ struct entry *r = pa_xnew0(struct entry, 1);
+ r->version = ENTRY_VERSION;
+ return r;
+}
+
+static void entry_free(struct entry* e) {
+ pa_assert(e);
+
+ pa_xfree(e->port);
+ pa_xfree(e);
+}
+
+static struct entry* entry_read(struct userdata *u, const char *name) {
pa_datum key, data;
- struct entry *e;
+ struct entry *e = NULL;
+ pa_tagstruct *t = NULL;
+ const char* port;
pa_assert(u);
pa_assert(name);
@@ -126,22 +142,26 @@ static struct entry* read_entry(struct userdata *u, const char *name) {
if (!pa_database_get(u->database, &key, &data))
goto fail;
- if (data.size != sizeof(struct entry)) {
- pa_log_debug("Database contains entry for device %s of wrong size %lu != %lu. Probably due to upgrade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry));
- goto fail;
- }
+ t = pa_tagstruct_new(data.data, data.size);
+ e = entry_new();
- e = (struct entry*) data.data;
+ if (pa_tagstruct_getu8(t, &e->version) < 0 ||
+ e->version > ENTRY_VERSION ||
+ pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
+ pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
+ pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
+ pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
+ pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
+ pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
+ pa_tagstruct_gets(t, &port) < 0) {
- if (e->version != ENTRY_VERSION) {
- pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name);
goto fail;
}
- if (!memchr(e->port, 0, sizeof(e->port))) {
- pa_log_warn("Database contains entry for device %s with missing NUL byte in port name", name);
+ e->port = pa_xstrdup(port);
+
+ if (!pa_tagstruct_eof(t))
goto fail;
- }
if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
pa_log_warn("Invalid channel map stored in database for device %s", name);
@@ -153,14 +173,64 @@ static struct entry* read_entry(struct userdata *u, const char *name) {
goto fail;
}
+ pa_tagstruct_free(t);
+ pa_datum_free(&data);
+
return e;
fail:
+ pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
+
+ if (e)
+ entry_free(e);
+ if (t)
+ pa_tagstruct_free(t);
pa_datum_free(&data);
return NULL;
}
+static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e) {
+ pa_tagstruct *t;
+ pa_datum key, data;
+ pa_bool_t r;
+
+ pa_assert(u);
+ pa_assert(name);
+ pa_assert(e);
+
+ t = pa_tagstruct_new(NULL, 0);
+ pa_tagstruct_putu8(t, e->version);
+ pa_tagstruct_put_boolean(t, e->volume_valid);
+ pa_tagstruct_put_channel_map(t, &e->channel_map);
+ pa_tagstruct_put_cvolume(t, &e->volume);
+ pa_tagstruct_put_boolean(t, e->muted_valid);
+ pa_tagstruct_put_boolean(t, e->muted);
+ pa_tagstruct_put_boolean(t, e->port_valid);
+ pa_tagstruct_puts(t, e->port);
+
+ key.data = (char *) name;
+ key.size = strlen(name);
+
+ data.data = (void*)pa_tagstruct_data(t, &data.size);
+
+ r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
+
+ pa_tagstruct_free(t);
+
+ return r;
+}
+
+static struct entry* entry_copy(const struct entry *e) {
+ struct entry* r;
+
+ pa_assert(e);
+ r = entry_new();
+ *r = *e;
+ r->port = pa_xstrdup(e->port);
+ return r;
+}
+
static void trigger_save(struct userdata *u) {
if (u->save_time_event)
return;
@@ -172,7 +242,7 @@ static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
pa_cvolume t;
if (a->port_valid != b->port_valid ||
- (a->port_valid && strncmp(a->port, b->port, sizeof(a->port))))
+ (a->port_valid && !pa_streq(a->port, b->port)))
return FALSE;
if (a->muted_valid != b->muted_valid ||
@@ -189,9 +259,8 @@ static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
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;
+ struct entry *entry, *old;
char *name;
- pa_datum key, data;
pa_assert(c);
pa_assert(u);
@@ -202,9 +271,6 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
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;
@@ -213,23 +279,26 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
name = pa_sprintf_malloc("sink:%s", sink->name);
- if ((old = read_entry(u, name)))
- entry = *old;
+ if ((old = entry_read(u, name)))
+ entry = entry_copy(old);
+ else
+ entry = entry_new();
if (sink->save_volume) {
- entry.channel_map = sink->channel_map;
- entry.volume = *pa_sink_get_volume(sink, FALSE);
- entry.volume_valid = TRUE;
+ 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;
+ 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;
+ pa_xfree(entry->port);
+ entry->port = pa_xstrdup(sink->active_port ? sink->active_port->name : "");
+ entry->port_valid = TRUE;
}
} else {
@@ -242,50 +311,50 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3
name = pa_sprintf_malloc("source:%s", source->name);
- if ((old = read_entry(u, name)))
- entry = *old;
+ if ((old = entry_read(u, name)))
+ entry = entry_copy(old);
+ else
+ entry = entry_new();
if (source->save_volume) {
- entry.channel_map = source->channel_map;
- entry.volume = *pa_source_get_volume(source, FALSE);
- entry.volume_valid = TRUE;
+ 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;
+ 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;
+ pa_xfree(entry->port);
+ entry->port = pa_xstrdup(source->active_port ? source->active_port->name : "");
+ entry->port_valid = TRUE;
}
}
+ pa_assert(entry);
+
if (old) {
- if (entries_equal(old, &entry)) {
- pa_xfree(old);
+ if (entries_equal(old, entry)) {
+ entry_free(old);
+ entry_free(entry);
pa_xfree(name);
return;
}
- pa_xfree(old);
+ entry_free(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);
+ if (entry_write(u, name, entry))
+ trigger_save(u);
+ entry_free(entry);
pa_xfree(name);
-
- trigger_save(u);
}
static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
@@ -299,7 +368,7 @@ static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new
name = pa_sprintf_malloc("sink:%s", new_data->name);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
if (e->port_valid) {
if (!new_data->active_port) {
@@ -310,7 +379,7 @@ static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new
pa_log_debug("Not restoring port for sink %s, because already set.", name);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
@@ -329,7 +398,7 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *
name = pa_sprintf_malloc("sink:%s", new_data->name);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
if (u->restore_volume && e->volume_valid) {
@@ -357,7 +426,7 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *
pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
@@ -376,7 +445,7 @@ static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data
name = pa_sprintf_malloc("source:%s", new_data->name);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
if (e->port_valid) {
if (!new_data->active_port) {
@@ -387,7 +456,7 @@ static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data
pa_log_debug("Not restoring port for source %s, because already set.", name);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);
@@ -406,7 +475,7 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da
name = pa_sprintf_malloc("source:%s", new_data->name);
- if ((e = read_entry(u, name))) {
+ if ((e = entry_read(u, name))) {
if (u->restore_volume && e->volume_valid) {
@@ -434,7 +503,7 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da
pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
}
- pa_xfree(e);
+ entry_free(e);
}
pa_xfree(name);