]> code.delx.au - pulseaudio/blob - src/modules/module-device-restore.c
device-restore: Restore volumes on port change.
[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 for (c = pa_idxset_first(u->subscribed, &idx); c; c = pa_idxset_next(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 pa_bool_t perportentry_write(struct userdata *u, const char *name, const struct perportentry *e);
181 static void perportentry_free(struct perportentry* e);
182 #endif
183
184 static struct entry* entry_new() {
185 struct entry *r = pa_xnew0(struct entry, 1);
186 r->version = ENTRY_VERSION;
187 return r;
188 }
189
190 static void entry_free(struct entry* e) {
191 pa_assert(e);
192
193 pa_xfree(e->port);
194 pa_xfree(e);
195 }
196
197 static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e) {
198 pa_tagstruct *t;
199 pa_datum key, data;
200 pa_bool_t r;
201
202 pa_assert(u);
203 pa_assert(name);
204 pa_assert(e);
205
206 t = pa_tagstruct_new(NULL, 0);
207 pa_tagstruct_putu8(t, e->version);
208 pa_tagstruct_put_boolean(t, e->port_valid);
209 pa_tagstruct_puts(t, e->port);
210
211 key.data = (char *) name;
212 key.size = strlen(name);
213
214 data.data = (void*)pa_tagstruct_data(t, &data.size);
215
216 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
217
218 pa_tagstruct_free(t);
219
220 return r;
221 }
222
223 static struct entry* entry_read(struct userdata *u, const char *name) {
224 pa_datum key, data;
225 struct entry *e = NULL;
226 pa_tagstruct *t = NULL;
227 const char* port;
228
229 pa_assert(u);
230 pa_assert(name);
231
232 key.data = (char*) name;
233 key.size = strlen(name);
234
235 pa_zero(data);
236
237 if (!pa_database_get(u->database, &key, &data))
238 goto fail;
239
240 t = pa_tagstruct_new(data.data, data.size);
241 e = entry_new(FALSE);
242
243 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
244 e->version > ENTRY_VERSION ||
245 pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
246 pa_tagstruct_gets(t, &port) < 0) {
247
248 goto fail;
249 }
250
251 if (!pa_tagstruct_eof(t))
252 goto fail;
253
254 e->port = pa_xstrdup(port);
255
256 pa_tagstruct_free(t);
257 pa_datum_free(&data);
258
259 return e;
260
261 fail:
262
263 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
264
265 if (e)
266 entry_free(e);
267 if (t)
268 pa_tagstruct_free(t);
269
270 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
271 {
272 struct perportentry *ppe;
273 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
274 if (legacy_entry_read(u, &data, &e, &ppe)) {
275 pa_bool_t written = FALSE;
276 pa_device_port *dport;
277 char *ppename;
278 void *state = NULL;
279
280 pa_log_debug("Success. Saving new format for key: %s", name);
281 written = entry_write(u, name, e);
282
283 /* Now convert the legacy entry into per-port entries */
284 if (0 == strncmp("sink:", name, 5)) {
285 pa_sink *sink;
286
287 if ((sink = pa_namereg_get(u->core, name+5, PA_NAMEREG_SINK))) {
288 if (sink->ports) {
289 PA_HASHMAP_FOREACH(dport, sink->ports, state) {
290 ppename = pa_sprintf_malloc("%s:%s", name, dport->name);
291 written = perportentry_write(u, ppename, ppe) || written;
292 pa_xfree(ppename);
293 }
294 } else {
295 ppename = pa_sprintf_malloc("%s:%s", name, "null");
296 written = perportentry_write(u, ppename, ppe) || written;
297 pa_xfree(ppename);
298 }
299 }
300 } else if (0 == strncmp("source:", name, 7)) {
301 pa_source *source;
302
303 if ((source = pa_namereg_get(u->core, name+7, PA_NAMEREG_SOURCE))) {
304 if (source->ports) {
305 PA_HASHMAP_FOREACH(dport, source->ports, state) {
306 ppename = pa_sprintf_malloc("%s:%s", name, dport->name);
307 written = perportentry_write(u, ppename, ppe) || written;
308 pa_xfree(ppename);
309 }
310 } else {
311 ppename = pa_sprintf_malloc("%s:%s", name, "null");
312 written = perportentry_write(u, ppename, ppe) || written;
313 pa_xfree(ppename);
314 }
315 }
316 }
317 perportentry_free(ppe);
318
319 if (written)
320 /* NB The device type doesn't matter when we pass in an invalid index. */
321 trigger_save(u, PA_DEVICE_TYPE_SINK, PA_INVALID_INDEX);
322
323 pa_datum_free(&data);
324 return e;
325 }
326 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
327 }
328 #endif
329
330 pa_datum_free(&data);
331 return NULL;
332 }
333
334 static struct entry* entry_copy(const struct entry *e) {
335 struct entry* r;
336
337 pa_assert(e);
338 r = entry_new();
339 r->version = e->version;
340 r->port_valid = e->port_valid;
341 r->port = pa_xstrdup(e->port);
342
343 return r;
344 }
345
346 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
347
348 pa_assert(a && b);
349
350 if (a->port_valid != b->port_valid ||
351 (a->port_valid && !pa_streq(a->port, b->port)))
352 return FALSE;
353
354 return TRUE;
355 }
356
357 static struct perportentry* perportentry_new(pa_bool_t add_pcm_format) {
358 struct perportentry *r = pa_xnew0(struct perportentry, 1);
359 r->version = PERPORTENTRY_VERSION;
360 r->formats = pa_idxset_new(NULL, NULL);
361 if (add_pcm_format) {
362 pa_format_info *f = pa_format_info_new();
363 f->encoding = PA_ENCODING_PCM;
364 pa_idxset_put(r->formats, f, NULL);
365 }
366 return r;
367 }
368
369 static void perportentry_free(struct perportentry* e) {
370 pa_assert(e);
371
372 pa_idxset_free(e->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
373 pa_xfree(e);
374 }
375
376 static pa_bool_t perportentry_write(struct userdata *u, const char *name, const struct perportentry *e) {
377 pa_tagstruct *t;
378 pa_datum key, data;
379 pa_bool_t r;
380 uint32_t i;
381 pa_format_info *f;
382 uint8_t n_formats;
383
384 pa_assert(u);
385 pa_assert(name);
386 pa_assert(e);
387
388 n_formats = pa_idxset_size(e->formats);
389 pa_assert(n_formats > 0);
390
391 t = pa_tagstruct_new(NULL, 0);
392 pa_tagstruct_putu8(t, e->version);
393 pa_tagstruct_put_boolean(t, e->volume_valid);
394 pa_tagstruct_put_channel_map(t, &e->channel_map);
395 pa_tagstruct_put_cvolume(t, &e->volume);
396 pa_tagstruct_put_boolean(t, e->muted_valid);
397 pa_tagstruct_put_boolean(t, e->muted);
398 pa_tagstruct_putu8(t, n_formats);
399
400 PA_IDXSET_FOREACH(f, e->formats, i) {
401 pa_tagstruct_put_format_info(t, f);
402 }
403
404 key.data = (char *) name;
405 key.size = strlen(name);
406
407 data.data = (void*)pa_tagstruct_data(t, &data.size);
408
409 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
410
411 pa_tagstruct_free(t);
412
413 return r;
414 }
415
416 static struct perportentry* perportentry_read(struct userdata *u, const char *name) {
417 pa_datum key, data;
418 struct perportentry *e = NULL;
419 pa_tagstruct *t = NULL;
420 uint8_t i, n_formats;
421
422 pa_assert(u);
423 pa_assert(name);
424
425 key.data = (char*) name;
426 key.size = strlen(name);
427
428 pa_zero(data);
429
430 if (!pa_database_get(u->database, &key, &data))
431 goto fail;
432
433 t = pa_tagstruct_new(data.data, data.size);
434 e = perportentry_new(FALSE);
435
436 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
437 e->version > PERPORTENTRY_VERSION ||
438 pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
439 pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
440 pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
441 pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
442 pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
443 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
444
445 goto fail;
446 }
447
448 for (i = 0; i < n_formats; ++i) {
449 pa_format_info *f = pa_format_info_new();
450 if (pa_tagstruct_get_format_info(t, f) < 0) {
451 pa_format_info_free(f);
452 goto fail;
453 }
454 pa_idxset_put(e->formats, f, NULL);
455 }
456
457 if (!pa_tagstruct_eof(t))
458 goto fail;
459
460 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
461 pa_log_warn("Invalid channel map stored in database for device %s", name);
462 goto fail;
463 }
464
465 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
466 pa_log_warn("Volume and channel map don't match in database entry for device %s", name);
467 goto fail;
468 }
469
470 pa_tagstruct_free(t);
471 pa_datum_free(&data);
472
473 return e;
474
475 fail:
476
477 pa_log_debug("Database contains invalid data for key: %s", name);
478
479 if (e)
480 perportentry_free(e);
481 if (t)
482 pa_tagstruct_free(t);
483
484 pa_datum_free(&data);
485 return NULL;
486 }
487
488 static struct perportentry* perportentry_copy(const struct perportentry *e) {
489 struct perportentry* r;
490 uint32_t idx;
491 pa_format_info *f;
492
493 pa_assert(e);
494 r = perportentry_new(FALSE);
495 r->version = e->version;
496 r->muted_valid = e->muted_valid;
497 r->volume_valid = e->volume_valid;
498 r->muted = e->muted;
499 r->channel_map = e->channel_map;
500 r->volume = e->volume;
501
502 PA_IDXSET_FOREACH(f, e->formats, idx) {
503 pa_idxset_put(r->formats, pa_format_info_copy(f), NULL);
504 }
505 return r;
506 }
507
508 static pa_bool_t perportentries_equal(const struct perportentry *a, const struct perportentry *b) {
509 pa_cvolume t;
510
511 pa_assert(a && b);
512
513 if (a->muted_valid != b->muted_valid ||
514 (a->muted_valid && (a->muted != b->muted)))
515 return FALSE;
516
517 t = b->volume;
518 if (a->volume_valid != b->volume_valid ||
519 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
520 return FALSE;
521
522 if (pa_idxset_size(a->formats) != pa_idxset_size(b->formats))
523 return FALSE;
524
525 /** TODO: Compare a bit better */
526
527 return TRUE;
528 }
529
530 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
531
532 #define LEGACY_ENTRY_VERSION 2
533 static pa_bool_t legacy_entry_read(struct userdata *u, pa_datum *data, struct entry **entry, struct perportentry **perportentry) {
534 struct legacy_entry {
535 uint8_t version;
536 pa_bool_t muted_valid:1, volume_valid:1, port_valid:1;
537 pa_bool_t muted:1;
538 pa_channel_map channel_map;
539 pa_cvolume volume;
540 char port[PA_NAME_MAX];
541 } PA_GCC_PACKED;
542 struct legacy_entry *le;
543
544 pa_assert(u);
545 pa_assert(data);
546 pa_assert(entry);
547 pa_assert(perportentry);
548
549 if (data->size != sizeof(struct legacy_entry)) {
550 pa_log_debug("Size does not match.");
551 return FALSE;
552 }
553
554 le = (struct legacy_entry*)data->data;
555
556 if (le->version != LEGACY_ENTRY_VERSION) {
557 pa_log_debug("Version mismatch.");
558 return FALSE;
559 }
560
561 if (!memchr(le->port, 0, sizeof(le->port))) {
562 pa_log_warn("Port has missing NUL byte.");
563 return FALSE;
564 }
565
566 if (le->volume_valid && !pa_channel_map_valid(&le->channel_map)) {
567 pa_log_warn("Invalid channel map.");
568 return FALSE;
569 }
570
571 if (le->volume_valid && (!pa_cvolume_valid(&le->volume) || !pa_cvolume_compatible_with_channel_map(&le->volume, &le->channel_map))) {
572 pa_log_warn("Volume and channel map don't match.");
573 return FALSE;
574 }
575
576 *entry = entry_new();
577 (*entry)->port_valid = le->port_valid;
578 (*entry)->port = pa_xstrdup(le->port);
579
580 *perportentry = perportentry_new(TRUE);
581 (*perportentry)->muted_valid = le->muted_valid;
582 (*perportentry)->volume_valid = le->volume_valid;
583 (*perportentry)->muted = le->muted;
584 (*perportentry)->channel_map = le->channel_map;
585 (*perportentry)->volume = le->volume;
586
587 return TRUE;
588 }
589 #endif
590
591 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
592 struct userdata *u = userdata;
593 struct entry *e, *olde;
594 struct perportentry *ppe, *oldppe;
595 char *ename, *ppename;
596 pa_device_type_t type;
597 pa_bool_t 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
616 ename = pa_sprintf_malloc("sink:%s", sink->name);
617 if ((olde = entry_read(u, ename)))
618 e = entry_copy(olde);
619 else
620 e = entry_new();
621
622 if (sink->save_port) {
623 pa_xfree(e->port);
624 e->port = pa_xstrdup(sink->active_port ? sink->active_port->name : "");
625 e->port_valid = TRUE;
626 }
627
628 ppename = pa_sprintf_malloc("sink:%s:%s", sink->name, (sink->active_port ? sink->active_port->name : "null"));
629 if ((oldppe = perportentry_read(u, ppename)))
630 ppe = perportentry_copy(oldppe);
631 else
632 ppe = perportentry_new(TRUE);
633
634 if (sink->save_volume) {
635 ppe->channel_map = sink->channel_map;
636 ppe->volume = *pa_sink_get_volume(sink, FALSE);
637 ppe->volume_valid = TRUE;
638 }
639
640 if (sink->save_muted) {
641 ppe->muted = pa_sink_get_mute(sink, FALSE);
642 ppe->muted_valid = TRUE;
643 }
644 } else {
645 pa_source *source;
646
647 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
648
649 if (!(source = pa_idxset_get_by_index(c->sources, idx)))
650 return;
651
652 type = PA_DEVICE_TYPE_SOURCE;
653
654 ename = pa_sprintf_malloc("source:%s", source->name);
655 if ((olde = entry_read(u, ename)))
656 e = entry_copy(olde);
657 else
658 e = entry_new();
659
660 if (source->save_port) {
661 pa_xfree(e->port);
662 e->port = pa_xstrdup(source->active_port ? source->active_port->name : "");
663 e->port_valid = TRUE;
664 }
665
666 ppename = pa_sprintf_malloc("source:%s:%s", source->name, (source->active_port ? source->active_port->name : "null"));
667 if ((oldppe = perportentry_read(u, ppename)))
668 ppe = perportentry_copy(oldppe);
669 else
670 ppe = perportentry_new(TRUE);
671
672 if (source->save_volume) {
673 ppe->channel_map = source->channel_map;
674 ppe->volume = *pa_source_get_volume(source, FALSE);
675 ppe->volume_valid = TRUE;
676 }
677
678 if (source->save_muted) {
679 ppe->muted = pa_source_get_mute(source, FALSE);
680 ppe->muted_valid = TRUE;
681 }
682 }
683
684
685 pa_assert(e);
686
687 if (olde) {
688
689 if (entries_equal(olde, e)) {
690 entry_free(olde);
691 entry_free(e);
692 e = NULL;
693 } else
694 entry_free(olde);
695 }
696
697 if (e) {
698 pa_log_info("Storing port for device %s.", ename);
699
700 written = entry_write(u, ename, e);
701
702 entry_free(e);
703 }
704 pa_xfree(ename);
705
706
707 pa_assert(ppe);
708
709 if (oldppe) {
710
711 if (perportentries_equal(oldppe, ppe)) {
712 perportentry_free(oldppe);
713 perportentry_free(ppe);
714 ppe = NULL;
715 } else
716 perportentry_free(oldppe);
717 }
718
719 if (ppe) {
720 pa_log_info("Storing volume/mute for device+port %s.", ppename);
721
722 written = perportentry_write(u, ppename, ppe) || written;
723
724 perportentry_free(ppe);
725 }
726 pa_xfree(ppename);
727
728 if (written)
729 trigger_save(u, type, idx);
730 }
731
732 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
733 char *name;
734 struct entry *e;
735
736 pa_assert(c);
737 pa_assert(new_data);
738 pa_assert(u);
739 pa_assert(u->restore_port);
740
741 name = pa_sprintf_malloc("sink:%s", new_data->name);
742
743 if ((e = entry_read(u, name))) {
744
745 if (e->port_valid) {
746 if (!new_data->active_port) {
747 pa_log_info("Restoring port for sink %s.", name);
748 pa_sink_new_data_set_port(new_data, e->port);
749 new_data->save_port = TRUE;
750 } else
751 pa_log_debug("Not restoring port for sink %s, because already set.", name);
752 }
753
754 entry_free(e);
755 }
756
757 pa_xfree(name);
758
759 return PA_HOOK_OK;
760 }
761
762 static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
763 char *name;
764 struct perportentry *e;
765
766 pa_assert(c);
767 pa_assert(new_data);
768 pa_assert(u);
769 pa_assert(u->restore_volume || u->restore_muted);
770
771 name = pa_sprintf_malloc("sink:%s:%s", new_data->name, (new_data->active_port ? new_data->active_port : "null"));
772
773 if ((e = perportentry_read(u, name))) {
774
775 if (u->restore_volume && e->volume_valid) {
776
777 if (!new_data->volume_is_set) {
778 pa_cvolume v;
779
780 pa_log_info("Restoring volume for sink %s.", new_data->name);
781
782 v = e->volume;
783 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
784 pa_sink_new_data_set_volume(new_data, &v);
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:%s", sink->name, (sink->active_port ? sink->active_port->name : "null"));
819
820 if ((e = perportentry_read(u, name))) {
821
822 if (u->restore_volume && e->volume_valid) {
823
824 pa_cvolume v;
825
826 pa_log_info("Restoring volume for sink %s.", sink->name);
827
828 v = e->volume;
829 pa_cvolume_remap(&v, &e->channel_map, &sink->channel_map);
830 pa_sink_set_volume(sink, &v, TRUE, FALSE);
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:%s", sink->name, (sink->active_port ? sink->active_port->name : "null"));
859
860 if ((e = perportentry_read(u, name))) {
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:%s", new_data->name, (new_data->active_port ? new_data->active_port : "null"));
913
914 if ((e = perportentry_read(u, name))) {
915
916 if (u->restore_volume && e->volume_valid) {
917
918 if (!new_data->volume_is_set) {
919 pa_cvolume v;
920
921 pa_log_info("Restoring volume for source %s.", new_data->name);
922
923 v = e->volume;
924 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
925 pa_source_new_data_set_volume(new_data, &v);
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:%s", source->name, (source->active_port ? source->active_port->name : "null"));
960
961 if ((e = perportentry_read(u, name))) {
962
963 if (u->restore_volume && e->volume_valid) {
964
965 pa_cvolume v;
966
967 pa_log_info("Restoring volume for source %s.", source->name);
968
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 source->save_volume = TRUE;
973 }
974
975 if (u->restore_muted && e->muted_valid) {
976
977 pa_log_info("Restoring mute state for source %s.", source->name);
978 pa_source_set_mute(source, e->muted, FALSE);
979 source->save_muted = TRUE;
980 }
981
982 perportentry_free(e);
983 }
984
985 pa_xfree(name);
986
987 return PA_HOOK_OK;
988 }
989
990 #define EXT_VERSION 1
991
992 static void read_sink_format_reply(struct userdata *u, pa_tagstruct *reply, pa_sink *sink) {
993 struct perportentry *e;
994 char *name;
995
996 pa_assert(u);
997 pa_assert(reply);
998 pa_assert(sink);
999
1000 pa_tagstruct_putu32(reply, PA_DEVICE_TYPE_SINK);
1001 pa_tagstruct_putu32(reply, sink->index);
1002
1003 /* Read or create an entry */
1004 name = pa_sprintf_malloc("sink:%s:%s", sink->name, (sink->active_port ? sink->active_port->name : "null"));
1005 if (!(e = perportentry_read(u, name))) {
1006 /* Fake a reply with PCM encoding supported */
1007 pa_format_info *f = pa_format_info_new();
1008
1009 pa_tagstruct_putu8(reply, 1);
1010 f->encoding = PA_ENCODING_PCM;
1011 pa_tagstruct_put_format_info(reply, f);
1012
1013 pa_format_info_free(f);
1014 } else {
1015 uint32_t idx;
1016 pa_format_info *f;
1017
1018 /* Write all the formats from the entry to the reply */
1019 pa_tagstruct_putu8(reply, pa_idxset_size(e->formats));
1020 PA_IDXSET_FOREACH(f, e->formats, idx) {
1021 pa_tagstruct_put_format_info(reply, f);
1022 }
1023 }
1024 pa_xfree(name);
1025 }
1026
1027 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
1028 struct userdata *u;
1029 uint32_t command;
1030 pa_tagstruct *reply = NULL;
1031
1032 pa_assert(p);
1033 pa_assert(m);
1034 pa_assert(c);
1035 pa_assert(t);
1036
1037 u = m->userdata;
1038
1039 if (pa_tagstruct_getu32(t, &command) < 0)
1040 goto fail;
1041
1042 reply = pa_tagstruct_new(NULL, 0);
1043 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
1044 pa_tagstruct_putu32(reply, tag);
1045
1046 switch (command) {
1047 case SUBCOMMAND_TEST: {
1048 if (!pa_tagstruct_eof(t))
1049 goto fail;
1050
1051 pa_tagstruct_putu32(reply, EXT_VERSION);
1052 break;
1053 }
1054
1055 case SUBCOMMAND_SUBSCRIBE: {
1056
1057 pa_bool_t enabled;
1058
1059 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
1060 !pa_tagstruct_eof(t))
1061 goto fail;
1062
1063 if (enabled)
1064 pa_idxset_put(u->subscribed, c, NULL);
1065 else
1066 pa_idxset_remove_by_data(u->subscribed, c, NULL);
1067
1068 break;
1069 }
1070
1071 case SUBCOMMAND_READ_FORMATS_ALL: {
1072 pa_sink *sink;
1073 uint32_t idx;
1074
1075 if (!pa_tagstruct_eof(t))
1076 goto fail;
1077
1078 PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
1079 read_sink_format_reply(u, reply, sink);
1080 }
1081
1082 break;
1083 }
1084 case SUBCOMMAND_READ_FORMATS: {
1085 pa_device_type_t type;
1086 uint32_t sink_index;
1087 pa_sink *sink;
1088
1089 pa_assert(reply);
1090
1091 /* Get the sink index and the number of formats from the tagstruct */
1092 if (pa_tagstruct_getu32(t, &type) < 0 ||
1093 pa_tagstruct_getu32(t, &sink_index) < 0)
1094 goto fail;
1095
1096 if (type != PA_DEVICE_TYPE_SINK) {
1097 pa_log("Device format reading is only supported on sinks");
1098 goto fail;
1099 }
1100
1101 if (!pa_tagstruct_eof(t))
1102 goto fail;
1103
1104 /* Now find our sink */
1105 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
1106 goto fail;
1107
1108 read_sink_format_reply(u, reply, sink);
1109
1110 break;
1111 }
1112
1113 case SUBCOMMAND_SAVE_FORMATS: {
1114
1115 struct perportentry *e;
1116 pa_device_type_t type;
1117 uint32_t sink_index;
1118 char *name;
1119 pa_sink *sink;
1120 uint8_t i, n_formats;
1121
1122 /* Get the sink index and the number of formats from the tagstruct */
1123 if (pa_tagstruct_getu32(t, &type) < 0 ||
1124 pa_tagstruct_getu32(t, &sink_index) < 0 ||
1125 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
1126
1127 goto fail;
1128 }
1129
1130 if (type != PA_DEVICE_TYPE_SINK) {
1131 pa_log("Device format saving is only supported on sinks");
1132 goto fail;
1133 }
1134
1135 /* Now find our sink */
1136 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index))) {
1137 pa_log("Could not find sink #%d", sink_index);
1138 goto fail;
1139 }
1140
1141 /* Read or create an entry */
1142 name = pa_sprintf_malloc("sink:%s:%s", sink->name, (sink->active_port ? sink->active_port->name : "null"));
1143 if (!(e = perportentry_read(u, name)))
1144 e = perportentry_new(FALSE);
1145 else {
1146 /* Clean out any saved formats */
1147 pa_idxset_free(e->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
1148 e->formats = pa_idxset_new(NULL, NULL);
1149 }
1150
1151 /* Read all the formats from our tagstruct */
1152 for (i = 0; i < n_formats; ++i) {
1153 pa_format_info *f = pa_format_info_new();
1154 if (pa_tagstruct_get_format_info(t, f) < 0) {
1155 pa_format_info_free(f);
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, 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 pa_bool_t 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 for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx))
1276 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
1277
1278 for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(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, NULL);
1335
1336 pa_xfree(u);
1337 }