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 "stream-manager-priv.h"
29 #include "stream-manager-dbus-priv.h"
30 #include "stream-manager-volume-priv.h"
31 #include "stream-manager-filter-priv.h"
32 #include "stream-manager-restriction-priv.h"
34 static const char *dbus_str_none = "none";
35 static const char *stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK",
36 "STREAM_MANAGER_RETURN_ERROR_INTERNAL",
37 "STREAM_MANAGER_RETURN_ERROR_NO_STREAM",
38 "STREAM_MANAGER_RETURN_ERROR_INVALID_ARGUMENT",
39 "STREAM_MANAGER_RETURN_ERROR_DEVICE_NOT_FOUND",
40 "STREAM_MANAGER_RETURN_ERROR_POLICY",
41 "STREAM_MANAGER_RETURN_ERROR_INVALID_STATE"};
43 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
44 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
45 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
46 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
47 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
48 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
49 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
50 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
51 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
52 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
53 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
54 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
55 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
56 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
59 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
61 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata);
62 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
63 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
64 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata);
65 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata);
66 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
67 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
69 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
71 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata);
72 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level);
75 static pa_dbus_arg_info get_stream_info_args[] = { { "stream_type", "s", "in" },
76 { "priority", "i", "out" },
77 { "route_type", "i", "out" },
78 { "volume_types", "as", "out" },
79 { "avail_in_devices", "as", "out" },
80 { "avail_out_devices", "as", "out" },
81 { "avail_frameworks", "as", "out"} };
82 static pa_dbus_arg_info get_stream_list_args[] = { { "stream_type", "as", "out" },
83 { "priority", "ai", "out" } };
84 static pa_dbus_arg_info set_stream_route_devices_args[] = { { "parent_id", "u", "in" },
85 { "route_in_devices", "au", "in" },
86 { "route_out_devices", "au", "in" },
87 { "ret_msg", "s", "out" } };
88 static pa_dbus_arg_info set_stream_route_option_args[] = { { "parent_id", "u", "in" },
89 { "name", "s", "in" },
90 { "value", "i", "in" },
91 { "ret_msg", "s", "out" } };
92 static pa_dbus_arg_info set_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
93 { "io_direction", "s", "in" },
94 { "device_id", "u", "in" },
95 { "ret_msg", "s", "out" } };
96 static pa_dbus_arg_info get_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
97 { "in_device_id", "u", "out" },
98 { "out_device_id", "u", "out" },
99 { "ret_msg", "s", "out" } };
100 static pa_dbus_arg_info set_stream_preemptive_device_args[] = { { "stream_type", "s", "in" },
101 { "io_direction", "s", "in" },
102 { "device_id", "u", "in" },
103 { "ret_msg", "s", "out" } };
104 static pa_dbus_arg_info get_stream_preemptive_device_args[] = { { "stream_type", "s", "in" },
105 { "in_device_id", "u", "out" },
106 { "out_device_id", "u", "out" },
107 { "ret_msg", "s", "out" } };
108 static pa_dbus_arg_info set_volume_level_args[] = { { "io_direction", "s", "in" },
109 { "type", "s", "in" },
110 { "level", "u", "in" },
111 { "ret_msg", "s", "out" } };
112 static pa_dbus_arg_info get_volume_level_args[] = { { "io_direction", "s", "in" },
113 { "type", "s", "in" },
114 { "level", "u", "out" },
115 { "ret_msg", "s", "out" } };
116 static pa_dbus_arg_info get_volume_max_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 set_volume_mute_args[] = { { "io_direction", "s", "in" },
121 { "type", "s", "in" },
123 { "ret_msg", "s", "out" } };
124 static pa_dbus_arg_info get_volume_mute_args[] = { { "io_direction", "s", "in" },
125 { "type", "s", "in" },
126 { "on", "u", "out" },
127 { "ret_msg", "s", "out" } };
128 static pa_dbus_arg_info set_volume_ratio_args[] = { { "io_direction", "s", "in" },
129 { "idx", "u", "in" },
130 { "ratio", "d", "in" },
131 { "ret_msg", "s", "out" } };
132 static pa_dbus_arg_info get_volume_ratio_args[] = { { "io_direction", "s", "in" },
133 { "idx", "u", "in" },
134 { "ratio", "d", "out" },
135 { "ret_msg", "s", "out" } };
136 static pa_dbus_arg_info get_current_volume_type_args[] = { { "io_direction", "s", "in" },
137 { "type", "s", "out" },
138 { "ret_msg", "s", "out" } };
139 static pa_dbus_arg_info get_current_media_routing_path_args[] = { { "io_direction", "s", "in" },
140 { "device_type", "s", "out" },
141 { "ret_msg", "s", "out" } };
142 static pa_dbus_arg_info update_focus_status_args[] = { { "parent_id", "u", "in" },
143 { "focus_status", "u", "in" },
144 { "ret_msg", "s", "out" } };
145 static pa_dbus_arg_info update_focus_status_by_focus_id_args[] = { { "focus_id", "i", "in" },
146 { "focus_status", "u", "in" },
147 { "ret_msg", "s", "out" } };
148 static pa_dbus_arg_info update_restriction_args[] = { { "name", "s", "in" },
149 { "value", "u", "in" },
150 { "ret_msg", "s", "out" } };
151 static pa_dbus_arg_info update_call_parameters_args[] = { { "parameters", "s", "in" },
152 { "ret_msg", "s", "out" } };
153 static pa_dbus_arg_info set_filter_args[] = { { "filter_name", "s", "in" },
154 { "filter_parameters", "s", "in" },
155 { "filter_group", "s", "in" },
156 { "stream_type", "s", "in" },
157 { "ret_msg", "s", "out" } };
158 static pa_dbus_arg_info unset_filter_args[] = { { "stream_type", "s", "in" },
159 { "ret_msg", "s", "out" } };
160 static pa_dbus_arg_info control_filter_args[] = { { "filter_name", "s", "in" },
161 { "filter_controls", "s", "in" },
162 { "stream_type", "s", "in" },
163 { "ret_msg", "s", "out" } };
164 static pa_dbus_arg_info check_stream_exist_by_pid_args[] = { { "pid", "u", "in" },
165 { "stream_type", "s", "in" },
166 { "io_direction", "s", "in" },
167 { "ret_msg", "s", "out" } };
168 static pa_dbus_arg_info get_pid_of_latest_stream_args[] = { { "io_direction", "s", "in" },
169 { "stream_types", "as", "in" },
170 { "pid", "u", "out" },
171 { "ret_msg", "s", "out" } };
172 static pa_dbus_arg_info activate_ducking_args[] = { { "index", "u", "in" },
173 { "enable", "b", "in" },
174 { "target_stream", "s", "in" },
175 { "duration", "u", "in" },
176 { "ratio", "d", "in" },
177 { "ret_msg", "s", "out" } };
179 static pa_dbus_arg_info get_ducking_state_args[] = { { "index", "u", "in" },
180 { "is_ducked", "b", "out" },
181 { "ret_msg", "s", "out" } };
183 static const char* signature_args_for_in[] = {
184 "s", /* METHOD_HANDLER_GET_STREAM_INFO */
185 "", /* METHOD_HANDLER_GET_STREAM_LIST */
186 "uauau", /* METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES */
187 "usi", /* METHOD_HANDLER_SET_STREAM_ROUTE_OPTION */
188 "usu", /* METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE */
189 "u", /* METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE */
190 "ssu", /* METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE */
191 "s", /* METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE */
192 "ssu", /* METHOD_HANDLER_SET_VOLUME_LEVEL */
193 "ss", /* METHOD_HANDLER_GET_VOLUME_LEVEL */
194 "ss", /* METHOD_HANDLER_GET_VOLUME_MAX_LEVEL */
195 "ssu", /* METHOD_HANDLER_SET_VOLUME_MUTE */
196 "ss", /* METHOD_HANDLER_GET_VOLUME_MUTE */
197 "sud", /* METHOD_HANDLER_SET_VOLUME_RATIO */
198 "su", /* METHOD_HANDLER_GET_VOLUME_RATIO */
199 "s", /* METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE */
200 "s", /* METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH */
201 "uu", /* METHOD_HANDLER_UPDATE_FOCUS_STATUS */
202 "iu", /* METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID */
203 "su", /* METHOD_HANDLER_UPDATE_RESTRICTION */
204 "s", /* METHOD_HANDLER_UPDATE_CALL_PARAMETERS */
205 "ssss", /* METHOD_HANDLER_SET_FILTER */
206 "s", /* METHOD_HANDLER_UNSET_FILTER */
207 "sss", /* METHOD_HANDLER_CONTROL_FILTER */
208 "uss", /* METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID */
209 "sas", /* METHOD_HANDLER_GET_PID_OF_LATEST_STREAM */
210 "ubsud", /* METHOD_HANDLER_ACTIVATE_DUCKING */
211 "u" /* METHOD_HANDLER_GET_DUCKING_STATE */
214 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
215 [METHOD_HANDLER_GET_STREAM_INFO] = {
216 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
217 .arguments = get_stream_info_args,
218 .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
219 .receive_cb = handle_get_stream_info },
220 [METHOD_HANDLER_GET_STREAM_LIST] = {
221 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
222 .arguments = get_stream_list_args,
223 .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
224 .receive_cb = handle_get_stream_list },
225 [METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES] = {
226 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
227 .arguments = set_stream_route_devices_args,
228 .n_arguments = sizeof(set_stream_route_devices_args) / sizeof(pa_dbus_arg_info),
229 .receive_cb = handle_set_stream_route_devices },
230 [METHOD_HANDLER_SET_STREAM_ROUTE_OPTION] = {
231 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
232 .arguments = set_stream_route_option_args,
233 .n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
234 .receive_cb = handle_set_stream_route_option },
235 [METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE] = {
236 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREFERRED_DEVICE,
237 .arguments = set_stream_preferred_device_args,
238 .n_arguments = sizeof(set_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
239 .receive_cb = handle_set_stream_preferred_device },
240 [METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE] = {
241 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREFERRED_DEVICE,
242 .arguments = get_stream_preferred_device_args,
243 .n_arguments = sizeof(get_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
244 .receive_cb = handle_get_stream_preferred_device },
245 [METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE] = {
246 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREEMPTIVE_DEVICE,
247 .arguments = set_stream_preemptive_device_args,
248 .n_arguments = sizeof(set_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
249 .receive_cb = handle_set_stream_preemptive_device },
250 [METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE] = {
251 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREEMPTIVE_DEVICE,
252 .arguments = get_stream_preemptive_device_args,
253 .n_arguments = sizeof(get_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
254 .receive_cb = handle_get_stream_preemptive_device },
255 [METHOD_HANDLER_SET_VOLUME_LEVEL] = {
256 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
257 .arguments = set_volume_level_args,
258 .n_arguments = sizeof(set_volume_level_args) / sizeof(pa_dbus_arg_info),
259 .receive_cb = handle_set_volume_level },
260 [METHOD_HANDLER_GET_VOLUME_LEVEL] = {
261 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
262 .arguments = get_volume_level_args,
263 .n_arguments = sizeof(get_volume_level_args) / sizeof(pa_dbus_arg_info),
264 .receive_cb = handle_get_volume_level },
265 [METHOD_HANDLER_GET_VOLUME_MAX_LEVEL] = {
266 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
267 .arguments = get_volume_max_level_args,
268 .n_arguments = sizeof(get_volume_max_level_args) / sizeof(pa_dbus_arg_info),
269 .receive_cb = handle_get_volume_max_level },
270 [METHOD_HANDLER_SET_VOLUME_MUTE] = {
271 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE,
272 .arguments = set_volume_mute_args,
273 .n_arguments = sizeof(set_volume_mute_args) / sizeof(pa_dbus_arg_info),
274 .receive_cb = handle_set_volume_mute },
275 [METHOD_HANDLER_GET_VOLUME_MUTE] = {
276 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE,
277 .arguments = get_volume_mute_args,
278 .n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
279 .receive_cb = handle_get_volume_mute },
280 [METHOD_HANDLER_SET_VOLUME_RATIO] = {
281 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_RATIO,
282 .arguments = set_volume_ratio_args,
283 .n_arguments = sizeof(set_volume_ratio_args) / sizeof(pa_dbus_arg_info),
284 .receive_cb = handle_set_volume_ratio },
285 [METHOD_HANDLER_GET_VOLUME_RATIO] = {
286 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_RATIO,
287 .arguments = get_volume_ratio_args,
288 .n_arguments = sizeof(get_volume_ratio_args) / sizeof(pa_dbus_arg_info),
289 .receive_cb = handle_get_volume_ratio },
290 [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
291 .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
292 .arguments = get_current_volume_type_args,
293 .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
294 .receive_cb = handle_get_current_volume_type },
295 [METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH] = {
296 .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_MEDIA_ROUTING_PATH,
297 .arguments = get_current_media_routing_path_args,
298 .n_arguments = sizeof(get_current_media_routing_path_args) / sizeof(pa_dbus_arg_info),
299 .receive_cb = handle_get_current_media_routing_path },
300 [METHOD_HANDLER_UPDATE_FOCUS_STATUS] = {
301 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS,
302 .arguments = update_focus_status_args,
303 .n_arguments = sizeof(update_focus_status_args) / sizeof(pa_dbus_arg_info),
304 .receive_cb = handle_update_focus_status },
305 [METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID] = {
306 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS_BY_FOCUS_ID,
307 .arguments = update_focus_status_by_focus_id_args,
308 .n_arguments = sizeof(update_focus_status_by_focus_id_args) / sizeof(pa_dbus_arg_info),
309 .receive_cb = handle_update_focus_status_by_focus_id },
310 [METHOD_HANDLER_UPDATE_RESTRICTION] = {
311 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_RESTRICTION,
312 .arguments = update_restriction_args,
313 .n_arguments = sizeof(update_restriction_args) / sizeof(pa_dbus_arg_info),
314 .receive_cb = handle_update_restriction },
315 [METHOD_HANDLER_UPDATE_CALL_PARAMETERS] = {
316 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_CALL_PARAMETERS,
317 .arguments = update_call_parameters_args,
318 .n_arguments = sizeof(update_call_parameters_args) / sizeof(pa_dbus_arg_info),
319 .receive_cb = handle_update_call_parameters },
320 [METHOD_HANDLER_SET_FILTER] = {
321 .method_name = STREAM_MANAGER_METHOD_NAME_SET_FILTER,
322 .arguments = set_filter_args,
323 .n_arguments = sizeof(set_filter_args) / sizeof(pa_dbus_arg_info),
324 .receive_cb = handle_set_filter },
325 [METHOD_HANDLER_UNSET_FILTER] = {
326 .method_name = STREAM_MANAGER_METHOD_NAME_UNSET_FILTER,
327 .arguments = unset_filter_args,
328 .n_arguments = sizeof(unset_filter_args) / sizeof(pa_dbus_arg_info),
329 .receive_cb = handle_unset_filter },
330 [METHOD_HANDLER_CONTROL_FILTER] = {
331 .method_name = STREAM_MANAGER_METHOD_NAME_CONTROL_FILTER,
332 .arguments = control_filter_args,
333 .n_arguments = sizeof(control_filter_args) / sizeof(pa_dbus_arg_info),
334 .receive_cb = handle_control_filter },
335 [METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID] = {
336 .method_name = STREAM_MANAGER_METHOD_NAME_CHECK_STREAM_EXIST_BY_PID,
337 .arguments = check_stream_exist_by_pid_args,
338 .n_arguments = sizeof(check_stream_exist_by_pid_args) / sizeof(pa_dbus_arg_info),
339 .receive_cb = handle_check_stream_exist_by_pid },
340 [METHOD_HANDLER_GET_PID_OF_LATEST_STREAM] = {
341 .method_name = STREAM_MANAGER_METHOD_NAME_GET_PID_OF_LATEST_STREAM,
342 .arguments = get_pid_of_latest_stream_args,
343 .n_arguments = sizeof(get_pid_of_latest_stream_args) / sizeof(pa_dbus_arg_info),
344 .receive_cb = handle_get_pid_of_latest_stream },
345 [METHOD_HANDLER_ACTIVATE_DUCKING] = {
346 .method_name = STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING,
347 .arguments = activate_ducking_args,
348 .n_arguments = sizeof(activate_ducking_args) / sizeof(pa_dbus_arg_info),
349 .receive_cb = handle_activate_ducking },
350 [METHOD_HANDLER_GET_DUCKING_STATE] = {
351 .method_name = STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE,
352 .arguments = get_ducking_state_args,
353 .n_arguments = sizeof(get_ducking_state_args) / sizeof(pa_dbus_arg_info),
354 .receive_cb = handle_get_ducking_state },
357 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
358 const char *xml = STREAM_MGR_INTROSPECT_XML;
359 DBusMessage *r = NULL;
365 pa_assert_se((r = dbus_message_new_method_return(msg)));
366 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
369 pa_assert_se(dbus_connection_send((conn), r, NULL));
370 dbus_message_unref(r);
373 return DBUS_HANDLER_RESULT_HANDLED;
376 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
378 DBusMessage *reply = NULL;
379 DBusMessageIter msg_iter;
380 pa_stream_manager *m = (pa_stream_manager*)userdata;
386 pa_assert_se(dbus_message_get_args(msg, NULL,
388 pa_log_info("get stream list");
390 memset(&list, 0, sizeof(stream_list));
391 pa_assert_se((reply = dbus_message_new_method_return(msg)));
392 dbus_message_iter_init_append(reply, &msg_iter);
393 if (!get_available_streams(m, &list)) {
394 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
395 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
397 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
398 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, NULL, 0);
400 pa_assert_se(dbus_connection_send(conn, reply, NULL));
401 dbus_message_unref(reply);
404 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
406 stream_info_per_type info;
407 DBusMessage *reply = NULL;
408 DBusMessageIter msg_iter;
409 pa_stream_manager *m = (pa_stream_manager*)userdata;
415 pa_assert_se(dbus_message_get_args(msg, NULL,
416 DBUS_TYPE_STRING, &type,
418 pa_log_info("type[%s]", type);
420 memset(&info, 0, sizeof(stream_info_per_type));
421 pa_assert_se((reply = dbus_message_new_method_return(msg)));
422 dbus_message_iter_init_append(reply, &msg_iter);
423 get_stream_info(m, type, &info);
424 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
425 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
426 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.volume_types, STREAM_DIRECTION_MAX);
427 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
428 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
429 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
431 pa_assert_se(dbus_connection_send(conn, reply, NULL));
432 dbus_message_unref(reply);
435 static bool check_all_requested_devices_connected(pa_stream_manager *m, uint32_t *device_list, uint32_t length) {
436 pa_idxset *dm_device_list;
437 uint32_t found_count = 0;
441 pa_assert(device_list);
443 dm_device_list = pa_device_manager_get_device_list(m->dm);
445 for (i = 0; i < length; i++) {
446 pa_tz_device *dm_device;
447 uint32_t dm_device_id;
450 PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
451 dm_device_id = pa_tz_device_get_id(dm_device);
452 if (device_list[i] == dm_device_id) {
453 pa_log_debug("device[%u] is connected", dm_device_id);
455 if (length == found_count)
465 static ret_msg_t update_devices_and_trigger_routing(pa_stream_manager *m, stream_parent *sp, stream_type_t type) {
467 pa_idxset *idx_streams = NULL;
469 void *cur_highest_priority_stream = NULL;
470 stream_route_type_t route_type = STREAM_ROUTE_TYPE_DEFAULT;
471 ret_msg_t ret = RET_MSG_OK;
476 if (type == STREAM_SINK_INPUT) {
477 idx_streams = sp->idx_sink_inputs;
478 cur_highest_priority_stream = (void*)m->cur_highest_priority.sink_input;
480 idx_streams = sp->idx_source_outputs;
481 cur_highest_priority_stream = (void*)m->cur_highest_priority.source_output;
484 /* update route type of this stream parent */
485 if (sp->route_type == STREAM_ROUTE_TYPE_DEFAULT) {
486 PA_IDXSET_FOREACH(stream, idx_streams, idx) {
487 /* find route type of stream */
488 if (get_route_type(stream, type, false, &route_type))
489 return RET_MSG_ERROR_INTERNAL;
491 if (route_type == STREAM_ROUTE_TYPE_MANUAL ||
492 route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
493 sp->route_type = route_type;
494 pa_log_info(" -- the route type is [%d]", route_type);
496 pa_log_error(" -- the route type is not valid[%d]", route_type);
497 return RET_MSG_ERROR_POLICY;
502 /* if any stream that belongs to this id has been activated, do notify right away */
503 if (sp->route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
504 PA_IDXSET_FOREACH(stream, idx_streams, idx) {
505 pa_log_debug(" -- stream->index[%u] belongs to this stream parent[%p], do notify for the select proper source",
506 GET_STREAM_INDEX(stream, type), sp);
507 ret = do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, false, stream);
510 /* trigger only when it occupies routing path */
511 if (cur_highest_priority_stream && pa_idxset_get_by_data(idx_streams, cur_highest_priority_stream, NULL)) {
512 pa_log_debug(" -- cur_highest_priority_stream->index[%u] belongs to this stream_parent[%p], do notify for the route change",
513 GET_STREAM_INDEX(cur_highest_priority_stream, type), sp);
514 ret = do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, false, cur_highest_priority_stream);
515 if (!ret && stream_is_call_family(PA_OBJECT(cur_highest_priority_stream)) && m->on_call) {
516 pa_log_info("set active device for new call route device");
517 change_active_route_for_call(m, PA_OBJECT(cur_highest_priority_stream), false);
525 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
528 uint32_t *in_device_list = NULL;
529 uint32_t *out_device_list = NULL;
531 int list_len_out = 0;
532 stream_parent *sp = NULL;
533 DBusMessage *reply = NULL;
534 pa_stream_manager *m = (pa_stream_manager*)userdata;
535 ret_msg_t ret = RET_MSG_OK;
541 pa_assert_se(dbus_message_get_args(msg, NULL,
542 DBUS_TYPE_UINT32, &id,
543 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &in_device_list, &list_len_in,
544 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &out_device_list, &list_len_out,
546 pa_log_info("id[%u], in_device_list[%p]:length[%d], out_device_list[%p]:length[%d]",
547 id, in_device_list, list_len_in, out_device_list, list_len_out);
549 pa_assert_se((reply = dbus_message_new_method_return(msg)));
551 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
553 pa_log_error("could not find matching client for this parent_id[%u]", id);
554 ret = RET_MSG_ERROR_INTERNAL;
557 if (!in_device_list && !out_device_list) {
558 pa_log_error("invalid arguments");
559 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
562 if (!sp->idx_route_in_devices || !sp->idx_route_out_devices) {
563 pa_log_error("failed to update, idx_route_in_devices[%p], idx_route_out_devices[%p]",
564 sp->idx_route_in_devices, sp->idx_route_out_devices);
565 ret = RET_MSG_ERROR_INTERNAL;
569 /* check if all the requested devices are connected now */
570 if (in_device_list && !check_all_requested_devices_connected(m, in_device_list, list_len_in)) {
571 pa_log_error("could not find requested in-devices");
572 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
575 if (out_device_list && !check_all_requested_devices_connected(m, out_device_list, list_len_out)) {
576 pa_log_error("could not find requested out-devices");
577 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
581 pa_idxset_remove_all(sp->idx_route_in_devices, pa_xfree);
582 if (in_device_list && list_len_in) {
583 for (i = 0; i < list_len_in; i++) {
584 pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(uint32_t)), NULL);
585 pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
588 if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SOURCE_OUTPUT)))
591 pa_idxset_remove_all(sp->idx_route_out_devices, pa_xfree);
592 if (out_device_list && list_len_out) {
593 for (i = 0; i < list_len_out; i++) {
594 pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(uint32_t)), NULL);
595 pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
598 if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SINK_INPUT)))
602 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
603 pa_assert_se(dbus_connection_send(conn, reply, NULL));
604 dbus_message_unref(reply);
607 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
609 const char *name = NULL;
611 bool updated = false;
612 stream_parent *sp = NULL;
613 stream_route_option route_option;
614 DBusMessage *reply = NULL;
615 pa_stream_manager *m = (pa_stream_manager*)userdata;
621 pa_assert_se(dbus_message_get_args(msg, NULL,
622 DBUS_TYPE_UINT32, &id,
623 DBUS_TYPE_STRING, &name,
624 DBUS_TYPE_INT32, &value,
626 pa_log_info("name[%s], value[%d]", name, value);
628 pa_assert_se((reply = dbus_message_new_method_return(msg)));
630 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
633 route_option.name = name;
634 route_option.value = value;
636 /* if any stream that belongs to this id has been activated, do notify right away */
637 if (m->cur_highest_priority.sink_input) {
638 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
639 pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
640 (m->cur_highest_priority.sink_input)->index, id);
641 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
645 if (m->cur_highest_priority.source_output) {
646 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
647 pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
648 (m->cur_highest_priority.source_output)->index, id);
649 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SOURCE_OUTPUT, false, &route_option);
654 pa_log_error("invalid state");
655 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
657 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
659 pa_log_error("invalid arguments");
660 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT], DBUS_TYPE_INVALID));
664 pa_log_error("could not find matching client for this parent_id[%u]", id);
665 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
668 pa_assert_se(dbus_connection_send(conn, reply, NULL));
669 dbus_message_unref(reply);
672 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) {
677 if (device_id == 0) {
678 /* get a device of default role from previous device type */
679 if (!(*device = pa_device_manager_get_device(m->dm, sp->preferred_device.types[direction], NULL))) {
680 pa_log_error("could not get device[%s]", sp->preferred_device.types[direction]);
683 pa_log_debug("unset preferred device, rollback to type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
685 /* get the device of device id */
686 if (!(*device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
687 pa_log_error("could not get device by id[%u]", device_id);
690 pa_log_debug("requested preferred device type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
696 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
697 const char *device_direction = NULL;
699 uint32_t device_id = 0;
702 stream_direction_t direction;
703 pa_tz_device *device;
704 pa_tz_device *prev_device;
705 const char *device_role;
706 const char *prev_device_type;
707 const char *prev_device_role;
708 stream_parent *sp = NULL;
712 pa_proplist *device_props;
713 uint32_t stream_index;
715 void *new_device = NULL;
716 ret_msg_t ret = RET_MSG_OK;
717 DBusMessage *reply = NULL;
719 pa_stream_manager *m = (pa_stream_manager*)userdata;
725 pa_assert_se(dbus_message_get_args(msg, NULL,
726 DBUS_TYPE_UINT32, &sp_id,
727 DBUS_TYPE_STRING, &device_direction,
728 DBUS_TYPE_UINT32, &device_id,
730 pa_log_info("stream parent id[%u], device direction[%s], device_id[%u]", sp_id, device_direction, device_id);
732 pa_assert_se((reply = dbus_message_new_method_return(msg)));
734 if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
735 pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
736 ret = RET_MSG_ERROR_INTERNAL;
740 if (pa_safe_streq(device_direction, "in"))
741 direction = STREAM_DIRECTION_IN;
742 else if (pa_safe_streq(device_direction, "out"))
743 direction = STREAM_DIRECTION_OUT;
745 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
749 /* allow only auto routing type */
750 if (sp->route_type != STREAM_ROUTE_TYPE_AUTO &&
751 sp->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
752 pa_log_error("not allowed this route type[%d] of this parent_id[%u]", sp->route_type, sp_id);
753 ret = RET_MSG_ERROR_POLICY;
757 if (device_id == 0 && !sp->preferred_device.types[direction]) {
758 pa_log_debug("it is already unset");
762 if (get_device_for_preference(m, sp, direction, device_id, &device) < 0) {
763 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
767 /* only allow built-in device types */
768 if (!device_type_is_builtin(device->type)) {
769 pa_log_error("This device(id:%u, type:%s) is not built-in type", device_id, device->type);
770 ret = RET_MSG_ERROR_POLICY;
774 /* get default role of the device */
775 device_role = pa_tz_device_get_role(device, NULL);
777 sp->preferred_device.types[direction] = (device_id == 0) ? NULL : device->type;
778 sp->preferred_device.roles[direction] = (device_id == 0) ? NULL : device_role;
780 pa_log_info("preferred device role is set to [%s] of device type[%s], direction[%s]",
781 sp->preferred_device.roles[direction], device->type, direction == STREAM_DIRECTION_OUT ? "out" : "in");
783 streams = (direction == STREAM_DIRECTION_OUT) ? sp->idx_sink_inputs : sp->idx_source_outputs;
784 devices = (direction == STREAM_DIRECTION_OUT) ? device->playback_devices : device->capture_devices;
786 count = pa_idxset_size(streams);
787 PA_IDXSET_FOREACH(stream, streams, idx) {
788 props = GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ?
789 STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT);
790 pa_log_info("stream index(%u), props %p", (direction == STREAM_DIRECTION_OUT) ? PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index, props);
791 device_props = (direction == STREAM_DIRECTION_OUT) ?
792 PA_SINK_INPUT(stream)->sink->proplist : PA_SOURCE_OUTPUT(stream)->source->proplist;
793 stream_index = (direction == STREAM_DIRECTION_OUT) ?
794 PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index;
797 pa_proplist_unset(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
799 pa_proplist_sets(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE, device_role);
801 prev_device_type = pa_proplist_gets(props, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
802 prev_device_role = pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE);
804 if (pa_safe_streq(prev_device_type, device->type)) {
805 /* If the request is for the same device type,
806 * new device role should be applied - move streams. */
807 if (!pa_safe_streq(prev_device_role, device_role)) {
808 new_device = pa_hashmap_get(devices, device_role);
809 pa_log_debug("move stream[%u]: [%s][%s -> %s]",
810 stream_index, prev_device_type, prev_device_role, device_role);
813 /* If the request is for a different device type,
814 * check the previous device role and move streams to default role if needed. */
815 if ((prev_device = pa_device_manager_get_device(m->dm, prev_device_type, NULL)))
816 new_device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
817 prev_device->playback_devices : prev_device->capture_devices);
819 device_props = (direction == STREAM_DIRECTION_OUT) ? PA_SINK(new_device)->proplist : PA_SOURCE(new_device)->proplist;
820 pa_log_debug("may move stream[%u] to default role: [%s][%s -> %s]",
821 stream_index, prev_device_type, prev_device_role, pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE));
825 (direction == STREAM_DIRECTION_OUT) ? pa_sink_input_move_to(stream, PA_SINK(new_device), false) :
826 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
829 /* Use PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED here.
830 * It's not about the focus change, but this command exactly does what is needed here
831 * including updating the highest priority, find the next stream to be set to HAL as well as
832 * change the state of the builtin-device that use internal codec. */
833 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
834 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
839 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
840 pa_assert_se(dbus_connection_send(conn, reply, NULL));
841 dbus_message_unref(reply);
844 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
845 stream_parent *sp = NULL;
847 uint32_t in_device_id = 0;
848 uint32_t out_device_id = 0;
849 const char *pref_in_type, *pref_out_type;
850 const char *pref_in_role, *pref_out_role;
851 pa_idxset *dm_device_list;
852 pa_tz_device *dm_device;
853 dm_device_direction_t dm_direction;
855 ret_msg_t ret = RET_MSG_OK;
856 DBusMessage *reply = NULL;
858 pa_stream_manager *m = (pa_stream_manager*)userdata;
864 pa_assert_se(dbus_message_get_args(msg, NULL,
865 DBUS_TYPE_UINT32, &sp_id,
867 pa_log_info("stream parent id[%u]", sp_id);
869 pa_assert_se((reply = dbus_message_new_method_return(msg)));
871 if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
872 pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
873 ret = RET_MSG_ERROR_INTERNAL;
877 pref_in_type = sp->preferred_device.types[STREAM_DIRECTION_IN];
878 pref_in_role = sp->preferred_device.roles[STREAM_DIRECTION_IN];
879 pref_out_type = sp->preferred_device.types[STREAM_DIRECTION_OUT];
880 pref_out_role = sp->preferred_device.roles[STREAM_DIRECTION_OUT];
882 /* get device ids of preferred in/out device respectively */
883 dm_device_list = pa_device_manager_get_device_list(m->dm);
884 PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
885 dm_direction = pa_tz_device_get_direction(dm_device);
886 if (!in_device_id && dm_direction & DM_DEVICE_DIRECTION_IN) {
887 if (pa_safe_streq(pref_in_type, pa_tz_device_get_type(dm_device))) {
888 if (pa_safe_streq(pref_in_role, pa_tz_device_get_role(dm_device, pref_in_role)))
889 in_device_id = pa_tz_device_get_id(dm_device);
892 if (!out_device_id && dm_direction & DM_DEVICE_DIRECTION_OUT) {
893 if (pa_safe_streq(pref_out_type, pa_tz_device_get_type(dm_device))) {
894 if (pa_safe_streq(pref_out_role, pa_tz_device_get_role(dm_device, pref_out_role)))
895 out_device_id = pa_tz_device_get_id(dm_device);
900 pa_log_info("preferred IN device: type[%s] role[%s] id[%u]", pref_in_type, pref_in_role, in_device_id);
901 pa_log_info("preferred OUT device: type[%s] role[%s] id[%u]", pref_out_type, pref_out_role, out_device_id);
904 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id, DBUS_TYPE_INVALID));
905 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &out_device_id, DBUS_TYPE_INVALID));
906 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
907 pa_assert_se(dbus_connection_send(conn, reply, NULL));
908 dbus_message_unref(reply);
911 static uint32_t get_num_of_target_streams(pa_stream_manager *m, pa_idxset *streams, stream_direction_t direction, const char *role) {
921 PA_IDXSET_FOREACH(s, streams, idx) {
922 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
923 PA_SINK_INPUT(s)->proplist : PA_SOURCE_OUTPUT(s)->proplist, PA_PROP_MEDIA_ROLE);
924 if (pa_safe_streq(_role, role))
930 static void routing_process_to_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
939 pa_assert(tz_device);
941 count = get_num_of_target_streams(m, (direction == STREAM_DIRECTION_OUT) ?
942 m->core->sink_inputs : m->core->source_outputs,
944 PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
945 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
946 PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
947 if (!pa_safe_streq(_role, role))
950 /* move stream to the preemptive device */
951 device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
952 tz_device->playback_devices : tz_device->capture_devices);
953 if (direction == STREAM_DIRECTION_OUT) {
954 pa_sink_input_move_to(stream, PA_SINK(device), false);
955 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT),
956 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
958 pa_source_output_move_to(stream, PA_SOURCE(device), false);
959 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT),
960 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
965 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
966 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
971 static void rollback_process_from_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
977 const char *active_device = NULL;
982 pa_assert(tz_device);
984 device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
985 tz_device->playback_devices : tz_device->capture_devices);
987 PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? PA_SINK(device)->inputs : PA_SOURCE(device)->outputs, idx) {
988 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
989 PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
990 if (!pa_safe_streq(_role, role))
994 /* find and set new device */
995 do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
996 (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
998 new_device = (direction == STREAM_DIRECTION_OUT) ? (void*)(PA_SINK_INPUT(stream)->sink) :
999 (void*)(PA_SOURCE_OUTPUT(stream)->source);
1000 active_device = pa_proplist_gets(GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT),
1001 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
1002 /* change routing */
1003 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
1004 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1006 if (direction == STREAM_DIRECTION_OUT)
1007 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1009 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1014 /* move stream to the new device */
1015 if (direction == STREAM_DIRECTION_OUT) {
1016 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1018 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1020 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1022 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1027 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1028 const char *stream_type = NULL;
1029 const char *device_direction = NULL;
1030 stream_direction_t direction;
1031 uint32_t device_id = 0;
1032 stream_info *s = NULL;
1033 pa_tz_device *device = NULL;
1034 char *device_type = NULL;
1035 const char *prev_device_type = NULL;
1036 uint32_t prev_device_id = 0;
1039 ret_msg_t ret = RET_MSG_OK;
1040 DBusMessage *reply = NULL;
1042 pa_stream_manager *m = (pa_stream_manager*)userdata;
1048 pa_assert_se(dbus_message_get_args(msg, NULL,
1049 DBUS_TYPE_STRING, &stream_type,
1050 DBUS_TYPE_STRING, &device_direction,
1051 DBUS_TYPE_UINT32, &device_id,
1052 DBUS_TYPE_INVALID));
1053 pa_log_info("stream type[%s], device direction[%s], device_id[%u]", stream_type, device_direction, device_id);
1055 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1057 if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1058 pa_log_error("could not find this stream type(%s)", stream_type);
1059 ret = RET_MSG_ERROR_INTERNAL;
1063 if (pa_safe_streq(device_direction, "in"))
1064 direction = STREAM_DIRECTION_IN;
1065 else if (pa_safe_streq(device_direction, "out"))
1066 direction = STREAM_DIRECTION_OUT;
1068 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1072 /* allow only auto routing type */
1073 if (s->route_type != STREAM_ROUTE_TYPE_AUTO &&
1074 s->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1075 pa_log_error("not allowed this route type[%d]", s->route_type);
1076 ret = RET_MSG_ERROR_POLICY;
1080 if (device_id > 0) {
1081 if (!(device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
1082 pa_log_error("could not get device by id[%u]", device_id);
1083 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1087 PA_IDXSET_FOREACH(device_type, (direction == STREAM_DIRECTION_OUT) ? s->idx_avail_out_devices : s->idx_avail_in_devices, idx) {
1088 if (pa_safe_streq(device_type, device->type)) {
1094 pa_log_error("not supported this device type[%s]", device->type);
1095 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1100 if (device_id == 0 && s->preemptive_device[direction].id == 0) {
1101 pa_log_debug("there's no preemptive device, nothing to do");
1105 prev_device_type = s->preemptive_device[direction].type;
1106 prev_device_id = s->preemptive_device[direction].id;
1107 s->preemptive_device[direction].type = device_id > 0 ? device->type : NULL;
1108 s->preemptive_device[direction].id = device_id;
1110 pa_log_info("preemptive [%s] device is set, [%s, id:%u]",
1111 direction == STREAM_DIRECTION_OUT ? "out" : "in",
1112 device_id > 0 ? device->type : NULL,
1115 /* move streams and change routing */
1116 if (device_id == 0) {
1117 if (!(device = pa_device_manager_get_device_by_id(m->dm, prev_device_id)) || !pa_safe_streq(device->type, prev_device_type)) {
1118 pa_log_debug("could not find the previous device of id[%u], type[%s], nothing to do.", prev_device_id, prev_device_type);
1121 rollback_process_from_preemptive_device(m, direction, stream_type, device);
1123 routing_process_to_preemptive_device(m, direction, stream_type, device);
1127 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1128 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1129 dbus_message_unref(reply);
1132 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1133 const char *stream_type = NULL;
1134 stream_info *s = NULL;
1135 uint32_t in_device_id = 0;
1136 uint32_t out_device_id = 0;
1137 const char *in_device_type;
1138 const char *out_device_type;
1139 ret_msg_t ret = RET_MSG_OK;
1140 DBusMessage *reply = NULL;
1142 pa_stream_manager *m = (pa_stream_manager*)userdata;
1148 pa_assert_se(dbus_message_get_args(msg, NULL,
1149 DBUS_TYPE_STRING, &stream_type,
1150 DBUS_TYPE_INVALID));
1151 pa_log_info("stream type[%s]", stream_type);
1153 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1155 if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1156 pa_log_error("could not find this stream type(%s)", stream_type);
1157 ret = RET_MSG_ERROR_INTERNAL;
1161 in_device_id = s->preemptive_device[STREAM_DIRECTION_IN].id;
1162 in_device_type = s->preemptive_device[STREAM_DIRECTION_IN].type;
1163 out_device_id = s->preemptive_device[STREAM_DIRECTION_OUT].id;
1164 out_device_type = s->preemptive_device[STREAM_DIRECTION_OUT].type;
1166 pa_log_info("preemptive IN device: type[%s] id[%u]", in_device_type, in_device_id);
1167 pa_log_info("preemptive OUT device: type[%s] id[%u]", out_device_type, out_device_id);
1170 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id, DBUS_TYPE_INVALID));
1171 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &out_device_id, DBUS_TYPE_INVALID));
1172 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1173 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1174 dbus_message_unref(reply);
1177 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1178 const char *direction = NULL;
1179 const char *type = NULL;
1181 stream_type_t stream_type = STREAM_SINK_INPUT;
1182 DBusMessage *reply = NULL;
1183 pa_stream_manager *m = (pa_stream_manager*)userdata;
1185 ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1191 pa_assert_se(dbus_message_get_args(msg, NULL,
1192 DBUS_TYPE_STRING, &direction,
1193 DBUS_TYPE_STRING, &type,
1194 DBUS_TYPE_UINT32, &level,
1195 DBUS_TYPE_INVALID));
1196 pa_log_info("direction[%s], type[%s], level[%u]", direction, type, level);
1198 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1200 if (pa_safe_streq(direction, "in"))
1201 stream_type = STREAM_SOURCE_OUTPUT;
1202 else if (pa_safe_streq(direction, "out"))
1203 stream_type = STREAM_SINK_INPUT;
1205 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1210 /* check vconf update here, volume will not be set if update fails */
1211 if ((ret = update_volume_vconf(type, level))) {
1212 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1216 if ((ret = set_volume_level_by_type(m, stream_type, type, level))) {
1218 ret_msg = RET_MSG_ERROR_INVALID_ARGUMENT;
1219 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1221 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1225 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1226 dbus_message_unref(reply);
1229 send_volume_changed_signal(conn, direction, type, level);
1232 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1233 const char *direction = NULL;
1234 const char *type = NULL;
1236 stream_type_t stream_type = STREAM_SINK_INPUT;
1237 DBusMessage *reply = NULL;
1238 pa_stream_manager *m = (pa_stream_manager*)userdata;
1244 pa_assert_se(dbus_message_get_args(msg, NULL,
1245 DBUS_TYPE_STRING, &direction,
1246 DBUS_TYPE_STRING, &type,
1247 DBUS_TYPE_INVALID));
1248 pa_log_info("direction[%s], type[%s]", direction, type);
1250 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1252 if (pa_safe_streq(direction, "in"))
1253 stream_type = STREAM_SOURCE_OUTPUT;
1254 else if (pa_safe_streq(direction, "out"))
1255 stream_type = STREAM_SINK_INPUT;
1257 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1258 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1262 if (get_volume_level_by_type(m, GET_VOLUME_CURRENT_LEVEL, stream_type, type, &level)) {
1263 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1264 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1266 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1267 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1271 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1272 dbus_message_unref(reply);
1275 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1276 const char *direction = NULL;
1277 const char *type = NULL;
1279 stream_type_t stream_type = STREAM_SINK_INPUT;
1280 DBusMessage *reply = NULL;
1281 pa_stream_manager *m = (pa_stream_manager*)userdata;
1287 pa_assert_se(dbus_message_get_args(msg, NULL,
1288 DBUS_TYPE_STRING, &direction,
1289 DBUS_TYPE_STRING, &type,
1290 DBUS_TYPE_INVALID));
1291 pa_log_info("direction[%s], type[%s]", direction, type);
1293 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1295 if (pa_safe_streq(direction, "in"))
1296 stream_type = STREAM_SOURCE_OUTPUT;
1297 else if (pa_safe_streq(direction, "out"))
1298 stream_type = STREAM_SINK_INPUT;
1300 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1301 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1305 if (get_volume_level_by_type(m, GET_VOLUME_MAX_LEVEL, stream_type, type, &level)) {
1306 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1307 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1309 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1310 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1313 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1314 dbus_message_unref(reply);
1317 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1318 const char *direction = NULL;
1319 const char *type = NULL;
1320 uint32_t do_mute = 0;
1321 stream_type_t stream_type = STREAM_SINK_INPUT;
1322 DBusMessage *reply = NULL;
1323 pa_stream_manager *m = (pa_stream_manager*)userdata;
1330 pa_assert_se(dbus_message_get_args(msg, NULL,
1331 DBUS_TYPE_STRING, &direction,
1332 DBUS_TYPE_STRING, &type,
1333 DBUS_TYPE_UINT32, &do_mute,
1334 DBUS_TYPE_INVALID));
1335 pa_log_info("direction[%s], type[%s], do_mute[%u]", direction, type, do_mute);
1337 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1339 if (pa_safe_streq(direction, "in"))
1340 stream_type = STREAM_SOURCE_OUTPUT;
1341 else if (pa_safe_streq(direction, "out"))
1342 stream_type = STREAM_SINK_INPUT;
1344 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1348 /* check vconf update here, mute will not be set if update fails */
1349 if ((ret = update_mute_vconf(type, do_mute))) {
1350 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1354 if (set_volume_mute_by_type(m, stream_type, type, (bool)do_mute))
1355 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1357 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1360 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1361 dbus_message_unref(reply);
1364 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1365 const char *direction = NULL;
1366 const char *type = NULL;
1367 uint32_t is_muted = 0;
1368 stream_type_t stream_type = STREAM_SINK_INPUT;
1369 DBusMessage *reply = NULL;
1370 pa_stream_manager *m = (pa_stream_manager*)userdata;
1376 pa_assert_se(dbus_message_get_args(msg, NULL,
1377 DBUS_TYPE_STRING, &direction,
1378 DBUS_TYPE_STRING, &type,
1379 DBUS_TYPE_INVALID));
1380 pa_log_info("direction[%s], type[%s]", direction, type);
1382 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1384 if (pa_safe_streq(direction, "in"))
1385 stream_type = STREAM_SOURCE_OUTPUT;
1386 else if (pa_safe_streq(direction, "out"))
1387 stream_type = STREAM_SINK_INPUT;
1389 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1390 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1394 if (get_volume_mute_by_type(m, stream_type, type, (bool*)&is_muted)) {
1395 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1396 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1398 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1399 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1403 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1404 dbus_message_unref(reply);
1407 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1408 const char *direction = NULL;
1411 stream_type_t stream_type = STREAM_SINK_INPUT;
1412 DBusMessage *reply = NULL;
1413 pa_stream_manager *m = (pa_stream_manager*)userdata;
1415 ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1421 pa_assert_se(dbus_message_get_args(msg, NULL,
1422 DBUS_TYPE_STRING, &direction,
1423 DBUS_TYPE_UINT32, &idx,
1424 DBUS_TYPE_DOUBLE, &ratio,
1425 DBUS_TYPE_INVALID));
1426 pa_log_info("direction[%s], idx[%u], ratio[%f]", direction, idx, ratio);
1428 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1430 if (pa_safe_streq(direction, "in"))
1431 stream_type = STREAM_SOURCE_OUTPUT;
1432 else if (pa_safe_streq(direction, "out"))
1433 stream_type = STREAM_SINK_INPUT;
1435 pa_log_error("invalid direction[%s]", direction);
1436 goto invalid_argument;
1439 /* Check the ratio range (0.0 ~ 1.0) */
1440 if (ratio < 0 || ratio > 1) {
1441 pa_log_error("invalid range, ratio[%f]", ratio);
1442 goto invalid_argument;
1445 if ((ret = set_volume_ratio_by_idx(m, stream_type, idx, ratio))) {
1447 ret_msg = RET_MSG_ERROR_NO_STREAM;
1448 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1450 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1453 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1454 dbus_message_unref(reply);
1458 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
1459 DBUS_TYPE_INVALID));
1460 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1461 dbus_message_unref(reply);
1464 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1465 const char *direction = NULL;
1468 stream_type_t stream_type = STREAM_SINK_INPUT;
1469 DBusMessage *reply = NULL;
1470 pa_stream_manager *m = (pa_stream_manager*)userdata;
1476 pa_assert_se(dbus_message_get_args(msg, NULL,
1477 DBUS_TYPE_STRING, &direction,
1478 DBUS_TYPE_UINT32, &idx,
1479 DBUS_TYPE_INVALID));
1480 pa_log_info("direction[%s], idx[%u]", direction, idx);
1482 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1484 if (pa_safe_streq(direction, "in"))
1485 stream_type = STREAM_SOURCE_OUTPUT;
1486 else if (pa_safe_streq(direction, "out"))
1487 stream_type = STREAM_SINK_INPUT;
1489 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1490 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT], DBUS_TYPE_INVALID));
1494 if (get_volume_ratio_by_idx(m, stream_type, idx, &ratio)) {
1495 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1496 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
1498 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1499 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1503 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1504 dbus_message_unref(reply);
1507 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1508 const char *direction = NULL;
1509 const char *type = NULL;
1511 stream_type_t stream_type = STREAM_SINK_INPUT;
1512 DBusMessage *reply = NULL;
1513 pa_stream_manager *m = (pa_stream_manager*)userdata;
1515 pa_idxset *streams = NULL;
1521 pa_assert_se(dbus_message_get_args(msg, NULL,
1522 DBUS_TYPE_STRING, &direction,
1523 DBUS_TYPE_INVALID));
1524 pa_log_info("direction[%s]", direction);
1526 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1528 if (pa_safe_streq(direction, "in")) {
1529 stream_type = STREAM_SOURCE_OUTPUT;
1530 streams = m->core->source_outputs;
1531 } else if (pa_safe_streq(direction, "out")) {
1532 stream_type = STREAM_SINK_INPUT;
1533 streams = m->core->sink_inputs;
1535 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1536 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1540 /* Get a volume type of a stream that has the max priority role among all the running streams regardless of devices.
1541 Note that it does not represent any focus status of a stream rather only checking the priority of it */
1542 if (pa_idxset_size(streams)) {
1543 int cur_max_priority = 0;
1544 const char *cur_max_type = NULL;
1545 const char *role = NULL;
1546 stream_info *s_info;
1548 PA_IDXSET_FOREACH(s, streams, idx) {
1549 if (!CHECK_STREAM_RUNNING(s, stream_type))
1551 if (!(type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE)))
1553 if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE)))
1555 if ((s_info = pa_hashmap_get(m->stream_infos, role))) {
1556 if (s_info->priority >= cur_max_priority) {
1557 cur_max_priority = s_info->priority;
1558 cur_max_type = type;
1559 pa_log_info("updated, volume type of the max priority stream(%u): %s", GET_STREAM_INDEX(s, stream_type), cur_max_type);
1563 type = cur_max_type;
1567 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID));
1568 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1570 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1571 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
1575 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1576 dbus_message_unref(reply);
1579 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1580 const char *direction = NULL;
1581 const char *device_type = NULL;
1582 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
1583 stream_info *s = NULL;
1584 DBusMessage *reply = NULL;
1585 pa_tz_device *device = NULL;
1586 pa_stream_manager *m = (pa_stream_manager*)userdata;
1592 pa_assert_se(dbus_message_get_args(msg, NULL,
1593 DBUS_TYPE_STRING, &direction,
1594 DBUS_TYPE_INVALID));
1595 pa_log_info("direction[%s]", direction);
1597 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1599 if (pa_safe_streq(direction, "in")) {
1600 dm_device_direction = DM_DEVICE_DIRECTION_IN;
1601 } else if (pa_safe_streq(direction, "out")) {
1602 dm_device_direction = DM_DEVICE_DIRECTION_OUT;
1604 pa_log_error("invalid direction[%s]", direction);
1608 if ((s = pa_hashmap_get(m->stream_infos, STREAM_ROLE_MEDIA)) == NULL) {
1609 pa_log_error("could not find media role");
1613 if (s->route_type == STREAM_ROUTE_TYPE_AUTO) {
1614 device = get_media_auto_device(m, dm_device_direction);
1615 } else if (s->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1616 device = get_media_last_device(m, dm_device_direction);
1618 pa_log_error("unexpected routing type for media[%d]", s->route_type);
1623 device_type = pa_tz_device_get_type(device);
1626 pa_log_error("could not found matched device");
1630 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1631 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1632 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1633 dbus_message_unref(reply);
1636 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_type, DBUS_TYPE_INVALID));
1637 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1638 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1639 dbus_message_unref(reply);
1642 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1646 uint32_t acquired_focus_status = 0;
1647 stream_parent *sp = NULL;
1648 void *stream = NULL;
1649 DBusMessage *reply = NULL;
1650 pa_stream_manager *m = (pa_stream_manager*)userdata;
1651 int prev_status = STREAM_FOCUS_ACQUIRED_NONE;
1657 pa_assert_se(dbus_message_get_args(msg, NULL,
1658 DBUS_TYPE_UINT32, &id,
1659 DBUS_TYPE_UINT32, &acquired_focus_status,
1660 DBUS_TYPE_INVALID));
1661 pa_log_info("id[%u], acquired_focus_status[0x%x]", id, acquired_focus_status);
1663 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1665 if ((sp = pa_hashmap_get(m->stream_parents, (const void*)id))) {
1666 if (sp->focus_status != acquired_focus_status) {
1667 /* need to update */
1668 prev_status = sp->focus_status;
1669 sp->focus_status = acquired_focus_status;
1670 if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_PLAYBACK) && sp->idx_sink_inputs) {
1671 count = pa_idxset_size(sp->idx_sink_inputs);
1672 PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
1673 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1674 GET_FOCUS_STATUS(sp->focus_status, STREAM_SINK_INPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1676 process_stream(m, stream, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1679 if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_CAPTURE) && sp->idx_source_outputs) {
1680 count = pa_idxset_size(sp->idx_source_outputs);
1681 PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
1682 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1683 GET_FOCUS_STATUS(sp->focus_status, STREAM_SOURCE_OUTPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1685 process_stream(m, stream, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1689 pa_log_debug("same as before, skip updating focus status[0x%x]", acquired_focus_status);
1692 pa_log_error("could not find matching client for this parent_id[%u]", id);
1693 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1696 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1698 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1699 dbus_message_unref(reply);
1702 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1705 uint32_t acquired_focus_status = 0;
1706 int32_t focus_id = 0;
1707 const char *focus_id_str;
1708 pa_sink_input *i = NULL;
1709 DBusMessage *reply = NULL;
1710 pa_stream_manager *m = (pa_stream_manager*)userdata;
1716 pa_assert_se(dbus_message_get_args(msg, NULL,
1717 DBUS_TYPE_INT32, &id,
1718 DBUS_TYPE_UINT32, &acquired_focus_status,
1719 DBUS_TYPE_INVALID));
1720 pa_log_info("id[%d], acquired_focus_status[0x%x]", id, acquired_focus_status);
1722 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1724 /* Currently, we only support sink-inputs */
1725 PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
1726 if ((focus_id_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_ID))) {
1727 if (pa_atoi(focus_id_str, &focus_id))
1729 if (id == focus_id) {
1730 pa_log_info("found matching sink-input(%p, %u) - focus_id(%d)", i, i->index, id);
1731 pa_proplist_sets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1732 acquired_focus_status ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1733 process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1735 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1740 pa_log_error("could not find matching stream for this focus_id[%i]", id);
1741 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1743 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1744 dbus_message_unref(reply);
1747 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1750 DBusMessage *reply = NULL;
1751 pa_stream_manager *m = (pa_stream_manager*)userdata;
1757 pa_assert_se(dbus_message_get_args(msg, NULL,
1758 DBUS_TYPE_STRING, &name,
1759 DBUS_TYPE_UINT32, &value,
1760 DBUS_TYPE_INVALID));
1761 pa_log_info("name[%s], value[%u]", name, value);
1763 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1765 if (handle_restrictions(m, name, value) < 0) {
1766 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_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1772 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1773 dbus_message_unref(reply);
1776 #define MAX_CALL_PARAM_SIZE 32
1777 static int32_t parse_call_parameters(const char *parameters, char *call_type, char *call_domain, char *network_band) {
1778 const char delimiter[] = ";";
1779 char *token, *ptr = NULL;
1782 pa_assert(parameters);
1783 pa_assert(call_type);
1784 pa_assert(call_domain);
1785 pa_assert(network_band);
1787 pa_log_info("parameters[%s]", parameters);
1789 /*Reset the call parameters*/
1790 memset(call_type, 0, MAX_CALL_PARAM_SIZE);
1791 memset(call_domain, 0, MAX_CALL_PARAM_SIZE);
1792 memset(network_band, 0, MAX_CALL_PARAM_SIZE);
1795 token = strtok_r((char *)parameters, delimiter, &ptr);
1797 char *delimiter_ptr = NULL;
1800 delimiter_ptr = strstr(token, "=");
1801 if (!delimiter_ptr) {
1802 token = strtok_r(NULL, delimiter, &ptr);
1805 strncpy(key, token, delimiter_ptr - token);
1806 value = delimiter_ptr + 1;
1807 pa_log_debug("key(%s), value(%s)", key, value);
1808 if (!strncmp(key, "call-type", strlen("call-type")))
1809 pa_strlcpy(call_type, value, MAX_CALL_PARAM_SIZE);
1810 else if (!strncmp(key, "call-domain", strlen("call-domain")))
1811 pa_strlcpy(call_domain, value, MAX_CALL_PARAM_SIZE);
1812 else if (!strncmp(key, "network-band", strlen("network-band")))
1813 pa_strlcpy(network_band, value, MAX_CALL_PARAM_SIZE);
1815 pa_log_warn("not supported key(%s)", key);
1817 token = strtok_r(NULL, delimiter, &ptr);
1818 memset(key, 0, sizeof(key));
1820 pa_log_info("call-type[%s], call-domain[%s], network-band[%s]", call_type, call_domain, network_band);
1826 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1827 const char *parameters;
1828 DBusMessage *reply = NULL;
1829 pa_stream_manager *m = (pa_stream_manager*)userdata;
1830 char call_type[MAX_CALL_PARAM_SIZE] = {0,};
1831 char call_domain[MAX_CALL_PARAM_SIZE] = {0,};
1832 char network_band[MAX_CALL_PARAM_SIZE] = {0,};
1833 stream_route_option route_option;
1834 ret_msg_t ret = RET_MSG_OK;
1840 pa_assert_se(dbus_message_get_args(msg, NULL,
1841 DBUS_TYPE_STRING, ¶meters,
1842 DBUS_TYPE_INVALID));
1843 pa_log_info("parameters[%s]", parameters);
1845 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1847 if (parse_call_parameters(parameters, call_type, call_domain, network_band) < 0) {
1848 ret = RET_MSG_ERROR_INTERNAL;
1852 pa_log_debug("call_type[%s], call_domain[%s], network_band[%s]", call_type, call_domain, network_band);
1854 /* Currently, we only use network band */
1855 route_option.name = "call-wideband";
1856 if (pa_safe_streq(network_band, "wb"))
1857 route_option.value = 1;
1859 route_option.value = 0;
1860 ret = do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
1863 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1864 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1865 dbus_message_unref(reply);
1868 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1869 const char *filter_name, *filter_parameters, *filter_group, *stream_type;
1870 DBusMessage *reply = NULL;
1871 pa_stream_manager *m = (pa_stream_manager*)userdata;
1877 pa_assert_se(dbus_message_get_args(msg, NULL,
1878 DBUS_TYPE_STRING, &filter_name,
1879 DBUS_TYPE_STRING, &filter_parameters,
1880 DBUS_TYPE_STRING, &filter_group,
1881 DBUS_TYPE_STRING, &stream_type,
1882 DBUS_TYPE_INVALID));
1883 pa_log_info("filter_name[%s], filter_parameters[%s], filter_group[%s], stream_type[%s]", filter_name,
1884 filter_parameters, filter_group, stream_type);
1886 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1888 /* Set filter sink according to stream type */
1889 if (update_filter(m, filter_name, filter_parameters, filter_group, stream_type) < 0) {
1890 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1891 DBUS_TYPE_INVALID));
1895 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1896 DBUS_TYPE_INVALID));
1899 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1900 dbus_message_unref(reply);
1903 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1904 const char *stream_type;
1905 DBusMessage *reply = NULL;
1906 pa_stream_manager *m = (pa_stream_manager*)userdata;
1912 pa_assert_se(dbus_message_get_args(msg, NULL,
1913 DBUS_TYPE_STRING, &stream_type,
1914 DBUS_TYPE_INVALID));
1915 pa_log_info("stream_type[%s]", stream_type);
1917 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1919 /* Unset filter sink according to stream type */
1920 if (update_filter(m, NULL, NULL, NULL, stream_type) < 0) {
1921 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1922 DBUS_TYPE_INVALID));
1926 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1927 DBUS_TYPE_INVALID));
1930 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1931 dbus_message_unref(reply);
1934 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1935 const char *filter_name, *filter_controls, *stream_type;
1936 DBusMessage *reply = NULL;
1937 pa_stream_manager *m = (pa_stream_manager*)userdata;
1943 pa_assert_se(dbus_message_get_args(msg, NULL,
1944 DBUS_TYPE_STRING, &filter_name,
1945 DBUS_TYPE_STRING, &filter_controls,
1946 DBUS_TYPE_STRING, &stream_type,
1947 DBUS_TYPE_INVALID));
1948 pa_log_info("filter_name[%s], filter_controls[%s], stream_type[%s]", filter_name, filter_controls, stream_type);
1950 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1952 /* Control parameters to filter sink */
1953 if (control_filter(m, filter_name, filter_controls, stream_type, conn) < 0) {
1954 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1955 DBUS_TYPE_INVALID));
1959 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1960 DBUS_TYPE_INVALID));
1962 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1963 dbus_message_unref(reply);
1966 static bool check_stream_exist_by_pid(pa_stream_manager *m, uint32_t pid, const char *stream_role, stream_type_t type) {
1967 void *stream = NULL;
1969 const char *role = NULL;
1970 const char *app_pid_str = NULL;
1971 uint32_t app_pid = 0;
1974 pa_assert(stream_role);
1976 pa_log_info("pid[%u], role[%s], type[%d]", pid, stream_role, type);
1978 PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
1979 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1980 if (!pa_safe_streq(role, stream_role))
1983 if (!CHECK_STREAM_RUNNING(stream, type)) {
1984 pa_log_info("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
1988 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
1989 if (app_pid_str && !pa_atou(app_pid_str, &app_pid)) {
1990 if (app_pid == pid) {
1991 pa_log_info("found matching stream(%p, index:%u)", stream, GET_STREAM_INDEX(stream, type));
2000 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2003 const char *direction;
2004 stream_type_t stream_type = STREAM_SINK_INPUT;
2005 DBusMessage *reply = NULL;
2006 pa_stream_manager *m = (pa_stream_manager*)userdata;
2012 pa_assert_se(dbus_message_get_args(msg, NULL,
2013 DBUS_TYPE_UINT32, &pid,
2014 DBUS_TYPE_STRING, &type,
2015 DBUS_TYPE_STRING, &direction,
2016 DBUS_TYPE_INVALID));
2017 pa_log_info("pid[%u], type[%s], direction[%s]", pid, type, direction);
2019 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2021 if (pa_safe_streq(direction, "in"))
2022 stream_type = STREAM_SOURCE_OUTPUT;
2023 else if (pa_safe_streq(direction, "out"))
2024 stream_type = STREAM_SINK_INPUT;
2026 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
2027 DBUS_TYPE_INVALID));
2031 if (!check_stream_exist_by_pid(m, pid, type, stream_type)) {
2032 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM],
2033 DBUS_TYPE_INVALID));
2037 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
2038 DBUS_TYPE_INVALID));
2040 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2041 dbus_message_unref(reply);
2044 static bool find_the_lastest_stream(pa_stream_manager *m, stream_type_t type, const char ** stream_roles, int length, uint32_t *pid) {
2045 void *stream = NULL;
2048 const char *app_pid_str = NULL;
2049 uint32_t latest_pid = 0;
2050 pa_usec_t latest_time = 0;
2051 uint32_t tmp_pid = 0;
2052 pa_usec_t tmp_time = 0;
2056 pa_assert(stream_roles);
2059 PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
2060 if (!CHECK_STREAM_RUNNING(stream, type)) {
2061 pa_log_debug("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
2065 for (i = 0; i <length; i++) {
2069 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2070 if (!pa_safe_streq(stream_roles[i], role))
2073 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID_ORIGIN);
2074 if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid)) {
2075 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]);
2077 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
2078 if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid))
2079 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]);
2082 tmp_time = GET_STREAM_LAST_RUN_TIME(stream, type);
2083 if (latest_time <= tmp_time) {
2084 latest_time = tmp_time;
2085 latest_pid = tmp_pid;
2091 if (latest_pid > 0) {
2093 pa_log_info("found the stream(pid:%u)", *pid);
2097 pa_log_info("no match is found");
2101 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2102 const char *direction;
2105 stream_type_t stream_type = STREAM_SINK_INPUT;
2107 ret_msg_t ret_msg = RET_MSG_OK;
2109 DBusMessage *reply = NULL;
2110 pa_stream_manager *m = (pa_stream_manager*)userdata;
2116 pa_assert_se(dbus_message_get_args(msg, NULL,
2117 DBUS_TYPE_STRING, &direction,
2118 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &types, &length,
2119 DBUS_TYPE_INVALID));
2121 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2123 if (pa_safe_streq(direction, "in"))
2124 stream_type = STREAM_SOURCE_OUTPUT;
2125 else if (pa_safe_streq(direction, "out"))
2126 stream_type = STREAM_SINK_INPUT;
2128 pa_log_error("invalid direction[%s]", direction);
2129 goto invalid_argument;
2133 pa_log_error("At least one stream type should be contained");
2134 goto invalid_argument;
2137 if (!find_the_lastest_stream(m, stream_type, types, length, &pid))
2138 ret_msg = RET_MSG_ERROR_NO_STREAM;
2140 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID));
2141 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg],
2142 DBUS_TYPE_INVALID));
2143 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2144 dbus_message_unref(reply);
2148 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID));
2149 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
2150 DBUS_TYPE_INVALID));
2151 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2152 dbus_message_unref(reply);
2155 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2156 dbus_uint32_t id = 0;
2157 dbus_bool_t enable = 0;
2158 const char *target_stream = NULL;
2160 pa_sink_input *i = NULL;
2161 dbus_uint32_t duration = 0;
2163 DBusMessage *reply = NULL;
2164 pa_stream_manager *m = (pa_stream_manager*)userdata;
2165 stream_ducking *sd = NULL;
2166 bool target_matched = false;
2167 hal_ducking_activation_info ducking_activation_info;
2168 ret_msg_t ret_msg = RET_MSG_OK;
2174 pa_assert_se(dbus_message_get_args(msg, NULL,
2175 DBUS_TYPE_UINT32, &id,
2176 DBUS_TYPE_BOOLEAN, &enable,
2177 DBUS_TYPE_STRING, &target_stream,
2178 DBUS_TYPE_UINT32, &duration,
2179 DBUS_TYPE_DOUBLE, &ratio,
2180 DBUS_TYPE_INVALID));
2182 pa_log_info("id[%u], enable[%u], target stream[%s], duration[%u], ratio[%lf]",
2183 id, enable, target_stream, duration, ratio);
2185 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2187 /* get stream_ducking */
2188 sd = pa_hashmap_get(m->stream_duckings, (const void*)id);
2190 pa_log_error("no matched stream ducking for id[%u]", id);
2191 ret_msg = RET_MSG_ERROR_INTERNAL;
2192 goto _ACTIVATE_DUCKING_DONE;
2195 /* validate state with command */
2196 if ((enable && sd->state != STREAM_DUCKING_STATE_UNDUCKED) ||
2197 (!enable && sd->state != STREAM_DUCKING_STATE_DUCKED)) {
2198 pa_log_error("state validation failed - [%d,s:%u]", enable, sd->state);
2199 ret_msg = RET_MSG_ERROR_INVALID_STATE;
2200 goto _ACTIVATE_DUCKING_DONE;
2203 sd->duration = duration;
2205 sd->set_vol = PA_VOLUME_NORM * ratio;
2208 sd->state = STREAM_DUCKING_STATE_DUCKING;
2209 snprintf(sd->vol_key, VOLUME_KEY_LENGTH, "stream_ducking_%u_%s", id, target_stream);
2210 snprintf(sd->target_role, STREAM_ROLE_STR_MAX, "%s", target_stream);
2212 sd->state = STREAM_DUCKING_STATE_UNDUCKING;
2215 /* set volume ramp factor to target stream */
2216 PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
2217 if (!pa_safe_streq(target_stream, pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
2220 if (i->state == PA_SINK_INPUT_RUNNING) {
2221 target_matched = true;
2222 sd->ducking_stream_count++;
2226 pa_cvolume_ramp vol_ramp;
2228 pa_idxset_put(sd->idx_ducking_streams, (void *)i, NULL);
2230 pa_log_error("ducking: add volume_ramp factor, key[%s], set_vol[%u] to stream[idx:%u]",
2231 sd->vol_key, sd->set_vol, i->index);
2233 pa_cvolume_ramp_set(&vol_ramp, i->volume.channels,
2234 PA_VOLUME_RAMP_TYPE_LINEAR, (long)duration, sd->set_vol);
2236 if (i->state != PA_SINK_INPUT_RUNNING) {
2238 pa_cvolume_set(&vol, i->volume.channels, sd->set_vol);
2239 pa_sink_input_add_volume_factor(i, sd->vol_key, &vol);
2240 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, false);
2242 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, true);
2245 pa_log_error("unducking: remove volume(ramp) factor, key[%s] from stream[idx:%u]",
2246 sd->vol_key, i->index);
2248 pa_sink_input_remove_volume_factor(i, sd->vol_key);
2249 pa_sink_input_remove_volume_ramp_factor(i, sd->vol_key, true);
2254 memset(&sd->target_role, 0, sizeof(sd->target_role));
2255 memset(&sd->vol_key, 0, sizeof(sd->vol_key));
2258 pa_log_info("ducking stream count[%p,%d]", sd, sd->ducking_stream_count);
2260 _ACTIVATE_DUCKING_DONE:
2261 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
2262 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2263 dbus_message_unref(reply);
2265 if (ret_msg != RET_MSG_OK)
2268 /* notify ducking activation */
2269 ducking_activation_info.target_role = target_stream;
2270 ducking_activation_info.duration = duration;
2271 ducking_activation_info.ratio = ratio;
2272 ducking_activation_info.is_activated = enable;
2274 pa_hal_interface_notify_ducking_activation_changed(m->hal, &ducking_activation_info);
2276 if (target_matched == false) {
2277 /* change ducking state and send signal here,
2278 because ramp_finish_cb could not be called in this case */
2280 sd->state = STREAM_DUCKING_STATE_DUCKED;
2282 sd->state = STREAM_DUCKING_STATE_UNDUCKED;
2284 pa_log_info("send signal for ramp finished(but, no stream matched) - state[%u]", sd->state);
2286 send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
2290 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2291 dbus_uint32_t id = 0;
2292 DBusMessage *reply = NULL;
2293 pa_stream_manager *m = (pa_stream_manager*)userdata;
2294 stream_ducking *sd = NULL;
2295 dbus_bool_t is_ducked = FALSE;
2296 ret_msg_t ret_msg = RET_MSG_OK;
2302 pa_assert_se(dbus_message_get_args(msg, NULL,
2303 DBUS_TYPE_UINT32, &id,
2304 DBUS_TYPE_INVALID));
2306 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2308 /* get stream_ducking */
2309 sd = pa_hashmap_get(m->stream_duckings, (const void *)id);
2311 is_ducked = (dbus_bool_t)is_stream_ducked(sd);
2312 pa_log_info("id[%u], is_ducked[%p,%d]", id, sd, is_ducked);
2314 ret_msg = RET_MSG_ERROR_INTERNAL;
2315 pa_log_error("no matched stream ducking for id[%u]", id);
2318 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_ducked, DBUS_TYPE_INVALID));
2319 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
2321 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2322 dbus_message_unref(reply);
2325 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2327 pa_stream_manager *m = (pa_stream_manager*)userdata;
2333 for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
2334 if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name)) {
2335 pa_log_debug("Message signature [%s] (Expected [%s])", dbus_message_get_signature(msg), signature_args_for_in[idx]);
2336 if (pa_safe_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
2337 method_handlers[idx].receive_cb(conn, msg, userdata);
2338 return DBUS_HANDLER_RESULT_HANDLED;
2340 pa_log_warn("Wrong Argument Signature");
2341 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE, "Wrong Signature, Expected %s", signature_args_for_in[idx]);
2342 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2347 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2350 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
2351 pa_stream_manager *u = (pa_stream_manager*)userdata;
2352 const char *path, *interface, *member;
2358 path = dbus_message_get_path(m);
2359 interface = dbus_message_get_interface(m);
2360 member = dbus_message_get_member(m);
2362 pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
2364 if (!pa_safe_streq(path, STREAM_MANAGER_OBJECT_PATH))
2365 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2367 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2368 return handle_introspect(c, m, u);
2370 return handle_methods(c, m, u);
2373 return DBUS_HANDLER_RESULT_HANDLED;
2376 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level) {
2377 DBusMessage *signal_msg;
2378 DBusMessageIter msg_iter;
2381 pa_assert(direction);
2382 pa_assert(volume_type);
2384 pa_log_debug("direction[%s], type[%s], level[%d]", direction, volume_type, volume_level);
2386 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED)));
2387 dbus_message_iter_init_append(signal_msg, &msg_iter);
2389 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &direction);
2390 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &volume_type);
2391 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &volume_level);
2393 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2394 dbus_message_unref(signal_msg);
2398 void send_ducking_state_changed_signal(DBusConnection *conn, const int index, const int is_ducked)
2400 DBusMessage *signal_msg;
2401 DBusMessageIter msg_iter;
2405 pa_log_debug("trigger_index(%d) : is_ducked(%d)", index, is_ducked);
2407 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_DUCKING_STATE_CHANGED)));
2408 dbus_message_iter_init_append(signal_msg, &msg_iter);
2410 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &index);
2411 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &is_ducked);
2413 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2414 dbus_message_unref(signal_msg);
2419 void send_command_signal(DBusConnection *conn, const char *name, int value) {
2420 DBusMessage *signal_msg;
2421 DBusMessageIter msg_iter;
2426 pa_log_debug("name[%s], value[%d]", name, value);
2428 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_COMMAND)));
2429 dbus_message_iter_init_append(signal_msg, &msg_iter);
2431 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2432 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &value);
2434 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2435 dbus_message_unref(signal_msg);
2438 int32_t init_sm_dbus(pa_stream_manager *m) {
2441 #ifdef USE_DBUS_PROTOCOL
2442 m->dbus_protocol = pa_dbus_protocol_get(m->core);
2443 pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
2444 pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2447 pa_dbus_connection *conn = NULL;
2448 static const DBusObjectPathVTable vtable = {
2449 .message_function = method_handler_for_vt,
2452 dbus_error_init(&err);
2454 if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
2456 pa_dbus_connection_unref(conn);
2458 pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
2461 pa_log_notice("Got dbus connection");
2463 m->dbus_conn = conn;
2464 pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
2469 void deinit_sm_dbus(pa_stream_manager *m) {
2472 #ifdef USE_DBUS_PROTOCOL
2473 if (m->dbus_protocol) {
2474 pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2475 pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
2476 pa_dbus_protocol_unref(m->dbus_protocol);
2477 m->dbus_protocol = NULL;
2481 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
2482 pa_log_error("failed to unregister object path");
2483 m->dbus_conn = NULL;