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