tizenaudio-policy: Add support for the preemptive device routing
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / stream-manager-dbus.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2017 Sangchul Lee <sc11.lee@samsung.com>
5
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.
10
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.
15
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
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #ifdef HAVE_DBUS
27
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"
33
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"};
42
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);
74
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" },
122                                                               { "on", "u", "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" } };
178
179 static pa_dbus_arg_info get_ducking_state_args[] = { { "index", "u", "in" },
180                                                { "is_ducked", "b",  "out" },
181                                                 { "ret_msg", "s", "out" } };
182
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 */
212     };
213
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 },
355 };
356
357 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
358     const char *xml = STREAM_MGR_INTROSPECT_XML;
359     DBusMessage *r = NULL;
360
361     pa_assert(conn);
362     pa_assert(msg);
363     pa_assert(userdata);
364
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));
367
368     if (r) {
369         pa_assert_se(dbus_connection_send((conn), r, NULL));
370         dbus_message_unref(r);
371     }
372
373     return DBUS_HANDLER_RESULT_HANDLED;
374 }
375
376 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
377     stream_list list;
378     DBusMessage *reply = NULL;
379     DBusMessageIter msg_iter;
380     pa_stream_manager *m = (pa_stream_manager*)userdata;
381
382     pa_assert(conn);
383     pa_assert(msg);
384     pa_assert(m);
385
386     pa_assert_se(dbus_message_get_args(msg, NULL,
387                                        DBUS_TYPE_INVALID));
388     pa_log_info("get stream list");
389
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);
396     } else {
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);
399     }
400     pa_assert_se(dbus_connection_send(conn, reply, NULL));
401     dbus_message_unref(reply);
402 }
403
404 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
405     char *type;
406     stream_info_per_type info;
407     DBusMessage *reply = NULL;
408     DBusMessageIter msg_iter;
409     pa_stream_manager *m = (pa_stream_manager*)userdata;
410
411     pa_assert(conn);
412     pa_assert(msg);
413     pa_assert(m);
414
415     pa_assert_se(dbus_message_get_args(msg, NULL,
416                                        DBUS_TYPE_STRING, &type,
417                                        DBUS_TYPE_INVALID));
418     pa_log_info("type[%s]", type);
419
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);
430
431     pa_assert_se(dbus_connection_send(conn, reply, NULL));
432     dbus_message_unref(reply);
433 }
434
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;
438     uint32_t i = 0;
439
440     pa_assert(m);
441     pa_assert(device_list);
442
443     dm_device_list = pa_device_manager_get_device_list(m->dm);
444
445     for (i = 0; i < length; i++) {
446         pa_tz_device *dm_device;
447         uint32_t dm_device_id;
448         uint32_t idx = 0;
449
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);
454                 found_count++;
455                 if (length == found_count)
456                     return true;
457                 break;
458             }
459         }
460     }
461
462   return false;
463 }
464
465 static ret_msg_t update_devices_and_trigger_routing(pa_stream_manager *m, stream_parent *sp, stream_type_t type) {
466     void *stream = NULL;
467     pa_idxset *idx_streams = NULL;
468     uint32_t idx = 0;
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;
472
473     pa_assert(m);
474     pa_assert(sp);
475
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;
479     } else {
480         idx_streams = sp->idx_source_outputs;
481         cur_highest_priority_stream = (void*)m->cur_highest_priority.source_output;
482     }
483
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;
490
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);
495             } else {
496                 pa_log_error(" -- the route type is not valid[%d]", route_type);
497                 return RET_MSG_ERROR_POLICY;
498             }
499         }
500     }
501
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);
508         }
509     } else {
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);
518             }
519         }
520     }
521
522     return ret;
523 }
524
525 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
526     uint32_t id = 0;
527     int i = 0;
528     uint32_t *in_device_list = NULL;
529     uint32_t *out_device_list = NULL;
530     int list_len_in = 0;
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;
536
537     pa_assert(conn);
538     pa_assert(msg);
539     pa_assert(m);
540
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,
545                                        DBUS_TYPE_INVALID));
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);
548
549     pa_assert_se((reply = dbus_message_new_method_return(msg)));
550
551     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
552     if (!sp) {
553         pa_log_error("could not find matching client for this parent_id[%u]", id);
554         ret = RET_MSG_ERROR_INTERNAL;
555         goto finish;
556     }
557     if (!in_device_list && !out_device_list) {
558         pa_log_error("invalid arguments");
559         ret = RET_MSG_ERROR_INVALID_ARGUMENT;
560         goto finish;
561     }
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;
566         goto finish;
567     }
568
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;
573         goto finish;
574     }
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;
578         goto finish;
579     }
580
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]);
586         }
587     }
588     if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SOURCE_OUTPUT)))
589         goto finish;
590
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]);
596         }
597     }
598     if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SINK_INPUT)))
599         goto finish;
600
601 finish:
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);
605 }
606
607 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
608     uint32_t id = 0;
609     const char *name = NULL;
610     int32_t value = 0;
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;
616
617     pa_assert(conn);
618     pa_assert(msg);
619     pa_assert(m);
620
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,
625                                        DBUS_TYPE_INVALID));
626     pa_log_info("name[%s], value[%d]", name, value);
627
628     pa_assert_se((reply = dbus_message_new_method_return(msg)));
629
630     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
631     if (sp) {
632         if (name) {
633             route_option.name = name;
634             route_option.value = value;
635
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);
642                     updated = true;
643                 }
644             }
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);
650                     updated = true;
651                 }
652             }
653             if (!updated) {
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));
656             } else
657                 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
658         } else {
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));
661         }
662
663     } else {
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));
666     }
667
668     pa_assert_se(dbus_connection_send(conn, reply, NULL));
669     dbus_message_unref(reply);
670 }
671
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) {
673     pa_assert(m);
674     pa_assert(sp);
675     pa_assert(device);
676
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]);
681             return -1;
682         }
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));
684     } else {
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);
688             return -1;
689         }
690         pa_log_debug("requested preferred device type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
691     }
692
693     return 0;
694 }
695
696 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
697     const char *device_direction = NULL;
698     uint32_t sp_id = 0;
699     uint32_t device_id = 0;
700     uint32_t idx;
701     uint32_t count = 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;
709     void *stream;
710     pa_idxset *streams;
711     pa_proplist *props;
712     pa_proplist *device_props;
713     uint32_t stream_index;
714     pa_hashmap *devices;
715     void *new_device = NULL;
716     ret_msg_t ret = RET_MSG_OK;
717     DBusMessage *reply = NULL;
718
719     pa_stream_manager *m = (pa_stream_manager*)userdata;
720
721     pa_assert(conn);
722     pa_assert(msg);
723     pa_assert(m);
724
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,
729                                        DBUS_TYPE_INVALID));
730     pa_log_info("stream parent id[%u], device direction[%s], device_id[%u]", sp_id, device_direction, device_id);
731
732     pa_assert_se((reply = dbus_message_new_method_return(msg)));
733
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;
737         goto finish;
738     }
739
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;
744     else {
745         ret = RET_MSG_ERROR_INVALID_ARGUMENT;
746         goto finish;
747     }
748
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;
754         goto finish;
755     }
756
757     if (device_id == 0 && !sp->preferred_device.types[direction]) {
758         pa_log_debug("it is already unset");
759         goto finish;
760     }
761
762     if (get_device_for_preference(m, sp, direction, device_id, &device) < 0) {
763         ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
764         goto finish;
765     }
766
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;
771         goto finish;
772     }
773
774     /* get default role of the device */
775     device_role = pa_tz_device_get_role(device, NULL);
776
777     sp->preferred_device.types[direction] = (device_id == 0) ? NULL : device->type;
778     sp->preferred_device.roles[direction] = (device_id == 0) ? NULL : device_role;
779
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");
782
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;
785
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;
795
796         if (device_id == 0)
797             pa_proplist_unset(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
798         else
799             pa_proplist_sets(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE, device_role);
800
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);
803
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);
811             }
812         } else {
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);
818             if (new_device) {
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));
822             }
823         }
824         if (new_device)
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);
827
828         if (count == 1)
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);
835         count--;
836     }
837
838 finish:
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);
842 }
843
844 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
845     stream_parent *sp = NULL;
846     uint32_t sp_id = 0;
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;
854     uint32_t idx = 0;
855     ret_msg_t ret = RET_MSG_OK;
856     DBusMessage *reply = NULL;
857
858     pa_stream_manager *m = (pa_stream_manager*)userdata;
859
860     pa_assert(conn);
861     pa_assert(msg);
862     pa_assert(m);
863
864     pa_assert_se(dbus_message_get_args(msg, NULL,
865                                        DBUS_TYPE_UINT32, &sp_id,
866                                        DBUS_TYPE_INVALID));
867     pa_log_info("stream parent id[%u]", sp_id);
868
869     pa_assert_se((reply = dbus_message_new_method_return(msg)));
870
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;
874         goto finish;
875     }
876
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];
881
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);
890             }
891         }
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);
896             }
897         }
898     }
899
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);
902
903 finish:
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);
909 }
910
911 static uint32_t get_num_of_target_streams(pa_stream_manager *m, pa_idxset *streams, stream_direction_t direction, const char *role) {
912     void *s;
913     const char *_role;
914     uint32_t idx;
915     uint32_t count = 0;
916
917     pa_assert(m);
918     pa_assert(streams);
919     pa_assert(role);
920
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))
925             count++;
926     }
927     return count;
928 }
929
930 static void routing_process_to_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
931     void *stream;
932     void *device = NULL;
933     const char *_role;
934     uint32_t count = 0;
935     uint32_t idx;
936
937     pa_assert(m);
938     pa_assert(role);
939     pa_assert(tz_device);
940
941     count = get_num_of_target_streams(m, (direction == STREAM_DIRECTION_OUT) ?
942                                       m->core->sink_inputs : m->core->source_outputs,
943                                       direction, role);
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))
948             continue;
949
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);
957         } else {
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);
961         }
962
963         /* change routing */
964         if (--count == 0) {
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);
967         }
968     }
969 }
970
971 static void rollback_process_from_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
972     void *device;
973     void *stream;
974     void *new_device;
975     uint32_t idx;
976     uint32_t count = 0;
977     const char *active_device = NULL;
978     const char *_role;
979
980     pa_assert(m);
981     pa_assert(role);
982     pa_assert(tz_device);
983
984     device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
985                               tz_device->playback_devices : tz_device->capture_devices);
986
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))
991             continue;
992
993         if (count++ == 0) {
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,
997                      false, stream);
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);
1005
1006             if (direction == STREAM_DIRECTION_OUT)
1007                 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1008             else
1009                 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1010
1011             continue;
1012         }
1013
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);
1017             if (active_device)
1018                 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1019         } else {
1020             pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1021             if (active_device)
1022                 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1023         }
1024     }
1025 }
1026
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;
1037     uint32_t idx;
1038     bool found = false;
1039     ret_msg_t ret = RET_MSG_OK;
1040     DBusMessage *reply = NULL;
1041
1042     pa_stream_manager *m = (pa_stream_manager*)userdata;
1043
1044     pa_assert(conn);
1045     pa_assert(msg);
1046     pa_assert(m);
1047
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);
1054
1055     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1056
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;
1060         goto finish;
1061     }
1062
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;
1067     else {
1068         ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1069         goto finish;
1070     }
1071
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;
1077         goto finish;
1078     }
1079
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;
1084             goto finish;
1085         }
1086
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)) {
1089                 found = true;
1090                 break;
1091             }
1092         }
1093         if (!found) {
1094             pa_log_error("not supported this device type[%s]", device->type);
1095             ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1096             goto finish;
1097         }
1098     }
1099
1100     if (device_id == 0 && s->preemptive_device[direction].id == 0) {
1101         pa_log_debug("there's no preemptive device, nothing to do");
1102         goto finish;
1103     }
1104
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;
1109
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,
1113                 device_id);
1114
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);
1119             goto finish;
1120         }
1121         rollback_process_from_preemptive_device(m, direction, stream_type, device);
1122     } else {
1123         routing_process_to_preemptive_device(m, direction, stream_type, device);
1124     }
1125
1126 finish:
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);
1130 }
1131
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;
1141
1142     pa_stream_manager *m = (pa_stream_manager*)userdata;
1143
1144     pa_assert(conn);
1145     pa_assert(msg);
1146     pa_assert(m);
1147
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);
1152
1153     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1154
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;
1158         goto finish;
1159     }
1160
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;
1165
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);
1168
1169 finish:
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);
1175 }
1176
1177 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1178     const char *direction = NULL;
1179     const char *type = NULL;
1180     uint32_t level = 0;
1181     stream_type_t stream_type = STREAM_SINK_INPUT;
1182     DBusMessage *reply = NULL;
1183     pa_stream_manager *m = (pa_stream_manager*)userdata;
1184     int ret = 0;
1185     ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1186
1187     pa_assert(conn);
1188     pa_assert(msg);
1189     pa_assert(m);
1190
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);
1197
1198     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1199
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;
1204     else {
1205         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1206         ret = -1;
1207         goto finish;
1208     }
1209
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));
1213         goto finish;
1214     }
1215
1216     if ((ret = set_volume_level_by_type(m, stream_type, type, level))) {
1217         if (ret == -2)
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));
1220     } else {
1221         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1222     }
1223
1224 finish:
1225     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1226     dbus_message_unref(reply);
1227
1228     if (!ret)
1229         send_volume_changed_signal(conn, direction, type, level);
1230 }
1231
1232 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1233     const char *direction = NULL;
1234     const char *type = NULL;
1235     uint32_t level = 0;
1236     stream_type_t stream_type = STREAM_SINK_INPUT;
1237     DBusMessage *reply = NULL;
1238     pa_stream_manager *m = (pa_stream_manager*)userdata;
1239
1240     pa_assert(conn);
1241     pa_assert(msg);
1242     pa_assert(m);
1243
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);
1249
1250     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1251
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;
1256     else {
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));
1259         goto finish;
1260     }
1261
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));
1265     } else {
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));
1268     }
1269
1270 finish:
1271     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1272     dbus_message_unref(reply);
1273 }
1274
1275 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1276     const char *direction = NULL;
1277     const char *type = NULL;
1278     uint32_t level = 0;
1279     stream_type_t stream_type = STREAM_SINK_INPUT;
1280     DBusMessage *reply = NULL;
1281     pa_stream_manager *m = (pa_stream_manager*)userdata;
1282
1283     pa_assert(conn);
1284     pa_assert(msg);
1285     pa_assert(m);
1286
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);
1292
1293     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1294
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;
1299     else {
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));
1302         goto finish;
1303     }
1304
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));
1308     } else {
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));
1311     }
1312 finish:
1313     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1314     dbus_message_unref(reply);
1315 }
1316
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;
1324     int ret = 0;
1325
1326     pa_assert(conn);
1327     pa_assert(msg);
1328     pa_assert(m);
1329
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);
1336
1337     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1338
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;
1343     else {
1344         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1345         goto finish;
1346     }
1347
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));
1351         goto finish;
1352     }
1353
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));
1356     else
1357         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1358
1359 finish:
1360     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1361     dbus_message_unref(reply);
1362 }
1363
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;
1371
1372     pa_assert(conn);
1373     pa_assert(msg);
1374     pa_assert(m);
1375
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);
1381
1382     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1383
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;
1388     else {
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));
1391         goto fail;
1392     }
1393
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));
1397     } else {
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));
1400     }
1401
1402 fail:
1403     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1404     dbus_message_unref(reply);
1405 }
1406
1407 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1408     const char *direction = NULL;
1409     uint32_t idx;
1410     double ratio;
1411     stream_type_t stream_type = STREAM_SINK_INPUT;
1412     DBusMessage *reply = NULL;
1413     pa_stream_manager *m = (pa_stream_manager*)userdata;
1414     int ret = 0;
1415     ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1416
1417     pa_assert(conn);
1418     pa_assert(msg);
1419     pa_assert(m);
1420
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);
1427
1428     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1429
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;
1434     else {
1435         pa_log_error("invalid direction[%s]", direction);
1436         goto invalid_argument;
1437     }
1438
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;
1443     }
1444
1445     if ((ret = set_volume_ratio_by_idx(m, stream_type, idx, ratio))) {
1446         if (ret == -2)
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));
1449     } else {
1450         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1451     }
1452
1453     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1454     dbus_message_unref(reply);
1455     return;
1456
1457 invalid_argument:
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);
1462 }
1463
1464 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1465     const char *direction = NULL;
1466     uint32_t idx = 0;
1467     double ratio;
1468     stream_type_t stream_type = STREAM_SINK_INPUT;
1469     DBusMessage *reply = NULL;
1470     pa_stream_manager *m = (pa_stream_manager*)userdata;
1471
1472     pa_assert(conn);
1473     pa_assert(msg);
1474     pa_assert(m);
1475
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);
1481
1482     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1483
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;
1488     else {
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));
1491         goto finish;
1492     }
1493
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));
1497     } else {
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));
1500     }
1501
1502 finish:
1503     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1504     dbus_message_unref(reply);
1505 }
1506
1507 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1508     const char *direction = NULL;
1509     const char *type = NULL;
1510     void *s = NULL;
1511     stream_type_t stream_type = STREAM_SINK_INPUT;
1512     DBusMessage *reply = NULL;
1513     pa_stream_manager *m = (pa_stream_manager*)userdata;
1514     uint32_t idx = 0;
1515     pa_idxset *streams = NULL;
1516
1517     pa_assert(conn);
1518     pa_assert(msg);
1519     pa_assert(m);
1520
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);
1525
1526     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1527
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;
1534     } else {
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));
1537         goto fail;
1538     }
1539
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;
1547
1548         PA_IDXSET_FOREACH(s, streams, idx) {
1549             if (!CHECK_STREAM_RUNNING(s, stream_type))
1550                 continue;
1551             if (!(type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE)))
1552                 continue;
1553             if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE)))
1554                 continue;
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);
1560                 }
1561             }
1562         }
1563         type = cur_max_type;
1564     }
1565
1566     if (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));
1569     } else {
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));
1572     }
1573
1574 fail:
1575     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1576     dbus_message_unref(reply);
1577 }
1578
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;
1587
1588     pa_assert(conn);
1589     pa_assert(msg);
1590     pa_assert(m);
1591
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);
1596
1597     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1598
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;
1603     } else {
1604         pa_log_error("invalid direction[%s]", direction);
1605         goto fail;
1606     }
1607
1608     if ((s = pa_hashmap_get(m->stream_infos, STREAM_ROLE_MEDIA)) == NULL) {
1609         pa_log_error("could not find media role");
1610         goto fail;
1611     }
1612
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);
1617     } else {
1618         pa_log_error("unexpected routing type for media[%d]", s->route_type);
1619         goto fail;
1620     }
1621
1622     if (device) {
1623         device_type = pa_tz_device_get_type(device);
1624         goto success;
1625     } else {
1626         pa_log_error("could not found matched device");
1627     }
1628
1629 fail:
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);
1634     return;
1635 success:
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);
1640 }
1641
1642 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1643     uint32_t id = 0;
1644     uint32_t idx = 0;
1645     uint32_t count = 0;
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;
1652
1653     pa_assert(conn);
1654     pa_assert(msg);
1655     pa_assert(m);
1656
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);
1662
1663     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1664
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);
1675                     if (--count == 0)
1676                         process_stream(m, stream, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1677                 }
1678             }
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);
1684                     if (--count == 0)
1685                         process_stream(m, stream, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1686                 }
1687             }
1688         } else
1689             pa_log_debug("same as before, skip updating focus status[0x%x]", acquired_focus_status);
1690
1691     } else {
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));
1694         goto fail;
1695     }
1696     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1697 fail:
1698     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1699     dbus_message_unref(reply);
1700 }
1701
1702 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1703     int32_t id = 0;
1704     uint32_t idx = 0;
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;
1711
1712     pa_assert(conn);
1713     pa_assert(msg);
1714     pa_assert(m);
1715
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);
1721
1722     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1723
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))
1728               continue;
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);
1734
1735             pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1736             goto success;
1737         }
1738       }
1739     }
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));
1742 success:
1743     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1744     dbus_message_unref(reply);
1745 }
1746
1747 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1748     const char *name;
1749     uint32_t value = 0;
1750     DBusMessage *reply = NULL;
1751     pa_stream_manager *m = (pa_stream_manager*)userdata;
1752
1753     pa_assert(conn);
1754     pa_assert(msg);
1755     pa_assert(m);
1756
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);
1762
1763     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1764
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));
1767         goto fail;
1768     }
1769
1770     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1771 fail:
1772     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1773     dbus_message_unref(reply);
1774 }
1775
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;
1780     char key[32] = "";
1781
1782     pa_assert(parameters);
1783     pa_assert(call_type);
1784     pa_assert(call_domain);
1785     pa_assert(network_band);
1786
1787     pa_log_info("parameters[%s]", parameters);
1788
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);
1793
1794     if (parameters) {
1795         token = strtok_r((char *)parameters, delimiter, &ptr);
1796         while (token) {
1797             char *delimiter_ptr = NULL;
1798             char *value = NULL;
1799
1800             delimiter_ptr = strstr(token, "=");
1801             if (!delimiter_ptr) {
1802                 token = strtok_r(NULL, delimiter, &ptr);
1803                 continue;
1804             }
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);
1814             else
1815                 pa_log_warn("not supported key(%s)", key);
1816
1817             token = strtok_r(NULL, delimiter, &ptr);
1818             memset(key, 0, sizeof(key));
1819         }
1820         pa_log_info("call-type[%s], call-domain[%s], network-band[%s]", call_type, call_domain, network_band);
1821     }
1822
1823     return 0;
1824 }
1825
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;
1835
1836     pa_assert(conn);
1837     pa_assert(msg);
1838     pa_assert(m);
1839
1840     pa_assert_se(dbus_message_get_args(msg, NULL,
1841                                        DBUS_TYPE_STRING, &parameters,
1842                                        DBUS_TYPE_INVALID));
1843     pa_log_info("parameters[%s]", parameters);
1844
1845     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1846
1847     if (parse_call_parameters(parameters, call_type, call_domain, network_band) < 0) {
1848         ret = RET_MSG_ERROR_INTERNAL;
1849         goto fail;
1850     }
1851
1852     pa_log_debug("call_type[%s], call_domain[%s], network_band[%s]", call_type, call_domain, network_band);
1853
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;
1858     else
1859         route_option.value = 0;
1860     ret = do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
1861
1862 fail:
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);
1866 }
1867
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;
1872
1873     pa_assert(conn);
1874     pa_assert(msg);
1875     pa_assert(m);
1876
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);
1885
1886     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1887
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));
1892         goto fail;
1893     }
1894
1895     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1896                                           DBUS_TYPE_INVALID));
1897
1898 fail:
1899     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1900     dbus_message_unref(reply);
1901 }
1902
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;
1907
1908     pa_assert(conn);
1909     pa_assert(msg);
1910     pa_assert(m);
1911
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);
1916
1917     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1918
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));
1923         goto fail;
1924     }
1925
1926     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1927                                           DBUS_TYPE_INVALID));
1928
1929 fail:
1930     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1931     dbus_message_unref(reply);
1932 }
1933
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;
1938
1939     pa_assert(conn);
1940     pa_assert(msg);
1941     pa_assert(m);
1942
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);
1949
1950     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1951
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));
1956         goto fail;
1957     }
1958
1959     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1960                  DBUS_TYPE_INVALID));
1961 fail:
1962     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1963     dbus_message_unref(reply);
1964 }
1965
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;
1968     uint32_t idx = 0;
1969     const char *role = NULL;
1970     const char *app_pid_str = NULL;
1971     uint32_t app_pid = 0;
1972
1973     pa_assert(m);
1974     pa_assert(stream_role);
1975
1976     pa_log_info("pid[%u], role[%s], type[%d]", pid, stream_role, type);
1977
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))
1981             continue;
1982
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));
1985             continue;
1986         }
1987
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));
1992                 return true;
1993             }
1994         }
1995     }
1996
1997     return false;
1998 }
1999
2000 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2001     uint32_t pid = 0;
2002     const char *type;
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;
2007
2008     pa_assert(conn);
2009     pa_assert(msg);
2010     pa_assert(m);
2011
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);
2018
2019     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2020
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;
2025     else {
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));
2028         goto fail;
2029     }
2030
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));
2034         goto fail;
2035     }
2036
2037     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
2038                  DBUS_TYPE_INVALID));
2039 fail:
2040     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2041     dbus_message_unref(reply);
2042 }
2043
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;
2046     uint32_t idx = 0;
2047     const char *role;
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;
2053     int i;
2054
2055     pa_assert(m);
2056     pa_assert(stream_roles);
2057     pa_assert(pid);
2058
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));
2062             continue;
2063         }
2064
2065         for (i = 0; i <length; i++) {
2066             tmp_pid = 0;
2067             tmp_time = 0;
2068
2069             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2070             if (!pa_safe_streq(stream_roles[i], role))
2071                 continue;
2072
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]);
2076             } else {
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]);
2080             }
2081             if (tmp_pid) {
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;
2086                 }
2087             }
2088         }
2089     }
2090
2091     if (latest_pid > 0) {
2092         *pid = latest_pid;
2093         pa_log_info("found the stream(pid:%u)", *pid);
2094         return true;
2095     }
2096
2097     pa_log_info("no match is found");
2098     return false;
2099 }
2100
2101 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2102     const char *direction;
2103     const char **types;
2104     int length;
2105     stream_type_t stream_type = STREAM_SINK_INPUT;
2106     uint32_t pid = 0;
2107     ret_msg_t ret_msg = RET_MSG_OK;
2108
2109     DBusMessage *reply = NULL;
2110     pa_stream_manager *m = (pa_stream_manager*)userdata;
2111
2112     pa_assert(conn);
2113     pa_assert(msg);
2114     pa_assert(m);
2115
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));
2120
2121     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2122
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;
2127     else {
2128         pa_log_error("invalid direction[%s]", direction);
2129         goto invalid_argument;
2130     }
2131
2132     if (length <= 0) {
2133         pa_log_error("At least one stream type should be contained");
2134         goto invalid_argument;
2135     }
2136
2137     if (!find_the_lastest_stream(m, stream_type, types, length, &pid))
2138         ret_msg = RET_MSG_ERROR_NO_STREAM;
2139
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);
2145     return;
2146
2147 invalid_argument:
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);
2153 }
2154
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;
2159     uint32_t idx = 0;
2160     pa_sink_input *i = NULL;
2161     dbus_uint32_t duration = 0;
2162     double ratio = 0.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;
2169
2170     pa_assert(conn);
2171     pa_assert(msg);
2172     pa_assert(m);
2173
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));
2181
2182     pa_log_info("id[%u], enable[%u], target stream[%s], duration[%u], ratio[%lf]",
2183         id, enable, target_stream, duration, ratio);
2184
2185     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2186
2187     /* get stream_ducking */
2188     sd = pa_hashmap_get(m->stream_duckings, (const void*)id);
2189     if (!sd) {
2190         pa_log_error("no matched stream ducking for id[%u]", id);
2191         ret_msg = RET_MSG_ERROR_INTERNAL;
2192         goto _ACTIVATE_DUCKING_DONE;
2193     }
2194
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;
2201     }
2202
2203     sd->duration = duration;
2204     sd->ratio = ratio;
2205     sd->set_vol = PA_VOLUME_NORM * ratio;
2206
2207     if (enable) {
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);
2211     } else {
2212         sd->state = STREAM_DUCKING_STATE_UNDUCKING;
2213     }
2214
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)))
2218             continue;
2219
2220         if (i->state == PA_SINK_INPUT_RUNNING) {
2221             target_matched = true;
2222             sd->ducking_stream_count++;
2223         }
2224
2225         if (enable) {
2226             pa_cvolume_ramp vol_ramp;
2227
2228             pa_idxset_put(sd->idx_ducking_streams, (void *)i, NULL);
2229
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);
2232
2233             pa_cvolume_ramp_set(&vol_ramp, i->volume.channels,
2234                 PA_VOLUME_RAMP_TYPE_LINEAR, (long)duration, sd->set_vol);
2235
2236             if (i->state != PA_SINK_INPUT_RUNNING) {
2237                 pa_cvolume vol;
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);
2241             } else {
2242                 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, true);
2243             }
2244         } else {
2245             pa_log_error("unducking: remove volume(ramp) factor, key[%s] from stream[idx:%u]",
2246                 sd->vol_key, i->index);
2247
2248             pa_sink_input_remove_volume_factor(i, sd->vol_key);
2249             pa_sink_input_remove_volume_ramp_factor(i, sd->vol_key, true);
2250         }
2251     }
2252
2253     if (!enable) {
2254         memset(&sd->target_role, 0, sizeof(sd->target_role));
2255         memset(&sd->vol_key, 0, sizeof(sd->vol_key));
2256     }
2257
2258     pa_log_info("ducking stream count[%p,%d]", sd, sd->ducking_stream_count);
2259
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);
2264
2265     if (ret_msg != RET_MSG_OK)
2266         return;
2267
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;
2273
2274     pa_hal_interface_notify_ducking_activation_changed(m->hal, &ducking_activation_info);
2275
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 */
2279         if (enable)
2280             sd->state = STREAM_DUCKING_STATE_DUCKED;
2281         else
2282             sd->state = STREAM_DUCKING_STATE_UNDUCKED;
2283
2284         pa_log_info("send signal for ramp finished(but, no stream matched) - state[%u]", sd->state);
2285
2286         send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
2287     }
2288 }
2289
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;
2297
2298     pa_assert(conn);
2299     pa_assert(msg);
2300     pa_assert(m);
2301
2302     pa_assert_se(dbus_message_get_args(msg, NULL,
2303                                        DBUS_TYPE_UINT32, &id,
2304                                        DBUS_TYPE_INVALID));
2305
2306     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2307
2308     /* get stream_ducking */
2309     sd = pa_hashmap_get(m->stream_duckings, (const void *)id);
2310     if (sd) {
2311         is_ducked = (dbus_bool_t)is_stream_ducked(sd);
2312         pa_log_info("id[%u], is_ducked[%p,%d]", id, sd, is_ducked);
2313     } else {
2314         ret_msg = RET_MSG_ERROR_INTERNAL;
2315         pa_log_error("no matched stream ducking for id[%u]", id);
2316     }
2317
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));
2320
2321     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2322     dbus_message_unref(reply);
2323 }
2324
2325 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2326     int idx = 0;
2327     pa_stream_manager *m = (pa_stream_manager*)userdata;
2328
2329     pa_assert(conn);
2330     pa_assert(msg);
2331     pa_assert(m);
2332
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;
2339             } else {
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;
2343             }
2344         }
2345     }
2346
2347     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2348 }
2349
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;
2353
2354     pa_assert(c);
2355     pa_assert(m);
2356     pa_assert(u);
2357
2358     path = dbus_message_get_path(m);
2359     interface = dbus_message_get_interface(m);
2360     member = dbus_message_get_member(m);
2361
2362     pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
2363
2364     if (!pa_safe_streq(path, STREAM_MANAGER_OBJECT_PATH))
2365         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2366
2367     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2368         return handle_introspect(c, m, u);
2369     } else {
2370         return handle_methods(c, m, u);
2371     }
2372
2373     return DBUS_HANDLER_RESULT_HANDLED;
2374 }
2375
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;
2379
2380     pa_assert(conn);
2381     pa_assert(direction);
2382     pa_assert(volume_type);
2383
2384     pa_log_debug("direction[%s], type[%s], level[%d]", direction, volume_type, volume_level);
2385
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);
2388
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);
2392
2393     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2394     dbus_message_unref(signal_msg);
2395     return;
2396 }
2397
2398 void send_ducking_state_changed_signal(DBusConnection *conn, const int index, const int is_ducked)
2399 {
2400     DBusMessage *signal_msg;
2401     DBusMessageIter msg_iter;
2402
2403     pa_assert(conn);
2404
2405     pa_log_debug("trigger_index(%d) : is_ducked(%d)", index, is_ducked);
2406
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);
2409
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);
2412
2413     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2414     dbus_message_unref(signal_msg);
2415
2416     return;
2417 }
2418
2419 void send_command_signal(DBusConnection *conn, const char *name, int value) {
2420     DBusMessage *signal_msg;
2421     DBusMessageIter msg_iter;
2422
2423     pa_assert(conn);
2424     pa_assert(name);
2425
2426     pa_log_debug("name[%s], value[%d]", name, value);
2427
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);
2430
2431     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2432     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &value);
2433
2434     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2435     dbus_message_unref(signal_msg);
2436 }
2437
2438 int32_t init_sm_dbus(pa_stream_manager *m) {
2439     pa_assert(m);
2440
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);
2445 #else
2446     DBusError err;
2447     pa_dbus_connection *conn = NULL;
2448     static const DBusObjectPathVTable vtable = {
2449         .message_function = method_handler_for_vt,
2450     };
2451
2452     dbus_error_init(&err);
2453
2454     if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
2455         if (conn) {
2456             pa_dbus_connection_unref(conn);
2457         }
2458         pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
2459         return -1;
2460     } else {
2461         pa_log_notice("Got dbus connection");
2462     }
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));
2465 #endif
2466     return 0;
2467 }
2468
2469 void deinit_sm_dbus(pa_stream_manager *m) {
2470     pa_assert(m);
2471
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;
2478     }
2479 #else
2480     if (m->dbus_conn) {
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;
2484     }
2485 #endif
2486 }
2487
2488 #endif