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
{
42 pa_dbusiface_core
*core
;
45 pa_sink_input
*sink_input
;
46 pa_source_output
*source_output
;
48 enum stream_type type
;
57 pa_proplist
*proplist
;
60 pa_bool_t read_only_volume
;
62 pa_dbus_protocol
*dbus_protocol
;
63 pa_subscription
*subscription
;
64 pa_hook_slot
*send_event_slot
;
67 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
68 static void handle_get_driver(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
69 static void handle_get_owner_module(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
70 static void handle_get_client(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
71 static void handle_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
72 static void handle_get_sample_format(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
73 static void handle_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
74 static void handle_get_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
75 static void handle_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
76 static void handle_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
77 static void handle_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
78 static void handle_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
79 static void handle_get_buffer_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
80 static void handle_get_device_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
81 static void handle_get_resample_method(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
82 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
84 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
86 static void handle_move(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
87 static void handle_kill(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
89 enum property_handler_index
{
90 PROPERTY_HANDLER_INDEX
,
91 PROPERTY_HANDLER_DRIVER
,
92 PROPERTY_HANDLER_OWNER_MODULE
,
93 PROPERTY_HANDLER_CLIENT
,
94 PROPERTY_HANDLER_DEVICE
,
95 PROPERTY_HANDLER_SAMPLE_FORMAT
,
96 PROPERTY_HANDLER_SAMPLE_RATE
,
97 PROPERTY_HANDLER_CHANNELS
,
98 PROPERTY_HANDLER_VOLUME
,
99 PROPERTY_HANDLER_MUTE
,
100 PROPERTY_HANDLER_BUFFER_LATENCY
,
101 PROPERTY_HANDLER_DEVICE_LATENCY
,
102 PROPERTY_HANDLER_RESAMPLE_METHOD
,
103 PROPERTY_HANDLER_PROPERTY_LIST
,
107 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
108 [PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_get_index
, .set_cb
= NULL
},
109 [PROPERTY_HANDLER_DRIVER
] = { .property_name
= "Driver", .type
= "s", .get_cb
= handle_get_driver
, .set_cb
= NULL
},
110 [PROPERTY_HANDLER_OWNER_MODULE
] = { .property_name
= "OwnerModule", .type
= "o", .get_cb
= handle_get_owner_module
, .set_cb
= NULL
},
111 [PROPERTY_HANDLER_CLIENT
] = { .property_name
= "Client", .type
= "o", .get_cb
= handle_get_client
, .set_cb
= NULL
},
112 [PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "o", .get_cb
= handle_get_device
, .set_cb
= NULL
},
113 [PROPERTY_HANDLER_SAMPLE_FORMAT
] = { .property_name
= "SampleFormat", .type
= "u", .get_cb
= handle_get_sample_format
, .set_cb
= NULL
},
114 [PROPERTY_HANDLER_SAMPLE_RATE
] = { .property_name
= "SampleRate", .type
= "u", .get_cb
= handle_get_sample_rate
, .set_cb
= NULL
},
115 [PROPERTY_HANDLER_CHANNELS
] = { .property_name
= "Channels", .type
= "au", .get_cb
= handle_get_channels
, .set_cb
= NULL
},
116 [PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "au", .get_cb
= handle_get_volume
, .set_cb
= handle_set_volume
},
117 [PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_get_mute
, .set_cb
= handle_set_mute
},
118 [PROPERTY_HANDLER_BUFFER_LATENCY
] = { .property_name
= "BufferLatency", .type
= "t", .get_cb
= handle_get_buffer_latency
, .set_cb
= NULL
},
119 [PROPERTY_HANDLER_DEVICE_LATENCY
] = { .property_name
= "DeviceLatency", .type
= "t", .get_cb
= handle_get_device_latency
, .set_cb
= NULL
},
120 [PROPERTY_HANDLER_RESAMPLE_METHOD
] = { .property_name
= "ResampleMethod", .type
= "s", .get_cb
= handle_get_resample_method
, .set_cb
= NULL
},
121 [PROPERTY_HANDLER_PROPERTY_LIST
] = { .property_name
= "PropertyList", .type
= "a{say}", .get_cb
= handle_get_property_list
, .set_cb
= NULL
}
124 enum method_handler_index
{
130 static pa_dbus_arg_info move_args
[] = { { "device", "o", "in" } };
132 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
133 [METHOD_HANDLER_MOVE
] = {
134 .method_name
= "Move",
135 .arguments
= move_args
,
136 .n_arguments
= sizeof(move_args
) / sizeof(pa_dbus_arg_info
),
137 .receive_cb
= handle_move
},
138 [METHOD_HANDLER_KILL
] = {
139 .method_name
= "Kill",
142 .receive_cb
= handle_kill
}
146 SIGNAL_DEVICE_UPDATED
,
147 SIGNAL_SAMPLE_RATE_UPDATED
,
148 SIGNAL_VOLUME_UPDATED
,
150 SIGNAL_PROPERTY_LIST_UPDATED
,
155 static pa_dbus_arg_info device_updated_args
[] = { { "device", "o", NULL
} };
156 static pa_dbus_arg_info sample_rate_updated_args
[] = { { "sample_rate", "u", NULL
} };
157 static pa_dbus_arg_info volume_updated_args
[] = { { "volume", "au", NULL
} };
158 static pa_dbus_arg_info mute_updated_args
[] = { { "muted", "b", NULL
} };
159 static pa_dbus_arg_info property_list_updated_args
[] = { { "property_list", "a{say}", NULL
} };
160 static pa_dbus_arg_info stream_event_args
[] = { { "name", "s", NULL
}, { "property_list", "a{say}", NULL
} };
162 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
163 [SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= device_updated_args
, .n_arguments
= 1 },
164 [SIGNAL_SAMPLE_RATE_UPDATED
] = { .name
= "SampleRateUpdated", .arguments
= sample_rate_updated_args
, .n_arguments
= 1 },
165 [SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= volume_updated_args
, .n_arguments
= 1 },
166 [SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= mute_updated_args
, .n_arguments
= 1 },
167 [SIGNAL_PROPERTY_LIST_UPDATED
] = { .name
= "PropertyListUpdated", .arguments
= property_list_updated_args
, .n_arguments
= 1 },
168 [SIGNAL_STREAM_EVENT
] = { .name
= "StreamEvent", .arguments
= stream_event_args
, .n_arguments
= sizeof(stream_event_args
) / sizeof(pa_dbus_arg_info
) }
171 static pa_dbus_interface_info stream_interface_info
= {
172 .name
= PA_DBUSIFACE_STREAM_INTERFACE
,
173 .method_handlers
= method_handlers
,
174 .n_method_handlers
= METHOD_HANDLER_MAX
,
175 .property_handlers
= property_handlers
,
176 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
177 .get_all_properties_cb
= handle_get_all
,
179 .n_signals
= SIGNAL_MAX
182 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
183 pa_dbusiface_stream
*s
= userdata
;
190 idx
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->index
: s
->source_output
->index
;
192 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &idx
);
195 /* The returned string has to be freed with pa_xfree() by the caller. */
196 static char *stream_to_string(pa_dbusiface_stream
*s
) {
197 if (s
->type
== STREAM_TYPE_PLAYBACK
)
198 return pa_sprintf_malloc("Playback stream %u", (unsigned) s
->sink_input
->index
);
200 return pa_sprintf_malloc("Record stream %u", (unsigned) s
->source_output
->index
);
203 static void handle_get_driver(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
204 pa_dbusiface_stream
*s
= userdata
;
205 const char *driver
= NULL
;
211 driver
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->driver
: s
->source_output
->driver
;
214 char *str
= stream_to_string(s
);
216 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "%s doesn't have a driver.", str
);
222 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &driver
);
225 static void handle_get_owner_module(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
226 pa_dbusiface_stream
*s
= userdata
;
227 pa_module
*owner_module
= NULL
;
228 const char *object_path
= NULL
;
234 owner_module
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->module
: s
->source_output
->module
;
237 char *str
= stream_to_string(s
);
239 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "%s doesn't have an owner module.", str
);
245 object_path
= pa_dbusiface_core_get_module_path(s
->core
, owner_module
);
247 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
250 static void handle_get_client(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
251 pa_dbusiface_stream
*s
= userdata
;
252 pa_client
*client
= NULL
;
253 const char *object_path
= NULL
;
259 client
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->client
: s
->source_output
->client
;
262 char *str
= stream_to_string(s
);
264 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "%s isn't associated to any client.", str
);
270 object_path
= pa_dbusiface_core_get_client_path(s
->core
, client
);
272 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
275 static void handle_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
276 pa_dbusiface_stream
*s
= userdata
;
277 const char *device
= NULL
;
283 if (s
->type
== STREAM_TYPE_PLAYBACK
)
284 device
= pa_dbusiface_core_get_sink_path(s
->core
, s
->sink
);
286 device
= pa_dbusiface_core_get_source_path(s
->core
, s
->source
);
288 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &device
);
291 static void handle_get_sample_format(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
292 pa_dbusiface_stream
*s
= userdata
;
293 dbus_uint32_t sample_format
= 0;
299 sample_format
= (s
->type
== STREAM_TYPE_PLAYBACK
)
300 ? s
->sink_input
->sample_spec
.format
301 : s
->source_output
->sample_spec
.format
;
303 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &sample_format
);
306 static void handle_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
307 pa_dbusiface_stream
*s
= userdata
;
313 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &s
->sample_rate
);
316 static void handle_get_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
317 pa_dbusiface_stream
*s
= userdata
;
318 pa_channel_map
*channel_map
= NULL
;
319 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
326 channel_map
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? &s
->sink_input
->channel_map
: &s
->source_output
->channel_map
;
328 for (i
= 0; i
< channel_map
->channels
; ++i
)
329 channels
[i
] = channel_map
->map
[i
];
331 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
334 static void handle_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
335 pa_dbusiface_stream
*s
= userdata
;
336 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
343 if (!s
->has_volume
) {
344 char *str
= stream_to_string(s
);
346 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "%s doesn't have volume.", str
);
352 for (i
= 0; i
< s
->volume
.channels
; ++i
)
353 volume
[i
] = s
->volume
.values
[i
];
355 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, volume
, s
->volume
.channels
);
358 static void handle_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
359 pa_dbusiface_stream
*s
= userdata
;
360 DBusMessageIter array_iter
;
361 int stream_channels
= 0;
362 dbus_uint32_t
*volume
= NULL
;
363 int n_volume_entries
= 0;
372 if (!s
->has_volume
|| s
->read_only_volume
) {
373 char *str
= stream_to_string(s
);
376 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "%s doesn't have volume.", str
);
377 else if (s
->read_only_volume
)
378 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_ACCESS_DENIED
, "%s has read-only volume.", str
);
384 pa_cvolume_init(&new_vol
);
386 stream_channels
= s
->sink_input
->channel_map
.channels
;
388 new_vol
.channels
= stream_channels
;
390 dbus_message_iter_recurse(iter
, &array_iter
);
391 dbus_message_iter_get_fixed_array(&array_iter
, &volume
, &n_volume_entries
);
393 if (n_volume_entries
!= stream_channels
) {
394 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
,
395 "Expected %u volume entries, got %u.", stream_channels
, n_volume_entries
);
399 for (i
= 0; i
< n_volume_entries
; ++i
) {
400 if (!PA_VOLUME_IS_VALID(volume
[i
])) {
401 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", volume
[i
]);
404 new_vol
.values
[i
] = volume
[i
];
407 pa_sink_input_set_volume(s
->sink_input
, &new_vol
, TRUE
, TRUE
);
409 pa_dbus_send_empty_reply(conn
, msg
);
412 static void handle_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
413 pa_dbusiface_stream
*s
= userdata
;
419 if (s
->type
== STREAM_TYPE_RECORD
) {
420 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "Record streams don't have mute.");
424 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &s
->mute
);
427 static void handle_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
428 pa_dbusiface_stream
*s
= userdata
;
429 dbus_bool_t mute
= FALSE
;
436 dbus_message_iter_get_basic(iter
, &mute
);
438 if (s
->type
== STREAM_TYPE_RECORD
) {
439 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "Record streams don't have mute.");
443 pa_sink_input_set_mute(s
->sink_input
, mute
, TRUE
);
445 pa_dbus_send_empty_reply(conn
, msg
);
448 static void handle_get_buffer_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
449 pa_dbusiface_stream
*s
= userdata
;
450 dbus_uint64_t buffer_latency
= 0;
456 if (s
->type
== STREAM_TYPE_PLAYBACK
)
457 buffer_latency
= pa_sink_input_get_latency(s
->sink_input
, NULL
);
459 buffer_latency
= pa_source_output_get_latency(s
->source_output
, NULL
);
461 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &buffer_latency
);
464 static void handle_get_device_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
465 pa_dbusiface_stream
*s
= userdata
;
466 dbus_uint64_t device_latency
= 0;
472 if (s
->type
== STREAM_TYPE_PLAYBACK
)
473 pa_sink_input_get_latency(s
->sink_input
, &device_latency
);
475 pa_source_output_get_latency(s
->source_output
, &device_latency
);
477 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &device_latency
);
480 static void handle_get_resample_method(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
481 pa_dbusiface_stream
*s
= userdata
;
482 const char *resample_method
= NULL
;
488 if (s
->type
== STREAM_TYPE_PLAYBACK
)
489 resample_method
= pa_resample_method_to_string(s
->sink_input
->actual_resample_method
);
491 resample_method
= pa_resample_method_to_string(s
->source_output
->actual_resample_method
);
493 if (!resample_method
)
494 resample_method
= "";
496 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &resample_method
);
499 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
500 pa_dbusiface_stream
*s
= userdata
;
506 pa_dbus_send_proplist_variant_reply(conn
, msg
, s
->proplist
);
509 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
510 pa_dbusiface_stream
*s
= userdata
;
511 DBusMessage
*reply
= NULL
;
512 DBusMessageIter msg_iter
;
513 DBusMessageIter dict_iter
;
514 dbus_uint32_t idx
= 0;
515 const char *driver
= NULL
;
516 pa_module
*owner_module
= NULL
;
517 const char *owner_module_path
= NULL
;
518 pa_client
*client
= NULL
;
519 const char *client_path
= NULL
;
520 const char *device
= NULL
;
521 dbus_uint32_t sample_format
= 0;
522 pa_channel_map
*channel_map
= NULL
;
523 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
524 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
525 dbus_uint64_t buffer_latency
= 0;
526 dbus_uint64_t device_latency
= 0;
527 const char *resample_method
= NULL
;
535 for (i
= 0; i
< s
->volume
.channels
; ++i
)
536 volume
[i
] = s
->volume
.values
[i
];
539 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
540 idx
= s
->sink_input
->index
;
541 driver
= s
->sink_input
->driver
;
542 owner_module
= s
->sink_input
->module
;
543 client
= s
->sink_input
->client
;
544 device
= pa_dbusiface_core_get_sink_path(s
->core
, s
->sink
);
545 sample_format
= s
->sink_input
->sample_spec
.format
;
546 channel_map
= &s
->sink_input
->channel_map
;
547 buffer_latency
= pa_sink_input_get_latency(s
->sink_input
, &device_latency
);
548 resample_method
= pa_resample_method_to_string(s
->sink_input
->actual_resample_method
);
550 idx
= s
->source_output
->index
;
551 driver
= s
->source_output
->driver
;
552 owner_module
= s
->source_output
->module
;
553 client
= s
->source_output
->client
;
554 device
= pa_dbusiface_core_get_source_path(s
->core
, s
->source
);
555 sample_format
= s
->source_output
->sample_spec
.format
;
556 channel_map
= &s
->source_output
->channel_map
;
557 buffer_latency
= pa_source_output_get_latency(s
->source_output
, &device_latency
);
558 resample_method
= pa_resample_method_to_string(s
->source_output
->actual_resample_method
);
561 owner_module_path
= pa_dbusiface_core_get_module_path(s
->core
, owner_module
);
563 client_path
= pa_dbusiface_core_get_client_path(s
->core
, client
);
564 for (i
= 0; i
< channel_map
->channels
; ++i
)
565 channels
[i
] = channel_map
->map
[i
];
566 if (!resample_method
)
567 resample_method
= "";
569 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
571 dbus_message_iter_init_append(reply
, &msg_iter
);
572 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
574 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &idx
);
577 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DRIVER
].property_name
, DBUS_TYPE_STRING
, &driver
);
580 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_OWNER_MODULE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &owner_module_path
);
583 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CLIENT
].property_name
, DBUS_TYPE_OBJECT_PATH
, &client_path
);
585 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &device
);
586 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_FORMAT
].property_name
, DBUS_TYPE_UINT32
, &sample_format
);
587 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_RATE
].property_name
, DBUS_TYPE_UINT32
, &s
->sample_rate
);
588 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CHANNELS
].property_name
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
591 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_VOLUME
].property_name
, DBUS_TYPE_UINT32
, volume
, s
->volume
.channels
);
592 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &s
->mute
);
595 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_BUFFER_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &buffer_latency
);
596 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DEVICE_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &device_latency
);
597 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_RESAMPLE_METHOD
].property_name
, DBUS_TYPE_STRING
, &resample_method
);
598 pa_dbus_append_proplist_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_PROPERTY_LIST
].property_name
, s
->proplist
);
600 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
601 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
602 dbus_message_unref(reply
);
605 static void handle_move(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
606 pa_dbusiface_stream
*s
= userdata
;
607 const char *device
= NULL
;
613 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
615 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
616 pa_sink
*sink
= pa_dbusiface_core_get_sink(s
->core
, device
);
619 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "%s: No such sink.", device
);
623 if (pa_sink_input_move_to(s
->sink_input
, sink
, TRUE
) < 0) {
624 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
625 "Moving playback stream %u to sink %s failed.", s
->sink_input
->index
, sink
->name
);
629 pa_source
*source
= pa_dbusiface_core_get_source(s
->core
, device
);
632 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "%s: No such source.", device
);
636 if (pa_source_output_move_to(s
->source_output
, source
, TRUE
) < 0) {
637 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
638 "Moving record stream %u to source %s failed.", s
->source_output
->index
, source
->name
);
643 pa_dbus_send_empty_reply(conn
, msg
);
646 static void handle_kill(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
647 pa_dbusiface_stream
*s
= userdata
;
653 if (s
->type
== STREAM_TYPE_PLAYBACK
)
654 pa_sink_input_kill(s
->sink_input
);
656 pa_source_output_kill(s
->source_output
);
658 pa_dbus_send_empty_reply(conn
, msg
);
661 static void subscription_cb(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
662 pa_dbusiface_stream
*s
= userdata
;
663 DBusMessage
*signal_msg
= NULL
;
664 const char *new_device_path
= NULL
;
665 uint32_t new_sample_rate
= 0;
666 pa_proplist
*new_proplist
= NULL
;
672 if ((s
->type
== STREAM_TYPE_PLAYBACK
&& idx
!= s
->sink_input
->index
)
673 || (s
->type
== STREAM_TYPE_RECORD
&& idx
!= s
->source_output
->index
))
676 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
679 pa_assert(((s
->type
== STREAM_TYPE_PLAYBACK
)
680 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
))
681 || ((s
->type
== STREAM_TYPE_RECORD
)
682 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
)));
684 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
685 pa_sink
*new_sink
= s
->sink_input
->sink
;
687 if (s
->sink
!= new_sink
) {
688 pa_sink_unref(s
->sink
);
689 s
->sink
= pa_sink_ref(new_sink
);
691 new_device_path
= pa_dbusiface_core_get_sink_path(s
->core
, new_sink
);
693 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
694 PA_DBUSIFACE_STREAM_INTERFACE
,
695 signals
[SIGNAL_DEVICE_UPDATED
].name
));
696 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &new_device_path
, DBUS_TYPE_INVALID
));
698 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
699 dbus_message_unref(signal_msg
);
703 pa_source
*new_source
= s
->source_output
->source
;
705 if (s
->source
!= new_source
) {
706 pa_source_unref(s
->source
);
707 s
->source
= pa_source_ref(new_source
);
709 new_device_path
= pa_dbusiface_core_get_source_path(s
->core
, new_source
);
711 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
712 PA_DBUSIFACE_STREAM_INTERFACE
,
713 signals
[SIGNAL_DEVICE_UPDATED
].name
));
714 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &new_device_path
, DBUS_TYPE_INVALID
));
716 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
717 dbus_message_unref(signal_msg
);
722 new_sample_rate
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->sample_spec
.rate
: s
->source_output
->sample_spec
.rate
;
724 if (s
->sample_rate
!= new_sample_rate
) {
725 s
->sample_rate
= new_sample_rate
;
727 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
728 PA_DBUSIFACE_STREAM_INTERFACE
,
729 signals
[SIGNAL_SAMPLE_RATE_UPDATED
].name
));
730 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_UINT32
, &s
->sample_rate
, DBUS_TYPE_INVALID
));
732 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
733 dbus_message_unref(signal_msg
);
737 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
738 pa_bool_t new_mute
= FALSE
;
741 pa_cvolume new_volume
;
743 pa_sink_input_get_volume(s
->sink_input
, &new_volume
, TRUE
);
745 if (!pa_cvolume_equal(&s
->volume
, &new_volume
)) {
746 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
747 dbus_uint32_t
*volume_ptr
= volume
;
749 s
->volume
= new_volume
;
751 for (i
= 0; i
< s
->volume
.channels
; ++i
)
752 volume
[i
] = s
->volume
.values
[i
];
754 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
755 PA_DBUSIFACE_STREAM_INTERFACE
,
756 signals
[SIGNAL_VOLUME_UPDATED
].name
));
757 pa_assert_se(dbus_message_append_args(signal_msg
,
758 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &volume_ptr
, s
->volume
.channels
,
761 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
762 dbus_message_unref(signal_msg
);
767 new_mute
= pa_sink_input_get_mute(s
->sink_input
);
769 if (s
->mute
!= new_mute
) {
772 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
773 PA_DBUSIFACE_STREAM_INTERFACE
,
774 signals
[SIGNAL_MUTE_UPDATED
].name
));
775 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &s
->mute
, DBUS_TYPE_INVALID
));
777 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
778 dbus_message_unref(signal_msg
);
783 new_proplist
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->proplist
: s
->source_output
->proplist
;
785 if (!pa_proplist_equal(s
->proplist
, new_proplist
)) {
786 DBusMessageIter msg_iter
;
788 pa_proplist_update(s
->proplist
, PA_UPDATE_SET
, new_proplist
);
790 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
791 PA_DBUSIFACE_STREAM_INTERFACE
,
792 signals
[SIGNAL_PROPERTY_LIST_UPDATED
].name
));
793 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
794 pa_dbus_append_proplist(&msg_iter
, s
->proplist
);
796 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
797 dbus_message_unref(signal_msg
);
802 static pa_hook_result_t
send_event_cb(void *hook_data
, void *call_data
, void *slot_data
) {
803 pa_dbusiface_stream
*s
= slot_data
;
804 DBusMessage
*signal_msg
= NULL
;
805 DBusMessageIter msg_iter
;
806 const char *name
= NULL
;
807 pa_proplist
*property_list
= NULL
;
809 pa_assert(call_data
);
812 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
813 pa_sink_input_send_event_hook_data
*data
= call_data
;
815 if (data
->sink_input
!= s
->sink_input
)
819 property_list
= data
->data
;
821 pa_source_output_send_event_hook_data
*data
= call_data
;
823 if (data
->source_output
!= s
->source_output
)
827 property_list
= data
->data
;
830 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
831 PA_DBUSIFACE_STREAM_INTERFACE
,
832 signals
[SIGNAL_STREAM_EVENT
].name
));
833 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
834 pa_assert_se(dbus_message_iter_append_basic(&msg_iter
, DBUS_TYPE_STRING
, &name
));
835 pa_dbus_append_proplist(&msg_iter
, property_list
);
837 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
838 dbus_message_unref(signal_msg
);
843 pa_dbusiface_stream
*pa_dbusiface_stream_new_playback(pa_dbusiface_core
*core
, pa_sink_input
*sink_input
) {
844 pa_dbusiface_stream
*s
;
847 pa_assert(sink_input
);
849 s
= pa_xnew(pa_dbusiface_stream
, 1);
851 s
->sink_input
= pa_sink_input_ref(sink_input
);
852 s
->type
= STREAM_TYPE_PLAYBACK
;
853 s
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, PLAYBACK_OBJECT_NAME
, sink_input
->index
);
854 s
->sink
= pa_sink_ref(sink_input
->sink
);
855 s
->sample_rate
= sink_input
->sample_spec
.rate
;
856 s
->has_volume
= pa_sink_input_is_volume_readable(sink_input
);
857 s
->read_only_volume
= s
->has_volume
? !pa_sink_input_is_volume_writable(sink_input
) : FALSE
;
860 pa_sink_input_get_volume(sink_input
, &s
->volume
, TRUE
);
862 pa_cvolume_init(&s
->volume
);
864 s
->mute
= pa_sink_input_get_mute(sink_input
);
865 s
->proplist
= pa_proplist_copy(sink_input
->proplist
);
866 s
->dbus_protocol
= pa_dbus_protocol_get(sink_input
->core
);
867 s
->subscription
= pa_subscription_new(sink_input
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
, subscription_cb
, s
);
868 s
->send_event_slot
= pa_hook_connect(&sink_input
->core
->hooks
[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT
],
873 pa_assert_se(pa_dbus_protocol_add_interface(s
->dbus_protocol
, s
->path
, &stream_interface_info
, s
) >= 0);
878 pa_dbusiface_stream
*pa_dbusiface_stream_new_record(pa_dbusiface_core
*core
, pa_source_output
*source_output
) {
879 pa_dbusiface_stream
*s
;
882 pa_assert(source_output
);
884 s
= pa_xnew(pa_dbusiface_stream
, 1);
886 s
->source_output
= pa_source_output_ref(source_output
);
887 s
->type
= STREAM_TYPE_RECORD
;
888 s
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, RECORD_OBJECT_NAME
, source_output
->index
);
889 s
->source
= pa_source_ref(source_output
->source
);
890 s
->sample_rate
= source_output
->sample_spec
.rate
;
891 pa_cvolume_init(&s
->volume
);
893 s
->proplist
= pa_proplist_copy(source_output
->proplist
);
894 s
->has_volume
= FALSE
;
895 s
->read_only_volume
= FALSE
;
896 s
->dbus_protocol
= pa_dbus_protocol_get(source_output
->core
);
897 s
->subscription
= pa_subscription_new(source_output
->core
, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscription_cb
, s
);
898 s
->send_event_slot
= pa_hook_connect(&source_output
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT
],
903 pa_assert_se(pa_dbus_protocol_add_interface(s
->dbus_protocol
, s
->path
, &stream_interface_info
, s
) >= 0);
908 void pa_dbusiface_stream_free(pa_dbusiface_stream
*s
) {
911 pa_assert_se(pa_dbus_protocol_remove_interface(s
->dbus_protocol
, s
->path
, stream_interface_info
.name
) >= 0);
913 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
914 pa_sink_input_unref(s
->sink_input
);
915 pa_sink_unref(s
->sink
);
917 pa_source_output_unref(s
->source_output
);
918 pa_source_unref(s
->source
);
921 pa_proplist_free(s
->proplist
);
922 pa_dbus_protocol_unref(s
->dbus_protocol
);
923 pa_subscription_free(s
->subscription
);
924 pa_hook_slot_free(s
->send_event_slot
);
930 const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream
*s
) {