2 This file is part of PulseAudio.
4 Copyright 2009 Tanu Kaskinen
5 Copyright 2009 Vincent Filali-Ansary <filali.v@azurdigitalnetworks.net>
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
27 #include <pulsecore/core-util.h>
28 #include <pulsecore/dbus-util.h>
29 #include <pulsecore/protocol-dbus.h>
31 #include "iface-stream.h"
33 #define PLAYBACK_OBJECT_NAME "playback_stream"
34 #define RECORD_OBJECT_NAME "record_stream"
41 struct pa_dbusiface_stream {
43 pa_sink_input *sink_input;
44 pa_source_output *source_output;
46 enum stream_type type;
50 pa_proplist *proplist;
52 pa_dbus_protocol *dbus_protocol;
53 pa_subscription *subscription;
56 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 /*static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
59 static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
61 static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
62 static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
63 static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);*/
64 static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
65 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
66 static void handle_get_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata);
67 static void handle_set_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 /*static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
69 static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata);*/
71 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 /*static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);*/
78 enum property_handler_index {
79 PROPERTY_HANDLER_INDEX,
80 /* PROPERTY_HANDLER_DRIVER,
81 PROPERTY_HANDLER_OWNER_MODULE,
82 PROPERTY_HANDLER_CLIENT,
83 PROPERTY_HANDLER_DEVICE,
84 PROPERTY_HANDLER_SAMPLE_FORMAT,
85 PROPERTY_HANDLER_SAMPLE_RATE,
86 PROPERTY_HANDLER_CHANNELS,*/
87 PROPERTY_HANDLER_VOLUME,
88 PROPERTY_HANDLER_IS_MUTED,
89 /* PROPERTY_HANDLER_BUFFER_LATENCY,
90 PROPERTY_HANDLER_DEVICE_LATENCY,
91 PROPERTY_HANDLER_RESAMPLE_METHOD,*/
92 PROPERTY_HANDLER_PROPERTY_LIST,
96 static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
97 [PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL },
98 /* [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL },
99 [PROPERTY_HANDLER_OWNER_MODULE] = { .property_name = "OwnerModule", .type = "o", .get_cb = handle_get_owner_module, .set_cb = NULL },
100 [PROPERTY_HANDLER_CLIENT] = { .property_name = "Client", .type = "o", .get_cb = handle_get_client, .set_cb = NULL },
101 [PROPERTY_HANDLER_DEVICE] = { .property_name = "Device", .type = "o", .get_cb = handle_get_device, .set_cb = NULL },
102 [PROPERTY_HANDLER_SAMPLE_FORMAT] = { .property_name = "SampleFormat", .type = "u", .get_cb = handle_get_sample_format, .set_cb = NULL },
103 [PROPERTY_HANDLER_SAMPLE_RATE] = { .property_name = "SampleRate", .type = "u", .get_cb = handle_get_sample_rate, .set_cb = NULL },
104 [PROPERTY_HANDLER_CHANNELS] = { .property_name = "Channels", .type = "au", .get_cb = handle_get_channels, .set_cb = NULL },*/
105 [PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "au", .get_cb = handle_get_volume, .set_cb = handle_set_volume },
106 [PROPERTY_HANDLER_IS_MUTED] = { .property_name = "IsMuted", .type = "b", .get_cb = handle_get_is_muted, .set_cb = handle_set_is_muted },
107 /* [PROPERTY_HANDLER_BUFFER_LATENCY] = { .property_name = "BufferLatency", .type = "t", .get_cb = handle_get_buffer_latency, .set_cb = NULL },
108 [PROPERTY_HANDLER_DEVICE_LATENCY] = { .property_name = "DeviceLatency", .type = "t", .get_cb = handle_get_device_latency, .set_cb = NULL },
109 [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s", .get_cb = handle_get_resample_method, .set_cb = NULL },*/
110 [PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL }
113 /*enum method_handler_index {
119 static pa_dbus_arg_info move_args[] = { { "device", "o", "in" } };
121 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
122 [METHOD_HANDLER_MOVE] = {
123 .method_name = "Move",
124 .arguments = move_args,
125 .n_arguments = sizeof(move_args) / sizeof(pa_dbus_arg_info),
126 .receive_cb = handle_move },
127 [METHOD_HANDLER_KILL] = {
128 .method_name = "Kill",
131 .receive_cb = handle_kill }
135 /* SIGNAL_DEVICE_UPDATED,
136 SIGNAL_SAMPLE_RATE_UPDATED,*/
137 SIGNAL_VOLUME_UPDATED,
139 SIGNAL_PROPERTY_LIST_UPDATED,
140 /* SIGNAL_STREAM_EVENT,*/
144 /*static pa_dbus_arg_info device_updated_args[] = { { "device", "o", NULL } };
145 static pa_dbus_arg_info sample_rate_updated_args[] = { { "sample_rate", "u", NULL } };*/
146 static pa_dbus_arg_info volume_updated_args[] = { { "volume", "au", NULL } };
147 static pa_dbus_arg_info mute_updated_args[] = { { "muted", "b", NULL } };
148 static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
149 /*static pa_dbus_arg_info stream_event_args[] = { { "name", "s", NULL }, { "property_list", "a{say}", NULL } };*/
151 static pa_dbus_signal_info signals[SIGNAL_MAX] = {
152 /* [SIGNAL_DEVICE_UPDATED] = { .name = "DeviceUpdated", .arguments = device_updated_args, .n_arguments = 1 },
153 [SIGNAL_SAMPLE_RATE_UPDATED] = { .name = "SampleRateUpdated", .arguments = sample_rate_updated_args, .n_arguments = 1 },*/
154 [SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = volume_updated_args, .n_arguments = 1 },
155 [SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = mute_updated_args, .n_arguments = 1 },
156 [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }/*,
157 [SIGNAL_STREAM_EVENT] = { .name = "StreamEvent", .arguments = stream_event_args, .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) }*/
160 static pa_dbus_interface_info stream_interface_info = {
161 .name = PA_DBUSIFACE_STREAM_INTERFACE,
162 .method_handlers = /*method_handlers*/ NULL,
163 .n_method_handlers = /*METHOD_HANDLER_MAX*/ 0,
164 .property_handlers = property_handlers,
165 .n_property_handlers = PROPERTY_HANDLER_MAX,
166 .get_all_properties_cb = handle_get_all,
168 .n_signals = SIGNAL_MAX
171 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
172 pa_dbusiface_stream *s = userdata;
179 idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index;
181 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
184 static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
185 pa_dbusiface_stream *s = userdata;
186 dbus_uint32_t volume[PA_CHANNELS_MAX];
193 if (s->type == STREAM_TYPE_RECORD) {
194 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
198 for (i = 0; i < s->volume.channels; ++i)
199 volume[i] = s->volume.values[i];
201 pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, s->volume.channels);
204 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
205 pa_dbusiface_stream *s = userdata;
206 unsigned stream_channels = 0;
207 dbus_uint32_t *volume = NULL;
208 unsigned n_volume_entries = 0;
216 if (s->type == STREAM_TYPE_RECORD) {
217 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
221 pa_cvolume_init(&new_vol);
223 stream_channels = s->sink_input->channel_map.channels;
225 new_vol.channels = stream_channels;
227 if (pa_dbus_get_fixed_array_set_property_arg(conn, msg, DBUS_TYPE_UINT32, &volume, &n_volume_entries) < 0)
230 if (n_volume_entries != stream_channels) {
231 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
235 for (i = 0; i < n_volume_entries; ++i) {
236 if (volume[i] > PA_VOLUME_MAX) {
237 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too large volume value: %u", volume[i]);
240 new_vol.values[i] = volume[i];
243 pa_sink_input_set_volume(s->sink_input, &new_vol, TRUE, TRUE);
245 pa_dbus_send_empty_reply(conn, msg);
248 static void handle_get_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata) {
249 pa_dbusiface_stream *s = userdata;
255 if (s->type == STREAM_TYPE_RECORD) {
256 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
260 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &s->is_muted);
263 static void handle_set_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata) {
264 pa_dbusiface_stream *s = userdata;
265 dbus_bool_t is_muted = FALSE;
271 if (pa_dbus_get_basic_set_property_arg(conn, msg, DBUS_TYPE_BOOLEAN, &is_muted) < 0)
274 if (s->type == STREAM_TYPE_RECORD) {
275 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
279 pa_sink_input_set_mute(s->sink_input, is_muted, TRUE);
281 pa_dbus_send_empty_reply(conn, msg);
284 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
285 pa_dbusiface_stream *s = userdata;
291 pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
294 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
295 pa_dbusiface_stream *s = userdata;
296 DBusMessage *reply = NULL;
297 DBusMessageIter msg_iter;
298 DBusMessageIter dict_iter;
300 dbus_uint32_t volume[PA_CHANNELS_MAX];
307 idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index;
308 if (s->type == STREAM_TYPE_PLAYBACK) {
309 for (i = 0; i < s->volume.channels; ++i)
310 volume[i] = s->volume.values[i];
313 pa_assert_se((reply = dbus_message_new_method_return(msg)));
315 dbus_message_iter_init_append(reply, &msg_iter);
316 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
318 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
320 if (s->type == STREAM_TYPE_PLAYBACK) {
321 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
322 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_IS_MUTED].property_name, DBUS_TYPE_BOOLEAN, &s->is_muted);
325 pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
327 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
328 pa_assert_se(dbus_connection_send(conn, reply, NULL));
329 dbus_message_unref(reply);
332 static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
333 pa_dbusiface_stream *s = userdata;
338 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) {
339 DBusMessage *signal = NULL;
340 pa_proplist *new_proplist = NULL;
343 pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
344 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
345 || ((s->type == STREAM_TYPE_RECORD)
346 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
348 if (s->type == STREAM_TYPE_PLAYBACK) {
349 pa_cvolume new_volume;
350 pa_bool_t new_muted = FALSE;
352 pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
354 if (!pa_cvolume_equal(&s->volume, &new_volume)) {
355 dbus_uint32_t volume[PA_CHANNELS_MAX];
356 dbus_uint32_t *volume_ptr = volume;
358 s->volume = new_volume;
360 for (i = 0; i < s->volume.channels; ++i)
361 volume[i] = s->volume.values[i];
363 pa_assert_se(signal = dbus_message_new_signal(s->path,
364 PA_DBUSIFACE_STREAM_INTERFACE,
365 signals[SIGNAL_VOLUME_UPDATED].name));
366 pa_assert_se(dbus_message_append_args(signal,
367 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
370 pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
371 dbus_message_unref(signal);
375 new_muted = pa_sink_input_get_mute(s->sink_input);
377 if (s->is_muted != new_muted) {
378 s->is_muted = new_muted;
380 pa_assert_se(signal = dbus_message_new_signal(s->path,
381 PA_DBUSIFACE_STREAM_INTERFACE,
382 signals[SIGNAL_MUTE_UPDATED].name));
383 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &s->is_muted, DBUS_TYPE_INVALID));
385 pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
386 dbus_message_unref(signal);
391 new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
393 if (!pa_proplist_equal(s->proplist, new_proplist)) {
394 DBusMessageIter msg_iter;
396 pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
398 pa_assert_se(signal = dbus_message_new_signal(s->path,
399 PA_DBUSIFACE_STREAM_INTERFACE,
400 signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
401 dbus_message_iter_init_append(signal, &msg_iter);
402 pa_dbus_append_proplist(&msg_iter, s->proplist);
404 pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
405 dbus_message_unref(signal);
411 pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
412 pa_dbusiface_stream *s;
415 pa_assert(sink_input);
417 s = pa_xnew(pa_dbusiface_stream, 1);
418 s->sink_input = pa_sink_input_ref(sink_input);
419 s->type = STREAM_TYPE_PLAYBACK;
420 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
421 pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
422 s->is_muted = pa_sink_input_get_mute(sink_input);
423 s->proplist = pa_proplist_copy(sink_input->proplist);
424 s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
425 s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
427 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
432 pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) {
433 pa_dbusiface_stream *s;
436 pa_assert(source_output);
438 s = pa_xnew(pa_dbusiface_stream, 1);
439 s->source_output = pa_source_output_ref(source_output);
440 s->type = STREAM_TYPE_RECORD;
441 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
442 pa_cvolume_init(&s->volume);
444 s->proplist = pa_proplist_copy(source_output->proplist);
445 s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
446 s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
448 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
453 void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
456 pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0);
458 if (s->type == STREAM_TYPE_PLAYBACK)
459 pa_sink_input_unref(s->sink_input);
461 pa_source_output_unref(s->source_output);
463 pa_proplist_free(s->proplist);
464 pa_dbus_protocol_unref(s->dbus_protocol);
465 pa_subscription_free(s->subscription);
471 const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s) {