2 This file is part of PulseAudio.
4 Copyright 2017 Sangchul Lee <sc11.lee@samsung.com>
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 #include <pulsecore/proplist-util.h>
29 #include "stream-manager-priv.h"
30 #include "stream-manager-dbus-priv.h"
31 #include "stream-manager-volume-priv.h"
32 #include "stream-manager-filter-priv.h"
33 #include "stream-manager-restriction-priv.h"
35 static const char *dbus_str_none = "none";
36 static const char *stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK",
37 "STREAM_MANAGER_RETURN_ERROR_INTERNAL",
38 "STREAM_MANAGER_RETURN_ERROR_NO_STREAM",
39 "STREAM_MANAGER_RETURN_ERROR_INVALID_ARGUMENT",
40 "STREAM_MANAGER_RETURN_ERROR_DEVICE_NOT_FOUND",
41 "STREAM_MANAGER_RETURN_ERROR_POLICY",
42 "STREAM_MANAGER_RETURN_ERROR_INVALID_STATE"};
44 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
45 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
46 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
47 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
48 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
49 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
50 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
51 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
52 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
53 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
54 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
55 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
56 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
59 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
61 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
62 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata);
63 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
64 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
65 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata);
66 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata);
67 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
69 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata);
71 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
72 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata);
74 static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
77 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level);
79 static pa_dbus_arg_info get_stream_info_args[] = { { "stream_type", "s", "in" },
80 { "priority", "i", "out" },
81 { "route_type", "i", "out" },
82 { "volume_types", "as", "out" },
83 { "avail_in_devices", "as", "out" },
84 { "avail_out_devices", "as", "out" },
85 { "avail_frameworks", "as", "out"} };
86 static pa_dbus_arg_info get_stream_list_args[] = { { "stream_type", "as", "out" },
87 { "priority", "ai", "out" } };
88 static pa_dbus_arg_info set_stream_route_devices_args[] = { { "parent_id", "u", "in" },
89 { "route_in_devices", "au", "in" },
90 { "route_out_devices", "au", "in" },
91 { "ret_msg", "s", "out" } };
92 static pa_dbus_arg_info set_stream_route_option_args[] = { { "parent_id", "u", "in" },
93 { "name", "s", "in" },
94 { "value", "i", "in" },
95 { "ret_msg", "s", "out" } };
96 static pa_dbus_arg_info set_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
97 { "io_direction", "s", "in" },
98 { "device_id", "u", "in" },
99 { "ret_msg", "s", "out" } };
100 static pa_dbus_arg_info get_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
101 { "in_device_id", "u", "out" },
102 { "out_device_id", "u", "out" },
103 { "ret_msg", "s", "out" } };
104 static pa_dbus_arg_info set_stream_preemptive_device_args[] = { { "stream_type", "s", "in" },
105 { "io_direction", "s", "in" },
106 { "device_id", "u", "in" },
107 { "ret_msg", "s", "out" } };
108 static pa_dbus_arg_info get_stream_preemptive_device_args[] = { { "stream_type", "s", "in" },
109 { "in_device_id", "u", "out" },
110 { "out_device_id", "u", "out" },
111 { "ret_msg", "s", "out" } };
112 static pa_dbus_arg_info set_volume_level_args[] = { { "io_direction", "s", "in" },
113 { "type", "s", "in" },
114 { "level", "u", "in" },
115 { "ret_msg", "s", "out" } };
116 static pa_dbus_arg_info get_volume_level_args[] = { { "io_direction", "s", "in" },
117 { "type", "s", "in" },
118 { "level", "u", "out" },
119 { "ret_msg", "s", "out" } };
120 static pa_dbus_arg_info get_volume_max_level_args[] = { { "io_direction", "s", "in" },
121 { "type", "s", "in" },
122 { "level", "u", "out" },
123 { "ret_msg", "s", "out" } };
124 static pa_dbus_arg_info set_volume_mute_args[] = { { "io_direction", "s", "in" },
125 { "type", "s", "in" },
127 { "ret_msg", "s", "out" } };
128 static pa_dbus_arg_info get_volume_mute_args[] = { { "io_direction", "s", "in" },
129 { "type", "s", "in" },
130 { "on", "u", "out" },
131 { "ret_msg", "s", "out" } };
132 static pa_dbus_arg_info set_volume_ratio_args[] = { { "io_direction", "s", "in" },
133 { "idx", "u", "in" },
134 { "ratio", "d", "in" },
135 { "ret_msg", "s", "out" } };
136 static pa_dbus_arg_info get_volume_ratio_args[] = { { "io_direction", "s", "in" },
137 { "idx", "u", "in" },
138 { "ratio", "d", "out" },
139 { "ret_msg", "s", "out" } };
140 static pa_dbus_arg_info get_current_volume_type_args[] = { { "io_direction", "s", "in" },
141 { "type", "s", "out" },
142 { "ret_msg", "s", "out" } };
143 static pa_dbus_arg_info get_current_media_routing_path_args[] = { { "io_direction", "s", "in" },
144 { "device_type", "s", "out" },
145 { "ret_msg", "s", "out" } };
146 static pa_dbus_arg_info update_focus_status_args[] = { { "parent_id", "u", "in" },
147 { "focus_status", "u", "in" },
148 { "ret_msg", "s", "out" } };
149 static pa_dbus_arg_info update_focus_status_by_focus_id_args[] = { { "focus_id", "i", "in" },
150 { "focus_status", "u", "in" },
151 { "ret_msg", "s", "out" } };
152 static pa_dbus_arg_info update_restriction_args[] = { { "name", "s", "in" },
153 { "value", "u", "in" },
154 { "ret_msg", "s", "out" } };
155 static pa_dbus_arg_info update_call_parameters_args[] = { { "parameters", "s", "in" },
156 { "ret_msg", "s", "out" } };
157 static pa_dbus_arg_info set_filter_args[] = { { "filter_name", "s", "in" },
158 { "filter_parameters", "s", "in" },
159 { "filter_group", "s", "in" },
160 { "stream_type", "s", "in" },
161 { "ret_msg", "s", "out" } };
162 static pa_dbus_arg_info unset_filter_args[] = { { "stream_type", "s", "in" },
163 { "ret_msg", "s", "out" } };
164 static pa_dbus_arg_info control_filter_args[] = { { "filter_name", "s", "in" },
165 { "filter_controls", "s", "in" },
166 { "stream_type", "s", "in" },
167 { "ret_msg", "s", "out" } };
168 static pa_dbus_arg_info check_stream_exist_by_pid_args[] = { { "pid", "u", "in" },
169 { "stream_type", "s", "in" },
170 { "io_direction", "s", "in" },
171 { "ret_msg", "s", "out" } };
172 static pa_dbus_arg_info get_pid_of_latest_stream_args[] = { { "io_direction", "s", "in" },
173 { "stream_types", "as", "in" },
174 { "pid", "u", "out" },
175 { "ret_msg", "s", "out" } };
176 static pa_dbus_arg_info activate_ducking_args[] = { { "index", "u", "in" },
177 { "enable", "b", "in" },
178 { "target_stream", "s", "in" },
179 { "duration", "u", "in" },
180 { "ratio", "d", "in" },
181 { "ret_msg", "s", "out" } };
183 static pa_dbus_arg_info get_ducking_state_args[] = { { "index", "u", "in" },
184 { "is_ducked", "b", "out" },
185 { "ret_msg", "s", "out" } };
186 static pa_dbus_arg_info set_remote_permission_args[] = { { "type", "s", "in" },
187 { "index", "u", "in" },
188 { "allowed", "b", "in" } };
189 static pa_dbus_arg_info discover_remote_device_args[] = { { "enable", "b", "in" } };
190 static pa_dbus_arg_info publish_local_device_args[] = { { "enable", "b", "in" } };
192 static const char* signature_args_for_in[] = {
193 "s", /* METHOD_HANDLER_GET_STREAM_INFO */
194 "", /* METHOD_HANDLER_GET_STREAM_LIST */
195 "uauau", /* METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES */
196 "usi", /* METHOD_HANDLER_SET_STREAM_ROUTE_OPTION */
197 "usu", /* METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE */
198 "u", /* METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE */
199 "ssu", /* METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE */
200 "s", /* METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE */
201 "ssu", /* METHOD_HANDLER_SET_VOLUME_LEVEL */
202 "ss", /* METHOD_HANDLER_GET_VOLUME_LEVEL */
203 "ss", /* METHOD_HANDLER_GET_VOLUME_MAX_LEVEL */
204 "ssu", /* METHOD_HANDLER_SET_VOLUME_MUTE */
205 "ss", /* METHOD_HANDLER_GET_VOLUME_MUTE */
206 "sud", /* METHOD_HANDLER_SET_VOLUME_RATIO */
207 "su", /* METHOD_HANDLER_GET_VOLUME_RATIO */
208 "s", /* METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE */
209 "s", /* METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH */
210 "uu", /* METHOD_HANDLER_UPDATE_FOCUS_STATUS */
211 "iu", /* METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID */
212 "su", /* METHOD_HANDLER_UPDATE_RESTRICTION */
213 "s", /* METHOD_HANDLER_UPDATE_CALL_PARAMETERS */
214 "ssss", /* METHOD_HANDLER_SET_FILTER */
215 "s", /* METHOD_HANDLER_UNSET_FILTER */
216 "sss", /* METHOD_HANDLER_CONTROL_FILTER */
217 "uss", /* METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID */
218 "sas", /* METHOD_HANDLER_GET_PID_OF_LATEST_STREAM */
219 "ubsud", /* METHOD_HANDLER_ACTIVATE_DUCKING */
220 "u", /* METHOD_HANDLER_GET_DUCKING_STATE */
221 "sub", /* METHOD_HANDLER_SET_REMOTE_PERMISSION */
222 "b", /* METHOD_HANDLER_DISCOVER_REMOTE_DEVICE */
223 "b" /* METHOD_HANDLER_PUBLISH_LOCAL_DEVICE */
226 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
227 [METHOD_HANDLER_GET_STREAM_INFO] = {
228 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
229 .arguments = get_stream_info_args,
230 .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
231 .receive_cb = handle_get_stream_info },
232 [METHOD_HANDLER_GET_STREAM_LIST] = {
233 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
234 .arguments = get_stream_list_args,
235 .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
236 .receive_cb = handle_get_stream_list },
237 [METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES] = {
238 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
239 .arguments = set_stream_route_devices_args,
240 .n_arguments = sizeof(set_stream_route_devices_args) / sizeof(pa_dbus_arg_info),
241 .receive_cb = handle_set_stream_route_devices },
242 [METHOD_HANDLER_SET_STREAM_ROUTE_OPTION] = {
243 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
244 .arguments = set_stream_route_option_args,
245 .n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
246 .receive_cb = handle_set_stream_route_option },
247 [METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE] = {
248 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREFERRED_DEVICE,
249 .arguments = set_stream_preferred_device_args,
250 .n_arguments = sizeof(set_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
251 .receive_cb = handle_set_stream_preferred_device },
252 [METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE] = {
253 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREFERRED_DEVICE,
254 .arguments = get_stream_preferred_device_args,
255 .n_arguments = sizeof(get_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
256 .receive_cb = handle_get_stream_preferred_device },
257 [METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE] = {
258 .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREEMPTIVE_DEVICE,
259 .arguments = set_stream_preemptive_device_args,
260 .n_arguments = sizeof(set_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
261 .receive_cb = handle_set_stream_preemptive_device },
262 [METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE] = {
263 .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREEMPTIVE_DEVICE,
264 .arguments = get_stream_preemptive_device_args,
265 .n_arguments = sizeof(get_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
266 .receive_cb = handle_get_stream_preemptive_device },
267 [METHOD_HANDLER_SET_VOLUME_LEVEL] = {
268 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
269 .arguments = set_volume_level_args,
270 .n_arguments = sizeof(set_volume_level_args) / sizeof(pa_dbus_arg_info),
271 .receive_cb = handle_set_volume_level },
272 [METHOD_HANDLER_GET_VOLUME_LEVEL] = {
273 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
274 .arguments = get_volume_level_args,
275 .n_arguments = sizeof(get_volume_level_args) / sizeof(pa_dbus_arg_info),
276 .receive_cb = handle_get_volume_level },
277 [METHOD_HANDLER_GET_VOLUME_MAX_LEVEL] = {
278 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
279 .arguments = get_volume_max_level_args,
280 .n_arguments = sizeof(get_volume_max_level_args) / sizeof(pa_dbus_arg_info),
281 .receive_cb = handle_get_volume_max_level },
282 [METHOD_HANDLER_SET_VOLUME_MUTE] = {
283 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE,
284 .arguments = set_volume_mute_args,
285 .n_arguments = sizeof(set_volume_mute_args) / sizeof(pa_dbus_arg_info),
286 .receive_cb = handle_set_volume_mute },
287 [METHOD_HANDLER_GET_VOLUME_MUTE] = {
288 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE,
289 .arguments = get_volume_mute_args,
290 .n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
291 .receive_cb = handle_get_volume_mute },
292 [METHOD_HANDLER_SET_VOLUME_RATIO] = {
293 .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_RATIO,
294 .arguments = set_volume_ratio_args,
295 .n_arguments = sizeof(set_volume_ratio_args) / sizeof(pa_dbus_arg_info),
296 .receive_cb = handle_set_volume_ratio },
297 [METHOD_HANDLER_GET_VOLUME_RATIO] = {
298 .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_RATIO,
299 .arguments = get_volume_ratio_args,
300 .n_arguments = sizeof(get_volume_ratio_args) / sizeof(pa_dbus_arg_info),
301 .receive_cb = handle_get_volume_ratio },
302 [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
303 .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
304 .arguments = get_current_volume_type_args,
305 .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
306 .receive_cb = handle_get_current_volume_type },
307 [METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH] = {
308 .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_MEDIA_ROUTING_PATH,
309 .arguments = get_current_media_routing_path_args,
310 .n_arguments = sizeof(get_current_media_routing_path_args) / sizeof(pa_dbus_arg_info),
311 .receive_cb = handle_get_current_media_routing_path },
312 [METHOD_HANDLER_UPDATE_FOCUS_STATUS] = {
313 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS,
314 .arguments = update_focus_status_args,
315 .n_arguments = sizeof(update_focus_status_args) / sizeof(pa_dbus_arg_info),
316 .receive_cb = handle_update_focus_status },
317 [METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID] = {
318 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS_BY_FOCUS_ID,
319 .arguments = update_focus_status_by_focus_id_args,
320 .n_arguments = sizeof(update_focus_status_by_focus_id_args) / sizeof(pa_dbus_arg_info),
321 .receive_cb = handle_update_focus_status_by_focus_id },
322 [METHOD_HANDLER_UPDATE_RESTRICTION] = {
323 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_RESTRICTION,
324 .arguments = update_restriction_args,
325 .n_arguments = sizeof(update_restriction_args) / sizeof(pa_dbus_arg_info),
326 .receive_cb = handle_update_restriction },
327 [METHOD_HANDLER_UPDATE_CALL_PARAMETERS] = {
328 .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_CALL_PARAMETERS,
329 .arguments = update_call_parameters_args,
330 .n_arguments = sizeof(update_call_parameters_args) / sizeof(pa_dbus_arg_info),
331 .receive_cb = handle_update_call_parameters },
332 [METHOD_HANDLER_SET_FILTER] = {
333 .method_name = STREAM_MANAGER_METHOD_NAME_SET_FILTER,
334 .arguments = set_filter_args,
335 .n_arguments = sizeof(set_filter_args) / sizeof(pa_dbus_arg_info),
336 .receive_cb = handle_set_filter },
337 [METHOD_HANDLER_UNSET_FILTER] = {
338 .method_name = STREAM_MANAGER_METHOD_NAME_UNSET_FILTER,
339 .arguments = unset_filter_args,
340 .n_arguments = sizeof(unset_filter_args) / sizeof(pa_dbus_arg_info),
341 .receive_cb = handle_unset_filter },
342 [METHOD_HANDLER_CONTROL_FILTER] = {
343 .method_name = STREAM_MANAGER_METHOD_NAME_CONTROL_FILTER,
344 .arguments = control_filter_args,
345 .n_arguments = sizeof(control_filter_args) / sizeof(pa_dbus_arg_info),
346 .receive_cb = handle_control_filter },
347 [METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID] = {
348 .method_name = STREAM_MANAGER_METHOD_NAME_CHECK_STREAM_EXIST_BY_PID,
349 .arguments = check_stream_exist_by_pid_args,
350 .n_arguments = sizeof(check_stream_exist_by_pid_args) / sizeof(pa_dbus_arg_info),
351 .receive_cb = handle_check_stream_exist_by_pid },
352 [METHOD_HANDLER_GET_PID_OF_LATEST_STREAM] = {
353 .method_name = STREAM_MANAGER_METHOD_NAME_GET_PID_OF_LATEST_STREAM,
354 .arguments = get_pid_of_latest_stream_args,
355 .n_arguments = sizeof(get_pid_of_latest_stream_args) / sizeof(pa_dbus_arg_info),
356 .receive_cb = handle_get_pid_of_latest_stream },
357 [METHOD_HANDLER_ACTIVATE_DUCKING] = {
358 .method_name = STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING,
359 .arguments = activate_ducking_args,
360 .n_arguments = sizeof(activate_ducking_args) / sizeof(pa_dbus_arg_info),
361 .receive_cb = handle_activate_ducking },
362 [METHOD_HANDLER_GET_DUCKING_STATE] = {
363 .method_name = STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE,
364 .arguments = get_ducking_state_args,
365 .n_arguments = sizeof(get_ducking_state_args) / sizeof(pa_dbus_arg_info),
366 .receive_cb = handle_get_ducking_state },
367 [METHOD_HANDLER_NAME_SET_REMOTE_PERMISSION] = {
368 .method_name = STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION,
369 .arguments = set_remote_permission_args,
370 .n_arguments = sizeof(set_remote_permission_args) / sizeof(pa_dbus_arg_info),
371 .receive_cb = handle_set_remote_permission },
372 [METHOD_HANDLER_DISCOVER_REMOTE_DEVICE] = {
373 .method_name = STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICE,
374 .arguments = discover_remote_device_args,
375 .n_arguments = sizeof(discover_remote_device_args) / sizeof(pa_dbus_arg_info),
376 .receive_cb = handle_discover_remote_device },
377 [METHOD_HANDLER_PUBLISH_LOCAL_DEVICE] = {
378 .method_name = STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE,
379 .arguments = publish_local_device_args,
380 .n_arguments = sizeof(publish_local_device_args) / sizeof(pa_dbus_arg_info),
381 .receive_cb = handle_publish_local_device },
384 static int get_stream_type(const char *direction, stream_type_t *stream_type) {
385 if (pa_safe_streq(direction, "in"))
386 *stream_type = STREAM_SOURCE_OUTPUT;
387 else if (pa_safe_streq(direction, "out"))
388 *stream_type = STREAM_SINK_INPUT;
395 static int get_direction_type(const char *direction, stream_direction_t *direction_type) {
396 if (pa_safe_streq(direction, "in"))
397 *direction_type = STREAM_DIRECTION_IN;
398 else if (pa_safe_streq(direction, "out"))
399 *direction_type = STREAM_DIRECTION_OUT;
406 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
407 const char *xml = STREAM_MGR_INTROSPECT_XML;
408 DBusMessage *r = NULL;
414 pa_assert_se((r = dbus_message_new_method_return(msg)));
415 pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
418 pa_assert_se(dbus_connection_send((conn), r, NULL));
419 dbus_message_unref(r);
422 return DBUS_HANDLER_RESULT_HANDLED;
425 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
426 pa_stream_manager *m = (pa_stream_manager *)userdata;
428 DBusMessage *reply = NULL;
429 DBusMessageIter msg_iter;
435 pa_assert_se(dbus_message_get_args(msg, NULL,
437 pa_log_info("get stream list");
439 memset(&list, 0, sizeof(stream_list));
440 pa_assert_se((reply = dbus_message_new_method_return(msg)));
441 dbus_message_iter_init_append(reply, &msg_iter);
442 if (!get_available_streams(m, &list)) {
443 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
444 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
446 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
447 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, NULL, 0);
449 pa_assert_se(dbus_connection_send(conn, reply, NULL));
450 dbus_message_unref(reply);
453 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
454 pa_stream_manager *m = (pa_stream_manager *)userdata;
456 stream_info_per_type info;
457 DBusMessage *reply = NULL;
458 DBusMessageIter msg_iter;
464 pa_assert_se(dbus_message_get_args(msg, NULL,
465 DBUS_TYPE_STRING, &type,
467 pa_log_info("type[%s]", type);
469 memset(&info, 0, sizeof(stream_info_per_type));
470 pa_assert_se((reply = dbus_message_new_method_return(msg)));
471 dbus_message_iter_init_append(reply, &msg_iter);
472 get_stream_info(m, type, &info);
473 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
474 pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
475 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.volume_types, STREAM_DIRECTION_MAX);
476 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
477 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
478 pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
480 pa_assert_se(dbus_connection_send(conn, reply, NULL));
481 dbus_message_unref(reply);
484 static bool check_all_requested_devices_connected(pa_stream_manager *m, uint32_t *device_list, uint32_t length) {
485 pa_idxset *dm_device_list;
486 uint32_t found_count = 0;
490 pa_assert(device_list);
492 dm_device_list = pa_device_manager_get_device_list(m->dm);
494 for (i = 0; i < length; i++) {
495 pa_tz_device *dm_device;
496 uint32_t dm_device_id;
499 PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
500 dm_device_id = pa_tz_device_get_id(dm_device);
501 if (device_list[i] == dm_device_id) {
502 pa_log_debug("device[%u] is connected", dm_device_id);
504 if (length == found_count)
514 static ret_msg_t update_devices_and_trigger_routing(pa_stream_manager *m, stream_parent *sp, stream_type_t type) {
516 pa_idxset *idx_streams = NULL;
518 void *cur_highest_priority_stream = NULL;
519 stream_route_type_t route_type = STREAM_ROUTE_TYPE_DEFAULT;
520 ret_msg_t ret = RET_MSG_OK;
525 if (type == STREAM_SINK_INPUT) {
526 idx_streams = sp->idx_sink_inputs;
527 cur_highest_priority_stream = (void*)m->cur_highest_priority.sink_input;
529 idx_streams = sp->idx_source_outputs;
530 cur_highest_priority_stream = (void*)m->cur_highest_priority.source_output;
533 /* update route type of this stream parent */
534 if (sp->route_type == STREAM_ROUTE_TYPE_DEFAULT) {
535 PA_IDXSET_FOREACH(stream, idx_streams, idx) {
536 /* find route type of stream */
537 if (get_route_type(stream, type, false, &route_type))
538 return RET_MSG_ERROR_INTERNAL;
540 if (route_type == STREAM_ROUTE_TYPE_MANUAL ||
541 route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
542 sp->route_type = route_type;
543 pa_log_info(" -- the route type is [%d]", route_type);
545 pa_log_error(" -- the route type is not valid[%d]", route_type);
546 return RET_MSG_ERROR_POLICY;
551 /* if any stream that belongs to this id has been activated, do notify right away */
552 if (sp->route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
553 PA_IDXSET_FOREACH(stream, idx_streams, idx) {
554 pa_log_debug(" -- stream->index[%u] belongs to this stream parent[%p], do notify for the select proper source",
555 GET_STREAM_INDEX(stream, type), sp);
556 ret = do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, false, stream);
559 /* trigger only when it occupies routing path */
560 if (cur_highest_priority_stream && pa_idxset_get_by_data(idx_streams, cur_highest_priority_stream, NULL)) {
561 pa_log_debug(" -- cur_highest_priority_stream->index[%u] belongs to this stream_parent[%p], do notify for the route change",
562 GET_STREAM_INDEX(cur_highest_priority_stream, type), sp);
563 ret = do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, false, cur_highest_priority_stream);
564 if (!ret && is_stream_related_call_active_routing(PA_OBJECT(cur_highest_priority_stream)) && m->on_call) {
565 pa_log_info("set active device for new call route device");
566 change_active_route_for_call(m, PA_OBJECT(cur_highest_priority_stream), false);
574 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
575 pa_stream_manager *m = (pa_stream_manager *)userdata;
577 dbus_uint32_t *in_device_list = NULL;
578 dbus_uint32_t *out_device_list = NULL;
579 dbus_uint32_t id = 0;
580 dbus_uint32_t list_len_in = 0;
581 dbus_uint32_t list_len_out = 0;
582 stream_parent *sp = NULL;
583 ret_msg_t ret = RET_MSG_OK;
589 pa_assert_se(dbus_message_get_args(msg, NULL,
590 DBUS_TYPE_UINT32, &id,
591 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &in_device_list, &list_len_in,
592 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &out_device_list, &list_len_out,
594 pa_log_info("id[%u], in_device_list[%p]:length[%u], out_device_list[%p]:length[%u]",
595 id, in_device_list, list_len_in, out_device_list, list_len_out);
597 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
599 pa_log_error("could not find matching client for this parent_id[%u]", id);
600 ret = RET_MSG_ERROR_INTERNAL;
603 if (!in_device_list && !out_device_list) {
604 pa_log_error("invalid arguments");
605 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
608 if (!sp->idx_route_in_devices || !sp->idx_route_out_devices) {
609 pa_log_error("failed to update, idx_route_in_devices[%p], idx_route_out_devices[%p]",
610 sp->idx_route_in_devices, sp->idx_route_out_devices);
611 ret = RET_MSG_ERROR_INTERNAL;
615 /* check if all the requested devices are connected now */
616 if (in_device_list && !check_all_requested_devices_connected(m, in_device_list, list_len_in)) {
617 pa_log_error("could not find requested in-devices");
618 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
621 if (out_device_list && !check_all_requested_devices_connected(m, out_device_list, list_len_out)) {
622 pa_log_error("could not find requested out-devices");
623 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
627 pa_idxset_remove_all(sp->idx_route_in_devices, pa_xfree);
628 if (in_device_list) {
629 for (i = 0; i < list_len_in; i++) {
630 pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(dbus_uint32_t)), NULL);
631 pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
634 if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SOURCE_OUTPUT)))
637 pa_idxset_remove_all(sp->idx_route_out_devices, pa_xfree);
638 if (out_device_list) {
639 for (i = 0; i < list_len_out; i++) {
640 pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(dbus_uint32_t)), NULL);
641 pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
645 ret = update_devices_and_trigger_routing(m, sp, STREAM_SINK_INPUT);
648 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
651 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
652 pa_stream_manager *m = (pa_stream_manager *)userdata;
653 dbus_uint32_t id = 0;
654 const char *name = NULL;
655 dbus_int32_t value = 0;
656 bool updated = false;
657 stream_parent *sp = NULL;
658 stream_route_option route_option;
659 ret_msg_t ret = RET_MSG_OK;
665 pa_assert_se(dbus_message_get_args(msg, NULL,
666 DBUS_TYPE_UINT32, &id,
667 DBUS_TYPE_STRING, &name,
668 DBUS_TYPE_INT32, &value,
670 pa_log_info("id[%u], name[%s], value[%d]", id, name, value);
672 sp = pa_hashmap_get(m->stream_parents, (const void*)id);
675 route_option.name = name;
676 route_option.value = value;
678 /* if any stream that belongs to this id has been activated, do notify right away */
679 if (m->cur_highest_priority.sink_input) {
680 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
681 pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
682 (m->cur_highest_priority.sink_input)->index, id);
683 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
687 if (m->cur_highest_priority.source_output) {
688 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
689 pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
690 (m->cur_highest_priority.source_output)->index, id);
691 do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SOURCE_OUTPUT, false, &route_option);
696 pa_log_error("invalid state");
697 ret = RET_MSG_ERROR_NO_STREAM;
700 pa_log_error("invalid arguments");
701 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
704 pa_log_error("could not find matching client for this parent_id[%u]", id);
705 ret = RET_MSG_ERROR_INTERNAL;
708 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
711 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) {
716 if (device_id == 0) {
717 /* get a device of default role from previous device type */
718 if (!(*device = pa_device_manager_get_device(m->dm, sp->preferred_device.types[direction], NULL))) {
719 pa_log_error("could not get device[%s]", sp->preferred_device.types[direction]);
722 pa_log_debug("unset preferred device, rollback to type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
724 /* get the device of device id */
725 if (!(*device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
726 pa_log_error("could not get device by id[%u]", device_id);
729 pa_log_debug("requested preferred device type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
735 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
736 pa_stream_manager *m = (pa_stream_manager *)userdata;
737 const char *device_direction = NULL;
738 dbus_uint32_t sp_id = 0;
739 dbus_uint32_t device_id = 0;
742 stream_direction_t direction;
743 pa_tz_device *device;
744 pa_tz_device *prev_device;
745 const char *device_role;
746 const char *prev_device_type;
747 const char *prev_device_role;
748 stream_parent *sp = NULL;
752 pa_proplist *device_props;
753 uint32_t stream_index;
755 void *new_device = NULL;
756 ret_msg_t ret = RET_MSG_OK;
762 pa_assert_se(dbus_message_get_args(msg, NULL,
763 DBUS_TYPE_UINT32, &sp_id,
764 DBUS_TYPE_STRING, &device_direction,
765 DBUS_TYPE_UINT32, &device_id,
767 pa_log_info("stream parent id[%u], device direction[%s], device_id[%u]", sp_id, device_direction, device_id);
769 if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
770 pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
771 ret = RET_MSG_ERROR_INTERNAL;
775 if (get_direction_type(device_direction, &direction) != 0) {
776 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
780 /* allow only auto routing type */
781 if (sp->route_type != STREAM_ROUTE_TYPE_AUTO &&
782 sp->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
783 pa_log_error("not allowed this route type[%d] of this parent_id[%u]", sp->route_type, sp_id);
784 ret = RET_MSG_ERROR_POLICY;
788 if (device_id == 0 && !sp->preferred_device.types[direction]) {
789 pa_log_debug("it is already unset");
793 if (get_device_for_preference(m, sp, direction, device_id, &device) < 0) {
794 ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
798 /* only allow built-in device types */
799 if (!device_type_is_builtin(device->type)) {
800 pa_log_error("This device(id:%u, type:%s) is not built-in type", device_id, device->type);
801 ret = RET_MSG_ERROR_POLICY;
805 /* get default role of the device */
806 device_role = pa_tz_device_get_role(device, NULL);
808 sp->preferred_device.types[direction] = (device_id == 0) ? NULL : device->type;
809 sp->preferred_device.roles[direction] = (device_id == 0) ? NULL : device_role;
811 pa_log_info("preferred device role is set to [%s] of device type[%s], direction[%s]",
812 sp->preferred_device.roles[direction], device->type, direction == STREAM_DIRECTION_OUT ? "out" : "in");
814 streams = (direction == STREAM_DIRECTION_OUT) ? sp->idx_sink_inputs : sp->idx_source_outputs;
815 devices = (direction == STREAM_DIRECTION_OUT) ? device->playback_devices : device->capture_devices;
817 count = pa_idxset_size(streams);
818 PA_IDXSET_FOREACH(stream, streams, idx) {
819 props = GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ?
820 STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT);
821 pa_log_info("stream index(%u), props %p", (direction == STREAM_DIRECTION_OUT) ? PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index, props);
822 device_props = (direction == STREAM_DIRECTION_OUT) ?
823 PA_SINK_INPUT(stream)->sink->proplist : PA_SOURCE_OUTPUT(stream)->source->proplist;
824 stream_index = (direction == STREAM_DIRECTION_OUT) ?
825 PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index;
828 pa_proplist_unset(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
830 pa_proplist_sets(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE, device_role);
832 prev_device_type = pa_proplist_gets(props, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
833 prev_device_role = pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE);
835 if (pa_safe_streq(prev_device_type, device->type)) {
836 /* If the request is for the same device type,
837 * new device role should be applied - move streams. */
838 if (!pa_safe_streq(prev_device_role, device_role)) {
839 new_device = pa_hashmap_get(devices, device_role);
840 pa_log_debug("move stream[%u]: [%s][%s -> %s]",
841 stream_index, prev_device_type, prev_device_role, device_role);
844 /* If the request is for a different device type,
845 * check the previous device role and move streams to default role if needed. */
846 if ((prev_device = pa_device_manager_get_device(m->dm, prev_device_type, NULL)))
847 new_device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
848 prev_device->playback_devices : prev_device->capture_devices);
850 device_props = (direction == STREAM_DIRECTION_OUT) ? PA_SINK(new_device)->proplist : PA_SOURCE(new_device)->proplist;
851 pa_log_debug("may move stream[%u] to default role: [%s][%s -> %s]",
852 stream_index, prev_device_type, prev_device_role, pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE));
856 (direction == STREAM_DIRECTION_OUT) ? pa_sink_input_move_to(stream, PA_SINK(new_device), false) :
857 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
860 /* Use PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED here.
861 * It's not about the focus change, but this command exactly does what is needed here
862 * including updating the highest priority, find the next stream to be set to HAL as well as
863 * change the state of the builtin-device that use internal codec. */
864 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
865 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
870 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
873 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
874 pa_stream_manager *m = (pa_stream_manager *)userdata;
875 stream_parent *sp = NULL;
876 dbus_uint32_t sp_id = 0;
877 uint32_t in_device_id = 0;
878 uint32_t out_device_id = 0;
879 const char *pref_in_type, *pref_out_type;
880 const char *pref_in_role, *pref_out_role;
881 pa_idxset *dm_device_list;
882 pa_tz_device *dm_device;
883 dm_device_direction_t dm_direction;
885 ret_msg_t ret = RET_MSG_OK;
886 DBusMessage *reply = NULL;
892 pa_assert_se(dbus_message_get_args(msg, NULL,
893 DBUS_TYPE_UINT32, &sp_id,
895 pa_log_info("stream parent id[%u]", sp_id);
897 pa_assert_se((reply = dbus_message_new_method_return(msg)));
899 if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
900 pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
901 ret = RET_MSG_ERROR_INTERNAL;
905 pref_in_type = sp->preferred_device.types[STREAM_DIRECTION_IN];
906 pref_in_role = sp->preferred_device.roles[STREAM_DIRECTION_IN];
907 pref_out_type = sp->preferred_device.types[STREAM_DIRECTION_OUT];
908 pref_out_role = sp->preferred_device.roles[STREAM_DIRECTION_OUT];
910 /* get device ids of preferred in/out device respectively */
911 dm_device_list = pa_device_manager_get_device_list(m->dm);
912 PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
913 dm_direction = pa_tz_device_get_direction(dm_device);
914 if (in_device_id == 0 && (dm_direction & DM_DEVICE_DIRECTION_IN)) {
915 if (pa_safe_streq(pref_in_type, pa_tz_device_get_type(dm_device))) {
916 if (pa_safe_streq(pref_in_role, pa_tz_device_get_role(dm_device, pref_in_role)))
917 in_device_id = pa_tz_device_get_id(dm_device);
920 if (out_device_id == 0 && (dm_direction & DM_DEVICE_DIRECTION_OUT)) {
921 if (pa_safe_streq(pref_out_type, pa_tz_device_get_type(dm_device))) {
922 if (pa_safe_streq(pref_out_role, pa_tz_device_get_role(dm_device, pref_out_role)))
923 out_device_id = pa_tz_device_get_id(dm_device);
928 pa_log_info("preferred IN device: type[%s] role[%s] id[%u]", pref_in_type, pref_in_role, in_device_id);
929 pa_log_info("preferred OUT device: type[%s] role[%s] id[%u]", pref_out_type, pref_out_role, out_device_id);
932 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id,
933 DBUS_TYPE_UINT32, &out_device_id,
934 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
936 pa_assert_se(dbus_connection_send(conn, reply, NULL));
937 dbus_message_unref(reply);
940 static uint32_t get_num_of_target_streams(pa_stream_manager *m, pa_idxset *streams, stream_direction_t direction, const char *role) {
950 PA_IDXSET_FOREACH(s, streams, idx) {
951 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
952 PA_SINK_INPUT(s)->proplist : PA_SOURCE_OUTPUT(s)->proplist, PA_PROP_MEDIA_ROLE);
953 if (pa_safe_streq(_role, role))
959 static void routing_process_to_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
968 pa_assert(tz_device);
970 count = get_num_of_target_streams(m, (direction == STREAM_DIRECTION_OUT) ?
971 m->core->sink_inputs : m->core->source_outputs,
973 PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
974 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
975 PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
976 if (!pa_safe_streq(_role, role))
979 /* move stream to the preemptive device */
980 device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
981 tz_device->playback_devices : tz_device->capture_devices);
982 if (direction == STREAM_DIRECTION_OUT) {
983 pa_sink_input_move_to(stream, PA_SINK(device), false);
984 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT),
985 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
987 pa_source_output_move_to(stream, PA_SOURCE(device), false);
988 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT),
989 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
994 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
995 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1000 static void rollback_process_from_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
1006 const char *active_device = NULL;
1011 pa_assert(tz_device);
1013 device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
1014 tz_device->playback_devices : tz_device->capture_devices);
1016 PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? PA_SINK(device)->inputs : PA_SOURCE(device)->outputs, idx) {
1017 _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
1018 PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
1019 if (!pa_safe_streq(_role, role))
1023 /* find and set new device */
1024 do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
1025 (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
1027 new_device = (direction == STREAM_DIRECTION_OUT) ? (void*)(PA_SINK_INPUT(stream)->sink) :
1028 (void*)(PA_SOURCE_OUTPUT(stream)->source);
1029 active_device = pa_proplist_gets(GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT),
1030 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
1031 /* change routing */
1032 process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
1033 PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1035 if (direction == STREAM_DIRECTION_OUT)
1036 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1038 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1043 /* move stream to the new device */
1044 if (direction == STREAM_DIRECTION_OUT) {
1045 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1047 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1049 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1051 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1056 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1057 pa_stream_manager *m = (pa_stream_manager *)userdata;
1058 const char *stream_type = NULL;
1059 const char *device_direction = NULL;
1060 stream_direction_t direction;
1061 dbus_uint32_t device_id = 0;
1062 stream_info *s = NULL;
1063 pa_tz_device *device = NULL;
1064 char *device_type = NULL;
1065 const char *prev_device_type = NULL;
1066 uint32_t prev_device_id = 0;
1069 ret_msg_t ret = RET_MSG_OK;
1075 pa_assert_se(dbus_message_get_args(msg, NULL,
1076 DBUS_TYPE_STRING, &stream_type,
1077 DBUS_TYPE_STRING, &device_direction,
1078 DBUS_TYPE_UINT32, &device_id,
1079 DBUS_TYPE_INVALID));
1080 pa_log_info("stream type[%s], device direction[%s], device_id[%u]", stream_type, device_direction, device_id);
1082 if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1083 pa_log_error("could not find this stream type(%s)", stream_type);
1084 ret = RET_MSG_ERROR_INTERNAL;
1088 if (get_direction_type(device_direction, &direction) != 0) {
1089 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1093 /* allow only auto routing type */
1094 if (s->route_type != STREAM_ROUTE_TYPE_AUTO &&
1095 s->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1096 pa_log_error("not allowed this route type[%d]", s->route_type);
1097 ret = RET_MSG_ERROR_POLICY;
1101 if (device_id > 0) {
1102 if (!(device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
1103 pa_log_error("could not get device by id[%u]", device_id);
1104 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1108 PA_IDXSET_FOREACH(device_type, (direction == STREAM_DIRECTION_OUT) ? s->idx_avail_out_devices : s->idx_avail_in_devices, idx) {
1109 if (pa_safe_streq(device_type, device->type)) {
1115 pa_log_error("not supported this device type[%s]", device->type);
1116 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1121 if (device_id == 0 && s->preemptive_device[direction].id == 0) {
1122 pa_log_debug("there's no preemptive device, nothing to do");
1126 prev_device_type = s->preemptive_device[direction].type;
1127 prev_device_id = s->preemptive_device[direction].id;
1128 s->preemptive_device[direction].type = device_id > 0 ? device->type : NULL;
1129 s->preemptive_device[direction].id = device_id;
1131 pa_log_info("preemptive [%s] device is set, [%s, id:%u]",
1132 direction == STREAM_DIRECTION_OUT ? "out" : "in",
1133 device_id > 0 ? device->type : NULL,
1136 /* move streams and change routing */
1137 if (device_id == 0) {
1138 if (!(device = pa_device_manager_get_device_by_id(m->dm, prev_device_id)) ||
1139 !pa_safe_streq(device->type, prev_device_type)) {
1140 pa_log_debug("could not find the previous device of id[%u], type[%s], nothing to do.", prev_device_id, prev_device_type);
1143 rollback_process_from_preemptive_device(m, direction, stream_type, device);
1145 routing_process_to_preemptive_device(m, direction, stream_type, device);
1149 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1152 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1153 pa_stream_manager *m = (pa_stream_manager *)userdata;
1154 const char *stream_type = NULL;
1155 stream_info *s = NULL;
1156 uint32_t in_device_id = 0;
1157 uint32_t out_device_id = 0;
1158 const char *in_device_type;
1159 const char *out_device_type;
1160 ret_msg_t ret = RET_MSG_OK;
1161 DBusMessage *reply = NULL;
1167 pa_assert_se(dbus_message_get_args(msg, NULL,
1168 DBUS_TYPE_STRING, &stream_type,
1169 DBUS_TYPE_INVALID));
1170 pa_log_info("stream type[%s]", stream_type);
1172 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1174 if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1175 pa_log_error("could not find this stream type(%s)", stream_type);
1176 ret = RET_MSG_ERROR_INTERNAL;
1180 in_device_id = s->preemptive_device[STREAM_DIRECTION_IN].id;
1181 in_device_type = s->preemptive_device[STREAM_DIRECTION_IN].type;
1182 out_device_id = s->preemptive_device[STREAM_DIRECTION_OUT].id;
1183 out_device_type = s->preemptive_device[STREAM_DIRECTION_OUT].type;
1185 pa_log_info("preemptive IN device: type[%s] id[%u]", in_device_type, in_device_id);
1186 pa_log_info("preemptive OUT device: type[%s] id[%u]", out_device_type, out_device_id);
1189 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id,
1190 DBUS_TYPE_UINT32, &out_device_id,
1191 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
1192 DBUS_TYPE_INVALID));
1193 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1194 dbus_message_unref(reply);
1197 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1198 pa_stream_manager *m = (pa_stream_manager *)userdata;
1199 const char *direction = NULL;
1200 const char *type = NULL;
1201 dbus_uint32_t level = 0;
1202 stream_type_t stream_type = STREAM_SINK_INPUT;
1209 pa_assert_se(dbus_message_get_args(msg, NULL,
1210 DBUS_TYPE_STRING, &direction,
1211 DBUS_TYPE_STRING, &type,
1212 DBUS_TYPE_UINT32, &level,
1213 DBUS_TYPE_INVALID));
1214 pa_log_info("direction[%s], type[%s], level[%u]", direction, type, level);
1216 if (get_stream_type(direction, &stream_type) != 0) {
1217 ret = RET_MSG_ERROR_INTERNAL;
1221 /* check vconf update here, volume will not be set if update fails */
1222 if ((ret = update_volume_vconf(type, level))) {
1223 ret = RET_MSG_ERROR_INTERNAL;
1227 if ((ret = set_volume_level_by_type(m, stream_type, type, level)) != 0)
1228 ret = (ret == -2) ? RET_MSG_ERROR_INVALID_ARGUMENT : RET_MSG_ERROR_INTERNAL;
1231 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1234 send_volume_changed_signal(conn, direction, type, level);
1237 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1238 pa_stream_manager *m = (pa_stream_manager *)userdata;
1239 const char *direction = NULL;
1240 const char *type = NULL;
1242 stream_type_t stream_type = STREAM_SINK_INPUT;
1243 DBusMessage *reply = NULL;
1244 ret_msg_t ret = RET_MSG_OK;
1250 pa_assert_se(dbus_message_get_args(msg, NULL,
1251 DBUS_TYPE_STRING, &direction,
1252 DBUS_TYPE_STRING, &type,
1253 DBUS_TYPE_INVALID));
1254 pa_log_info("direction[%s], type[%s]", direction, type);
1256 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1258 if (get_stream_type(direction, &stream_type) != 0) {
1259 ret = RET_MSG_ERROR_INTERNAL;
1263 if (get_volume_level_by_type(m, GET_VOLUME_CURRENT_LEVEL, stream_type, type, &level) != 0)
1264 ret = RET_MSG_ERROR_INTERNAL;
1267 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level,
1268 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
1269 DBUS_TYPE_INVALID));
1270 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1271 dbus_message_unref(reply);
1274 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1275 pa_stream_manager *m = (pa_stream_manager *)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 ret_msg_t ret = RET_MSG_OK;
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 (get_stream_type(direction, &stream_type) != 0) {
1296 ret = RET_MSG_ERROR_INTERNAL;
1300 if (get_volume_level_by_type(m, GET_VOLUME_MAX_LEVEL, stream_type, type, &level) != 0)
1301 ret = RET_MSG_ERROR_INTERNAL;
1304 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level,
1305 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
1306 DBUS_TYPE_INVALID));
1307 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1308 dbus_message_unref(reply);
1311 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1312 pa_stream_manager *m = (pa_stream_manager *)userdata;
1313 const char *direction = NULL;
1314 const char *type = NULL;
1315 dbus_uint32_t do_mute = 0;
1316 stream_type_t stream_type = STREAM_SINK_INPUT;
1317 ret_msg_t ret = RET_MSG_OK;
1323 pa_assert_se(dbus_message_get_args(msg, NULL,
1324 DBUS_TYPE_STRING, &direction,
1325 DBUS_TYPE_STRING, &type,
1326 DBUS_TYPE_UINT32, &do_mute,
1327 DBUS_TYPE_INVALID));
1328 pa_log_info("direction[%s], type[%s], do_mute[%u]", direction, type, do_mute);
1330 if (get_stream_type(direction, &stream_type) != 0) {
1331 ret = RET_MSG_ERROR_INTERNAL;
1335 /* check vconf update here, mute will not be set if update fails */
1336 if (update_mute_vconf(type, do_mute) != 0) {
1337 ret = RET_MSG_ERROR_INTERNAL;
1341 if (set_volume_mute_by_type(m, stream_type, type, (bool)do_mute) != 0)
1342 ret = RET_MSG_ERROR_INTERNAL;
1345 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1348 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1349 pa_stream_manager *m = (pa_stream_manager *)userdata;
1350 const char *direction = NULL;
1351 const char *type = NULL;
1352 dbus_uint32_t is_muted = 0;
1353 stream_type_t stream_type = STREAM_SINK_INPUT;
1354 DBusMessage *reply = NULL;
1355 bool _is_muted = false;
1356 ret_msg_t ret = RET_MSG_OK;
1362 pa_assert_se(dbus_message_get_args(msg, NULL,
1363 DBUS_TYPE_STRING, &direction,
1364 DBUS_TYPE_STRING, &type,
1365 DBUS_TYPE_INVALID));
1366 pa_log_info("direction[%s], type[%s]", direction, type);
1368 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1370 if (get_stream_type(direction, &stream_type) != 0) {
1371 ret = RET_MSG_ERROR_INTERNAL;
1375 if (get_volume_mute_by_type(m, stream_type, type, &_is_muted) != 0) {
1376 ret = RET_MSG_ERROR_INTERNAL;
1380 is_muted = (dbus_uint32_t)_is_muted;
1383 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted,
1384 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
1385 DBUS_TYPE_INVALID));
1386 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1387 dbus_message_unref(reply);
1390 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1391 pa_stream_manager *m = (pa_stream_manager *)userdata;
1392 const char *direction = NULL;
1395 stream_type_t stream_type = STREAM_SINK_INPUT;
1396 ret_msg_t ret = RET_MSG_OK;
1402 pa_assert_se(dbus_message_get_args(msg, NULL,
1403 DBUS_TYPE_STRING, &direction,
1404 DBUS_TYPE_UINT32, &idx,
1405 DBUS_TYPE_DOUBLE, &ratio,
1406 DBUS_TYPE_INVALID));
1407 pa_log_info("direction[%s], idx[%u], ratio[%f]", direction, idx, ratio);
1409 if (get_stream_type(direction, &stream_type) != 0) {
1410 pa_log_error("invalid direction[%s]", direction);
1411 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1415 /* Check the ratio range (0.0 ~ 1.0) */
1416 if (ratio < 0 || ratio > 1) {
1417 pa_log_error("invalid range, ratio[%f]", ratio);
1418 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1422 if ((ret = set_volume_ratio_by_idx(m, stream_type, idx, ratio)) != 0)
1423 ret = (ret == -2) ? RET_MSG_ERROR_NO_STREAM : RET_MSG_ERROR_INTERNAL;
1426 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1429 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1430 pa_stream_manager *m = (pa_stream_manager *)userdata;
1431 const char *direction = NULL;
1432 dbus_uint32_t idx = 0;
1434 stream_type_t stream_type = STREAM_SINK_INPUT;
1435 DBusMessage *reply = NULL;
1436 ret_msg_t ret = RET_MSG_OK;
1442 pa_assert_se(dbus_message_get_args(msg, NULL,
1443 DBUS_TYPE_STRING, &direction,
1444 DBUS_TYPE_UINT32, &idx,
1445 DBUS_TYPE_INVALID));
1446 pa_log_info("direction[%s], idx[%u]", direction, idx);
1448 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1450 if (get_stream_type(direction, &stream_type) != 0) {
1451 pa_log_error("invalid direction[%s]", direction);
1452 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1456 if (get_volume_ratio_by_idx(m, stream_type, idx, &ratio) != 0)
1457 ret = RET_MSG_ERROR_NO_STREAM;
1460 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio,
1461 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
1462 DBUS_TYPE_INVALID));
1463 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1464 dbus_message_unref(reply);
1467 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1468 pa_stream_manager *m = (pa_stream_manager *)userdata;
1469 const char *direction = NULL;
1470 const char *type = dbus_str_none;
1472 stream_type_t stream_type = STREAM_SINK_INPUT;
1473 DBusMessage *reply = NULL;
1475 pa_idxset *streams = NULL;
1476 ret_msg_t ret = RET_MSG_OK;
1482 pa_assert_se(dbus_message_get_args(msg, NULL,
1483 DBUS_TYPE_STRING, &direction,
1484 DBUS_TYPE_INVALID));
1485 pa_log_info("direction[%s]", direction);
1487 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1489 if (get_stream_type(direction, &stream_type) != 0) {
1490 ret = RET_MSG_ERROR_INTERNAL;
1494 streams = (stream_type == STREAM_SOURCE_OUTPUT) ? m->core->source_outputs : m->core->sink_inputs;
1496 /* Get a volume type of a stream that has the max priority role among all the running streams regardless of devices.
1497 Note that it does not represent any focus status of a stream rather only checking the priority of it */
1498 if (pa_idxset_size(streams)) {
1499 int cur_max_priority = 0;
1500 const char *cur_max_type = NULL;
1501 const char *role = NULL;
1502 stream_info *s_info;
1504 PA_IDXSET_FOREACH(s, streams, idx) {
1505 if (!CHECK_STREAM_RUNNING(s, stream_type))
1507 if (!(type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE)))
1509 if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE)))
1511 if ((s_info = pa_hashmap_get(m->stream_infos, role))) {
1512 if (s_info->priority >= cur_max_priority) {
1513 cur_max_priority = s_info->priority;
1514 cur_max_type = type;
1515 pa_log_info("updated, volume type of the max priority stream(%u): %s", GET_STREAM_INDEX(s, stream_type), cur_max_type);
1519 type = cur_max_type;
1522 if (!strncmp(type, dbus_str_none, strlen(dbus_str_none)))
1523 ret = RET_MSG_ERROR_NO_STREAM;
1526 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type,
1527 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
1528 DBUS_TYPE_INVALID));
1529 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1530 dbus_message_unref(reply);
1533 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1534 pa_stream_manager *m = (pa_stream_manager *)userdata;
1535 const char *direction = NULL;
1536 const char *device_type = dbus_str_none;
1537 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
1538 stream_info *s = NULL;
1539 DBusMessage *reply = NULL;
1540 pa_tz_device *device = NULL;
1541 ret_msg_t ret = RET_MSG_ERROR_INTERNAL;
1547 pa_assert_se(dbus_message_get_args(msg, NULL,
1548 DBUS_TYPE_STRING, &direction,
1549 DBUS_TYPE_INVALID));
1550 pa_log_info("direction[%s]", direction);
1552 pa_assert_se((reply = dbus_message_new_method_return(msg)));
1554 if (pa_safe_streq(direction, "in")) {
1555 dm_device_direction = DM_DEVICE_DIRECTION_IN;
1556 } else if (pa_safe_streq(direction, "out")) {
1557 dm_device_direction = DM_DEVICE_DIRECTION_OUT;
1559 pa_log_error("invalid direction[%s]", direction);
1563 if ((s = pa_hashmap_get(m->stream_infos, STREAM_ROLE_MEDIA)) == NULL) {
1564 pa_log_error("could not find media role");
1568 if (s->route_type == STREAM_ROUTE_TYPE_AUTO) {
1569 device = get_media_auto_device(m, dm_device_direction);
1570 } else if (s->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1571 device = get_media_last_device(m, dm_device_direction);
1573 pa_log_error("unexpected routing type for media[%d]", s->route_type);
1578 device_type = pa_tz_device_get_type(device);
1581 pa_log_error("could not found matched device");
1585 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_type,
1586 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
1587 DBUS_TYPE_INVALID));
1588 pa_assert_se(dbus_connection_send(conn, reply, NULL));
1589 dbus_message_unref(reply);
1592 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1593 pa_stream_manager *m = (pa_stream_manager *)userdata;
1594 dbus_uint32_t id = 0;
1595 dbus_uint32_t acquired_focus_status = 0;
1598 stream_parent *sp = NULL;
1599 void *stream = NULL;
1600 int prev_status = STREAM_FOCUS_ACQUIRED_NONE;
1601 ret_msg_t ret = RET_MSG_OK;
1607 pa_assert_se(dbus_message_get_args(msg, NULL,
1608 DBUS_TYPE_UINT32, &id,
1609 DBUS_TYPE_UINT32, &acquired_focus_status,
1610 DBUS_TYPE_INVALID));
1611 pa_log_info("id[%u], acquired_focus_status[0x%x]", id, acquired_focus_status);
1613 if ((sp = pa_hashmap_get(m->stream_parents, (const void*)id))) {
1614 if (sp->focus_status != acquired_focus_status) {
1615 /* need to update */
1616 prev_status = sp->focus_status;
1617 sp->focus_status = acquired_focus_status;
1618 if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_PLAYBACK) && sp->idx_sink_inputs) {
1619 count = pa_idxset_size(sp->idx_sink_inputs);
1620 PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
1621 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1622 GET_FOCUS_STATUS(sp->focus_status, STREAM_SINK_INPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1624 process_stream(m, stream, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1627 if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_CAPTURE) && sp->idx_source_outputs) {
1628 count = pa_idxset_size(sp->idx_source_outputs);
1629 PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
1630 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1631 GET_FOCUS_STATUS(sp->focus_status, STREAM_SOURCE_OUTPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1633 process_stream(m, stream, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1637 pa_log_debug("same as before, skip updating focus status[0x%x]", acquired_focus_status);
1640 pa_log_error("could not find matching client for this parent_id[%u]", id);
1641 ret = RET_MSG_ERROR_INTERNAL;
1644 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1647 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1648 pa_stream_manager *m = (pa_stream_manager *)userdata;
1649 dbus_int32_t id = 0;
1650 dbus_uint32_t acquired_focus_status = 0;
1652 int32_t focus_id = 0;
1653 const char *focus_id_str;
1654 pa_sink_input *i = NULL;
1655 ret_msg_t ret = RET_MSG_ERROR_INTERNAL;
1661 pa_assert_se(dbus_message_get_args(msg, NULL,
1662 DBUS_TYPE_INT32, &id,
1663 DBUS_TYPE_UINT32, &acquired_focus_status,
1664 DBUS_TYPE_INVALID));
1665 pa_log_info("id[%d], acquired_focus_status[0x%x]", id, acquired_focus_status);
1667 /* Currently, we only support sink-inputs */
1668 PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
1669 if ((focus_id_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_ID))) {
1670 if (pa_atoi(focus_id_str, &focus_id))
1676 pa_log_info("found matching sink-input(%p, %u) - focus_id(%d)", i, i->index, id);
1677 pa_proplist_sets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1678 acquired_focus_status ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1680 process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1687 if (ret != RET_MSG_OK)
1688 pa_log_error("could not find matching stream for this focus_id[%d]", id);
1690 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1693 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1694 pa_stream_manager *m = (pa_stream_manager *)userdata;
1696 dbus_uint32_t value = 0;
1697 ret_msg_t ret = RET_MSG_OK;
1703 pa_assert_se(dbus_message_get_args(msg, NULL,
1704 DBUS_TYPE_STRING, &name,
1705 DBUS_TYPE_UINT32, &value,
1706 DBUS_TYPE_INVALID));
1707 pa_log_info("name[%s], value[%u]", name, value);
1709 if (handle_restrictions(m, name, value) != 0)
1710 ret = RET_MSG_ERROR_INTERNAL;
1712 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1715 #define MAX_CALL_PARAM_SIZE 32
1716 static int32_t parse_call_parameters(const char *parameters, char *call_type, char *call_domain, char *network_band) {
1717 const char delimiter[] = ";";
1718 char *token, *ptr = NULL;
1721 pa_assert(parameters);
1722 pa_assert(call_type);
1723 pa_assert(call_domain);
1724 pa_assert(network_band);
1726 pa_log_info("parameters[%s]", parameters);
1728 /*Reset the call parameters*/
1729 memset(call_type, 0, MAX_CALL_PARAM_SIZE);
1730 memset(call_domain, 0, MAX_CALL_PARAM_SIZE);
1731 memset(network_band, 0, MAX_CALL_PARAM_SIZE);
1734 token = strtok_r((char *)parameters, delimiter, &ptr);
1736 char *delimiter_ptr = NULL;
1739 delimiter_ptr = strstr(token, "=");
1740 if (!delimiter_ptr) {
1741 token = strtok_r(NULL, delimiter, &ptr);
1744 strncpy(key, token, delimiter_ptr - token);
1745 value = delimiter_ptr + 1;
1746 pa_log_debug("key(%s), value(%s)", key, value);
1747 if (!strncmp(key, "call-type", strlen("call-type")))
1748 pa_strlcpy(call_type, value, MAX_CALL_PARAM_SIZE);
1749 else if (!strncmp(key, "call-domain", strlen("call-domain")))
1750 pa_strlcpy(call_domain, value, MAX_CALL_PARAM_SIZE);
1751 else if (!strncmp(key, "network-band", strlen("network-band")))
1752 pa_strlcpy(network_band, value, MAX_CALL_PARAM_SIZE);
1754 pa_log_warn("not supported key(%s)", key);
1756 token = strtok_r(NULL, delimiter, &ptr);
1757 memset(key, 0, sizeof(key));
1759 pa_log_info("call-type[%s], call-domain[%s], network-band[%s]", call_type, call_domain, network_band);
1765 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1766 pa_stream_manager *m = (pa_stream_manager *)userdata;
1767 const char *parameters;
1768 char call_type[MAX_CALL_PARAM_SIZE] = {0,};
1769 char call_domain[MAX_CALL_PARAM_SIZE] = {0,};
1770 char network_band[MAX_CALL_PARAM_SIZE] = {0,};
1771 stream_route_option route_option;
1772 ret_msg_t ret = RET_MSG_OK;
1778 pa_assert_se(dbus_message_get_args(msg, NULL,
1779 DBUS_TYPE_STRING, ¶meters,
1780 DBUS_TYPE_INVALID));
1781 pa_log_info("parameters[%s]", parameters);
1783 if (parse_call_parameters(parameters, call_type, call_domain, network_band) != 0) {
1784 ret = RET_MSG_ERROR_INTERNAL;
1788 pa_log_debug("call_type[%s], call_domain[%s], network_band[%s]", call_type, call_domain, network_band);
1790 /* Currently, we only use network band */
1791 route_option.name = "call-wideband";
1792 route_option.value = pa_safe_streq(network_band, "wb") ? 1 : 0;
1794 ret = do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
1797 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1800 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1801 pa_stream_manager *m = (pa_stream_manager *)userdata;
1802 const char *filter_name, *filter_parameters, *filter_group, *stream_type;
1803 ret_msg_t ret = RET_MSG_OK;
1809 pa_assert_se(dbus_message_get_args(msg, NULL,
1810 DBUS_TYPE_STRING, &filter_name,
1811 DBUS_TYPE_STRING, &filter_parameters,
1812 DBUS_TYPE_STRING, &filter_group,
1813 DBUS_TYPE_STRING, &stream_type,
1814 DBUS_TYPE_INVALID));
1815 pa_log_info("filter_name[%s], filter_parameters[%s], filter_group[%s], stream_type[%s]",
1816 filter_name, filter_parameters, filter_group, stream_type);
1818 /* Set filter sink according to stream type */
1819 if (update_filter(m, filter_name, filter_parameters, filter_group, stream_type) != 0)
1820 ret = RET_MSG_ERROR_INTERNAL;
1822 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1825 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1826 pa_stream_manager *m = (pa_stream_manager *)userdata;
1827 const char *stream_type;
1828 ret_msg_t ret = RET_MSG_OK;
1834 pa_assert_se(dbus_message_get_args(msg, NULL,
1835 DBUS_TYPE_STRING, &stream_type,
1836 DBUS_TYPE_INVALID));
1837 pa_log_info("stream_type[%s]", stream_type);
1839 /* Unset filter sink according to stream type */
1840 if (update_filter(m, NULL, NULL, NULL, stream_type) != 0)
1841 ret = RET_MSG_ERROR_INTERNAL;
1843 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1846 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1847 pa_stream_manager *m = (pa_stream_manager *)userdata;
1848 const char *filter_name, *filter_controls, *stream_type;
1849 ret_msg_t ret = RET_MSG_OK;
1855 pa_assert_se(dbus_message_get_args(msg, NULL,
1856 DBUS_TYPE_STRING, &filter_name,
1857 DBUS_TYPE_STRING, &filter_controls,
1858 DBUS_TYPE_STRING, &stream_type,
1859 DBUS_TYPE_INVALID));
1860 pa_log_info("filter_name[%s], filter_controls[%s], stream_type[%s]", filter_name, filter_controls, stream_type);
1862 /* Control parameters to filter sink */
1863 if (control_filter(m, filter_name, filter_controls, stream_type, conn) != 0)
1864 ret = RET_MSG_ERROR_INTERNAL;
1866 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1869 static bool check_stream_exist_by_pid(pa_stream_manager *m, uint32_t pid, const char *stream_role, stream_type_t type) {
1870 void *stream = NULL;
1872 const char *role = NULL;
1873 const char *app_pid_str = NULL;
1874 uint32_t app_pid = 0;
1877 pa_assert(stream_role);
1879 pa_log_info("pid[%u], role[%s], type[%d]", pid, stream_role, type);
1881 PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
1882 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1883 if (!pa_safe_streq(role, stream_role))
1886 if (!CHECK_STREAM_RUNNING(stream, type)) {
1887 pa_log_info("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
1891 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
1892 if (app_pid_str && !pa_atou(app_pid_str, &app_pid)) {
1893 if (app_pid == pid) {
1894 pa_log_info("found matching stream(%p, index:%u)", stream, GET_STREAM_INDEX(stream, type));
1903 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1904 pa_stream_manager *m = (pa_stream_manager *)userdata;
1905 dbus_uint32_t pid = 0;
1907 const char *direction;
1908 stream_type_t stream_type = STREAM_SINK_INPUT;
1909 ret_msg_t ret = RET_MSG_OK;
1915 pa_assert_se(dbus_message_get_args(msg, NULL,
1916 DBUS_TYPE_UINT32, &pid,
1917 DBUS_TYPE_STRING, &type,
1918 DBUS_TYPE_STRING, &direction,
1919 DBUS_TYPE_INVALID));
1920 pa_log_info("pid[%u], type[%s], direction[%s]", pid, type, direction);
1922 if (get_stream_type(direction, &stream_type) != 0) {
1923 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1927 if (!check_stream_exist_by_pid(m, pid, type, stream_type))
1928 ret = RET_MSG_ERROR_NO_STREAM;
1931 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret]);
1934 static bool find_the_lastest_stream(pa_stream_manager *m, stream_type_t type, const char ** stream_roles, int length, uint32_t *pid) {
1935 void *stream = NULL;
1938 const char *app_pid_str = NULL;
1939 uint32_t latest_pid = 0;
1940 pa_usec_t latest_time = 0;
1941 uint32_t tmp_pid = 0;
1942 pa_usec_t tmp_time = 0;
1946 pa_assert(stream_roles);
1949 PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
1950 if (!CHECK_STREAM_RUNNING(stream, type)) {
1951 pa_log_debug("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
1955 for (i = 0; i <length; i++) {
1959 role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1960 if (!pa_safe_streq(stream_roles[i], role))
1963 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID_ORIGIN);
1964 if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid)) {
1965 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]);
1967 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
1968 if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid))
1969 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]);
1972 tmp_time = GET_STREAM_LAST_RUN_TIME(stream, type);
1973 if (latest_time <= tmp_time) {
1974 latest_time = tmp_time;
1975 latest_pid = tmp_pid;
1981 if (latest_pid > 0) {
1983 pa_log_info("found the stream(pid:%u)", *pid);
1987 pa_log_info("no match is found");
1991 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1992 pa_stream_manager *m = (pa_stream_manager *)userdata;
1993 const char *direction;
1996 stream_type_t stream_type = STREAM_SINK_INPUT;
1998 ret_msg_t ret = RET_MSG_OK;
2000 DBusMessage *reply = NULL;
2006 pa_assert_se(dbus_message_get_args(msg, NULL,
2007 DBUS_TYPE_STRING, &direction,
2008 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &types, &length,
2009 DBUS_TYPE_INVALID));
2011 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2013 if (get_stream_type(direction, &stream_type) != 0) {
2014 pa_log_error("invalid direction[%s]", direction);
2015 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
2020 pa_log_error("At least one stream type should be contained");
2021 ret = RET_MSG_ERROR_INVALID_ARGUMENT;
2025 if (!find_the_lastest_stream(m, stream_type, types, length, &pid))
2026 ret = RET_MSG_ERROR_NO_STREAM;
2029 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &pid,
2030 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret],
2031 DBUS_TYPE_INVALID));
2032 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2033 dbus_message_unref(reply);
2036 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2037 pa_stream_manager *m = (pa_stream_manager *)userdata;
2038 dbus_uint32_t id = 0;
2039 dbus_bool_t enable = 0;
2040 const char *target_stream = NULL;
2041 dbus_uint32_t duration = 0;
2044 pa_sink_input *i = NULL;
2046 pa_cvolume_ramp vol_ramp;
2047 stream_ducking *sd = NULL;
2048 hal_ducking_activation_info ducking_activation_info;
2049 ret_msg_t ret_msg = RET_MSG_OK;
2055 pa_assert_se(dbus_message_get_args(msg, NULL,
2056 DBUS_TYPE_UINT32, &id,
2057 DBUS_TYPE_BOOLEAN, &enable,
2058 DBUS_TYPE_STRING, &target_stream,
2059 DBUS_TYPE_UINT32, &duration,
2060 DBUS_TYPE_DOUBLE, &ratio,
2061 DBUS_TYPE_INVALID));
2063 pa_log_info("id[%u], enable[%u], target stream[%s], duration[%u], ratio[%lf]",
2064 id, enable, target_stream, duration, ratio);
2066 /* get stream_ducking */
2067 sd = pa_hashmap_get(m->stream_duckings, (const void*)id);
2069 pa_log_error("no matched stream ducking for id[%u]", id);
2070 ret_msg = RET_MSG_ERROR_INTERNAL;
2071 goto _ACTIVATE_DUCKING_DONE;
2074 /* validate state with command */
2075 if ((enable && sd->state != STREAM_DUCKING_STATE_UNDUCKED) ||
2076 (!enable && sd->state != STREAM_DUCKING_STATE_DUCKED)) {
2077 pa_log_error("state validation failed - [%d,s:%u]", enable, sd->state);
2078 ret_msg = RET_MSG_ERROR_INVALID_STATE;
2079 goto _ACTIVATE_DUCKING_DONE;
2082 sd->duration = duration;
2084 sd->set_vol = PA_VOLUME_NORM * ratio;
2087 sd->state = STREAM_DUCKING_STATE_DUCKING;
2088 snprintf(sd->vol_key, VOLUME_KEY_LENGTH, "stream_ducking_%u_%s", id, target_stream);
2089 snprintf(sd->target_role, STREAM_ROLE_STR_MAX, "%s", target_stream);
2091 sd->state = STREAM_DUCKING_STATE_UNDUCKING;
2094 /* set volume ramp factor to target stream */
2095 PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
2096 if (!pa_safe_streq(target_stream, pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
2099 if (i->state == PA_SINK_INPUT_RUNNING)
2100 sd->ducking_stream_count++;
2103 pa_idxset_put(sd->idx_ducking_streams, (void *)i, NULL);
2105 pa_log_error("ducking: add volume_ramp factor, key[%s], set_vol[%u] to stream[idx:%u]",
2106 sd->vol_key, sd->set_vol, i->index);
2108 pa_cvolume_ramp_set(&vol_ramp, i->volume.channels,
2109 PA_VOLUME_RAMP_TYPE_LINEAR, (long)duration, sd->set_vol);
2111 if (i->state != PA_SINK_INPUT_RUNNING || duration == 0) {
2112 pa_cvolume_set(&vol, i->volume.channels, sd->set_vol);
2113 pa_sink_input_add_volume_factor(i, sd->vol_key, &vol);
2114 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, false);
2116 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, true);
2119 pa_log_error("unducking: remove volume(ramp) factor, key[%s] from stream[idx:%u]",
2120 sd->vol_key, i->index);
2122 pa_sink_input_remove_volume_factor(i, sd->vol_key);
2123 pa_sink_input_remove_volume_ramp_factor(i, sd->vol_key, true);
2128 memset(&sd->target_role, 0, sizeof(sd->target_role));
2129 memset(&sd->vol_key, 0, sizeof(sd->vol_key));
2132 pa_log_info("ducking stream count[%p,%d]", sd, sd->ducking_stream_count);
2134 _ACTIVATE_DUCKING_DONE:
2135 pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg]);
2137 if (ret_msg != RET_MSG_OK)
2140 /* notify ducking activation */
2141 ducking_activation_info.target_role = target_stream;
2142 ducking_activation_info.duration = duration;
2143 ducking_activation_info.ratio = ratio;
2144 ducking_activation_info.is_activated = enable;
2146 pa_hal_interface_notify_ducking_activation_changed(m->hal, &ducking_activation_info);
2148 if (sd->ducking_stream_count <= 0 || duration == 0) {
2149 /* change ducking state and send signal here,
2150 because ramp_finish_cb could not be called in this case. */
2152 sd->state = STREAM_DUCKING_STATE_DUCKED;
2154 sd->state = STREAM_DUCKING_STATE_UNDUCKED;
2156 pa_log_info("send signal for ramp finished - state[%u]", sd->state);
2158 /* It should be reset here because it's increased,
2159 but will not be decreased in case of 0 duration. */
2160 sd->ducking_stream_count = 0;
2162 send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
2166 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2167 pa_stream_manager *m = (pa_stream_manager *)userdata;
2168 dbus_uint32_t id = 0;
2169 DBusMessage *reply = NULL;
2170 stream_ducking *sd = NULL;
2171 dbus_bool_t is_ducked = FALSE;
2172 ret_msg_t ret_msg = RET_MSG_OK;
2178 pa_assert_se(dbus_message_get_args(msg, NULL,
2179 DBUS_TYPE_UINT32, &id,
2180 DBUS_TYPE_INVALID));
2182 pa_assert_se((reply = dbus_message_new_method_return(msg)));
2184 /* get stream_ducking */
2185 sd = pa_hashmap_get(m->stream_duckings, (const void *)id);
2187 pa_log_error("no matched stream ducking for id[%u]", id);
2188 ret_msg = RET_MSG_ERROR_INTERNAL;
2192 is_ducked = (dbus_bool_t)is_stream_ducked(sd);
2193 pa_log_info("id[%u], is_ducked[%p,%d]", id, sd, is_ducked);
2196 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_ducked,
2197 DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg],
2198 DBUS_TYPE_INVALID));
2200 pa_assert_se(dbus_connection_send(conn, reply, NULL));
2201 dbus_message_unref(reply);
2204 static int dbus_launch_mdnsd(pa_stream_manager *m, DBusConnection *conn) {
2205 DBusMessage *msg, *reply;
2207 const char *name = NULL;
2209 pa_log_info("launching mdnsd");
2211 if (!(msg = dbus_message_new_method_call("net.netconfig",
2212 "/net/netconfig/network",
2213 "net.netconfig.network",
2215 pa_log_error("dbus method call failed");
2219 name = dbus_bus_get_unique_name(conn);
2220 pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
2222 dbus_error_init(&err);
2223 if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2224 pa_log_error("Failed to method call : %s", err.message);
2225 dbus_error_free(&err);
2229 dbus_message_unref(reply);
2231 pa_log_info("success");
2236 static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2237 pa_stream_manager *m = (pa_stream_manager *)userdata;
2238 const char *type = NULL;
2239 dbus_uint32_t index;
2240 dbus_bool_t allowed;
2241 pa_proplist *p = NULL;
2247 pa_assert_se(dbus_message_get_args(msg, NULL,
2248 DBUS_TYPE_STRING, &type,
2249 DBUS_TYPE_UINT32, &index,
2250 DBUS_TYPE_BOOLEAN, &allowed,
2251 DBUS_TYPE_INVALID));
2254 pa_log_error("invalid arguments");
2258 pa_log_info("type(%s), index(%u), allowed(%u)", type, index, allowed);
2260 p = pa_proplist_new();
2262 pa_log_error("failed to create proplist");
2266 if (pa_proplist_set_remote_access_permission(p, allowed)) {
2267 pa_log_error("set remote access permission error");
2271 if (pa_streq(type, "sink-input")) {
2272 pa_sink_input *i = pa_idxset_get_by_index(m->core->sink_inputs, index);
2274 pa_log_error("not found sink-input");
2278 if (pa_proplist_remote_is_allowed(i->proplist) != allowed){
2279 pa_sink_input_update_proplist(i, PA_UPDATE_REPLACE, p);
2280 pa_sink_input_send_event(i, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
2283 } else if (pa_streq(type, "source-output")) {
2284 pa_source_output *o = pa_idxset_get_by_index(m->core->source_outputs, index);
2286 pa_log_error("not found source-output");
2290 if (pa_proplist_remote_is_allowed(o->proplist) != allowed){
2291 pa_source_output_update_proplist(o, PA_UPDATE_REPLACE, p);
2292 pa_source_output_send_event(o, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
2296 pa_log_warn("unknown type");
2301 pa_proplist_free(p);
2303 pa_dbus_send_empty_reply(conn, msg);
2306 static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2307 pa_stream_manager *m = (pa_stream_manager *)userdata;
2315 pa_assert_se(dbus_message_get_args(msg, NULL,
2316 DBUS_TYPE_BOOLEAN, &enable,
2317 DBUS_TYPE_INVALID));
2319 pa_log_info("discover module enable(%u)", enable);
2322 if (m->m_discover) {
2323 pa_log_error("already loaded");
2327 if (dbus_launch_mdnsd(m, conn) == -1) {
2328 pa_log_error("failed to launch mdnsd!!!");
2332 if (pa_module_load(&module, m->core, "module-tizenaudio-discover", NULL)) {
2333 pa_log_error("failed to load module");
2336 m->m_discover = module->index;
2338 if (m->m_discover) {
2339 pa_module_unload_request_by_index(m->core, m->m_discover, true);
2344 pa_dbus_send_empty_reply(conn, msg);
2348 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
2349 "org.tizen.multimedia.audio.Internal");
2352 static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2353 pa_stream_manager *m = (pa_stream_manager *)userdata;
2361 pa_assert_se(dbus_message_get_args(msg, NULL,
2362 DBUS_TYPE_BOOLEAN, &enable,
2363 DBUS_TYPE_INVALID));
2365 pa_log_info("publish module enable(%u)", enable);
2368 if (m->m_protocol_tcp || m->m_publish) {
2369 pa_log_error("already loaded");
2373 if (dbus_launch_mdnsd(m, conn) == -1) {
2374 pa_log_error("failed to launch mdnsd!!!");
2378 if (pa_module_load(&module, m->core, "module-native-protocol-tcp", "auth-anonymous=1")) {
2379 pa_log_error("failed to load module");
2382 m->m_protocol_tcp = module->index;
2384 if (pa_module_load(&module, m->core, "module-tizenaudio-publish", NULL)) {
2385 pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
2386 pa_log_error("failed to load module");
2389 m->m_publish = module->index;
2391 if (m->m_protocol_tcp) {
2392 pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
2393 m->m_protocol_tcp = 0;
2396 pa_module_unload_request_by_index(m->core, m->m_publish, true);
2401 pa_dbus_send_empty_reply(conn, msg);
2405 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
2406 "org.tizen.multimedia.audio.Internal");
2409 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2411 pa_stream_manager *m = (pa_stream_manager *)userdata;
2417 for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
2418 if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name)) {
2419 pa_log_debug("Message signature [%s] (Expected [%s])", dbus_message_get_signature(msg), signature_args_for_in[idx]);
2420 if (pa_safe_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
2421 method_handlers[idx].receive_cb(conn, msg, userdata);
2422 return DBUS_HANDLER_RESULT_HANDLED;
2424 pa_log_warn("Wrong Argument Signature");
2425 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE, "Wrong Signature, Expected %s", signature_args_for_in[idx]);
2426 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2431 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2434 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
2435 pa_stream_manager *u = (pa_stream_manager *)userdata;
2436 const char *path, *interface, *member;
2442 path = dbus_message_get_path(m);
2443 interface = dbus_message_get_interface(m);
2444 member = dbus_message_get_member(m);
2446 pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
2448 if (!pa_safe_streq(path, STREAM_MANAGER_OBJECT_PATH))
2449 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2451 if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2452 return handle_introspect(c, m, u);
2454 return handle_methods(c, m, u);
2457 return DBUS_HANDLER_RESULT_HANDLED;
2460 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level) {
2461 DBusMessage *signal_msg;
2462 DBusMessageIter msg_iter;
2465 pa_assert(direction);
2466 pa_assert(volume_type);
2468 pa_log_debug("direction[%s], type[%s], level[%d]", direction, volume_type, volume_level);
2470 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED)));
2471 dbus_message_iter_init_append(signal_msg, &msg_iter);
2473 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &direction);
2474 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &volume_type);
2475 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &volume_level);
2477 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2478 dbus_message_unref(signal_msg);
2482 void send_ducking_state_changed_signal(DBusConnection *conn, const int index, const int is_ducked)
2484 DBusMessage *signal_msg;
2485 DBusMessageIter msg_iter;
2489 pa_log_debug("trigger_index(%d) : is_ducked(%d)", index, is_ducked);
2491 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_DUCKING_STATE_CHANGED)));
2492 dbus_message_iter_init_append(signal_msg, &msg_iter);
2494 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &index);
2495 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &is_ducked);
2497 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2498 dbus_message_unref(signal_msg);
2503 void send_command_signal(DBusConnection *conn, const char *name, int value) {
2504 DBusMessage *signal_msg;
2505 DBusMessageIter msg_iter;
2510 pa_log_debug("name[%s], value[%d]", name, value);
2512 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_COMMAND)));
2513 dbus_message_iter_init_append(signal_msg, &msg_iter);
2515 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2516 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &value);
2518 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2519 dbus_message_unref(signal_msg);
2522 void send_remote_found_signal(DBusConnection *conn, int type, bool connected, unsigned int index,
2523 const char *name, const char *description) {
2524 DBusMessage *signal_msg;
2525 DBusMessageIter msg_iter;
2526 dbus_bool_t c = (dbus_bool_t)connected;
2530 if (!name || !description) {
2531 pa_log_error("Unknown device");
2535 pa_log_info("type[%d], index[%d], connected[%d], name[%s] description[%s]", type, index, connected, name, description);
2537 pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND)));
2538 dbus_message_iter_init_append(signal_msg, &msg_iter);
2540 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &type);
2541 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &index);
2542 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &c);
2543 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2544 dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &description);
2546 pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2547 dbus_message_unref(signal_msg);
2550 int32_t init_sm_dbus(pa_stream_manager *m) {
2553 #ifdef USE_DBUS_PROTOCOL
2554 m->dbus_protocol = pa_dbus_protocol_get(m->core);
2555 pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
2556 pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2559 pa_dbus_connection *conn = NULL;
2560 static const DBusObjectPathVTable vtable = {
2561 .message_function = method_handler_for_vt,
2564 dbus_error_init(&err);
2566 if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
2568 pa_dbus_connection_unref(conn);
2570 pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
2573 pa_log_notice("Got dbus connection");
2575 m->dbus_conn = conn;
2576 pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
2581 void deinit_sm_dbus(pa_stream_manager *m) {
2584 #ifdef USE_DBUS_PROTOCOL
2585 if (m->dbus_protocol) {
2586 pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2587 pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
2588 pa_dbus_protocol_unref(m->dbus_protocol);
2589 m->dbus_protocol = NULL;
2593 if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
2594 pa_log_error("failed to unregister object path");
2596 pa_dbus_connection_unref(m->dbus_conn);
2597 m->dbus_conn = NULL;