2 This file is part of PulseAudio.
4 Copyright 2009 Tanu Kaskinen
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/dbus-util.h>
28 #include <pulsecore/modargs.h>
29 #include <pulsecore/protocol-dbus.h>
31 #include "iface-module.h"
33 #define OBJECT_NAME "module"
35 struct pa_dbusiface_module
{
38 pa_proplist
*proplist
;
40 pa_dbus_protocol
*dbus_protocol
;
41 pa_subscription
*subscription
;
44 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
45 static void handle_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
46 static void handle_get_arguments(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
47 static void handle_get_usage_counter(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
48 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
50 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
52 static void handle_unload(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
54 enum property_handler_index
{
55 PROPERTY_HANDLER_INDEX
,
56 PROPERTY_HANDLER_NAME
,
57 PROPERTY_HANDLER_ARGUMENTS
,
58 PROPERTY_HANDLER_USAGE_COUNTER
,
59 PROPERTY_HANDLER_PROPERTY_LIST
,
63 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
64 [PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_get_index
, .set_cb
= NULL
},
65 [PROPERTY_HANDLER_NAME
] = { .property_name
= "Name", .type
= "s", .get_cb
= handle_get_name
, .set_cb
= NULL
},
66 [PROPERTY_HANDLER_ARGUMENTS
] = { .property_name
= "Arguments", .type
= "a{ss}", .get_cb
= handle_get_arguments
, .set_cb
= NULL
},
67 [PROPERTY_HANDLER_USAGE_COUNTER
] = { .property_name
= "UsageCounter", .type
= "u", .get_cb
= handle_get_usage_counter
, .set_cb
= NULL
},
68 [PROPERTY_HANDLER_PROPERTY_LIST
] = { .property_name
= "PropertyList", .type
= "a{say}", .get_cb
= handle_get_property_list
, .set_cb
= NULL
}
71 enum method_handler_index
{
72 METHOD_HANDLER_UNLOAD
,
76 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
77 [METHOD_HANDLER_UNLOAD
] = {
78 .method_name
= "Unload",
81 .receive_cb
= handle_unload
}
85 SIGNAL_PROPERTY_LIST_UPDATED
,
89 static pa_dbus_arg_info property_list_updated_args
[] = { { "property_list", "a{say}", NULL
} };
91 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
92 [SIGNAL_PROPERTY_LIST_UPDATED
] = { .name
= "PropertyListUpdated", .arguments
= property_list_updated_args
, .n_arguments
= 1 }
95 static pa_dbus_interface_info module_interface_info
= {
96 .name
= PA_DBUSIFACE_MODULE_INTERFACE
,
97 .method_handlers
= method_handlers
,
98 .n_method_handlers
= METHOD_HANDLER_MAX
,
99 .property_handlers
= property_handlers
,
100 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
101 .get_all_properties_cb
= handle_get_all
,
103 .n_signals
= SIGNAL_MAX
106 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
107 pa_dbusiface_module
*m
= userdata
;
108 dbus_uint32_t idx
= 0;
114 idx
= m
->module
->index
;
116 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &idx
);
119 static void handle_get_name(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
120 pa_dbusiface_module
*m
= userdata
;
126 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &m
->module
->name
);
129 static void append_modargs_variant(DBusMessageIter
*iter
, pa_dbusiface_module
*m
) {
130 pa_modargs
*ma
= NULL
;
131 DBusMessageIter variant_iter
;
132 DBusMessageIter dict_iter
;
133 DBusMessageIter dict_entry_iter
;
135 const char *key
= NULL
;
136 const char *value
= NULL
;
141 pa_assert_se(ma
= pa_modargs_new(m
->module
->argument
, NULL
));
143 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a{ss}", &variant_iter
));
144 pa_assert_se(dbus_message_iter_open_container(&variant_iter
, DBUS_TYPE_ARRAY
, "{ss}", &dict_iter
));
146 for (state
= NULL
, key
= pa_modargs_iterate(ma
, &state
); key
; key
= pa_modargs_iterate(ma
, &state
)) {
147 pa_assert_se(value
= pa_modargs_get_value(ma
, key
, NULL
));
149 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
151 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &key
));
152 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &value
));
154 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
157 pa_assert_se(dbus_message_iter_close_container(&variant_iter
, &dict_iter
));
158 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
163 static void handle_get_arguments(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
164 pa_dbusiface_module
*m
= userdata
;
165 DBusMessage
*reply
= NULL
;
166 DBusMessageIter msg_iter
;
172 pa_assert_se(reply
= dbus_message_new_method_return(msg
));
173 dbus_message_iter_init_append(reply
, &msg_iter
);
174 append_modargs_variant(&msg_iter
, m
);
175 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
176 dbus_message_unref(reply
);
179 static void handle_get_usage_counter(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
180 pa_dbusiface_module
*m
= userdata
;
181 int real_counter_value
= -1;
182 dbus_uint32_t usage_counter
= 0;
188 if (!m
->module
->get_n_used
|| (real_counter_value
= m
->module
->get_n_used(m
->module
)) < 0) {
189 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
190 "Module %u (%s) doesn't have a usage counter.", m
->module
->index
, m
->module
->name
);
194 usage_counter
= real_counter_value
;
196 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &usage_counter
);
199 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
200 pa_dbusiface_module
*m
= userdata
;
206 pa_dbus_send_proplist_variant_reply(conn
, msg
, m
->proplist
);
209 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
210 pa_dbusiface_module
*m
= userdata
;
211 DBusMessage
*reply
= NULL
;
212 DBusMessageIter msg_iter
;
213 DBusMessageIter dict_iter
;
214 DBusMessageIter dict_entry_iter
;
215 dbus_uint32_t idx
= 0;
216 int real_counter_value
= -1;
217 dbus_uint32_t usage_counter
= 0;
223 idx
= m
->module
->index
;
224 if (m
->module
->get_n_used
&& (real_counter_value
= m
->module
->get_n_used(m
->module
)) >= 0)
225 usage_counter
= real_counter_value
;
227 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
229 dbus_message_iter_init_append(reply
, &msg_iter
);
230 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
232 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &idx
);
233 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_NAME
].property_name
, DBUS_TYPE_STRING
, &m
->module
->name
);
235 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
236 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &property_handlers
[PROPERTY_HANDLER_ARGUMENTS
].property_name
));
237 append_modargs_variant(&dict_entry_iter
, m
);
238 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
240 if (real_counter_value
>= 0)
241 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_ARGUMENTS
].property_name
, DBUS_TYPE_UINT32
, &usage_counter
);
243 pa_dbus_append_proplist_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_PROPERTY_LIST
].property_name
, m
->proplist
);
245 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
247 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
249 dbus_message_unref(reply
);
252 static void handle_unload(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
253 pa_dbusiface_module
*m
= userdata
;
259 if (m
->module
->core
->disallow_module_loading
) {
260 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_ACCESS_DENIED
, "The server is configured to disallow module unloading.");
264 pa_module_unload_request(m
->module
, FALSE
);
266 pa_dbus_send_empty_reply(conn
, msg
);
269 static void subscription_cb(pa_core
*core
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
270 pa_dbusiface_module
*m
= userdata
;
271 DBusMessage
*signal
= NULL
;
274 pa_assert((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_MODULE
);
277 /* We can't use idx != m->module->index, because the m->module pointer may
278 * be stale at this point. */
279 if (pa_idxset_get_by_index(core
->modules
, idx
) != m
->module
)
282 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
285 if (!pa_proplist_equal(m
->proplist
, m
->module
->proplist
)) {
286 DBusMessageIter msg_iter
;
288 pa_proplist_update(m
->proplist
, PA_UPDATE_SET
, m
->module
->proplist
);
290 pa_assert_se(signal
= dbus_message_new_signal(m
->path
,
291 PA_DBUSIFACE_MODULE_INTERFACE
,
292 signals
[SIGNAL_PROPERTY_LIST_UPDATED
].name
));
293 dbus_message_iter_init_append(signal
, &msg_iter
);
294 pa_dbus_append_proplist(&msg_iter
, m
->proplist
);
296 pa_dbus_protocol_send_signal(m
->dbus_protocol
, signal
);
297 dbus_message_unref(signal
);
302 pa_dbusiface_module
*pa_dbusiface_module_new(pa_module
*module
) {
303 pa_dbusiface_module
*m
;
307 m
= pa_xnew0(pa_dbusiface_module
, 1);
309 m
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, OBJECT_NAME
, module
->index
);
310 m
->proplist
= pa_proplist_copy(module
->proplist
);
311 m
->dbus_protocol
= pa_dbus_protocol_get(module
->core
);
312 m
->subscription
= pa_subscription_new(module
->core
, PA_SUBSCRIPTION_MASK_MODULE
, subscription_cb
, m
);
314 pa_assert_se(pa_dbus_protocol_add_interface(m
->dbus_protocol
, m
->path
, &module_interface_info
, m
) >= 0);
319 void pa_dbusiface_module_free(pa_dbusiface_module
*m
) {
322 pa_assert_se(pa_dbus_protocol_remove_interface(m
->dbus_protocol
, m
->path
, module_interface_info
.name
) >= 0);
324 pa_proplist_free(m
->proplist
);
325 pa_dbus_protocol_unref(m
->dbus_protocol
);
326 pa_subscription_free(m
->subscription
);
332 const char *pa_dbusiface_module_get_path(pa_dbusiface_module
*m
) {