diff options
Diffstat (limited to 'src/modules/module-device-restore.c')
| -rw-r--r-- | src/modules/module-device-restore.c | 76 | 
1 files changed, 48 insertions, 28 deletions
diff --git a/src/modules/module-device-restore.c b/src/modules/module-device-restore.c index c0d2ddb7..920b4517 100644 --- a/src/modules/module-device-restore.c +++ b/src/modules/module-device-restore.c @@ -1,7 +1,7 @@  /***    This file is part of PulseAudio. -  Copyright 2006 Lennart Poettering +  Copyright 2006-2008 Lennart Poettering    PulseAudio is free software; you can redistribute it and/or modify    it under the terms of the GNU Lesser General Public License as published @@ -64,6 +64,7 @@ static const char* const valid_modargs[] = {  struct userdata {      pa_core *core; +    pa_module *module;      pa_subscription *subscription;      pa_hook_slot          *sink_fixate_hook_slot, @@ -76,6 +77,7 @@ struct userdata {  };  struct entry { +    pa_channel_map channel_map;      pa_cvolume volume;      pa_bool_t muted:1;  }; @@ -104,7 +106,7 @@ static struct entry* read_entry(struct userdata *u, char *name) {      pa_assert(name);      key.dptr = name; -    key.dsize = strlen(name); +    key.dsize = (int) strlen(name);      data = gdbm_fetch(u->gdbm_file, key); @@ -123,6 +125,16 @@ static struct entry* read_entry(struct userdata *u, char *name) {          goto fail;      } +    if (!(pa_channel_map_valid(&e->channel_map))) { +        pa_log_warn("Invalid channel map stored in database for device %s", name); +        goto fail; +    } + +    if (e->volume.channels != e->channel_map.channels) { +        pa_log_warn("Volume and channel map don't match in database entry for device %s", name); +        goto fail; +    } +      return e;  fail: @@ -131,6 +143,17 @@ fail:      return NULL;  } +static void trigger_save(struct userdata *u) { +    struct timeval tv; + +    if (u->save_time_event) +        return; + +    pa_gettimeofday(&tv); +    tv.tv_sec += SAVE_INTERVAL; +    u->save_time_event = u->core->mainloop->time_new(u->core->mainloop, &tv, save_time_callback, u); +} +  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; @@ -146,6 +169,8 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3          t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))          return; +    memset(&entry, 0, sizeof(entry)); +      if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {          pa_sink *sink; @@ -153,8 +178,9 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3              return;          name = pa_sprintf_malloc("sink:%s", sink->name); -        entry.volume = *pa_sink_get_volume(sink); -        entry.muted = pa_sink_get_mute(sink); +        entry.channel_map = sink->channel_map; +        entry.volume = *pa_sink_get_volume(sink, FALSE); +        entry.muted = pa_sink_get_mute(sink, FALSE);      } else {          pa_source *source; @@ -165,13 +191,14 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3              return;          name = pa_sprintf_malloc("source:%s", source->name); -        entry.volume = *pa_source_get_volume(source); -        entry.muted = pa_source_get_mute(source); +        entry.channel_map = source->channel_map; +        entry.volume = *pa_source_get_volume(source, FALSE); +        entry.muted = pa_source_get_mute(source, FALSE);      }      if ((old = read_entry(u, name))) { -        if (pa_cvolume_equal(&old->volume, &entry.volume) && +        if (pa_cvolume_equal(pa_cvolume_remap(&old->volume, &old->channel_map, &entry.channel_map), &entry.volume) &&              !old->muted == !entry.muted) {              pa_xfree(old); @@ -183,7 +210,7 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3      }      key.dptr = name; -    key.dsize = strlen(name); +    key.dsize = (int) strlen(name);      data.dptr = (void*) &entry;      data.dsize = sizeof(entry); @@ -192,14 +219,9 @@ static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint3      gdbm_store(u->gdbm_file, key, data, GDBM_REPLACE); -    if (!u->save_time_event) { -        struct timeval tv; -        pa_gettimeofday(&tv); -        tv.tv_sec += SAVE_INTERVAL; -        u->save_time_event = u->core->mainloop->time_new(u->core->mainloop, &tv, save_time_callback, u); -    } -      pa_xfree(name); + +    trigger_save(u);  }  static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) { @@ -212,11 +234,9 @@ static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *      if ((e = read_entry(u, name))) { -        if (u->restore_volume && -            e->volume.channels == new_data->sample_spec.channels) { - +        if (u->restore_volume) {              pa_log_info("Restoring volume for sink %s.", new_data->name); -            pa_sink_new_data_set_volume(new_data, &e->volume); +            pa_sink_new_data_set_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));          }          if (u->restore_muted) { @@ -242,11 +262,9 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da      if ((e = read_entry(u, name))) { -        if (u->restore_volume && -            e->volume.channels == new_data->sample_spec.channels) { - +        if (u->restore_volume) {              pa_log_info("Restoring volume for source %s.", new_data->name); -            pa_source_new_data_set_volume(new_data, &e->volume); +            pa_source_new_data_set_volume(new_data, pa_cvolume_remap(&e->volume, &e->channel_map, &new_data->channel_map));          }          if (u->restore_muted) { @@ -266,7 +284,6 @@ int pa__init(pa_module*m) {      pa_modargs *ma = NULL;      struct userdata *u;      char *fname, *fn; -    char hn[256];      pa_sink *sink;      pa_source *source;      uint32_t idx; @@ -290,9 +307,11 @@ int pa__init(pa_module*m) {      m->userdata = u = pa_xnew(struct userdata, 1);      u->core = m->core; +    u->module = m;      u->save_time_event = NULL;      u->restore_volume = restore_volume;      u->restore_muted = restore_muted; +    u->gdbm_file = NULL;      u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u); @@ -301,11 +320,12 @@ int pa__init(pa_module*m) {          u->source_fixate_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_fixate_hook_callback, u);      } -    if (!pa_get_host_name(hn, sizeof(hn))) -        goto fail; +    /* We include the host identifier in the file name because gdbm +     * files are CPU dependant, and we don't want things to go wrong +     * if we are on a multiarch system. */ -    fn = pa_sprintf_malloc("device-volumes.%s."CANONICAL_HOST".gdbm", hn); -    fname = pa_state_path(fn); +    fn = pa_sprintf_malloc("device-volumes."CANONICAL_HOST".gdbm"); +    fname = pa_state_path(fn, TRUE);      pa_xfree(fn);      if (!fname)  | 
