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