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