summaryrefslogtreecommitdiffstats
path: root/src/modules/module-device-restore.c
diff options
context:
space:
mode:
authorColin Guthrie <colin@mageia.org>2011-06-07 23:21:04 +0100
committerColin Guthrie <colin@mageia.org>2011-06-22 22:47:55 +0100
commit695d5363803b7051f85bef82b55220aa37b212a5 (patch)
tree674945ffeec9d803e62bbad9dae31385d35a64ee /src/modules/module-device-restore.c
parentec4fa4c668a61de8ed7c9452e73919ba0bb1a870 (diff)
database: Convert our use of database files to save in tagstruct format.
This has the advantage of allowing versioned updates in the future, thus allowing us to be more user friendly going forward (as opposed to just ignoring entries from old versions). The primary motivation for this, however, is to allow variable length storage in each entry which will be needed for upcoming work. At present this commit will ignore any legacy entries but support for reading and subsequently converting legacy entries will be added shortly.
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);