c365345171814133bf004d16affc2a28fafc00e3
[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 <pulsecore/proplist-util.h>
29 #include "stream-manager-priv.h"
30 #include "stream-manager-dbus-priv.h"
31 #include "stream-manager-volume-priv.h"
32 #include "stream-manager-filter-priv.h"
33 #include "stream-manager-restriction-priv.h"
34
35 static const char *dbus_str_none = "none";
36 static const char *stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK",
37                                              "STREAM_MANAGER_RETURN_ERROR_INTERNAL",
38                                              "STREAM_MANAGER_RETURN_ERROR_NO_STREAM",
39                                              "STREAM_MANAGER_RETURN_ERROR_INVALID_ARGUMENT",
40                                              "STREAM_MANAGER_RETURN_ERROR_DEVICE_NOT_FOUND",
41                                              "STREAM_MANAGER_RETURN_ERROR_POLICY",
42                                              "STREAM_MANAGER_RETURN_ERROR_INVALID_STATE"};
43
44 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
45 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
46 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
47 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
48 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
49 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
50 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
51 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
52 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
53 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
54 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
55 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
56 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
57 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
58 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
59 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
60 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata);
61 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
62 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata);
63 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
64 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata);
65 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata);
66 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata);
67 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
68 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
69 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata);
70 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata);
71 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
72 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata);
74 static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
77 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level);
78
79 static pa_dbus_arg_info get_stream_info_args[]  = { { "stream_type", "s", "in" },
80                                                       { "priority", "i", "out" },
81                                                     { "route_type", "i", "out" },
82                                                  { "volume_types", "as", "out" },
83                                              { "avail_in_devices", "as", "out" },
84                                             { "avail_out_devices", "as", "out" },
85                                             { "avail_frameworks", "as", "out"} };
86 static pa_dbus_arg_info get_stream_list_args[]  = { { "stream_type", "as", "out" },
87                                                      { "priority", "ai", "out" } };
88 static pa_dbus_arg_info set_stream_route_devices_args[]  = { { "parent_id", "u", "in" },
89                                                      { "route_in_devices", "au", "in" },
90                                                     { "route_out_devices", "au", "in" },
91                                                             { "ret_msg", "s", "out" } };
92 static pa_dbus_arg_info set_stream_route_option_args[]  = { { "parent_id", "u", "in" },
93                                                                  { "name", "s", "in" },
94                                                                 { "value", "i", "in" },
95                                                            { "ret_msg", "s", "out" } };
96 static pa_dbus_arg_info set_stream_preferred_device_args[]  = { { "parent_id", "u", "in" },
97                                                              { "io_direction", "s", "in" },
98                                                                 { "device_id", "u", "in" },
99                                                                { "ret_msg", "s", "out" } };
100 static pa_dbus_arg_info get_stream_preferred_device_args[]  = { { "parent_id", "u", "in" },
101                                                             { "in_device_id", "u", "out" },
102                                                            { "out_device_id", "u", "out" },
103                                                                { "ret_msg", "s", "out" } };
104 static pa_dbus_arg_info set_stream_preemptive_device_args[]  = { { "stream_type", "s", "in" },
105                                                                 { "io_direction", "s", "in" },
106                                                                    { "device_id", "u", "in" },
107                                                                   { "ret_msg", "s", "out" } };
108 static pa_dbus_arg_info get_stream_preemptive_device_args[]  = { { "stream_type", "s", "in" },
109                                                                { "in_device_id", "u", "out" },
110                                                               { "out_device_id", "u", "out" },
111                                                                   { "ret_msg", "s", "out" } };
112 static pa_dbus_arg_info set_volume_level_args[]  = { { "io_direction", "s", "in" },
113                                                              { "type", "s", "in" },
114                                                             { "level", "u", "in" },
115                                                        { "ret_msg", "s", "out" } };
116 static pa_dbus_arg_info get_volume_level_args[]  = { { "io_direction", "s", "in" },
117                                                              { "type", "s", "in" },
118                                                            { "level", "u", "out" },
119                                                        { "ret_msg", "s", "out" } };
120 static pa_dbus_arg_info get_volume_max_level_args[]  = { { "io_direction", "s", "in" },
121                                                                  { "type", "s", "in" },
122                                                                { "level", "u", "out" },
123                                                            { "ret_msg", "s", "out" } };
124 static pa_dbus_arg_info set_volume_mute_args[]  = { { "io_direction", "s", "in" },
125                                                             { "type", "s", "in" },
126                                                               { "on", "u", "in" },
127                                                       { "ret_msg", "s", "out" } };
128 static pa_dbus_arg_info get_volume_mute_args[]  = { { "io_direction", "s", "in" },
129                                                             { "type", "s", "in" },
130                                                              { "on", "u", "out" },
131                                                       { "ret_msg", "s", "out" } };
132 static pa_dbus_arg_info set_volume_ratio_args[]  = { { "io_direction", "s", "in" },
133                                                              { "idx", "u", "in" },
134                                                            { "ratio", "d", "in" },
135                                                       { "ret_msg", "s", "out" } };
136 static pa_dbus_arg_info get_volume_ratio_args[]  = { { "io_direction", "s", "in" },
137                                                              { "idx", "u", "in" },
138                                                           { "ratio", "d", "out" },
139                                                       { "ret_msg", "s", "out" } };
140 static pa_dbus_arg_info get_current_volume_type_args[]  = { { "io_direction", "s", "in" },
141                                                                    { "type", "s", "out" },
142                                                               { "ret_msg", "s", "out" } };
143 static pa_dbus_arg_info get_current_media_routing_path_args[]  = { { "io_direction", "s", "in" },
144                                                                    { "device_type", "s", "out" },
145                                                                      { "ret_msg", "s", "out" } };
146 static pa_dbus_arg_info update_focus_status_args[]  = { { "parent_id", "u", "in" },
147                                                      { "focus_status", "u", "in" },
148                                                        { "ret_msg", "s", "out" } };
149 static pa_dbus_arg_info update_focus_status_by_focus_id_args[]  = { { "focus_id", "i", "in" },
150                                                                 { "focus_status", "u", "in" },
151                                                                   { "ret_msg", "s", "out" } };
152 static pa_dbus_arg_info update_restriction_args[]  = { { "name", "s", "in" },
153                                                       { "value", "u", "in" },
154                                                  { "ret_msg", "s", "out" } };
155 static pa_dbus_arg_info update_call_parameters_args[]  = { { "parameters", "s", "in" },
156                                                            { "ret_msg", "s", "out" } };
157 static pa_dbus_arg_info set_filter_args[] = { { "filter_name",       "s",  "in" },
158                                               { "filter_parameters", "s",  "in" },
159                                               { "filter_group",      "s",  "in" },
160                                               { "stream_type",       "s",  "in" },
161                                             { "ret_msg",           "s", "out" } };
162 static pa_dbus_arg_info unset_filter_args[] =   { { "stream_type",       "s",  "in" },
163                                                 { "ret_msg",           "s", "out" } };
164 static pa_dbus_arg_info control_filter_args[] = { { "filter_name",       "s",  "in" },
165                                                   { "filter_controls",   "s",  "in" },
166                                                   { "stream_type",       "s",  "in" },
167                                                 { "ret_msg",           "s", "out" } };
168 static pa_dbus_arg_info check_stream_exist_by_pid_args[]  = { { "pid", "u", "in" },
169                                                       { "stream_type", "s", "in" },
170                                                      { "io_direction", "s", "in" },
171                                                        { "ret_msg", "s", "out" } };
172 static pa_dbus_arg_info get_pid_of_latest_stream_args[]  = { { "io_direction", "s", "in" },
173                                                             { "stream_types", "as", "in" },
174                                                                      { "pid", "u", "out" },
175                                                                { "ret_msg", "s", "out" } };
176 static pa_dbus_arg_info activate_ducking_args[] = { { "index", "u", "in" },
177                                                   { "enable", "b",  "in" },
178                                            { "target_stream", "s",  "in" },
179                                                 { "duration", "u",  "in" },
180                                                    { "ratio", "d",  "in" },
181                                                { "ret_msg", "s", "out" } };
182
183 static pa_dbus_arg_info get_ducking_state_args[] = { { "index", "u", "in" },
184                                                { "is_ducked", "b",  "out" },
185                                                 { "ret_msg", "s", "out" } };
186 static pa_dbus_arg_info set_remote_permission_args[] = { { "type", "s", "in" },
187                                                    { "index", "u",  "in" },
188                                                    { "allowed", "b", "in" } };
189 static pa_dbus_arg_info discover_remote_device_args[] = { { "enable", "b", "in" } };
190 static pa_dbus_arg_info publish_local_device_args[] = { { "enable", "b", "in" } };
191
192 static const char* signature_args_for_in[] = {
193     "s",        /* METHOD_HANDLER_GET_STREAM_INFO */
194     "",         /* METHOD_HANDLER_GET_STREAM_LIST */
195     "uauau",    /* METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES */
196     "usi",      /* METHOD_HANDLER_SET_STREAM_ROUTE_OPTION */
197     "usu",      /* METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE */
198     "u",        /* METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE */
199     "ssu",      /* METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE */
200     "s",        /* METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE */
201     "ssu",      /* METHOD_HANDLER_SET_VOLUME_LEVEL */
202     "ss",       /* METHOD_HANDLER_GET_VOLUME_LEVEL */
203     "ss",       /* METHOD_HANDLER_GET_VOLUME_MAX_LEVEL */
204     "ssu",      /* METHOD_HANDLER_SET_VOLUME_MUTE */
205     "ss",       /* METHOD_HANDLER_GET_VOLUME_MUTE */
206     "sud",      /* METHOD_HANDLER_SET_VOLUME_RATIO */
207     "su",       /* METHOD_HANDLER_GET_VOLUME_RATIO */
208     "s",        /* METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE */
209     "s",        /* METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH */
210     "uu",       /* METHOD_HANDLER_UPDATE_FOCUS_STATUS */
211     "iu",       /* METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID */
212     "su",       /* METHOD_HANDLER_UPDATE_RESTRICTION */
213     "s",        /* METHOD_HANDLER_UPDATE_CALL_PARAMETERS */
214     "ssss",     /* METHOD_HANDLER_SET_FILTER */
215     "s",        /* METHOD_HANDLER_UNSET_FILTER */
216     "sss",      /* METHOD_HANDLER_CONTROL_FILTER */
217     "uss",      /* METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID */
218     "sas",      /* METHOD_HANDLER_GET_PID_OF_LATEST_STREAM */
219     "ubsud",    /* METHOD_HANDLER_ACTIVATE_DUCKING */
220     "u",        /* METHOD_HANDLER_GET_DUCKING_STATE */
221     "sub",      /* METHOD_HANDLER_SET_REMOTE_PERMISSION */
222     "b",        /* METHOD_HANDLER_DISCOVER_REMOTE_DEVICE */
223     "b"         /* METHOD_HANDLER_PUBLISH_LOCAL_DEVICE */
224     };
225
226 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
227     [METHOD_HANDLER_GET_STREAM_INFO] = {
228         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
229         .arguments = get_stream_info_args,
230         .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
231         .receive_cb = handle_get_stream_info },
232     [METHOD_HANDLER_GET_STREAM_LIST] = {
233         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
234         .arguments = get_stream_list_args,
235         .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
236         .receive_cb = handle_get_stream_list },
237     [METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES] = {
238         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
239         .arguments = set_stream_route_devices_args,
240         .n_arguments = sizeof(set_stream_route_devices_args) / sizeof(pa_dbus_arg_info),
241         .receive_cb = handle_set_stream_route_devices },
242     [METHOD_HANDLER_SET_STREAM_ROUTE_OPTION] = {
243         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
244         .arguments = set_stream_route_option_args,
245         .n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
246         .receive_cb = handle_set_stream_route_option },
247     [METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE] = {
248         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREFERRED_DEVICE,
249         .arguments = set_stream_preferred_device_args,
250         .n_arguments = sizeof(set_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
251         .receive_cb = handle_set_stream_preferred_device },
252     [METHOD_HANDLER_GET_STREAM_PREFERRED_DEVICE] = {
253         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREFERRED_DEVICE,
254         .arguments = get_stream_preferred_device_args,
255         .n_arguments = sizeof(get_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
256         .receive_cb = handle_get_stream_preferred_device },
257     [METHOD_HANDLER_SET_STREAM_PREEMPTIVE_DEVICE] = {
258         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREEMPTIVE_DEVICE,
259         .arguments = set_stream_preemptive_device_args,
260         .n_arguments = sizeof(set_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
261         .receive_cb = handle_set_stream_preemptive_device },
262     [METHOD_HANDLER_GET_STREAM_PREEMPTIVE_DEVICE] = {
263         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_PREEMPTIVE_DEVICE,
264         .arguments = get_stream_preemptive_device_args,
265         .n_arguments = sizeof(get_stream_preemptive_device_args) / sizeof(pa_dbus_arg_info),
266         .receive_cb = handle_get_stream_preemptive_device },
267     [METHOD_HANDLER_SET_VOLUME_LEVEL] = {
268         .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
269         .arguments = set_volume_level_args,
270         .n_arguments = sizeof(set_volume_level_args) / sizeof(pa_dbus_arg_info),
271         .receive_cb = handle_set_volume_level },
272     [METHOD_HANDLER_GET_VOLUME_LEVEL] = {
273         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
274         .arguments = get_volume_level_args,
275         .n_arguments = sizeof(get_volume_level_args) / sizeof(pa_dbus_arg_info),
276         .receive_cb = handle_get_volume_level },
277     [METHOD_HANDLER_GET_VOLUME_MAX_LEVEL] = {
278         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
279         .arguments = get_volume_max_level_args,
280         .n_arguments = sizeof(get_volume_max_level_args) / sizeof(pa_dbus_arg_info),
281         .receive_cb = handle_get_volume_max_level },
282     [METHOD_HANDLER_SET_VOLUME_MUTE] = {
283         .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE,
284         .arguments = set_volume_mute_args,
285         .n_arguments = sizeof(set_volume_mute_args) / sizeof(pa_dbus_arg_info),
286         .receive_cb = handle_set_volume_mute },
287     [METHOD_HANDLER_GET_VOLUME_MUTE] = {
288         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE,
289         .arguments = get_volume_mute_args,
290         .n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
291         .receive_cb = handle_get_volume_mute },
292     [METHOD_HANDLER_SET_VOLUME_RATIO] = {
293         .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_RATIO,
294         .arguments = set_volume_ratio_args,
295         .n_arguments = sizeof(set_volume_ratio_args) / sizeof(pa_dbus_arg_info),
296         .receive_cb = handle_set_volume_ratio },
297     [METHOD_HANDLER_GET_VOLUME_RATIO] = {
298         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_RATIO,
299         .arguments = get_volume_ratio_args,
300         .n_arguments = sizeof(get_volume_ratio_args) / sizeof(pa_dbus_arg_info),
301         .receive_cb = handle_get_volume_ratio },
302     [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
303         .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
304         .arguments = get_current_volume_type_args,
305         .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
306         .receive_cb = handle_get_current_volume_type },
307     [METHOD_HANDLER_GET_CURRENT_MEDIA_ROUTING_PATH] = {
308         .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_MEDIA_ROUTING_PATH,
309         .arguments = get_current_media_routing_path_args,
310         .n_arguments = sizeof(get_current_media_routing_path_args) / sizeof(pa_dbus_arg_info),
311         .receive_cb = handle_get_current_media_routing_path },
312     [METHOD_HANDLER_UPDATE_FOCUS_STATUS] = {
313         .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS,
314         .arguments = update_focus_status_args,
315         .n_arguments = sizeof(update_focus_status_args) / sizeof(pa_dbus_arg_info),
316         .receive_cb = handle_update_focus_status },
317     [METHOD_HANDLER_UPDATE_FOCUS_STATUS_BY_FOCUS_ID] = {
318         .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS_BY_FOCUS_ID,
319         .arguments = update_focus_status_by_focus_id_args,
320         .n_arguments = sizeof(update_focus_status_by_focus_id_args) / sizeof(pa_dbus_arg_info),
321         .receive_cb = handle_update_focus_status_by_focus_id },
322     [METHOD_HANDLER_UPDATE_RESTRICTION] = {
323         .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_RESTRICTION,
324         .arguments = update_restriction_args,
325         .n_arguments = sizeof(update_restriction_args) / sizeof(pa_dbus_arg_info),
326         .receive_cb = handle_update_restriction },
327     [METHOD_HANDLER_UPDATE_CALL_PARAMETERS] = {
328         .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_CALL_PARAMETERS,
329         .arguments = update_call_parameters_args,
330         .n_arguments = sizeof(update_call_parameters_args) / sizeof(pa_dbus_arg_info),
331         .receive_cb = handle_update_call_parameters },
332     [METHOD_HANDLER_SET_FILTER] = {
333         .method_name = STREAM_MANAGER_METHOD_NAME_SET_FILTER,
334         .arguments = set_filter_args,
335         .n_arguments = sizeof(set_filter_args) / sizeof(pa_dbus_arg_info),
336         .receive_cb = handle_set_filter },
337     [METHOD_HANDLER_UNSET_FILTER] = {
338         .method_name = STREAM_MANAGER_METHOD_NAME_UNSET_FILTER,
339         .arguments = unset_filter_args,
340         .n_arguments = sizeof(unset_filter_args) / sizeof(pa_dbus_arg_info),
341         .receive_cb = handle_unset_filter },
342     [METHOD_HANDLER_CONTROL_FILTER] = {
343         .method_name = STREAM_MANAGER_METHOD_NAME_CONTROL_FILTER,
344         .arguments = control_filter_args,
345         .n_arguments = sizeof(control_filter_args) / sizeof(pa_dbus_arg_info),
346         .receive_cb = handle_control_filter },
347     [METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID] = {
348         .method_name = STREAM_MANAGER_METHOD_NAME_CHECK_STREAM_EXIST_BY_PID,
349         .arguments = check_stream_exist_by_pid_args,
350         .n_arguments = sizeof(check_stream_exist_by_pid_args) / sizeof(pa_dbus_arg_info),
351         .receive_cb = handle_check_stream_exist_by_pid },
352     [METHOD_HANDLER_GET_PID_OF_LATEST_STREAM] = {
353         .method_name = STREAM_MANAGER_METHOD_NAME_GET_PID_OF_LATEST_STREAM,
354         .arguments = get_pid_of_latest_stream_args,
355         .n_arguments = sizeof(get_pid_of_latest_stream_args) / sizeof(pa_dbus_arg_info),
356         .receive_cb = handle_get_pid_of_latest_stream },
357     [METHOD_HANDLER_ACTIVATE_DUCKING] = {
358         .method_name = STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING,
359         .arguments = activate_ducking_args,
360         .n_arguments = sizeof(activate_ducking_args) / sizeof(pa_dbus_arg_info),
361         .receive_cb = handle_activate_ducking },
362     [METHOD_HANDLER_GET_DUCKING_STATE] = {
363         .method_name = STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE,
364         .arguments = get_ducking_state_args,
365         .n_arguments = sizeof(get_ducking_state_args) / sizeof(pa_dbus_arg_info),
366         .receive_cb = handle_get_ducking_state },
367     [METHOD_HANDLER_NAME_SET_REMOTE_PERMISSION] = {
368         .method_name = STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION,
369         .arguments = set_remote_permission_args,
370         .n_arguments = sizeof(set_remote_permission_args) / sizeof(pa_dbus_arg_info),
371         .receive_cb = handle_set_remote_permission },
372     [METHOD_HANDLER_DISCOVER_REMOTE_DEVICE] = {
373         .method_name = STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICE,
374         .arguments = discover_remote_device_args,
375         .n_arguments = sizeof(discover_remote_device_args) / sizeof(pa_dbus_arg_info),
376         .receive_cb = handle_discover_remote_device },
377     [METHOD_HANDLER_PUBLISH_LOCAL_DEVICE] = {
378         .method_name = STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE,
379         .arguments = publish_local_device_args,
380         .n_arguments = sizeof(publish_local_device_args) / sizeof(pa_dbus_arg_info),
381         .receive_cb = handle_publish_local_device },
382 };
383
384 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
385     const char *xml = STREAM_MGR_INTROSPECT_XML;
386     DBusMessage *r = NULL;
387
388     pa_assert(conn);
389     pa_assert(msg);
390     pa_assert(userdata);
391
392     pa_assert_se((r = dbus_message_new_method_return(msg)));
393     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
394
395     if (r) {
396         pa_assert_se(dbus_connection_send((conn), r, NULL));
397         dbus_message_unref(r);
398     }
399
400     return DBUS_HANDLER_RESULT_HANDLED;
401 }
402
403 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
404     stream_list list;
405     DBusMessage *reply = NULL;
406     DBusMessageIter msg_iter;
407     pa_stream_manager *m = (pa_stream_manager*)userdata;
408
409     pa_assert(conn);
410     pa_assert(msg);
411     pa_assert(m);
412
413     pa_assert_se(dbus_message_get_args(msg, NULL,
414                                        DBUS_TYPE_INVALID));
415     pa_log_info("get stream list");
416
417     memset(&list, 0, sizeof(stream_list));
418     pa_assert_se((reply = dbus_message_new_method_return(msg)));
419     dbus_message_iter_init_append(reply, &msg_iter);
420     if (!get_available_streams(m, &list)) {
421         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
422         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
423     } else {
424         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
425         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, NULL, 0);
426     }
427     pa_assert_se(dbus_connection_send(conn, reply, NULL));
428     dbus_message_unref(reply);
429 }
430
431 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
432     char *type;
433     stream_info_per_type info;
434     DBusMessage *reply = NULL;
435     DBusMessageIter msg_iter;
436     pa_stream_manager *m = (pa_stream_manager*)userdata;
437
438     pa_assert(conn);
439     pa_assert(msg);
440     pa_assert(m);
441
442     pa_assert_se(dbus_message_get_args(msg, NULL,
443                                        DBUS_TYPE_STRING, &type,
444                                        DBUS_TYPE_INVALID));
445     pa_log_info("type[%s]", type);
446
447     memset(&info, 0, sizeof(stream_info_per_type));
448     pa_assert_se((reply = dbus_message_new_method_return(msg)));
449     dbus_message_iter_init_append(reply, &msg_iter);
450     get_stream_info(m, type, &info);
451     pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
452     pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
453     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.volume_types, STREAM_DIRECTION_MAX);
454     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
455     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
456     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
457
458     pa_assert_se(dbus_connection_send(conn, reply, NULL));
459     dbus_message_unref(reply);
460 }
461
462 static bool check_all_requested_devices_connected(pa_stream_manager *m, uint32_t *device_list, uint32_t length) {
463     pa_idxset *dm_device_list;
464     uint32_t found_count = 0;
465     uint32_t i = 0;
466
467     pa_assert(m);
468     pa_assert(device_list);
469
470     dm_device_list = pa_device_manager_get_device_list(m->dm);
471
472     for (i = 0; i < length; i++) {
473         pa_tz_device *dm_device;
474         uint32_t dm_device_id;
475         uint32_t idx = 0;
476
477         PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
478             dm_device_id = pa_tz_device_get_id(dm_device);
479             if (device_list[i] == dm_device_id) {
480                 pa_log_debug("device[%u] is connected", dm_device_id);
481                 found_count++;
482                 if (length == found_count)
483                     return true;
484                 break;
485             }
486         }
487     }
488
489   return false;
490 }
491
492 static ret_msg_t update_devices_and_trigger_routing(pa_stream_manager *m, stream_parent *sp, stream_type_t type) {
493     void *stream = NULL;
494     pa_idxset *idx_streams = NULL;
495     uint32_t idx = 0;
496     void *cur_highest_priority_stream = NULL;
497     stream_route_type_t route_type = STREAM_ROUTE_TYPE_DEFAULT;
498     ret_msg_t ret = RET_MSG_OK;
499
500     pa_assert(m);
501     pa_assert(sp);
502
503     if (type == STREAM_SINK_INPUT) {
504         idx_streams = sp->idx_sink_inputs;
505         cur_highest_priority_stream = (void*)m->cur_highest_priority.sink_input;
506     } else {
507         idx_streams = sp->idx_source_outputs;
508         cur_highest_priority_stream = (void*)m->cur_highest_priority.source_output;
509     }
510
511     /* update route type of this stream parent */
512     if (sp->route_type == STREAM_ROUTE_TYPE_DEFAULT) {
513         PA_IDXSET_FOREACH(stream, idx_streams, idx) {
514             /* find route type of stream */
515             if (get_route_type(stream, type, false, &route_type))
516                 return RET_MSG_ERROR_INTERNAL;
517
518             if (route_type == STREAM_ROUTE_TYPE_MANUAL ||
519                 route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
520                 sp->route_type = route_type;
521                 pa_log_info(" -- the route type is [%d]", route_type);
522             } else {
523                 pa_log_error(" -- the route type is not valid[%d]", route_type);
524                 return RET_MSG_ERROR_POLICY;
525             }
526         }
527     }
528
529     /* if any stream that belongs to this id has been activated, do notify right away */
530     if (sp->route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
531         PA_IDXSET_FOREACH(stream, idx_streams, idx) {
532             pa_log_debug(" -- stream->index[%u] belongs to this stream parent[%p], do notify for the select proper source",
533                         GET_STREAM_INDEX(stream, type), sp);
534             ret = do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, false, stream);
535         }
536     } else {
537         /* trigger only when it occupies routing path */
538         if (cur_highest_priority_stream && pa_idxset_get_by_data(idx_streams, cur_highest_priority_stream, NULL)) {
539             pa_log_debug(" -- cur_highest_priority_stream->index[%u] belongs to this stream_parent[%p], do notify for the route change",
540                         GET_STREAM_INDEX(cur_highest_priority_stream, type), sp);
541             ret = do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, false, cur_highest_priority_stream);
542             if (!ret && is_stream_related_call_active_routing(PA_OBJECT(cur_highest_priority_stream)) && m->on_call) {
543                 pa_log_info("set active device for new call route device");
544                 change_active_route_for_call(m, PA_OBJECT(cur_highest_priority_stream), false);
545             }
546         }
547     }
548
549     return ret;
550 }
551
552 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
553     uint32_t id = 0;
554     int i = 0;
555     uint32_t *in_device_list = NULL;
556     uint32_t *out_device_list = NULL;
557     int list_len_in = 0;
558     int list_len_out = 0;
559     stream_parent *sp = NULL;
560     DBusMessage *reply = NULL;
561     pa_stream_manager *m = (pa_stream_manager*)userdata;
562     ret_msg_t ret = RET_MSG_OK;
563
564     pa_assert(conn);
565     pa_assert(msg);
566     pa_assert(m);
567
568     pa_assert_se(dbus_message_get_args(msg, NULL,
569                                        DBUS_TYPE_UINT32, &id,
570                                        DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &in_device_list, &list_len_in,
571                                        DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &out_device_list, &list_len_out,
572                                        DBUS_TYPE_INVALID));
573     pa_log_info("id[%u], in_device_list[%p]:length[%d], out_device_list[%p]:length[%d]",
574         id, in_device_list, list_len_in, out_device_list, list_len_out);
575
576     pa_assert_se((reply = dbus_message_new_method_return(msg)));
577
578     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
579     if (!sp) {
580         pa_log_error("could not find matching client for this parent_id[%u]", id);
581         ret = RET_MSG_ERROR_INTERNAL;
582         goto finish;
583     }
584     if (!in_device_list && !out_device_list) {
585         pa_log_error("invalid arguments");
586         ret = RET_MSG_ERROR_INVALID_ARGUMENT;
587         goto finish;
588     }
589     if (!sp->idx_route_in_devices || !sp->idx_route_out_devices) {
590         pa_log_error("failed to update, idx_route_in_devices[%p], idx_route_out_devices[%p]",
591                      sp->idx_route_in_devices, sp->idx_route_out_devices);
592         ret = RET_MSG_ERROR_INTERNAL;
593         goto finish;
594     }
595
596     /* check if all the requested devices are connected now */
597     if (in_device_list && !check_all_requested_devices_connected(m, in_device_list, list_len_in)) {
598         pa_log_error("could not find requested in-devices");
599         ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
600         goto finish;
601     }
602     if (out_device_list && !check_all_requested_devices_connected(m, out_device_list, list_len_out)) {
603         pa_log_error("could not find requested out-devices");
604         ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
605         goto finish;
606     }
607
608     pa_idxset_remove_all(sp->idx_route_in_devices, pa_xfree);
609     if (in_device_list && list_len_in) {
610         for (i = 0; i < list_len_in; i++) {
611             pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(uint32_t)), NULL);
612             pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
613         }
614     }
615     if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SOURCE_OUTPUT)))
616         goto finish;
617
618     pa_idxset_remove_all(sp->idx_route_out_devices, pa_xfree);
619     if (out_device_list && list_len_out) {
620         for (i = 0; i < list_len_out; i++) {
621             pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(uint32_t)), NULL);
622             pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
623         }
624     }
625     if ((ret = update_devices_and_trigger_routing(m, sp, STREAM_SINK_INPUT)))
626         goto finish;
627
628 finish:
629     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
630     pa_assert_se(dbus_connection_send(conn, reply, NULL));
631     dbus_message_unref(reply);
632 }
633
634 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
635     uint32_t id = 0;
636     const char *name = NULL;
637     int32_t value = 0;
638     bool updated = false;
639     stream_parent *sp = NULL;
640     stream_route_option route_option;
641     DBusMessage *reply = NULL;
642     pa_stream_manager *m = (pa_stream_manager*)userdata;
643
644     pa_assert(conn);
645     pa_assert(msg);
646     pa_assert(m);
647
648     pa_assert_se(dbus_message_get_args(msg, NULL,
649                                        DBUS_TYPE_UINT32, &id,
650                                        DBUS_TYPE_STRING, &name,
651                                        DBUS_TYPE_INT32, &value,
652                                        DBUS_TYPE_INVALID));
653     pa_log_info("name[%s], value[%d]", name, value);
654
655     pa_assert_se((reply = dbus_message_new_method_return(msg)));
656
657     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
658     if (sp) {
659         if (name) {
660             route_option.name = name;
661             route_option.value = value;
662
663             /* if any stream that belongs to this id has been activated, do notify right away */
664             if (m->cur_highest_priority.sink_input) {
665                 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
666                     pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
667                         (m->cur_highest_priority.sink_input)->index, id);
668                     do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
669                     updated = true;
670                 }
671             }
672             if (m->cur_highest_priority.source_output) {
673                 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
674                     pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
675                         (m->cur_highest_priority.source_output)->index, id);
676                     do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SOURCE_OUTPUT, false, &route_option);
677                     updated = true;
678                 }
679             }
680             if (!updated) {
681                 pa_log_error("invalid state");
682                 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
683             } else
684                 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
685         } else {
686             pa_log_error("invalid arguments");
687             pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT], DBUS_TYPE_INVALID));
688         }
689
690     } else {
691         pa_log_error("could not find matching client for this parent_id[%u]", id);
692         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
693     }
694
695     pa_assert_se(dbus_connection_send(conn, reply, NULL));
696     dbus_message_unref(reply);
697 }
698
699 static int get_device_for_preference(pa_stream_manager *m, stream_parent *sp, stream_direction_t direction, uint32_t device_id, pa_tz_device **device) {
700     pa_assert(m);
701     pa_assert(sp);
702     pa_assert(device);
703
704     if (device_id == 0) {
705         /* get a device of default role from previous device type */
706         if (!(*device = pa_device_manager_get_device(m->dm, sp->preferred_device.types[direction], NULL))) {
707             pa_log_error("could not get device[%s]", sp->preferred_device.types[direction]);
708             return -1;
709         }
710         pa_log_debug("unset preferred device, rollback to type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
711     } else {
712         /* get the device of device id */
713         if (!(*device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
714             pa_log_error("could not get device by id[%u]", device_id);
715             return -1;
716         }
717         pa_log_debug("requested preferred device type(%s), id(%u)", pa_tz_device_get_type(*device), pa_tz_device_get_id(*device));
718     }
719
720     return 0;
721 }
722
723 static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
724     const char *device_direction = NULL;
725     uint32_t sp_id = 0;
726     uint32_t device_id = 0;
727     uint32_t idx;
728     uint32_t count = 0;
729     stream_direction_t direction;
730     pa_tz_device *device;
731     pa_tz_device *prev_device;
732     const char *device_role;
733     const char *prev_device_type;
734     const char *prev_device_role;
735     stream_parent *sp = NULL;
736     void *stream;
737     pa_idxset *streams;
738     pa_proplist *props;
739     pa_proplist *device_props;
740     uint32_t stream_index;
741     pa_hashmap *devices;
742     void *new_device = NULL;
743     ret_msg_t ret = RET_MSG_OK;
744     DBusMessage *reply = NULL;
745
746     pa_stream_manager *m = (pa_stream_manager*)userdata;
747
748     pa_assert(conn);
749     pa_assert(msg);
750     pa_assert(m);
751
752     pa_assert_se(dbus_message_get_args(msg, NULL,
753                                        DBUS_TYPE_UINT32, &sp_id,
754                                        DBUS_TYPE_STRING, &device_direction,
755                                        DBUS_TYPE_UINT32, &device_id,
756                                        DBUS_TYPE_INVALID));
757     pa_log_info("stream parent id[%u], device direction[%s], device_id[%u]", sp_id, device_direction, device_id);
758
759     pa_assert_se((reply = dbus_message_new_method_return(msg)));
760
761     if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
762         pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
763         ret = RET_MSG_ERROR_INTERNAL;
764         goto finish;
765     }
766
767     if (pa_safe_streq(device_direction, "in"))
768         direction = STREAM_DIRECTION_IN;
769     else if (pa_safe_streq(device_direction, "out"))
770         direction = STREAM_DIRECTION_OUT;
771     else {
772         ret = RET_MSG_ERROR_INVALID_ARGUMENT;
773         goto finish;
774     }
775
776     /* allow only auto routing type */
777     if (sp->route_type != STREAM_ROUTE_TYPE_AUTO &&
778         sp->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
779         pa_log_error("not allowed this route type[%d] of this parent_id[%u]", sp->route_type, sp_id);
780         ret = RET_MSG_ERROR_POLICY;
781         goto finish;
782     }
783
784     if (device_id == 0 && !sp->preferred_device.types[direction]) {
785         pa_log_debug("it is already unset");
786         goto finish;
787     }
788
789     if (get_device_for_preference(m, sp, direction, device_id, &device) < 0) {
790         ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
791         goto finish;
792     }
793
794     /* only allow built-in device types */
795     if (!device_type_is_builtin(device->type)) {
796         pa_log_error("This device(id:%u, type:%s) is not built-in type", device_id, device->type);
797         ret = RET_MSG_ERROR_POLICY;
798         goto finish;
799     }
800
801     /* get default role of the device */
802     device_role = pa_tz_device_get_role(device, NULL);
803
804     sp->preferred_device.types[direction] = (device_id == 0) ? NULL : device->type;
805     sp->preferred_device.roles[direction] = (device_id == 0) ? NULL : device_role;
806
807     pa_log_info("preferred device role is set to [%s] of device type[%s], direction[%s]",
808             sp->preferred_device.roles[direction], device->type, direction == STREAM_DIRECTION_OUT ? "out" :  "in");
809
810     streams = (direction == STREAM_DIRECTION_OUT) ? sp->idx_sink_inputs : sp->idx_source_outputs;
811     devices = (direction == STREAM_DIRECTION_OUT) ? device->playback_devices : device->capture_devices;
812
813     count = pa_idxset_size(streams);
814     PA_IDXSET_FOREACH(stream, streams, idx) {
815         props = GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ?
816                         STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT);
817         pa_log_info("stream index(%u), props %p", (direction == STREAM_DIRECTION_OUT) ? PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index, props);
818         device_props = (direction == STREAM_DIRECTION_OUT) ?
819                         PA_SINK_INPUT(stream)->sink->proplist : PA_SOURCE_OUTPUT(stream)->source->proplist;
820         stream_index = (direction == STREAM_DIRECTION_OUT) ?
821                         PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index;
822
823         if (device_id == 0)
824             pa_proplist_unset(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
825         else
826             pa_proplist_sets(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE, device_role);
827
828         prev_device_type = pa_proplist_gets(props, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
829         prev_device_role = pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE);
830
831         if (pa_safe_streq(prev_device_type, device->type)) {
832             /* If the request is for the same device type,
833              * new device role should be applied - move streams. */
834             if (!pa_safe_streq(prev_device_role, device_role)) {
835                 new_device = pa_hashmap_get(devices, device_role);
836                 pa_log_debug("move stream[%u]: [%s][%s -> %s]",
837                         stream_index, prev_device_type, prev_device_role, device_role);
838             }
839         } else {
840             /* If the request is for a different device type,
841              * check the previous device role and move streams to default role if needed. */
842             if ((prev_device = pa_device_manager_get_device(m->dm, prev_device_type, NULL)))
843                 new_device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
844                                         prev_device->playback_devices : prev_device->capture_devices);
845             if (new_device) {
846                 device_props = (direction == STREAM_DIRECTION_OUT) ? PA_SINK(new_device)->proplist : PA_SOURCE(new_device)->proplist;
847                 pa_log_debug("may move stream[%u] to default role: [%s][%s -> %s]",
848                         stream_index, prev_device_type, prev_device_role, pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE));
849             }
850         }
851         if (new_device)
852             (direction == STREAM_DIRECTION_OUT) ? pa_sink_input_move_to(stream, PA_SINK(new_device), false) :
853                                                 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
854
855         if (count == 1)
856         /* Use PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED here.
857          * It's not about the focus change, but this command exactly does what is needed here
858          * including updating the highest priority, find the next stream to be set to HAL as well as
859          * change the state of the builtin-device that use internal codec. */
860             process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
861                             PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
862         count--;
863     }
864
865 finish:
866     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
867     pa_assert_se(dbus_connection_send(conn, reply, NULL));
868     dbus_message_unref(reply);
869 }
870
871 static void handle_get_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
872     stream_parent *sp = NULL;
873     uint32_t sp_id = 0;
874     uint32_t in_device_id = 0;
875     uint32_t out_device_id = 0;
876     const char *pref_in_type, *pref_out_type;
877     const char *pref_in_role, *pref_out_role;
878     pa_idxset *dm_device_list;
879     pa_tz_device *dm_device;
880     dm_device_direction_t dm_direction;
881     uint32_t idx = 0;
882     ret_msg_t ret = RET_MSG_OK;
883     DBusMessage *reply = NULL;
884
885     pa_stream_manager *m = (pa_stream_manager*)userdata;
886
887     pa_assert(conn);
888     pa_assert(msg);
889     pa_assert(m);
890
891     pa_assert_se(dbus_message_get_args(msg, NULL,
892                                        DBUS_TYPE_UINT32, &sp_id,
893                                        DBUS_TYPE_INVALID));
894     pa_log_info("stream parent id[%u]", sp_id);
895
896     pa_assert_se((reply = dbus_message_new_method_return(msg)));
897
898     if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
899         pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
900         ret = RET_MSG_ERROR_INTERNAL;
901         goto finish;
902     }
903
904     pref_in_type = sp->preferred_device.types[STREAM_DIRECTION_IN];
905     pref_in_role = sp->preferred_device.roles[STREAM_DIRECTION_IN];
906     pref_out_type = sp->preferred_device.types[STREAM_DIRECTION_OUT];
907     pref_out_role = sp->preferred_device.roles[STREAM_DIRECTION_OUT];
908
909     /* get device ids of preferred in/out device respectively */
910     dm_device_list = pa_device_manager_get_device_list(m->dm);
911     PA_IDXSET_FOREACH(dm_device, dm_device_list, idx) {
912         dm_direction = pa_tz_device_get_direction(dm_device);
913         if (!in_device_id && dm_direction & DM_DEVICE_DIRECTION_IN) {
914             if (pa_safe_streq(pref_in_type, pa_tz_device_get_type(dm_device))) {
915                 if (pa_safe_streq(pref_in_role, pa_tz_device_get_role(dm_device, pref_in_role)))
916                     in_device_id = pa_tz_device_get_id(dm_device);
917             }
918         }
919         if (!out_device_id && dm_direction & DM_DEVICE_DIRECTION_OUT) {
920             if (pa_safe_streq(pref_out_type, pa_tz_device_get_type(dm_device))) {
921                 if (pa_safe_streq(pref_out_role, pa_tz_device_get_role(dm_device, pref_out_role)))
922                     out_device_id = pa_tz_device_get_id(dm_device);
923             }
924         }
925     }
926
927     pa_log_info("preferred  IN device: type[%s] role[%s] id[%u]",  pref_in_type, pref_in_role, in_device_id);
928     pa_log_info("preferred  OUT device: type[%s] role[%s] id[%u]", pref_out_type, pref_out_role, out_device_id);
929
930 finish:
931     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id, DBUS_TYPE_INVALID));
932     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &out_device_id, DBUS_TYPE_INVALID));
933     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
934     pa_assert_se(dbus_connection_send(conn, reply, NULL));
935     dbus_message_unref(reply);
936 }
937
938 static uint32_t get_num_of_target_streams(pa_stream_manager *m, pa_idxset *streams, stream_direction_t direction, const char *role) {
939     void *s;
940     const char *_role;
941     uint32_t idx;
942     uint32_t count = 0;
943
944     pa_assert(m);
945     pa_assert(streams);
946     pa_assert(role);
947
948     PA_IDXSET_FOREACH(s, streams, idx) {
949         _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
950                                  PA_SINK_INPUT(s)->proplist : PA_SOURCE_OUTPUT(s)->proplist, PA_PROP_MEDIA_ROLE);
951         if (pa_safe_streq(_role, role))
952             count++;
953     }
954     return count;
955 }
956
957 static void routing_process_to_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
958     void *stream;
959     void *device = NULL;
960     const char *_role;
961     uint32_t count = 0;
962     uint32_t idx;
963
964     pa_assert(m);
965     pa_assert(role);
966     pa_assert(tz_device);
967
968     count = get_num_of_target_streams(m, (direction == STREAM_DIRECTION_OUT) ?
969                                       m->core->sink_inputs : m->core->source_outputs,
970                                       direction, role);
971     PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
972         _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
973                                  PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
974         if (!pa_safe_streq(_role, role))
975             continue;
976
977         /* move stream to the preemptive device */
978         device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
979                                 tz_device->playback_devices : tz_device->capture_devices);
980         if (direction == STREAM_DIRECTION_OUT) {
981             pa_sink_input_move_to(stream, PA_SINK(device), false);
982             pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT),
983                              PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
984         } else {
985             pa_source_output_move_to(stream, PA_SOURCE(device), false);
986             pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT),
987                              PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, tz_device->type);
988         }
989
990         /* change routing */
991         if (--count == 0) {
992             process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
993                            PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
994         }
995     }
996 }
997
998 static void rollback_process_from_preemptive_device(pa_stream_manager *m, stream_direction_t direction, const char *role, pa_tz_device *tz_device) {
999     void *device;
1000     void *stream;
1001     void *new_device;
1002     uint32_t idx;
1003     uint32_t count = 0;
1004     const char *active_device = NULL;
1005     const char *_role;
1006
1007     pa_assert(m);
1008     pa_assert(role);
1009     pa_assert(tz_device);
1010
1011     device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
1012                               tz_device->playback_devices : tz_device->capture_devices);
1013
1014     PA_IDXSET_FOREACH(stream, (direction == STREAM_DIRECTION_OUT) ? PA_SINK(device)->inputs : PA_SOURCE(device)->outputs, idx) {
1015         _role = pa_proplist_gets((direction == STREAM_DIRECTION_OUT) ?
1016                                  PA_SINK_INPUT(stream)->proplist : PA_SOURCE_OUTPUT(stream)->proplist, PA_PROP_MEDIA_ROLE);
1017         if (!pa_safe_streq(_role, role))
1018             continue;
1019
1020         if (count++ == 0) {
1021             /* find and set new device */
1022             do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
1023                      (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
1024                      false, stream);
1025             new_device = (direction == STREAM_DIRECTION_OUT) ? (void*)(PA_SINK_INPUT(stream)->sink) :
1026                                                                (void*)(PA_SOURCE_OUTPUT(stream)->source);
1027             active_device = pa_proplist_gets(GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT),
1028                                                                  PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
1029             /* change routing */
1030             process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
1031                            PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1032
1033             if (direction == STREAM_DIRECTION_OUT)
1034                 pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1035             else
1036                 pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1037
1038             continue;
1039         }
1040
1041         /* move stream to the new device */
1042         if (direction == STREAM_DIRECTION_OUT) {
1043             pa_sink_input_move_to(stream, PA_SINK(new_device), false);
1044             if (active_device)
1045                 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1046         } else {
1047             pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
1048             if (active_device)
1049                 pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_device);
1050         }
1051     }
1052 }
1053
1054 static void handle_set_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1055     const char *stream_type = NULL;
1056     const char *device_direction = NULL;
1057     stream_direction_t direction;
1058     uint32_t device_id = 0;
1059     stream_info *s = NULL;
1060     pa_tz_device *device = NULL;
1061     char *device_type = NULL;
1062     const char *prev_device_type = NULL;
1063     uint32_t prev_device_id = 0;
1064     uint32_t idx;
1065     bool found = false;
1066     ret_msg_t ret = RET_MSG_OK;
1067     DBusMessage *reply = NULL;
1068
1069     pa_stream_manager *m = (pa_stream_manager*)userdata;
1070
1071     pa_assert(conn);
1072     pa_assert(msg);
1073     pa_assert(m);
1074
1075     pa_assert_se(dbus_message_get_args(msg, NULL,
1076                                        DBUS_TYPE_STRING, &stream_type,
1077                                        DBUS_TYPE_STRING, &device_direction,
1078                                        DBUS_TYPE_UINT32, &device_id,
1079                                        DBUS_TYPE_INVALID));
1080     pa_log_info("stream type[%s], device direction[%s], device_id[%u]", stream_type, device_direction, device_id);
1081
1082     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1083
1084     if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1085         pa_log_error("could not find this stream type(%s)", stream_type);
1086         ret = RET_MSG_ERROR_INTERNAL;
1087         goto finish;
1088     }
1089
1090     if (pa_safe_streq(device_direction, "in"))
1091         direction = STREAM_DIRECTION_IN;
1092     else if (pa_safe_streq(device_direction, "out"))
1093         direction = STREAM_DIRECTION_OUT;
1094     else {
1095         ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1096         goto finish;
1097     }
1098
1099     /* allow only auto routing type */
1100     if (s->route_type != STREAM_ROUTE_TYPE_AUTO &&
1101         s->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1102         pa_log_error("not allowed this route type[%d]", s->route_type);
1103         ret = RET_MSG_ERROR_POLICY;
1104         goto finish;
1105     }
1106
1107     if (device_id > 0) {
1108         if (!(device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
1109             pa_log_error("could not get device by id[%u]", device_id);
1110             ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1111             goto finish;
1112         }
1113
1114         PA_IDXSET_FOREACH(device_type, (direction == STREAM_DIRECTION_OUT) ? s->idx_avail_out_devices : s->idx_avail_in_devices, idx) {
1115             if (pa_safe_streq(device_type, device->type)) {
1116                 found = true;
1117                 break;
1118             }
1119         }
1120         if (!found) {
1121             pa_log_error("not supported this device type[%s]", device->type);
1122             ret = RET_MSG_ERROR_INVALID_ARGUMENT;
1123             goto finish;
1124         }
1125     }
1126
1127     if (device_id == 0 && s->preemptive_device[direction].id == 0) {
1128         pa_log_debug("there's no preemptive device, nothing to do");
1129         goto finish;
1130     }
1131
1132     prev_device_type = s->preemptive_device[direction].type;
1133     prev_device_id = s->preemptive_device[direction].id;
1134     s->preemptive_device[direction].type = device_id > 0 ? device->type : NULL;
1135     s->preemptive_device[direction].id = device_id;
1136
1137     pa_log_info("preemptive [%s] device is set, [%s, id:%u]",
1138                 direction == STREAM_DIRECTION_OUT ? "out" :  "in",
1139                 device_id > 0 ? device->type : NULL,
1140                 device_id);
1141
1142     /* move streams and change routing */
1143     if (device_id == 0) {
1144         if (!(device = pa_device_manager_get_device_by_id(m->dm, prev_device_id)) || !pa_safe_streq(device->type, prev_device_type)) {
1145             pa_log_debug("could not find the previous device of id[%u], type[%s], nothing to do.", prev_device_id, prev_device_type);
1146             goto finish;
1147         }
1148         rollback_process_from_preemptive_device(m, direction, stream_type, device);
1149     } else {
1150         routing_process_to_preemptive_device(m, direction, stream_type, device);
1151     }
1152
1153 finish:
1154     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1155     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1156     dbus_message_unref(reply);
1157 }
1158
1159 static void handle_get_stream_preemptive_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1160     const char *stream_type = NULL;
1161     stream_info *s = NULL;
1162     uint32_t in_device_id = 0;
1163     uint32_t out_device_id = 0;
1164     const char *in_device_type;
1165     const char *out_device_type;
1166     ret_msg_t ret = RET_MSG_OK;
1167     DBusMessage *reply = NULL;
1168
1169     pa_stream_manager *m = (pa_stream_manager*)userdata;
1170
1171     pa_assert(conn);
1172     pa_assert(msg);
1173     pa_assert(m);
1174
1175     pa_assert_se(dbus_message_get_args(msg, NULL,
1176                                        DBUS_TYPE_STRING, &stream_type,
1177                                        DBUS_TYPE_INVALID));
1178     pa_log_info("stream type[%s]", stream_type);
1179
1180     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1181
1182     if ((s = pa_hashmap_get(m->stream_infos, stream_type)) == NULL) {
1183         pa_log_error("could not find this stream type(%s)", stream_type);
1184         ret = RET_MSG_ERROR_INTERNAL;
1185         goto finish;
1186     }
1187
1188     in_device_id = s->preemptive_device[STREAM_DIRECTION_IN].id;
1189     in_device_type = s->preemptive_device[STREAM_DIRECTION_IN].type;
1190     out_device_id = s->preemptive_device[STREAM_DIRECTION_OUT].id;
1191     out_device_type = s->preemptive_device[STREAM_DIRECTION_OUT].type;
1192
1193     pa_log_info("preemptive IN device: type[%s] id[%u]", in_device_type, in_device_id);
1194     pa_log_info("preemptive OUT device: type[%s] id[%u]", out_device_type, out_device_id);
1195
1196 finish:
1197     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &in_device_id, DBUS_TYPE_INVALID));
1198     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &out_device_id, DBUS_TYPE_INVALID));
1199     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1200     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1201     dbus_message_unref(reply);
1202 }
1203
1204 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1205     const char *direction = NULL;
1206     const char *type = NULL;
1207     uint32_t level = 0;
1208     stream_type_t stream_type = STREAM_SINK_INPUT;
1209     DBusMessage *reply = NULL;
1210     pa_stream_manager *m = (pa_stream_manager*)userdata;
1211     int ret = 0;
1212     ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1213
1214     pa_assert(conn);
1215     pa_assert(msg);
1216     pa_assert(m);
1217
1218     pa_assert_se(dbus_message_get_args(msg, NULL,
1219                                        DBUS_TYPE_STRING, &direction,
1220                                        DBUS_TYPE_STRING, &type,
1221                                        DBUS_TYPE_UINT32, &level,
1222                                        DBUS_TYPE_INVALID));
1223     pa_log_info("direction[%s], type[%s], level[%u]", direction, type, level);
1224
1225     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1226
1227     if (pa_safe_streq(direction, "in"))
1228         stream_type = STREAM_SOURCE_OUTPUT;
1229     else if (pa_safe_streq(direction, "out"))
1230         stream_type = STREAM_SINK_INPUT;
1231     else {
1232         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1233         ret = -1;
1234         goto finish;
1235     }
1236
1237     /* check vconf update here, volume will not be set if update fails */
1238     if ((ret = update_volume_vconf(type, level))) {
1239         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1240         goto finish;
1241     }
1242
1243     if ((ret = set_volume_level_by_type(m, stream_type, type, level))) {
1244         if (ret == -2)
1245             ret_msg = RET_MSG_ERROR_INVALID_ARGUMENT;
1246         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1247     } else {
1248         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1249     }
1250
1251 finish:
1252     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1253     dbus_message_unref(reply);
1254
1255     if (!ret)
1256         send_volume_changed_signal(conn, direction, type, level);
1257 }
1258
1259 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1260     const char *direction = NULL;
1261     const char *type = NULL;
1262     uint32_t level = 0;
1263     stream_type_t stream_type = STREAM_SINK_INPUT;
1264     DBusMessage *reply = NULL;
1265     pa_stream_manager *m = (pa_stream_manager*)userdata;
1266
1267     pa_assert(conn);
1268     pa_assert(msg);
1269     pa_assert(m);
1270
1271     pa_assert_se(dbus_message_get_args(msg, NULL,
1272                                        DBUS_TYPE_STRING, &direction,
1273                                        DBUS_TYPE_STRING, &type,
1274                                        DBUS_TYPE_INVALID));
1275     pa_log_info("direction[%s], type[%s]", direction, type);
1276
1277     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1278
1279     if (pa_safe_streq(direction, "in"))
1280         stream_type = STREAM_SOURCE_OUTPUT;
1281     else if (pa_safe_streq(direction, "out"))
1282         stream_type = STREAM_SINK_INPUT;
1283     else {
1284         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1285         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1286         goto finish;
1287     }
1288
1289     if (get_volume_level_by_type(m, GET_VOLUME_CURRENT_LEVEL, stream_type, type, &level)) {
1290         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1291         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1292     } else {
1293         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1294         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1295     }
1296
1297 finish:
1298     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1299     dbus_message_unref(reply);
1300 }
1301
1302 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1303     const char *direction = NULL;
1304     const char *type = NULL;
1305     uint32_t level = 0;
1306     stream_type_t stream_type = STREAM_SINK_INPUT;
1307     DBusMessage *reply = NULL;
1308     pa_stream_manager *m = (pa_stream_manager*)userdata;
1309
1310     pa_assert(conn);
1311     pa_assert(msg);
1312     pa_assert(m);
1313
1314     pa_assert_se(dbus_message_get_args(msg, NULL,
1315                                        DBUS_TYPE_STRING, &direction,
1316                                        DBUS_TYPE_STRING, &type,
1317                                        DBUS_TYPE_INVALID));
1318     pa_log_info("direction[%s], type[%s]", direction, type);
1319
1320     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1321
1322     if (pa_safe_streq(direction, "in"))
1323         stream_type = STREAM_SOURCE_OUTPUT;
1324     else if (pa_safe_streq(direction, "out"))
1325         stream_type = STREAM_SINK_INPUT;
1326     else {
1327         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1328         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1329         goto finish;
1330     }
1331
1332     if (get_volume_level_by_type(m, GET_VOLUME_MAX_LEVEL, stream_type, type, &level)) {
1333         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1334         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1335     } else {
1336         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
1337         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1338     }
1339 finish:
1340     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1341     dbus_message_unref(reply);
1342 }
1343
1344 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1345     const char *direction = NULL;
1346     const char *type = NULL;
1347     uint32_t do_mute = 0;
1348     stream_type_t stream_type = STREAM_SINK_INPUT;
1349     DBusMessage *reply = NULL;
1350     pa_stream_manager *m = (pa_stream_manager*)userdata;
1351     int ret = 0;
1352
1353     pa_assert(conn);
1354     pa_assert(msg);
1355     pa_assert(m);
1356
1357     pa_assert_se(dbus_message_get_args(msg, NULL,
1358                                        DBUS_TYPE_STRING, &direction,
1359                                        DBUS_TYPE_STRING, &type,
1360                                        DBUS_TYPE_UINT32, &do_mute,
1361                                        DBUS_TYPE_INVALID));
1362     pa_log_info("direction[%s], type[%s], do_mute[%u]", direction, type, do_mute);
1363
1364     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1365
1366     if (pa_safe_streq(direction, "in"))
1367         stream_type = STREAM_SOURCE_OUTPUT;
1368     else if (pa_safe_streq(direction, "out"))
1369         stream_type = STREAM_SINK_INPUT;
1370     else {
1371         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1372         goto finish;
1373     }
1374
1375     /* check vconf update here, mute will not be set if update fails */
1376     if ((ret = update_mute_vconf(type, do_mute))) {
1377         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1378         goto finish;
1379     }
1380
1381     if (set_volume_mute_by_type(m, stream_type, type, (bool)do_mute))
1382         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1383     else
1384         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1385
1386 finish:
1387     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1388     dbus_message_unref(reply);
1389 }
1390
1391 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1392     const char *direction = NULL;
1393     const char *type = NULL;
1394     uint32_t is_muted = 0;
1395     stream_type_t stream_type = STREAM_SINK_INPUT;
1396     DBusMessage *reply = NULL;
1397     pa_stream_manager *m = (pa_stream_manager*)userdata;
1398
1399     pa_assert(conn);
1400     pa_assert(msg);
1401     pa_assert(m);
1402
1403     pa_assert_se(dbus_message_get_args(msg, NULL,
1404                                        DBUS_TYPE_STRING, &direction,
1405                                        DBUS_TYPE_STRING, &type,
1406                                        DBUS_TYPE_INVALID));
1407     pa_log_info("direction[%s], type[%s]", direction, type);
1408
1409     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1410
1411     if (pa_safe_streq(direction, "in"))
1412         stream_type = STREAM_SOURCE_OUTPUT;
1413     else if (pa_safe_streq(direction, "out"))
1414         stream_type = STREAM_SINK_INPUT;
1415     else {
1416         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1417         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1418         goto fail;
1419     }
1420
1421     if (get_volume_mute_by_type(m, stream_type, type, (bool*)&is_muted)) {
1422         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1423         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1424     } else {
1425         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1426         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1427     }
1428
1429 fail:
1430     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1431     dbus_message_unref(reply);
1432 }
1433
1434 static void handle_set_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1435     const char *direction = NULL;
1436     uint32_t idx;
1437     double ratio;
1438     stream_type_t stream_type = STREAM_SINK_INPUT;
1439     DBusMessage *reply = NULL;
1440     pa_stream_manager *m = (pa_stream_manager*)userdata;
1441     int ret = 0;
1442     ret_msg_t ret_msg = RET_MSG_ERROR_INTERNAL;
1443
1444     pa_assert(conn);
1445     pa_assert(msg);
1446     pa_assert(m);
1447
1448     pa_assert_se(dbus_message_get_args(msg, NULL,
1449                                        DBUS_TYPE_STRING, &direction,
1450                                        DBUS_TYPE_UINT32, &idx,
1451                                        DBUS_TYPE_DOUBLE, &ratio,
1452                                        DBUS_TYPE_INVALID));
1453     pa_log_info("direction[%s], idx[%u], ratio[%f]", direction, idx, ratio);
1454
1455     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1456
1457     if (pa_safe_streq(direction, "in"))
1458         stream_type = STREAM_SOURCE_OUTPUT;
1459     else if (pa_safe_streq(direction, "out"))
1460         stream_type = STREAM_SINK_INPUT;
1461     else {
1462         pa_log_error("invalid direction[%s]", direction);
1463         goto invalid_argument;
1464     }
1465
1466     /* Check the ratio range (0.0 ~ 1.0) */
1467     if (ratio < 0 || ratio > 1) {
1468         pa_log_error("invalid range, ratio[%f]", ratio);
1469         goto invalid_argument;
1470     }
1471
1472     if ((ret = set_volume_ratio_by_idx(m, stream_type, idx, ratio))) {
1473         if (ret == -2)
1474             ret_msg = RET_MSG_ERROR_NO_STREAM;
1475         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
1476     } else {
1477         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1478     }
1479
1480     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1481     dbus_message_unref(reply);
1482     return;
1483
1484 invalid_argument:
1485     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
1486                      DBUS_TYPE_INVALID));
1487     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1488     dbus_message_unref(reply);
1489 }
1490
1491 static void handle_get_volume_ratio(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1492     const char *direction = NULL;
1493     uint32_t idx = 0;
1494     double ratio;
1495     stream_type_t stream_type = STREAM_SINK_INPUT;
1496     DBusMessage *reply = NULL;
1497     pa_stream_manager *m = (pa_stream_manager*)userdata;
1498
1499     pa_assert(conn);
1500     pa_assert(msg);
1501     pa_assert(m);
1502
1503     pa_assert_se(dbus_message_get_args(msg, NULL,
1504                                        DBUS_TYPE_STRING, &direction,
1505                                        DBUS_TYPE_UINT32, &idx,
1506                                        DBUS_TYPE_INVALID));
1507     pa_log_info("direction[%s], idx[%u]", direction, idx);
1508
1509     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1510
1511     if (pa_safe_streq(direction, "in"))
1512         stream_type = STREAM_SOURCE_OUTPUT;
1513     else if (pa_safe_streq(direction, "out"))
1514         stream_type = STREAM_SINK_INPUT;
1515     else {
1516         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1517         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT], DBUS_TYPE_INVALID));
1518         goto finish;
1519     }
1520
1521     if (get_volume_ratio_by_idx(m, stream_type, idx, &ratio)) {
1522         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1523         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
1524     } else {
1525         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_DOUBLE, &ratio, DBUS_TYPE_INVALID));
1526         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1527     }
1528
1529 finish:
1530     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1531     dbus_message_unref(reply);
1532 }
1533
1534 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1535     const char *direction = NULL;
1536     const char *type = NULL;
1537     void *s = NULL;
1538     stream_type_t stream_type = STREAM_SINK_INPUT;
1539     DBusMessage *reply = NULL;
1540     pa_stream_manager *m = (pa_stream_manager*)userdata;
1541     uint32_t idx = 0;
1542     pa_idxset *streams = NULL;
1543
1544     pa_assert(conn);
1545     pa_assert(msg);
1546     pa_assert(m);
1547
1548     pa_assert_se(dbus_message_get_args(msg, NULL,
1549                                        DBUS_TYPE_STRING, &direction,
1550                                        DBUS_TYPE_INVALID));
1551     pa_log_info("direction[%s]", direction);
1552
1553     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1554
1555     if (pa_safe_streq(direction, "in")) {
1556         stream_type = STREAM_SOURCE_OUTPUT;
1557         streams = m->core->source_outputs;
1558     } else if (pa_safe_streq(direction, "out")) {
1559         stream_type = STREAM_SINK_INPUT;
1560         streams = m->core->sink_inputs;
1561     } else {
1562         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1563         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1564         goto fail;
1565     }
1566
1567     /* Get a volume type of a stream that has the max priority role among all the running streams regardless of devices.
1568        Note that it does not represent any focus status of a stream rather only checking the priority of it */
1569     if (pa_idxset_size(streams)) {
1570         int cur_max_priority = 0;
1571         const char *cur_max_type = NULL;
1572         const char *role = NULL;
1573         stream_info *s_info;
1574
1575         PA_IDXSET_FOREACH(s, streams, idx) {
1576             if (!CHECK_STREAM_RUNNING(s, stream_type))
1577                 continue;
1578             if (!(type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE)))
1579                 continue;
1580             if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE)))
1581                 continue;
1582             if ((s_info = pa_hashmap_get(m->stream_infos, role))) {
1583                 if (s_info->priority >= cur_max_priority) {
1584                     cur_max_priority = s_info->priority;
1585                     cur_max_type = type;
1586                     pa_log_info("updated, volume type of the max priority stream(%u): %s", GET_STREAM_INDEX(s, stream_type), cur_max_type);
1587                 }
1588             }
1589         }
1590         type = cur_max_type;
1591     }
1592
1593     if (type) {
1594         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID));
1595         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1596     } else {
1597         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1598         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
1599     }
1600
1601 fail:
1602     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1603     dbus_message_unref(reply);
1604 }
1605
1606 static void handle_get_current_media_routing_path(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1607     const char *direction = NULL;
1608     const char *device_type = NULL;
1609     dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
1610     stream_info *s = NULL;
1611     DBusMessage *reply = NULL;
1612     pa_tz_device *device = NULL;
1613     pa_stream_manager *m = (pa_stream_manager*)userdata;
1614
1615     pa_assert(conn);
1616     pa_assert(msg);
1617     pa_assert(m);
1618
1619     pa_assert_se(dbus_message_get_args(msg, NULL,
1620                                        DBUS_TYPE_STRING, &direction,
1621                                        DBUS_TYPE_INVALID));
1622     pa_log_info("direction[%s]", direction);
1623
1624     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1625
1626     if (pa_safe_streq(direction, "in")) {
1627         dm_device_direction = DM_DEVICE_DIRECTION_IN;
1628     } else if (pa_safe_streq(direction, "out")) {
1629         dm_device_direction = DM_DEVICE_DIRECTION_OUT;
1630     } else {
1631         pa_log_error("invalid direction[%s]", direction);
1632         goto fail;
1633     }
1634
1635     if ((s = pa_hashmap_get(m->stream_infos, STREAM_ROLE_MEDIA)) == NULL) {
1636         pa_log_error("could not find media role");
1637         goto fail;
1638     }
1639
1640     if (s->route_type == STREAM_ROUTE_TYPE_AUTO) {
1641         device = get_media_auto_device(m, dm_device_direction);
1642     } else if (s->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1643         device = get_media_last_device(m, dm_device_direction);
1644     } else {
1645         pa_log_error("unexpected routing type for media[%d]", s->route_type);
1646         goto fail;
1647     }
1648
1649     if (device) {
1650         device_type = pa_tz_device_get_type(device);
1651         goto success;
1652     } else {
1653         pa_log_error("could not found matched device");
1654     }
1655
1656 fail:
1657     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1658     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1659     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1660     dbus_message_unref(reply);
1661     return;
1662 success:
1663     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_type, DBUS_TYPE_INVALID));
1664     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1665     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1666     dbus_message_unref(reply);
1667 }
1668
1669 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1670     uint32_t id = 0;
1671     uint32_t idx = 0;
1672     uint32_t count = 0;
1673     uint32_t acquired_focus_status = 0;
1674     stream_parent *sp = NULL;
1675     void *stream = NULL;
1676     DBusMessage *reply = NULL;
1677     pa_stream_manager *m = (pa_stream_manager*)userdata;
1678     int prev_status = STREAM_FOCUS_ACQUIRED_NONE;
1679
1680     pa_assert(conn);
1681     pa_assert(msg);
1682     pa_assert(m);
1683
1684     pa_assert_se(dbus_message_get_args(msg, NULL,
1685                                        DBUS_TYPE_UINT32, &id,
1686                                        DBUS_TYPE_UINT32, &acquired_focus_status,
1687                                        DBUS_TYPE_INVALID));
1688     pa_log_info("id[%u], acquired_focus_status[0x%x]", id, acquired_focus_status);
1689
1690     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1691
1692     if ((sp = pa_hashmap_get(m->stream_parents, (const void*)id))) {
1693         if (sp->focus_status != acquired_focus_status) {
1694             /* need to update */
1695             prev_status = sp->focus_status;
1696             sp->focus_status = acquired_focus_status;
1697             if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_PLAYBACK) && sp->idx_sink_inputs) {
1698                 count = pa_idxset_size(sp->idx_sink_inputs);
1699                 PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
1700                     pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1701                                      GET_FOCUS_STATUS(sp->focus_status, STREAM_SINK_INPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1702                     if (--count == 0)
1703                         process_stream(m, stream, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1704                 }
1705             }
1706             if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_CAPTURE) && sp->idx_source_outputs) {
1707                 count = pa_idxset_size(sp->idx_source_outputs);
1708                 PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
1709                     pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1710                                      GET_FOCUS_STATUS(sp->focus_status, STREAM_SOURCE_OUTPUT) ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1711                     if (--count == 0)
1712                         process_stream(m, stream, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1713                 }
1714             }
1715         } else
1716             pa_log_debug("same as before, skip updating focus status[0x%x]", acquired_focus_status);
1717
1718     } else {
1719         pa_log_error("could not find matching client for this parent_id[%u]", id);
1720         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1721         goto fail;
1722     }
1723     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1724 fail:
1725     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1726     dbus_message_unref(reply);
1727 }
1728
1729 static void handle_update_focus_status_by_focus_id(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1730     int32_t id = 0;
1731     uint32_t idx = 0;
1732     uint32_t acquired_focus_status = 0;
1733     int32_t focus_id = 0;
1734     const char *focus_id_str;
1735     pa_sink_input *i = NULL;
1736     DBusMessage *reply = NULL;
1737     pa_stream_manager *m = (pa_stream_manager*)userdata;
1738
1739     pa_assert(conn);
1740     pa_assert(msg);
1741     pa_assert(m);
1742
1743     pa_assert_se(dbus_message_get_args(msg, NULL,
1744                                        DBUS_TYPE_INT32, &id,
1745                                        DBUS_TYPE_UINT32, &acquired_focus_status,
1746                                        DBUS_TYPE_INVALID));
1747     pa_log_info("id[%d], acquired_focus_status[0x%x]", id, acquired_focus_status);
1748
1749     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1750
1751     /* Currently, we only support sink-inputs */
1752     PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
1753         if ((focus_id_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_ID))) {
1754             if (pa_atoi(focus_id_str, &focus_id))
1755               continue;
1756         if (id == focus_id) {
1757             pa_log_info("found matching sink-input(%p, %u) - focus_id(%d)", i, i->index, id);
1758             pa_proplist_sets(GET_STREAM_PROPLIST(i, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1759                              acquired_focus_status ? STREAM_FOCUS_STATE_ACQUIRED : STREAM_FOCUS_STATE_RELEASED);
1760             process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1761
1762             pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1763             goto success;
1764         }
1765       }
1766     }
1767     pa_log_error("could not find matching stream for this focus_id[%i]", id);
1768     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1769 success:
1770     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1771     dbus_message_unref(reply);
1772 }
1773
1774 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1775     const char *name;
1776     uint32_t value = 0;
1777     DBusMessage *reply = NULL;
1778     pa_stream_manager *m = (pa_stream_manager*)userdata;
1779
1780     pa_assert(conn);
1781     pa_assert(msg);
1782     pa_assert(m);
1783
1784     pa_assert_se(dbus_message_get_args(msg, NULL,
1785                                        DBUS_TYPE_STRING, &name,
1786                                        DBUS_TYPE_UINT32, &value,
1787                                        DBUS_TYPE_INVALID));
1788     pa_log_info("name[%s], value[%u]", name, value);
1789
1790     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1791
1792     if (handle_restrictions(m, name, value) < 0) {
1793         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL], DBUS_TYPE_INVALID));
1794         goto fail;
1795     }
1796
1797     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK], DBUS_TYPE_INVALID));
1798 fail:
1799     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1800     dbus_message_unref(reply);
1801 }
1802
1803 #define MAX_CALL_PARAM_SIZE 32
1804 static int32_t parse_call_parameters(const char *parameters, char *call_type, char *call_domain, char *network_band) {
1805     const char delimiter[] = ";";
1806     char *token, *ptr = NULL;
1807     char key[32] = "";
1808
1809     pa_assert(parameters);
1810     pa_assert(call_type);
1811     pa_assert(call_domain);
1812     pa_assert(network_band);
1813
1814     pa_log_info("parameters[%s]", parameters);
1815
1816     /*Reset the call parameters*/
1817     memset(call_type, 0, MAX_CALL_PARAM_SIZE);
1818     memset(call_domain, 0, MAX_CALL_PARAM_SIZE);
1819     memset(network_band, 0, MAX_CALL_PARAM_SIZE);
1820
1821     if (parameters) {
1822         token = strtok_r((char *)parameters, delimiter, &ptr);
1823         while (token) {
1824             char *delimiter_ptr = NULL;
1825             char *value = NULL;
1826
1827             delimiter_ptr = strstr(token, "=");
1828             if (!delimiter_ptr) {
1829                 token = strtok_r(NULL, delimiter, &ptr);
1830                 continue;
1831             }
1832             strncpy(key, token, delimiter_ptr - token);
1833             value = delimiter_ptr + 1;
1834             pa_log_debug("key(%s), value(%s)", key, value);
1835             if (!strncmp(key, "call-type", strlen("call-type")))
1836                 pa_strlcpy(call_type, value, MAX_CALL_PARAM_SIZE);
1837             else if (!strncmp(key, "call-domain", strlen("call-domain")))
1838                 pa_strlcpy(call_domain, value, MAX_CALL_PARAM_SIZE);
1839             else if (!strncmp(key, "network-band", strlen("network-band")))
1840                 pa_strlcpy(network_band, value, MAX_CALL_PARAM_SIZE);
1841             else
1842                 pa_log_warn("not supported key(%s)", key);
1843
1844             token = strtok_r(NULL, delimiter, &ptr);
1845             memset(key, 0, sizeof(key));
1846         }
1847         pa_log_info("call-type[%s], call-domain[%s], network-band[%s]", call_type, call_domain, network_band);
1848     }
1849
1850     return 0;
1851 }
1852
1853 static void handle_update_call_parameters(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1854     const char *parameters;
1855     DBusMessage *reply = NULL;
1856     pa_stream_manager *m = (pa_stream_manager*)userdata;
1857     char call_type[MAX_CALL_PARAM_SIZE] = {0,};
1858     char call_domain[MAX_CALL_PARAM_SIZE] = {0,};
1859     char network_band[MAX_CALL_PARAM_SIZE] = {0,};
1860     stream_route_option route_option;
1861     ret_msg_t ret = RET_MSG_OK;
1862
1863     pa_assert(conn);
1864     pa_assert(msg);
1865     pa_assert(m);
1866
1867     pa_assert_se(dbus_message_get_args(msg, NULL,
1868                                        DBUS_TYPE_STRING, &parameters,
1869                                        DBUS_TYPE_INVALID));
1870     pa_log_info("parameters[%s]", parameters);
1871
1872     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1873
1874     if (parse_call_parameters(parameters, call_type, call_domain, network_band) < 0) {
1875         ret = RET_MSG_ERROR_INTERNAL;
1876         goto fail;
1877     }
1878
1879     pa_log_debug("call_type[%s], call_domain[%s], network_band[%s]", call_type, call_domain, network_band);
1880
1881     /* Currently, we only use network band */
1882     route_option.name = "call-wideband";
1883     if (pa_safe_streq(network_band, "wb"))
1884         route_option.value = 1;
1885     else
1886         route_option.value = 0;
1887     ret = do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
1888
1889 fail:
1890     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
1891     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1892     dbus_message_unref(reply);
1893 }
1894
1895 static void handle_set_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1896     const char *filter_name, *filter_parameters, *filter_group, *stream_type;
1897     DBusMessage *reply = NULL;
1898     pa_stream_manager *m = (pa_stream_manager*)userdata;
1899
1900     pa_assert(conn);
1901     pa_assert(msg);
1902     pa_assert(m);
1903
1904     pa_assert_se(dbus_message_get_args(msg, NULL,
1905                                        DBUS_TYPE_STRING, &filter_name,
1906                                        DBUS_TYPE_STRING, &filter_parameters,
1907                                        DBUS_TYPE_STRING, &filter_group,
1908                                        DBUS_TYPE_STRING, &stream_type,
1909                                        DBUS_TYPE_INVALID));
1910     pa_log_info("filter_name[%s], filter_parameters[%s], filter_group[%s], stream_type[%s]", filter_name,
1911                 filter_parameters, filter_group, stream_type);
1912
1913     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1914
1915     /* Set filter sink according to stream type */
1916     if (update_filter(m, filter_name, filter_parameters, filter_group, stream_type) < 0) {
1917         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1918                                               DBUS_TYPE_INVALID));
1919         goto fail;
1920     }
1921
1922     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1923                                           DBUS_TYPE_INVALID));
1924
1925 fail:
1926     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1927     dbus_message_unref(reply);
1928 }
1929
1930 static void handle_unset_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1931     const char *stream_type;
1932     DBusMessage *reply = NULL;
1933     pa_stream_manager *m = (pa_stream_manager*)userdata;
1934
1935     pa_assert(conn);
1936     pa_assert(msg);
1937     pa_assert(m);
1938
1939     pa_assert_se(dbus_message_get_args(msg, NULL,
1940                                        DBUS_TYPE_STRING, &stream_type,
1941                                        DBUS_TYPE_INVALID));
1942     pa_log_info("stream_type[%s]", stream_type);
1943
1944     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1945
1946     /* Unset filter sink according to stream type */
1947     if (update_filter(m, NULL, NULL, NULL, stream_type) < 0) {
1948         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1949                                               DBUS_TYPE_INVALID));
1950         goto fail;
1951     }
1952
1953     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1954                                           DBUS_TYPE_INVALID));
1955
1956 fail:
1957     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1958     dbus_message_unref(reply);
1959 }
1960
1961 static void handle_control_filter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1962     const char *filter_name, *filter_controls, *stream_type;
1963     DBusMessage *reply = NULL;
1964     pa_stream_manager *m = (pa_stream_manager*)userdata;
1965
1966     pa_assert(conn);
1967     pa_assert(msg);
1968     pa_assert(m);
1969
1970     pa_assert_se(dbus_message_get_args(msg, NULL,
1971                                        DBUS_TYPE_STRING, &filter_name,
1972                                        DBUS_TYPE_STRING, &filter_controls,
1973                                        DBUS_TYPE_STRING, &stream_type,
1974                                        DBUS_TYPE_INVALID));
1975     pa_log_info("filter_name[%s], filter_controls[%s], stream_type[%s]", filter_name, filter_controls, stream_type);
1976
1977     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1978
1979     /* Control parameters to filter sink */
1980     if (control_filter(m, filter_name, filter_controls, stream_type, conn) < 0) {
1981         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INTERNAL],
1982                                               DBUS_TYPE_INVALID));
1983         goto fail;
1984     }
1985
1986     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
1987                  DBUS_TYPE_INVALID));
1988 fail:
1989     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1990     dbus_message_unref(reply);
1991 }
1992
1993 static bool check_stream_exist_by_pid(pa_stream_manager *m, uint32_t pid, const char *stream_role, stream_type_t type) {
1994     void *stream = NULL;
1995     uint32_t idx = 0;
1996     const char *role = NULL;
1997     const char *app_pid_str = NULL;
1998     uint32_t app_pid = 0;
1999
2000     pa_assert(m);
2001     pa_assert(stream_role);
2002
2003     pa_log_info("pid[%u], role[%s], type[%d]", pid, stream_role, type);
2004
2005     PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
2006         role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2007         if (!pa_safe_streq(role, stream_role))
2008             continue;
2009
2010         if (!CHECK_STREAM_RUNNING(stream, type)) {
2011             pa_log_info("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
2012             continue;
2013         }
2014
2015         app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
2016         if (app_pid_str && !pa_atou(app_pid_str, &app_pid)) {
2017             if (app_pid == pid) {
2018                 pa_log_info("found matching stream(%p, index:%u)", stream, GET_STREAM_INDEX(stream, type));
2019                 return true;
2020             }
2021         }
2022     }
2023
2024     return false;
2025 }
2026
2027 static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2028     uint32_t pid = 0;
2029     const char *type;
2030     const char *direction;
2031     stream_type_t stream_type = STREAM_SINK_INPUT;
2032     DBusMessage *reply = NULL;
2033     pa_stream_manager *m = (pa_stream_manager*)userdata;
2034
2035     pa_assert(conn);
2036     pa_assert(msg);
2037     pa_assert(m);
2038
2039     pa_assert_se(dbus_message_get_args(msg, NULL,
2040                                        DBUS_TYPE_UINT32, &pid,
2041                                        DBUS_TYPE_STRING, &type,
2042                                        DBUS_TYPE_STRING, &direction,
2043                                        DBUS_TYPE_INVALID));
2044     pa_log_info("pid[%u], type[%s], direction[%s]", pid, type, direction);
2045
2046     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2047
2048     if (pa_safe_streq(direction, "in"))
2049         stream_type = STREAM_SOURCE_OUTPUT;
2050     else if (pa_safe_streq(direction, "out"))
2051         stream_type = STREAM_SINK_INPUT;
2052     else {
2053         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
2054                      DBUS_TYPE_INVALID));
2055         goto fail;
2056     }
2057
2058     if (!check_stream_exist_by_pid(m, pid, type, stream_type)) {
2059         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_NO_STREAM],
2060                      DBUS_TYPE_INVALID));
2061         goto fail;
2062     }
2063
2064     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_OK],
2065                  DBUS_TYPE_INVALID));
2066 fail:
2067     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2068     dbus_message_unref(reply);
2069 }
2070
2071 static bool find_the_lastest_stream(pa_stream_manager *m, stream_type_t type, const char ** stream_roles, int length, uint32_t *pid) {
2072     void *stream = NULL;
2073     uint32_t idx = 0;
2074     const char *role;
2075     const char *app_pid_str = NULL;
2076     uint32_t latest_pid = 0;
2077     pa_usec_t latest_time = 0;
2078     uint32_t tmp_pid = 0;
2079     pa_usec_t tmp_time = 0;
2080     int i;
2081
2082     pa_assert(m);
2083     pa_assert(stream_roles);
2084     pa_assert(pid);
2085
2086     PA_IDXSET_FOREACH(stream, (type == STREAM_SINK_INPUT) ? m->core->sink_inputs : m->core->source_outputs, idx) {
2087         if (!CHECK_STREAM_RUNNING(stream, type)) {
2088             pa_log_debug("stream(%p, index:%u) is not in running state, skip it.", stream, GET_STREAM_INDEX(stream, type));
2089             continue;
2090         }
2091
2092         for (i = 0; i <length; i++) {
2093             tmp_pid = 0;
2094             tmp_time = 0;
2095
2096             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2097             if (!pa_safe_streq(stream_roles[i], role))
2098                 continue;
2099
2100             app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID_ORIGIN);
2101             if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid)) {
2102                 pa_log_debug("found a stream(pid.origin:%u, index:%u) that matches requested stream role[%s]", tmp_pid, GET_STREAM_INDEX(stream, type), stream_roles[i]);
2103             } else {
2104                 app_pid_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_APPLICATION_PROCESS_ID);
2105                 if (app_pid_str && !pa_atou(app_pid_str, &tmp_pid))
2106                     pa_log_debug("found a stream(pid:%u, index:%u) that matches requested stream role[%s]", tmp_pid, GET_STREAM_INDEX(stream, type), stream_roles[i]);
2107             }
2108             if (tmp_pid) {
2109                 tmp_time = GET_STREAM_LAST_RUN_TIME(stream, type);
2110                 if (latest_time <= tmp_time) {
2111                     latest_time = tmp_time;
2112                     latest_pid = tmp_pid;
2113                 }
2114             }
2115         }
2116     }
2117
2118     if (latest_pid > 0) {
2119         *pid = latest_pid;
2120         pa_log_info("found the stream(pid:%u)", *pid);
2121         return true;
2122     }
2123
2124     pa_log_info("no match is found");
2125     return false;
2126 }
2127
2128 static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2129     const char *direction;
2130     const char **types;
2131     int length;
2132     stream_type_t stream_type = STREAM_SINK_INPUT;
2133     uint32_t pid = 0;
2134     ret_msg_t ret_msg = RET_MSG_OK;
2135
2136     DBusMessage *reply = NULL;
2137     pa_stream_manager *m = (pa_stream_manager*)userdata;
2138
2139     pa_assert(conn);
2140     pa_assert(msg);
2141     pa_assert(m);
2142
2143     pa_assert_se(dbus_message_get_args(msg, NULL,
2144                                        DBUS_TYPE_STRING, &direction,
2145                                        DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &types, &length,
2146                                        DBUS_TYPE_INVALID));
2147
2148     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2149
2150     if (pa_safe_streq(direction, "in"))
2151         stream_type = STREAM_SOURCE_OUTPUT;
2152     else if (pa_safe_streq(direction, "out"))
2153         stream_type = STREAM_SINK_INPUT;
2154     else {
2155         pa_log_error("invalid direction[%s]", direction);
2156         goto invalid_argument;
2157     }
2158
2159     if (length <= 0) {
2160         pa_log_error("At least one stream type should be contained");
2161         goto invalid_argument;
2162     }
2163
2164     if (!find_the_lastest_stream(m, stream_type, types, length, &pid))
2165         ret_msg = RET_MSG_ERROR_NO_STREAM;
2166
2167     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID));
2168     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg],
2169                 DBUS_TYPE_INVALID));
2170     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2171     dbus_message_unref(reply);
2172     return;
2173
2174 invalid_argument:
2175     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID));
2176     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_ERROR_INVALID_ARGUMENT],
2177                      DBUS_TYPE_INVALID));
2178     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2179     dbus_message_unref(reply);
2180 }
2181
2182 static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2183     dbus_uint32_t id = 0;
2184     dbus_bool_t enable = 0;
2185     const char *target_stream = NULL;
2186     uint32_t idx = 0;
2187     pa_sink_input *i = NULL;
2188     dbus_uint32_t duration = 0;
2189     double ratio = 0.0;
2190     DBusMessage *reply = NULL;
2191     pa_stream_manager *m = (pa_stream_manager*)userdata;
2192     pa_cvolume vol;
2193     pa_cvolume_ramp vol_ramp;
2194     stream_ducking *sd = NULL;
2195     hal_ducking_activation_info ducking_activation_info;
2196     ret_msg_t ret_msg = RET_MSG_OK;
2197
2198     pa_assert(conn);
2199     pa_assert(msg);
2200     pa_assert(m);
2201
2202     pa_assert_se(dbus_message_get_args(msg, NULL,
2203                                        DBUS_TYPE_UINT32, &id,
2204                                        DBUS_TYPE_BOOLEAN, &enable,
2205                                        DBUS_TYPE_STRING, &target_stream,
2206                                        DBUS_TYPE_UINT32, &duration,
2207                                        DBUS_TYPE_DOUBLE, &ratio,
2208                                        DBUS_TYPE_INVALID));
2209
2210     pa_log_info("id[%u], enable[%u], target stream[%s], duration[%u], ratio[%lf]",
2211         id, enable, target_stream, duration, ratio);
2212
2213     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2214
2215     /* get stream_ducking */
2216     sd = pa_hashmap_get(m->stream_duckings, (const void*)id);
2217     if (!sd) {
2218         pa_log_error("no matched stream ducking for id[%u]", id);
2219         ret_msg = RET_MSG_ERROR_INTERNAL;
2220         goto _ACTIVATE_DUCKING_DONE;
2221     }
2222
2223     /* validate state with command */
2224     if ((enable && sd->state != STREAM_DUCKING_STATE_UNDUCKED) ||
2225         (!enable && sd->state != STREAM_DUCKING_STATE_DUCKED)) {
2226         pa_log_error("state validation failed - [%d,s:%u]", enable, sd->state);
2227         ret_msg = RET_MSG_ERROR_INVALID_STATE;
2228         goto _ACTIVATE_DUCKING_DONE;
2229     }
2230
2231     sd->duration = duration;
2232     sd->ratio = ratio;
2233     sd->set_vol = PA_VOLUME_NORM * ratio;
2234
2235     if (enable) {
2236         sd->state = STREAM_DUCKING_STATE_DUCKING;
2237         snprintf(sd->vol_key, VOLUME_KEY_LENGTH, "stream_ducking_%u_%s", id, target_stream);
2238         snprintf(sd->target_role, STREAM_ROLE_STR_MAX, "%s", target_stream);
2239     } else {
2240         sd->state = STREAM_DUCKING_STATE_UNDUCKING;
2241     }
2242
2243     /* set volume ramp factor to target stream */
2244     PA_IDXSET_FOREACH(i, m->core->sink_inputs, idx) {
2245         if (!pa_safe_streq(target_stream, pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
2246             continue;
2247
2248         if (i->state == PA_SINK_INPUT_RUNNING)
2249             sd->ducking_stream_count++;
2250
2251         if (enable) {
2252             pa_idxset_put(sd->idx_ducking_streams, (void *)i, NULL);
2253
2254             pa_log_error("ducking: add volume_ramp factor, key[%s], set_vol[%u] to stream[idx:%u]",
2255                 sd->vol_key, sd->set_vol, i->index);
2256
2257             pa_cvolume_ramp_set(&vol_ramp, i->volume.channels,
2258                 PA_VOLUME_RAMP_TYPE_LINEAR, (long)duration, sd->set_vol);
2259
2260             if (i->state != PA_SINK_INPUT_RUNNING || duration == 0) {
2261                 pa_cvolume_set(&vol, i->volume.channels, sd->set_vol);
2262                 pa_sink_input_add_volume_factor(i, sd->vol_key, &vol);
2263                 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, false);
2264             } else {
2265                 pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, true);
2266             }
2267         } else {
2268             pa_log_error("unducking: remove volume(ramp) factor, key[%s] from stream[idx:%u]",
2269                 sd->vol_key, i->index);
2270
2271             pa_sink_input_remove_volume_factor(i, sd->vol_key);
2272             pa_sink_input_remove_volume_ramp_factor(i, sd->vol_key, true);
2273         }
2274     }
2275
2276     if (!enable) {
2277         memset(&sd->target_role, 0, sizeof(sd->target_role));
2278         memset(&sd->vol_key, 0, sizeof(sd->vol_key));
2279     }
2280
2281     pa_log_info("ducking stream count[%p,%d]", sd, sd->ducking_stream_count);
2282
2283 _ACTIVATE_DUCKING_DONE:
2284     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
2285     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2286     dbus_message_unref(reply);
2287
2288     if (ret_msg != RET_MSG_OK)
2289         return;
2290
2291     /* notify ducking activation */
2292     ducking_activation_info.target_role = target_stream;
2293     ducking_activation_info.duration = duration;
2294     ducking_activation_info.ratio = ratio;
2295     ducking_activation_info.is_activated = enable;
2296
2297     pa_hal_interface_notify_ducking_activation_changed(m->hal, &ducking_activation_info);
2298
2299     if (sd->ducking_stream_count <= 0 || duration == 0) {
2300         /* change ducking state and send signal here,
2301            because ramp_finish_cb could not be called in this case. */
2302         if (enable)
2303             sd->state = STREAM_DUCKING_STATE_DUCKED;
2304         else
2305             sd->state = STREAM_DUCKING_STATE_UNDUCKED;
2306
2307         pa_log_info("send signal for ramp finished - state[%u]", sd->state);
2308
2309         /* It should be reset here because it's increased,
2310            but will not be decreased in case of 0 duration. */
2311         sd->ducking_stream_count = 0;
2312
2313         send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
2314     }
2315 }
2316
2317 static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2318     dbus_uint32_t id = 0;
2319     DBusMessage *reply = NULL;
2320     pa_stream_manager *m = (pa_stream_manager*)userdata;
2321     stream_ducking *sd = NULL;
2322     dbus_bool_t is_ducked = FALSE;
2323     ret_msg_t ret_msg = RET_MSG_OK;
2324
2325     pa_assert(conn);
2326     pa_assert(msg);
2327     pa_assert(m);
2328
2329     pa_assert_se(dbus_message_get_args(msg, NULL,
2330                                        DBUS_TYPE_UINT32, &id,
2331                                        DBUS_TYPE_INVALID));
2332
2333     pa_assert_se((reply = dbus_message_new_method_return(msg)));
2334
2335     /* get stream_ducking */
2336     sd = pa_hashmap_get(m->stream_duckings, (const void *)id);
2337     if (sd) {
2338         is_ducked = (dbus_bool_t)is_stream_ducked(sd);
2339         pa_log_info("id[%u], is_ducked[%p,%d]", id, sd, is_ducked);
2340     } else {
2341         ret_msg = RET_MSG_ERROR_INTERNAL;
2342         pa_log_error("no matched stream ducking for id[%u]", id);
2343     }
2344
2345     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_ducked, DBUS_TYPE_INVALID));
2346     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret_msg], DBUS_TYPE_INVALID));
2347
2348     pa_assert_se(dbus_connection_send(conn, reply, NULL));
2349     dbus_message_unref(reply);
2350 }
2351
2352 static int dbus_launch_mdnsd(pa_stream_manager *m, DBusConnection *conn) {
2353     DBusMessage *msg, *reply;
2354     DBusError err;
2355     const char *name = NULL;
2356
2357     pa_log_info("launching mdnsd");
2358
2359     if (!(msg = dbus_message_new_method_call("net.netconfig",
2360                                              "/net/netconfig/network",
2361                                              "net.netconfig.network",
2362                                              "LaunchMdns"))) {
2363         pa_log_error("dbus method call failed");
2364         return -1;
2365     }
2366
2367     name = dbus_bus_get_unique_name(conn);
2368     pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID));
2369
2370     dbus_error_init(&err);
2371     if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) {
2372         pa_log_error("Failed to method call :  %s", err.message);
2373         dbus_error_free(&err);
2374         return -1;
2375     }
2376
2377     dbus_message_unref(reply);
2378
2379     pa_log_info("success");
2380
2381     return 0;
2382 }
2383
2384 static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2385     pa_stream_manager *m = (pa_stream_manager*)userdata;
2386     dbus_uint32_t index;
2387     dbus_bool_t allowed;
2388     pa_proplist *p = NULL;
2389     char *type = NULL;
2390
2391     pa_assert(conn);
2392     pa_assert(msg);
2393     pa_assert(m);
2394
2395     pa_assert_se(dbus_message_get_args(msg, NULL,
2396                                        DBUS_TYPE_STRING, &type,
2397                                        DBUS_TYPE_UINT32, &index,
2398                                        DBUS_TYPE_BOOLEAN, &allowed,
2399                                        DBUS_TYPE_INVALID));
2400
2401     if (!type) {
2402         pa_log_error("invalid arguments");
2403         goto out;
2404     }
2405
2406     pa_log_info("type(%s), index(%d), allowed(%d)", type, index, allowed);
2407
2408     p = pa_proplist_new();
2409     if (!p) {
2410         pa_log_error("failed to create proplist");
2411         goto out;
2412     }
2413
2414     if (pa_proplist_set_remote_access_permission(p, allowed)) {
2415          pa_log_error("set remote access permission error");
2416          goto out;
2417     }
2418
2419     if (pa_streq(type, "sink-input")) {
2420         pa_sink_input *i;
2421
2422         i = pa_idxset_get_by_index(m->core->sink_inputs, index);
2423         if (!i) {
2424             pa_log_error("not found sink-input");
2425             goto out;
2426         }
2427
2428         if (pa_proplist_remote_is_allowed(i->proplist) != allowed){
2429             pa_sink_input_update_proplist(i, PA_UPDATE_REPLACE, p);
2430             pa_sink_input_send_event(i, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
2431         }
2432
2433     } else if (pa_streq(type, "source-output")) {
2434         pa_source_output *o;
2435
2436         o = pa_idxset_get_by_index(m->core->source_outputs, index);
2437         if (!o) {
2438             pa_log_error("not found source-output");
2439             goto out;
2440         }
2441
2442         if (pa_proplist_remote_is_allowed(o->proplist) != allowed){
2443             pa_source_output_update_proplist(o, PA_UPDATE_REPLACE, p);
2444             pa_source_output_send_event(o, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
2445         }
2446
2447     } else {
2448         pa_log_warn("unknown type");
2449     }
2450
2451 out:
2452     if (p)
2453         pa_proplist_free(p);
2454
2455     pa_dbus_send_empty_reply(conn, msg);
2456 }
2457
2458 static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2459     pa_stream_manager *m = (pa_stream_manager*)userdata;
2460     pa_module *module;
2461     dbus_bool_t enable;
2462
2463     pa_assert(conn);
2464     pa_assert(msg);
2465     pa_assert(m);
2466
2467     pa_assert_se(dbus_message_get_args(msg, NULL,
2468                                        DBUS_TYPE_BOOLEAN, &enable,
2469                                        DBUS_TYPE_INVALID));
2470
2471     pa_log_info("discover module enable(%d)", enable);
2472
2473     if (enable) {
2474         if (m->m_discover) {
2475             pa_log_error("already loaded");
2476             goto error;
2477         }
2478
2479         if (dbus_launch_mdnsd(m, conn) == -1) {
2480             pa_log_error("failed to launch mdnsd!!!");
2481             goto error;
2482         }
2483
2484         if (pa_module_load(&module, m->core, "module-tizenaudio-discover", NULL)) {
2485             pa_log_error("failed to load module");
2486             goto error;
2487         }
2488         m->m_discover = module->index;
2489     } else {
2490         if (m->m_discover) {
2491             pa_module_unload_request_by_index(m->core, m->m_discover, true);
2492             m->m_discover = 0;
2493         }
2494     }
2495
2496     pa_dbus_send_empty_reply(conn, msg);
2497
2498     return;
2499
2500 error:
2501     pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
2502                             "org.tizen.multimedia.audio.Internal");
2503 }
2504
2505 static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2506     pa_stream_manager *m = (pa_stream_manager*)userdata;
2507     pa_module *module;
2508     dbus_bool_t enable;
2509
2510     pa_assert(conn);
2511     pa_assert(msg);
2512     pa_assert(m);
2513
2514     pa_assert_se(dbus_message_get_args(msg, NULL,
2515                                        DBUS_TYPE_BOOLEAN, &enable,
2516                                        DBUS_TYPE_INVALID));
2517
2518     pa_log_info("publish module enable(%d)", enable);
2519
2520     if (enable) {
2521         if (m->m_protocol_tcp || m->m_publish) {
2522             pa_log_error("already loaded");
2523             goto error;
2524         }
2525
2526         if (dbus_launch_mdnsd(m, conn) == -1) {
2527             pa_log_error("failed to launch mdnsd!!!");
2528             goto error;
2529         }
2530
2531         if (pa_module_load(&module, m->core, "module-native-protocol-tcp", "auth-anonymous=1")) {
2532             pa_log_error("failed to load module");
2533             goto error;
2534         }
2535         m->m_protocol_tcp = module->index;
2536
2537         if (pa_module_load(&module, m->core, "module-tizenaudio-publish", NULL)) {
2538             pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
2539             pa_log_error("failed to load module");
2540             goto error;
2541         }
2542         m->m_publish = module->index;
2543     } else {
2544         if (m->m_protocol_tcp) {
2545             pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
2546             m->m_protocol_tcp = 0;
2547         }
2548         if (m->m_publish) {
2549             pa_module_unload_request_by_index(m->core, m->m_publish, true);
2550             m->m_publish = 0;
2551         }
2552     }
2553
2554     pa_dbus_send_empty_reply(conn, msg);
2555
2556     return;
2557
2558 error:
2559     pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
2560                             "org.tizen.multimedia.audio.Internal");
2561 }
2562
2563 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
2564     int idx = 0;
2565     pa_stream_manager *m = (pa_stream_manager*)userdata;
2566
2567     pa_assert(conn);
2568     pa_assert(msg);
2569     pa_assert(m);
2570
2571     for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
2572         if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name)) {
2573             pa_log_debug("Message signature [%s] (Expected [%s])", dbus_message_get_signature(msg), signature_args_for_in[idx]);
2574             if (pa_safe_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
2575                 method_handlers[idx].receive_cb(conn, msg, userdata);
2576                 return DBUS_HANDLER_RESULT_HANDLED;
2577             } else {
2578                 pa_log_warn("Wrong Argument Signature");
2579                 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE,  "Wrong Signature, Expected %s", signature_args_for_in[idx]);
2580                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2581             }
2582         }
2583     }
2584
2585     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2586 }
2587
2588 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
2589     pa_stream_manager *u = (pa_stream_manager*)userdata;
2590     const char *path, *interface, *member;
2591
2592     pa_assert(c);
2593     pa_assert(m);
2594     pa_assert(u);
2595
2596     path = dbus_message_get_path(m);
2597     interface = dbus_message_get_interface(m);
2598     member = dbus_message_get_member(m);
2599
2600     pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
2601
2602     if (!pa_safe_streq(path, STREAM_MANAGER_OBJECT_PATH))
2603         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2604
2605     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
2606         return handle_introspect(c, m, u);
2607     } else {
2608         return handle_methods(c, m, u);
2609     }
2610
2611     return DBUS_HANDLER_RESULT_HANDLED;
2612 }
2613
2614 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level) {
2615     DBusMessage *signal_msg;
2616     DBusMessageIter msg_iter;
2617
2618     pa_assert(conn);
2619     pa_assert(direction);
2620     pa_assert(volume_type);
2621
2622     pa_log_debug("direction[%s], type[%s], level[%d]", direction, volume_type, volume_level);
2623
2624     pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED)));
2625     dbus_message_iter_init_append(signal_msg, &msg_iter);
2626
2627     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &direction);
2628     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &volume_type);
2629     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &volume_level);
2630
2631     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2632     dbus_message_unref(signal_msg);
2633     return;
2634 }
2635
2636 void send_ducking_state_changed_signal(DBusConnection *conn, const int index, const int is_ducked)
2637 {
2638     DBusMessage *signal_msg;
2639     DBusMessageIter msg_iter;
2640
2641     pa_assert(conn);
2642
2643     pa_log_debug("trigger_index(%d) : is_ducked(%d)", index, is_ducked);
2644
2645     pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_DUCKING_STATE_CHANGED)));
2646     dbus_message_iter_init_append(signal_msg, &msg_iter);
2647
2648     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &index);
2649     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &is_ducked);
2650
2651     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2652     dbus_message_unref(signal_msg);
2653
2654     return;
2655 }
2656
2657 void send_command_signal(DBusConnection *conn, const char *name, int value) {
2658     DBusMessage *signal_msg;
2659     DBusMessageIter msg_iter;
2660
2661     pa_assert(conn);
2662     pa_assert(name);
2663
2664     pa_log_debug("name[%s], value[%d]", name, value);
2665
2666     pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_COMMAND)));
2667     dbus_message_iter_init_append(signal_msg, &msg_iter);
2668
2669     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2670     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &value);
2671
2672     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2673     dbus_message_unref(signal_msg);
2674 }
2675
2676 void send_remote_found_signal(DBusConnection *conn, int type, bool connected, unsigned int index,
2677                                                       const char *name, const char *description) {
2678     DBusMessage *signal_msg;
2679     DBusMessageIter msg_iter;
2680     dbus_bool_t c = (dbus_bool_t)connected;
2681
2682     pa_assert(conn);
2683
2684     if (!name || !description) {
2685         pa_log_error("Unknown device");
2686         return;
2687     }
2688
2689     pa_log_info("type[%d], index[%d], connected[%d], name[%s] description[%s]", type, index, connected, name, description);
2690
2691     pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND)));
2692     dbus_message_iter_init_append(signal_msg, &msg_iter);
2693
2694     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &type);
2695     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &index);
2696     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &c);
2697     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
2698     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &description);
2699
2700     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
2701     dbus_message_unref(signal_msg);
2702 }
2703
2704 int32_t init_sm_dbus(pa_stream_manager *m) {
2705     pa_assert(m);
2706
2707 #ifdef USE_DBUS_PROTOCOL
2708     m->dbus_protocol = pa_dbus_protocol_get(m->core);
2709     pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
2710     pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2711 #else
2712     DBusError err;
2713     pa_dbus_connection *conn = NULL;
2714     static const DBusObjectPathVTable vtable = {
2715         .message_function = method_handler_for_vt,
2716     };
2717
2718     dbus_error_init(&err);
2719
2720     if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
2721         if (conn) {
2722             pa_dbus_connection_unref(conn);
2723         }
2724         pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
2725         return -1;
2726     } else {
2727         pa_log_notice("Got dbus connection");
2728     }
2729     m->dbus_conn = conn;
2730     pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
2731 #endif
2732     return 0;
2733 }
2734
2735 void deinit_sm_dbus(pa_stream_manager *m) {
2736     pa_assert(m);
2737
2738 #ifdef USE_DBUS_PROTOCOL
2739     if (m->dbus_protocol) {
2740         pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2741         pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
2742         pa_dbus_protocol_unref(m->dbus_protocol);
2743         m->dbus_protocol = NULL;
2744     }
2745 #else
2746     if (m->dbus_conn) {
2747         if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
2748             pa_log_error("failed to unregister object path");
2749
2750         pa_dbus_connection_unref(m->dbus_conn);
2751         m->dbus_conn = NULL;
2752     }
2753 #endif
2754 }
2755
2756 #endif