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