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