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