]> code.delx.au - pulseaudio/blob - src/modules/module-device-restore.c
0490677b38e681215e979c42e8a321cc152319a6
[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_log_info("Restoring mute state for sink %s.", new_data->name);
795 pa_sink_new_data_set_muted(new_data, e->muted);
796 new_data->save_muted = true;
797 } else
798 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
799 }
800
801 perportentry_free(e);
802 }
803
804 pa_xfree(name);
805
806 return PA_HOOK_OK;
807 }
808
809 static pa_hook_result_t sink_port_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
810 char *name;
811 struct perportentry *e;
812
813 pa_assert(c);
814 pa_assert(sink);
815 pa_assert(u);
816 pa_assert(u->restore_volume || u->restore_muted);
817
818 name = pa_sprintf_malloc("sink:%s", sink->name);
819
820 if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
821
822 if (u->restore_volume && e->volume_valid) {
823 pa_cvolume v;
824
825 pa_log_info("Restoring volume for sink %s.", sink->name);
826 v = e->volume;
827 pa_cvolume_remap(&v, &e->channel_map, &sink->channel_map);
828 pa_sink_set_volume(sink, &v, true, false);
829
830 sink->save_volume = true;
831 }
832
833 if (u->restore_muted && e->muted_valid) {
834
835 pa_log_info("Restoring mute state for sink %s.", sink->name);
836 pa_sink_set_mute(sink, e->muted, false);
837 sink->save_muted = true;
838 }
839
840 perportentry_free(e);
841 }
842
843 pa_xfree(name);
844
845 return PA_HOOK_OK;
846 }
847
848 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
849 char *name;
850 struct perportentry *e;
851
852 pa_assert(c);
853 pa_assert(sink);
854 pa_assert(u);
855 pa_assert(u->restore_formats);
856
857 name = pa_sprintf_malloc("sink:%s", sink->name);
858
859 if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
860
861 if (!pa_sink_set_formats(sink, e->formats))
862 pa_log_debug("Could not set format on sink %s", sink->name);
863
864 perportentry_free(e);
865 }
866
867 pa_xfree(name);
868
869 return PA_HOOK_OK;
870 }
871
872 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
873 char *name;
874 struct entry *e;
875
876 pa_assert(c);
877 pa_assert(new_data);
878 pa_assert(u);
879 pa_assert(u->restore_port);
880
881 name = pa_sprintf_malloc("source:%s", new_data->name);
882
883 if ((e = entry_read(u, name))) {
884
885 if (e->port_valid) {
886 if (!new_data->active_port) {
887 pa_log_info("Restoring port for source %s.", name);
888 pa_source_new_data_set_port(new_data, e->port);
889 new_data->save_port = true;
890 } else
891 pa_log_debug("Not restoring port for source %s, because already set.", name);
892 }
893
894 entry_free(e);
895 }
896
897 pa_xfree(name);
898
899 return PA_HOOK_OK;
900 }
901
902 static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
903 char *name;
904 struct perportentry *e;
905
906 pa_assert(c);
907 pa_assert(new_data);
908 pa_assert(u);
909 pa_assert(u->restore_volume || u->restore_muted);
910
911 name = pa_sprintf_malloc("source:%s", new_data->name);
912
913 if ((e = perportentry_read(u, name, new_data->active_port))) {
914
915 if (u->restore_volume && e->volume_valid) {
916
917 if (!new_data->volume_is_set) {
918 pa_cvolume v;
919 char buf[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
920
921 v = e->volume;
922 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
923 pa_source_new_data_set_volume(new_data, &v);
924 pa_log_info("Restoring volume for source %s: %s", new_data->name,
925 pa_cvolume_snprint_verbose(buf, sizeof(buf), &new_data->volume, &new_data->channel_map, false));
926
927 new_data->save_volume = true;
928 } else
929 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
930 }
931
932 if (u->restore_muted && e->muted_valid) {
933
934 if (!new_data->muted_is_set) {
935 pa_log_info("Restoring mute state for source %s.", new_data->name);
936 pa_source_new_data_set_muted(new_data, e->muted);
937 new_data->save_muted = true;
938 } else
939 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
940 }
941
942 perportentry_free(e);
943 }
944
945 pa_xfree(name);
946
947 return PA_HOOK_OK;
948 }
949
950 static pa_hook_result_t source_port_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
951 char *name;
952 struct perportentry *e;
953
954 pa_assert(c);
955 pa_assert(source);
956 pa_assert(u);
957 pa_assert(u->restore_volume || u->restore_muted);
958
959 name = pa_sprintf_malloc("source:%s", source->name);
960
961 if ((e = perportentry_read(u, name, (source->active_port ? source->active_port->name : NULL)))) {
962
963 if (u->restore_volume && e->volume_valid) {
964 pa_cvolume v;
965
966 pa_log_info("Restoring volume for source %s.", source->name);
967 v = e->volume;
968 pa_cvolume_remap(&v, &e->channel_map, &source->channel_map);
969 pa_source_set_volume(source, &v, true, false);
970
971 source->save_volume = true;
972 }
973
974 if (u->restore_muted && e->muted_valid) {
975
976 pa_log_info("Restoring mute state for source %s.", source->name);
977 pa_source_set_mute(source, e->muted, false);
978 source->save_muted = true;
979 }
980
981 perportentry_free(e);
982 }
983
984 pa_xfree(name);
985
986 return PA_HOOK_OK;
987 }
988
989 #define EXT_VERSION 1
990
991 static void read_sink_format_reply(struct userdata *u, pa_tagstruct *reply, pa_sink *sink) {
992 struct perportentry *e;
993 char *name;
994
995 pa_assert(u);
996 pa_assert(reply);
997 pa_assert(sink);
998
999 pa_tagstruct_putu32(reply, PA_DEVICE_TYPE_SINK);
1000 pa_tagstruct_putu32(reply, sink->index);
1001
1002 /* Read or create an entry */
1003 name = pa_sprintf_malloc("sink:%s", sink->name);
1004 if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
1005 /* Fake a reply with PCM encoding supported */
1006 pa_format_info *f = pa_format_info_new();
1007
1008 pa_tagstruct_putu8(reply, 1);
1009 f->encoding = PA_ENCODING_PCM;
1010 pa_tagstruct_put_format_info(reply, f);
1011
1012 pa_format_info_free(f);
1013 } else {
1014 uint32_t idx;
1015 pa_format_info *f;
1016
1017 /* Write all the formats from the entry to the reply */
1018 pa_tagstruct_putu8(reply, pa_idxset_size(e->formats));
1019 PA_IDXSET_FOREACH(f, e->formats, idx) {
1020 pa_tagstruct_put_format_info(reply, f);
1021 }
1022 }
1023 pa_xfree(name);
1024 }
1025
1026 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
1027 struct userdata *u;
1028 uint32_t command;
1029 pa_tagstruct *reply = NULL;
1030
1031 pa_assert(p);
1032 pa_assert(m);
1033 pa_assert(c);
1034 pa_assert(t);
1035
1036 u = m->userdata;
1037
1038 if (pa_tagstruct_getu32(t, &command) < 0)
1039 goto fail;
1040
1041 reply = pa_tagstruct_new(NULL, 0);
1042 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1043 pa_tagstruct_putu32(reply, tag);
1044
1045 switch (command) {
1046 case SUBCOMMAND_TEST: {
1047 if (!pa_tagstruct_eof(t))
1048 goto fail;
1049
1050 pa_tagstruct_putu32(reply, EXT_VERSION);
1051 break;
1052 }
1053
1054 case SUBCOMMAND_SUBSCRIBE: {
1055
1056 bool enabled;
1057
1058 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1059 !pa_tagstruct_eof(t))
1060 goto fail;
1061
1062 if (enabled)
1063 pa_idxset_put(u->subscribed, c, NULL);
1064 else
1065 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1066
1067 break;
1068 }
1069
1070 case SUBCOMMAND_READ_FORMATS_ALL: {
1071 pa_sink *sink;
1072 uint32_t idx;
1073
1074 if (!pa_tagstruct_eof(t))
1075 goto fail;
1076
1077 PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
1078 read_sink_format_reply(u, reply, sink);
1079 }
1080
1081 break;
1082 }
1083 case SUBCOMMAND_READ_FORMATS: {
1084 pa_device_type_t type;
1085 uint32_t sink_index;
1086 pa_sink *sink;
1087
1088 pa_assert(reply);
1089
1090 /* Get the sink index and the number of formats from the tagstruct */
1091 if (pa_tagstruct_getu32(t, &type) < 0 ||
1092 pa_tagstruct_getu32(t, &sink_index) < 0)
1093 goto fail;
1094
1095 if (type != PA_DEVICE_TYPE_SINK) {
1096 pa_log("Device format reading is only supported on sinks");
1097 goto fail;
1098 }
1099
1100 if (!pa_tagstruct_eof(t))
1101 goto fail;
1102
1103 /* Now find our sink */
1104 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
1105 goto fail;
1106
1107 read_sink_format_reply(u, reply, sink);
1108
1109 break;
1110 }
1111
1112 case SUBCOMMAND_SAVE_FORMATS: {
1113
1114 struct perportentry *e;
1115 pa_device_type_t type;
1116 uint32_t sink_index;
1117 char *name;
1118 pa_sink *sink;
1119 uint8_t i, n_formats;
1120
1121 /* Get the sink index and the number of formats from the tagstruct */
1122 if (pa_tagstruct_getu32(t, &type) < 0 ||
1123 pa_tagstruct_getu32(t, &sink_index) < 0 ||
1124 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
1125
1126 goto fail;
1127 }
1128
1129 if (type != PA_DEVICE_TYPE_SINK) {
1130 pa_log("Device format saving is only supported on sinks");
1131 goto fail;
1132 }
1133
1134 /* Now find our sink */
1135 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) {
1136 pa_log("Could not find sink #%d", sink_index);
1137 goto fail;
1138 }
1139
1140 /* Read or create an entry */
1141 name = pa_sprintf_malloc("sink:%s", sink->name);
1142 if (!(e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL))))
1143 e = perportentry_new(false);
1144 else {
1145 /* Clean out any saved formats */
1146 pa_idxset_free(e->formats, (pa_free_cb_t) pa_format_info_free);
1147 e->formats = pa_idxset_new(NULL, NULL);
1148 }
1149
1150 /* Read all the formats from our tagstruct */
1151 for (i = 0; i < n_formats; ++i) {
1152 pa_format_info *f = pa_format_info_new();
1153 if (pa_tagstruct_get_format_info(t, f) < 0) {
1154 pa_format_info_free(f);
1155 perportentry_free(e);
1156 pa_xfree(name);
1157 goto fail;
1158 }
1159 pa_idxset_put(e->formats, f, NULL);
1160 }
1161
1162 if (!pa_tagstruct_eof(t)) {
1163 perportentry_free(e);
1164 pa_xfree(name);
1165 goto fail;
1166 }
1167
1168 if (pa_sink_set_formats(sink, e->formats) && perportentry_write(u, name, (sink->active_port ? sink->active_port->name : NULL), e))
1169 trigger_save(u, type, sink_index);
1170 else
1171 pa_log_warn("Could not save format info for sink %s", sink->name);
1172
1173 pa_xfree(name);
1174 perportentry_free(e);
1175
1176 break;
1177 }
1178
1179 default:
1180 goto fail;
1181 }
1182
1183 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
1184 return 0;
1185
1186 fail:
1187
1188 if (reply)
1189 pa_tagstruct_free(reply);
1190
1191 return -1;
1192 }
1193
1194 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
1195 pa_assert(p);
1196 pa_assert(c);
1197 pa_assert(u);
1198
1199 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1200 return PA_HOOK_OK;
1201 }
1202
1203 int pa__init(pa_module*m) {
1204 pa_modargs *ma = NULL;
1205 struct userdata *u;
1206 char *fname;
1207 pa_sink *sink;
1208 pa_source *source;
1209 uint32_t idx;
1210 bool restore_volume = true, restore_muted = true, restore_port = true, restore_formats = true;
1211
1212 pa_assert(m);
1213
1214 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1215 pa_log("Failed to parse module arguments");
1216 goto fail;
1217 }
1218
1219 if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
1220 pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
1221 pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0 ||
1222 pa_modargs_get_value_boolean(ma, "restore_formats", &restore_formats) < 0) {
1223 pa_log("restore_port, restore_volume, restore_muted and restore_formats expect boolean arguments");
1224 goto fail;
1225 }
1226
1227 if (!restore_muted && !restore_volume && !restore_port && !restore_formats)
1228 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!");
1229
1230 m->userdata = u = pa_xnew0(struct userdata, 1);
1231 u->core = m->core;
1232 u->module = m;
1233 u->restore_volume = restore_volume;
1234 u->restore_muted = restore_muted;
1235 u->restore_port = restore_port;
1236 u->restore_formats = restore_formats;
1237
1238 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
1239
1240 u->protocol = pa_native_protocol_get(m->core);
1241 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
1242
1243 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);
1244
1245 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
1246
1247 if (restore_port) {
1248 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);
1249 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);
1250 }
1251
1252 if (restore_muted || restore_volume) {
1253 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);
1254 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);
1255
1256 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);
1257 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);
1258 }
1259
1260 if (restore_formats)
1261 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);
1262
1263 if (!(fname = pa_state_path("device-volumes", true)))
1264 goto fail;
1265
1266 if (!(u->database = pa_database_open(fname, true))) {
1267 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
1268 pa_xfree(fname);
1269 goto fail;
1270 }
1271
1272 pa_log_info("Successfully opened database file '%s'.", fname);
1273 pa_xfree(fname);
1274
1275 PA_IDXSET_FOREACH(sink, m->core->sinks, idx)
1276 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1277
1278 PA_IDXSET_FOREACH(source, m->core->sources, idx)
1279 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
1280
1281 pa_modargs_free(ma);
1282 return 0;
1283
1284 fail:
1285 pa__done(m);
1286
1287 if (ma)
1288 pa_modargs_free(ma);
1289
1290 return -1;
1291 }
1292
1293 void pa__done(pa_module*m) {
1294 struct userdata* u;
1295
1296 pa_assert(m);
1297
1298 if (!(u = m->userdata))
1299 return;
1300
1301 if (u->subscription)
1302 pa_subscription_free(u->subscription);
1303
1304 if (u->sink_fixate_hook_slot)
1305 pa_hook_slot_free(u->sink_fixate_hook_slot);
1306 if (u->source_fixate_hook_slot)
1307 pa_hook_slot_free(u->source_fixate_hook_slot);
1308 if (u->sink_new_hook_slot)
1309 pa_hook_slot_free(u->sink_new_hook_slot);
1310 if (u->source_new_hook_slot)
1311 pa_hook_slot_free(u->source_new_hook_slot);
1312 if (u->sink_port_hook_slot)
1313 pa_hook_slot_free(u->sink_port_hook_slot);
1314 if (u->source_port_hook_slot)
1315 pa_hook_slot_free(u->source_port_hook_slot);
1316 if (u->sink_put_hook_slot)
1317 pa_hook_slot_free(u->sink_put_hook_slot);
1318
1319 if (u->connection_unlink_hook_slot)
1320 pa_hook_slot_free(u->connection_unlink_hook_slot);
1321
1322 if (u->save_time_event)
1323 u->core->mainloop->time_free(u->save_time_event);
1324
1325 if (u->database)
1326 pa_database_close(u->database);
1327
1328 if (u->protocol) {
1329 pa_native_protocol_remove_ext(u->protocol, m);
1330 pa_native_protocol_unref(u->protocol);
1331 }
1332
1333 if (u->subscribed)
1334 pa_idxset_free(u->subscribed, NULL);
1335
1336 pa_xfree(u);
1337 }