2 This file is part of PulseAudio.
4 Copyright 2008 Lennart Poettering
5 Copyright 2009 Tanu Kaskinen
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.
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.
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
30 #include <sys/types.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/modargs.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/core-subscribe.h>
47 #include <pulsecore/sink-input.h>
48 #include <pulsecore/source-output.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/protocol-native.h>
51 #include <pulsecore/pstream.h>
52 #include <pulsecore/pstream-util.h>
53 #include <pulsecore/database.h>
56 #include <pulsecore/dbus-util.h>
57 #include <pulsecore/protocol-dbus.h>
60 #include "module-stream-restore-symdef.h"
62 PA_MODULE_AUTHOR("Lennart Poettering");
63 PA_MODULE_DESCRIPTION("Automatically restore the volume/mute/device state of streams");
64 PA_MODULE_VERSION(PACKAGE_VERSION
);
65 PA_MODULE_LOAD_ONCE(TRUE
);
67 "restore_device=<Save/restore sinks/sources?> "
68 "restore_volume=<Save/restore volumes?> "
69 "restore_muted=<Save/restore muted states?> "
70 "on_hotplug=<When new device becomes available, recheck streams?> "
71 "on_rescue=<When device becomes unavailable, recheck streams?>");
73 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
74 #define IDENTIFICATION_PROPERTY "module-stream-restore.id"
76 static const char* const valid_modargs
[] = {
88 pa_subscription
*subscription
;
90 *sink_input_new_hook_slot
,
91 *sink_input_fixate_hook_slot
,
92 *source_output_new_hook_slot
,
94 *source_put_hook_slot
,
95 *sink_unlink_hook_slot
,
96 *source_unlink_hook_slot
,
97 *connection_unlink_hook_slot
;
98 pa_time_event
*save_time_event
;
99 pa_database
* database
;
101 pa_bool_t restore_device
:1;
102 pa_bool_t restore_volume
:1;
103 pa_bool_t restore_muted
:1;
104 pa_bool_t on_hotplug
:1;
105 pa_bool_t on_rescue
:1;
107 pa_native_protocol
*protocol
;
108 pa_idxset
*subscribed
;
111 pa_dbus_protocol
*dbus_protocol
;
112 pa_hashmap
*dbus_entries
;
113 uint32_t next_index
; /* For generating object paths for entries. */
117 #define ENTRY_VERSION 2
121 pa_bool_t muted_valid
:1, volume_valid
:1, device_valid
:1;
123 pa_channel_map channel_map
;
125 char device
[PA_NAME_MAX
];
133 SUBCOMMAND_SUBSCRIBE
,
137 static struct entry
*read_entry(struct userdata
*u
, const char *name
);
138 static void apply_entry(struct userdata
*u
, const char *name
, struct entry
*e
);
139 static void trigger_save(struct userdata
*u
);
143 #define OBJECT_PATH "/org/pulseaudio/stream_restore1"
144 #define ENTRY_OBJECT_NAME "entry"
145 #define INTERFACE_STREAM_RESTORE "org.PulseAudio.Ext.StreamRestore1"
146 #define INTERFACE_ENTRY INTERFACE_STREAM_RESTORE ".RestoreEntry"
148 #define DBUS_INTERFACE_REVISION 0
151 struct userdata
*userdata
;
158 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
159 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
161 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
163 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
164 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
166 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
167 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
168 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
169 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
170 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
171 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
172 static void handle_entry_get_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
173 static void handle_entry_set_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
175 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
177 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
179 enum property_handler_index
{
180 PROPERTY_HANDLER_INTERFACE_REVISION
,
181 PROPERTY_HANDLER_ENTRIES
,
185 enum entry_property_handler_index
{
186 ENTRY_PROPERTY_HANDLER_INDEX
,
187 ENTRY_PROPERTY_HANDLER_NAME
,
188 ENTRY_PROPERTY_HANDLER_DEVICE
,
189 ENTRY_PROPERTY_HANDLER_VOLUME
,
190 ENTRY_PROPERTY_HANDLER_IS_MUTED
,
191 ENTRY_PROPERTY_HANDLER_MAX
194 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
195 [PROPERTY_HANDLER_INTERFACE_REVISION
] = { .property_name
= "InterfaceRevision", .type
= "u", .get_cb
= handle_get_interface_revision
, .set_cb
= NULL
},
196 [PROPERTY_HANDLER_ENTRIES
] = { .property_name
= "Entries", .type
= "ao", .get_cb
= handle_get_entries
, .set_cb
= NULL
}
199 static pa_dbus_property_handler entry_property_handlers
[ENTRY_PROPERTY_HANDLER_MAX
] = {
200 [ENTRY_PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_entry_get_index
, .set_cb
= NULL
},
201 [ENTRY_PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_entry_get_name
, .set_cb
= NULL
},
202 [ENTRY_PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "s", .get_cb
= handle_entry_get_device
, .set_cb
= handle_entry_set_device
},
203 [ENTRY_PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "a(uu)", .get_cb
= handle_entry_get_volume
, .set_cb
= handle_entry_set_volume
},
204 [ENTRY_PROPERTY_HANDLER_IS_MUTED
] = { .property_name
= "IsMuted", .type
= "b", .get_cb
= handle_entry_get_is_muted
, .set_cb
= handle_entry_set_is_muted
}
207 enum method_handler_index
{
208 METHOD_HANDLER_ADD_ENTRY
,
209 METHOD_HANDLER_GET_ENTRY_BY_NAME
,
213 enum entry_method_handler_index
{
214 ENTRY_METHOD_HANDLER_REMOVE
,
215 ENTRY_METHOD_HANDLER_MAX
218 static pa_dbus_arg_info add_entry_args
[] = { { "name", "s", "in" },
219 { "device", "s", "in" },
220 { "volume", "a(uu)", "in" },
221 { "is_muted", "b", "in" },
222 { "entry", "o", "out" } };
223 static pa_dbus_arg_info get_entry_by_name_args
[] = { { "name", "s", "in" }, { "entry", "o", "out" } };
225 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
226 [METHOD_HANDLER_ADD_ENTRY
] = {
227 .method_name
= "AddEntry",
228 .arguments
= add_entry_args
,
229 .n_arguments
= sizeof(add_entry_args
) / sizeof(pa_dbus_arg_info
),
230 .receive_cb
= handle_add_entry
},
231 [METHOD_HANDLER_GET_ENTRY_BY_NAME
] = {
232 .method_name
= "GetEntryByName",
233 .arguments
= get_entry_by_name_args
,
234 .n_arguments
= sizeof(get_entry_by_name_args
) / sizeof(pa_dbus_arg_info
),
235 .receive_cb
= handle_get_entry_by_name
}
238 static pa_dbus_method_handler entry_method_handlers
[ENTRY_METHOD_HANDLER_MAX
] = {
239 [ENTRY_METHOD_HANDLER_REMOVE
] = {
240 .method_name
= "Remove",
243 .receive_cb
= handle_entry_remove
}
248 SIGNAL_ENTRY_REMOVED
,
252 enum entry_signal_index
{
253 ENTRY_SIGNAL_DEVICE_UPDATED
,
254 ENTRY_SIGNAL_VOLUME_UPDATED
,
255 ENTRY_SIGNAL_MUTE_UPDATED
,
259 static pa_dbus_arg_info new_entry_args
[] = { { "entry", "o", NULL
} };
260 static pa_dbus_arg_info entry_removed_args
[] = { { "entry", "o", NULL
} };
262 static pa_dbus_arg_info entry_device_updated_args
[] = { { "device", "s", NULL
} };
263 static pa_dbus_arg_info entry_volume_updated_args
[] = { { "volume", "a(uu)", NULL
} };
264 static pa_dbus_arg_info entry_mute_updated_args
[] = { { "muted", "b", NULL
} };
266 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
267 [SIGNAL_NEW_ENTRY
] = { .name
= "NewEntry", .arguments
= new_entry_args
, .n_arguments
= 1 },
268 [SIGNAL_ENTRY_REMOVED
] = { .name
= "EntryRemoved", .arguments
= entry_removed_args
, .n_arguments
= 1 }
271 static pa_dbus_signal_info entry_signals
[ENTRY_SIGNAL_MAX
] = {
272 [ENTRY_SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= entry_device_updated_args
, .n_arguments
= 1 },
273 [ENTRY_SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= entry_volume_updated_args
, .n_arguments
= 1 },
274 [ENTRY_SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= entry_mute_updated_args
, .n_arguments
= 1 }
277 static pa_dbus_interface_info stream_restore_interface_info
= {
278 .name
= INTERFACE_STREAM_RESTORE
,
279 .method_handlers
= method_handlers
,
280 .n_method_handlers
= METHOD_HANDLER_MAX
,
281 .property_handlers
= property_handlers
,
282 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
283 .get_all_properties_cb
= handle_get_all
,
285 .n_signals
= SIGNAL_MAX
288 static pa_dbus_interface_info entry_interface_info
= {
289 .name
= INTERFACE_ENTRY
,
290 .method_handlers
= entry_method_handlers
,
291 .n_method_handlers
= ENTRY_METHOD_HANDLER_MAX
,
292 .property_handlers
= entry_property_handlers
,
293 .n_property_handlers
= ENTRY_PROPERTY_HANDLER_MAX
,
294 .get_all_properties_cb
= handle_entry_get_all
,
295 .signals
= entry_signals
,
296 .n_signals
= ENTRY_SIGNAL_MAX
299 static struct dbus_entry
*dbus_entry_new(struct userdata
*u
, const char *entry_name
) {
300 struct dbus_entry
*de
;
303 pa_assert(entry_name
);
304 pa_assert(*entry_name
);
306 de
= pa_xnew(struct dbus_entry
, 1);
308 de
->entry_name
= pa_xstrdup(entry_name
);
309 de
->index
= u
->next_index
++;
310 de
->object_path
= pa_sprintf_malloc("%s/%s%u", OBJECT_PATH
, ENTRY_OBJECT_NAME
, de
->index
);
312 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, de
->object_path
, &entry_interface_info
, u
) >= 0);
317 static void dbus_entry_free(struct dbus_entry
*de
) {
320 pa_assert_se(pa_dbus_protocol_remove_interface(de
->userdata
->dbus_protocol
, de
->object_path
, entry_interface_info
.name
) >= 0);
322 pa_xfree(de
->entry_name
);
323 pa_xfree(de
->object_path
);
326 /* Reads an array [(UInt32, UInt32)] from the iterator. The struct items are
327 * are a channel position and a volume value, respectively. The result is
328 * stored in the map and vol arguments. If the volume can't be read from the
329 * iterator, an error reply is sent and a negative number is returned. In case
330 * of a failure we make no guarantees about the state of map and vol. In case
331 * of an empty array the channels field of both map and vol are set to 0. */
332 static int get_volume_arg(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, pa_channel_map
*map
, pa_cvolume
*vol
) {
333 DBusMessageIter array_iter
;
334 DBusMessageIter struct_iter
;
343 pa_channel_map_init(map
);
344 pa_cvolume_init(vol
);
349 arg_type
= dbus_message_iter_get_arg_type(iter
);
350 if (arg_type
!= DBUS_TYPE_ARRAY
) {
351 if (arg_type
== DBUS_TYPE_INVALID
)
352 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too few arguments. An array was expected.");
354 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong argument type: '%c'. An array was expected.", (char) arg_type
);
358 arg_type
= dbus_message_iter_get_element_type(iter
);
359 if (arg_type
!= DBUS_TYPE_STRUCT
) {
360 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong array element type: '%c'. A struct was expected.", (char) arg_type
);
364 dbus_message_iter_recurse(iter
, &array_iter
);
366 while (dbus_message_iter_get_arg_type(&array_iter
) != DBUS_TYPE_INVALID
) {
367 dbus_uint32_t chan_pos
;
368 dbus_uint32_t chan_vol
;
370 dbus_message_iter_recurse(&array_iter
, &struct_iter
);
372 arg_type
= dbus_message_iter_get_arg_type(&struct_iter
);
373 if (arg_type
!= DBUS_TYPE_UINT32
) {
374 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong channel position type: '%c'. An unsigned 32-bit integer was expected.", (char) arg_type
);
378 dbus_message_iter_get_basic(&struct_iter
, &chan_pos
);
379 dbus_message_iter_next(&struct_iter
);
381 if (chan_pos
>= PA_CHANNEL_POSITION_MAX
) {
382 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid channel position: %u", chan_pos
);
386 arg_type
= dbus_message_iter_get_arg_type(&struct_iter
);
387 if (arg_type
!= DBUS_TYPE_UINT32
) {
388 if (arg_type
== DBUS_TYPE_INVALID
)
389 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Channel volume missing.");
391 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong volume value type: '%c'. An unsigned 32-bit integer was expected.", (char) arg_type
);
395 dbus_message_iter_get_basic(&struct_iter
, &chan_vol
);
397 if (chan_vol
> PA_VOLUME_MAX
) {
398 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", chan_vol
);
402 if (map
->channels
< PA_CHANNELS_MAX
) {
403 map
->map
[map
->channels
] = chan_pos
;
404 vol
->values
[map
->channels
] = chan_vol
;
409 dbus_message_iter_next(&array_iter
);
412 if (map
->channels
> PA_CHANNELS_MAX
) {
413 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too many channels: %u. The maximum is %u.", map
->channels
, PA_CHANNELS_MAX
);
417 dbus_message_iter_next(iter
);
422 static void append_volume(DBusMessageIter
*iter
, struct entry
*e
) {
423 DBusMessageIter array_iter
;
424 DBusMessageIter struct_iter
;
430 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "(uu)", &array_iter
));
432 if (!e
->volume_valid
) {
433 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
437 for (i
= 0; i
< e
->channel_map
.channels
; ++i
) {
438 pa_assert_se(dbus_message_iter_open_container(&array_iter
, DBUS_TYPE_STRUCT
, NULL
, &struct_iter
));
440 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->channel_map
.map
[i
]));
441 pa_assert_se(dbus_message_iter_append_basic(&struct_iter
, DBUS_TYPE_UINT32
, &e
->volume
.values
[i
]));
443 pa_assert_se(dbus_message_iter_close_container(&array_iter
, &struct_iter
));
446 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
449 static void append_volume_variant(DBusMessageIter
*iter
, struct entry
*e
) {
450 DBusMessageIter variant_iter
;
455 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a(uu)", &variant_iter
));
457 append_volume(&variant_iter
, e
);
459 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
462 static void send_new_entry_signal(struct dbus_entry
*entry
) {
467 pa_assert_se(signal
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_NEW_ENTRY
].name
));
468 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
469 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal
);
470 dbus_message_unref(signal
);
473 static void send_entry_removed_signal(struct dbus_entry
*entry
) {
478 pa_assert_se(signal
= dbus_message_new_signal(OBJECT_PATH
, INTERFACE_STREAM_RESTORE
, signals
[SIGNAL_ENTRY_REMOVED
].name
));
479 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_OBJECT_PATH
, &entry
->object_path
, DBUS_TYPE_INVALID
));
480 pa_dbus_protocol_send_signal(entry
->userdata
->dbus_protocol
, signal
);
481 dbus_message_unref(signal
);
484 static void send_device_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
491 device
= e
->device_valid
? e
->device
: "";
493 pa_assert_se(signal
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_DEVICE_UPDATED
].name
));
494 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
495 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal
);
496 dbus_message_unref(signal
);
499 static void send_volume_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
501 DBusMessageIter msg_iter
;
506 pa_assert_se(signal
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_VOLUME_UPDATED
].name
));
507 dbus_message_iter_init_append(signal
, &msg_iter
);
508 append_volume(&msg_iter
, e
);
509 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal
);
510 dbus_message_unref(signal
);
513 static void send_mute_updated_signal(struct dbus_entry
*de
, struct entry
*e
) {
520 pa_assert(e
->muted_valid
);
524 pa_assert_se(signal
= dbus_message_new_signal(de
->object_path
, INTERFACE_ENTRY
, entry_signals
[ENTRY_SIGNAL_MUTE_UPDATED
].name
));
525 pa_assert_se(dbus_message_append_args(signal
, DBUS_TYPE_BOOLEAN
, &muted
, DBUS_TYPE_INVALID
));
526 pa_dbus_protocol_send_signal(de
->userdata
->dbus_protocol
, signal
);
527 dbus_message_unref(signal
);
530 static void handle_get_interface_revision(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
531 dbus_uint32_t interface_revision
= DBUS_INTERFACE_REVISION
;
536 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &interface_revision
);
539 /* The caller frees the array, but not the strings. */
540 static const char **get_entries(struct userdata
*u
, unsigned *n
) {
541 const char **entries
;
544 struct dbus_entry
*de
;
549 *n
= pa_hashmap_size(u
->dbus_entries
);
554 entries
= pa_xnew(const char *, *n
);
556 while ((de
= pa_hashmap_iterate(u
->dbus_entries
, &state
, NULL
))) {
557 entries
[i
] = de
->object_path
;
564 static void handle_get_entries(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
565 struct userdata
*u
= userdata
;
566 const char **entries
;
573 entries
= get_entries(u
, &n
);
575 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, entries
, n
);
580 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
581 struct userdata
*u
= userdata
;
582 DBusMessage
*reply
= NULL
;
583 DBusMessageIter msg_iter
;
584 DBusMessageIter dict_iter
;
585 dbus_uint32_t interface_revision
;
586 const char **entries
;
593 interface_revision
= DBUS_INTERFACE_REVISION
;
594 entries
= get_entries(u
, &n_entries
);
596 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
598 dbus_message_iter_init_append(reply
, &msg_iter
);
599 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
601 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INTERFACE_REVISION
].property_name
, DBUS_TYPE_UINT32
, &interface_revision
);
602 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ENTRIES
].property_name
, DBUS_TYPE_OBJECT_PATH
, entries
, n_entries
);
604 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
606 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
608 dbus_message_unref(reply
);
613 static void handle_add_entry(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
614 struct userdata
*u
= userdata
;
615 DBusMessageIter msg_iter
;
621 dbus_bool_t apply_immediately
;
624 struct dbus_entry
*dbus_entry
;
631 if (!dbus_message_iter_init(msg
, &msg_iter
)) {
632 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too few arguments.");
636 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_STRING
, &name
) < 0)
639 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_STRING
, &device
) < 0)
642 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
645 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_BOOLEAN
, &muted
) < 0)
648 if (pa_dbus_get_basic_arg(conn
, msg
, &msg_iter
, DBUS_TYPE_BOOLEAN
, &apply_immediately
) < 0)
652 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "An empty string was given as the entry name.");
656 if ((dbus_entry
= pa_hashmap_get(u
->dbus_entries
, name
))) {
657 pa_bool_t mute_updated
= FALSE
;
658 pa_bool_t volume_updated
= FALSE
;
659 pa_bool_t device_updated
= FALSE
;
661 pa_assert_se(e
= read_entry(u
, name
));
662 mute_updated
= e
->muted
!= muted
;
664 e
->muted_valid
= TRUE
;
666 volume_updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
668 e
->channel_map
= map
;
669 e
->volume_valid
= !!map
.channels
;
671 device_updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
672 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
673 e
->device_valid
= !!device
[0];
676 send_mute_updated_signal(dbus_entry
, e
);
678 send_volume_updated_signal(dbus_entry
, e
);
680 send_device_updated_signal(dbus_entry
, e
);
683 dbus_entry
= dbus_entry_new(u
, name
);
684 pa_assert(pa_hashmap_put(u
->dbus_entries
, dbus_entry
->entry_name
, dbus_entry
) >= 0);
686 e
->muted_valid
= TRUE
;
687 e
->volume_valid
= !!map
.channels
;
688 e
->device_valid
= !!device
[0];
691 e
->channel_map
= map
;
692 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
694 send_new_entry_signal(dbus_entry
);
697 key
.data
= (char *) name
;
698 key
.size
= strlen(name
);
701 value
.size
= sizeof(struct entry
);
703 pa_assert_se(pa_database_set(u
->database
, &key
, &value
, TRUE
) == 0);
704 if (apply_immediately
)
705 apply_entry(u
, name
, e
);
709 pa_dbus_send_empty_reply(conn
, msg
);
714 static void handle_get_entry_by_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
715 struct userdata
*u
= userdata
;
717 struct dbus_entry
*de
;
724 dbus_error_init(&error
);
726 if (!dbus_message_get_args(msg
, &error
, DBUS_TYPE_STRING
, &name
, DBUS_TYPE_INVALID
)) {
727 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "%s", error
.message
);
728 dbus_error_free(&error
);
732 if (!(de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
733 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "No such stream restore entry.");
737 pa_dbus_send_basic_value_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &de
->object_path
);
740 static void handle_entry_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
741 struct dbus_entry
*de
= userdata
;
747 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &de
->index
);
750 static void handle_entry_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
751 struct dbus_entry
*de
= userdata
;
757 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &de
->entry_name
);
760 static void handle_entry_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
761 struct dbus_entry
*de
= userdata
;
769 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
771 device
= e
->device_valid
? e
->device
: "";
773 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &device
);
778 static void handle_entry_set_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
779 struct dbus_entry
*de
= userdata
;
788 if (pa_dbus_get_basic_set_property_arg(conn
, msg
, DBUS_TYPE_STRING
, &device
) < 0)
791 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
793 updated
= (e
->device_valid
!= !!device
[0]) || !pa_streq(e
->device
, device
);
799 pa_strlcpy(e
->device
, device
, sizeof(e
->device
));
800 e
->device_valid
= !!device
[0];
802 key
.data
= de
->entry_name
;
803 key
.size
= strlen(de
->entry_name
);
805 value
.size
= sizeof(struct entry
);
806 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
808 send_device_updated_signal(de
, e
);
809 trigger_save(de
->userdata
);
812 pa_dbus_send_empty_reply(conn
, msg
);
817 static void handle_entry_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
818 struct dbus_entry
*de
= userdata
;
820 DBusMessageIter msg_iter
;
827 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
829 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
831 dbus_message_iter_init_append(reply
, &msg_iter
);
832 append_volume_variant(&msg_iter
, e
);
834 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
839 static void handle_entry_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
840 struct dbus_entry
*de
= userdata
;
841 DBusMessageIter msg_iter
;
851 /* Skip the interface and property name arguments. */
852 if (!dbus_message_iter_init(msg
, &msg_iter
) || !dbus_message_iter_next(&msg_iter
) || !dbus_message_iter_next(&msg_iter
)) {
853 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too few arguments.");
857 if (get_volume_arg(conn
, msg
, &msg_iter
, &map
, &vol
) < 0)
860 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
862 updated
= (e
->volume_valid
!= !!map
.channels
) || !pa_cvolume_equal(&e
->volume
, &vol
);
869 e
->channel_map
= map
;
870 e
->volume_valid
= !!map
.channels
;
872 key
.data
= de
->entry_name
;
873 key
.size
= strlen(de
->entry_name
);
875 value
.size
= sizeof(struct entry
);
876 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
878 send_volume_updated_signal(de
, e
);
879 trigger_save(de
->userdata
);
882 pa_dbus_send_empty_reply(conn
, msg
);
887 static void handle_entry_get_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
888 struct dbus_entry
*de
= userdata
;
896 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
898 muted
= e
->muted_valid
? e
->muted
: FALSE
;
900 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &muted
);
905 static void handle_entry_set_is_muted(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
906 struct dbus_entry
*de
= userdata
;
915 if (pa_dbus_get_basic_set_property_arg(conn
, msg
, DBUS_TYPE_BOOLEAN
, &muted
) < 0)
918 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
920 updated
= !e
->muted_valid
|| e
->muted
!= muted
;
927 e
->muted_valid
= TRUE
;
929 key
.data
= de
->entry_name
;
930 key
.size
= strlen(de
->entry_name
);
932 value
.size
= sizeof(struct entry
);
933 pa_assert_se(pa_database_set(de
->userdata
->database
, &key
, &value
, TRUE
) == 0);
935 send_mute_updated_signal(de
, e
);
936 trigger_save(de
->userdata
);
939 pa_dbus_send_empty_reply(conn
, msg
);
944 static void handle_entry_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
945 struct dbus_entry
*de
= userdata
;
947 DBusMessage
*reply
= NULL
;
948 DBusMessageIter msg_iter
;
949 DBusMessageIter dict_iter
;
950 DBusMessageIter dict_entry_iter
;
958 pa_assert_se(e
= read_entry(de
->userdata
, de
->entry_name
));
960 device
= e
->device_valid
? e
->device
: "";
961 muted
= e
->muted_valid
? e
->muted
: FALSE
;
963 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
965 dbus_message_iter_init_append(reply
, &msg_iter
);
966 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
968 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &de
->index
);
969 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &de
->entry_name
);
970 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_STRING
, &device
);
972 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
974 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &entry_property_handlers
[ENTRY_PROPERTY_HANDLER_VOLUME
].property_name
));
975 append_volume_variant(&dict_entry_iter
, e
);
977 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
979 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, entry_property_handlers
[ENTRY_PROPERTY_HANDLER_IS_MUTED
].property_name
, DBUS_TYPE_BOOLEAN
, &muted
);
981 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
983 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
985 dbus_message_unref(reply
);
990 static void handle_entry_remove(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
991 struct dbus_entry
*de
= userdata
;
998 key
.data
= de
->entry_name
;
999 key
.size
= strlen(de
->entry_name
);
1001 pa_assert_se(pa_database_unset(de
->userdata
->database
, &key
) == 0);
1003 send_entry_removed_signal(de
);
1004 trigger_save(de
->userdata
);
1006 pa_assert_se(pa_hashmap_remove(de
->userdata
->dbus_entries
, de
->entry_name
));
1007 dbus_entry_free(de
);
1009 pa_dbus_send_empty_reply(conn
, msg
);
1012 #endif /* HAVE_DBUS */
1014 static void save_time_callback(pa_mainloop_api
*a
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
1015 struct userdata
*u
= userdata
;
1021 pa_assert(e
== u
->save_time_event
);
1022 u
->core
->mainloop
->time_free(u
->save_time_event
);
1023 u
->save_time_event
= NULL
;
1025 pa_database_sync(u
->database
);
1026 pa_log_info("Synced.");
1029 static char *get_name(pa_proplist
*p
, const char *prefix
) {
1036 if ((r
= pa_proplist_gets(p
, IDENTIFICATION_PROPERTY
)))
1037 return pa_xstrdup(r
);
1039 if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_ROLE
)))
1040 t
= pa_sprintf_malloc("%s-by-media-role:%s", prefix
, r
);
1041 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_ID
)))
1042 t
= pa_sprintf_malloc("%s-by-application-id:%s", prefix
, r
);
1043 else if ((r
= pa_proplist_gets(p
, PA_PROP_APPLICATION_NAME
)))
1044 t
= pa_sprintf_malloc("%s-by-application-name:%s", prefix
, r
);
1045 else if ((r
= pa_proplist_gets(p
, PA_PROP_MEDIA_NAME
)))
1046 t
= pa_sprintf_malloc("%s-by-media-name:%s", prefix
, r
);
1048 t
= pa_sprintf_malloc("%s-fallback:%s", prefix
, r
);
1050 pa_proplist_sets(p
, IDENTIFICATION_PROPERTY
, t
);
1054 static struct entry
*read_entry(struct userdata
*u
, const char *name
) {
1061 key
.data
= (char*) name
;
1062 key
.size
= strlen(name
);
1066 if (!pa_database_get(u
->database
, &key
, &data
))
1069 if (data
.size
!= sizeof(struct entry
)) {
1070 /* This is probably just a database upgrade, hence let's not
1071 * consider this more than a debug message */
1072 pa_log_debug("Database contains entry for stream %s of wrong size %lu != %lu. Probably due to uprade, ignoring.", name
, (unsigned long) data
.size
, (unsigned long) sizeof(struct entry
));
1076 e
= (struct entry
*) data
.data
;
1078 if (e
->version
!= ENTRY_VERSION
) {
1079 pa_log_debug("Version of database entry for stream %s doesn't match our version. Probably due to upgrade, ignoring.", name
);
1083 if (!memchr(e
->device
, 0, sizeof(e
->device
))) {
1084 pa_log_warn("Database contains entry for stream %s with missing NUL byte in device name", name
);
1088 if (e
->device_valid
&& !pa_namereg_is_valid_name(e
->device
)) {
1089 pa_log_warn("Invalid device name stored in database for stream %s", name
);
1093 if (e
->volume_valid
&& !pa_channel_map_valid(&e
->channel_map
)) {
1094 pa_log_warn("Invalid channel map stored in database for stream %s", name
);
1098 if (e
->volume_valid
&& (!pa_cvolume_valid(&e
->volume
) || !pa_cvolume_compatible_with_channel_map(&e
->volume
, &e
->channel_map
))) {
1099 pa_log_warn("Invalid volume stored in database for stream %s", name
);
1107 pa_datum_free(&data
);
1111 static void trigger_save(struct userdata
*u
) {
1112 pa_native_connection
*c
;
1115 for (c
= pa_idxset_first(u
->subscribed
, &idx
); c
; c
= pa_idxset_next(u
->subscribed
, &idx
)) {
1118 t
= pa_tagstruct_new(NULL
, 0);
1119 pa_tagstruct_putu32(t
, PA_COMMAND_EXTENSION
);
1120 pa_tagstruct_putu32(t
, 0);
1121 pa_tagstruct_putu32(t
, u
->module
->index
);
1122 pa_tagstruct_puts(t
, u
->module
->name
);
1123 pa_tagstruct_putu32(t
, SUBCOMMAND_EVENT
);
1125 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), t
);
1128 if (u
->save_time_event
)
1131 u
->save_time_event
= pa_core_rttime_new(u
->core
, pa_rtclock_now() + SAVE_INTERVAL
, save_time_callback
, u
);
1134 static pa_bool_t
entries_equal(const struct entry
*a
, const struct entry
*b
) {
1140 if (a
->device_valid
!= b
->device_valid
||
1141 (a
->device_valid
&& strncmp(a
->device
, b
->device
, sizeof(a
->device
))))
1144 if (a
->muted_valid
!= b
->muted_valid
||
1145 (a
->muted_valid
&& (a
->muted
!= b
->muted
)))
1149 if (a
->volume_valid
!= b
->volume_valid
||
1150 (a
->volume_valid
&& !pa_cvolume_equal(pa_cvolume_remap(&t
, &b
->channel_map
, &a
->channel_map
), &a
->volume
)))
1156 static void subscribe_callback(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
1157 struct userdata
*u
= userdata
;
1158 struct entry entry
, *old
;
1162 /* These are only used when D-Bus is enabled, but in order to reduce ifdef
1163 * clutter these are defined here unconditionally. */
1164 pa_bool_t created_new_entry
= TRUE
;
1165 pa_bool_t device_updated
= FALSE
;
1166 pa_bool_t volume_updated
= FALSE
;
1167 pa_bool_t mute_updated
= FALSE
;
1170 struct dbus_entry
*de
= NULL
;
1176 if (t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1177 t
!= (PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
) &&
1178 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
) &&
1179 t
!= (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
))
1183 entry
.version
= ENTRY_VERSION
;
1185 if ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
) {
1186 pa_sink_input
*sink_input
;
1188 if (!(sink_input
= pa_idxset_get_by_index(c
->sink_inputs
, idx
)))
1191 if (!(name
= get_name(sink_input
->proplist
, "sink-input")))
1194 if ((old
= read_entry(u
, name
))) {
1196 created_new_entry
= FALSE
;
1199 if (sink_input
->save_volume
) {
1200 entry
.channel_map
= sink_input
->channel_map
;
1201 pa_sink_input_get_volume(sink_input
, &entry
.volume
, FALSE
);
1202 entry
.volume_valid
= TRUE
;
1204 volume_updated
= !created_new_entry
1205 && (!old
->volume_valid
1206 || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
)
1207 || !pa_cvolume_equal(&entry
.volume
, &old
->volume
));
1210 if (sink_input
->save_muted
) {
1211 entry
.muted
= pa_sink_input_get_mute(sink_input
);
1212 entry
.muted_valid
= TRUE
;
1214 mute_updated
= !created_new_entry
&& (!old
->muted_valid
|| entry
.muted
!= old
->muted
);
1217 if (sink_input
->save_sink
) {
1218 pa_strlcpy(entry
.device
, sink_input
->sink
->name
, sizeof(entry
.device
));
1219 entry
.device_valid
= TRUE
;
1221 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1225 pa_source_output
*source_output
;
1227 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
);
1229 if (!(source_output
= pa_idxset_get_by_index(c
->source_outputs
, idx
)))
1232 if (!(name
= get_name(source_output
->proplist
, "source-output")))
1235 if ((old
= read_entry(u
, name
))) {
1237 created_new_entry
= FALSE
;
1240 if (source_output
->save_source
) {
1241 pa_strlcpy(entry
.device
, source_output
->source
->name
, sizeof(entry
.device
));
1242 entry
.device_valid
= source_output
->save_source
;
1244 device_updated
= !created_new_entry
&& (!old
->device_valid
|| !pa_streq(entry
.device
, old
->device
));
1250 if (entries_equal(old
, &entry
)) {
1260 key
.size
= strlen(name
);
1263 data
.size
= sizeof(entry
);
1265 pa_log_info("Storing volume/mute/device for stream %s.", name
);
1267 pa_database_set(u
->database
, &key
, &data
, TRUE
);
1270 if (created_new_entry
) {
1271 de
= dbus_entry_new(u
, name
);
1272 pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
);
1273 send_new_entry_signal(de
);
1275 pa_assert((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1278 send_device_updated_signal(de
, &entry
);
1280 send_volume_updated_signal(de
, &entry
);
1282 send_mute_updated_signal(de
, &entry
);
1291 static pa_hook_result_t
sink_input_new_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1296 pa_assert(new_data
);
1298 pa_assert(u
->restore_device
);
1300 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1303 if ((e
= read_entry(u
, name
))) {
1305 if (e
->device_valid
) {
1308 if ((s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
))) {
1309 if (!new_data
->sink
) {
1310 pa_log_info("Restoring device for stream %s.", name
);
1312 new_data
->save_sink
= TRUE
;
1314 pa_log_debug("Not restoring device for stream %s, because already set.", name
);
1326 static pa_hook_result_t
sink_input_fixate_hook_callback(pa_core
*c
, pa_sink_input_new_data
*new_data
, struct userdata
*u
) {
1331 pa_assert(new_data
);
1333 pa_assert(u
->restore_volume
|| u
->restore_muted
);
1335 if (!(name
= get_name(new_data
->proplist
, "sink-input")))
1338 if ((e
= read_entry(u
, name
))) {
1340 if (u
->restore_volume
&& e
->volume_valid
) {
1342 if (!new_data
->volume_is_set
) {
1345 pa_log_info("Restoring volume for sink input %s.", name
);
1348 pa_cvolume_remap(&v
, &e
->channel_map
, &new_data
->channel_map
);
1349 pa_sink_input_new_data_set_volume(new_data
, &v
);
1351 new_data
->volume_is_absolute
= FALSE
;
1352 new_data
->save_volume
= TRUE
;
1354 pa_log_debug("Not restoring volume for sink input %s, because already set.", name
);
1357 if (u
->restore_muted
&& e
->muted_valid
) {
1359 if (!new_data
->muted_is_set
) {
1360 pa_log_info("Restoring mute state for sink input %s.", name
);
1361 pa_sink_input_new_data_set_muted(new_data
, e
->muted
);
1362 new_data
->save_muted
= TRUE
;
1364 pa_log_debug("Not restoring mute state for sink input %s, because already set.", name
);
1375 static pa_hook_result_t
source_output_new_hook_callback(pa_core
*c
, pa_source_output_new_data
*new_data
, struct userdata
*u
) {
1380 pa_assert(new_data
);
1382 pa_assert(u
->restore_device
);
1384 if (new_data
->direct_on_input
)
1387 if (!(name
= get_name(new_data
->proplist
, "source-output")))
1390 if ((e
= read_entry(u
, name
))) {
1393 if (e
->device_valid
) {
1394 if ((s
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
))) {
1395 if (!new_data
->source
) {
1396 pa_log_info("Restoring device for stream %s.", name
);
1397 new_data
->source
= s
;
1398 new_data
->save_source
= TRUE
;
1400 pa_log_debug("Not restoring device for stream %s, because already set", name
);
1412 static pa_hook_result_t
sink_put_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1419 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1421 PA_IDXSET_FOREACH(si
, c
->sink_inputs
, idx
) {
1425 if (si
->sink
== sink
)
1431 if (!(name
= get_name(si
->proplist
, "sink-input")))
1434 if ((e
= read_entry(u
, name
))) {
1435 if (e
->device_valid
&& pa_streq(e
->device
, sink
->name
))
1436 pa_sink_input_move_to(si
, sink
, TRUE
);
1447 static pa_hook_result_t
source_put_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1448 pa_source_output
*so
;
1454 pa_assert(u
->on_hotplug
&& u
->restore_device
);
1456 PA_IDXSET_FOREACH(so
, c
->source_outputs
, idx
) {
1460 if (so
->source
== source
)
1463 if (so
->save_source
)
1466 if (so
->direct_on_input
)
1469 if (!(name
= get_name(so
->proplist
, "source-input")))
1472 if ((e
= read_entry(u
, name
))) {
1473 if (e
->device_valid
&& pa_streq(e
->device
, source
->name
))
1474 pa_source_output_move_to(so
, source
, TRUE
);
1485 static pa_hook_result_t
sink_unlink_hook_callback(pa_core
*c
, pa_sink
*sink
, struct userdata
*u
) {
1492 pa_assert(u
->on_rescue
&& u
->restore_device
);
1494 /* There's no point in doing anything if the core is shut down anyway */
1495 if (c
->state
== PA_CORE_SHUTDOWN
)
1498 PA_IDXSET_FOREACH(si
, sink
->inputs
, idx
) {
1502 if (!(name
= get_name(si
->proplist
, "sink-input")))
1505 if ((e
= read_entry(u
, name
))) {
1507 if (e
->device_valid
) {
1510 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SINK
)) && d
!= sink
)
1511 pa_sink_input_move_to(si
, d
, TRUE
);
1523 static pa_hook_result_t
source_unlink_hook_callback(pa_core
*c
, pa_source
*source
, struct userdata
*u
) {
1524 pa_source_output
*so
;
1530 pa_assert(u
->on_rescue
&& u
->restore_device
);
1532 /* There's no point in doing anything if the core is shut down anyway */
1533 if (c
->state
== PA_CORE_SHUTDOWN
)
1536 PA_IDXSET_FOREACH(so
, source
->outputs
, idx
) {
1540 if (!(name
= get_name(so
->proplist
, "source-output")))
1543 if ((e
= read_entry(u
, name
))) {
1545 if (e
->device_valid
) {
1548 if ((d
= pa_namereg_get(c
, e
->device
, PA_NAMEREG_SOURCE
)) && d
!= source
)
1549 pa_source_output_move_to(so
, d
, TRUE
);
1561 #define EXT_VERSION 1
1563 static void apply_entry(struct userdata
*u
, const char *name
, struct entry
*e
) {
1565 pa_source_output
*so
;
1572 for (si
= pa_idxset_first(u
->core
->sink_inputs
, &idx
); si
; si
= pa_idxset_next(u
->core
->sink_inputs
, &idx
)) {
1576 if (!(n
= get_name(si
->proplist
, "sink-input")))
1579 if (!pa_streq(name
, n
)) {
1585 if (u
->restore_volume
&& e
->volume_valid
) {
1589 pa_log_info("Restoring volume for sink input %s.", name
);
1590 pa_sink_input_set_volume(si
, pa_cvolume_remap(&v
, &e
->channel_map
, &si
->channel_map
), FALSE
, FALSE
);
1593 if (u
->restore_muted
&& e
->muted_valid
) {
1594 pa_log_info("Restoring mute state for sink input %s.", name
);
1595 pa_sink_input_set_mute(si
, e
->muted
, FALSE
);
1598 if (u
->restore_device
&&
1600 (s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SINK
))) {
1602 pa_log_info("Restoring device for stream %s.", name
);
1603 pa_sink_input_move_to(si
, s
, FALSE
);
1607 for (so
= pa_idxset_first(u
->core
->source_outputs
, &idx
); so
; so
= pa_idxset_next(u
->core
->source_outputs
, &idx
)) {
1611 if (!(n
= get_name(so
->proplist
, "source-output")))
1614 if (!pa_streq(name
, n
)) {
1620 if (u
->restore_device
&&
1622 (s
= pa_namereg_get(u
->core
, e
->device
, PA_NAMEREG_SOURCE
))) {
1624 pa_log_info("Restoring device for stream %s.", name
);
1625 pa_source_output_move_to(so
, s
, FALSE
);
1631 static void dump_database(struct userdata
*u
) {
1635 done
= !pa_database_first(u
->database
, &key
, NULL
);
1642 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1644 name
= pa_xstrndup(key
.data
, key
.size
);
1645 pa_datum_free(&key
);
1647 if ((e
= read_entry(u
, name
))) {
1649 pa_log("name=%s", name
);
1650 pa_log("device=%s %s", e
->device
, pa_yes_no(e
->device_valid
));
1651 pa_log("channel_map=%s", pa_channel_map_snprint(t
, sizeof(t
), &e
->channel_map
));
1652 pa_log("volume=%s %s", pa_cvolume_snprint(t
, sizeof(t
), &e
->volume
), pa_yes_no(e
->volume_valid
));
1653 pa_log("mute=%s %s", pa_yes_no(e
->muted
), pa_yes_no(e
->volume_valid
));
1664 static int extension_cb(pa_native_protocol
*p
, pa_module
*m
, pa_native_connection
*c
, uint32_t tag
, pa_tagstruct
*t
) {
1667 pa_tagstruct
*reply
= NULL
;
1676 if (pa_tagstruct_getu32(t
, &command
) < 0)
1679 reply
= pa_tagstruct_new(NULL
, 0);
1680 pa_tagstruct_putu32(reply
, PA_COMMAND_REPLY
);
1681 pa_tagstruct_putu32(reply
, tag
);
1684 case SUBCOMMAND_TEST
: {
1685 if (!pa_tagstruct_eof(t
))
1688 pa_tagstruct_putu32(reply
, EXT_VERSION
);
1692 case SUBCOMMAND_READ
: {
1696 if (!pa_tagstruct_eof(t
))
1699 done
= !pa_database_first(u
->database
, &key
, NULL
);
1706 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
1708 name
= pa_xstrndup(key
.data
, key
.size
);
1709 pa_datum_free(&key
);
1711 if ((e
= read_entry(u
, name
))) {
1715 pa_tagstruct_puts(reply
, name
);
1716 pa_tagstruct_put_channel_map(reply
, e
->volume_valid
? &e
->channel_map
: pa_channel_map_init(&cm
));
1717 pa_tagstruct_put_cvolume(reply
, e
->volume_valid
? &e
->volume
: pa_cvolume_init(&r
));
1718 pa_tagstruct_puts(reply
, e
->device_valid
? e
->device
: NULL
);
1719 pa_tagstruct_put_boolean(reply
, e
->muted_valid
? e
->muted
: FALSE
);
1732 case SUBCOMMAND_WRITE
: {
1734 pa_bool_t apply_immediately
= FALSE
;
1736 if (pa_tagstruct_getu32(t
, &mode
) < 0 ||
1737 pa_tagstruct_get_boolean(t
, &apply_immediately
) < 0)
1740 if (mode
!= PA_UPDATE_MERGE
&&
1741 mode
!= PA_UPDATE_REPLACE
&&
1742 mode
!= PA_UPDATE_SET
)
1745 if (mode
== PA_UPDATE_SET
) {
1747 struct dbus_entry
*de
;
1750 while ((de
= pa_hashmap_iterate(u
->dbus_entries
, &state
, NULL
))) {
1751 send_entry_removed_signal(de
);
1752 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, de
->entry_name
));
1755 pa_database_clear(u
->database
);
1758 while (!pa_tagstruct_eof(t
)) {
1759 const char *name
, *device
;
1768 entry
.version
= ENTRY_VERSION
;
1770 if (pa_tagstruct_gets(t
, &name
) < 0 ||
1771 pa_tagstruct_get_channel_map(t
, &entry
.channel_map
) ||
1772 pa_tagstruct_get_cvolume(t
, &entry
.volume
) < 0 ||
1773 pa_tagstruct_gets(t
, &device
) < 0 ||
1774 pa_tagstruct_get_boolean(t
, &muted
) < 0)
1777 if (!name
|| !*name
)
1780 entry
.volume_valid
= entry
.volume
.channels
> 0;
1782 if (entry
.volume_valid
)
1783 if (!pa_cvolume_compatible_with_channel_map(&entry
.volume
, &entry
.channel_map
))
1786 entry
.muted
= muted
;
1787 entry
.muted_valid
= TRUE
;
1790 pa_strlcpy(entry
.device
, device
, sizeof(entry
.device
));
1791 entry
.device_valid
= !!entry
.device
[0];
1793 if (entry
.device_valid
&&
1794 !pa_namereg_is_valid_name(entry
.device
))
1798 old
= read_entry(u
, name
);
1801 key
.data
= (char*) name
;
1802 key
.size
= strlen(name
);
1805 data
.size
= sizeof(entry
);
1807 if (pa_database_set(u
->database
, &key
, &data
, mode
== PA_UPDATE_REPLACE
) == 0) {
1809 struct dbus_entry
*de
;
1812 pa_assert_se((de
= pa_hashmap_get(u
->dbus_entries
, name
)));
1814 if ((old
->device_valid
!= entry
.device_valid
)
1815 || (entry
.device_valid
&& !pa_streq(entry
.device
, old
->device
)))
1816 send_device_updated_signal(de
, &entry
);
1818 if ((old
->volume_valid
!= entry
.volume_valid
)
1819 || (entry
.volume_valid
1820 && (!pa_cvolume_equal(&entry
.volume
, &old
->volume
) || !pa_channel_map_equal(&entry
.channel_map
, &old
->channel_map
))))
1821 send_volume_updated_signal(de
, &entry
);
1823 if (!old
->muted_valid
|| (entry
.muted
!= old
->muted
))
1824 send_mute_updated_signal(de
, &entry
);
1827 de
= dbus_entry_new(u
, name
);
1828 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
));
1829 send_new_entry_signal(de
);
1833 if (apply_immediately
)
1834 apply_entry(u
, name
, &entry
);
1848 case SUBCOMMAND_DELETE
:
1850 while (!pa_tagstruct_eof(t
)) {
1854 struct dbus_entry
*de
;
1857 if (pa_tagstruct_gets(t
, &name
) < 0)
1861 if ((de
= pa_hashmap_get(u
->dbus_entries
, name
))) {
1862 send_entry_removed_signal(de
);
1863 dbus_entry_free(pa_hashmap_remove(u
->dbus_entries
, name
));
1867 key
.data
= (char*) name
;
1868 key
.size
= strlen(name
);
1870 pa_database_unset(u
->database
, &key
);
1877 case SUBCOMMAND_SUBSCRIBE
: {
1881 if (pa_tagstruct_get_boolean(t
, &enabled
) < 0 ||
1882 !pa_tagstruct_eof(t
))
1886 pa_idxset_put(u
->subscribed
, c
, NULL
);
1888 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1897 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c
), reply
);
1903 pa_tagstruct_free(reply
);
1908 static pa_hook_result_t
connection_unlink_hook_cb(pa_native_protocol
*p
, pa_native_connection
*c
, struct userdata
*u
) {
1913 pa_idxset_remove_by_data(u
->subscribed
, c
, NULL
);
1917 int pa__init(pa_module
*m
) {
1918 pa_modargs
*ma
= NULL
;
1922 pa_source_output
*so
;
1924 pa_bool_t restore_device
= TRUE
, restore_volume
= TRUE
, restore_muted
= TRUE
, on_hotplug
= TRUE
, on_rescue
= TRUE
;
1932 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
1933 pa_log("Failed to parse module arguments");
1937 if (pa_modargs_get_value_boolean(ma
, "restore_device", &restore_device
) < 0 ||
1938 pa_modargs_get_value_boolean(ma
, "restore_volume", &restore_volume
) < 0 ||
1939 pa_modargs_get_value_boolean(ma
, "restore_muted", &restore_muted
) < 0 ||
1940 pa_modargs_get_value_boolean(ma
, "on_hotplug", &on_hotplug
) < 0 ||
1941 pa_modargs_get_value_boolean(ma
, "on_rescue", &on_rescue
) < 0) {
1942 pa_log("restore_device=, restore_volume=, restore_muted=, on_hotplug= and on_rescue= expect boolean arguments");
1946 if (!restore_muted
&& !restore_volume
&& !restore_device
)
1947 pa_log_warn("Neither restoring volume, nor restoring muted, nor restoring device enabled!");
1949 m
->userdata
= u
= pa_xnew0(struct userdata
, 1);
1952 u
->restore_device
= restore_device
;
1953 u
->restore_volume
= restore_volume
;
1954 u
->restore_muted
= restore_muted
;
1955 u
->on_hotplug
= on_hotplug
;
1956 u
->on_rescue
= on_rescue
;
1957 u
->subscribed
= pa_idxset_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
1959 u
->protocol
= pa_native_protocol_get(m
->core
);
1960 pa_native_protocol_install_ext(u
->protocol
, m
, extension_cb
);
1962 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
);
1964 u
->subscription
= pa_subscription_new(m
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
|PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscribe_callback
, u
);
1966 if (restore_device
) {
1967 /* A little bit earlier than module-intended-roles ... */
1968 u
->sink_input_new_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SINK_INPUT_NEW
], PA_HOOK_EARLY
, (pa_hook_cb_t
) sink_input_new_hook_callback
, u
);
1969 u
->source_output_new_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_NEW
], PA_HOOK_EARLY
, (pa_hook_cb_t
) source_output_new_hook_callback
, u
);
1972 if (restore_device
&& on_hotplug
) {
1973 /* A little bit earlier than module-intended-roles ... */
1974 u
->sink_put_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SINK_PUT
], PA_HOOK_LATE
, (pa_hook_cb_t
) sink_put_hook_callback
, u
);
1975 u
->source_put_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], PA_HOOK_LATE
, (pa_hook_cb_t
) source_put_hook_callback
, u
);
1978 if (restore_device
&& on_rescue
) {
1979 /* A little bit earlier than module-intended-roles, module-rescue-streams, ... */
1980 u
->sink_unlink_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SINK_UNLINK
], PA_HOOK_LATE
, (pa_hook_cb_t
) sink_unlink_hook_callback
, u
);
1981 u
->source_unlink_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], PA_HOOK_LATE
, (pa_hook_cb_t
) source_unlink_hook_callback
, u
);
1984 if (restore_volume
|| restore_muted
)
1985 u
->sink_input_fixate_hook_slot
= pa_hook_connect(&m
->core
->hooks
[PA_CORE_HOOK_SINK_INPUT_FIXATE
], PA_HOOK_EARLY
, (pa_hook_cb_t
) sink_input_fixate_hook_callback
, u
);
1987 if (!(fname
= pa_state_path("stream-volumes", TRUE
)))
1990 if (!(u
->database
= pa_database_open(fname
, TRUE
))) {
1991 pa_log("Failed to open volume database '%s': %s", fname
, pa_cstrerror(errno
));
1996 pa_log_info("Sucessfully opened database file '%s'.", fname
);
2000 u
->dbus_protocol
= pa_dbus_protocol_get(u
->core
);
2001 u
->dbus_entries
= pa_hashmap_new(pa_idxset_string_hash_func
, pa_idxset_string_compare_func
);
2003 pa_assert_se(pa_dbus_protocol_add_interface(u
->dbus_protocol
, OBJECT_PATH
, &stream_restore_interface_info
, u
) >= 0);
2004 pa_assert_se(pa_dbus_protocol_register_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2006 /* Create the initial dbus entries. */
2007 done
= !pa_database_first(u
->database
, &key
, NULL
);
2011 struct dbus_entry
*de
;
2013 done
= !pa_database_next(u
->database
, &key
, &next_key
, NULL
);
2015 name
= pa_xstrndup(key
.data
, key
.size
);
2016 pa_datum_free(&key
);
2018 de
= dbus_entry_new(u
, name
);
2019 pa_assert_se(pa_hashmap_put(u
->dbus_entries
, de
->entry_name
, de
) >= 0);
2027 PA_IDXSET_FOREACH(si
, m
->core
->sink_inputs
, idx
)
2028 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_NEW
, si
->index
, u
);
2030 PA_IDXSET_FOREACH(so
, m
->core
->source_outputs
, idx
)
2031 subscribe_callback(m
->core
, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
|PA_SUBSCRIPTION_EVENT_NEW
, so
->index
, u
);
2033 pa_modargs_free(ma
);
2040 pa_modargs_free(ma
);
2046 static void free_dbus_entry_cb(void *p
, void *userdata
) {
2047 struct dbus_entry
*de
= p
;
2051 dbus_entry_free(de
);
2055 void pa__done(pa_module
*m
) {
2060 if (!(u
= m
->userdata
))
2064 if (u
->dbus_protocol
) {
2065 pa_assert(u
->dbus_entries
);
2067 pa_assert_se(pa_dbus_protocol_unregister_extension(u
->dbus_protocol
, INTERFACE_STREAM_RESTORE
) >= 0);
2068 pa_assert_se(pa_dbus_protocol_remove_interface(u
->dbus_protocol
, OBJECT_PATH
, stream_restore_interface_info
.name
) >= 0);
2070 pa_hashmap_free(u
->dbus_entries
, free_dbus_entry_cb
, NULL
);
2072 pa_dbus_protocol_unref(u
->dbus_protocol
);
2076 if (u
->subscription
)
2077 pa_subscription_free(u
->subscription
);
2079 if (u
->sink_input_new_hook_slot
)
2080 pa_hook_slot_free(u
->sink_input_new_hook_slot
);
2081 if (u
->sink_input_fixate_hook_slot
)
2082 pa_hook_slot_free(u
->sink_input_fixate_hook_slot
);
2083 if (u
->source_output_new_hook_slot
)
2084 pa_hook_slot_free(u
->source_output_new_hook_slot
);
2086 if (u
->sink_put_hook_slot
)
2087 pa_hook_slot_free(u
->sink_put_hook_slot
);
2088 if (u
->source_put_hook_slot
)
2089 pa_hook_slot_free(u
->source_put_hook_slot
);
2091 if (u
->sink_unlink_hook_slot
)
2092 pa_hook_slot_free(u
->sink_unlink_hook_slot
);
2093 if (u
->source_unlink_hook_slot
)
2094 pa_hook_slot_free(u
->source_unlink_hook_slot
);
2096 if (u
->connection_unlink_hook_slot
)
2097 pa_hook_slot_free(u
->connection_unlink_hook_slot
);
2099 if (u
->save_time_event
)
2100 u
->core
->mainloop
->time_free(u
->save_time_event
);
2103 pa_database_close(u
->database
);
2106 pa_native_protocol_remove_ext(u
->protocol
, m
);
2107 pa_native_protocol_unref(u
->protocol
);
2111 pa_idxset_free(u
->subscribed
, NULL
, NULL
);