]> code.delx.au - pulseaudio/blob - src/modules/module-device-restore.c
Whitespace cleanup: Remove all multiple newlines
[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 #define ENTRY_VERSION 1
115
116 struct entry {
117 uint8_t version;
118 pa_bool_t port_valid;
119 char *port;
120 };
121
122 #define PERPORTENTRY_VERSION 1
123
124 struct perportentry {
125 uint8_t version;
126 pa_bool_t muted_valid, volume_valid;
127 pa_bool_t muted;
128 pa_channel_map channel_map;
129 pa_cvolume volume;
130 pa_idxset *formats;
131 };
132
133 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
134 struct userdata *u = userdata;
135
136 pa_assert(a);
137 pa_assert(e);
138 pa_assert(u);
139
140 pa_assert(e == u->save_time_event);
141 u->core->mainloop->time_free(u->save_time_event);
142 u->save_time_event = NULL;
143
144 pa_database_sync(u->database);
145 pa_log_info("Synced.");
146 }
147
148 static void trigger_save(struct userdata *u, pa_device_type_t type, uint32_t sink_idx) {
149 pa_native_connection *c;
150 uint32_t idx;
151
152 if (sink_idx != PA_INVALID_INDEX) {
153 PA_IDXSET_FOREACH(c, u->subscribed, idx) {
154 pa_tagstruct *t;
155
156 t = pa_tagstruct_new(NULL, 0);
157 pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
158 pa_tagstruct_putu32(t, 0);
159 pa_tagstruct_putu32(t, u->module->index);
160 pa_tagstruct_puts(t, u->module->name);
161 pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
162 pa_tagstruct_putu32(t, type);
163 pa_tagstruct_putu32(t, sink_idx);
164
165 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
166 }
167 }
168
169 if (u->save_time_event)
170 return;
171
172 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
173 }
174
175 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
176 /* Some forward declarations */
177 static pa_bool_t legacy_entry_read(struct userdata *u, pa_datum *data, struct entry **entry, struct perportentry **perportentry);
178 static struct perportentry* perportentry_read(struct userdata *u, const char *basekeyname, const char *port);
179 static pa_bool_t perportentry_write(struct userdata *u, const char *basekeyname, const char *port, const struct perportentry *e);
180 static void perportentry_free(struct perportentry* e);
181 #endif
182
183 static struct entry* entry_new(void) {
184 struct entry *r = pa_xnew0(struct entry, 1);
185 r->version = ENTRY_VERSION;
186 return r;
187 }
188
189 static void entry_free(struct entry* e) {
190 pa_assert(e);
191
192 pa_xfree(e->port);
193 pa_xfree(e);
194 }
195
196 static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e) {
197 pa_tagstruct *t;
198 pa_datum key, data;
199 pa_bool_t r;
200
201 pa_assert(u);
202 pa_assert(name);
203 pa_assert(e);
204
205 t = pa_tagstruct_new(NULL, 0);
206 pa_tagstruct_putu8(t, e->version);
207 pa_tagstruct_put_boolean(t, e->port_valid);
208 pa_tagstruct_puts(t, e->port);
209
210 key.data = (char *) name;
211 key.size = strlen(name);
212
213 data.data = (void*)pa_tagstruct_data(t, &data.size);
214
215 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
216
217 pa_tagstruct_free(t);
218
219 return r;
220 }
221
222 static struct entry* entry_read(struct userdata *u, const char *name) {
223 pa_datum key, data;
224 struct entry *e = NULL;
225 pa_tagstruct *t = NULL;
226 const char* port;
227
228 pa_assert(u);
229 pa_assert(name);
230
231 key.data = (char*) name;
232 key.size = strlen(name);
233
234 pa_zero(data);
235
236 if (!pa_database_get(u->database, &key, &data))
237 goto fail;
238
239 t = pa_tagstruct_new(data.data, data.size);
240 e = entry_new();
241
242 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
243 e->version > ENTRY_VERSION ||
244 pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
245 pa_tagstruct_gets(t, &port) < 0) {
246
247 goto fail;
248 }
249
250 if (!pa_tagstruct_eof(t))
251 goto fail;
252
253 e->port = pa_xstrdup(port);
254
255 pa_tagstruct_free(t);
256 pa_datum_free(&data);
257
258 return e;
259
260 fail:
261
262 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
263
264 if (e)
265 entry_free(e);
266 if (t)
267 pa_tagstruct_free(t);
268
269 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
270 {
271 struct perportentry *ppe;
272 pa_log_debug("Attempting to load legacy (pre-v1.0) data for key: %s", name);
273 if (legacy_entry_read(u, &data, &e, &ppe)) {
274 pa_bool_t written = FALSE;
275
276 pa_log_debug("Success. Saving new format for key: %s", name);
277 written = entry_write(u, name, e);
278
279 /* Now convert the legacy entry into per-port entries */
280 if (0 == strncmp("sink:", name, 5)) {
281 pa_sink *sink;
282
283 if ((sink = pa_namereg_get(u->core, name+5, PA_NAMEREG_SINK))) {
284 /* Write a "null" port entry. The read code will automatically try this
285 * if it cannot find a specific port-named entry. */
286 written = perportentry_write(u, name, NULL, ppe) || written;
287 }
288 } else if (0 == strncmp("source:", name, 7)) {
289 pa_source *source;
290
291 if ((source = pa_namereg_get(u->core, name+7, PA_NAMEREG_SOURCE))) {
292 /* Write a "null" port entry. The read code will automatically try this
293 * if it cannot find a specific port-named entry. */
294 written = perportentry_write(u, name, NULL, ppe) || written;
295 }
296 }
297 perportentry_free(ppe);
298
299 if (written)
300 /* NB The device type doesn't matter when we pass in an invalid index. */
301 trigger_save(u, PA_DEVICE_TYPE_SINK, PA_INVALID_INDEX);
302
303 pa_datum_free(&data);
304 return e;
305 }
306 pa_log_debug("Unable to load legacy (pre-v1.0) data for key: %s. Ignoring.", name);
307 }
308 #endif
309
310 pa_datum_free(&data);
311 return NULL;
312 }
313
314 static struct entry* entry_copy(const struct entry *e) {
315 struct entry* r;
316
317 pa_assert(e);
318 r = entry_new();
319 r->version = e->version;
320 r->port_valid = e->port_valid;
321 r->port = pa_xstrdup(e->port);
322
323 return r;
324 }
325
326 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
327
328 pa_assert(a && b);
329
330 if (a->port_valid != b->port_valid ||
331 (a->port_valid && !pa_streq(a->port, b->port)))
332 return FALSE;
333
334 return TRUE;
335 }
336
337 static struct perportentry* perportentry_new(pa_bool_t add_pcm_format) {
338 struct perportentry *r = pa_xnew0(struct perportentry, 1);
339 r->version = PERPORTENTRY_VERSION;
340 r->formats = pa_idxset_new(NULL, NULL);
341 if (add_pcm_format) {
342 pa_format_info *f = pa_format_info_new();
343 f->encoding = PA_ENCODING_PCM;
344 pa_idxset_put(r->formats, f, NULL);
345 }
346 return r;
347 }
348
349 static void perportentry_free(struct perportentry* e) {
350 pa_assert(e);
351
352 pa_idxset_free(e->formats, (pa_free_cb_t) pa_format_info_free);
353 pa_xfree(e);
354 }
355
356 static pa_bool_t perportentry_write(struct userdata *u, const char *basekeyname, const char *port, const struct perportentry *e) {
357 pa_tagstruct *t;
358 pa_datum key, data;
359 pa_bool_t r;
360 uint32_t i;
361 pa_format_info *f;
362 uint8_t n_formats;
363 char *name;
364
365 pa_assert(u);
366 pa_assert(basekeyname);
367 pa_assert(e);
368
369 name = pa_sprintf_malloc("%s:%s", basekeyname, (port ? port : "null"));
370
371 n_formats = pa_idxset_size(e->formats);
372 pa_assert(n_formats > 0);
373
374 t = pa_tagstruct_new(NULL, 0);
375 pa_tagstruct_putu8(t, e->version);
376 pa_tagstruct_put_boolean(t, e->volume_valid);
377 pa_tagstruct_put_channel_map(t, &e->channel_map);
378 pa_tagstruct_put_cvolume(t, &e->volume);
379 pa_tagstruct_put_boolean(t, e->muted_valid);
380 pa_tagstruct_put_boolean(t, e->muted);
381 pa_tagstruct_putu8(t, n_formats);
382
383 PA_IDXSET_FOREACH(f, e->formats, i) {
384 pa_tagstruct_put_format_info(t, f);
385 }
386
387 key.data = (char *) name;
388 key.size = strlen(name);
389
390 data.data = (void*)pa_tagstruct_data(t, &data.size);
391
392 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
393
394 pa_tagstruct_free(t);
395 pa_xfree(name);
396
397 return r;
398 }
399
400 static struct perportentry* perportentry_read(struct userdata *u, const char *basekeyname, const char *port) {
401 pa_datum key, data;
402 struct perportentry *e = NULL;
403 pa_tagstruct *t = NULL;
404 uint8_t i, n_formats;
405 char *name;
406
407 pa_assert(u);
408 pa_assert(basekeyname);
409
410 name = pa_sprintf_malloc("%s:%s", basekeyname, (port ? port : "null"));
411
412 key.data = name;
413 key.size = strlen(name);
414
415 pa_zero(data);
416
417 if (!pa_database_get(u->database, &key, &data))
418 goto fail;
419
420 t = pa_tagstruct_new(data.data, data.size);
421 e = perportentry_new(FALSE);
422
423 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
424 e->version > PERPORTENTRY_VERSION ||
425 pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
426 pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
427 pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
428 pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
429 pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
430 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
431
432 goto fail;
433 }
434
435 for (i = 0; i < n_formats; ++i) {
436 pa_format_info *f = pa_format_info_new();
437 if (pa_tagstruct_get_format_info(t, f) < 0) {
438 pa_format_info_free(f);
439 goto fail;
440 }
441 pa_idxset_put(e->formats, f, NULL);
442 }
443
444 if (!pa_tagstruct_eof(t))
445 goto fail;
446
447 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
448 pa_log_warn("Invalid channel map stored in database for device %s", name);
449 goto fail;
450 }
451
452 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
453 pa_log_warn("Volume and channel map don't match in database entry for device %s", name);
454 goto fail;
455 }
456
457 pa_tagstruct_free(t);
458 pa_datum_free(&data);
459 pa_xfree(name);
460
461 return e;
462
463 fail:
464
465 if (e)
466 perportentry_free(e);
467 if (t)
468 pa_tagstruct_free(t);
469
470 pa_datum_free(&data);
471
472 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
473 /* Try again with a null port. This is used when dealing with migration from older versions */
474 if (port) {
475 pa_xfree(name);
476 return perportentry_read(u, basekeyname, NULL);
477 }
478 #endif
479
480 pa_log_debug("Database contains invalid data for key: %s", name);
481
482 pa_xfree(name);
483
484 return NULL;
485 }
486
487 static struct perportentry* perportentry_copy(const struct perportentry *e) {
488 struct perportentry* r;
489 uint32_t idx;
490 pa_format_info *f;
491
492 pa_assert(e);
493 r = perportentry_new(FALSE);
494 r->version = e->version;
495 r->muted_valid = e->muted_valid;
496 r->volume_valid = e->volume_valid;
497 r->muted = e->muted;
498 r->channel_map = e->channel_map;
499 r->volume = e->volume;
500
501 PA_IDXSET_FOREACH(f, e->formats, idx) {
502 pa_idxset_put(r->formats, pa_format_info_copy(f), NULL);
503 }
504 return r;
505 }
506
507 static pa_bool_t perportentries_equal(const struct perportentry *a, const struct perportentry *b) {
508 pa_cvolume t;
509
510 pa_assert(a && b);
511
512 if (a->muted_valid != b->muted_valid ||
513 (a->muted_valid && (a->muted != b->muted)))
514 return FALSE;
515
516 t = b->volume;
517 if (a->volume_valid != b->volume_valid ||
518 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
519 return FALSE;
520
521 if (pa_idxset_size(a->formats) != pa_idxset_size(b->formats))
522 return FALSE;
523
524 /** TODO: Compare a bit better */
525
526 return TRUE;
527 }
528
529 #ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
530
531 #define LEGACY_ENTRY_VERSION 2
532 static pa_bool_t legacy_entry_read(struct userdata *u, pa_datum *data, struct entry **entry, struct perportentry **perportentry) {
533 struct legacy_entry {
534 uint8_t version;
535 pa_bool_t muted_valid:1, volume_valid:1, port_valid:1;
536 pa_bool_t muted:1;
537 pa_channel_map channel_map;
538 pa_cvolume volume;
539 char port[PA_NAME_MAX];
540 } PA_GCC_PACKED;
541 struct legacy_entry *le;
542
543 pa_assert(u);
544 pa_assert(data);
545 pa_assert(entry);
546 pa_assert(perportentry);
547
548 if (data->size != sizeof(struct legacy_entry)) {
549 pa_log_debug("Size does not match.");
550 return FALSE;
551 }
552
553 le = (struct legacy_entry*)data->data;
554
555 if (le->version != LEGACY_ENTRY_VERSION) {
556 pa_log_debug("Version mismatch.");
557 return FALSE;
558 }
559
560 if (!memchr(le->port, 0, sizeof(le->port))) {
561 pa_log_warn("Port has missing NUL byte.");
562 return FALSE;
563 }
564
565 if (le->volume_valid && !pa_channel_map_valid(&le->channel_map)) {
566 pa_log_warn("Invalid channel map.");
567 return FALSE;
568 }
569
570 if (le->volume_valid && (!pa_cvolume_valid(&le->volume) || !pa_cvolume_compatible_with_channel_map(&le->volume, &le->channel_map))) {
571 pa_log_warn("Volume and channel map don't match.");
572 return FALSE;
573 }
574
575 *entry = entry_new();
576 (*entry)->port_valid = le->port_valid;
577 (*entry)->port = pa_xstrdup(le->port);
578
579 *perportentry = perportentry_new(TRUE);
580 (*perportentry)->muted_valid = le->muted_valid;
581 (*perportentry)->volume_valid = le->volume_valid;
582 (*perportentry)->muted = le->muted;
583 (*perportentry)->channel_map = le->channel_map;
584 (*perportentry)->volume = le->volume;
585
586 return TRUE;
587 }
588 #endif
589
590 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
591 struct userdata *u = userdata;
592 struct entry *e, *olde;
593 struct perportentry *ppe, *oldppe;
594 char *name;
595 const char *port = NULL;
596 pa_device_type_t type;
597 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 name = pa_sprintf_malloc("sink:%s", sink->name);
616 if (sink->active_port)
617 port = sink->active_port->name;
618
619 if ((olde = entry_read(u, name)))
620 e = entry_copy(olde);
621 else
622 e = entry_new();
623
624 if (sink->save_port) {
625 pa_xfree(e->port);
626 e->port = pa_xstrdup(port ? port : "");
627 e->port_valid = TRUE;
628 }
629
630 if ((oldppe = perportentry_read(u, name, port)))
631 ppe = perportentry_copy(oldppe);
632 else
633 ppe = perportentry_new(TRUE);
634
635 if (sink->save_volume) {
636 ppe->channel_map = sink->channel_map;
637 ppe->volume = *pa_sink_get_volume(sink, FALSE);
638 ppe->volume_valid = TRUE;
639 }
640
641 if (sink->save_muted) {
642 ppe->muted = pa_sink_get_mute(sink, FALSE);
643 ppe->muted_valid = TRUE;
644 }
645 } else {
646 pa_source *source;
647
648 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
649
650 if (!(source = pa_idxset_get_by_index(c->sources, idx)))
651 return;
652
653 type = PA_DEVICE_TYPE_SOURCE;
654 name = pa_sprintf_malloc("source:%s", source->name);
655 if (source->active_port)
656 port = source->active_port->name;
657
658 if ((olde = entry_read(u, name)))
659 e = entry_copy(olde);
660 else
661 e = entry_new();
662
663 if (source->save_port) {
664 pa_xfree(e->port);
665 e->port = pa_xstrdup(port ? port : "");
666 e->port_valid = TRUE;
667 }
668
669 if ((oldppe = perportentry_read(u, name, port)))
670 ppe = perportentry_copy(oldppe);
671 else
672 ppe = perportentry_new(TRUE);
673
674 if (source->save_volume) {
675 ppe->channel_map = source->channel_map;
676 ppe->volume = *pa_source_get_volume(source, FALSE);
677 ppe->volume_valid = TRUE;
678 }
679
680 if (source->save_muted) {
681 ppe->muted = pa_source_get_mute(source, FALSE);
682 ppe->muted_valid = TRUE;
683 }
684 }
685
686 pa_assert(e);
687
688 if (olde) {
689
690 if (entries_equal(olde, e)) {
691 entry_free(olde);
692 entry_free(e);
693 e = NULL;
694 } else
695 entry_free(olde);
696 }
697
698 if (e) {
699 pa_log_info("Storing port for device %s.", name);
700
701 written = entry_write(u, name, e);
702
703 entry_free(e);
704 }
705
706 pa_assert(ppe);
707
708 if (oldppe) {
709
710 if (perportentries_equal(oldppe, ppe)) {
711 perportentry_free(oldppe);
712 perportentry_free(ppe);
713 ppe = NULL;
714 } else
715 perportentry_free(oldppe);
716 }
717
718 if (ppe) {
719 pa_log_info("Storing volume/mute for device+port %s:%s.", name, (port ? port : "null"));
720
721 written = perportentry_write(u, name, port, ppe) || written;
722
723 perportentry_free(ppe);
724 }
725 pa_xfree(name);
726
727 if (written)
728 trigger_save(u, type, idx);
729 }
730
731 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
732 char *name;
733 struct entry *e;
734
735 pa_assert(c);
736 pa_assert(new_data);
737 pa_assert(u);
738 pa_assert(u->restore_port);
739
740 name = pa_sprintf_malloc("sink:%s", new_data->name);
741
742 if ((e = entry_read(u, name))) {
743
744 if (e->port_valid) {
745 if (!new_data->active_port) {
746 pa_log_info("Restoring port for sink %s.", name);
747 pa_sink_new_data_set_port(new_data, e->port);
748 new_data->save_port = TRUE;
749 } else
750 pa_log_debug("Not restoring port for sink %s, because already set.", name);
751 }
752
753 entry_free(e);
754 }
755
756 pa_xfree(name);
757
758 return PA_HOOK_OK;
759 }
760
761 static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
762 char *name;
763 struct perportentry *e;
764
765 pa_assert(c);
766 pa_assert(new_data);
767 pa_assert(u);
768 pa_assert(u->restore_volume || u->restore_muted);
769
770 name = pa_sprintf_malloc("sink:%s", new_data->name);
771
772 if ((e = perportentry_read(u, name, new_data->active_port))) {
773
774 if (u->restore_volume && e->volume_valid) {
775
776 if (!new_data->volume_is_set) {
777 pa_cvolume v;
778 char buf[PA_CVOLUME_SNPRINT_MAX];
779
780 pa_log_info("Restoring volume for sink %s.", new_data->name);
781 v = e->volume;
782 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
783 pa_sink_new_data_set_volume(new_data, &v);
784 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &new_data->volume));
785
786 new_data->save_volume = TRUE;
787 } else
788 pa_log_debug("Not restoring volume for sink %s, because already set.", new_data->name);
789 }
790
791 if (u->restore_muted && e->muted_valid) {
792
793 if (!new_data->muted_is_set) {
794 pa_log_info("Restoring mute state for sink %s.", new_data->name);
795 pa_sink_new_data_set_muted(new_data, e->muted);
796 new_data->save_muted = TRUE;
797 } else
798 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
799 }
800
801 perportentry_free(e);
802 }
803
804 pa_xfree(name);
805
806 return PA_HOOK_OK;
807 }
808
809 static pa_hook_result_t sink_port_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
810 char *name;
811 struct perportentry *e;
812
813 pa_assert(c);
814 pa_assert(sink);
815 pa_assert(u);
816 pa_assert(u->restore_volume || u->restore_muted);
817
818 name = pa_sprintf_malloc("sink:%s", sink->name);
819
820 if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
821
822 if (u->restore_volume && e->volume_valid) {
823 pa_cvolume v;
824 char buf[PA_CVOLUME_SNPRINT_MAX];
825
826 pa_log_info("Restoring volume for sink %s.", sink->name);
827 v = e->volume;
828 pa_cvolume_remap(&v, &e->channel_map, &sink->channel_map);
829 pa_sink_set_volume(sink, &v, TRUE, FALSE);
830 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &sink->reference_volume));
831
832 sink->save_volume = TRUE;
833 }
834
835 if (u->restore_muted && e->muted_valid) {
836
837 pa_log_info("Restoring mute state for sink %s.", sink->name);
838 pa_sink_set_mute(sink, e->muted, FALSE);
839 sink->save_muted = TRUE;
840 }
841
842 perportentry_free(e);
843 }
844
845 pa_xfree(name);
846
847 return PA_HOOK_OK;
848 }
849
850 static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, struct userdata *u) {
851 char *name;
852 struct perportentry *e;
853
854 pa_assert(c);
855 pa_assert(sink);
856 pa_assert(u);
857 pa_assert(u->restore_formats);
858
859 name = pa_sprintf_malloc("sink:%s", sink->name);
860
861 if ((e = perportentry_read(u, name, (sink->active_port ? sink->active_port->name : NULL)))) {
862
863 if (!pa_sink_set_formats(sink, e->formats))
864 pa_log_debug("Could not set format on sink %s", sink->name);
865
866 perportentry_free(e);
867 }
868
869 pa_xfree(name);
870
871 return PA_HOOK_OK;
872 }
873
874 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
875 char *name;
876 struct entry *e;
877
878 pa_assert(c);
879 pa_assert(new_data);
880 pa_assert(u);
881 pa_assert(u->restore_port);
882
883 name = pa_sprintf_malloc("source:%s", new_data->name);
884
885 if ((e = entry_read(u, name))) {
886
887 if (e->port_valid) {
888 if (!new_data->active_port) {
889 pa_log_info("Restoring port for source %s.", name);
890 pa_source_new_data_set_port(new_data, e->port);
891 new_data->save_port = TRUE;
892 } else
893 pa_log_debug("Not restoring port for source %s, because already set.", name);
894 }
895
896 entry_free(e);
897 }
898
899 pa_xfree(name);
900
901 return PA_HOOK_OK;
902 }
903
904 static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
905 char *name;
906 struct perportentry *e;
907
908 pa_assert(c);
909 pa_assert(new_data);
910 pa_assert(u);
911 pa_assert(u->restore_volume || u->restore_muted);
912
913 name = pa_sprintf_malloc("source:%s", new_data->name);
914
915 if ((e = perportentry_read(u, name, new_data->active_port))) {
916
917 if (u->restore_volume && e->volume_valid) {
918
919 if (!new_data->volume_is_set) {
920 pa_cvolume v;
921 char buf[PA_CVOLUME_SNPRINT_MAX];
922
923 pa_log_info("Restoring volume for source %s.", new_data->name);
924 v = e->volume;
925 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
926 pa_source_new_data_set_volume(new_data, &v);
927 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &new_data->volume));
928
929 new_data->save_volume = TRUE;
930 } else
931 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
932 }
933
934 if (u->restore_muted && e->muted_valid) {
935
936 if (!new_data->muted_is_set) {
937 pa_log_info("Restoring mute state for source %s.", new_data->name);
938 pa_source_new_data_set_muted(new_data, e->muted);
939 new_data->save_muted = TRUE;
940 } else
941 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
942 }
943
944 perportentry_free(e);
945 }
946
947 pa_xfree(name);
948
949 return PA_HOOK_OK;
950 }
951
952 static pa_hook_result_t source_port_hook_callback(pa_core *c, pa_source *source, struct userdata *u) {
953 char *name;
954 struct perportentry *e;
955
956 pa_assert(c);
957 pa_assert(source);
958 pa_assert(u);
959 pa_assert(u->restore_volume || u->restore_muted);
960
961 name = pa_sprintf_malloc("source:%s", source->name);
962
963 if ((e = perportentry_read(u, name, (source->active_port ? source->active_port->name : NULL)))) {
964
965 if (u->restore_volume && e->volume_valid) {
966 pa_cvolume v;
967 char buf[PA_CVOLUME_SNPRINT_MAX];
968
969 pa_log_info("Restoring volume for source %s.", source->name);
970 v = e->volume;
971 pa_cvolume_remap(&v, &e->channel_map, &source->channel_map);
972 pa_source_set_volume(source, &v, TRUE, FALSE);
973 pa_log_info("Restored volume: %s", pa_cvolume_snprint(buf, PA_CVOLUME_SNPRINT_MAX, &source->reference_volume));
974
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_free_cb_t) pa_format_info_free);
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);
1338
1339 pa_xfree(u);
1340 }