• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2006-2008 Lennart Poettering
5   Copyright 2011 Colin Guthrie
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 #include <pulse/gccmacro.h>
33 #include <pulse/xmalloc.h>
34 #include <pulse/volume.h>
35 #include <pulse/timeval.h>
36 #include <pulse/rtclock.h>
37 #include <pulse/format.h>
38 #include <pulse/internal.h>
39 
40 #include <pulsecore/core-error.h>
41 #include <pulsecore/module.h>
42 #include <pulsecore/core-util.h>
43 #include <pulsecore/modargs.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/core-subscribe.h>
46 #include <pulsecore/sink.h>
47 #include <pulsecore/source.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/protocol-native.h>
50 #include <pulsecore/pstream.h>
51 #include <pulsecore/pstream-util.h>
52 #include <pulsecore/database.h>
53 #include <pulsecore/tagstruct.h>
54 
55 PA_MODULE_AUTHOR("Lennart Poettering");
56 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute state of devices");
57 PA_MODULE_VERSION(PACKAGE_VERSION);
58 PA_MODULE_LOAD_ONCE(true);
59 PA_MODULE_USAGE(
60         "restore_port=<Save/restore port?> "
61         "restore_volume=<Save/restore volumes?> "
62         "restore_muted=<Save/restore muted states?> "
63         "restore_formats=<Save/restore saved formats?>");
64 
65 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
66 
67 static const char* const valid_modargs[] = {
68     "restore_volume",
69     "restore_muted",
70     "restore_port",
71     "restore_formats",
72     NULL
73 };
74 
75 struct userdata {
76     pa_core *core;
77     pa_module *module;
78     pa_subscription *subscription;
79     pa_time_event *save_time_event;
80     pa_database *database;
81 
82     pa_native_protocol *protocol;
83     pa_idxset *subscribed;
84 
85     bool restore_volume:1;
86     bool restore_muted:1;
87     bool restore_port:1;
88     bool restore_formats:1;
89 };
90 
91 /* Protocol extension commands */
92 enum {
93     SUBCOMMAND_TEST,
94     SUBCOMMAND_SUBSCRIBE,
95     SUBCOMMAND_EVENT,
96     SUBCOMMAND_READ_FORMATS_ALL,
97     SUBCOMMAND_READ_FORMATS,
98     SUBCOMMAND_SAVE_FORMATS
99 };
100 
101 #define ENTRY_VERSION 1
102 
103 struct entry {
104     uint8_t version;
105     bool port_valid;
106     char *port;
107 };
108 
109 #define PERPORTENTRY_VERSION 1
110 
111 struct perportentry {
112     uint8_t version;
113     bool muted_valid, volume_valid;
114     bool muted;
115     pa_channel_map channel_map;
116     pa_cvolume volume;
117     pa_idxset *formats;
118 };
119 
save_time_callback(pa_mainloop_api * a,pa_time_event * e,const struct timeval * t,void * userdata)120 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
121     struct userdata *u = userdata;
122 
123     pa_assert(a);
124     pa_assert(e);
125     pa_assert(u);
126 
127     pa_assert(e == u->save_time_event);
128     u->core->mainloop->time_free(u->save_time_event);
129     u->save_time_event = NULL;
130 
131     pa_database_sync(u->database);
132     pa_log_info("Synced.");
133 }
134 
trigger_save(struct userdata * u,pa_device_type_t type,uint32_t sink_idx)135 static void trigger_save(struct userdata *u, pa_device_type_t type, uint32_t sink_idx) {
136     pa_native_connection *c;
137     uint32_t idx;
138 
139     if (sink_idx != PA_INVALID_INDEX) {
140         PA_IDXSET_FOREACH(c, u->subscribed, idx) {
141             pa_tagstruct *t;
142 
143             t = pa_tagstruct_new();
144             pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
145             pa_tagstruct_putu32(t, 0);
146             pa_tagstruct_putu32(t, u->module->index);
147             pa_tagstruct_puts(t, u->module->name);
148             pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
149             pa_tagstruct_putu32(t, type);
150             pa_tagstruct_putu32(t, sink_idx);
151 
152             pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
153         }
154     }
155 
156     if (u->save_time_event)
157         return;
158 
159     u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
160 }
161 
162 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
163 /* Some forward declarations */
164 static bool legacy_entry_read(struct userdata *u, pa_datum *data, struct entry **entry, struct perportentry **perportentry);
165 static struct perportentry* perportentry_read(struct userdata *u, const char *basekeyname, const char *port);
166 static bool perportentry_write(struct userdata *u, const char *basekeyname, const char *port, const struct perportentry *e);
167 static void perportentry_free(struct perportentry* e);
168 #endif
169 
entry_new(void)170 static struct entry* entry_new(void) {
171     struct entry *r = pa_xnew0(struct entry, 1);
172     r->version = ENTRY_VERSION;
173     return r;
174 }
175 
entry_free(struct entry * e)176 static void entry_free(struct entry* e) {
177     pa_assert(e);
178 
179     pa_xfree(e->port);
180     pa_xfree(e);
181 }
182 
entry_write(struct userdata * u,const char * name,const struct entry * e)183 static bool entry_write(struct userdata *u, const char *name, const struct entry *e) {
184     pa_tagstruct *t;
185     pa_datum key, data;
186     bool r;
187 
188     pa_assert(u);
189     pa_assert(name);
190     pa_assert(e);
191 
192     t = pa_tagstruct_new();
193     pa_tagstruct_putu8(t, e->version);
194     pa_tagstruct_put_boolean(t, e->port_valid);
195     pa_tagstruct_puts(t, e->port);
196 
197     key.data = (char *) name;
198     key.size = strlen(name);
199 
200     data.data = (void*)pa_tagstruct_data(t, &data.size);
201 
202     r = (pa_database_set(u->database, &key, &data, true) == 0);
203 
204     pa_tagstruct_free(t);
205 
206     return r;
207 }
208 
entry_read(struct userdata * u,const char * name)209 static struct entry* entry_read(struct userdata *u, const char *name) {
210     pa_datum key, data;
211     struct entry *e = NULL;
212     pa_tagstruct *t = NULL;
213     const char* port;
214 
215     pa_assert(u);
216     pa_assert(name);
217 
218     key.data = (char*) name;
219     key.size = strlen(name);
220 
221     pa_zero(data);
222 
223     if (!pa_database_get(u->database, &key, &data)) {
224         pa_log_debug("Database contains no data for key: %s", name);
225         return NULL;
226     }
227 
228     t = pa_tagstruct_new_fixed(data.data, data.size);
229     e = entry_new();
230 
231     if (pa_tagstruct_getu8(t, &e->version) < 0 ||
232         e->version > ENTRY_VERSION ||
233         pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
234         pa_tagstruct_gets(t, &port) < 0) {
235 
236         goto fail;
237     }
238 
239     if (!pa_tagstruct_eof(t))
240         goto fail;
241 
242     e->port = pa_xstrdup(port);
243 
244     pa_tagstruct_free(t);
245     pa_datum_free(&data);
246 
247     return e;
248 
249 fail:
250 
251     pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
252 
253     if (e)
254         entry_free(e);
255     if (t)
256         pa_tagstruct_free(t);
257 
258 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
259 {
260     struct perportentry *ppe;
261     pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
262     if (legacy_entry_read(u, &data, &e, &ppe)) {
263         bool written = false;
264 
265         pa_log_debug("Success. Saving new format for key: %s", name);
266         written = entry_write(u, name, e);
267 
268         /* Now convert the legacy entry into per-port entries */
269         if (0 == strncmp("sink:", name, 5)) {
270             pa_sink *sink;
271 
272             if ((sink = pa_namereg_get(u->core, name+5, PA_NAMEREG_SINK))) {
273                 /* Write a "null" port entry. The read code will automatically try this
274                  * if it cannot find a specific port-named entry. */
275                 written = perportentry_write(u, name, NULL, ppe) || written;
276             }
277         } else if (0 == strncmp("source:", name, 7)) {
278             pa_source *source;
279 
280             if ((source = pa_namereg_get(u->core, name+7, PA_NAMEREG_SOURCE))) {
281                 /* Write a "null" port entry. The read code will automatically try this
282                  * if it cannot find a specific port-named entry. */
283                 written = perportentry_write(u, name, NULL, ppe) || written;
284             }
285         }
286         perportentry_free(ppe);
287 
288         if (written)
289             /* NB The device type doesn't matter when we pass in an invalid index. */
290             trigger_save(u, PA_DEVICE_TYPE_SINK, PA_INVALID_INDEX);
291 
292         pa_datum_free(&data);
293         return e;
294     }
295     pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
296 }
297 #endif
298 
299     pa_datum_free(&data);
300     return NULL;
301 }
302 
entry_copy(const struct entry * e)303 static struct entry* entry_copy(const struct entry *e) {
304     struct entry* r;
305 
306     pa_assert(e);
307     r = entry_new();
308     r->version = e->version;
309     r->port_valid = e->port_valid;
310     r->port = pa_xstrdup(e->port);
311 
312     return r;
313 }
314 
entries_equal(const struct entry * a,const struct entry * b)315 static bool entries_equal(const struct entry *a, const struct entry *b) {
316 
317     pa_assert(a && b);
318 
319     if (a->port_valid != b->port_valid ||
320         (a->port_valid && !pa_streq(a->port, b->port)))
321         return false;
322 
323     return true;
324 }
325 
perportentry_new(bool add_pcm_format)326 static struct perportentry* perportentry_new(bool add_pcm_format) {
327     struct perportentry *r = pa_xnew0(struct perportentry, 1);
328     r->version = PERPORTENTRY_VERSION;
329     r->formats = pa_idxset_new(NULL, NULL);
330     if (add_pcm_format) {
331         pa_format_info *f = pa_format_info_new();
332         f->encoding = PA_ENCODING_PCM;
333         pa_idxset_put(r->formats, f, NULL);
334     }
335     return r;
336 }
337 
perportentry_free(struct perportentry * e)338 static void perportentry_free(struct perportentry* e) {
339     pa_assert(e);
340 
341     pa_idxset_free(e->formats, (pa_free_cb_t) pa_format_info_free);
342     pa_xfree(e);
343 }
344 
perportentry_write(struct userdata * u,const char * basekeyname,const char * port,const struct perportentry * e)345 static bool perportentry_write(struct userdata *u, const char *basekeyname, const char *port, const struct perportentry *e) {
346     pa_tagstruct *t;
347     pa_datum key, data;
348     bool r;
349     uint32_t i;
350     pa_format_info *f;
351     uint8_t n_formats;
352     char *name;
353 
354     pa_assert(u);
355     pa_assert(basekeyname);
356     pa_assert(e);
357 
358     name = pa_sprintf_malloc("%s:%s", basekeyname, (port ? port : "null"));
359 
360     n_formats = pa_idxset_size(e->formats);
361     pa_assert(n_formats > 0);
362 
363     t = pa_tagstruct_new();
364     pa_tagstruct_putu8(t, e->version);
365     pa_tagstruct_put_boolean(t, e->volume_valid);
366     pa_tagstruct_put_channel_map(t, &e->channel_map);
367     pa_tagstruct_put_cvolume(t, &e->volume);
368     pa_tagstruct_put_boolean(t, e->muted_valid);
369     pa_tagstruct_put_boolean(t, e->muted);
370     pa_tagstruct_putu8(t, n_formats);
371 
372     PA_IDXSET_FOREACH(f, e->formats, i) {
373         pa_tagstruct_put_format_info(t, f);
374     }
375 
376     key.data = (char *) name;
377     key.size = strlen(name);
378 
379     data.data = (void*)pa_tagstruct_data(t, &data.size);
380 
381     r = (pa_database_set(u->database, &key, &data, true) == 0);
382 
383     pa_tagstruct_free(t);
384     pa_xfree(name);
385 
386     return r;
387 }
388 
perportentry_read(struct userdata * u,const char * basekeyname,const char * port)389 static struct perportentry* perportentry_read(struct userdata *u, const char *basekeyname, const char *port) {
390     pa_datum key, data;
391     struct perportentry *e = NULL;
392     pa_tagstruct *t = NULL;
393     uint8_t i, n_formats;
394     char *name;
395 
396     pa_assert(u);
397     pa_assert(basekeyname);
398 
399     name = pa_sprintf_malloc("%s:%s", basekeyname, (port ? port : "null"));
400 
401     key.data = name;
402     key.size = strlen(name);
403 
404     pa_zero(data);
405 
406     if (!pa_database_get(u->database, &key, &data))
407         goto fail;
408 
409     t = pa_tagstruct_new_fixed(data.data, data.size);
410     e = perportentry_new(false);
411 
412     if (pa_tagstruct_getu8(t, &e->version) < 0 ||
413         e->version > PERPORTENTRY_VERSION ||
414         pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
415         pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
416         pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
417         pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
418         pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
419         pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
420 
421         goto fail;
422     }
423 
424     for (i = 0; i < n_formats; ++i) {
425         pa_format_info *f = pa_format_info_new();
426         if (pa_tagstruct_get_format_info(t, f) < 0) {
427             pa_format_info_free(f);
428             goto fail;
429         }
430         pa_idxset_put(e->formats, f, NULL);
431     }
432 
433     if (!pa_tagstruct_eof(t))
434         goto fail;
435 
436     if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
437         pa_log_warn("Invalid channel map stored in database for device %s", name);
438         goto fail;
439     }
440 
441     if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
442         pa_log_warn("Volume and channel map don't match in database entry for device %s", name);
443         goto fail;
444     }
445 
446     pa_tagstruct_free(t);
447     pa_datum_free(&data);
448     pa_xfree(name);
449 
450     return e;
451 
452 fail:
453 
454     if (e)
455         perportentry_free(e);
456     if (t)
457         pa_tagstruct_free(t);
458 
459     pa_datum_free(&data);
460 
461 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
462     /* Try again with a null port. This is used when dealing with migration from older versions */
463     if (port) {
464         pa_xfree(name);
465         return perportentry_read(u, basekeyname, NULL);
466     }
467 #endif
468 
469     pa_log_debug("Database contains no (or invalid) data for key: %s", name);
470 
471     pa_xfree(name);
472 
473     return NULL;
474 }
475 
perportentry_copy(const struct perportentry * e)476 static struct perportentry* perportentry_copy(const struct perportentry *e) {
477     struct perportentry* r;
478     uint32_t idx;
479     pa_format_info *f;
480 
481     pa_assert(e);
482     r = perportentry_new(false);
483     r->version = e->version;
484     r->muted_valid = e->muted_valid;
485     r->volume_valid = e->volume_valid;
486     r->muted = e->muted;
487     r->channel_map = e->channel_map;
488     r->volume = e->volume;
489 
490     PA_IDXSET_FOREACH(f, e->formats, idx) {
491         pa_idxset_put(r->formats, pa_format_info_copy(f), NULL);
492     }
493     return r;
494 }
495 
perportentries_equal(const struct perportentry * a,const struct perportentry * b)496 static bool perportentries_equal(const struct perportentry *a, const struct perportentry *b) {
497     pa_cvolume t;
498 
499     pa_assert(a && b);
500 
501     if (a->muted_valid != b->muted_valid ||
502         (a->muted_valid && (a->muted != b->muted)))
503         return false;
504 
505     t = b->volume;
506     if (a->volume_valid != b->volume_valid ||
507         (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
508         return false;
509 
510     if (pa_idxset_size(a->formats) != pa_idxset_size(b->formats))
511         return false;
512 
513     /** TODO: Compare a bit better */
514 
515     return true;
516 }
517 
518 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
519 
520 #define LEGACY_ENTRY_VERSION 2
legacy_entry_read(struct userdata * u,pa_datum * data,struct entry ** entry,struct perportentry ** perportentry)521 static bool legacy_entry_read(struct userdata *u, pa_datum *data, struct entry **entry, struct perportentry **perportentry) {
522     struct legacy_entry {
523         uint8_t version;
524         bool muted_valid:1, volume_valid:1, port_valid:1;
525         bool muted:1;
526         pa_channel_map channel_map;
527         pa_cvolume volume;
528         char port[PA_NAME_MAX];
529     } PA_GCC_PACKED;
530     struct legacy_entry *le;
531     pa_channel_map channel_map;
532     pa_cvolume volume;
533 
534     pa_assert(u);
535     pa_assert(data);
536     pa_assert(entry);
537     pa_assert(perportentry);
538 
539     if (data->size != sizeof(struct legacy_entry)) {
540         pa_log_debug("Size does not match.");
541         return false;
542     }
543 
544     le = (struct legacy_entry*)data->data;
545 
546     if (le->version != LEGACY_ENTRY_VERSION) {
547         pa_log_debug("Version mismatch.");
548         return false;
549     }
550 
551     if (!memchr(le->port, 0, sizeof(le->port))) {
552         pa_log_warn("Port has missing NUL byte.");
553         return false;
554     }
555 
556     /* Read these out before accessing contents via pointers as struct legacy_entry may not be adequately aligned for these
557      * members to be accessed directly */
558     channel_map = le->channel_map;
559     volume = le->volume;
560 
561     if (le->volume_valid && !pa_channel_map_valid(&channel_map)) {
562         pa_log_warn("Invalid channel map.");
563         return false;
564     }
565 
566     if (le->volume_valid && (!pa_cvolume_valid(&volume) || !pa_cvolume_compatible_with_channel_map(&volume, &channel_map))) {
567         pa_log_warn("Volume and channel map don't match.");
568         return false;
569     }
570 
571     *entry = entry_new();
572     (*entry)->port_valid = le->port_valid;
573     (*entry)->port = pa_xstrdup(le->port);
574 
575     *perportentry = perportentry_new(true);
576     (*perportentry)->muted_valid = le->muted_valid;
577     (*perportentry)->volume_valid = le->volume_valid;
578     (*perportentry)->muted = le->muted;
579     (*perportentry)->channel_map = le->channel_map;
580     (*perportentry)->volume = le->volume;
581 
582     return true;
583 }
584 #endif
585 
subscribe_callback(pa_core * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)586 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
587     struct userdata *u = userdata;
588     struct entry *e, *olde;
589     struct perportentry *ppe, *oldppe;
590     char *name;
591     const char *port = NULL;
592     pa_device_type_t type;
593     bool written = false;
594 
595     pa_assert(c);
596     pa_assert(u);
597 
598     if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
599         t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
600         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
601         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
602         return;
603 
604     if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
605         pa_sink *sink;
606 
607         if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
608             return;
609 
610         type = PA_DEVICE_TYPE_SINK;
611         name = pa_sprintf_malloc("sink:%s", sink->name);
612         if (sink->active_port)
613             port = sink->active_port->name;
614 
615         if ((olde = entry_read(u, name)))
616             e = entry_copy(olde);
617         else
618             e = entry_new();
619 
620         if (sink->save_port) {
621             pa_xfree(e->port);
622             e->port = pa_xstrdup(port ? port : "");
623             e->port_valid = true;
624         }
625 
626         if ((oldppe = perportentry_read(u, name, port)))
627             ppe = perportentry_copy(oldppe);
628         else
629             ppe = perportentry_new(true);
630 
631         if (sink->save_volume) {
632             ppe->channel_map = sink->channel_map;
633             ppe->volume = *pa_sink_get_volume(sink, false);
634             ppe->volume_valid = true;
635         }
636 
637         if (sink->save_muted) {
638             ppe->muted = pa_sink_get_mute(sink, false);
639             ppe->muted_valid = true;
640         }
641     } else {
642         pa_source *source;
643 
644         pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
645 
646         if (!(source = pa_idxset_get_by_index(c->sources, idx)))
647             return;
648 
649         type = PA_DEVICE_TYPE_SOURCE;
650         name = pa_sprintf_malloc("source:%s", source->name);
651         if (source->active_port)
652             port = source->active_port->name;
653 
654         if ((olde = entry_read(u, name)))
655             e = entry_copy(olde);
656         else
657             e = entry_new();
658 
659         if (source->save_port) {
660             pa_xfree(e->port);
661             e->port = pa_xstrdup(port ? port : "");
662             e->port_valid = true;
663         }
664 
665         if ((oldppe = perportentry_read(u, name, port)))
666             ppe = perportentry_copy(oldppe);
667         else
668             ppe = perportentry_new(true);
669 
670         if (source->save_volume) {
671             ppe->channel_map = source->channel_map;
672             ppe->volume = *pa_source_get_volume(source, false);
673             ppe->volume_valid = true;
674         }
675 
676         if (source->save_muted) {
677             ppe->muted = pa_source_get_mute(source, false);
678             ppe->muted_valid = true;
679         }
680     }
681 
682     pa_assert(e);
683 
684     if (olde) {
685 
686         if (entries_equal(olde, e)) {
687             entry_free(olde);
688             entry_free(e);
689             e = NULL;
690         } else
691             entry_free(olde);
692     }
693 
694     if (e) {
695         pa_log_info("Storing port for device %s.", name);
696 
697         written = entry_write(u, name, e);
698 
699         entry_free(e);
700     }
701 
702     pa_assert(ppe);
703 
704     if (oldppe) {
705 
706         if (perportentries_equal(oldppe, ppe)) {
707             perportentry_free(oldppe);
708             perportentry_free(ppe);
709             ppe = NULL;
710         } else
711             perportentry_free(oldppe);
712     }
713 
714     if (ppe) {
715         pa_log_info("Storing volume/mute for device+port %s:%s.", name, (port ? port : "null"));
716 
717         written = perportentry_write(u, name, port, ppe) || written;
718 
719         perportentry_free(ppe);
720     }
721     pa_xfree(name);
722 
723     if (written)
724         trigger_save(u, type, idx);
725 }
726 
sink_new_hook_callback(pa_core * c,pa_sink_new_data * new_data,struct userdata * u)727 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
728     char *name;
729     struct entry *e;
730 
731     pa_assert(c);
732     pa_assert(new_data);
733     pa_assert(u);
734     pa_assert(u->restore_port);
735 
736     name = pa_sprintf_malloc("sink:%s", new_data->name);
737 
738     if ((e = entry_read(u, name))) {
739 
740         if (e->port_valid) {
741             if (!new_data->active_port) {
742                 pa_log_info("Restoring port '%s' for sink %s.", pa_strnull(e->port), name);
743                 pa_sink_new_data_set_port(new_data, e->port);
744                 new_data->save_port = true;
745             } else
746                 pa_log_debug("Not restoring port for sink %s, because already set.", name);
747         }
748 
749         entry_free(e);
750     }
751 
752     pa_xfree(name);
753 
754     return PA_HOOK_OK;
755 }
756 
sink_fixate_hook_callback(pa_core * c,pa_sink_new_data * new_data,struct userdata * u)757 static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
758     char *name;
759     struct perportentry *e;
760 
761     pa_assert(c);
762     pa_assert(new_data);
763     pa_assert(u);
764     pa_assert(u->restore_volume || u->restore_muted);
765 
766     name = pa_sprintf_malloc("sink:%s", new_data->name);
767 
768     if ((e = perportentry_read(u, name, new_data->active_port))) {
769 
770         if (u->restore_volume && e->volume_valid) {
771 
772             if (!new_data->volume_is_set) {
773                 pa_cvolume v;
774                 char buf[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
775 
776                 v = e->volume;
777                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
778                 pa_sink_new_data_set_volume(new_data, &v);
779                 pa_log_info("Restoring volume for sink %s: %s", new_data->name,
780                             pa_cvolume_snprint_verbose(buf, sizeof(buf), &new_data->volume, &new_data->channel_map, false));
781 
782                 new_data->save_volume = true;
783             } else
784                 pa_log_debug("Not restoring volume for sink %s, because already set.", new_data->name);
785         }
786 
787         if (u->restore_muted && e->muted_valid) {
788 
789             if (!new_data->muted_is_set) {
790                 pa_sink_new_data_set_muted(new_data, e->muted);
791                 new_data->save_muted = true;
792                 pa_log_info("Restoring mute state for sink %s: %smuted", new_data->name,
793                             new_data->muted ? "" : "un");
794             } else
795                 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
796         }
797 
798         perportentry_free(e);
799     }
800 
801     pa_xfree(name);
802 
803     return PA_HOOK_OK;
804 }
805 
sink_port_hook_callback(pa_core * c,pa_sink * sink,struct userdata * u)806 static pa_hook_result_t sink_port_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
807     char *name;
808     struct perportentry *e;
809 
810     pa_assert(c);
811     pa_assert(sink);
812     pa_assert(u);
813     pa_assert(u->restore_volume || u->restore_muted);
814 
815     name = pa_sprintf_malloc("sink:%s", sink->name);
816 
817     if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
818 
819         if (u->restore_volume && e->volume_valid) {
820             pa_cvolume v;
821 
822             pa_log_info("Restoring volume for sink %s.", sink->name);
823             v = e->volume;
824             pa_cvolume_remap(&v, &e->channel_map, &sink->channel_map);
825             pa_sink_set_volume(sink, &v, true, false);
826 
827             sink->save_volume = true;
828         }
829 
830         if (u->restore_muted && e->muted_valid) {
831 
832             pa_log_info("Restoring mute state for sink %s.", sink->name);
833             pa_sink_set_mute(sink, e->muted, false);
834             sink->save_muted = true;
835         }
836 
837         perportentry_free(e);
838     }
839 
840     pa_xfree(name);
841 
842     return PA_HOOK_OK;
843 }
844 
sink_put_hook_callback(pa_core * c,pa_sink * sink,struct userdata * u)845 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
846     char *name;
847     struct perportentry *e;
848 
849     pa_assert(c);
850     pa_assert(sink);
851     pa_assert(u);
852     pa_assert(u->restore_formats);
853 
854     name = pa_sprintf_malloc("sink:%s", sink->name);
855 
856     if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
857 
858         if (!pa_sink_set_formats(sink, e->formats))
859             pa_log_debug("Could not set format on sink %s", sink->name);
860 
861         perportentry_free(e);
862     }
863 
864     pa_xfree(name);
865 
866     return PA_HOOK_OK;
867 }
868 
source_new_hook_callback(pa_core * c,pa_source_new_data * new_data,struct userdata * u)869 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
870     char *name;
871     struct entry *e;
872 
873     pa_assert(c);
874     pa_assert(new_data);
875     pa_assert(u);
876     pa_assert(u->restore_port);
877 
878     name = pa_sprintf_malloc("source:%s", new_data->name);
879 
880     if ((e = entry_read(u, name))) {
881 
882         if (e->port_valid) {
883             if (!new_data->active_port) {
884                 pa_log_info("Restoring port '%s' for source %s.", pa_strnull(e->port), name);
885                 pa_source_new_data_set_port(new_data, e->port);
886                 new_data->save_port = true;
887             } else
888                 pa_log_debug("Not restoring port for source %s, because already set.", name);
889         }
890 
891         entry_free(e);
892     }
893 
894     pa_xfree(name);
895 
896     return PA_HOOK_OK;
897 }
898 
source_fixate_hook_callback(pa_core * c,pa_source_new_data * new_data,struct userdata * u)899 static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
900     char *name;
901     struct perportentry *e;
902 
903     pa_assert(c);
904     pa_assert(new_data);
905     pa_assert(u);
906     pa_assert(u->restore_volume || u->restore_muted);
907 
908     name = pa_sprintf_malloc("source:%s", new_data->name);
909 
910     if ((e = perportentry_read(u, name, new_data->active_port))) {
911 
912         if (u->restore_volume && e->volume_valid) {
913 
914             if (!new_data->volume_is_set) {
915                 pa_cvolume v;
916                 char buf[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
917 
918                 v = e->volume;
919                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
920                 pa_source_new_data_set_volume(new_data, &v);
921                 pa_log_info("Restoring volume for source %s: %s", new_data->name,
922                             pa_cvolume_snprint_verbose(buf, sizeof(buf), &new_data->volume, &new_data->channel_map, false));
923 
924                 new_data->save_volume = true;
925             } else
926                 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
927         }
928 
929         if (u->restore_muted && e->muted_valid) {
930 
931             if (!new_data->muted_is_set) {
932                 pa_source_new_data_set_muted(new_data, e->muted);
933                 new_data->save_muted = true;
934                 pa_log_info("Restoring mute state for source %s: %smuted", new_data->name,
935                             new_data->muted ? "" : "un");
936             } else
937                 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
938         }
939 
940         perportentry_free(e);
941     }
942 
943     pa_xfree(name);
944 
945     return PA_HOOK_OK;
946 }
947 
source_port_hook_callback(pa_core * c,pa_source * source,struct userdata * u)948 static pa_hook_result_t source_port_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
949     char *name;
950     struct perportentry *e;
951 
952     pa_assert(c);
953     pa_assert(source);
954     pa_assert(u);
955     pa_assert(u->restore_volume || u->restore_muted);
956 
957     name = pa_sprintf_malloc("source:%s", source->name);
958 
959     if ((e = perportentry_read(u, name, (source->active_port ? source->active_port->name : NULL)))) {
960 
961         if (u->restore_volume && e->volume_valid) {
962             pa_cvolume v;
963 
964             pa_log_info("Restoring volume for source %s.", source->name);
965             v = e->volume;
966             pa_cvolume_remap(&v, &e->channel_map, &source->channel_map);
967             pa_source_set_volume(source, &v, true, false);
968 
969             source->save_volume = true;
970         }
971 
972         if (u->restore_muted && e->muted_valid) {
973 
974             pa_log_info("Restoring mute state for source %s.", source->name);
975             pa_source_set_mute(source, e->muted, false);
976             source->save_muted = true;
977         }
978 
979         perportentry_free(e);
980     }
981 
982     pa_xfree(name);
983 
984     return PA_HOOK_OK;
985 }
986 
987 #define EXT_VERSION 1
988 
read_sink_format_reply(struct userdata * u,pa_tagstruct * reply,pa_sink * sink)989 static void read_sink_format_reply(struct userdata *u, pa_tagstruct *reply, pa_sink *sink) {
990     struct perportentry *e;
991     char *name;
992 
993     pa_assert(u);
994     pa_assert(reply);
995     pa_assert(sink);
996 
997     pa_tagstruct_putu32(reply, PA_DEVICE_TYPE_SINK);
998     pa_tagstruct_putu32(reply, sink->index);
999 
1000     /* Read or create an entry */
1001     name = pa_sprintf_malloc("sink:%s", sink->name);
1002     if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
1003         /* Fake a reply with PCM encoding supported */
1004         pa_format_info *f = pa_format_info_new();
1005 
1006         pa_tagstruct_putu8(reply, 1);
1007         f->encoding = PA_ENCODING_PCM;
1008         pa_tagstruct_put_format_info(reply, f);
1009 
1010         pa_format_info_free(f);
1011     } else {
1012         uint32_t idx;
1013         pa_format_info *f;
1014 
1015         /* Write all the formats from the entry to the reply */
1016         pa_tagstruct_putu8(reply, pa_idxset_size(e->formats));
1017         PA_IDXSET_FOREACH(f, e->formats, idx) {
1018             pa_tagstruct_put_format_info(reply, f);
1019         }
1020         perportentry_free(e);
1021     }
1022     pa_xfree(name);
1023 }
1024 
extension_cb(pa_native_protocol * p,pa_module * m,pa_native_connection * c,uint32_t tag,pa_tagstruct * t)1025 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
1026     struct userdata *u;
1027     uint32_t command;
1028     pa_tagstruct *reply = NULL;
1029 
1030     pa_assert(p);
1031     pa_assert(m);
1032     pa_assert(c);
1033     pa_assert(t);
1034 
1035     u = m->userdata;
1036 
1037     if (pa_tagstruct_getu32(t, &command) < 0)
1038         goto fail;
1039 
1040     reply = pa_tagstruct_new();
1041     pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1042     pa_tagstruct_putu32(reply, tag);
1043 
1044     switch (command) {
1045         case SUBCOMMAND_TEST: {
1046             if (!pa_tagstruct_eof(t))
1047                 goto fail;
1048 
1049             pa_tagstruct_putu32(reply, EXT_VERSION);
1050             break;
1051         }
1052 
1053         case SUBCOMMAND_SUBSCRIBE: {
1054 
1055             bool enabled;
1056 
1057             if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1058                 !pa_tagstruct_eof(t))
1059                 goto fail;
1060 
1061             if (enabled)
1062                 pa_idxset_put(u->subscribed, c, NULL);
1063             else
1064                 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1065 
1066             break;
1067         }
1068 
1069         case SUBCOMMAND_READ_FORMATS_ALL: {
1070             pa_sink *sink;
1071             uint32_t idx;
1072 
1073             if (!pa_tagstruct_eof(t))
1074                 goto fail;
1075 
1076             PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
1077                 read_sink_format_reply(u, reply, sink);
1078             }
1079 
1080             break;
1081         }
1082         case SUBCOMMAND_READ_FORMATS: {
1083             pa_device_type_t type;
1084             uint32_t sink_index;
1085             pa_sink *sink;
1086 
1087             pa_assert(reply);
1088 
1089             /* Get the sink index and the number of formats from the tagstruct */
1090             if (pa_tagstruct_getu32(t, &type) < 0 ||
1091                 pa_tagstruct_getu32(t, &sink_index) < 0)
1092                 goto fail;
1093 
1094             if (type != PA_DEVICE_TYPE_SINK) {
1095                 pa_log("Device format reading is only supported on sinks");
1096                 goto fail;
1097             }
1098 
1099             if (!pa_tagstruct_eof(t))
1100                 goto fail;
1101 
1102             /* Now find our sink */
1103             if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
1104                 goto fail;
1105 
1106             read_sink_format_reply(u, reply, sink);
1107 
1108             break;
1109         }
1110 
1111         case SUBCOMMAND_SAVE_FORMATS: {
1112 
1113             struct perportentry *e;
1114             pa_device_type_t type;
1115             uint32_t sink_index;
1116             char *name;
1117             pa_sink *sink;
1118             uint8_t i, n_formats;
1119 
1120             /* Get the sink index and the number of formats from the tagstruct */
1121             if (pa_tagstruct_getu32(t, &type) < 0 ||
1122                 pa_tagstruct_getu32(t, &sink_index) < 0 ||
1123                 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
1124 
1125                 goto fail;
1126             }
1127 
1128             if (type != PA_DEVICE_TYPE_SINK) {
1129                 pa_log("Device format saving is only supported on sinks");
1130                 goto fail;
1131             }
1132 
1133             /* Now find our sink */
1134             if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) {
1135                 pa_log("Could not find sink #%d", sink_index);
1136                 goto fail;
1137             }
1138 
1139             /* Read or create an entry */
1140             name = pa_sprintf_malloc("sink:%s", sink->name);
1141             if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL))))
1142                 e = perportentry_new(false);
1143             else {
1144                 /* Clean out any saved formats */
1145                 pa_idxset_free(e->formats, (pa_free_cb_t) pa_format_info_free);
1146                 e->formats = pa_idxset_new(NULL, NULL);
1147             }
1148 
1149             /* Read all the formats from our tagstruct */
1150             for (i = 0; i < n_formats; ++i) {
1151                 pa_format_info *f = pa_format_info_new();
1152                 if (pa_tagstruct_get_format_info(t, f) < 0) {
1153                     pa_format_info_free(f);
1154                     perportentry_free(e);
1155                     pa_xfree(name);
1156                     goto fail;
1157                 }
1158                 pa_idxset_put(e->formats, f, NULL);
1159             }
1160 
1161             if (!pa_tagstruct_eof(t)) {
1162                 perportentry_free(e);
1163                 pa_xfree(name);
1164                 goto fail;
1165             }
1166 
1167             if (pa_sink_set_formats(sink, e->formats) && perportentry_write(u, name, (sink->active_port ? sink->active_port->name : NULL), e))
1168                 trigger_save(u, type, sink_index);
1169             else
1170                 pa_log_warn("Could not save format info for sink %s", sink->name);
1171 
1172             pa_xfree(name);
1173             perportentry_free(e);
1174 
1175             break;
1176         }
1177 
1178         default:
1179             goto fail;
1180     }
1181 
1182     pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1183     return 0;
1184 
1185 fail:
1186 
1187     if (reply)
1188         pa_tagstruct_free(reply);
1189 
1190     return -1;
1191 }
1192 
connection_unlink_hook_cb(pa_native_protocol * p,pa_native_connection * c,struct userdata * u)1193 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1194     pa_assert(p);
1195     pa_assert(c);
1196     pa_assert(u);
1197 
1198     pa_idxset_remove_by_data(u->subscribed, c, NULL);
1199     return PA_HOOK_OK;
1200 }
1201 
pa__init(pa_module * m)1202 int pa__init(pa_module*m) {
1203     pa_modargs *ma = NULL;
1204     struct userdata *u;
1205     char *state_path;
1206     pa_sink *sink;
1207     pa_source *source;
1208     uint32_t idx;
1209     bool restore_volume = true, restore_muted = true, restore_port = true, restore_formats = true;
1210 
1211     pa_assert(m);
1212 
1213     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1214         pa_log("Failed to parse module arguments");
1215         goto fail;
1216     }
1217 
1218     if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
1219         pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
1220         pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0 ||
1221         pa_modargs_get_value_boolean(ma, "restore_formats", &restore_formats) < 0) {
1222         pa_log("restore_port, restore_volume, restore_muted and restore_formats expect boolean arguments");
1223         goto fail;
1224     }
1225 
1226     if (!restore_muted && !restore_volume && !restore_port && !restore_formats)
1227         pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!");
1228 
1229     m->userdata = u = pa_xnew0(struct userdata, 1);
1230     u->core = m->core;
1231     u->module = m;
1232     u->restore_volume = restore_volume;
1233     u->restore_muted = restore_muted;
1234     u->restore_port = restore_port;
1235     u->restore_formats = restore_formats;
1236 
1237     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1238 
1239     u->protocol = pa_native_protocol_get(m->core);
1240     pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1241 
1242     pa_module_hook_connect(m, &pa_native_protocol_hooks(u->protocol)[PA_NATIVE_HOOK_CONNECTION_UNLINK], PA_HOOK_NORMAL, (pa_hook_cb_t) connection_unlink_hook_cb, u);
1243 
1244     u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
1245 
1246     if (restore_port) {
1247         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_new_hook_callback, u);
1248         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_new_hook_callback, u);
1249     }
1250 
1251     if (restore_muted || restore_volume) {
1252         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) sink_fixate_hook_callback, u);
1253         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], PA_HOOK_EARLY, (pa_hook_cb_t) source_fixate_hook_callback, u);
1254 
1255         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) sink_port_hook_callback, u);
1256         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) source_port_hook_callback, u);
1257     }
1258 
1259     if (restore_formats)
1260         pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_put_hook_callback, u);
1261 
1262     if (!(state_path = pa_state_path(NULL, true)))
1263         goto fail;
1264 
1265     if (!(u->database = pa_database_open(state_path, "device-volumes", true, true))) {
1266         pa_xfree(state_path);
1267         goto fail;
1268     }
1269 
1270     pa_xfree(state_path);
1271 
1272     PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
1273         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1274 
1275     PA_IDXSET_FOREACH(source, m->core->sources, idx)
1276         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
1277 
1278     pa_modargs_free(ma);
1279     return 0;
1280 
1281 fail:
1282     pa__done(m);
1283 
1284     if (ma)
1285         pa_modargs_free(ma);
1286 
1287     return -1;
1288 }
1289 
pa__done(pa_module * m)1290 void pa__done(pa_module*m) {
1291     struct userdata* u;
1292 
1293     pa_assert(m);
1294 
1295     if (!(u = m->userdata))
1296         return;
1297 
1298     if (u->subscription)
1299         pa_subscription_free(u->subscription);
1300 
1301     if (u->save_time_event) {
1302         u->core->mainloop->time_free(u->save_time_event);
1303         pa_database_sync(u->database);
1304     }
1305 
1306     if (u->database)
1307         pa_database_close(u->database);
1308 
1309     if (u->protocol) {
1310         pa_native_protocol_remove_ext(u->protocol, m);
1311         pa_native_protocol_unref(u->protocol);
1312     }
1313 
1314     if (u->subscribed)
1315         pa_idxset_free(u->subscribed, NULL);
1316 
1317     pa_xfree(u);
1318 }
1319