2 This file is part of PulseAudio.
4 Copyright 2017 Sangchul Lee <sc11.lee@samsung.com>
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
28 #include <pulsecore/proplist-util.h>
29 #include "stream-manager-priv.h"
30 #include "stream-manager-dbus-priv.h"
31 #include "stream-manager-volume-priv.h"
32 #include "stream-manager-filter-priv.h"
33 #include "stream-manager-restriction-priv.h"
35 static const char *dbus_str_none = "none";
36 static const char *stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK",
37 "STREAM_MANAGER_RETURN_ERROR_INTERNAL",
38 "STREAM_MANAGER_RETURN_ERROR_NO_STREAM",
39 "STREAM_MANAGER_RETURN_ERROR_INVALID_ARGUMENT",
40 "STREAM_MANAGER_RETURN_ERROR_DEVICE_NOT_FOUND",
41 "STREAM_MANAGER_RETURN_ERROR_POLICY",
42 "STREAM_MANAGER_RETURN_ERROR_INVALID_STATE"};
44 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
45 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
46 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
47 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
48 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
49 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
50 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
51 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
52 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
53 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
54 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
55 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
56 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
59 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
61 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
62 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata);
63 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
64 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
65 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata);
66 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata);
67 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
69 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata);
71 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
72 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata);
74 static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
77 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level);
79 static pa_dbus_arg_info get_stream_info_args[] = { { "stream_type", "s", "in" },
80 { "priority", "i", "out" },
81 { "route_type", "i", "out" },
82 { "volume_types", "as", "out" },
83 { "avail_in_devices", "as", "out" },
84 { "avail_out_devices", "as", "out" },
85 { "avail_frameworks", "as", "out"} };
86 static pa_dbus_arg_info get_stream_list_args[] = { { "stream_type", "as", "out" },
87 { "priority", "ai", "out" } };
88 static pa_dbus_arg_info set_stream_route_devices_args[] = { { "parent_id", "u", "in" },
89 { "route_in_devices", "au", "in" },
90 { "route_out_devices", "au", "in" },
91 { "ret_msg", "s", "out" } };
92 static pa_dbus_arg_info set_stream_route_option_args[] = { { "parent_id", "u", "in" },
93 { "name", "s", "in" },
94 { "value", "i", "in" },
95 { "ret_msg", "s", "out" } };
96 static pa_dbus_arg_info set_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
97 { "io_direction", "s", "in" },
98 { "device_id", "u", "in" },
99 { "ret_msg", "s", "out" } };
100 static pa_dbus_arg_info get_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
101 { "in_device_id", "u", "out" },
102 { "out_device_id", "u", "out" },
103 { "ret_msg", "s", "out" } };
104 static pa_dbus_arg_info set_stream_preemptive_device_args[] = { { "stream_type", "s", "in" },
105 { "io_direction", "s", "in" },
106 { "device_id", "u", "in" },
107 { "ret_msg", "s", "out" } };
108 static pa_dbus_arg_info get_stream_preemptive_device_args[] = { { "stream_type", "s", "in" },
109 { "in_device_id", "u", "out" },
110 { "out_device_id", "u", "out" },
111 { "ret_msg", "s", "out" } };
112 static pa_dbus_arg_info set_volume_level_args[] = { { "io_direction", "s", "in" },
113 { "type", "s", "in" },
114 { "level", "u", "in" },
115 { "ret_msg", "s", "out" } };
116 static pa_dbus_arg_info get_volume_level_args[] = { { "io_direction", "s", "in" },
117 { "type", "s", "in" },
118 { "level", "u", "out" },
119 { "ret_msg", "s", "out" } };
120 static pa_dbus_arg_info get_volume_max_level_args[] = { { "io_direction", "s", "in" },
121 { "type", "s", "in" },
122 { "level", "u", "out" },
123 { "ret_msg", "s", "out" } };
124 static pa_dbus_arg_info set_volume_mute_args[] = { { "io_direction", "s", "in" },
125 { "type", "s", "in" },
127 { "ret_msg", "s", "out" } };
128 static pa_dbus_arg_info get_volume_mute_args[] = { { "io_direction", "s", "in" },
129 { "type", "s", "in" },
130 { "on", "u", "out" },
131 { "ret_msg", "s", "out" } };
132 static pa_dbus_arg_info set_volume_ratio_args[] = { { "io_direction", "s", "in" },
133 { "idx", "u", "in" },
134 { "ratio", "d", "in" },
135 { "ret_msg", "s", "out" } };
136 static pa_dbus_arg_info get_volume_ratio_args[] = { { "io_direction", "s", "in" },
137 { "idx", "u", "in" },
138 { "ratio", "d", "out" },
139 { "ret_msg", "s", "out" } };
140 static pa_dbus_arg_info get_current_volume_type_args[] = { { "io_direction", "s", "in" },
141 { "type", "s", "out" },
142 { "ret_msg", "s", "out" } };
143 static pa_dbus_arg_info get_current_media_routing_path_args[] = { { "io_direction", "s", "in" },
144 { "device_type", "s", "out" },
145 { "ret_msg", "s", "out" } };
146 static pa_dbus_arg_info update_focus_status_args[] = { { "parent_id", "u", "in" },
147 { "focus_status", "u", "in" },
148 { "ret_msg", "s", "out" } };
149 static pa_dbus_arg_info update_focus_status_by_focus_id_args[] = { { "focus_id", "i", "in" },
150 { "focus_status", "u", "in" },
151 { "ret_msg", "s", "out" } };
152 static pa_dbus_arg_info update_restriction_args[] = { { "name", "s", "in" },
153 { "value", "u", "in" },
154 { "ret_msg", "s", "out" } };
155 static pa_dbus_arg_info update_call_parameters_args[] = { { "parameters", "s", "in" },
156 { "ret_msg", "s", "out" } };
157 static pa_dbus_arg_info set_filter_args[] = { { "filter_name", "s", "in" },
158 { "filter_parameters", "s", "in" },
159 { "filter_group", "s", "in" },
160 { "stream_type", "s", "in" },
161 { "ret_msg", "s", "out" } };
162 static pa_dbus_arg_info unset_filter_args[] = { { "stream_type", "s", "in" },
163 { "ret_msg", "s", "out" } };
164 static pa_dbus_arg_info control_filter_args[] = { { "filter_name", "s", "in" },
165 { "filter_controls", "s", "in" },
166 { "stream_type", "s", "in" },
167 { "ret_msg", "s", "out" } };
168 static pa_dbus_arg_info check_stream_exist_by_pid_args[] = { { "pid", "u", "in" },
169 { "stream_type", "s", "in" },
170 { "io_direction", "s", "in" },
171 { "ret_msg", "s", "out" } };
172 static pa_dbus_arg_info get_pid_of_latest_stream_args[] = { { "io_direction", "s", "in" },
173 { "stream_types", "as", "in" },
174 { "pid", "u", "out" },
175 { "ret_msg", "s", "out" } };
176 static pa_dbus_arg_info activate_ducking_args[] = { { "index", "u", "in" },
177 { "enable", "b", "in" },
178 { "target_stream", "s", "in" },
179 { "duration", "u", "in" },
180 { "ratio", "d", "in" },
181 { "ret_msg", "s", "out" } };
183 static pa_dbus_arg_info get_ducking_state_args[] = { { "index", "u", "in" },
184 { "is_ducked", "b", "out" },
185 { "ret_msg", "s", "out" } };
186 static pa_dbus_arg_info set_remote_permission_args[] = { { "type", "s", "in" },
187 { "index", "u", "in" },
188 { "allowed", "b", "in" } };
189 static pa_dbus_arg_info discover_remote_device_args[] = { { "enable", "b", "in" } };
190 static pa_dbus_arg_info publish_local_device_args[] = { { "enable", "b", "in" } };
192 static const char* signature_args_for_in[] = {
193 "s", /* METHOD_HANDLER_GET_STREAM_INFO */
194 "", /* METHOD_HANDLER_GET_STREAM_LIST */
195 "uauau", /* METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES */
196 "usi", /* METHOD_HANDLER_SET_STREAM_ROUTE_OPTION */
197 "usu", /* METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE */
198 "u", /* METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE */
199 "ssu", /* METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE */
200 "s", /* METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE */
201 "ssu", /* METHOD_HANDLER_SET_VOLUME_LEVEL */
202 "ss", /* METHOD_HANDLER_GET_VOLUME_LEVEL */
203 "ss", /* METHOD_HANDLER_GET_VOLUME_MAX_LEVEL */
204 "ssu", /* METHOD_HANDLER_SET_VOLUME_MUTE */
205 "ss", /* METHOD_HANDLER_GET_VOLUME_MUTE */
206 "sud", /* METHOD_HANDLER_SET_VOLUME_RATIO */
207 "su", /* METHOD_HANDLER_GET_VOLUME_RATIO */
208 "s", /* METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE */
209 "s", /* METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH */
210 "uu", /* METHOD_HANDLER_UPDATE_FOCUS_STATUS */
211 "iu", /* METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID */
212 "su", /* METHOD_HANDLER_UPDATE_RESTRICTION */
213 "s", /* METHOD_HANDLER_UPDATE_CALL_PARAMETERS */
214 "ssss", /* METHOD_HANDLER_SET_FILTER */
215 "s", /* METHOD_HANDLER_UNSET_FILTER */
216 "sss", /* METHOD_HANDLER_CONTROL_FILTER */
217 "uss", /* METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID */
218 "sas", /* METHOD_HANDLER_GET_PID_OF_LATEST_STREAM */
219 "ubsud", /* METHOD_HANDLER_ACTIVATE_DUCKING */
220 "u", /* METHOD_HANDLER_GET_DUCKING_STATE */
221 "sub", /* METHOD_HANDLER_SET_REMOTE_PERMISSION */
222 "b", /* METHOD_HANDLER_DISCOVER_REMOTE_DEVICE */
223 "b" /* METHOD_HANDLER_PUBLISH_LOCAL_DEVICE */
226 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
227 [METHOD_HANDLER_GET_STREAM_INFO] = {
228 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
229 .arguments = get_stream_info_args,
230 .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
231 .receive_cb = handle_get_stream_info },
232 [METHOD_HANDLER_GET_STREAM_LIST] = {
233 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
234 .arguments = get_stream_list_args,
235 .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
236 .receive_cb = handle_get_stream_list },
237 [METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES] = {
238 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
239 .arguments = set_stream_route_devices_args,
240 .n_arguments = sizeof(set_stream_route_devices_args) / sizeof(pa_dbus_arg_info),
241 .receive_cb = handle_set_stream_route_devices },
242 [METHOD_HANDLER_SET_STREAM_ROUTE_OPTION] = {
243 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
244 .arguments = set_stream_route_option_args,
245 .n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
246 .receive_cb = handle_set_stream_route_option },
247 [METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE] = {
248 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREFERRED_DEVICE,
249 .arguments = set_stream_preferred_device_args,
250 .n_arguments = sizeof(set_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
251 .receive_cb = handle_set_stream_preferred_device },
252 [METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE] = {
253 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREFERRED_DEVICE,
254 .arguments = get_stream_preferred_device_args,
255 .n_arguments = sizeof(get_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
256 .receive_cb = handle_get_stream_preferred_device },
257 [METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE] = {
258 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREEMPTIVE_DEVICE,
259 .arguments = set_stream_preemptive_device_args,
260 .n_arguments = sizeof(set_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
261 .receive_cb = handle_set_stream_preemptive_device },
262 [METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE] = {
263 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREEMPTIVE_DEVICE,
264 .arguments = get_stream_preemptive_device_args,
265 .n_arguments = sizeof(get_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
266 .receive_cb = handle_get_stream_preemptive_device },
267 [METHOD_HANDLER_SET_VOLUME_LEVEL] = {
268 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
269 .arguments = set_volume_level_args,
270 .n_arguments = sizeof(set_volume_level_args) / sizeof(pa_dbus_arg_info),
271 .receive_cb = handle_set_volume_level },
272 [METHOD_HANDLER_GET_VOLUME_LEVEL] = {
273 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
274 .arguments = get_volume_level_args,
275 .n_arguments = sizeof(get_volume_level_args) / sizeof(pa_dbus_arg_info),
276 .receive_cb = handle_get_volume_level },
277 [METHOD_HANDLER_GET_VOLUME_MAX_LEVEL] = {
278 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
279 .arguments = get_volume_max_level_args,
280 .n_arguments = sizeof(get_volume_max_level_args) / sizeof(pa_dbus_arg_info),
281 .receive_cb = handle_get_volume_max_level },
282 [METHOD_HANDLER_SET_VOLUME_MUTE] = {
283 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE,
284 .arguments = set_volume_mute_args,
285 .n_arguments = sizeof(set_volume_mute_args) / sizeof(pa_dbus_arg_info),
286 .receive_cb = handle_set_volume_mute },
287 [METHOD_HANDLER_GET_VOLUME_MUTE] = {
288 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE,
289 .arguments = get_volume_mute_args,
290 .n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
291 .receive_cb = handle_get_volume_mute },
292 [METHOD_HANDLER_SET_VOLUME_RATIO] = {
293 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_RATIO,
294 .arguments = set_volume_ratio_args,
295 .n_arguments = sizeof(set_volume_ratio_args) / sizeof(pa_dbus_arg_info),
296 .receive_cb = handle_set_volume_ratio },
297 [METHOD_HANDLER_GET_VOLUME_RATIO] = {
298 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_RATIO,
299 .arguments = get_volume_ratio_args,
300 .n_arguments = sizeof(get_volume_ratio_args) / sizeof(pa_dbus_arg_info),
301 .receive_cb = handle_get_volume_ratio },
302 [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
303 .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
304 .arguments = get_current_volume_type_args,
305 .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
306 .receive_cb = handle_get_current_volume_type },
307 [METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH] = {
308 .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_MEDIA_ROUTING_PATH,
309 .arguments = get_current_media_routing_path_args,
310 .n_arguments = sizeof(get_current_media_routing_path_args) / sizeof(pa_dbus_arg_info),
311 .receive_cb = handle_get_current_media_routing_path },
312 [METHOD_HANDLER_UPDATE_FOCUS_STATUS] = {
313 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS,
314 .arguments = update_focus_status_args,
315 .n_arguments = sizeof(update_focus_status_args) / sizeof(pa_dbus_arg_info),
316 .receive_cb = handle_update_focus_status },
317 [METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID] = {
318 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS_BY_FOCUS_ID,
319 .arguments = update_focus_status_by_focus_id_args,
320 .n_arguments = sizeof(update_focus_status_by_focus_id_args) / sizeof(pa_dbus_arg_info),
321 .receive_cb = handle_update_focus_status_by_focus_id },
322 [METHOD_HANDLER_UPDATE_RESTRICTION] = {
323 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_RESTRICTION,
324 .arguments = update_restriction_args,
325 .n_arguments = sizeof(update_restriction_args) / sizeof(pa_dbus_arg_info),
326 .receive_cb = handle_update_restriction },
327 [METHOD_HANDLER_UPDATE_CALL_PARAMETERS] = {
328 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_CALL_PARAMETERS,
329 .arguments = update_call_parameters_args,
330 .n_arguments = sizeof(update_call_parameters_args) / sizeof(pa_dbus_arg_info),
331 .receive_cb = handle_update_call_parameters },
332 [METHOD_HANDLER_SET_FILTER] = {
333 .method_name = STREAM_MANAGER_METHOD_NAME_SET_FILTER,
334 .arguments = set_filter_args,
335 .n_arguments = sizeof(set_filter_args) / sizeof(pa_dbus_arg_info),
336 .receive_cb = handle_set_filter },
337 [METHOD_HANDLER_UNSET_FILTER] = {
338 .method_name = STREAM_MANAGER_METHOD_NAME_UNSET_FILTER,
339 .arguments = unset_filter_args,
340 .n_arguments = sizeof(unset_filter_args) / sizeof(pa_dbus_arg_info),
341 .receive_cb = handle_unset_filter },
342 [METHOD_HANDLER_CONTROL_FILTER] = {
343 .method_name = STREAM_MANAGER_METHOD_NAME_CONTROL_FILTER,
344 .arguments = control_filter_args,
345 .n_arguments = sizeof(control_filter_args) / sizeof(pa_dbus_arg_info),
346 .receive_cb = handle_control_filter },
347 [METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID] = {
348 .method_name = STREAM_MANAGER_METHOD_NAME_CHECK_STREAM_EXIST_BY_PID,
349 .arguments = check_stream_exist_by_pid_args,
350 .n_arguments = sizeof(check_stream_exist_by_pid_args) / sizeof(pa_dbus_arg_info),
351 .receive_cb = handle_check_stream_exist_by_pid },
352 [METHOD_HANDLER_GET_PID_OF_LATEST_STREAM] = {
353 .method_name = STREAM_MANAGER_METHOD_NAME_GET_PID_OF_LATEST_STREAM,
354 .arguments = get_pid_of_latest_stream_args,
355 .n_arguments = sizeof(get_pid_of_latest_stream_args) / sizeof(pa_dbus_arg_info),
356 .receive_cb = handle_get_pid_of_latest_stream },
357 [METHOD_HANDLER_ACTIVATE_DUCKING] = {
358 .method_name = STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING,
359 .arguments = activate_ducking_args,
360 .n_arguments = sizeof(activate_ducking_args) / sizeof(pa_dbus_arg_info),
361 .receive_cb = handle_activate_ducking },
362 [METHOD_HANDLER_GET_DUCKING_STATE] = {
363 .method_name = STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE,
364 .arguments = get_ducking_state_args,
365 .n_arguments = sizeof(get_ducking_state_args) / sizeof(pa_dbus_arg_info),
366 .receive_cb = handle_get_ducking_state },
367 [METHOD_HANDLER_NAME_SET_REMOTE_PERMISSION] = {
368 .method_name = STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION,
369 .arguments = set_remote_permission_args,
370 .n_arguments = sizeof(set_remote_permission_args) / sizeof(pa_dbus_arg_info),
371 .receive_cb = handle_set_remote_permission },
372 [METHOD_HANDLER_DISCOVER_REMOTE_DEVICE] = {
373 .method_name = STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICE,
374 .arguments = discover_remote_device_args,
375 .n_arguments = sizeof(discover_remote_device_args) / sizeof(pa_dbus_arg_info),
376 .receive_cb = handle_discover_remote_device },
377 [METHOD_HANDLER_PUBLISH_LOCAL_DEVICE] = {
378 .method_name = STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE,
379 .arguments = publish_local_device_args,
380 .n_arguments = sizeof(publish_local_device_args) / sizeof(pa_dbus_arg_info),
381 .receive_cb = handle_publish_local_device },
384 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
385 const char *xml = STREAM_MGR_INTROSPECT_XML;
386 DBusMessage *r = NULL;
392 pa_assert_se((r = dbus_message_new_method_return(msg)));
393 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
396 pa_assert_se(dbus_connection_send((conn), r, NULL));
397 dbus_message_unref(r);
400 return DBUS_HANDLER_RESULT_HANDLED;
403 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
405 DBusMessage *reply = NULL;
406 DBusMessageIter msg_iter;
407 pa_stream_manager *m = (pa_stream_manager*)userdata;
413 pa_assert_se(dbus_message_get_args(msg, NULL,
415 pa_log_info("get stream list");
417 memset(&list, 0, sizeof(stream_list));
418 pa_assert_se((reply = dbus_message_new_method_return(msg)));
419 dbus_message_iter_init_append(reply, &msg_iter);
420 if (!get_available_streams(m, &list)) {
421 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
422 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
424 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
425 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, NULL, 0);
427 pa_assert_se(dbus_connection_send(conn, reply, NULL));
428 dbus_message_unref(reply);
431 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
433 stream_info_per_type info;
434 DBusMessage *reply = NULL;
435 DBusMessageIter msg_iter;
436 pa_stream_manager *m = (pa_stream_manager*)userdata;
442 pa_assert_se(dbus_message_get_args(msg, NULL,
443 DBUS_TYPE_STRING, &type,
445 pa_log_info("type[%s]", type);
447 memset(&info, 0, sizeof(stream_info_per_type));
448 pa_assert_se((reply = dbus_message_new_method_return(msg)));
449 dbus_message_iter_init_append(reply, &msg_iter);
450 get_stream_info(m, type, &info);
451 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
452 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
453 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.volume_types, STREAM_DIRECTION_MAX);
454 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
455 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
456 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
458 pa_assert_se(dbus_connection_send(conn, reply, NULL));
459 dbus_message_unref(reply);
462 static bool check_all_requested_devices_connected(pa_stream_manager *m, uint32_t *device_list, uint32_t length) {
463 pa_idxset *dm_device_list;
464 uint32_t found_count = 0;
468 pa_assert(device_list);
470 dm_device_list = pa_device_manager_get_device_list(m->dm);
472 for (i = 0; i < length; i++) {
473 pa_tz_device *dm_device;
474 uint32_t dm_device_id;
477 PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
478 dm_device_id = pa_tz_device_get_id(dm_device);
479 if (device_list[i] == dm_device_id) {
480 pa_log_debug("device[%u] is connected", dm_device_id);
482 if (length == found_count)
492 static ret_msg_t update_devices_and_trigger_routing(pa_stream_manager *m, stream_parent *sp, stream_type_t type) {
494 pa_idxset *idx_streams = NULL;
496 void *cur_highest_priority_stream = NULL;
497 stream_route_type_t route_type = STREAM_ROUTE_TYPE_DEFAULT;
498 ret_msg_t ret = RET_MSG_OK;
503 if (type == STREAM_SINK_INPUT) {
504 idx_streams = sp->idx_sink_inputs;
505 cur_highest_priority_stream = (void*)m->cur_highest_priority.sink_input;
507 idx_streams = sp->idx_source_outputs;
508 cur_highest_priority_stream = (void*)m->cur_highest_priority.source_output;
511 /* update route type of this stream parent */
512 if (sp->route_type == STREAM_ROUTE_TYPE_DEFAULT) {
513 PA_IDXSET_FOREACH(stream, idx_streams, idx) {
514 /* find route type of stream */
515 if (get_route_type(stream, type, false, &route_type))
516 return RET_MSG_ERROR_INTERNAL;
518 if (route_type == STREAM_ROUTE_TYPE_MANUAL ||
519 route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
520 sp->route_type = route_type;
521 pa_log_info(" -- the route type is [%d]", route_type);
523 pa_log_error(" -- the route type is not valid[%d]", route_type);
524 return RET_MSG_ERROR_POLICY;
529 /* if any stream that belongs to this id has been activated, do notify right away */
530 if (sp->route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
531 PA_IDXSET_FOREACH(stream, idx_streams, idx) {
532 pa_log_debug(" -- stream->index[%u] belongs to this stream parent[%p], do notify for the select proper source",
533 GET_STREAM_INDEX(stream, type), sp);
534 ret = do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, false, stream);
537 /* trigger only when it occupies routing path */
538 if (cur_highest_priority_stream && pa_idxset_get_by_data(idx_streams, cur_highest_priority_stream, NULL)) {
539 pa_log_debug(" -- cur_highest_priority_stream->index[%u] belongs to this stream_parent[%p], do notify for the route change",
540 GET_STREAM_INDEX(cur_highest_priority_stream, type), sp);
541 ret = do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, false, cur_highest_priority_stream);
542 if (!ret && is_stream_related_call_active_routing(PA_OBJECT(cur_highest_priority_stream)) && m->on_call) {
543 pa_log_info("set active device for new call route device");
544 change_active_route_for_call(m, PA_OBJECT(cur_highest_priority_stream), false);
552 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
555 uint32_t *in_device_list = NULL;
556 uint32_t *out_device_list = NULL;
558 int list_len_out = 0;
559 stream_parent *sp = NULL;
560 DBusMessage *reply = NULL;
561 pa_stream_manager *m = (pa_stream_manager*)userdata;
562 ret_msg_t ret = RET_MSG_OK;
568 pa_assert_se(dbus_message_get_args(msg, NULL,
569 DBUS_TYPE_UINT32, &id,
570 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &in_device_list, &list_len_in,
571 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &out_device_list, &list_len_out,
573 pa_log_info("id[%u], in_device_list[%p]:length[%d], out_device_list[%p]:length[%d]",
574 id, in_device_list, list_len_in, out_device_list, list_len_out);
576 pa_assert_se((reply = dbus_message_new_method_return(msg)));
578 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
580 pa_log_error("could not find matching client for this parent_id[%u]", id);
581 ret = RET_MSG_ERROR_INTERNAL;
584 if (!in_device_list && !out_device_list) {
585 pa_log_error("invalid arguments");
586 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
589 if (!sp->idx_route_in_devices || !sp->idx_route_out_devices) {
590 pa_log_error("failed to update, idx_route_in_devices[%p], idx_route_out_devices[%p]",
591 sp->idx_route_in_devices, sp->idx_route_out_devices);
592 ret = RET_MSG_ERROR_INTERNAL;
596 /* check if all the requested devices are connected now */
597 if (in_device_list && !check_all_requested_devices_connected(m, in_device_list, list_len_in)) {
598 pa_log_error("could not find requested in-devices");
599 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
602 if (out_device_list && !check_all_requested_devices_connected(m, out_device_list, list_len_out)) {
603 pa_log_error("could not find requested out-devices");
604 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
608 pa_idxset_remove_all(sp->idx_route_in_devices, pa_xfree);
609 if (in_device_list && list_len_in) {
610 for (i = 0; i < list_len_in; i++) {
611 pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(uint32_t)), NULL);
612 pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
615 if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SOURCE_OUTPUT)))
618 pa_idxset_remove_all(sp->idx_route_out_devices, pa_xfree);
619 if (out_device_list && list_len_out) {
620 for (i = 0; i < list_len_out; i++) {
621 pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(uint32_t)), NULL);
622 pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
625 if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SINK_INPUT)))
629 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
630 pa_assert_se(dbus_connection_send(conn, reply, NULL));
631 dbus_message_unref(reply);
634 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
636 const char *name = NULL;
638 bool updated = false;
639 stream_parent *sp = NULL;
640 stream_route_option route_option;
641 DBusMessage *reply = NULL;
642 pa_stream_manager *m = (pa_stream_manager*)userdata;
648 pa_assert_se(dbus_message_get_args(msg, NULL,
649 DBUS_TYPE_UINT32, &id,
650 DBUS_TYPE_STRING, &name,
651 DBUS_TYPE_INT32, &value,
653 pa_log_info("name[%s], value[%d]", name, value);
655 pa_assert_se((reply = dbus_message_new_method_return(msg)));
657 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
660 route_option.name = name;
661 route_option.value = value;
663 /* if any stream that belongs to this id has been activated, do notify right away */
664 if (m->cur_highest_priority.sink_input) {
665 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
666 pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
667 (m->cur_highest_priority.sink_input)->index, id);
668 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
672 if (m->cur_highest_priority.source_output) {
673 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
674 pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
675 (m->cur_highest_priority.source_output)->index, id);
676 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SOURCE_OUTPUT, false, &route_option);
681 pa_log_error("invalid state");
682 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
684 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
686 pa_log_error("invalid arguments");
687 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT], DBUS_TYPE_INVALID));
691 pa_log_error("could not find matching client for this parent_id[%u]", id);
692 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
695 pa_assert_se(dbus_connection_send(conn, reply, NULL));
696 dbus_message_unref(reply);
699 static int get_device_for_preference(pa_stream_manager *m, stream_parent *sp, stream_direction_t direction, uint32_t device_id, pa_tz_device **device) {
704 if (device_id == 0) {
705 /* get a device of default role from previous device type */
706 if (!(*device = pa_device_manager_get_device(m->dm, sp->preferred_device.types[direction], NULL))) {
707 pa_log_error("could not get device[%s]", sp->preferred_device.types[direction]);
710 pa_log_debug("unset preferred device, rollback to type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
712 /* get the device of device id */
713 if (!(*device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
714 pa_log_error("could not get device by id[%u]", device_id);
717 pa_log_debug("requested preferred device type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
723 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
724 const char *device_direction = NULL;
726 uint32_t device_id = 0;
729 stream_direction_t direction;
730 pa_tz_device *device;
731 pa_tz_device *prev_device;
732 const char *device_role;
733 const char *prev_device_type;
734 const char *prev_device_role;
735 stream_parent *sp = NULL;
739 pa_proplist *device_props;
740 uint32_t stream_index;
742 void *new_device = NULL;
743 ret_msg_t ret = RET_MSG_OK;
744 DBusMessage *reply = NULL;
746 pa_stream_manager *m = (pa_stream_manager*)userdata;
752 pa_assert_se(dbus_message_get_args(msg, NULL,
753 DBUS_TYPE_UINT32, &sp_id,
754 DBUS_TYPE_STRING, &device_direction,
755 DBUS_TYPE_UINT32, &device_id,
757 pa_log_info("stream parent id[%u], device direction[%s], device_id[%u]", sp_id, device_direction, device_id);
759 pa_assert_se((reply = dbus_message_new_method_return(msg)));
761 if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
762 pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
763 ret = RET_MSG_ERROR_INTERNAL;
767 if (pa_safe_streq(device_direction, "in"))
768 direction = STREAM_DIRECTION_IN;
769 else if (pa_safe_streq(device_direction, "out"))
770 direction = STREAM_DIRECTION_OUT;
772 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
776 /* allow only auto routing type */
777 if (sp->route_type != STREAM_ROUTE_TYPE_AUTO &&
778 sp->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
779 pa_log_error("not allowed this route type[%d] of this parent_id[%u]", sp->route_type, sp_id);
780 ret = RET_MSG_ERROR_POLICY;
784 if (device_id == 0 && !sp->preferred_device.types[direction]) {
785 pa_log_debug("it is already unset");
789 if (get_device_for_preference(m, sp, direction, device_id, &device) < 0) {
790 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
794 /* only allow built-in device types */
795 if (!device_type_is_builtin(device->type)) {
796 pa_log_error("This device(id:%u, type:%s) is not built-in type", device_id, device->type);
797 ret = RET_MSG_ERROR_POLICY;
801 /* get default role of the device */
802 device_role = pa_tz_device_get_role(device, NULL);
804 sp->preferred_device.types[direction] = (device_id == 0) ? NULL : device->type;
805 sp->preferred_device.roles[direction] = (device_id == 0) ? NULL : device_role;
807 pa_log_info("preferred device role is set to [%s] of device type[%s], direction[%s]",
808 sp->preferred_device.roles[direction], device->type, direction == STREAM_DIRECTION_OUT ? "out" : "in");
810 streams = (direction == STREAM_DIRECTION_OUT) ? sp->idx_sink_inputs : sp->idx_source_outputs;
811 devices = (direction == STREAM_DIRECTION_OUT) ? device->playback_devices : device->capture_devices;
813 count = pa_idxset_size(streams);
814 PA_IDXSET_FOREACH(stream, streams, idx) {
815 props = GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ?
816 STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT);
817 pa_log_info("stream index(%u), props %p", (direction == STREAM_DIRECTION_OUT) ? PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index, props);
818 device_props = (direction == STREAM_DIRECTION_OUT) ?
819 PA_SINK_INPUT(stream)->sink->proplist : PA_SOURCE_OUTPUT(stream)->source->proplist;
820 stream_index = (direction == STREAM_DIRECTION_OUT) ?
821 PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index;
824 pa_proplist_unset(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
826 pa_proplist_sets(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE, device_role);
828 prev_device_type = pa_proplist_gets(props, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
829 prev_device_role = pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE);
831 if (pa_safe_streq(prev_device_type, device->type)) {
832 /* If the request is for the same device type,
833 * new device role should be applied - move streams. */
834 if (!pa_safe_streq(prev_device_role, device_role)) {
835 new_device = pa_hashmap_get(devices, device_role);
836 pa_log_debug("move stream[%u]: [%s][%s -> %s]",
837 stream_index, prev_device_type, prev_device_role, device_role);
840 /* If the request is for a different device type,
841 * check the previous device role and move streams to default role if needed. */
842 if ((prev_device = pa_device_manager_get_device(m->dm, prev_device_type, NULL)))
843 new_device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
844 prev_device->playback_devices : prev_device->capture_devices);
846 device_props = (direction == STREAM_DIRECTION_OUT) ? PA_SINK(new_device)->proplist : PA_SOURCE(new_device)->proplist;
847 pa_log_debug("may move stream[%u] to default role: [%s][%s -> %s]",
848 stream_index, prev_device_type, prev_device_role, pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE));
852 (direction == STREAM_DIRECTION_OUT) ? pa_sink_input_move_to(stream, PA_SINK(new_device), false) :
853 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
856 /* Use PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED here.
857 * It's not about the focus change, but this command exactly does what is needed here
858 * including updating the highest priority, find the next stream to be set to HAL as well as
859 * change the state of the builtin-device that use internal codec. */
860 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
861 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
866 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
867 pa_assert_se(dbus_connection_send(conn, reply, NULL));
868 dbus_message_unref(reply);
871 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
872 stream_parent *sp = NULL;
874 uint32_t in_device_id = 0;
875 uint32_t out_device_id = 0;
876 const char *pref_in_type, *pref_out_type;
877 const char *pref_in_role, *pref_out_role;
878 pa_idxset *dm_device_list;
879 pa_tz_device *dm_device;
880 dm_device_direction_t dm_direction;
882 ret_msg_t ret = RET_MSG_OK;
883 DBusMessage *reply = NULL;
885 pa_stream_manager *m = (pa_stream_manager*)userdata;
891 pa_assert_se(dbus_message_get_args(msg, NULL,
892 DBUS_TYPE_UINT32, &sp_id,
894 pa_log_info("stream parent id[%u]", sp_id);
896 pa_assert_se((reply = dbus_message_new_method_return(msg)));
898 if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
899 pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
900 ret = RET_MSG_ERROR_INTERNAL;
904 pref_in_type = sp->preferred_device.types[STREAM_DIRECTION_IN];
905 pref_in_role = sp->preferred_device.roles[STREAM_DIRECTION_IN];
906 pref_out_type = sp->preferred_device.types[STREAM_DIRECTION_OUT];
907 pref_out_role = sp->preferred_device.roles[STREAM_DIRECTION_OUT];
909 /* get device ids of preferred in/out device respectively */
910 dm_device_list = pa_device_manager_get_device_list(m->dm);
911 PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
912 dm_direction = pa_tz_device_get_direction(dm_device);
913 if (!in_device_id && dm_direction & DM_DEVICE_DIRECTION_IN) {
914 if (pa_safe_streq(pref_in_type, pa_tz_device_get_type(dm_device))) {
915 if (pa_safe_streq(pref_in_role, pa_tz_device_get_role(dm_device, pref_in_role)))
916 in_device_id = pa_tz_device_get_id(dm_device);
919 if (!out_device_id && dm_direction & DM_DEVICE_DIRECTION_OUT) {
920 if (pa_safe_streq(pref_out_type, pa_tz_device_get_type(dm_device))) {
921 if (pa_safe_streq(pref_out_role, pa_tz_device_get_role(dm_device, pref_out_role)))
922 out_device_id = pa_tz_device_get_id(dm_device);
927 pa_log_info("preferred IN device: type[%s] role[%s] id[%u]", pref_in_type, pref_in_role, in_device_id);
928 pa_log_info("preferred OUT device: type[%s] role[%s] id[%u]", pref_out_type, pref_out_role, out_device_id);
931 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id, DBUS_TYPE_INVALID));
932 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &out_device_id, DBUS_TYPE_INVALID));
933 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
934 pa_assert_se(dbus_connection_send(conn, reply, NULL));
935 dbus_message_unref(reply);
938 static uint32_t get_num_of_target_streams(pa_stream_manager *m, pa_idxset *streams, stream_direction_t direction, const char *role) {
948 PA_IDXSET_FOREACH(s, streams, idx) {
949 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
950 PA_SINK_INPUT(s)->proplist : PA_SOURCE_OUTPUT(s)->proplist, PA_PROP_MEDIA_ROLE);
951 if (pa_safe_streq(_role, role))
957 static void routing_process_to_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
966 pa_assert(tz_device);
968 count = get_num_of_target_streams(m, (direction == STREAM_DIRECTION_OUT) ?
969 m->core->sink_inputs : m->core->source_outputs,
971 PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
972 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
973 PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
974 if (!pa_safe_streq(_role, role))
977 /* move stream to the preemptive device */
978 device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
979 tz_device->playback_devices : tz_device->capture_devices);
980 if (direction == STREAM_DIRECTION_OUT) {
981 pa_sink_input_move_to(stream, PA_SINK(device), false);
982 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT),
983 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
985 pa_source_output_move_to(stream, PA_SOURCE(device), false);
986 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT),
987 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
992 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
993 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
998 static void rollback_process_from_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
1004 const char *active_device = NULL;
1009 pa_assert(tz_device);
1011 device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
1012 tz_device->playback_devices : tz_device->capture_devices);
1014 PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? PA_SINK(device)->inputs : PA_SOURCE(device)->outputs, idx) {
1015 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
1016 PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
1017 if (!pa_safe_streq(_role, role))
1021 /* find and set new device */
1022 do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
1023 (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
1025 new_device = (direction == STREAM_DIRECTION_OUT) ? (void*)(PA_SINK_INPUT(stream)->sink) :
1026 (void*)(PA_SOURCE_OUTPUT(stream)->source);
1027 active_device = pa_proplist_gets(GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT),
1028 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
1029 /* change routing */
1030 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
1031 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1033 if (direction == STREAM_DIRECTION_OUT)
1034 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1036 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1041 /* move stream to the new device */
1042 if (direction == STREAM_DIRECTION_OUT) {
1043 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1045 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1047 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1049 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1054 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1055 const char *stream_type = NULL;
1056 const char *device_direction = NULL;
1057 stream_direction_t direction;
1058 uint32_t device_id = 0;
1059 stream_info *s = NULL;
1060 pa_tz_device *device = NULL;
1061 char *device_type = NULL;
1062 const char *prev_device_type = NULL;
1063 uint32_t prev_device_id = 0;
1066 ret_msg_t ret = RET_MSG_OK;
1067 DBusMessage *reply = NULL;
1069 pa_stream_manager *m = (pa_stream_manager*)userdata;
1075 pa_assert_se(dbus_message_get_args(msg, NULL,
1076 DBUS_TYPE_STRING, &stream_type,
1077 DBUS_TYPE_STRING, &device_direction,
1078 DBUS_TYPE_UINT32, &device_id,
1079 DBUS_TYPE_INVALID));
1080 pa_log_info("stream type[%s], device direction[%s], device_id[%u]", stream_type, device_direction, device_id);
1082 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1084 if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1085 pa_log_error("could not find this stream type(%s)", stream_type);
1086 ret = RET_MSG_ERROR_INTERNAL;
1090 if (pa_safe_streq(device_direction, "in"))
1091 direction = STREAM_DIRECTION_IN;
1092 else if (pa_safe_streq(device_direction, "out"))
1093 direction = STREAM_DIRECTION_OUT;
1095 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1099 /* allow only auto routing type */
1100 if (s->route_type != STREAM_ROUTE_TYPE_AUTO &&
1101 s->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1102 pa_log_error("not allowed this route type[%d]", s->route_type);
1103 ret = RET_MSG_ERROR_POLICY;
1107 if (device_id > 0) {
1108 if (!(device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
1109 pa_log_error("could not get device by id[%u]", device_id);
1110 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1114 PA_IDXSET_FOREACH(device_type, (direction == STREAM_DIRECTION_OUT) ? s->idx_avail_out_devices : s->idx_avail_in_devices, idx) {
1115 if (pa_safe_streq(device_type, device->type)) {
1121 pa_log_error("not supported this device type[%s]", device->type);
1122 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1127 if (device_id == 0 && s->preemptive_device[direction].id == 0) {
1128 pa_log_debug("there's no preemptive device, nothing to do");
1132 prev_device_type = s->preemptive_device[direction].type;
1133 prev_device_id = s->preemptive_device[direction].id;
1134 s->preemptive_device[direction].type = device_id > 0 ? device->type : NULL;
1135 s->preemptive_device[direction].id = device_id;
1137 pa_log_info("preemptive [%s] device is set, [%s, id:%u]",
1138 direction == STREAM_DIRECTION_OUT ? "out" : "in",
1139 device_id > 0 ? device->type : NULL,
1142 /* move streams and change routing */
1143 if (device_id == 0) {
1144 if (!(device = pa_device_manager_get_device_by_id(m->dm, prev_device_id)) || !pa_safe_streq(device->type, prev_device_type)) {
1145 pa_log_debug("could not find the previous device of id[%u], type[%s], nothing to do.", prev_device_id, prev_device_type);
1148 rollback_process_from_preemptive_device(m, direction, stream_type, device);
1150 routing_process_to_preemptive_device(m, direction, stream_type, device);
1154 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1155 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1156 dbus_message_unref(reply);
1159 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1160 const char *stream_type = NULL;
1161 stream_info *s = NULL;
1162 uint32_t in_device_id = 0;
1163 uint32_t out_device_id = 0;
1164 const char *in_device_type;
1165 const char *out_device_type;
1166 ret_msg_t ret = RET_MSG_OK;
1167 DBusMessage *reply = NULL;
1169 pa_stream_manager *m = (pa_stream_manager*)userdata;
1175 pa_assert_se(dbus_message_get_args(msg, NULL,
1176 DBUS_TYPE_STRING, &stream_type,
1177 DBUS_TYPE_INVALID));
1178 pa_log_info("stream type[%s]", stream_type);
1180 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1182 if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1183 pa_log_error("could not find this stream type(%s)", stream_type);
1184 ret = RET_MSG_ERROR_INTERNAL;
1188 in_device_id = s->preemptive_device[STREAM_DIRECTION_IN].id;
1189 in_device_type = s->preemptive_device[STREAM_DIRECTION_IN].type;
1190 out_device_id = s->preemptive_device[STREAM_DIRECTION_OUT].id;
1191 out_device_type = s->preemptive_device[STREAM_DIRECTION_OUT].type;
1193 pa_log_info("preemptive IN device: type[%s] id[%u]", in_device_type, in_device_id);
1194 pa_log_info("preemptive OUT device: type[%s] id[%u]", out_device_type, out_device_id);
1197 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id, DBUS_TYPE_INVALID));
1198 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &out_device_id, DBUS_TYPE_INVALID));
1199 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1200 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1201 dbus_message_unref(reply);
1204 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1205 const char *direction = NULL;
1206 const char *type = NULL;
1208 stream_type_t stream_type = STREAM_SINK_INPUT;
1209 DBusMessage *reply = NULL;
1210 pa_stream_manager *m = (pa_stream_manager*)userdata;
1212 ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1218 pa_assert_se(dbus_message_get_args(msg, NULL,
1219 DBUS_TYPE_STRING, &direction,
1220 DBUS_TYPE_STRING, &type,
1221 DBUS_TYPE_UINT32, &level,
1222 DBUS_TYPE_INVALID));
1223 pa_log_info("direction[%s], type[%s], level[%u]", direction, type, level);
1225 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1227 if (pa_safe_streq(direction, "in"))
1228 stream_type = STREAM_SOURCE_OUTPUT;
1229 else if (pa_safe_streq(direction, "out"))
1230 stream_type = STREAM_SINK_INPUT;
1232 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1237 /* check vconf update here, volume will not be set if update fails */
1238 if ((ret = update_volume_vconf(type, level))) {
1239 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1243 if ((ret = set_volume_level_by_type(m, stream_type, type, level))) {
1245 ret_msg = RET_MSG_ERROR_INVALID_ARGUMENT;
1246 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1248 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1252 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1253 dbus_message_unref(reply);
1256 send_volume_changed_signal(conn, direction, type, level);
1259 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1260 const char *direction = NULL;
1261 const char *type = NULL;
1263 stream_type_t stream_type = STREAM_SINK_INPUT;
1264 DBusMessage *reply = NULL;
1265 pa_stream_manager *m = (pa_stream_manager*)userdata;
1271 pa_assert_se(dbus_message_get_args(msg, NULL,
1272 DBUS_TYPE_STRING, &direction,
1273 DBUS_TYPE_STRING, &type,
1274 DBUS_TYPE_INVALID));
1275 pa_log_info("direction[%s], type[%s]", direction, type);
1277 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1279 if (pa_safe_streq(direction, "in"))
1280 stream_type = STREAM_SOURCE_OUTPUT;
1281 else if (pa_safe_streq(direction, "out"))
1282 stream_type = STREAM_SINK_INPUT;
1284 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1285 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1289 if (get_volume_level_by_type(m, GET_VOLUME_CURRENT_LEVEL, stream_type, type, &level)) {
1290 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1291 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1293 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1294 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1298 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1299 dbus_message_unref(reply);
1302 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1303 const char *direction = NULL;
1304 const char *type = NULL;
1306 stream_type_t stream_type = STREAM_SINK_INPUT;
1307 DBusMessage *reply = NULL;
1308 pa_stream_manager *m = (pa_stream_manager*)userdata;
1314 pa_assert_se(dbus_message_get_args(msg, NULL,
1315 DBUS_TYPE_STRING, &direction,
1316 DBUS_TYPE_STRING, &type,
1317 DBUS_TYPE_INVALID));
1318 pa_log_info("direction[%s], type[%s]", direction, type);
1320 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1322 if (pa_safe_streq(direction, "in"))
1323 stream_type = STREAM_SOURCE_OUTPUT;
1324 else if (pa_safe_streq(direction, "out"))
1325 stream_type = STREAM_SINK_INPUT;
1327 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1328 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1332 if (get_volume_level_by_type(m, GET_VOLUME_MAX_LEVEL, stream_type, type, &level)) {
1333 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1334 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1336 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1337 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1340 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1341 dbus_message_unref(reply);
1344 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1345 const char *direction = NULL;
1346 const char *type = NULL;
1347 uint32_t do_mute = 0;
1348 stream_type_t stream_type = STREAM_SINK_INPUT;
1349 DBusMessage *reply = NULL;
1350 pa_stream_manager *m = (pa_stream_manager*)userdata;
1357 pa_assert_se(dbus_message_get_args(msg, NULL,
1358 DBUS_TYPE_STRING, &direction,
1359 DBUS_TYPE_STRING, &type,
1360 DBUS_TYPE_UINT32, &do_mute,
1361 DBUS_TYPE_INVALID));
1362 pa_log_info("direction[%s], type[%s], do_mute[%u]", direction, type, do_mute);
1364 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1366 if (pa_safe_streq(direction, "in"))
1367 stream_type = STREAM_SOURCE_OUTPUT;
1368 else if (pa_safe_streq(direction, "out"))
1369 stream_type = STREAM_SINK_INPUT;
1371 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1375 /* check vconf update here, mute will not be set if update fails */
1376 if ((ret = update_mute_vconf(type, do_mute))) {
1377 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1381 if (set_volume_mute_by_type(m, stream_type, type, (bool)do_mute))
1382 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1384 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1387 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1388 dbus_message_unref(reply);
1391 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1392 const char *direction = NULL;
1393 const char *type = NULL;
1394 uint32_t is_muted = 0;
1395 stream_type_t stream_type = STREAM_SINK_INPUT;
1396 DBusMessage *reply = NULL;
1397 pa_stream_manager *m = (pa_stream_manager*)userdata;
1403 pa_assert_se(dbus_message_get_args(msg, NULL,
1404 DBUS_TYPE_STRING, &direction,
1405 DBUS_TYPE_STRING, &type,
1406 DBUS_TYPE_INVALID));
1407 pa_log_info("direction[%s], type[%s]", direction, type);
1409 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1411 if (pa_safe_streq(direction, "in"))
1412 stream_type = STREAM_SOURCE_OUTPUT;
1413 else if (pa_safe_streq(direction, "out"))
1414 stream_type = STREAM_SINK_INPUT;
1416 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1417 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1421 if (get_volume_mute_by_type(m, stream_type, type, (bool*)&is_muted)) {
1422 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1423 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1425 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1426 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1430 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1431 dbus_message_unref(reply);
1434 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1435 const char *direction = NULL;
1438 stream_type_t stream_type = STREAM_SINK_INPUT;
1439 DBusMessage *reply = NULL;
1440 pa_stream_manager *m = (pa_stream_manager*)userdata;
1442 ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1448 pa_assert_se(dbus_message_get_args(msg, NULL,
1449 DBUS_TYPE_STRING, &direction,
1450 DBUS_TYPE_UINT32, &idx,
1451 DBUS_TYPE_DOUBLE, &ratio,
1452 DBUS_TYPE_INVALID));
1453 pa_log_info("direction[%s], idx[%u], ratio[%f]", direction, idx, ratio);
1455 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1457 if (pa_safe_streq(direction, "in"))
1458 stream_type = STREAM_SOURCE_OUTPUT;
1459 else if (pa_safe_streq(direction, "out"))
1460 stream_type = STREAM_SINK_INPUT;
1462 pa_log_error("invalid direction[%s]", direction);
1463 goto invalid_argument;
1466 /* Check the ratio range (0.0 ~ 1.0) */
1467 if (ratio < 0 || ratio > 1) {
1468 pa_log_error("invalid range, ratio[%f]", ratio);
1469 goto invalid_argument;
1472 if ((ret = set_volume_ratio_by_idx(m, stream_type, idx, ratio))) {
1474 ret_msg = RET_MSG_ERROR_NO_STREAM;
1475 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1477 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1480 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1481 dbus_message_unref(reply);
1485 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
1486 DBUS_TYPE_INVALID));
1487 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1488 dbus_message_unref(reply);
1491 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1492 const char *direction = NULL;
1495 stream_type_t stream_type = STREAM_SINK_INPUT;
1496 DBusMessage *reply = NULL;
1497 pa_stream_manager *m = (pa_stream_manager*)userdata;
1503 pa_assert_se(dbus_message_get_args(msg, NULL,
1504 DBUS_TYPE_STRING, &direction,
1505 DBUS_TYPE_UINT32, &idx,
1506 DBUS_TYPE_INVALID));
1507 pa_log_info("direction[%s], idx[%u]", direction, idx);
1509 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1511 if (pa_safe_streq(direction, "in"))
1512 stream_type = STREAM_SOURCE_OUTPUT;
1513 else if (pa_safe_streq(direction, "out"))
1514 stream_type = STREAM_SINK_INPUT;
1516 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1517 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT], DBUS_TYPE_INVALID));
1521 if (get_volume_ratio_by_idx(m, stream_type, idx, &ratio)) {
1522 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1523 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
1525 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1526 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1530 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1531 dbus_message_unref(reply);
1534 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1535 const char *direction = NULL;
1536 const char *type = NULL;
1538 stream_type_t stream_type = STREAM_SINK_INPUT;
1539 DBusMessage *reply = NULL;
1540 pa_stream_manager *m = (pa_stream_manager*)userdata;
1542 pa_idxset *streams = NULL;
1548 pa_assert_se(dbus_message_get_args(msg, NULL,
1549 DBUS_TYPE_STRING, &direction,
1550 DBUS_TYPE_INVALID));
1551 pa_log_info("direction[%s]", direction);
1553 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1555 if (pa_safe_streq(direction, "in")) {
1556 stream_type = STREAM_SOURCE_OUTPUT;
1557 streams = m->core->source_outputs;
1558 } else if (pa_safe_streq(direction, "out")) {
1559 stream_type = STREAM_SINK_INPUT;
1560 streams = m->core->sink_inputs;
1562 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1563 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1567 /* Get a volume type of a stream that has the max priority role among all the running streams regardless of devices.
1568 Note that it does not represent any focus status of a stream rather only checking the priority of it */
1569 if (pa_idxset_size(streams)) {
1570 int cur_max_priority = 0;
1571 const char *cur_max_type = NULL;
1572 const char *role = NULL;
1573 stream_info *s_info;
1575 PA_IDXSET_FOREACH(s, streams, idx) {
1576 if (!CHECK_STREAM_RUNNING(s, stream_type))
1578 if (!(type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE)))
1580 if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE)))
1582 if ((s_info = pa_hashmap_get(m->stream_infos, role))) {
1583 if (s_info->priority >= cur_max_priority) {
1584 cur_max_priority = s_info->priority;
1585 cur_max_type = type;
1586 pa_log_info("updated, volume type of the max priority stream(%u): %s", GET_STREAM_INDEX(s, stream_type), cur_max_type);
1590 type = cur_max_type;
1594 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID));
1595 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1597 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1598 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
1602 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1603 dbus_message_unref(reply);
1606 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1607 const char *direction = NULL;
1608 const char *device_type = NULL;
1609 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
1610 stream_info *s = NULL;
1611 DBusMessage *reply = NULL;
1612 pa_tz_device *device = NULL;
1613 pa_stream_manager *m = (pa_stream_manager*)userdata;
1619 pa_assert_se(dbus_message_get_args(msg, NULL,
1620 DBUS_TYPE_STRING, &direction,
1621 DBUS_TYPE_INVALID));
1622 pa_log_info("direction[%s]", direction);
1624 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1626 if (pa_safe_streq(direction, "in")) {
1627 dm_device_direction = DM_DEVICE_DIRECTION_IN;
1628 } else if (pa_safe_streq(direction, "out")) {
1629 dm_device_direction = DM_DEVICE_DIRECTION_OUT;
1631 pa_log_error("invalid direction[%s]", direction);
1635 if ((s = pa_hashmap_get(m->stream_infos, STREAM_ROLE_MEDIA)) == NULL) {
1636 pa_log_error("could not find media role");
1640 if (s->route_type == STREAM_ROUTE_TYPE_AUTO) {
1641 device = get_media_auto_device(m, dm_device_direction);
1642 } else if (s->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1643 device = get_media_last_device(m, dm_device_direction);
1645 pa_log_error("unexpected routing type for media[%d]", s->route_type);
1650 device_type = pa_tz_device_get_type(device);
1653 pa_log_error("could not found matched device");
1657 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1658 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1659 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1660 dbus_message_unref(reply);
1663 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_type, DBUS_TYPE_INVALID));
1664 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1665 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1666 dbus_message_unref(reply);
1669 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1673 uint32_t acquired_focus_status = 0;
1674 stream_parent *sp = NULL;
1675 void *stream = NULL;
1676 DBusMessage *reply = NULL;
1677 pa_stream_manager *m = (pa_stream_manager*)userdata;
1678 int prev_status = STREAM_FOCUS_ACQUIRED_NONE;
1684 pa_assert_se(dbus_message_get_args(msg, NULL,
1685 DBUS_TYPE_UINT32, &id,
1686 DBUS_TYPE_UINT32, &acquired_focus_status,
1687 DBUS_TYPE_INVALID));
1688 pa_log_info("id[%u], acquired_focus_status[0x%x]", id, acquired_focus_status);
1690 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1692 if ((sp = pa_hashmap_get(m->stream_parents, (const void*)id))) {
1693 if (sp->focus_status != acquired_focus_status) {
1694 /* need to update */
1695 prev_status = sp->focus_status;
1696 sp->focus_status = acquired_focus_status;
1697 if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_PLAYBACK) && sp->idx_sink_inputs) {
1698 count = pa_idxset_size(sp->idx_sink_inputs);
1699 PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
1700 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1701 GET_FOCUS_STATUS(sp->focus_status, STREAM_SINK_INPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1703 process_stream(m, stream, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1706 if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_CAPTURE) && sp->idx_source_outputs) {
1707 count = pa_idxset_size(sp->idx_source_outputs);
1708 PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
1709 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1710 GET_FOCUS_STATUS(sp->focus_status, STREAM_SOURCE_OUTPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1712 process_stream(m, stream, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1716 pa_log_debug("same as before, skip updating focus status[0x%x]", acquired_focus_status);
1719 pa_log_error("could not find matching client for this parent_id[%u]", id);
1720 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1723 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1725 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1726 dbus_message_unref(reply);
1729 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1732 uint32_t acquired_focus_status = 0;
1733 int32_t focus_id = 0;
1734 const char *focus_id_str;
1735 pa_sink_input *i = NULL;
1736 DBusMessage *reply = NULL;
1737 pa_stream_manager *m = (pa_stream_manager*)userdata;
1743 pa_assert_se(dbus_message_get_args(msg, NULL,
1744 DBUS_TYPE_INT32, &id,
1745 DBUS_TYPE_UINT32, &acquired_focus_status,
1746 DBUS_TYPE_INVALID));
1747 pa_log_info("id[%d], acquired_focus_status[0x%x]", id, acquired_focus_status);
1749 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1751 /* Currently, we only support sink-inputs */
1752 PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
1753 if ((focus_id_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_ID))) {
1754 if (pa_atoi(focus_id_str, &focus_id))
1756 if (id == focus_id) {
1757 pa_log_info("found matching sink-input(%p, %u) - focus_id(%d)", i, i->index, id);
1758 pa_proplist_sets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1759 acquired_focus_status ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1760 process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1762 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1767 pa_log_error("could not find matching stream for this focus_id[%i]", id);
1768 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1770 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1771 dbus_message_unref(reply);
1774 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1777 DBusMessage *reply = NULL;
1778 pa_stream_manager *m = (pa_stream_manager*)userdata;
1784 pa_assert_se(dbus_message_get_args(msg, NULL,
1785 DBUS_TYPE_STRING, &name,
1786 DBUS_TYPE_UINT32, &value,
1787 DBUS_TYPE_INVALID));
1788 pa_log_info("name[%s], value[%u]", name, value);
1790 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1792 if (handle_restrictions(m, name, value) < 0) {
1793 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1797 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1799 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1800 dbus_message_unref(reply);
1803 #define MAX_CALL_PARAM_SIZE 32
1804 static int32_t parse_call_parameters(const char *parameters, char *call_type, char *call_domain, char *network_band) {
1805 const char delimiter[] = ";";
1806 char *token, *ptr = NULL;
1809 pa_assert(parameters);
1810 pa_assert(call_type);
1811 pa_assert(call_domain);
1812 pa_assert(network_band);
1814 pa_log_info("parameters[%s]", parameters);
1816 /*Reset the call parameters*/
1817 memset(call_type, 0, MAX_CALL_PARAM_SIZE);
1818 memset(call_domain, 0, MAX_CALL_PARAM_SIZE);
1819 memset(network_band, 0, MAX_CALL_PARAM_SIZE);
1822 token = strtok_r((char *)parameters, delimiter, &ptr);
1824 char *delimiter_ptr = NULL;
1827 delimiter_ptr = strstr(token, "=");
1828 if (!delimiter_ptr) {
1829 token = strtok_r(NULL, delimiter, &ptr);
1832 strncpy(key, token, delimiter_ptr - token);
1833 value = delimiter_ptr + 1;
1834 pa_log_debug("key(%s), value(%s)", key, value);
1835 if (!strncmp(key, "call-type", strlen("call-type")))
1836 pa_strlcpy(call_type, value, MAX_CALL_PARAM_SIZE);
1837 else if (!strncmp(key, "call-domain", strlen("call-domain")))
1838 pa_strlcpy(call_domain, value, MAX_CALL_PARAM_SIZE);
1839 else if (!strncmp(key, "network-band", strlen("network-band")))
1840 pa_strlcpy(network_band, value, MAX_CALL_PARAM_SIZE);
1842 pa_log_warn("not supported key(%s)", key);
1844 token = strtok_r(NULL, delimiter, &ptr);
1845 memset(key, 0, sizeof(key));
1847 pa_log_info("call-type[%s], call-domain[%s], network-band[%s]", call_type, call_domain, network_band);
1853 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1854 const char *parameters;
1855 DBusMessage *reply = NULL;
1856 pa_stream_manager *m = (pa_stream_manager*)userdata;
1857 char call_type[MAX_CALL_PARAM_SIZE] = {0,};
1858 char call_domain[MAX_CALL_PARAM_SIZE] = {0,};
1859 char network_band[MAX_CALL_PARAM_SIZE] = {0,};
1860 stream_route_option route_option;
1861 ret_msg_t ret = RET_MSG_OK;
1867 pa_assert_se(dbus_message_get_args(msg, NULL,
1868 DBUS_TYPE_STRING, ¶meters,
1869 DBUS_TYPE_INVALID));
1870 pa_log_info("parameters[%s]", parameters);
1872 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1874 if (parse_call_parameters(parameters, call_type, call_domain, network_band) < 0) {
1875 ret = RET_MSG_ERROR_INTERNAL;
1879 pa_log_debug("call_type[%s], call_domain[%s], network_band[%s]", call_type, call_domain, network_band);
1881 /* Currently, we only use network band */
1882 route_option.name = "call-wideband";
1883 if (pa_safe_streq(network_band, "wb"))
1884 route_option.value = 1;
1886 route_option.value = 0;
1887 ret = do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
1890 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1891 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1892 dbus_message_unref(reply);
1895 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1896 const char *filter_name, *filter_parameters, *filter_group, *stream_type;
1897 DBusMessage *reply = NULL;
1898 pa_stream_manager *m = (pa_stream_manager*)userdata;
1904 pa_assert_se(dbus_message_get_args(msg, NULL,
1905 DBUS_TYPE_STRING, &filter_name,
1906 DBUS_TYPE_STRING, &filter_parameters,
1907 DBUS_TYPE_STRING, &filter_group,
1908 DBUS_TYPE_STRING, &stream_type,
1909 DBUS_TYPE_INVALID));
1910 pa_log_info("filter_name[%s], filter_parameters[%s], filter_group[%s], stream_type[%s]", filter_name,
1911 filter_parameters, filter_group, stream_type);
1913 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1915 /* Set filter sink according to stream type */
1916 if (update_filter(m, filter_name, filter_parameters, filter_group, stream_type) < 0) {
1917 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1918 DBUS_TYPE_INVALID));
1922 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1923 DBUS_TYPE_INVALID));
1926 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1927 dbus_message_unref(reply);
1930 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1931 const char *stream_type;
1932 DBusMessage *reply = NULL;
1933 pa_stream_manager *m = (pa_stream_manager*)userdata;
1939 pa_assert_se(dbus_message_get_args(msg, NULL,
1940 DBUS_TYPE_STRING, &stream_type,
1941 DBUS_TYPE_INVALID));
1942 pa_log_info("stream_type[%s]", stream_type);
1944 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1946 /* Unset filter sink according to stream type */
1947 if (update_filter(m, NULL, NULL, NULL, stream_type) < 0) {
1948 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1949 DBUS_TYPE_INVALID));
1953 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1954 DBUS_TYPE_INVALID));
1957 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1958 dbus_message_unref(reply);
1961 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1962 const char *filter_name, *filter_controls, *stream_type;
1963 DBusMessage *reply = NULL;
1964 pa_stream_manager *m = (pa_stream_manager*)userdata;
1970 pa_assert_se(dbus_message_get_args(msg, NULL,
1971 DBUS_TYPE_STRING, &filter_name,
1972 DBUS_TYPE_STRING, &filter_controls,
1973 DBUS_TYPE_STRING, &stream_type,
1974 DBUS_TYPE_INVALID));
1975 pa_log_info("filter_name[%s], filter_controls[%s], stream_type[%s]", filter_name, filter_controls, stream_type);
1977 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1979 /* Control parameters to filter sink */
1980 if (control_filter(m, filter_name, filter_controls, stream_type, conn) < 0) {
1981 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1982 DBUS_TYPE_INVALID));
1986 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1987 DBUS_TYPE_INVALID));
1989 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1990 dbus_message_unref(reply);
1993 static bool check_stream_exist_by_pid(pa_stream_manager *m, uint32_t pid, const char *stream_role, stream_type_t type) {
1994 void *stream = NULL;
1996 const char *role = NULL;
1997 const char *app_pid_str = NULL;
1998 uint32_t app_pid = 0;
2001 pa_assert(stream_role);
2003 pa_log_info("pid[%u], role[%s], type[%d]", pid, stream_role, type);
2005 PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
2006 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2007 if (!pa_safe_streq(role, stream_role))
2010 if (!CHECK_STREAM_RUNNING(stream, type)) {
2011 pa_log_info("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
2015 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
2016 if (app_pid_str && !pa_atou(app_pid_str, &app_pid)) {
2017 if (app_pid == pid) {
2018 pa_log_info("found matching stream(%p, index:%u)", stream, GET_STREAM_INDEX(stream, type));
2027 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2030 const char *direction;
2031 stream_type_t stream_type = STREAM_SINK_INPUT;
2032 DBusMessage *reply = NULL;
2033 pa_stream_manager *m = (pa_stream_manager*)userdata;
2039 pa_assert_se(dbus_message_get_args(msg, NULL,
2040 DBUS_TYPE_UINT32, &pid,
2041 DBUS_TYPE_STRING, &type,
2042 DBUS_TYPE_STRING, &direction,
2043 DBUS_TYPE_INVALID));
2044 pa_log_info("pid[%u], type[%s], direction[%s]", pid, type, direction);
2046 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2048 if (pa_safe_streq(direction, "in"))
2049 stream_type = STREAM_SOURCE_OUTPUT;
2050 else if (pa_safe_streq(direction, "out"))
2051 stream_type = STREAM_SINK_INPUT;
2053 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
2054 DBUS_TYPE_INVALID));
2058 if (!check_stream_exist_by_pid(m, pid, type, stream_type)) {
2059 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM],
2060 DBUS_TYPE_INVALID));
2064 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
2065 DBUS_TYPE_INVALID));
2067 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2068 dbus_message_unref(reply);
2071 static bool find_the_lastest_stream(pa_stream_manager *m, stream_type_t type, const char ** stream_roles, int length, uint32_t *pid) {
2072 void *stream = NULL;
2075 const char *app_pid_str = NULL;
2076 uint32_t latest_pid = 0;
2077 pa_usec_t latest_time = 0;
2078 uint32_t tmp_pid = 0;
2079 pa_usec_t tmp_time = 0;
2083 pa_assert(stream_roles);
2086 PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
2087 if (!CHECK_STREAM_RUNNING(stream, type)) {
2088 pa_log_debug("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
2092 for (i = 0; i <length; i++) {
2096 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2097 if (!pa_safe_streq(stream_roles[i], role))
2100 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID_ORIGIN);
2101 if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid)) {
2102 pa_log_debug("found a stream(pid.origin:%u, index:%u) that matches requested stream role[%s]", tmp_pid, GET_STREAM_INDEX(stream, type), stream_roles[i]);
2104 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
2105 if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid))
2106 pa_log_debug("found a stream(pid:%u, index:%u) that matches requested stream role[%s]", tmp_pid, GET_STREAM_INDEX(stream, type), stream_roles[i]);
2109 tmp_time = GET_STREAM_LAST_RUN_TIME(stream, type);
2110 if (latest_time <= tmp_time) {
2111 latest_time = tmp_time;
2112 latest_pid = tmp_pid;
2118 if (latest_pid > 0) {
2120 pa_log_info("found the stream(pid:%u)", *pid);
2124 pa_log_info("no match is found");
2128 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2129 const char *direction;
2132 stream_type_t stream_type = STREAM_SINK_INPUT;
2134 ret_msg_t ret_msg = RET_MSG_OK;
2136 DBusMessage *reply = NULL;
2137 pa_stream_manager *m = (pa_stream_manager*)userdata;
2143 pa_assert_se(dbus_message_get_args(msg, NULL,
2144 DBUS_TYPE_STRING, &direction,
2145 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &types, &length,
2146 DBUS_TYPE_INVALID));
2148 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2150 if (pa_safe_streq(direction, "in"))
2151 stream_type = STREAM_SOURCE_OUTPUT;
2152 else if (pa_safe_streq(direction, "out"))
2153 stream_type = STREAM_SINK_INPUT;
2155 pa_log_error("invalid direction[%s]", direction);
2156 goto invalid_argument;
2160 pa_log_error("At least one stream type should be contained");
2161 goto invalid_argument;
2164 if (!find_the_lastest_stream(m, stream_type, types, length, &pid))
2165 ret_msg = RET_MSG_ERROR_NO_STREAM;
2167 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID));
2168 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg],
2169 DBUS_TYPE_INVALID));
2170 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2171 dbus_message_unref(reply);
2175 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID));
2176 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
2177 DBUS_TYPE_INVALID));
2178 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2179 dbus_message_unref(reply);
2182 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2183 dbus_uint32_t id = 0;
2184 dbus_bool_t enable = 0;
2185 const char *target_stream = NULL;
2187 pa_sink_input *i = NULL;
2188 dbus_uint32_t duration = 0;
2190 DBusMessage *reply = NULL;
2191 pa_stream_manager *m = (pa_stream_manager*)userdata;
2193 pa_cvolume_ramp vol_ramp;
2194 stream_ducking *sd = NULL;
2195 hal_ducking_activation_info ducking_activation_info;
2196 ret_msg_t ret_msg = RET_MSG_OK;
2202 pa_assert_se(dbus_message_get_args(msg, NULL,
2203 DBUS_TYPE_UINT32, &id,
2204 DBUS_TYPE_BOOLEAN, &enable,
2205 DBUS_TYPE_STRING, &target_stream,
2206 DBUS_TYPE_UINT32, &duration,
2207 DBUS_TYPE_DOUBLE, &ratio,
2208 DBUS_TYPE_INVALID));
2210 pa_log_info("id[%u], enable[%u], target stream[%s], duration[%u], ratio[%lf]",
2211 id, enable, target_stream, duration, ratio);
2213 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2215 /* get stream_ducking */
2216 sd = pa_hashmap_get(m->stream_duckings, (const void*)id);
2218 pa_log_error("no matched stream ducking for id[%u]", id);
2219 ret_msg = RET_MSG_ERROR_INTERNAL;
2220 goto _ACTIVATE_DUCKING_DONE;
2223 /* validate state with command */
2224 if ((enable && sd->state != STREAM_DUCKING_STATE_UNDUCKED) ||
2225 (!enable && sd->state != STREAM_DUCKING_STATE_DUCKED)) {
2226 pa_log_error("state validation failed - [%d,s:%u]", enable, sd->state);
2227 ret_msg = RET_MSG_ERROR_INVALID_STATE;
2228 goto _ACTIVATE_DUCKING_DONE;
2231 sd->duration = duration;
2233 sd->set_vol = PA_VOLUME_NORM * ratio;
2236 sd->state = STREAM_DUCKING_STATE_DUCKING;
2237 snprintf(sd->vol_key, VOLUME_KEY_LENGTH, "stream_ducking_%u_%s", id, target_stream);
2238 snprintf(sd->target_role, STREAM_ROLE_STR_MAX, "%s", target_stream);
2240 sd->state = STREAM_DUCKING_STATE_UNDUCKING;
2243 /* set volume ramp factor to target stream */
2244 PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
2245 if (!pa_safe_streq(target_stream, pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
2248 if (i->state == PA_SINK_INPUT_RUNNING)
2249 sd->ducking_stream_count++;
2252 pa_idxset_put(sd->idx_ducking_streams, (void *)i, NULL);
2254 pa_log_error("ducking: add volume_ramp factor, key[%s], set_vol[%u] to stream[idx:%u]",
2255 sd->vol_key, sd->set_vol, i->index);
2257 pa_cvolume_ramp_set(&vol_ramp, i->volume.channels,
2258 PA_VOLUME_RAMP_TYPE_LINEAR, (long)duration, sd->set_vol);
2260 if (i->state != PA_SINK_INPUT_RUNNING || duration == 0) {
2261 pa_cvolume_set(&vol, i->volume.channels, sd->set_vol);
2262 pa_sink_input_add_volume_factor(i, sd->vol_key, &vol);
2263 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, false);
2265 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, true);
2268 pa_log_error("unducking: remove volume(ramp) factor, key[%s] from stream[idx:%u]",
2269 sd->vol_key, i->index);
2271 pa_sink_input_remove_volume_factor(i, sd->vol_key);
2272 pa_sink_input_remove_volume_ramp_factor(i, sd->vol_key, true);
2277 memset(&sd->target_role, 0, sizeof(sd->target_role));
2278 memset(&sd->vol_key, 0, sizeof(sd->vol_key));
2281 pa_log_info("ducking stream count[%p,%d]", sd, sd->ducking_stream_count);
2283 _ACTIVATE_DUCKING_DONE:
2284 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
2285 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2286 dbus_message_unref(reply);
2288 if (ret_msg != RET_MSG_OK)
2291 /* notify ducking activation */
2292 ducking_activation_info.target_role = target_stream;
2293 ducking_activation_info.duration = duration;
2294 ducking_activation_info.ratio = ratio;
2295 ducking_activation_info.is_activated = enable;
2297 pa_hal_interface_notify_ducking_activation_changed(m->hal, &ducking_activation_info);
2299 if (sd->ducking_stream_count <= 0 || duration == 0) {
2300 /* change ducking state and send signal here,
2301 because ramp_finish_cb could not be called in this case. */
2303 sd->state = STREAM_DUCKING_STATE_DUCKED;
2305 sd->state = STREAM_DUCKING_STATE_UNDUCKED;
2307 pa_log_info("send signal for ramp finished - state[%u]", sd->state);
2309 /* It should be reset here because it's increased,
2310 but will not be decreased in case of 0 duration. */
2311 sd->ducking_stream_count = 0;
2313 send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
2317 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2318 dbus_uint32_t id = 0;
2319 DBusMessage *reply = NULL;
2320 pa_stream_manager *m = (pa_stream_manager*)userdata;
2321 stream_ducking *sd = NULL;
2322 dbus_bool_t is_ducked = FALSE;
2323 ret_msg_t ret_msg = RET_MSG_OK;
2329 pa_assert_se(dbus_message_get_args(msg, NULL,
2330 DBUS_TYPE_UINT32, &id,
2331 DBUS_TYPE_INVALID));
2333 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2335 /* get stream_ducking */
2336 sd = pa_hashmap_get(m->stream_duckings, (const void *)id);
2338 is_ducked = (dbus_bool_t)is_stream_ducked(sd);
2339 pa_log_info("id[%u], is_ducked[%p,%d]", id, sd, is_ducked);
2341 ret_msg = RET_MSG_ERROR_INTERNAL;
2342 pa_log_error("no matched stream ducking for id[%u]", id);
2345 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_ducked, DBUS_TYPE_INVALID));
2346 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
2348 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2349 dbus_message_unref(reply);
2352 static int dbus_launch_mdnsd(pa_stream_manager *m, DBusConnection *conn) {
2353 DBusMessage *msg, *reply;
2355 const char *name = NULL;
2357 pa_log_info("launching mdnsd");
2359 if (!(msg = dbus_message_new_method_call("net.netconfig",
2360 "/net/netconfig/network",
2361 "net.netconfig.network",
2363 pa_log_error("dbus method call failed");
2367 name = dbus_bus_get_unique_name(conn);
2368 pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
2370 dbus_error_init(&err);
2371 if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2372 pa_log_error("Failed to method call : %s", err.message);
2373 dbus_error_free(&err);
2377 dbus_message_unref(reply);
2379 pa_log_info("success");
2384 static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2385 pa_stream_manager *m = (pa_stream_manager*)userdata;
2386 dbus_uint32_t index;
2387 dbus_bool_t allowed;
2388 pa_proplist *p = NULL;
2395 pa_assert_se(dbus_message_get_args(msg, NULL,
2396 DBUS_TYPE_STRING, &type,
2397 DBUS_TYPE_UINT32, &index,
2398 DBUS_TYPE_BOOLEAN, &allowed,
2399 DBUS_TYPE_INVALID));
2402 pa_log_error("invalid arguments");
2406 pa_log_info("type(%s), index(%d), allowed(%d)", type, index, allowed);
2408 p = pa_proplist_new();
2410 pa_log_error("failed to create proplist");
2414 if (pa_proplist_set_remote_access_permission(p, allowed)) {
2415 pa_log_error("set remote access permission error");
2419 if (pa_streq(type, "sink-input")) {
2422 i = pa_idxset_get_by_index(m->core->sink_inputs, index);
2424 pa_log_error("not found sink-input");
2428 if (pa_proplist_remote_is_allowed(i->proplist) != allowed){
2429 pa_sink_input_update_proplist(i, PA_UPDATE_REPLACE, p);
2430 pa_sink_input_send_event(i, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
2433 } else if (pa_streq(type, "source-output")) {
2434 pa_source_output *o;
2436 o = pa_idxset_get_by_index(m->core->source_outputs, index);
2438 pa_log_error("not found source-output");
2442 if (pa_proplist_remote_is_allowed(o->proplist) != allowed){
2443 pa_source_output_update_proplist(o, PA_UPDATE_REPLACE, p);
2444 pa_source_output_send_event(o, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
2448 pa_log_warn("unknown type");
2453 pa_proplist_free(p);
2455 pa_dbus_send_empty_reply(conn, msg);
2458 static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2459 pa_stream_manager *m = (pa_stream_manager*)userdata;
2467 pa_assert_se(dbus_message_get_args(msg, NULL,
2468 DBUS_TYPE_BOOLEAN, &enable,
2469 DBUS_TYPE_INVALID));
2471 pa_log_info("discover module enable(%d)", enable);
2474 if (m->m_discover) {
2475 pa_log_error("already loaded");
2479 if (dbus_launch_mdnsd(m, conn) == -1) {
2480 pa_log_error("failed to launch mdnsd!!!");
2484 if (pa_module_load(&module, m->core, "module-tizenaudio-discover", NULL)) {
2485 pa_log_error("failed to load module");
2488 m->m_discover = module->index;
2490 if (m->m_discover) {
2491 pa_module_unload_request_by_index(m->core, m->m_discover, true);
2496 pa_dbus_send_empty_reply(conn, msg);
2501 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
2502 "org.tizen.multimedia.audio.Internal");
2505 static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2506 pa_stream_manager *m = (pa_stream_manager*)userdata;
2514 pa_assert_se(dbus_message_get_args(msg, NULL,
2515 DBUS_TYPE_BOOLEAN, &enable,
2516 DBUS_TYPE_INVALID));
2518 pa_log_info("publish module enable(%d)", enable);
2521 if (m->m_protocol_tcp || m->m_publish) {
2522 pa_log_error("already loaded");
2526 if (dbus_launch_mdnsd(m, conn) == -1) {
2527 pa_log_error("failed to launch mdnsd!!!");
2531 if (pa_module_load(&module, m->core, "module-native-protocol-tcp", "auth-anonymous=1")) {
2532 pa_log_error("failed to load module");
2535 m->m_protocol_tcp = module->index;
2537 if (pa_module_load(&module, m->core, "module-tizenaudio-publish", NULL)) {
2538 pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
2539 pa_log_error("failed to load module");
2542 m->m_publish = module->index;
2544 if (m->m_protocol_tcp) {
2545 pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
2546 m->m_protocol_tcp = 0;
2549 pa_module_unload_request_by_index(m->core, m->m_publish, true);
2554 pa_dbus_send_empty_reply(conn, msg);
2559 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
2560 "org.tizen.multimedia.audio.Internal");
2563 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2565 pa_stream_manager *m = (pa_stream_manager*)userdata;
2571 for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
2572 if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name)) {
2573 pa_log_debug("Message signature [%s] (Expected [%s])", dbus_message_get_signature(msg), signature_args_for_in[idx]);
2574 if (pa_safe_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
2575 method_handlers[idx].receive_cb(conn, msg, userdata);
2576 return DBUS_HANDLER_RESULT_HANDLED;
2578 pa_log_warn("Wrong Argument Signature");
2579 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE, "Wrong Signature, Expected %s", signature_args_for_in[idx]);
2580 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2585 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2588 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
2589 pa_stream_manager *u = (pa_stream_manager*)userdata;
2590 const char *path, *interface, *member;
2596 path = dbus_message_get_path(m);
2597 interface = dbus_message_get_interface(m);
2598 member = dbus_message_get_member(m);
2600 pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
2602 if (!pa_safe_streq(path, STREAM_MANAGER_OBJECT_PATH))
2603 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2605 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2606 return handle_introspect(c, m, u);
2608 return handle_methods(c, m, u);
2611 return DBUS_HANDLER_RESULT_HANDLED;
2614 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level) {
2615 DBusMessage *signal_msg;
2616 DBusMessageIter msg_iter;
2619 pa_assert(direction);
2620 pa_assert(volume_type);
2622 pa_log_debug("direction[%s], type[%s], level[%d]", direction, volume_type, volume_level);
2624 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED)));
2625 dbus_message_iter_init_append(signal_msg, &msg_iter);
2627 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &direction);
2628 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &volume_type);
2629 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &volume_level);
2631 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2632 dbus_message_unref(signal_msg);
2636 void send_ducking_state_changed_signal(DBusConnection *conn, const int index, const int is_ducked)
2638 DBusMessage *signal_msg;
2639 DBusMessageIter msg_iter;
2643 pa_log_debug("trigger_index(%d) : is_ducked(%d)", index, is_ducked);
2645 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_DUCKING_STATE_CHANGED)));
2646 dbus_message_iter_init_append(signal_msg, &msg_iter);
2648 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &index);
2649 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &is_ducked);
2651 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2652 dbus_message_unref(signal_msg);
2657 void send_command_signal(DBusConnection *conn, const char *name, int value) {
2658 DBusMessage *signal_msg;
2659 DBusMessageIter msg_iter;
2664 pa_log_debug("name[%s], value[%d]", name, value);
2666 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_COMMAND)));
2667 dbus_message_iter_init_append(signal_msg, &msg_iter);
2669 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2670 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &value);
2672 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2673 dbus_message_unref(signal_msg);
2676 void send_remote_found_signal(DBusConnection *conn, int type, bool connected, unsigned int index,
2677 const char *name, const char *description) {
2678 DBusMessage *signal_msg;
2679 DBusMessageIter msg_iter;
2680 dbus_bool_t c = (dbus_bool_t)connected;
2684 if (!name || !description) {
2685 pa_log_error("Unknown device");
2689 pa_log_info("type[%d], index[%d], connected[%d], name[%s] description[%s]", type, index, connected, name, description);
2691 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND)));
2692 dbus_message_iter_init_append(signal_msg, &msg_iter);
2694 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &type);
2695 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &index);
2696 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &c);
2697 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2698 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &description);
2700 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2701 dbus_message_unref(signal_msg);
2704 int32_t init_sm_dbus(pa_stream_manager *m) {
2707 #ifdef USE_DBUS_PROTOCOL
2708 m->dbus_protocol = pa_dbus_protocol_get(m->core);
2709 pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
2710 pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2713 pa_dbus_connection *conn = NULL;
2714 static const DBusObjectPathVTable vtable = {
2715 .message_function = method_handler_for_vt,
2718 dbus_error_init(&err);
2720 if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
2722 pa_dbus_connection_unref(conn);
2724 pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
2727 pa_log_notice("Got dbus connection");
2729 m->dbus_conn = conn;
2730 pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
2735 void deinit_sm_dbus(pa_stream_manager *m) {
2738 #ifdef USE_DBUS_PROTOCOL
2739 if (m->dbus_protocol) {
2740 pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2741 pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
2742 pa_dbus_protocol_unref(m->dbus_protocol);
2743 m->dbus_protocol = NULL;
2747 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
2748 pa_log_error("failed to unregister object path");
2750 pa_dbus_connection_unref(m->dbus_conn);
2751 m->dbus_conn = NULL;