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