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
;
59 pa_dbus_protocol
*dbus_protocol
;
60 pa_subscription
*subscription
;
61 pa_hook_slot
*send_event_slot
;
64 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
65 static void handle_get_driver(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
66 static void handle_get_owner_module(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
67 static void handle_get_client(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
68 static void handle_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
69 static void handle_get_sample_format(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
70 static void handle_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
71 static void handle_get_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
72 static void handle_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
73 static void handle_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
74 static void handle_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
75 static void handle_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
);
76 static void handle_get_buffer_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
77 static void handle_get_device_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
78 static void handle_get_resample_method(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
79 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
81 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
83 static void handle_move(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
84 static void handle_kill(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
);
86 enum property_handler_index
{
87 PROPERTY_HANDLER_INDEX
,
88 PROPERTY_HANDLER_DRIVER
,
89 PROPERTY_HANDLER_OWNER_MODULE
,
90 PROPERTY_HANDLER_CLIENT
,
91 PROPERTY_HANDLER_DEVICE
,
92 PROPERTY_HANDLER_SAMPLE_FORMAT
,
93 PROPERTY_HANDLER_SAMPLE_RATE
,
94 PROPERTY_HANDLER_CHANNELS
,
95 PROPERTY_HANDLER_VOLUME
,
96 PROPERTY_HANDLER_MUTE
,
97 PROPERTY_HANDLER_BUFFER_LATENCY
,
98 PROPERTY_HANDLER_DEVICE_LATENCY
,
99 PROPERTY_HANDLER_RESAMPLE_METHOD
,
100 PROPERTY_HANDLER_PROPERTY_LIST
,
104 static pa_dbus_property_handler property_handlers
[PROPERTY_HANDLER_MAX
] = {
105 [PROPERTY_HANDLER_INDEX
] = { .property_name
= "Index", .type
= "u", .get_cb
= handle_get_index
, .set_cb
= NULL
},
106 [PROPERTY_HANDLER_DRIVER
] = { .property_name
= "Driver", .type
= "s", .get_cb
= handle_get_driver
, .set_cb
= NULL
},
107 [PROPERTY_HANDLER_OWNER_MODULE
] = { .property_name
= "OwnerModule", .type
= "o", .get_cb
= handle_get_owner_module
, .set_cb
= NULL
},
108 [PROPERTY_HANDLER_CLIENT
] = { .property_name
= "Client", .type
= "o", .get_cb
= handle_get_client
, .set_cb
= NULL
},
109 [PROPERTY_HANDLER_DEVICE
] = { .property_name
= "Device", .type
= "o", .get_cb
= handle_get_device
, .set_cb
= NULL
},
110 [PROPERTY_HANDLER_SAMPLE_FORMAT
] = { .property_name
= "SampleFormat", .type
= "u", .get_cb
= handle_get_sample_format
, .set_cb
= NULL
},
111 [PROPERTY_HANDLER_SAMPLE_RATE
] = { .property_name
= "SampleRate", .type
= "u", .get_cb
= handle_get_sample_rate
, .set_cb
= NULL
},
112 [PROPERTY_HANDLER_CHANNELS
] = { .property_name
= "Channels", .type
= "au", .get_cb
= handle_get_channels
, .set_cb
= NULL
},
113 [PROPERTY_HANDLER_VOLUME
] = { .property_name
= "Volume", .type
= "au", .get_cb
= handle_get_volume
, .set_cb
= handle_set_volume
},
114 [PROPERTY_HANDLER_MUTE
] = { .property_name
= "Mute", .type
= "b", .get_cb
= handle_get_mute
, .set_cb
= handle_set_mute
},
115 [PROPERTY_HANDLER_BUFFER_LATENCY
] = { .property_name
= "BufferLatency", .type
= "t", .get_cb
= handle_get_buffer_latency
, .set_cb
= NULL
},
116 [PROPERTY_HANDLER_DEVICE_LATENCY
] = { .property_name
= "DeviceLatency", .type
= "t", .get_cb
= handle_get_device_latency
, .set_cb
= NULL
},
117 [PROPERTY_HANDLER_RESAMPLE_METHOD
] = { .property_name
= "ResampleMethod", .type
= "s", .get_cb
= handle_get_resample_method
, .set_cb
= NULL
},
118 [PROPERTY_HANDLER_PROPERTY_LIST
] = { .property_name
= "PropertyList", .type
= "a{say}", .get_cb
= handle_get_property_list
, .set_cb
= NULL
}
121 enum method_handler_index
{
127 static pa_dbus_arg_info move_args
[] = { { "device", "o", "in" } };
129 static pa_dbus_method_handler method_handlers
[METHOD_HANDLER_MAX
] = {
130 [METHOD_HANDLER_MOVE
] = {
131 .method_name
= "Move",
132 .arguments
= move_args
,
133 .n_arguments
= sizeof(move_args
) / sizeof(pa_dbus_arg_info
),
134 .receive_cb
= handle_move
},
135 [METHOD_HANDLER_KILL
] = {
136 .method_name
= "Kill",
139 .receive_cb
= handle_kill
}
143 SIGNAL_DEVICE_UPDATED
,
144 SIGNAL_SAMPLE_RATE_UPDATED
,
145 SIGNAL_VOLUME_UPDATED
,
147 SIGNAL_PROPERTY_LIST_UPDATED
,
152 static pa_dbus_arg_info device_updated_args
[] = { { "device", "o", NULL
} };
153 static pa_dbus_arg_info sample_rate_updated_args
[] = { { "sample_rate", "u", NULL
} };
154 static pa_dbus_arg_info volume_updated_args
[] = { { "volume", "au", NULL
} };
155 static pa_dbus_arg_info mute_updated_args
[] = { { "muted", "b", NULL
} };
156 static pa_dbus_arg_info property_list_updated_args
[] = { { "property_list", "a{say}", NULL
} };
157 static pa_dbus_arg_info stream_event_args
[] = { { "name", "s", NULL
}, { "property_list", "a{say}", NULL
} };
159 static pa_dbus_signal_info signals
[SIGNAL_MAX
] = {
160 [SIGNAL_DEVICE_UPDATED
] = { .name
= "DeviceUpdated", .arguments
= device_updated_args
, .n_arguments
= 1 },
161 [SIGNAL_SAMPLE_RATE_UPDATED
] = { .name
= "SampleRateUpdated", .arguments
= sample_rate_updated_args
, .n_arguments
= 1 },
162 [SIGNAL_VOLUME_UPDATED
] = { .name
= "VolumeUpdated", .arguments
= volume_updated_args
, .n_arguments
= 1 },
163 [SIGNAL_MUTE_UPDATED
] = { .name
= "MuteUpdated", .arguments
= mute_updated_args
, .n_arguments
= 1 },
164 [SIGNAL_PROPERTY_LIST_UPDATED
] = { .name
= "PropertyListUpdated", .arguments
= property_list_updated_args
, .n_arguments
= 1 },
165 [SIGNAL_STREAM_EVENT
] = { .name
= "StreamEvent", .arguments
= stream_event_args
, .n_arguments
= sizeof(stream_event_args
) / sizeof(pa_dbus_arg_info
) }
168 static pa_dbus_interface_info stream_interface_info
= {
169 .name
= PA_DBUSIFACE_STREAM_INTERFACE
,
170 .method_handlers
= method_handlers
,
171 .n_method_handlers
= METHOD_HANDLER_MAX
,
172 .property_handlers
= property_handlers
,
173 .n_property_handlers
= PROPERTY_HANDLER_MAX
,
174 .get_all_properties_cb
= handle_get_all
,
176 .n_signals
= SIGNAL_MAX
179 static void handle_get_index(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
180 pa_dbusiface_stream
*s
= userdata
;
187 idx
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->index
: s
->source_output
->index
;
189 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &idx
);
192 static void handle_get_driver(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
193 pa_dbusiface_stream
*s
= userdata
;
194 const char *driver
= NULL
;
200 driver
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->driver
: s
->source_output
->driver
;
203 if (s
->type
== STREAM_TYPE_PLAYBACK
)
204 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
205 "Playback stream %u doesn't have a driver.", s
->sink_input
->index
);
207 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
208 "Record stream %u doesn't have a driver.", s
->source_output
->index
);
212 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &driver
);
215 static void handle_get_owner_module(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
216 pa_dbusiface_stream
*s
= userdata
;
217 pa_module
*owner_module
= NULL
;
218 const char *object_path
= NULL
;
224 owner_module
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->module
: s
->source_output
->module
;
227 if (s
->type
== STREAM_TYPE_PLAYBACK
)
228 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
229 "Playback stream %u doesn't have an owner module.", s
->sink_input
->index
);
231 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
232 "Record stream %u doesn't have an owner module.", s
->source_output
->index
);
236 object_path
= pa_dbusiface_core_get_module_path(s
->core
, owner_module
);
238 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
241 static void handle_get_client(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
242 pa_dbusiface_stream
*s
= userdata
;
243 pa_client
*client
= NULL
;
244 const char *object_path
= NULL
;
250 client
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->client
: s
->source_output
->client
;
253 if (s
->type
== STREAM_TYPE_PLAYBACK
)
254 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
255 "Playback stream %u isn't associated to any client.", s
->sink_input
->index
);
257 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
,
258 "Record stream %u isn't associated to any client.", s
->source_output
->index
);
262 object_path
= pa_dbusiface_core_get_client_path(s
->core
, client
);
264 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &object_path
);
267 static void handle_get_device(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
268 pa_dbusiface_stream
*s
= userdata
;
269 const char *device
= NULL
;
275 if (s
->type
== STREAM_TYPE_PLAYBACK
)
276 device
= pa_dbusiface_core_get_sink_path(s
->core
, s
->sink
);
278 device
= pa_dbusiface_core_get_source_path(s
->core
, s
->source
);
280 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_OBJECT_PATH
, &device
);
283 static void handle_get_sample_format(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
284 pa_dbusiface_stream
*s
= userdata
;
285 dbus_uint32_t sample_format
= 0;
291 sample_format
= (s
->type
== STREAM_TYPE_PLAYBACK
)
292 ? s
->sink_input
->sample_spec
.format
293 : s
->source_output
->sample_spec
.format
;
295 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &sample_format
);
298 static void handle_get_sample_rate(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
299 pa_dbusiface_stream
*s
= userdata
;
305 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, &s
->sample_rate
);
308 static void handle_get_channels(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
309 pa_dbusiface_stream
*s
= userdata
;
310 pa_channel_map
*channel_map
= NULL
;
311 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
318 channel_map
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? &s
->sink_input
->channel_map
: &s
->source_output
->channel_map
;
320 for (i
= 0; i
< channel_map
->channels
; ++i
)
321 channels
[i
] = channel_map
->map
[i
];
323 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
326 static void handle_get_volume(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
327 pa_dbusiface_stream
*s
= userdata
;
328 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
335 if (s
->type
== STREAM_TYPE_RECORD
) {
336 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "Record streams don't have volume.");
340 for (i
= 0; i
< s
->volume
.channels
; ++i
)
341 volume
[i
] = s
->volume
.values
[i
];
343 pa_dbus_send_basic_array_variant_reply(conn
, msg
, DBUS_TYPE_UINT32
, volume
, s
->volume
.channels
);
346 static void handle_set_volume(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
347 pa_dbusiface_stream
*s
= userdata
;
348 DBusMessageIter array_iter
;
349 int stream_channels
= 0;
350 dbus_uint32_t
*volume
= NULL
;
351 int n_volume_entries
= 0;
360 if (s
->type
== STREAM_TYPE_RECORD
) {
361 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "Record streams don't have volume.");
365 pa_cvolume_init(&new_vol
);
367 stream_channels
= s
->sink_input
->channel_map
.channels
;
369 new_vol
.channels
= stream_channels
;
371 dbus_message_iter_recurse(iter
, &array_iter
);
372 dbus_message_iter_get_fixed_array(&array_iter
, &volume
, &n_volume_entries
);
374 if (n_volume_entries
!= stream_channels
) {
375 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
,
376 "Expected %u volume entries, got %u.", stream_channels
, n_volume_entries
);
380 for (i
= 0; i
< n_volume_entries
; ++i
) {
381 if (!PA_VOLUME_IS_VALID(volume
[i
])) {
382 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid volume: %u", volume
[i
]);
385 new_vol
.values
[i
] = volume
[i
];
388 pa_sink_input_set_volume(s
->sink_input
, &new_vol
, TRUE
, TRUE
);
390 pa_dbus_send_empty_reply(conn
, msg
);
393 static void handle_get_mute(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
394 pa_dbusiface_stream
*s
= userdata
;
400 if (s
->type
== STREAM_TYPE_RECORD
) {
401 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NO_SUCH_PROPERTY
, "Record streams don't have mute.");
405 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_BOOLEAN
, &s
->mute
);
408 static void handle_set_mute(DBusConnection
*conn
, DBusMessage
*msg
, DBusMessageIter
*iter
, void *userdata
) {
409 pa_dbusiface_stream
*s
= userdata
;
410 dbus_bool_t mute
= FALSE
;
417 dbus_message_iter_get_basic(iter
, &mute
);
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_sink_input_set_mute(s
->sink_input
, mute
, TRUE
);
426 pa_dbus_send_empty_reply(conn
, msg
);
429 static void handle_get_buffer_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
430 pa_dbusiface_stream
*s
= userdata
;
431 dbus_uint64_t buffer_latency
= 0;
437 if (s
->type
== STREAM_TYPE_PLAYBACK
)
438 buffer_latency
= pa_sink_input_get_latency(s
->sink_input
, NULL
);
440 buffer_latency
= pa_source_output_get_latency(s
->source_output
, NULL
);
442 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &buffer_latency
);
445 static void handle_get_device_latency(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
446 pa_dbusiface_stream
*s
= userdata
;
447 dbus_uint64_t device_latency
= 0;
453 if (s
->type
== STREAM_TYPE_PLAYBACK
)
454 pa_sink_input_get_latency(s
->sink_input
, &device_latency
);
456 pa_source_output_get_latency(s
->source_output
, &device_latency
);
458 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_UINT64
, &device_latency
);
461 static void handle_get_resample_method(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
462 pa_dbusiface_stream
*s
= userdata
;
463 const char *resample_method
= NULL
;
469 if (s
->type
== STREAM_TYPE_PLAYBACK
)
470 resample_method
= pa_resample_method_to_string(s
->sink_input
->actual_resample_method
);
472 resample_method
= pa_resample_method_to_string(s
->source_output
->actual_resample_method
);
474 pa_dbus_send_basic_variant_reply(conn
, msg
, DBUS_TYPE_STRING
, &resample_method
);
477 static void handle_get_property_list(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
478 pa_dbusiface_stream
*s
= userdata
;
484 pa_dbus_send_proplist_variant_reply(conn
, msg
, s
->proplist
);
487 static void handle_get_all(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
488 pa_dbusiface_stream
*s
= userdata
;
489 DBusMessage
*reply
= NULL
;
490 DBusMessageIter msg_iter
;
491 DBusMessageIter dict_iter
;
492 dbus_uint32_t idx
= 0;
493 const char *driver
= NULL
;
494 pa_module
*owner_module
= NULL
;
495 const char *owner_module_path
= NULL
;
496 pa_client
*client
= NULL
;
497 const char *client_path
= NULL
;
498 const char *device
= NULL
;
499 dbus_uint32_t sample_format
= 0;
500 pa_channel_map
*channel_map
= NULL
;
501 dbus_uint32_t channels
[PA_CHANNELS_MAX
];
502 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
503 dbus_uint64_t buffer_latency
= 0;
504 dbus_uint64_t device_latency
= 0;
505 const char *resample_method
= NULL
;
512 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
513 idx
= s
->sink_input
->index
;
514 driver
= s
->sink_input
->driver
;
515 owner_module
= s
->sink_input
->module
;
516 client
= s
->sink_input
->client
;
517 device
= pa_dbusiface_core_get_sink_path(s
->core
, s
->sink
);
518 sample_format
= s
->sink_input
->sample_spec
.format
;
519 channel_map
= &s
->sink_input
->channel_map
;
520 for (i
= 0; i
< s
->volume
.channels
; ++i
)
521 volume
[i
] = s
->volume
.values
[i
];
522 buffer_latency
= pa_sink_input_get_latency(s
->sink_input
, &device_latency
);
523 resample_method
= pa_resample_method_to_string(s
->sink_input
->actual_resample_method
);
525 idx
= s
->source_output
->index
;
526 driver
= s
->source_output
->driver
;
527 owner_module
= s
->source_output
->module
;
528 client
= s
->source_output
->client
;
529 device
= pa_dbusiface_core_get_source_path(s
->core
, s
->source
);
530 sample_format
= s
->source_output
->sample_spec
.format
;
531 channel_map
= &s
->source_output
->channel_map
;
532 buffer_latency
= pa_source_output_get_latency(s
->source_output
, &device_latency
);
533 resample_method
= pa_resample_method_to_string(s
->source_output
->actual_resample_method
);
536 owner_module_path
= pa_dbusiface_core_get_module_path(s
->core
, owner_module
);
538 client_path
= pa_dbusiface_core_get_client_path(s
->core
, client
);
539 for (i
= 0; i
< channel_map
->channels
; ++i
)
540 channels
[i
] = channel_map
->map
[i
];
542 pa_assert_se((reply
= dbus_message_new_method_return(msg
)));
544 dbus_message_iter_init_append(reply
, &msg_iter
);
545 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_ARRAY
, "{sv}", &dict_iter
));
547 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_INDEX
].property_name
, DBUS_TYPE_UINT32
, &idx
);
550 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DRIVER
].property_name
, DBUS_TYPE_STRING
, &driver
);
553 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_OWNER_MODULE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &owner_module_path
);
556 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CLIENT
].property_name
, DBUS_TYPE_OBJECT_PATH
, &client_path
);
558 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DEVICE
].property_name
, DBUS_TYPE_OBJECT_PATH
, &device
);
559 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_FORMAT
].property_name
, DBUS_TYPE_UINT32
, &sample_format
);
560 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_SAMPLE_RATE
].property_name
, DBUS_TYPE_UINT32
, &s
->sample_rate
);
561 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_CHANNELS
].property_name
, DBUS_TYPE_UINT32
, channels
, channel_map
->channels
);
563 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
564 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_VOLUME
].property_name
, DBUS_TYPE_UINT32
, volume
, s
->volume
.channels
);
565 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_MUTE
].property_name
, DBUS_TYPE_BOOLEAN
, &s
->mute
);
568 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_BUFFER_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &buffer_latency
);
569 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_DEVICE_LATENCY
].property_name
, DBUS_TYPE_UINT64
, &device_latency
);
570 pa_dbus_append_basic_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_RESAMPLE_METHOD
].property_name
, DBUS_TYPE_STRING
, &resample_method
);
571 pa_dbus_append_proplist_variant_dict_entry(&dict_iter
, property_handlers
[PROPERTY_HANDLER_PROPERTY_LIST
].property_name
, s
->proplist
);
573 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &dict_iter
));
574 pa_assert_se(dbus_connection_send(conn
, reply
, NULL
));
575 dbus_message_unref(reply
);
578 static void handle_move(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
579 pa_dbusiface_stream
*s
= userdata
;
580 const char *device
= NULL
;
586 pa_assert_se(dbus_message_get_args(msg
, NULL
, DBUS_TYPE_STRING
, &device
, DBUS_TYPE_INVALID
));
588 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
589 pa_sink
*sink
= pa_dbusiface_core_get_sink(s
->core
, device
);
592 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "%s: No such sink.", device
);
596 if (pa_sink_input_move_to(s
->sink_input
, sink
, TRUE
) < 0) {
597 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
598 "Moving playback stream %u to sink %s failed.", s
->sink_input
->index
, sink
->name
);
602 pa_source
*source
= pa_dbusiface_core_get_source(s
->core
, device
);
605 pa_dbus_send_error(conn
, msg
, PA_DBUS_ERROR_NOT_FOUND
, "%s: No such source.", device
);
609 if (pa_source_output_move_to(s
->source_output
, source
, TRUE
) < 0) {
610 pa_dbus_send_error(conn
, msg
, DBUS_ERROR_FAILED
,
611 "Moving record stream %u to source %s failed.", s
->source_output
->index
, source
->name
);
616 pa_dbus_send_empty_reply(conn
, msg
);
619 static void handle_kill(DBusConnection
*conn
, DBusMessage
*msg
, void *userdata
) {
620 pa_dbusiface_stream
*s
= userdata
;
626 if (s
->type
== STREAM_TYPE_PLAYBACK
)
627 pa_sink_input_kill(s
->sink_input
);
629 pa_source_output_kill(s
->source_output
);
631 pa_dbus_send_empty_reply(conn
, msg
);
634 static void subscription_cb(pa_core
*c
, pa_subscription_event_type_t t
, uint32_t idx
, void *userdata
) {
635 pa_dbusiface_stream
*s
= userdata
;
636 DBusMessage
*signal_msg
= NULL
;
637 const char *new_device_path
= NULL
;
638 uint32_t new_sample_rate
= 0;
639 pa_proplist
*new_proplist
= NULL
;
645 if ((s
->type
== STREAM_TYPE_PLAYBACK
&& idx
!= s
->sink_input
->index
)
646 || (s
->type
== STREAM_TYPE_RECORD
&& idx
!= s
->source_output
->index
))
649 if ((t
& PA_SUBSCRIPTION_EVENT_TYPE_MASK
) != PA_SUBSCRIPTION_EVENT_CHANGE
)
652 pa_assert(((s
->type
== STREAM_TYPE_PLAYBACK
)
653 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SINK_INPUT
))
654 || ((s
->type
== STREAM_TYPE_RECORD
)
655 && ((t
& PA_SUBSCRIPTION_EVENT_FACILITY_MASK
) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
)));
657 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
658 pa_sink
*new_sink
= s
->sink_input
->sink
;
660 if (s
->sink
!= new_sink
) {
661 pa_sink_unref(s
->sink
);
662 s
->sink
= pa_sink_ref(new_sink
);
664 new_device_path
= pa_dbusiface_core_get_sink_path(s
->core
, new_sink
);
666 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
667 PA_DBUSIFACE_STREAM_INTERFACE
,
668 signals
[SIGNAL_DEVICE_UPDATED
].name
));
669 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &new_device_path
, DBUS_TYPE_INVALID
));
671 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
672 dbus_message_unref(signal_msg
);
676 pa_source
*new_source
= s
->source_output
->source
;
678 if (s
->source
!= new_source
) {
679 pa_source_unref(s
->source
);
680 s
->source
= pa_source_ref(new_source
);
682 new_device_path
= pa_dbusiface_core_get_source_path(s
->core
, new_source
);
684 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
685 PA_DBUSIFACE_STREAM_INTERFACE
,
686 signals
[SIGNAL_DEVICE_UPDATED
].name
));
687 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_OBJECT_PATH
, &new_device_path
, DBUS_TYPE_INVALID
));
689 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
690 dbus_message_unref(signal_msg
);
695 new_sample_rate
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->sample_spec
.rate
: s
->source_output
->sample_spec
.rate
;
697 if (s
->sample_rate
!= new_sample_rate
) {
698 s
->sample_rate
= new_sample_rate
;
700 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
701 PA_DBUSIFACE_STREAM_INTERFACE
,
702 signals
[SIGNAL_SAMPLE_RATE_UPDATED
].name
));
703 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_UINT32
, &s
->sample_rate
, DBUS_TYPE_INVALID
));
705 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
706 dbus_message_unref(signal_msg
);
710 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
711 pa_cvolume new_volume
;
712 pa_bool_t new_mute
= FALSE
;
714 pa_sink_input_get_volume(s
->sink_input
, &new_volume
, TRUE
);
716 if (!pa_cvolume_equal(&s
->volume
, &new_volume
)) {
717 dbus_uint32_t volume
[PA_CHANNELS_MAX
];
718 dbus_uint32_t
*volume_ptr
= volume
;
720 s
->volume
= new_volume
;
722 for (i
= 0; i
< s
->volume
.channels
; ++i
)
723 volume
[i
] = s
->volume
.values
[i
];
725 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
726 PA_DBUSIFACE_STREAM_INTERFACE
,
727 signals
[SIGNAL_VOLUME_UPDATED
].name
));
728 pa_assert_se(dbus_message_append_args(signal_msg
,
729 DBUS_TYPE_ARRAY
, DBUS_TYPE_UINT32
, &volume_ptr
, s
->volume
.channels
,
732 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
733 dbus_message_unref(signal_msg
);
737 new_mute
= pa_sink_input_get_mute(s
->sink_input
);
739 if (s
->mute
!= new_mute
) {
742 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
743 PA_DBUSIFACE_STREAM_INTERFACE
,
744 signals
[SIGNAL_MUTE_UPDATED
].name
));
745 pa_assert_se(dbus_message_append_args(signal_msg
, DBUS_TYPE_BOOLEAN
, &s
->mute
, DBUS_TYPE_INVALID
));
747 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
748 dbus_message_unref(signal_msg
);
753 new_proplist
= (s
->type
== STREAM_TYPE_PLAYBACK
) ? s
->sink_input
->proplist
: s
->source_output
->proplist
;
755 if (!pa_proplist_equal(s
->proplist
, new_proplist
)) {
756 DBusMessageIter msg_iter
;
758 pa_proplist_update(s
->proplist
, PA_UPDATE_SET
, new_proplist
);
760 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
761 PA_DBUSIFACE_STREAM_INTERFACE
,
762 signals
[SIGNAL_PROPERTY_LIST_UPDATED
].name
));
763 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
764 pa_dbus_append_proplist(&msg_iter
, s
->proplist
);
766 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
767 dbus_message_unref(signal_msg
);
772 static pa_hook_result_t
send_event_cb(void *hook_data
, void *call_data
, void *slot_data
) {
773 pa_dbusiface_stream
*s
= slot_data
;
774 DBusMessage
*signal_msg
= NULL
;
775 DBusMessageIter msg_iter
;
776 const char *name
= NULL
;
777 pa_proplist
*property_list
= NULL
;
779 pa_assert(call_data
);
782 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
783 pa_sink_input_send_event_hook_data
*data
= call_data
;
785 if (data
->sink_input
!= s
->sink_input
)
789 property_list
= data
->data
;
791 pa_source_output_send_event_hook_data
*data
= call_data
;
793 if (data
->source_output
!= s
->source_output
)
797 property_list
= data
->data
;
800 pa_assert_se(signal_msg
= dbus_message_new_signal(s
->path
,
801 PA_DBUSIFACE_STREAM_INTERFACE
,
802 signals
[SIGNAL_STREAM_EVENT
].name
));
803 dbus_message_iter_init_append(signal_msg
, &msg_iter
);
804 pa_assert_se(dbus_message_iter_append_basic(&msg_iter
, DBUS_TYPE_STRING
, &name
));
805 pa_dbus_append_proplist(&msg_iter
, property_list
);
807 pa_dbus_protocol_send_signal(s
->dbus_protocol
, signal_msg
);
808 dbus_message_unref(signal_msg
);
813 pa_dbusiface_stream
*pa_dbusiface_stream_new_playback(pa_dbusiface_core
*core
, pa_sink_input
*sink_input
) {
814 pa_dbusiface_stream
*s
;
817 pa_assert(sink_input
);
819 s
= pa_xnew(pa_dbusiface_stream
, 1);
821 s
->sink_input
= pa_sink_input_ref(sink_input
);
822 s
->type
= STREAM_TYPE_PLAYBACK
;
823 s
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, PLAYBACK_OBJECT_NAME
, sink_input
->index
);
824 s
->sink
= pa_sink_ref(sink_input
->sink
);
825 s
->sample_rate
= sink_input
->sample_spec
.rate
;
826 pa_sink_input_get_volume(sink_input
, &s
->volume
, TRUE
);
827 s
->mute
= pa_sink_input_get_mute(sink_input
);
828 s
->proplist
= pa_proplist_copy(sink_input
->proplist
);
829 s
->dbus_protocol
= pa_dbus_protocol_get(sink_input
->core
);
830 s
->subscription
= pa_subscription_new(sink_input
->core
, PA_SUBSCRIPTION_MASK_SINK_INPUT
, subscription_cb
, s
);
831 s
->send_event_slot
= pa_hook_connect(&sink_input
->core
->hooks
[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT
],
836 pa_assert_se(pa_dbus_protocol_add_interface(s
->dbus_protocol
, s
->path
, &stream_interface_info
, s
) >= 0);
841 pa_dbusiface_stream
*pa_dbusiface_stream_new_record(pa_dbusiface_core
*core
, pa_source_output
*source_output
) {
842 pa_dbusiface_stream
*s
;
845 pa_assert(source_output
);
847 s
= pa_xnew(pa_dbusiface_stream
, 1);
849 s
->source_output
= pa_source_output_ref(source_output
);
850 s
->type
= STREAM_TYPE_RECORD
;
851 s
->path
= pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH
, RECORD_OBJECT_NAME
, source_output
->index
);
852 s
->source
= pa_source_ref(source_output
->source
);
853 s
->sample_rate
= source_output
->sample_spec
.rate
;
854 pa_cvolume_init(&s
->volume
);
856 s
->proplist
= pa_proplist_copy(source_output
->proplist
);
857 s
->dbus_protocol
= pa_dbus_protocol_get(source_output
->core
);
858 s
->subscription
= pa_subscription_new(source_output
->core
, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT
, subscription_cb
, s
);
859 s
->send_event_slot
= pa_hook_connect(&source_output
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT
],
864 pa_assert_se(pa_dbus_protocol_add_interface(s
->dbus_protocol
, s
->path
, &stream_interface_info
, s
) >= 0);
869 void pa_dbusiface_stream_free(pa_dbusiface_stream
*s
) {
872 pa_assert_se(pa_dbus_protocol_remove_interface(s
->dbus_protocol
, s
->path
, stream_interface_info
.name
) >= 0);
874 if (s
->type
== STREAM_TYPE_PLAYBACK
) {
875 pa_sink_input_unref(s
->sink_input
);
876 pa_sink_unref(s
->sink
);
878 pa_source_output_unref(s
->source_output
);
879 pa_source_unref(s
->source
);
882 pa_proplist_free(s
->proplist
);
883 pa_dbus_protocol_unref(s
->dbus_protocol
);
884 pa_subscription_free(s
->subscription
);
885 pa_hook_slot_free(s
->send_event_slot
);
891 const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream
*s
) {