]> code.delx.au - pulseaudio/blob - src/modules/module-device-restore.c
35e455d9387460a7c070401ea2397f68afdd19fc
[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 #include <ctype.h>
34
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
40 #include <pulse/format.h>
41 #include <pulse/internal.h>
42
43 #include <pulsecore/core-error.h>
44 #include <pulsecore/module.h>
45 #include <pulsecore/core-util.h>
46 #include <pulsecore/modargs.h>
47 #include <pulsecore/log.h>
48 #include <pulsecore/core-subscribe.h>
49 #include <pulsecore/sink-input.h>
50 #include <pulsecore/source-output.h>
51 #include <pulsecore/namereg.h>
52 #include <pulsecore/protocol-native.h>
53 #include <pulsecore/pstream.h>
54 #include <pulsecore/pstream-util.h>
55 #include <pulsecore/database.h>
56 #include <pulsecore/tagstruct.h>
57
58 #include "module-device-restore-symdef.h"
59
60 PA_MODULE_AUTHOR("Lennart Poettering");
61 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute state of devices");
62 PA_MODULE_VERSION(PACKAGE_VERSION);
63 PA_MODULE_LOAD_ONCE(TRUE);
64 PA_MODULE_USAGE(
65 "restore_port=<Save/restore port?> "
66 "restore_volume=<Save/restore volumes?> "
67 "restore_muted=<Save/restore muted states?>");
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 NULL
76 };
77
78 struct userdata {
79 pa_core *core;
80 pa_module *module;
81 pa_subscription *subscription;
82 pa_hook_slot
83 *sink_new_hook_slot,
84 *sink_fixate_hook_slot,
85 *source_new_hook_slot,
86 *source_fixate_hook_slot,
87 *connection_unlink_hook_slot;
88 pa_time_event *save_time_event;
89 pa_database *database;
90
91 pa_native_protocol *protocol;
92 pa_idxset *subscribed;
93
94 pa_bool_t restore_volume:1;
95 pa_bool_t restore_muted:1;
96 pa_bool_t restore_port:1;
97 };
98
99 /* Protocol extention commands */
100 enum {
101 SUBCOMMAND_TEST,
102 SUBCOMMAND_SUBSCRIBE,
103 SUBCOMMAND_EVENT,
104 SUBCOMMAND_READ_SINK_FORMATS_ALL,
105 SUBCOMMAND_READ_SINK_FORMATS,
106 SUBCOMMAND_SAVE_SINK_FORMATS
107 };
108
109
110 #define ENTRY_VERSION 3
111
112 struct entry {
113 uint8_t version;
114 pa_bool_t muted_valid, volume_valid, port_valid;
115 pa_bool_t muted;
116 pa_channel_map channel_map;
117 pa_cvolume volume;
118 char *port;
119 pa_idxset *formats;
120 };
121
122 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
123 struct userdata *u = userdata;
124
125 pa_assert(a);
126 pa_assert(e);
127 pa_assert(u);
128
129 pa_assert(e == u->save_time_event);
130 u->core->mainloop->time_free(u->save_time_event);
131 u->save_time_event = NULL;
132
133 pa_database_sync(u->database);
134 pa_log_info("Synced.");
135 }
136
137 static struct entry* entry_new(void) {
138 struct entry *r = pa_xnew0(struct entry, 1);
139 r->version = ENTRY_VERSION;
140 r->formats = pa_idxset_new(NULL, NULL);
141 return r;
142 }
143
144 static void entry_free(struct entry* e) {
145 pa_assert(e);
146
147 pa_idxset_free(e->formats, (pa_free2_cb_t) pa_format_info_free2, NULL);
148 pa_xfree(e->port);
149 pa_xfree(e);
150 }
151
152 static struct entry* entry_read(struct userdata *u, const char *name) {
153 pa_datum key, data;
154 struct entry *e = NULL;
155 pa_tagstruct *t = NULL;
156 const char* port;
157 uint8_t i, n_formats;
158
159 pa_assert(u);
160 pa_assert(name);
161
162 key.data = (char*) name;
163 key.size = strlen(name);
164
165 pa_zero(data);
166
167 if (!pa_database_get(u->database, &key, &data))
168 goto fail;
169
170 t = pa_tagstruct_new(data.data, data.size);
171 e = entry_new();
172
173 if (pa_tagstruct_getu8(t, &e->version) < 0 ||
174 e->version > ENTRY_VERSION ||
175 pa_tagstruct_get_boolean(t, &e->volume_valid) < 0 ||
176 pa_tagstruct_get_channel_map(t, &e->channel_map) < 0 ||
177 pa_tagstruct_get_cvolume(t, &e->volume) < 0 ||
178 pa_tagstruct_get_boolean(t, &e->muted_valid) < 0 ||
179 pa_tagstruct_get_boolean(t, &e->muted) < 0 ||
180 pa_tagstruct_get_boolean(t, &e->port_valid) < 0 ||
181 pa_tagstruct_gets(t, &port) < 0 ||
182 pa_tagstruct_getu8(t, &n_formats) < 0) {
183
184 goto fail;
185 }
186
187 e->port = pa_xstrdup(port);
188
189 for (i = 0; i < n_formats; ++i) {
190 pa_format_info *f = pa_format_info_new();
191 if (pa_tagstruct_get_format_info(t, f) < 0) {
192 pa_format_info_free(f);
193 goto fail;
194 }
195 pa_idxset_put(e->formats, f, NULL);
196 }
197
198 if (!pa_tagstruct_eof(t))
199 goto fail;
200
201 if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
202 pa_log_warn("Invalid channel map stored in database for device %s", name);
203 goto fail;
204 }
205
206 if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
207 pa_log_warn("Volume and channel map don't match in database entry for device %s", name);
208 goto fail;
209 }
210
211 pa_tagstruct_free(t);
212 pa_datum_free(&data);
213
214 return e;
215
216 fail:
217
218 pa_log_debug("Database contains invalid data for key: %s (probably pre-v1.0 data)", name);
219
220 if (e)
221 entry_free(e);
222 if (t)
223 pa_tagstruct_free(t);
224 pa_datum_free(&data);
225 return NULL;
226 }
227
228 static pa_bool_t entry_write(struct userdata *u, const char *name, const struct entry *e) {
229 pa_tagstruct *t;
230 pa_datum key, data;
231 pa_bool_t r;
232 uint32_t i;
233 pa_format_info *f;
234
235 pa_assert(u);
236 pa_assert(name);
237 pa_assert(e);
238
239 t = pa_tagstruct_new(NULL, 0);
240 pa_tagstruct_putu8(t, e->version);
241 pa_tagstruct_put_boolean(t, e->volume_valid);
242 pa_tagstruct_put_channel_map(t, &e->channel_map);
243 pa_tagstruct_put_cvolume(t, &e->volume);
244 pa_tagstruct_put_boolean(t, e->muted_valid);
245 pa_tagstruct_put_boolean(t, e->muted);
246 pa_tagstruct_put_boolean(t, e->port_valid);
247 pa_tagstruct_puts(t, e->port);
248 pa_tagstruct_putu8(t, pa_idxset_size(e->formats));
249
250 PA_IDXSET_FOREACH(f, e->formats, i) {
251 pa_tagstruct_put_format_info(t, f);
252 }
253
254 key.data = (char *) name;
255 key.size = strlen(name);
256
257 data.data = (void*)pa_tagstruct_data(t, &data.size);
258
259 r = (pa_database_set(u->database, &key, &data, TRUE) == 0);
260
261 pa_tagstruct_free(t);
262
263 return r;
264 }
265
266 static struct entry* entry_copy(const struct entry *e) {
267 struct entry* r;
268 uint32_t idx;
269 pa_format_info *f;
270
271 pa_assert(e);
272 r = entry_new();
273 r->version = e->version;
274 r->muted_valid = e->muted_valid;
275 r->volume_valid = e->volume_valid;
276 r->port_valid = e->port_valid;
277 r->muted = e->muted;
278 r->channel_map = e->channel_map;
279 r->volume = e->volume;
280 r->port = pa_xstrdup(e->port);
281
282 PA_IDXSET_FOREACH(f, e->formats, idx) {
283 pa_idxset_put(r->formats, pa_format_info_copy(f), NULL);
284 }
285 return r;
286 }
287
288 static void trigger_save(struct userdata *u) {
289 if (u->save_time_event)
290 return;
291
292 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
293 }
294
295 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
296 pa_cvolume t;
297
298 if (a->port_valid != b->port_valid ||
299 (a->port_valid && !pa_streq(a->port, b->port)))
300 return FALSE;
301
302 if (a->muted_valid != b->muted_valid ||
303 (a->muted_valid && (a->muted != b->muted)))
304 return FALSE;
305
306 t = b->volume;
307 if (a->volume_valid != b->volume_valid ||
308 (a->volume_valid && !pa_cvolume_equal(pa_cvolume_remap(&t, &b->channel_map, &a->channel_map), &a->volume)))
309 return FALSE;
310
311 return TRUE;
312 }
313
314 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
315 struct userdata *u = userdata;
316 struct entry *entry, *old;
317 char *name;
318
319 pa_assert(c);
320 pa_assert(u);
321
322 if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
323 t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
324 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
325 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
326 return;
327
328 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
329 pa_sink *sink;
330
331 if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
332 return;
333
334 name = pa_sprintf_malloc("sink:%s", sink->name);
335
336 if ((old = entry_read(u, name)))
337 entry = entry_copy(old);
338 else
339 entry = entry_new();
340
341 if (sink->save_volume) {
342 entry->channel_map = sink->channel_map;
343 entry->volume = *pa_sink_get_volume(sink, FALSE);
344 entry->volume_valid = TRUE;
345 }
346
347 if (sink->save_muted) {
348 entry->muted = pa_sink_get_mute(sink, FALSE);
349 entry->muted_valid = TRUE;
350 }
351
352 if (sink->save_port) {
353 pa_xfree(entry->port);
354 entry->port = pa_xstrdup(sink->active_port ? sink->active_port->name : "");
355 entry->port_valid = TRUE;
356 }
357
358 } else {
359 pa_source *source;
360
361 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
362
363 if (!(source = pa_idxset_get_by_index(c->sources, idx)))
364 return;
365
366 name = pa_sprintf_malloc("source:%s", source->name);
367
368 if ((old = entry_read(u, name)))
369 entry = entry_copy(old);
370 else
371 entry = entry_new();
372
373 if (source->save_volume) {
374 entry->channel_map = source->channel_map;
375 entry->volume = *pa_source_get_volume(source, FALSE);
376 entry->volume_valid = TRUE;
377 }
378
379 if (source->save_muted) {
380 entry->muted = pa_source_get_mute(source, FALSE);
381 entry->muted_valid = TRUE;
382 }
383
384 if (source->save_port) {
385 pa_xfree(entry->port);
386 entry->port = pa_xstrdup(source->active_port ? source->active_port->name : "");
387 entry->port_valid = TRUE;
388 }
389 }
390
391 pa_assert(entry);
392
393 if (old) {
394
395 if (entries_equal(old, entry)) {
396 entry_free(old);
397 entry_free(entry);
398 pa_xfree(name);
399 return;
400 }
401
402 entry_free(old);
403 }
404
405 pa_log_info("Storing volume/mute/port for device %s.", name);
406
407 if (entry_write(u, name, entry))
408 trigger_save(u);
409
410 entry_free(entry);
411 pa_xfree(name);
412 }
413
414 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
415 char *name;
416 struct entry *e;
417
418 pa_assert(c);
419 pa_assert(new_data);
420 pa_assert(u);
421 pa_assert(u->restore_port);
422
423 name = pa_sprintf_malloc("sink:%s", new_data->name);
424
425 if ((e = entry_read(u, name))) {
426
427 if (e->port_valid) {
428 if (!new_data->active_port) {
429 pa_log_info("Restoring port for sink %s.", name);
430 pa_sink_new_data_set_port(new_data, e->port);
431 new_data->save_port = TRUE;
432 } else
433 pa_log_debug("Not restoring port for sink %s, because already set.", name);
434 }
435
436 entry_free(e);
437 }
438
439 pa_xfree(name);
440
441 return PA_HOOK_OK;
442 }
443
444 static pa_hook_result_t sink_fixate_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
445 char *name;
446 struct entry *e;
447
448 pa_assert(c);
449 pa_assert(new_data);
450 pa_assert(u);
451 pa_assert(u->restore_volume || u->restore_muted);
452
453 name = pa_sprintf_malloc("sink:%s", new_data->name);
454
455 if ((e = entry_read(u, name))) {
456
457 if (u->restore_volume && e->volume_valid) {
458
459 if (!new_data->volume_is_set) {
460 pa_cvolume v;
461
462 pa_log_info("Restoring volume for sink %s.", new_data->name);
463
464 v = e->volume;
465 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
466 pa_sink_new_data_set_volume(new_data, &v);
467
468 new_data->save_volume = TRUE;
469 } else
470 pa_log_debug("Not restoring volume for sink %s, because already set.", new_data->name);
471 }
472
473 if (u->restore_muted && e->muted_valid) {
474
475 if (!new_data->muted_is_set) {
476 pa_log_info("Restoring mute state for sink %s.", new_data->name);
477 pa_sink_new_data_set_muted(new_data, e->muted);
478 new_data->save_muted = TRUE;
479 } else
480 pa_log_debug("Not restoring mute state for sink %s, because already set.", new_data->name);
481 }
482
483 entry_free(e);
484 }
485
486 pa_xfree(name);
487
488 return PA_HOOK_OK;
489 }
490
491 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
492 char *name;
493 struct entry *e;
494
495 pa_assert(c);
496 pa_assert(new_data);
497 pa_assert(u);
498 pa_assert(u->restore_port);
499
500 name = pa_sprintf_malloc("source:%s", new_data->name);
501
502 if ((e = entry_read(u, name))) {
503
504 if (e->port_valid) {
505 if (!new_data->active_port) {
506 pa_log_info("Restoring port for source %s.", name);
507 pa_source_new_data_set_port(new_data, e->port);
508 new_data->save_port = TRUE;
509 } else
510 pa_log_debug("Not restoring port for source %s, because already set.", name);
511 }
512
513 entry_free(e);
514 }
515
516 pa_xfree(name);
517
518 return PA_HOOK_OK;
519 }
520
521 static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
522 char *name;
523 struct entry *e;
524
525 pa_assert(c);
526 pa_assert(new_data);
527 pa_assert(u);
528 pa_assert(u->restore_volume || u->restore_muted);
529
530 name = pa_sprintf_malloc("source:%s", new_data->name);
531
532 if ((e = entry_read(u, name))) {
533
534 if (u->restore_volume && e->volume_valid) {
535
536 if (!new_data->volume_is_set) {
537 pa_cvolume v;
538
539 pa_log_info("Restoring volume for source %s.", new_data->name);
540
541 v = e->volume;
542 pa_cvolume_remap(&v, &e->channel_map, &new_data->channel_map);
543 pa_source_new_data_set_volume(new_data, &v);
544
545 new_data->save_volume = TRUE;
546 } else
547 pa_log_debug("Not restoring volume for source %s, because already set.", new_data->name);
548 }
549
550 if (u->restore_muted && e->muted_valid) {
551
552 if (!new_data->muted_is_set) {
553 pa_log_info("Restoring mute state for source %s.", new_data->name);
554 pa_source_new_data_set_muted(new_data, e->muted);
555 new_data->save_muted = TRUE;
556 } else
557 pa_log_debug("Not restoring mute state for source %s, because already set.", new_data->name);
558 }
559
560 entry_free(e);
561 }
562
563 pa_xfree(name);
564
565 return PA_HOOK_OK;
566 }
567
568 #define EXT_VERSION 1
569
570 static void read_sink_format_reply(struct userdata *u, pa_tagstruct *reply, pa_sink *sink) {
571 struct entry *e;
572 char *name;
573
574 pa_assert(u);
575 pa_assert(reply);
576 pa_assert(sink);
577
578 pa_tagstruct_putu32(reply, sink->index);
579
580 /* Read or create an entry */
581 name = pa_sprintf_malloc("sink:%s", sink->name);
582 if (!(e = entry_read(u, name))) {
583 /* Fake a reply with PCM encoding supported */
584 pa_format_info *f = pa_format_info_new();
585
586 pa_tagstruct_putu8(reply, 1);
587 f->encoding = PA_ENCODING_PCM;
588 pa_tagstruct_put_format_info(reply, f);
589
590 pa_format_info_free(f);
591 } else {
592 uint32_t idx;
593 pa_format_info *f;
594
595 /* Write all the formats from the entry to the reply */
596 pa_tagstruct_putu8(reply, pa_idxset_size(e->formats));
597 PA_IDXSET_FOREACH(f, e->formats, idx) {
598 pa_tagstruct_put_format_info(reply, f);
599 }
600 }
601 pa_xfree(name);
602 }
603
604 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
605 struct userdata *u;
606 uint32_t command;
607 pa_tagstruct *reply = NULL;
608
609 pa_assert(p);
610 pa_assert(m);
611 pa_assert(c);
612 pa_assert(t);
613
614 u = m->userdata;
615
616 if (pa_tagstruct_getu32(t, &command) < 0)
617 goto fail;
618
619 reply = pa_tagstruct_new(NULL, 0);
620 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
621 pa_tagstruct_putu32(reply, tag);
622
623 switch (command) {
624 case SUBCOMMAND_TEST: {
625 if (!pa_tagstruct_eof(t))
626 goto fail;
627
628 pa_tagstruct_putu32(reply, EXT_VERSION);
629 break;
630 }
631
632 case SUBCOMMAND_SUBSCRIBE: {
633
634 pa_bool_t enabled;
635
636 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
637 !pa_tagstruct_eof(t))
638 goto fail;
639
640 if (enabled)
641 pa_idxset_put(u->subscribed, c, NULL);
642 else
643 pa_idxset_remove_by_data(u->subscribed, c, NULL);
644
645 break;
646 }
647
648 case SUBCOMMAND_READ_SINK_FORMATS_ALL: {
649 pa_sink *sink;
650 uint32_t idx;
651
652 if (!pa_tagstruct_eof(t))
653 goto fail;
654
655 PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
656 read_sink_format_reply(u, reply, sink);
657 }
658
659 break;
660 }
661 case SUBCOMMAND_READ_SINK_FORMATS: {
662 uint32_t sink_index;
663 pa_sink *sink;
664
665 pa_assert(reply);
666
667 /* Get the sink index and the number of formats from the tagstruct */
668 if (pa_tagstruct_getu32(t, &sink_index) < 0)
669 goto fail;
670
671 if (!pa_tagstruct_eof(t))
672 goto fail;
673
674 /* Now find our sink */
675 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
676 goto fail;
677
678 read_sink_format_reply(u, reply, sink);
679
680 break;
681 }
682
683 case SUBCOMMAND_SAVE_SINK_FORMATS: {
684
685 struct entry *e;
686 uint32_t sink_index;
687 char *name;
688 pa_sink *sink;
689 uint8_t i, n_formats;
690
691 /* Get the sink index and the number of formats from the tagstruct */
692 if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
693 pa_tagstruct_getu8(t, &n_formats) < 0 || n_formats < 1) {
694
695 goto fail;
696 }
697
698 /* Now find our sink */
699 if (!(sink = pa_idxset_get_by_index(u->core->sinks, sink_index)))
700 goto fail;
701
702 /* Read or create an entry */
703 name = pa_sprintf_malloc("sink:%s", sink->name);
704 if (!(e = entry_read(u, name)))
705 e = entry_new();
706
707 /* Read all the formats from our tagstruct */
708 for (i = 0; i < n_formats; ++i) {
709 pa_format_info *f = pa_format_info_new();
710 if (pa_tagstruct_get_format_info(t, f) < 0) {
711 pa_format_info_free(f);
712 pa_xfree(name);
713 goto fail;
714 }
715 pa_idxset_put(e->formats, f, NULL);
716 }
717
718 if (!pa_tagstruct_eof(t)) {
719 entry_free(e);
720 pa_xfree(name);
721 goto fail;
722 }
723
724 if (entry_write(u, name, e))
725 trigger_save(u);
726 else
727 pa_log_warn("Could not save format info for sink %s", sink->name);
728
729 pa_xfree(name);
730 entry_free(e);
731
732 break;
733 }
734
735 default:
736 goto fail;
737 }
738
739 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
740 return 0;
741
742 fail:
743
744 if (reply)
745 pa_tagstruct_free(reply);
746
747 return -1;
748 }
749
750 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
751 pa_assert(p);
752 pa_assert(c);
753 pa_assert(u);
754
755 pa_idxset_remove_by_data(u->subscribed, c, NULL);
756 return PA_HOOK_OK;
757 }
758
759 int pa__init(pa_module*m) {
760 pa_modargs *ma = NULL;
761 struct userdata *u;
762 char *fname;
763 pa_sink *sink;
764 pa_source *source;
765 uint32_t idx;
766 pa_bool_t restore_volume = TRUE, restore_muted = TRUE, restore_port = TRUE;
767
768 pa_assert(m);
769
770 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
771 pa_log("Failed to parse module arguments");
772 goto fail;
773 }
774
775 if (pa_modargs_get_value_boolean(ma, "restore_volume", &restore_volume) < 0 ||
776 pa_modargs_get_value_boolean(ma, "restore_muted", &restore_muted) < 0 ||
777 pa_modargs_get_value_boolean(ma, "restore_port", &restore_port) < 0) {
778 pa_log("restore_port=, restore_volume= and restore_muted= expect boolean arguments");
779 goto fail;
780 }
781
782 if (!restore_muted && !restore_volume && !restore_port)
783 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring port enabled!");
784
785 m->userdata = u = pa_xnew0(struct userdata, 1);
786 u->core = m->core;
787 u->module = m;
788 u->restore_volume = restore_volume;
789 u->restore_muted = restore_muted;
790 u->restore_port = restore_port;
791
792 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
793
794 u->protocol = pa_native_protocol_get(m->core);
795 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
796
797 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);
798
799 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
800
801 if (restore_port) {
802 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);
803 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);
804 }
805
806 if (restore_muted || restore_volume) {
807 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);
808 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);
809 }
810
811 if (!(fname = pa_state_path("device-volumes", TRUE)))
812 goto fail;
813
814 if (!(u->database = pa_database_open(fname, TRUE))) {
815 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
816 pa_xfree(fname);
817 goto fail;
818 }
819
820 pa_log_info("Successfully opened database file '%s'.", fname);
821 pa_xfree(fname);
822
823 for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx))
824 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
825
826 for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx))
827 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
828
829 pa_modargs_free(ma);
830 return 0;
831
832 fail:
833 pa__done(m);
834
835 if (ma)
836 pa_modargs_free(ma);
837
838 return -1;
839 }
840
841 void pa__done(pa_module*m) {
842 struct userdata* u;
843
844 pa_assert(m);
845
846 if (!(u = m->userdata))
847 return;
848
849 if (u->subscription)
850 pa_subscription_free(u->subscription);
851
852 if (u->sink_fixate_hook_slot)
853 pa_hook_slot_free(u->sink_fixate_hook_slot);
854 if (u->source_fixate_hook_slot)
855 pa_hook_slot_free(u->source_fixate_hook_slot);
856 if (u->sink_new_hook_slot)
857 pa_hook_slot_free(u->sink_new_hook_slot);
858 if (u->source_new_hook_slot)
859 pa_hook_slot_free(u->source_new_hook_slot);
860
861 if (u->connection_unlink_hook_slot)
862 pa_hook_slot_free(u->connection_unlink_hook_slot);
863
864 if (u->save_time_event)
865 u->core->mainloop->time_free(u->save_time_event);
866
867 if (u->database)
868 pa_database_close(u->database);
869
870 if (u->protocol) {
871 pa_native_protocol_remove_ext(u->protocol, m);
872 pa_native_protocol_unref(u->protocol);
873 }
874
875 if (u->subscribed)
876 pa_idxset_free(u->subscribed, NULL, NULL);
877
878 pa_xfree(u);
879 }