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