• 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 
532     pa_assert(u);
533     pa_assert(data);
534     pa_assert(entry);
535     pa_assert(perportentry);
536 
537     if (data->size != sizeof(struct legacy_entry)) {
538         pa_log_debug("Size does not match.");
539         return false;
540     }
541 
542     le = (struct legacy_entry*)data->data;
543 
544     if (le->version != LEGACY_ENTRY_VERSION) {
545         pa_log_debug("Version mismatch.");
546         return false;
547     }
548 
549     if (!memchr(le->port, 0, sizeof(le->port))) {
550         pa_log_warn("Port has missing NUL byte.");
551         return false;
552     }
553 
554     if (le->volume_valid && !pa_channel_map_valid(&le->channel_map)) {
555         pa_log_warn("Invalid channel map.");
556         return false;
557     }
558 
559     if (le->volume_valid && (!pa_cvolume_valid(&le->volume) || !pa_cvolume_compatible_with_channel_map(&le->volume, &le->channel_map))) {
560         pa_log_warn("Volume and channel map don't match.");
561         return false;
562     }
563 
564     *entry = entry_new();
565     (*entry)->port_valid = le->port_valid;
566     (*entry)->port = pa_xstrdup(le->port);
567 
568     *perportentry = perportentry_new(true);
569     (*perportentry)->muted_valid = le->muted_valid;
570     (*perportentry)->volume_valid = le->volume_valid;
571     (*perportentry)->muted = le->muted;
572     (*perportentry)->channel_map = le->channel_map;
573     (*perportentry)->volume = le->volume;
574 
575     return true;
576 }
577 #endif
578 
subscribe_callback(pa_core * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)579 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
580     struct userdata *u = userdata;
581     struct entry *e, *olde;
582     struct perportentry *ppe, *oldppe;
583     char *name;
584     const char *port = NULL;
585     pa_device_type_t type;
586     bool written = false;
587 
588     pa_assert(c);
589     pa_assert(u);
590 
591     if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
592         t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
593         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
594         t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
595         return;
596 
597     if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
598         pa_sink *sink;
599 
600         if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
601             return;
602 
603         type = PA_DEVICE_TYPE_SINK;
604         name = pa_sprintf_malloc("sink:%s", sink->name);
605         if (sink->active_port)
606             port = sink->active_port->name;
607 
608         if ((olde = entry_read(u, name)))
609             e = entry_copy(olde);
610         else
611             e = entry_new();
612 
613         if (sink->save_port) {
614             pa_xfree(e->port);
615             e->port = pa_xstrdup(port ? port : "");
616             e->port_valid = true;
617         }
618 
619         if ((oldppe = perportentry_read(u, name, port)))
620             ppe = perportentry_copy(oldppe);
621         else
622             ppe = perportentry_new(true);
623 
624         if (sink->save_volume) {
625             ppe->channel_map = sink->channel_map;
626             ppe->volume = *pa_sink_get_volume(sink, false);
627             ppe->volume_valid = true;
628         }
629 
630         if (sink->save_muted) {
631             ppe->muted = pa_sink_get_mute(sink, false);
632             ppe->muted_valid = true;
633         }
634     } else {
635         pa_source *source;
636 
637         pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
638 
639         if (!(source = pa_idxset_get_by_index(c->sources, idx)))
640             return;
641 
642         type = PA_DEVICE_TYPE_SOURCE;
643         name = pa_sprintf_malloc("source:%s", source->name);
644         if (source->active_port)
645             port = source->active_port->name;
646 
647         if ((olde = entry_read(u, name)))
648             e = entry_copy(olde);
649         else
650             e = entry_new();
651 
652         if (source->save_port) {
653             pa_xfree(e->port);
654             e->port = pa_xstrdup(port ? port : "");
655             e->port_valid = true;
656         }
657 
658         if ((oldppe = perportentry_read(u, name, port)))
659             ppe = perportentry_copy(oldppe);
660         else
661             ppe = perportentry_new(true);
662 
663         if (source->save_volume) {
664             ppe->channel_map = source->channel_map;
665             ppe->volume = *pa_source_get_volume(source, false);
666             ppe->volume_valid = true;
667         }
668 
669         if (source->save_muted) {
670             ppe->muted = pa_source_get_mute(source, false);
671             ppe->muted_valid = true;
672         }
673     }
674 
675     pa_assert(e);
676 
677     if (olde) {
678 
679         if (entries_equal(olde, e)) {
680             entry_free(olde);
681             entry_free(e);
682             e = NULL;
683         } else
684             entry_free(olde);
685     }
686 
687     if (e) {
688         pa_log_info("Storing port for device %s.", name);
689 
690         written = entry_write(u, name, e);
691 
692         entry_free(e);
693     }
694 
695     pa_assert(ppe);
696 
697     if (oldppe) {
698 
699         if (perportentries_equal(oldppe, ppe)) {
700             perportentry_free(oldppe);
701             perportentry_free(ppe);
702             ppe = NULL;
703         } else
704             perportentry_free(oldppe);
705     }
706 
707     if (ppe) {
708         pa_log_info("Storing volume/mute for device+port %s:%s.", name, (port ? port : "null"));
709 
710         written = perportentry_write(u, name, port, ppe) || written;
711 
712         perportentry_free(ppe);
713     }
714     pa_xfree(name);
715 
716     if (written)
717         trigger_save(u, type, idx);
718 }
719 
sink_new_hook_callback(pa_core * c,pa_sink_new_data * new_data,struct userdata * u)720 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
721     char *name;
722     struct entry *e;
723 
724     pa_assert(c);
725     pa_assert(new_data);
726     pa_assert(u);
727     pa_assert(u->restore_port);
728 
729     name = pa_sprintf_malloc("sink:%s", new_data->name);
730 
731     if ((e = entry_read(u, name))) {
732 
733         if (e->port_valid) {
734             if (!new_data->active_port) {
735                 pa_log_info("Restoring port for sink %s.", name);
736                 pa_sink_new_data_set_port(new_data, e->port);
737                 new_data->save_port = true;
738             } else
739                 pa_log_debug("Not restoring port for sink %s, because already set.", name);
740         }
741 
742         entry_free(e);
743     }
744 
745     pa_xfree(name);
746 
747     return PA_HOOK_OK;
748 }
749 
sink_fixate_hook_callback(pa_core * c,pa_sink_new_data * new_data,struct userdata * u)750 static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
751     char *name;
752     struct perportentry *e;
753 
754     pa_assert(c);
755     pa_assert(new_data);
756     pa_assert(u);
757     pa_assert(u->restore_volume || u->restore_muted);
758 
759     name = pa_sprintf_malloc("sink:%s", new_data->name);
760 
761     if ((e = perportentry_read(u, name, new_data->active_port))) {
762 
763         if (u->restore_volume && e->volume_valid) {
764 
765             if (!new_data->volume_is_set) {
766                 pa_cvolume v;
767                 char buf[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
768 
769                 v = e->volume;
770                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
771                 pa_sink_new_data_set_volume(new_data, &v);
772                 pa_log_info("Restoring volume for sink %s: %s", new_data->name,
773                             pa_cvolume_snprint_verbose(buf, sizeof(buf), &new_data->volume, &new_data->channel_map, false));
774 
775                 new_data->save_volume = true;
776             } else
777                 pa_log_debug("Not restoring volume for sink %s, because already set.", new_data->name);
778         }
779 
780         if (u->restore_muted && e->muted_valid) {
781 
782             if (!new_data->muted_is_set) {
783                 pa_sink_new_data_set_muted(new_data, e->muted);
784                 new_data->save_muted = true;
785                 pa_log_info("Restoring mute state for sink %s: %smuted", new_data->name,
786                             new_data->muted ? "" : "un");
787             } else
788                 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
789         }
790 
791         perportentry_free(e);
792     }
793 
794     pa_xfree(name);
795 
796     return PA_HOOK_OK;
797 }
798 
sink_port_hook_callback(pa_core * c,pa_sink * sink,struct userdata * u)799 static pa_hook_result_t sink_port_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
800     char *name;
801     struct perportentry *e;
802 
803     pa_assert(c);
804     pa_assert(sink);
805     pa_assert(u);
806     pa_assert(u->restore_volume || u->restore_muted);
807 
808     name = pa_sprintf_malloc("sink:%s", sink->name);
809 
810     if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
811 
812         if (u->restore_volume && e->volume_valid) {
813             pa_cvolume v;
814 
815             pa_log_info("Restoring volume for sink %s.", sink->name);
816             v = e->volume;
817             pa_cvolume_remap(&v, &e->channel_map, &sink->channel_map);
818             pa_sink_set_volume(sink, &v, true, false);
819 
820             sink->save_volume = true;
821         }
822 
823         if (u->restore_muted && e->muted_valid) {
824 
825             pa_log_info("Restoring mute state for sink %s.", sink->name);
826             pa_sink_set_mute(sink, e->muted, false);
827             sink->save_muted = true;
828         }
829 
830         perportentry_free(e);
831     }
832 
833     pa_xfree(name);
834 
835     return PA_HOOK_OK;
836 }
837 
sink_put_hook_callback(pa_core * c,pa_sink * sink,struct userdata * u)838 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
839     char *name;
840     struct perportentry *e;
841 
842     pa_assert(c);
843     pa_assert(sink);
844     pa_assert(u);
845     pa_assert(u->restore_formats);
846 
847     name = pa_sprintf_malloc("sink:%s", sink->name);
848 
849     if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
850 
851         if (!pa_sink_set_formats(sink, e->formats))
852             pa_log_debug("Could not set format on sink %s", sink->name);
853 
854         perportentry_free(e);
855     }
856 
857     pa_xfree(name);
858 
859     return PA_HOOK_OK;
860 }
861 
source_new_hook_callback(pa_core * c,pa_source_new_data * new_data,struct userdata * u)862 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
863     char *name;
864     struct entry *e;
865 
866     pa_assert(c);
867     pa_assert(new_data);
868     pa_assert(u);
869     pa_assert(u->restore_port);
870 
871     name = pa_sprintf_malloc("source:%s", new_data->name);
872 
873     if ((e = entry_read(u, name))) {
874 
875         if (e->port_valid) {
876             if (!new_data->active_port) {
877                 pa_log_info("Restoring port for source %s.", name);
878                 pa_source_new_data_set_port(new_data, e->port);
879                 new_data->save_port = true;
880             } else
881                 pa_log_debug("Not restoring port for source %s, because already set.", name);
882         }
883 
884         entry_free(e);
885     }
886 
887     pa_xfree(name);
888 
889     return PA_HOOK_OK;
890 }
891 
source_fixate_hook_callback(pa_core * c,pa_source_new_data * new_data,struct userdata * u)892 static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
893     char *name;
894     struct perportentry *e;
895 
896     pa_assert(c);
897     pa_assert(new_data);
898     pa_assert(u);
899     pa_assert(u->restore_volume || u->restore_muted);
900 
901     name = pa_sprintf_malloc("source:%s", new_data->name);
902 
903     if ((e = perportentry_read(u, name, new_data->active_port))) {
904 
905         if (u->restore_volume && e->volume_valid) {
906 
907             if (!new_data->volume_is_set) {
908                 pa_cvolume v;
909                 char buf[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
910 
911                 v = e->volume;
912                 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
913                 pa_source_new_data_set_volume(new_data, &v);
914                 pa_log_info("Restoring volume for source %s: %s", new_data->name,
915                             pa_cvolume_snprint_verbose(buf, sizeof(buf), &new_data->volume, &new_data->channel_map, false));
916 
917                 new_data->save_volume = true;
918             } else
919                 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
920         }
921 
922         if (u->restore_muted && e->muted_valid) {
923 
924             if (!new_data->muted_is_set) {
925                 pa_source_new_data_set_muted(new_data, e->muted);
926                 new_data->save_muted = true;
927                 pa_log_info("Restoring mute state for source %s: %smuted", new_data->name,
928                             new_data->muted ? "" : "un");
929             } else
930                 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
931         }
932 
933         perportentry_free(e);
934     }
935 
936     pa_xfree(name);
937 
938     return PA_HOOK_OK;
939 }
940 
source_port_hook_callback(pa_core * c,pa_source * source,struct userdata * u)941 static pa_hook_result_t source_port_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
942     char *name;
943     struct perportentry *e;
944 
945     pa_assert(c);
946     pa_assert(source);
947     pa_assert(u);
948     pa_assert(u->restore_volume || u->restore_muted);
949 
950     name = pa_sprintf_malloc("source:%s", source->name);
951 
952     if ((e = perportentry_read(u, name, (source->active_port ? source->active_port->name : NULL)))) {
953 
954         if (u->restore_volume && e->volume_valid) {
955             pa_cvolume v;
956 
957             pa_log_info("Restoring volume for source %s.", source->name);
958             v = e->volume;
959             pa_cvolume_remap(&v, &e->channel_map, &source->channel_map);
960             pa_source_set_volume(source, &v, true, false);
961 
962             source->save_volume = true;
963         }
964 
965         if (u->restore_muted && e->muted_valid) {
966 
967             pa_log_info("Restoring mute state for source %s.", source->name);
968             pa_source_set_mute(source, e->muted, false);
969             source->save_muted = true;
970         }
971 
972         perportentry_free(e);
973     }
974 
975     pa_xfree(name);
976 
977     return PA_HOOK_OK;
978 }
979 
980 #define EXT_VERSION 1
981 
read_sink_format_reply(struct userdata * u,pa_tagstruct * reply,pa_sink * sink)982 static void read_sink_format_reply(struct userdata *u, pa_tagstruct *reply, pa_sink *sink) {
983     struct perportentry *e;
984     char *name;
985 
986     pa_assert(u);
987     pa_assert(reply);
988     pa_assert(sink);
989 
990     pa_tagstruct_putu32(reply, PA_DEVICE_TYPE_SINK);
991     pa_tagstruct_putu32(reply, sink->index);
992 
993     /* Read or create an entry */
994     name = pa_sprintf_malloc("sink:%s", sink->name);
995     if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
996         /* Fake a reply with PCM encoding supported */
997         pa_format_info *f = pa_format_info_new();
998 
999         pa_tagstruct_putu8(reply, 1);
1000         f->encoding = PA_ENCODING_PCM;
1001         pa_tagstruct_put_format_info(reply, f);
1002 
1003         pa_format_info_free(f);
1004     } else {
1005         uint32_t idx;
1006         pa_format_info *f;
1007 
1008         /* Write all the formats from the entry to the reply */
1009         pa_tagstruct_putu8(reply, pa_idxset_size(e->formats));
1010         PA_IDXSET_FOREACH(f, e->formats, idx) {
1011             pa_tagstruct_put_format_info(reply, f);
1012         }
1013         perportentry_free(e);
1014     }
1015     pa_xfree(name);
1016 }
1017 
extension_cb(pa_native_protocol * p,pa_module * m,pa_native_connection * c,uint32_t tag,pa_tagstruct * t)1018 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
1019     struct userdata *u;
1020     uint32_t command;
1021     pa_tagstruct *reply = NULL;
1022 
1023     pa_assert(p);
1024     pa_assert(m);
1025     pa_assert(c);
1026     pa_assert(t);
1027 
1028     u = m->userdata;
1029 
1030     if (pa_tagstruct_getu32(t, &command) < 0)
1031         goto fail;
1032 
1033     reply = pa_tagstruct_new();
1034     pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1035     pa_tagstruct_putu32(reply, tag);
1036 
1037     switch (command) {
1038         case SUBCOMMAND_TEST: {
1039             if (!pa_tagstruct_eof(t))
1040                 goto fail;
1041 
1042             pa_tagstruct_putu32(reply, EXT_VERSION);
1043             break;
1044         }
1045 
1046         case SUBCOMMAND_SUBSCRIBE: {
1047 
1048             bool enabled;
1049 
1050             if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1051                 !pa_tagstruct_eof(t))
1052                 goto fail;
1053 
1054             if (enabled)
1055                 pa_idxset_put(u->subscribed, c, NULL);
1056             else
1057                 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1058 
1059             break;
1060         }
1061 
1062         case SUBCOMMAND_READ_FORMATS_ALL: {
1063             pa_sink *sink;
1064             uint32_t idx;
1065 
1066             if (!pa_tagstruct_eof(t))
1067                 goto fail;
1068 
1069             PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
1070                 read_sink_format_reply(u, reply, sink);
1071             }
1072 
1073             break;
1074         }
1075         case SUBCOMMAND_READ_FORMATS: {
1076             pa_device_type_t type;
1077             uint32_t sink_index;
1078             pa_sink *sink;
1079 
1080             pa_assert(reply);
1081 
1082             /* Get the sink index and the number of formats from the tagstruct */
1083             if (pa_tagstruct_getu32(t, &type) < 0 ||
1084                 pa_tagstruct_getu32(t, &sink_index) < 0)
1085                 goto fail;
1086 
1087             if (type != PA_DEVICE_TYPE_SINK) {
1088                 pa_log("Device format reading is only supported on sinks");
1089                 goto fail;
1090             }
1091 
1092             if (!pa_tagstruct_eof(t))
1093                 goto fail;
1094 
1095             /* Now find our sink */
1096             if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
1097                 goto fail;
1098 
1099             read_sink_format_reply(u, reply, sink);
1100 
1101             break;
1102         }
1103 
1104         case SUBCOMMAND_SAVE_FORMATS: {
1105 
1106             struct perportentry *e;
1107             pa_device_type_t type;
1108             uint32_t sink_index;
1109             char *name;
1110             pa_sink *sink;
1111             uint8_t i, n_formats;
1112 
1113             /* Get the sink index and the number of formats from the tagstruct */
1114             if (pa_tagstruct_getu32(t, &type) < 0 ||
1115                 pa_tagstruct_getu32(t, &sink_index) < 0 ||
1116                 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
1117 
1118                 goto fail;
1119             }
1120 
1121             if (type != PA_DEVICE_TYPE_SINK) {
1122                 pa_log("Device format saving is only supported on sinks");
1123                 goto fail;
1124             }
1125 
1126             /* Now find our sink */
1127             if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) {
1128                 pa_log("Could not find sink #%d", sink_index);
1129                 goto fail;
1130             }
1131 
1132             /* Read or create an entry */
1133             name = pa_sprintf_malloc("sink:%s", sink->name);
1134             if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL))))
1135                 e = perportentry_new(false);
1136             else {
1137                 /* Clean out any saved formats */
1138                 pa_idxset_free(e->formats, (pa_free_cb_t) pa_format_info_free);
1139                 e->formats = pa_idxset_new(NULL, NULL);
1140             }
1141 
1142             /* Read all the formats from our tagstruct */
1143             for (i = 0; i < n_formats; ++i) {
1144                 pa_format_info *f = pa_format_info_new();
1145                 if (pa_tagstruct_get_format_info(t, f) < 0) {
1146                     pa_format_info_free(f);
1147                     perportentry_free(e);
1148                     pa_xfree(name);
1149                     goto fail;
1150                 }
1151                 pa_idxset_put(e->formats, f, NULL);
1152             }
1153 
1154             if (!pa_tagstruct_eof(t)) {
1155                 perportentry_free(e);
1156                 pa_xfree(name);
1157                 goto fail;
1158             }
1159 
1160             if (pa_sink_set_formats(sink, e->formats) && perportentry_write(u, name, (sink->active_port ? sink->active_port->name : NULL), e))
1161                 trigger_save(u, type, sink_index);
1162             else
1163                 pa_log_warn("Could not save format info for sink %s", sink->name);
1164 
1165             pa_xfree(name);
1166             perportentry_free(e);
1167 
1168             break;
1169         }
1170 
1171         default:
1172             goto fail;
1173     }
1174 
1175     pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1176     return 0;
1177 
1178 fail:
1179 
1180     if (reply)
1181         pa_tagstruct_free(reply);
1182 
1183     return -1;
1184 }
1185 
connection_unlink_hook_cb(pa_native_protocol * p,pa_native_connection * c,struct userdata * u)1186 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1187     pa_assert(p);
1188     pa_assert(c);
1189     pa_assert(u);
1190 
1191     pa_idxset_remove_by_data(u->subscribed, c, NULL);
1192     return PA_HOOK_OK;
1193 }
1194 
pa__init(pa_module * m)1195 int pa__init(pa_module*m) {
1196     pa_modargs *ma = NULL;
1197     struct userdata *u;
1198     char *state_path;
1199     pa_sink *sink;
1200     pa_source *source;
1201     uint32_t idx;
1202     bool restore_volume = true, restore_muted = true, restore_port = true, restore_formats = true;
1203 
1204     pa_assert(m);
1205 
1206     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1207         pa_log("Failed to parse module arguments");
1208         goto fail;
1209     }
1210 
1211     if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
1212         pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
1213         pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0 ||
1214         pa_modargs_get_value_boolean(ma, "restore_formats", &restore_formats) < 0) {
1215         pa_log("restore_port, restore_volume, restore_muted and restore_formats expect boolean arguments");
1216         goto fail;
1217     }
1218 
1219     if (!restore_muted && !restore_volume && !restore_port && !restore_formats)
1220         pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!");
1221 
1222     m->userdata = u = pa_xnew0(struct userdata, 1);
1223     u->core = m->core;
1224     u->module = m;
1225     u->restore_volume = restore_volume;
1226     u->restore_muted = restore_muted;
1227     u->restore_port = restore_port;
1228     u->restore_formats = restore_formats;
1229 
1230     u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1231 
1232     u->protocol = pa_native_protocol_get(m->core);
1233     pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1234 
1235     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);
1236 
1237     u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
1238 
1239     if (restore_port) {
1240         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);
1241         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);
1242     }
1243 
1244     if (restore_muted || restore_volume) {
1245         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);
1246         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);
1247 
1248         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);
1249         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);
1250     }
1251 
1252     if (restore_formats)
1253         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);
1254 
1255     if (!(state_path = pa_state_path(NULL, true)))
1256         goto fail;
1257 
1258     if (!(u->database = pa_database_open(state_path, "device-volumes", true, true))) {
1259         pa_xfree(state_path);
1260         goto fail;
1261     }
1262 
1263     pa_xfree(state_path);
1264 
1265     PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
1266         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1267 
1268     PA_IDXSET_FOREACH(source, m->core->sources, idx)
1269         subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
1270 
1271     pa_modargs_free(ma);
1272     return 0;
1273 
1274 fail:
1275     pa__done(m);
1276 
1277     if (ma)
1278         pa_modargs_free(ma);
1279 
1280     return -1;
1281 }
1282 
pa__done(pa_module * m)1283 void pa__done(pa_module*m) {
1284     struct userdata* u;
1285 
1286     pa_assert(m);
1287 
1288     if (!(u = m->userdata))
1289         return;
1290 
1291     if (u->subscription)
1292         pa_subscription_free(u->subscription);
1293 
1294     if (u->save_time_event) {
1295         u->core->mainloop->time_free(u->save_time_event);
1296         pa_database_sync(u->database);
1297     }
1298 
1299     if (u->database)
1300         pa_database_close(u->database);
1301 
1302     if (u->protocol) {
1303         pa_native_protocol_remove_ext(u->protocol, m);
1304         pa_native_protocol_unref(u->protocol);
1305     }
1306 
1307     if (u->subscribed)
1308         pa_idxset_free(u->subscribed, NULL);
1309 
1310     pa_xfree(u);
1311 }
1312