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