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