stream-manager: Modify handle_update_focus_status() to update only if needed
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / stream-manager.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2015-2016 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 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <errno.h>
33
34 #include <pulse/xmalloc.h>
35 #include <pulse/proplist.h>
36
37 #include <pulsecore/module.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/sink.h>
40 #include <pulsecore/modargs.h>
41 #include <pulsecore/macro.h>
42
43 #include <json.h>
44 #include "stream-manager.h"
45 #include "stream-manager-priv.h"
46 #include "stream-manager-volume-priv.h"
47 #include "stream-manager-restriction-priv.h"
48
49 #ifdef HAVE_DBUS
50 #define ARR_ARG_MAX  32
51 #define STREAM_MANAGER_OBJECT_PATH "/org/pulseaudio/StreamManager"
52 #define STREAM_MANAGER_INTERFACE   "org.pulseaudio.StreamManager"
53 /* method */
54 #define STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO            "GetStreamInfo"
55 #define STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST            "GetStreamList"
56 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES   "SetStreamRouteDevices"
57 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION    "SetStreamRouteOption"
58 #define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL           "SetVolumeLevel"
59 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL           "GetVolumeLevel"
60 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL       "GetVolumeMaxLevel"
61 #define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE            "SetVolumeMute"
62 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE            "GetVolumeMute"
63 #define STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE    "GetCurrentVolumeType" /* the type that belongs to the stream of the current max priority */
64 #define STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS        "UpdateFocusStatus"
65 #define STREAM_MANAGER_METHOD_NAME_UPDATE_RESTRICTION         "UpdateRestriction"
66 /* signal */
67 #define STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED             "VolumeChanged"
68 #define STREAM_MANAGER_SIGNAL_NAME_COMMAND                    "Command"
69
70 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata);
71 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
72 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
73 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
74 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
75 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
76 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
77 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
78 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
79 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
80 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
81 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
82 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
83 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
84 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata);
85 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level);
86 static void send_command_signal(DBusConnection *conn, const char *name, int value);
87
88 enum method_handler_index {
89     METHOD_HANDLER_GET_STREAM_INFO,
90     METHOD_HANDLER_GET_STREAM_LIST,
91     METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES,
92     METHOD_HANDLER_SET_STREAM_ROUTE_OPTION,
93     METHOD_HANDLER_SET_VOLUME_LEVEL,
94     METHOD_HANDLER_GET_VOLUME_LEVEL,
95     METHOD_HANDLER_GET_VOLUME_MAX_LEVEL,
96     METHOD_HANDLER_SET_VOLUME_MUTE,
97     METHOD_HANDLER_GET_VOLUME_MUTE,
98     METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE,
99     METHOD_HANDLER_UPDATE_FOCUS_STATUS,
100     METHOD_HANDLER_UPDATE_RESTRICTION,
101     METHOD_HANDLER_MAX
102 };
103
104 static pa_dbus_arg_info get_stream_info_args[]  = { { "stream_type", "s", "in" },
105                                                       { "priority", "i", "out" },
106                                                     { "route_type", "i", "out" },
107                                                  { "volume_types", "as", "out" },
108                                              { "avail_in_devices", "as", "out" },
109                                             { "avail_out_devices", "as", "out" },
110                                             { "avail_frameworks", "as", "out"} };
111 static pa_dbus_arg_info get_stream_list_args[]  = { { "stream_type", "as", "out" },
112                                                      { "priority", "ai", "out" } };
113 static pa_dbus_arg_info set_stream_route_devices_args[]  = { { "parent_id", "u", "in" },
114                                                      { "route_in_devices", "au", "in" },
115                                                     { "route_out_devices", "au", "in" },
116                                                             { "ret_msg", "s", "out" } };
117 static pa_dbus_arg_info set_stream_route_option_args[]  = { { "parent_id", "u", "in" },
118                                                                  { "name", "s", "in" },
119                                                                 { "value", "i", "in" },
120                                                            { "ret_msg", "s", "out" } };
121 static pa_dbus_arg_info set_volume_level_args[]  = { { "io_direction", "s", "in" },
122                                                              { "type", "s", "in" },
123                                                             { "level", "u", "in" },
124                                                        { "ret_msg", "s", "out" } };
125 static pa_dbus_arg_info get_volume_level_args[]  = { { "io_direction", "s", "in" },
126                                                              { "type", "s", "in" },
127                                                            { "level", "u", "out" },
128                                                        { "ret_msg", "s", "out" } };
129 static pa_dbus_arg_info get_volume_max_level_args[]  = { { "io_direction", "s", "in" },
130                                                                  { "type", "s", "in" },
131                                                                { "level", "u", "out" },
132                                                            { "ret_msg", "s", "out" } };
133 static pa_dbus_arg_info set_volume_mute_args[]  = { { "io_direction", "s", "in" },
134                                                             { "type", "s", "in" },
135                                                               { "on", "u", "in" },
136                                                       { "ret_msg", "s", "out" } };
137 static pa_dbus_arg_info get_volume_mute_args[]  = { { "io_direction", "s", "in" },
138                                                             { "type", "s", "in" },
139                                                              { "on", "u", "out" },
140                                                       { "ret_msg", "s", "out" } };
141 static pa_dbus_arg_info get_current_volume_type_args[]  = { { "io_direction", "s", "in" },
142                                                                    { "type", "s", "out" },
143                                                               { "ret_msg", "s", "out" } };
144 static pa_dbus_arg_info update_focus_status_args[]  = { { "parent_id", "u", "in" },
145                                                      { "focus_status", "u", "in" },
146                                                        { "ret_msg", "s", "out" } };
147 static pa_dbus_arg_info update_restriction_args[]  = { { "name", "s", "in" },
148                                                       { "value", "u", "in" },
149                                                  { "ret_msg", "s", "out" } };
150 static const char* signature_args_for_in[] = { "s", "", "uauau", "usi", "ssu", "ss", "ss", "ssu", "ss", "s", "uu", "su"};
151
152 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
153     [METHOD_HANDLER_GET_STREAM_INFO] = {
154         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
155         .arguments = get_stream_info_args,
156         .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
157         .receive_cb = handle_get_stream_info },
158     [METHOD_HANDLER_GET_STREAM_LIST] = {
159         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
160         .arguments = get_stream_list_args,
161         .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
162         .receive_cb = handle_get_stream_list },
163     [METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES] = {
164         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
165         .arguments = set_stream_route_devices_args,
166         .n_arguments = sizeof(set_stream_route_devices_args) / sizeof(pa_dbus_arg_info),
167         .receive_cb = handle_set_stream_route_devices },
168     [METHOD_HANDLER_SET_STREAM_ROUTE_OPTION] = {
169         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
170         .arguments = set_stream_route_option_args,
171         .n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
172         .receive_cb = handle_set_stream_route_option },
173     [METHOD_HANDLER_SET_VOLUME_LEVEL] = {
174         .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
175         .arguments = set_volume_level_args,
176         .n_arguments = sizeof(set_volume_level_args) / sizeof(pa_dbus_arg_info),
177         .receive_cb = handle_set_volume_level },
178     [METHOD_HANDLER_GET_VOLUME_LEVEL] = {
179         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
180         .arguments = get_volume_level_args,
181         .n_arguments = sizeof(get_volume_level_args) / sizeof(pa_dbus_arg_info),
182         .receive_cb = handle_get_volume_level },
183     [METHOD_HANDLER_GET_VOLUME_MAX_LEVEL] = {
184         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
185         .arguments = get_volume_max_level_args,
186         .n_arguments = sizeof(get_volume_max_level_args) / sizeof(pa_dbus_arg_info),
187         .receive_cb = handle_get_volume_max_level },
188     [METHOD_HANDLER_SET_VOLUME_MUTE] = {
189         .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE,
190         .arguments = set_volume_mute_args,
191         .n_arguments = sizeof(set_volume_mute_args) / sizeof(pa_dbus_arg_info),
192         .receive_cb = handle_set_volume_mute },
193     [METHOD_HANDLER_GET_VOLUME_MUTE] = {
194         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE,
195         .arguments = get_volume_mute_args,
196         .n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
197         .receive_cb = handle_get_volume_mute },
198     [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
199         .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
200         .arguments = get_current_volume_type_args,
201         .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
202         .receive_cb = handle_get_current_volume_type },
203     [METHOD_HANDLER_UPDATE_FOCUS_STATUS] = {
204         .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS,
205         .arguments = update_focus_status_args,
206         .n_arguments = sizeof(update_focus_status_args) / sizeof(pa_dbus_arg_info),
207         .receive_cb = handle_update_focus_status },
208     [METHOD_HANDLER_UPDATE_RESTRICTION] = {
209         .method_name = STREAM_MANAGER_METHOD_NAME_UPDATE_RESTRICTION,
210         .arguments = update_restriction_args,
211         .n_arguments = sizeof(update_restriction_args) / sizeof(pa_dbus_arg_info),
212         .receive_cb = handle_update_restriction },
213 };
214
215 const char *dbus_str_none = "none";
216 const char* stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK", "STREAM_MANAGER_RETURN_ERROR", "STREAM_MANAGER_RETURN_ERROR_NO_STREAM"};
217 enum {
218     RET_MSG_INDEX_OK,
219     RET_MSG_INDEX_ERROR,
220     RET_MSG_INDEX_ERROR_NO_STREAM,
221 };
222
223 #ifdef USE_DBUS_PROTOCOL
224
225 static pa_dbus_interface_info stream_manager_interface_info = {
226     .name = STREAM_MANAGER_INTERFACE,
227     .method_handlers = method_handlers,
228     .n_method_handlers = METHOD_HANDLER_MAX,
229     .property_handlers = ,
230     .n_property_handlers = ,
231     .get_all_properties_cb =,
232     .signals =,
233     .n_signals =
234 };
235
236 #else
237
238 #define STREAM_MGR_INTROSPECT_XML                                            \
239     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                \
240     "<node>"                                                                 \
241     " <interface name=\"STREAM_MANAGER_INTERFACE\">"                         \
242     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO\">"         \
243     "   <arg name=\"stream_type\" direction=\"in\" type=\"s\"/>"             \
244     "   <arg name=\"priority\" direction=\"out\" type=\"i\"/>"               \
245     "   <arg name=\"route_type\" direction=\"out\" type=\"i\"/>"             \
246     "   <arg name=\"volume_types\" direction=\"out\" type=\"as\"/>"          \
247     "   <arg name=\"avail_in_devices\" direction=\"out\" type=\"as\"/>"      \
248     "   <arg name=\"avail_out_devices\" direction=\"out\" type=\"as\"/>"     \
249     "   <arg name=\"avail_frameworks\" direction=\"out\" type=\"as\"/>"      \
250     "  </method>"                                                            \
251     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST\">"         \
252     "   <arg name=\"stream_type\" direction=\"in\" type=\"as\"/>"            \
253     "   <arg name=\"priority\" direction=\"in\" type=\"ai\"/>"               \
254     "  </method>"                                                            \
255     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES\">"\
256     "   <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>"               \
257     "   <arg name=\"route_in_devices\" direction=\"in\" type=\"au\"/>"       \
258     "   <arg name=\"route_out_devices\" direction=\"in\" type=\"au\"/>"      \
259     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
260     "  </method>"                                                            \
261     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION\">" \
262     "   <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>"               \
263     "   <arg name=\"name\" direction=\"in\" type=\"s\"/>"                    \
264     "   <arg name=\"value\" direction=\"in\" type=\"i\"/>"                   \
265     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
266     "  </method>"                                                            \
267     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL\">"        \
268     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
269     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
270     "   <arg name=\"level\" direction=\"in\" type=\"u\"/>"                   \
271     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
272     "  </method>"                                                            \
273     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL\">"        \
274     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
275     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
276     "   <arg name=\"level\" direction=\"out\" type=\"u\"/>"                  \
277     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
278     "  </method>"                                                            \
279     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL\">"    \
280     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
281     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
282     "   <arg name=\"level\" direction=\"out\" type=\"u\"/>"                  \
283     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
284     "  </method>"                                                            \
285     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE\">"         \
286     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
287     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
288     "   <arg name=\"on\" direction=\"in\" type=\"u\"/>"                      \
289     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
290     "  </method>"                                                            \
291     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE\">"         \
292     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
293     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
294     "   <arg name=\"on\" direction=\"out\" type=\"u\"/>"                     \
295     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
296     "  </method>"                                                            \
297     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE\">" \
298     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
299     "   <arg name=\"type\" direction=\"out\" type=\"s\"/>"                   \
300     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
301     "  </method>"                                                            \
302     "  <method name=\"STREAM_MANAGER_METHOD_NAME_UPDATE_FOCUS_STATUS\">"     \
303     "   <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>"               \
304     "   <arg name=\"focus_status\" direction=\"in\" type=\"u\"/>"            \
305     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
306     "  </method>"                                                            \
307     "  <method name=\"STREAM_MANAGER_METHOD_NAME_UPDATE_RESTRICTION\">"      \
308     "   <arg name=\"name\" direction=\"in\" type=\"s\"/>"                    \
309     "   <arg name=\"value\" direction=\"in\" type=\"u\"/>"                   \
310     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
311     "  </method>"                                                            \
312     "  <signal name=\"STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED\">"          \
313     "   <arg name=\"direction\" type=\"s\"/>"                                \
314     "   <arg name=\"volume_type\" type=\"s\"/>"                              \
315     "   <arg name=\"volume_level\" type=\"u\"/>"                             \
316     "  </signal>"                                                            \
317     "  <signal name=\"STREAM_MANAGER_SIGNAL_NAME_COMMAND\">"                 \
318     "   <arg name=\"name\" type=\"s\"/>"                                     \
319     "   <arg name=\"value\" type=\"i\"/>"                                    \
320     "  </signal>"                                                            \
321     " </interface>"                                                          \
322     " <interface name=\"org.freedesktop.DBus.Introspectable\">"              \
323     "  <method name=\"Introspect\">"                                         \
324     "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"                   \
325     "  </method>"                                                            \
326     " </interface>"                                                          \
327     "</node>"
328 #endif
329
330 #endif
331
332 #define STREAM_MANAGER_CLIENT_NAME "SOUND_MANAGER_STREAM_INFO" /* The client via sound-manager */
333 #define VIRTUAL_STREAM_NAME "VIRTUAL_STREAM" /* The virtual stream created by sound-manager */
334 #define DEFAULT_ROLE "media"
335 #define SKIP_ROLE "skip"
336 #define ACTIVE_DEV_REMOVED "removed"
337
338 /* There are some streams that need to be skipped.
339  * In other words, we do not care about streams that have a name of listed as below */
340 #define NAME_FOR_SKIP_MAX 1
341 const char* stream_manager_media_names_for_skip[NAME_FOR_SKIP_MAX] = {"pulsesink probe"};
342
343 #define STREAM_FOCUS_NONE     "0"
344 #define STREAM_FOCUS_PLAYBACK "1"
345 #define STREAM_FOCUS_CAPTURE  "2"
346
347 typedef enum _process_stream_result {
348     PROCESS_STREAM_RESULT_OK,
349     PROCESS_STREAM_RESULT_STOP,
350     PROCESS_STREAM_RESULT_SKIP,
351 } process_stream_result_t;
352
353 typedef enum _process_command_type {
354     PROCESS_COMMAND_PREPARE,
355     PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED,
356     PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED,
357     PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED,
358     PROCESS_COMMAND_UPDATE_VOLUME,
359     PROCESS_COMMAND_ADD_PARENT_ID,
360     PROCESS_COMMAND_REMOVE_PARENT_ID,
361     PROCESS_COMMAND_UPDATE_BUFFER_ATTR,
362 } process_command_type_t;
363
364 typedef enum _notify_command_type {
365     NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
366     NOTIFY_COMMAND_CHANGE_ROUTE_START,
367     NOTIFY_COMMAND_CHANGE_ROUTE_END,
368     NOTIFY_COMMAND_UPDATE_ROUTE_OPTION,
369     NOTIFY_COMMAND_INFORM_STREAM_CONNECTED,
370     NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED,
371 } notify_command_type_t;
372
373 const char* process_command_type_str[] = {
374     "PREPARE",
375     "CHANGE_ROUTE_BY_STREAM_STARTED",
376     "CHANGE_ROUTE_BY_STREAM_ENDED",
377     "CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED",
378     "UPDATE_VOLUME",
379     "ADD_PARENT_ID",
380     "REMOVE_PARENT_ID",
381     "UPDATE_BUFFER_ATTR",
382 };
383
384 const char* notify_command_type_str[] = {
385     "SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT",
386     "CHANGE_ROUTE_START",
387     "CHANGE_ROUTE_END",
388     "UPDATE_ROUTE_OPTION",
389     "INFORM_STREAM_CONNECTED",
390     "INFORM_STREAM_DISCONNECTED",
391 };
392
393 #define STREAM_MAP_FILE "/etc/pulse/stream-map.json"
394 #define STREAM_MAP_VOLUMES "volumes"
395 #define STREAM_MAP_VOLUME_TYPE "type"
396 #define STREAM_MAP_VOLUME_IS_FOR_HAL "is-hal-volume"
397 #define STREAM_MAP_LATENCIES "latencies"
398 #define STREAM_MAP_LATENCY_TYPE "type"
399 #define STREAM_MAP_LATENCY_FRAGSIZE_MS "fragsize-ms"
400 #define STREAM_MAP_LATENCY_TLENGTH_MS "tlength-ms"
401 #define STREAM_MAP_LATENCY_MINREQ_MS "minreq-ms"
402 #define STREAM_MAP_LATENCY_PREBUF_MS "prebuf-ms"
403 #define STREAM_MAP_LATENCY_MAXLENGTH "maxlength"
404 #define STREAM_MAP_STREAMS "streams"
405 #define STREAM_MAP_STREAM_ROLE "role"
406 #define STREAM_MAP_STREAM_PRIORITY "priority"
407 #define STREAM_MAP_STREAM_ROUTE_TYPE "route-type"
408 #define STREAM_MAP_STREAM_DIRECTIONS "directions"
409 #define STREAM_MAP_STREAM_VOLUME_TYPES "volume-types"
410 #define STREAM_MAP_STREAM_VOLUME_TYPE_IN "in"
411 #define STREAM_MAP_STREAM_VOLUME_TYPE_OUT "out"
412 #define STREAM_MAP_STREAM_CAPTURE_VOLUME_TYPE "capture-volume-type"
413 #define STREAM_MAP_STREAM_PLAYBACK_VOLUME_TYPE "playback-volume-type"
414 #define STREAM_MAP_STREAM_AVAIL_IN_DEVICES "avail-in-devices"
415 #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices"
416 #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks"
417
418 typedef struct _stream_parent {
419     pa_idxset *idx_sink_inputs;
420     pa_idxset *idx_source_outputs;
421     pa_idxset *idx_route_in_devices;
422     pa_idxset *idx_route_out_devices;
423     focus_acquired_status_t focus_status;
424 } stream_parent;
425
426 #define AVAIL_DEVICES_MAX 16
427 #define AVAIL_FRAMEWORKS_MAX 16
428 #define AVAIL_STREAMS_MAX 32
429 typedef struct _stream_info_per_type {
430     int32_t priority;
431     int32_t route_type;
432     int32_t num_of_in_devices;
433     int32_t num_of_out_devices;
434     int32_t num_of_frameworks;
435     const char *volume_types[STREAM_DIRECTION_MAX];
436     const char *avail_in_devices[AVAIL_DEVICES_MAX];
437     const char *avail_out_devices[AVAIL_DEVICES_MAX];
438     const char *avail_frameworks[AVAIL_FRAMEWORKS_MAX];
439 } stream_info_per_type;
440 typedef struct _stream_list {
441     int32_t num_of_streams;
442     char *types[AVAIL_STREAMS_MAX];
443     int32_t priorities[AVAIL_STREAMS_MAX];
444 } stream_list;
445 typedef struct _stream_route_option {
446     const char *name;
447     int32_t value;
448 } stream_route_option;
449
450 #define CONVERT_TO_DEVICE_DIRECTION(stream_type) \
451     ((stream_type == STREAM_SINK_INPUT) ? DM_DEVICE_DIRECTION_OUT : DM_DEVICE_DIRECTION_IN)
452
453 #define CONVERT_TO_DEVICE_ROLE(x_stream_role, x_device_role) { \
454     pa_assert(x_stream_role); \
455     if (pa_streq(x_stream_role, STREAM_ROLE_CALL_VOICE)) \
456         x_device_role = DEVICE_ROLE_CALL_VOICE; \
457     else if (pa_streq(x_stream_role, STREAM_ROLE_CALL_VIDEO)) \
458         x_device_role = DEVICE_ROLE_CALL_VIDEO; \
459     else if (pa_streq(x_stream_role, STREAM_ROLE_VOIP)) \
460         x_device_role = DEVICE_ROLE_VOIP; \
461     else \
462         x_device_role = DEVICE_ROLE_NORMAL; \
463 } \
464
465 #define SET_NEW_DATA_STREAM_TO_NULL_SINK_SOURCE(x_m, x_stream, x_stream_type) { \
466     pa_sink *null_sink; \
467     pa_source *null_source; \
468     if (x_stream_type == STREAM_SINK_INPUT && \
469         (!((pa_sink_input_new_data*)x_stream)->sink)) { \
470         if ((null_sink = (pa_sink*)pa_namereg_get(x_m->core, SINK_NAME_NULL, PA_NAMEREG_SINK))) \
471             ((pa_sink_input_new_data*)x_stream)->sink = null_sink; \
472         else \
473             pa_log_warn("could not get null_sink"); \
474     } else if (x_stream_type == STREAM_SOURCE_OUTPUT && \
475                (!((pa_source_output_new_data*)x_stream)->source)) { \
476         if ((null_source = (pa_source*)pa_namereg_get(x_m->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE))) \
477             ((pa_source_output_new_data*)x_stream)->source = null_source; \
478         else \
479             pa_log_warn("could not get null_source"); \
480     } \
481 } \
482
483 static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, bool is_new_data, void *user_data);
484 static process_stream_result_t process_stream(pa_stream_manager *m, void *stream, stream_type_t type, process_command_type_t command, bool is_new_data);
485
486 static int32_t get_available_streams(pa_stream_manager *m, stream_list *list) {
487     void *state = NULL;
488     stream_info *s = NULL;
489     char *role = NULL;
490     int i = 0;
491
492     pa_log_info("get_available_streams");
493     if (m->stream_infos) {
494         while ((s = pa_hashmap_iterate(m->stream_infos, &state, (const void**)&role))) {
495             if (i < AVAIL_STREAMS_MAX) {
496                 list->priorities[i] = s->priority;
497                 list->types[i++] = role;
498                 pa_log_debug("  [%d] stream_type[%s], priority[%d]", i-1, role, s->priority);
499             } else {
500                 pa_log_error("  out of range, [%d]", i);
501                 break;
502             }
503         }
504         list->num_of_streams = i;
505         pa_log_debug("  num_of_streams[%d]", i);
506     } else {
507         pa_log_error("stream_map is not initialized..");
508         return -1;
509     }
510     return 0;
511 }
512
513 static int32_t get_stream_info(pa_stream_manager *m, const char *stream_role, stream_info_per_type *info) {
514     uint32_t idx = 0;
515     char *name;
516     int i = 0;
517     stream_info *s = NULL;
518     pa_log_info("get_stream_info : role[%s]", stream_role);
519     if (m->stream_infos) {
520         s = pa_hashmap_get(m->stream_infos, stream_role);
521         if (s) {
522             info->priority = s->priority;
523             info->route_type = s->route_type;
524             for (i = 0; i < STREAM_DIRECTION_MAX; i++) {
525                 pa_log_debug("  volume_types[%d] name : %s", i, s->volume_types[i]);
526                 info->volume_types[i] = s->volume_types[i];
527             }
528             PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx) {
529                 pa_log_debug("  avail-in-device[%d] name  : %s", idx, name);
530                 if (idx < AVAIL_DEVICES_MAX)
531                     info->avail_in_devices[idx] = name;
532                 else
533                     pa_log_error("  avail-in-devices, out of range, [%d]", idx);
534             }
535             info->num_of_in_devices = pa_idxset_size(s->idx_avail_in_devices);
536             PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx) {
537                 pa_log_debug("  avail-out-device[%d] name  : %s", idx, name);
538                 if (idx < AVAIL_DEVICES_MAX)
539                     info->avail_out_devices[idx] = name;
540                 else
541                     pa_log_error("  avail-out-devices, out of range, [%d]", idx);
542             }
543             info->num_of_out_devices = pa_idxset_size(s->idx_avail_out_devices);
544             PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx) {
545                 pa_log_debug("  avail-frameworks[%d] name  : %s", idx, name);
546                 if (idx < AVAIL_FRAMEWORKS_MAX)
547                     info->avail_frameworks[idx] = name;
548                 else
549                     pa_log_error("  avail-frameworks, out of range, [%d]", idx);
550             }
551             info->num_of_frameworks = pa_idxset_size(s->idx_avail_frameworks);
552         } else {
553             /* set variables for error */
554             info->priority = -1;
555             info->num_of_in_devices = info->num_of_out_devices = info->num_of_frameworks = 1;
556             info->volume_types[0] = info->volume_types[1] = dbus_str_none;
557             info->avail_in_devices[0] = dbus_str_none;
558             info->avail_out_devices[0] = dbus_str_none;
559             info->avail_frameworks[0] = dbus_str_none;
560             pa_log_error("could not find the stream_role : %s", stream_role);
561             return -1;
562         }
563     } else {
564         pa_log_error("stream_map is not initialized..");
565         return -1;
566     }
567     return 0;
568 }
569
570 #ifdef HAVE_DBUS
571 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
572     const char *xml = STREAM_MGR_INTROSPECT_XML;
573     DBusMessage *r = NULL;
574
575     pa_assert(conn);
576     pa_assert(msg);
577     pa_assert(userdata);
578
579     pa_assert_se(r = dbus_message_new_method_return(msg));
580     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
581
582     if (r) {
583         pa_assert_se(dbus_connection_send((conn), r, NULL));
584         dbus_message_unref(r);
585     }
586
587     return DBUS_HANDLER_RESULT_HANDLED;
588 }
589
590 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
591     stream_list list;
592     DBusMessage *reply = NULL;
593     DBusMessageIter msg_iter;
594     pa_stream_manager *m = (pa_stream_manager*)userdata;
595
596     pa_assert(conn);
597     pa_assert(msg);
598     pa_assert(m);
599
600     pa_assert_se(dbus_message_get_args(msg, NULL,
601                                        DBUS_TYPE_INVALID));
602     pa_log_info("handle_get_stream_list() dbus method is called");
603
604     memset(&list, 0, sizeof(stream_list));
605     pa_assert_se((reply = dbus_message_new_method_return(msg)));
606     dbus_message_iter_init_append(reply, &msg_iter);
607     if (!get_available_streams(m, &list)) {
608         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
609         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
610     } else {
611         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
612         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, NULL, 0);
613     }
614     pa_assert_se(dbus_connection_send(conn, reply, NULL));
615     dbus_message_unref(reply);
616 }
617
618 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
619     char *type;
620     stream_info_per_type info;
621     DBusMessage *reply = NULL;
622     DBusMessageIter msg_iter;
623     pa_stream_manager *m = (pa_stream_manager*)userdata;
624
625     pa_assert(conn);
626     pa_assert(msg);
627     pa_assert(m);
628
629     pa_assert_se(dbus_message_get_args(msg, NULL,
630                                        DBUS_TYPE_STRING, &type,
631                                        DBUS_TYPE_INVALID));
632     pa_log_info("handle_get_stream_info(), type[%s]", type);
633
634     memset(&info, 0, sizeof(stream_info_per_type));
635     pa_assert_se((reply = dbus_message_new_method_return(msg)));
636     dbus_message_iter_init_append(reply, &msg_iter);
637     get_stream_info(m, type, &info);
638     pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
639     pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
640     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.volume_types, STREAM_DIRECTION_MAX);
641     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
642     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
643     pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
644
645     pa_assert_se(dbus_connection_send(conn, reply, NULL));
646     dbus_message_unref(reply);
647 }
648
649 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
650     uint32_t id = 0;
651     int i = 0;
652     uint32_t *in_device_list = NULL;
653     uint32_t *out_device_list = NULL;
654     int list_len_in = 0;
655     int list_len_out = 0;
656     uint32_t idx = 0;
657     uint32_t *device_id = NULL;
658     void *stream = NULL;
659     stream_parent *sp = NULL;
660     const char *route_type_str = NULL;
661     stream_route_type_t route_type;
662     DBusMessage *reply = NULL;
663     pa_stream_manager *m = (pa_stream_manager*)userdata;
664
665     pa_assert(conn);
666     pa_assert(msg);
667     pa_assert(m);
668
669     pa_assert_se(dbus_message_get_args(msg, NULL,
670                                        DBUS_TYPE_UINT32, &id,
671                                        DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &in_device_list, &list_len_in,
672                                        DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &out_device_list, &list_len_out,
673                                        DBUS_TYPE_INVALID));
674     pa_log_info("handle_set_stream_route_devices(), id[%u], in_device_list[%p]:length[%d], out_device_list[%p]:length[%d]",
675         id, in_device_list, list_len_in, out_device_list, list_len_out);
676
677     pa_assert_se((reply = dbus_message_new_method_return(msg)));
678
679     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
680     if (sp) {
681         if (!in_device_list && !out_device_list) {
682             pa_log_error("invalid arguments");
683             goto fail;
684         }
685
686         if (sp->idx_route_in_devices) {
687             PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, idx) {
688                 pa_idxset_remove_by_data(sp->idx_route_in_devices, device_id, NULL);
689                 pa_xfree(device_id);
690             }
691             if (in_device_list && list_len_in) {
692                 for (i = 0; i < list_len_in; i++) {
693                     pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(uint32_t)), NULL);
694                     pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
695                 }
696             }
697             PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
698                 /* find route type of stream */
699                 route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
700                 if (route_type_str) {
701                     pa_log_debug(" -- the route type of source_output that belongs to this parent id[%u] is [%s]", id, route_type_str);
702                     break;
703                 }
704             }
705             /* if any stream that belongs to this id has been activated, do notify right away */
706             if (IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
707                 PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
708                     pa_log_debug(" -- source_output[%p] belongs to this parent id[%u], do notify for the select proper source", stream, id);
709                     do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, STREAM_SOURCE_OUTPUT, false, stream);
710                 }
711             } else if (m->cur_highest_priority.source_output) {
712                 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
713                     pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the route change",
714                             (m->cur_highest_priority.source_output)->index, id);
715                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, false, m->cur_highest_priority.source_output);
716                 }
717             }
718         } else {
719             pa_log_error("failed to update, idx_route_in_devices[%p]", sp->idx_route_in_devices);
720             goto fail;
721         }
722
723         if (sp->idx_route_out_devices) {
724             PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, idx) {
725                 pa_idxset_remove_by_data(sp->idx_route_out_devices, device_id, NULL);
726                 pa_xfree(device_id);
727             }
728             if (out_device_list && list_len_out) {
729                 for (i = 0; i < list_len_out; i++) {
730                     pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(uint32_t)), NULL);
731                     pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
732                 }
733             }
734             PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
735                 /* find route type of stream */
736                 route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
737                 if (route_type_str) {
738                     pa_log_debug(" -- the route type of sink_input that belongs to this parent id[%u] is [%s]", id, route_type_str);
739                     break;
740                 }
741             }
742             /* if any stream that belongs to this id has been activated, do notify right away */
743             if (IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
744                 PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
745                     pa_log_debug(" -- sink_input[%p] belongs to this parent id[%u], do notify for the select proper sink", stream, id);
746                     do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, STREAM_SINK_INPUT, false, stream);
747                 }
748             } else if (m->cur_highest_priority.sink_input) {
749                 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
750                     pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the route change",
751                             (m->cur_highest_priority.sink_input)->index, id);
752                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
753                 }
754             }
755         } else {
756             pa_log_error("failed to update, idx_route_out_devices[%p]", sp->idx_route_out_devices);
757             goto fail;
758         }
759         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
760     } else {
761         pa_log_error("could not find matching client for this parent_id[%u]", id);
762         goto fail;
763     }
764
765     pa_assert_se(dbus_connection_send(conn, reply, NULL));
766     dbus_message_unref(reply);
767     return;
768 fail:
769     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
770     pa_assert_se(dbus_connection_send(conn, reply, NULL));
771     dbus_message_unref(reply);
772 }
773
774 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
775     uint32_t id = 0;
776     const char *name = NULL;
777     int32_t value = 0;
778     bool updated = false;
779     stream_parent *sp = NULL;
780     stream_route_option route_option;
781     DBusMessage *reply = NULL;
782     pa_stream_manager *m = (pa_stream_manager*)userdata;
783
784     pa_assert(conn);
785     pa_assert(msg);
786     pa_assert(m);
787
788     pa_assert_se(dbus_message_get_args(msg, NULL,
789                                        DBUS_TYPE_UINT32, &id,
790                                        DBUS_TYPE_STRING, &name,
791                                        DBUS_TYPE_INT32, &value,
792                                        DBUS_TYPE_INVALID));
793     pa_log_info("handle_set_stream_route_option(), name[%s], value[%d]", name, value);
794
795     pa_assert_se((reply = dbus_message_new_method_return(msg)));
796
797     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
798     if (sp) {
799         if (name) {
800             route_option.name = name;
801             route_option.value = value;
802
803             /* if any stream that belongs to this id has been activated, do notify right away */
804             if (m->cur_highest_priority.sink_input) {
805                 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
806                     pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
807                         (m->cur_highest_priority.sink_input)->index, id);
808                     do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, false, &route_option);
809                     updated = true;
810                 }
811             }
812             if (m->cur_highest_priority.source_output) {
813                 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
814                     pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
815                         (m->cur_highest_priority.source_output)->index, id);
816                     do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SOURCE_OUTPUT, false, &route_option);
817                     updated = true;
818                 }
819             }
820             if (!updated) {
821                 pa_log_error("invalid state");
822                 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
823             } else
824                 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
825         } else {
826             pa_log_error("invalid arguments");
827             pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
828         }
829
830     } else {
831         pa_log_error("could not find matching client for this parent_id[%u]", id);
832         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
833     }
834
835     pa_assert_se(dbus_connection_send(conn, reply, NULL));
836     dbus_message_unref(reply);
837 }
838
839 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
840     const char *direction = NULL;
841     const char *type = NULL;
842     uint32_t level = 0;
843     stream_type_t stream_type = STREAM_SINK_INPUT;
844     DBusMessage *reply = NULL;
845     pa_stream_manager *m = (pa_stream_manager*)userdata;
846     int ret = 0;
847
848     pa_assert(conn);
849     pa_assert(msg);
850     pa_assert(m);
851
852     pa_assert_se(dbus_message_get_args(msg, NULL,
853                                        DBUS_TYPE_STRING, &direction,
854                                        DBUS_TYPE_STRING, &type,
855                                        DBUS_TYPE_UINT32, &level,
856                                        DBUS_TYPE_INVALID));
857     pa_log_info("handle_set_volume_level(), direction[%s], type[%s], level[%u]", direction, type, level);
858
859     pa_assert_se((reply = dbus_message_new_method_return(msg)));
860
861     if (pa_streq(direction, "in"))
862         stream_type = STREAM_SOURCE_OUTPUT;
863     else if (pa_streq(direction, "out"))
864         stream_type = STREAM_SINK_INPUT;
865     else {
866         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
867         ret = -1;
868         goto finish;
869     }
870
871     if ((ret = set_volume_level_by_type(m, stream_type, type, level)))
872         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
873     else
874         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
875
876 finish:
877     pa_assert_se(dbus_connection_send(conn, reply, NULL));
878     dbus_message_unref(reply);
879
880     if (!ret)
881         send_volume_changed_signal(conn, direction, type, level);
882 }
883
884 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
885     const char *direction = NULL;
886     const char *type = NULL;
887     uint32_t level = 0;
888     stream_type_t stream_type = STREAM_SINK_INPUT;
889     DBusMessage *reply = NULL;
890     pa_stream_manager *m = (pa_stream_manager*)userdata;
891
892     pa_assert(conn);
893     pa_assert(msg);
894     pa_assert(m);
895
896     pa_assert_se(dbus_message_get_args(msg, NULL,
897                                        DBUS_TYPE_STRING, &direction,
898                                        DBUS_TYPE_STRING, &type,
899                                        DBUS_TYPE_INVALID));
900     pa_log_info("handle_get_volume_level(), direction(%s), type(%s)", direction, type);
901
902     pa_assert_se((reply = dbus_message_new_method_return(msg)));
903
904     if (pa_streq(direction, "in"))
905         stream_type = STREAM_SOURCE_OUTPUT;
906     else if (pa_streq(direction, "out"))
907         stream_type = STREAM_SINK_INPUT;
908     else {
909         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
910         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
911         goto finish;
912     }
913
914     if (get_volume_level_by_type(m, GET_VOLUME_CURRENT_LEVEL, stream_type, type, &level)) {
915         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
916         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
917     } else {
918         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
919         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
920     }
921
922 finish:
923     pa_assert_se(dbus_connection_send(conn, reply, NULL));
924     dbus_message_unref(reply);
925 }
926
927 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
928     const char *direction = NULL;
929     const char *type = NULL;
930     uint32_t level = 0;
931     stream_type_t stream_type = STREAM_SINK_INPUT;
932     DBusMessage *reply = NULL;
933     pa_stream_manager *m = (pa_stream_manager*)userdata;
934
935     pa_assert(conn);
936     pa_assert(msg);
937     pa_assert(m);
938
939     pa_assert_se(dbus_message_get_args(msg, NULL,
940                                        DBUS_TYPE_STRING, &direction,
941                                        DBUS_TYPE_STRING, &type,
942                                        DBUS_TYPE_INVALID));
943     pa_log_info("handle_get_volume_max_level(), direction[%s], type[%s]", direction, type);
944
945     pa_assert_se((reply = dbus_message_new_method_return(msg)));
946
947     if (pa_streq(direction, "in"))
948         stream_type = STREAM_SOURCE_OUTPUT;
949     else if (pa_streq(direction, "out"))
950         stream_type = STREAM_SINK_INPUT;
951     else {
952         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
953         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
954         goto finish;
955     }
956
957     if (get_volume_level_by_type(m, GET_VOLUME_MAX_LEVEL, stream_type, type, &level)) {
958         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
959         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
960     } else {
961         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
962         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
963     }
964 finish:
965     pa_assert_se(dbus_connection_send(conn, reply, NULL));
966     dbus_message_unref(reply);
967 }
968
969 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
970     const char *direction = NULL;
971     const char *type = NULL;
972     uint32_t do_mute = 0;
973     stream_type_t stream_type = STREAM_SINK_INPUT;
974     DBusMessage *reply = NULL;
975     pa_stream_manager *m = (pa_stream_manager*)userdata;
976
977     pa_assert(conn);
978     pa_assert(msg);
979     pa_assert(m);
980
981     pa_assert_se(dbus_message_get_args(msg, NULL,
982                                        DBUS_TYPE_STRING, &direction,
983                                        DBUS_TYPE_STRING, &type,
984                                        DBUS_TYPE_UINT32, &do_mute,
985                                        DBUS_TYPE_INVALID));
986     pa_log_info("handle_set_volume_mute(), direction[%s], type[%s], do_mute[%u]", direction, type, do_mute);
987
988     pa_assert_se((reply = dbus_message_new_method_return(msg)));
989
990     if (pa_streq(direction, "in"))
991         stream_type = STREAM_SOURCE_OUTPUT;
992     else if (pa_streq(direction, "out"))
993         stream_type = STREAM_SINK_INPUT;
994     else {
995         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
996         goto finish;
997     }
998
999     if (set_volume_mute_by_type(m, stream_type, type, (bool)do_mute))
1000         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
1001     else
1002         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
1003
1004 finish:
1005     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1006     dbus_message_unref(reply);
1007 }
1008
1009 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1010     const char *direction = NULL;
1011     const char *type = NULL;
1012     uint32_t is_muted = 0;
1013     stream_type_t stream_type = STREAM_SINK_INPUT;
1014     DBusMessage *reply = NULL;
1015     pa_stream_manager *m = (pa_stream_manager*)userdata;
1016
1017     pa_assert(conn);
1018     pa_assert(msg);
1019     pa_assert(m);
1020
1021     pa_assert_se(dbus_message_get_args(msg, NULL,
1022                                        DBUS_TYPE_STRING, &direction,
1023                                        DBUS_TYPE_STRING, &type,
1024                                        DBUS_TYPE_INVALID));
1025     pa_log_info("handle_get_volume_mute(), direction[%s], type[%s]", direction, type);
1026
1027     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1028
1029     if (pa_streq(direction, "in"))
1030         stream_type = STREAM_SOURCE_OUTPUT;
1031     else if (pa_streq(direction, "out"))
1032         stream_type = STREAM_SINK_INPUT;
1033     else {
1034         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
1035         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
1036         goto fail;
1037     }
1038
1039     if (get_volume_mute_by_type(m, stream_type, type, (bool*)&is_muted)) {
1040         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
1041         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
1042     } else {
1043         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
1044         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
1045     }
1046
1047 fail:
1048     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1049     dbus_message_unref(reply);
1050 }
1051
1052 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1053     const char *direction = NULL;
1054     const char *type = NULL;
1055     void *s = NULL;
1056     stream_type_t stream_type = STREAM_SINK_INPUT;
1057     DBusMessage *reply = NULL;
1058     pa_stream_manager *m = (pa_stream_manager*)userdata;
1059     uint32_t idx = 0;
1060
1061     pa_assert(conn);
1062     pa_assert(msg);
1063     pa_assert(m);
1064
1065     pa_assert_se(dbus_message_get_args(msg, NULL,
1066                                        DBUS_TYPE_STRING, &direction,
1067                                        DBUS_TYPE_INVALID));
1068     pa_log_info("handle_get_current_volume_type(), direction[%s]", direction);
1069
1070     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1071
1072     if (pa_streq(direction, "in"))
1073         stream_type = STREAM_SOURCE_OUTPUT;
1074     else if (pa_streq(direction, "out"))
1075         stream_type = STREAM_SINK_INPUT;
1076     else {
1077         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1078         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
1079         goto fail;
1080     }
1081
1082     if ((s = (stream_type == STREAM_SINK_INPUT) ? (void*)(m->cur_highest_priority.sink_input) : (void*)(m->cur_highest_priority.source_output)))
1083         type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
1084     else {
1085         if (pa_idxset_size(m->core->sink_inputs)) {
1086             PA_IDXSET_FOREACH(s, m->core->sink_inputs, idx) {
1087                 if ((type = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE)))
1088                     break;
1089             }
1090         }
1091     }
1092
1093     if (type) {
1094         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID));
1095         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
1096     } else {
1097         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
1098         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR_NO_STREAM], DBUS_TYPE_INVALID));
1099     }
1100
1101 fail:
1102     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1103     dbus_message_unref(reply);
1104 }
1105
1106 static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1107     uint32_t id = 0;
1108     uint32_t idx = 0;
1109     uint32_t count = 0;
1110     uint32_t acquired_focus_status = 0;
1111     stream_parent *sp = NULL;
1112     void *stream = NULL;
1113     DBusMessage *reply = NULL;
1114     pa_stream_manager *m = (pa_stream_manager*)userdata;
1115     int prev_status = STREAM_FOCUS_ACQUIRED_NONE;
1116
1117     pa_assert(conn);
1118     pa_assert(msg);
1119     pa_assert(m);
1120
1121     pa_assert_se(dbus_message_get_args(msg, NULL,
1122                                        DBUS_TYPE_UINT32, &id,
1123                                        DBUS_TYPE_UINT32, &acquired_focus_status,
1124                                        DBUS_TYPE_INVALID));
1125     pa_log_info("handle_update_focus_status(), id[%u], acquired_focus_status[0x%x]", id, acquired_focus_status);
1126
1127     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1128
1129     if ((sp = pa_hashmap_get(m->stream_parents, (const void*)id))) {
1130         if (sp->focus_status != acquired_focus_status) {
1131             /* need to update */
1132             prev_status = sp->focus_status;
1133             sp->focus_status = acquired_focus_status;
1134             if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_PLAYBACK) && sp->idx_sink_inputs) {
1135                 count = pa_idxset_size(sp->idx_sink_inputs);
1136                 PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
1137                     pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1138                                      GET_FOCUS_STATUS(sp->focus_status, STREAM_SINK_INPUT) ? STREAM_FOCUS_PLAYBACK : STREAM_FOCUS_NONE);
1139                     if (--count == 0)
1140                         process_stream(m, stream, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1141                 }
1142             }
1143             if (((prev_status ^ sp->focus_status) & STREAM_FOCUS_ACQUIRED_CAPTURE) && sp->idx_source_outputs) {
1144                 count = pa_idxset_size(sp->idx_source_outputs);
1145                 PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
1146                     pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_FOCUS_STATUS,
1147                                      GET_FOCUS_STATUS(sp->focus_status, STREAM_SOURCE_OUTPUT) ? STREAM_FOCUS_CAPTURE : STREAM_FOCUS_NONE);
1148                     if (--count == 0)
1149                         process_stream(m, stream, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
1150                 }
1151             }
1152         } else
1153             pa_log_debug("same as before, skip updating focus status[0x%x]", acquired_focus_status);
1154
1155     } else {
1156         pa_log_error("could not find matching client for this parent_id[%u]", id);
1157         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
1158         goto fail;
1159     }
1160     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
1161 fail:
1162     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1163     dbus_message_unref(reply);
1164 }
1165
1166 static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1167     const char *name;
1168     uint32_t value = 0;
1169     DBusMessage *reply = NULL;
1170     pa_stream_manager *m = (pa_stream_manager*)userdata;
1171
1172     pa_assert(conn);
1173     pa_assert(msg);
1174     pa_assert(m);
1175
1176     pa_assert_se(dbus_message_get_args(msg, NULL,
1177                                        DBUS_TYPE_STRING, &name,
1178                                        DBUS_TYPE_UINT32, &value,
1179                                        DBUS_TYPE_INVALID));
1180     pa_log_info("handle_update_restriction(), name[%s], value[%u]", name, value);
1181
1182     pa_assert_se((reply = dbus_message_new_method_return(msg)));
1183
1184     if (handle_restrictions(m, name, value) < 0) {
1185         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
1186         goto fail;
1187     }
1188
1189     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
1190 fail:
1191     pa_assert_se(dbus_connection_send(conn, reply, NULL));
1192     dbus_message_unref(reply);
1193 }
1194
1195 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
1196         int idx = 0;
1197     pa_stream_manager *m = (pa_stream_manager*)userdata;
1198
1199     pa_assert(conn);
1200     pa_assert(msg);
1201     pa_assert(m);
1202
1203     for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
1204         if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name)) {
1205             pa_log_debug("Message signature [%s] (Expected [%s])", dbus_message_get_signature(msg), signature_args_for_in[idx]);
1206             if (pa_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
1207                 method_handlers[idx].receive_cb(conn, msg, userdata);
1208                 return DBUS_HANDLER_RESULT_HANDLED;
1209             } else {
1210                 pa_log_warn("Wrong Argument Signature");
1211                 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE,  "Wrong Signature, Expected %s", signature_args_for_in[idx]);
1212                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1213             }
1214         }
1215     }
1216
1217     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1218 }
1219
1220 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
1221     pa_stream_manager *u = (pa_stream_manager*)userdata;
1222     const char *path, *interface, *member;
1223
1224     pa_assert(c);
1225     pa_assert(m);
1226     pa_assert(u);
1227
1228     path = dbus_message_get_path(m);
1229     interface = dbus_message_get_interface(m);
1230     member = dbus_message_get_member(m);
1231
1232     pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
1233
1234     if (!pa_streq(path, STREAM_MANAGER_OBJECT_PATH))
1235         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1236
1237     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1238         return handle_introspect(c, m, u);
1239     } else {
1240         return handle_methods(c, m, u);
1241     }
1242
1243     return DBUS_HANDLER_RESULT_HANDLED;
1244 }
1245
1246 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level) {
1247     DBusMessage *signal_msg;
1248     DBusMessageIter msg_iter;
1249
1250     pa_assert(conn);
1251     pa_assert(direction);
1252     pa_assert(volume_type);
1253
1254     pa_log_debug("Send volume changed signal: direction(%s), type(%s), level(%d)", direction, volume_type, volume_level);
1255
1256     pa_assert_se(signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED));
1257     dbus_message_iter_init_append(signal_msg, &msg_iter);
1258
1259     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &direction);
1260     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &volume_type);
1261     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &volume_level);
1262
1263     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
1264     dbus_message_unref(signal_msg);
1265     return;
1266 }
1267
1268 static void send_command_signal(DBusConnection *conn, const char *name, int value) {
1269     DBusMessage *signal_msg;
1270     DBusMessageIter msg_iter;
1271
1272     pa_assert(conn);
1273     pa_assert(name);
1274
1275     pa_log_debug("Send command signal: name(%s), value(%d)", name, value);
1276
1277     pa_assert_se(signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_COMMAND));
1278     dbus_message_iter_init_append(signal_msg, &msg_iter);
1279
1280     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
1281     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &value);
1282
1283     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
1284     dbus_message_unref(signal_msg);
1285 }
1286 #endif
1287
1288 static int32_t convert_route_type(stream_route_type_t *route_type, const char *route_type_string) {
1289     int ret = 0;
1290
1291     pa_assert(route_type);
1292     pa_assert(route_type_string);
1293
1294     if (pa_streq("auto", route_type_string))
1295         *route_type = STREAM_ROUTE_TYPE_AUTO;
1296     else if (pa_streq("auto-last-connected", route_type_string))
1297         *route_type = STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED;
1298     else if (pa_streq("auto-all", route_type_string))
1299         *route_type = STREAM_ROUTE_TYPE_AUTO_ALL;
1300     else if (pa_streq("manual", route_type_string))
1301         *route_type = STREAM_ROUTE_TYPE_MANUAL;
1302     else if (pa_streq("manual-ext", route_type_string))
1303         *route_type = STREAM_ROUTE_TYPE_MANUAL_EXT;
1304     else {
1305         ret = -1;
1306         pa_log_error("Not supported route_type(%s)", route_type_string);
1307     }
1308
1309     return ret;
1310 }
1311
1312 static int32_t get_route_type(void *stream, stream_type_t stream_type, bool is_new_data, stream_route_type_t *stream_route_type) {
1313     const char *route_type_str = NULL;
1314
1315     pa_assert(stream);
1316     pa_assert(stream_route_type);
1317
1318     if (is_new_data)
1319         route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, stream_type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
1320     else
1321         route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, stream_type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
1322     if (!route_type_str) {
1323         pa_log_warn("could not get route type from the stream(%p)", stream);
1324         return -1;
1325      }
1326
1327     if (pa_atoi(route_type_str, (int32_t*)stream_route_type)) {
1328         pa_log_error("could not convert route_type_str(%s) to int", route_type_str);
1329         return -1;
1330     }
1331
1332     return 0;
1333 }
1334
1335 static void dump_stream_map(pa_stream_manager *m) {
1336     stream_info *s = NULL;
1337     const char *role = NULL;
1338     char *name = NULL;
1339     void *state = NULL;
1340     uint32_t idx = 0;
1341     pa_assert(m);
1342     pa_log_debug("==========[START stream-map dump]==========");
1343     while (m->stream_infos && (s = pa_hashmap_iterate(m->stream_infos, &state, (const void **)&role))) {
1344         pa_log_debug("[role : %s]", role);
1345         pa_log_debug("  - priority   : %d", s->priority);
1346         pa_log_debug("  - route-type : %d (0:auto,1:auto-last-conn,2:auto-all,3:manual,4:manual-ext)", s->route_type);
1347         pa_log_debug("  - volume-types : in[%s], out[%s]", s->volume_types[STREAM_DIRECTION_IN], s->volume_types[STREAM_DIRECTION_OUT]);
1348         pa_log_debug("  - avail-in-devices");
1349         PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx)
1350             pa_log_debug("      name[%d]  : %s", idx, name);
1351         pa_log_debug("  - avail-out-devices");
1352         PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx)
1353             pa_log_debug("      name[%d]  : %s", idx, name);
1354         pa_log_debug("  - avail-frameworks");
1355         PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx)
1356             pa_log_debug("      name[%d]  : %s", idx, name);
1357     }
1358     pa_log_debug("===========[END stream-map dump]===========");
1359 }
1360
1361 static int init_stream_map(pa_stream_manager *m) {
1362     volume_info *v;
1363     stream_info *s;
1364     latency_info *l;
1365     json_object *o;
1366     json_object *array_o;
1367     json_object *array_item_o;
1368     json_object *item_o;
1369     json_object *sub_array_o;
1370     int array_length = 0;
1371     int sub_array_length = 0;
1372     const char *type = NULL;
1373     const char *role = NULL;
1374     int i = 0, j = 0;
1375     json_object *out_device_o;
1376     json_object *in_device_o;
1377     json_object *framework_o;
1378     void *state = NULL;
1379
1380     pa_assert(m);
1381
1382     o = json_object_from_file(STREAM_MAP_FILE);
1383     if (is_error(o)) {
1384         pa_log_error("Read stream-map file(%s) failed", STREAM_MAP_FILE);
1385         return -1;
1386     }
1387
1388     /* Latencies */
1389     m->latency_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1390     if (json_object_object_get_ex(o, STREAM_MAP_LATENCIES, &array_o) && json_object_is_type(array_o, json_type_array)) {
1391         array_length = json_object_array_length(array_o);
1392         for (i = 0; i < array_length; i++) {
1393             if ((array_item_o = json_object_array_get_idx(array_o, i)) && json_object_is_type(array_item_o, json_type_object)) {
1394                 l = pa_xmalloc0(sizeof(latency_info));
1395                 pa_log_debug("latency found [%d]", i);
1396                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_TYPE, &item_o) && json_object_is_type(item_o, json_type_string)) {
1397                     type = json_object_get_string(item_o);
1398                     pa_log_debug(" - type : %s", type);
1399                 } else {
1400                     pa_log_error("Get type failed");
1401                     goto fail;
1402                 }
1403                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_FRAGSIZE_MS, &item_o) && json_object_is_type(item_o, json_type_int)) {
1404                     l->fragsize_ms = json_object_get_int(item_o);
1405                     pa_log_debug(" - fragsize-ms : %d", l->fragsize_ms);
1406                 } else {
1407                     pa_log_error("Get fragsize-ms failed");
1408                     goto fail;
1409                 }
1410                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_TLENGTH_MS, &item_o) && json_object_is_type(item_o, json_type_int)) {
1411                     l->tlength_ms = json_object_get_int(item_o);
1412                     pa_log_debug(" - tlength-ms : %d", l->tlength_ms);
1413                 } else {
1414                     pa_log_error("Get tlength-ms failed");
1415                     goto fail;
1416                 }
1417                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_MINREQ_MS, &item_o) && json_object_is_type(item_o, json_type_int)) {
1418                     l->minreq_ms = json_object_get_int(item_o);
1419                     pa_log_debug(" - minreq-ms : %d", l->minreq_ms);
1420                 } else {
1421                     pa_log_error("Get minreq-ms failed");
1422                     goto fail;
1423                 }
1424                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_PREBUF_MS, &item_o) && json_object_is_type(item_o, json_type_int)) {
1425                     l->prebuf_ms = json_object_get_int(item_o);
1426                     pa_log_debug(" - prebuf-ms : %d", l->prebuf_ms);
1427                 } else {
1428                     pa_log_error("Get prebuf-ms failed");
1429                     goto fail;
1430                 }
1431                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_MAXLENGTH, &item_o) && json_object_is_type(item_o, json_type_int)) {
1432                     l->maxlength = json_object_get_int(item_o);
1433                     pa_log_debug(" - maxlength : %d", l->maxlength);
1434                 } else {
1435                     pa_log_error("Get maxlength failed");
1436                     goto fail;
1437                 }
1438                 pa_hashmap_put(m->latency_infos, (void*)type, l);
1439             }
1440         }
1441     }
1442
1443     /* Volumes */
1444     m->volume_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1445     if (json_object_object_get_ex(o, STREAM_MAP_VOLUMES, &array_o) && json_object_is_type(array_o, json_type_array)) {
1446         array_length = json_object_array_length(array_o);
1447         for (i = 0; i < array_length; i++) {
1448             if ((array_item_o = json_object_array_get_idx(array_o, i)) && json_object_is_type(array_item_o, json_type_object)) {
1449                 v = pa_xmalloc0(sizeof(volume_info));
1450                 pa_log_debug("volume found [%d]", i);
1451                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_VOLUME_TYPE, &item_o) && json_object_is_type(item_o, json_type_string)) {
1452                     type = json_object_get_string(item_o);
1453                     pa_log_debug(" - type : %s", type);
1454                 } else {
1455                     pa_log_error("Get volume type failed");
1456                     goto fail;
1457                 }
1458                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_VOLUME_IS_FOR_HAL, &item_o) && json_object_is_type(item_o, json_type_int)) {
1459                     v->is_hal_volume_type = (bool)json_object_get_int(item_o);
1460                     pa_log_debug(" - is-hal-volume : %d", v->is_hal_volume_type);
1461                 } else {
1462                     pa_log_error("Get is-hal-volume failed");
1463                     goto fail;
1464                 }
1465                 pa_hashmap_put(m->volume_infos, (void*)type, v);
1466             }
1467         }
1468     }
1469
1470     /* Streams */
1471     m->stream_infos = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1472     if (json_object_object_get_ex(o, STREAM_MAP_STREAMS, &array_o) && json_object_is_type(array_o, json_type_array)) {
1473         array_length = json_object_array_length(array_o);
1474         for (i = 0; i < array_length; i++) {
1475
1476             if ((array_item_o = json_object_array_get_idx(array_o, i)) && json_object_is_type(array_item_o, json_type_object)) {
1477                 s = pa_xmalloc0(sizeof(stream_info));
1478                 pa_log_debug("stream found [%d]", i);
1479                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_ROLE, &item_o) && json_object_is_type(item_o, json_type_string)) {
1480                     role = json_object_get_string(item_o);
1481                     pa_log_debug(" - role : %s", role);
1482                 } else {
1483                     pa_log_error("Get stream role failed");
1484                     goto fail;
1485                 }
1486                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_PRIORITY, &item_o) && json_object_is_type(item_o, json_type_int)) {
1487                     s->priority = json_object_get_int(item_o);
1488                     pa_log_debug(" - priority : %d", s->priority);
1489                 } else {
1490                     pa_log_error("Get stream priority failed");
1491                     goto fail;
1492                 }
1493                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_ROUTE_TYPE, &item_o) && json_object_is_type(item_o, json_type_string)) {
1494                     if (convert_route_type(&(s->route_type), json_object_get_string(item_o))) {
1495                         pa_log_error("convert stream route-type failed");
1496                         goto fail;
1497                     }
1498                     pa_log_debug(" - route-type : %d", s->route_type);
1499                 } else {
1500                     pa_log_error("Get stream route-type failed");
1501                     goto fail;
1502                 }
1503                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_VOLUME_TYPES, &sub_array_o) && json_object_is_type(sub_array_o, json_type_object)) {
1504                     if (json_object_object_get_ex(sub_array_o, STREAM_MAP_STREAM_VOLUME_TYPE_IN, &item_o) && json_object_is_type(item_o, json_type_string))
1505                         s->volume_types[STREAM_DIRECTION_IN] = json_object_get_string(item_o);
1506                     else {
1507                         pa_log_error("Get stream volume-type-in failed");
1508                         goto fail;
1509                     }
1510                     if (json_object_object_get_ex(sub_array_o, STREAM_MAP_STREAM_VOLUME_TYPE_OUT, &item_o) && json_object_is_type(item_o, json_type_string))
1511                         s->volume_types[STREAM_DIRECTION_OUT] = json_object_get_string(item_o);
1512                     else {
1513                         pa_log_error("Get stream volume-type-out failed");
1514                         goto fail;
1515                     }
1516                     pa_log_debug(" - volume-types : in[%s], out[%s]", s->volume_types[STREAM_DIRECTION_IN], s->volume_types[STREAM_DIRECTION_OUT]);
1517                 } else {
1518                     pa_log_error("Get stream volume-types failed");
1519                     goto fail;
1520                 }
1521                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_AVAIL_IN_DEVICES, &sub_array_o) && json_object_is_type(sub_array_o, json_type_array)) {
1522                     j = 0;
1523                     s->idx_avail_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1524                     sub_array_length = json_object_array_length(sub_array_o);
1525                     pa_log_debug(" - avail-in-devices");
1526                     for (j = 0; j < sub_array_length; j++) {
1527                         if ((in_device_o = json_object_array_get_idx(sub_array_o, j)) && json_object_is_type(in_device_o, json_type_string)) {
1528                             pa_idxset_put(s->idx_avail_in_devices, (void*)json_object_get_string(in_device_o), NULL);
1529                             pa_log_debug("      device[%d] : %s", j, json_object_get_string(in_device_o));
1530                            }
1531                        }
1532                 } else {
1533                     pa_log_error("Get stream avail-in-devices failed");
1534                     goto fail;
1535                 }
1536                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_AVAIL_OUT_DEVICES, &sub_array_o) && json_object_is_type(sub_array_o, json_type_array)) {
1537                     j = 0;
1538                     s->idx_avail_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1539                     sub_array_length = json_object_array_length(sub_array_o);
1540                     pa_log_debug(" - avail-out-devices");
1541                     for (j = 0; j < sub_array_length; j++) {
1542                         if ((out_device_o = json_object_array_get_idx(sub_array_o, j)) && json_object_is_type(out_device_o, json_type_string)) {
1543                             pa_idxset_put(s->idx_avail_out_devices, (void*)json_object_get_string(out_device_o), NULL);
1544                             pa_log_debug("      device[%d] : %s", j, json_object_get_string(out_device_o));
1545                            }
1546                        }
1547                 } else {
1548                     pa_log_error("Get stream avail-out-devices failed");
1549                     goto fail;
1550                 }
1551                 if (json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_AVAIL_FRAMEWORKS, &sub_array_o) && json_object_is_type(sub_array_o, json_type_array)) {
1552                     j = 0;
1553                     s->idx_avail_frameworks = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1554                     sub_array_length = json_object_array_length(sub_array_o);
1555                     pa_log_debug(" - avail-frameworks");
1556                     for (j = 0; j < sub_array_length; j++) {
1557                         if ((framework_o = json_object_array_get_idx(sub_array_o, j)) && json_object_is_type(framework_o, json_type_string)) {
1558                             pa_idxset_put(s->idx_avail_frameworks, (void*)json_object_get_string(framework_o), NULL);
1559                             pa_log_debug("      framework[%d] : %s", j, json_object_get_string(framework_o));
1560                            }
1561                        }
1562                 } else {
1563                     pa_log_error("Get stream avail-frameworks failed");
1564                     goto fail;
1565                 }
1566                 pa_hashmap_put(m->stream_infos, (void*)role, s);
1567             }
1568         }
1569     } else {
1570         pa_log_error("Get streams object failed");
1571         goto fail;
1572     }
1573
1574     dump_stream_map(m);
1575
1576     return 0;
1577 fail:
1578     pa_log_error("failed to initialize stream-map");
1579     if (m->stream_infos) {
1580         PA_HASHMAP_FOREACH(s, m->stream_infos, state) {
1581             if (s->idx_avail_in_devices)
1582                 pa_idxset_free(s->idx_avail_in_devices, NULL);
1583             if (s->idx_avail_out_devices)
1584                 pa_idxset_free(s->idx_avail_out_devices, NULL);
1585             if (s->idx_avail_frameworks)
1586                 pa_idxset_free(s->idx_avail_frameworks, NULL);
1587             pa_xfree(s);
1588         }
1589         pa_hashmap_free(m->stream_infos);
1590     }
1591     if (m->volume_infos) {
1592         PA_HASHMAP_FOREACH(v, m->volume_infos, state) {
1593             pa_xfree(v);
1594         }
1595         pa_hashmap_free(m->volume_infos);
1596     }
1597     if (m->latency_infos) {
1598         PA_HASHMAP_FOREACH(l, m->latency_infos, state) {
1599             pa_xfree(l);
1600         }
1601         pa_hashmap_free(m->latency_infos);
1602     }
1603     return -1;
1604 }
1605
1606 static void deinit_stream_map(pa_stream_manager *m) {
1607     stream_info *s = NULL;
1608     volume_info *v = NULL;
1609     latency_info *l = NULL;
1610     void *state = NULL;
1611
1612     pa_assert(m);
1613
1614     if (m->stream_infos) {
1615         PA_HASHMAP_FOREACH(s, m->stream_infos, state) {
1616             if (s->idx_avail_in_devices)
1617                 pa_idxset_free(s->idx_avail_in_devices, NULL);
1618             if (s->idx_avail_out_devices)
1619                 pa_idxset_free(s->idx_avail_out_devices, NULL);
1620             if (s->idx_avail_frameworks)
1621                 pa_idxset_free(s->idx_avail_frameworks, NULL);
1622             pa_xfree(s);
1623         }
1624         pa_hashmap_free(m->stream_infos);
1625     }
1626     if (m->volume_infos) {
1627         PA_HASHMAP_FOREACH(v, m->volume_infos, state) {
1628             pa_xfree(v);
1629         }
1630         pa_hashmap_free(m->volume_infos);
1631     }
1632     if (m->latency_infos) {
1633         PA_HASHMAP_FOREACH(l, m->latency_infos, state) {
1634             pa_xfree(l);
1635         }
1636         pa_hashmap_free(m->latency_infos);
1637     }
1638 }
1639
1640 static bool check_name_to_skip(pa_stream_manager *m, process_command_type_t command, void *stream, stream_type_t type, bool is_new_data) {
1641     bool ret = false;
1642     const char *name = NULL;
1643     const char *role = NULL;
1644     int i = 0;
1645
1646     pa_assert(m);
1647     pa_assert(stream);
1648
1649     if (command == PROCESS_COMMAND_PREPARE && is_new_data) {
1650         if ((name = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_NAME))) {
1651             for (i = 0; i < NAME_FOR_SKIP_MAX; i++)
1652                 if (pa_streq(name, stream_manager_media_names_for_skip[i])) {
1653                     ret = true;
1654                     pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE, SKIP_ROLE);
1655                     break;
1656                 }
1657             pa_log_info("name is [%s], skip(%d) command(%s)", name, ret, process_command_type_str[command]);
1658         }
1659     } else {
1660         if (is_new_data)
1661             role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1662         else
1663             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1664
1665         if (role && pa_streq(role, SKIP_ROLE))
1666             ret = true;
1667     }
1668
1669     return ret;
1670 }
1671
1672 static bool check_role_to_skip(pa_stream_manager *m, process_command_type_t command, const char *role) {
1673     bool ret = true;
1674     stream_info *s = NULL;
1675
1676     pa_assert(m);
1677     pa_assert(m->stream_infos);
1678     pa_assert(role);
1679
1680     if ((s = pa_hashmap_get(m->stream_infos, role)))
1681       ret = false;
1682     if (s && pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING) &&
1683        (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED ||
1684        command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED))
1685       ret = true;
1686
1687     pa_log_debug("role is [%s], skip(%d)", role, ret);
1688
1689     return ret;
1690 }
1691
1692 static bool check_route_type_to_skip(process_command_type_t command, const char *route_type_str) {
1693     bool ret = false;
1694     stream_route_type_t route_type;
1695
1696     pa_assert(route_type_str);
1697
1698     if (!pa_atoi(route_type_str, (int32_t*)&route_type)) {
1699         if ((route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) &&
1700             (command > PROCESS_COMMAND_PREPARE && command < PROCESS_COMMAND_UPDATE_VOLUME))
1701             ret = true; /* this route route is for external device, need to skip */
1702     } else {
1703         pa_log_error("could not convert route_type_str(%s) to int", route_type_str);
1704         ret = true;
1705     }
1706     pa_log_debug("command is [%s], skip(%d) for route_type(%d)", process_command_type_str[command], ret, route_type);
1707
1708     return ret;
1709 }
1710
1711 static bool check_name_is_vstream(void *stream, stream_type_t type, bool is_new_data) {
1712     bool ret = false;
1713     const char *name = NULL;
1714
1715     pa_assert(stream);
1716
1717     if (is_new_data)
1718         name = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_NAME);
1719     else
1720         name = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_NAME);
1721     if (name) {
1722         if (pa_streq(name, VIRTUAL_STREAM_NAME)) {
1723             ret = true;
1724             pa_log_info("name is [%s]", name);
1725         }
1726     }
1727
1728     return ret;
1729 }
1730
1731 static bool update_priority_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role, bool is_new_data) {
1732     bool ret = false;
1733     stream_info *s = NULL;
1734
1735     pa_assert(m);
1736     pa_assert(stream);
1737     pa_assert(m->stream_infos);
1738     pa_assert(role);
1739
1740     if ((s = pa_hashmap_get(m->stream_infos, role))) {
1741         if (is_new_data)
1742             pa_proplist_set(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void*)&(s->priority), sizeof(s->priority));
1743         else
1744             pa_proplist_set(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void*)&(s->priority), sizeof(s->priority));
1745         ret = true;
1746     }
1747
1748     return ret;
1749 }
1750
1751 static bool update_route_type_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role) {
1752     bool ret = false;
1753     stream_route_type_t route_type = STREAM_ROUTE_TYPE_AUTO;
1754     stream_info *s = NULL;
1755
1756     pa_assert(m);
1757     pa_assert(stream);
1758     pa_assert(m->stream_infos);
1759     pa_assert(role);
1760
1761     if ((s = pa_hashmap_get(m->stream_infos, role))) {
1762         route_type = s->route_type;
1763         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE, "%d", route_type);
1764         ret = true;
1765     }
1766
1767     return ret;
1768 }
1769
1770 static bool update_volume_type_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role) {
1771     bool ret = false;
1772     const char *volume_type = NULL;
1773     stream_info *s = NULL;
1774
1775     pa_assert(m);
1776     pa_assert(stream);
1777     pa_assert(m->stream_infos);
1778     pa_assert(role);
1779
1780     if ((s = pa_hashmap_get(m->stream_infos, role)))
1781         volume_type = s->volume_types[type];
1782
1783     if (volume_type && (!pa_streq(volume_type, "none"))) {
1784         pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type);
1785         ret = true;
1786     } else
1787         pa_log_warn("this stream[%p] does not have any volume type, skip updating volume type. stream_type[%d], role[%s]", stream, type, role);
1788
1789     return ret;
1790 }
1791
1792 static bool update_focus_status_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, bool is_new_data) {
1793     const char *p_idx;
1794     uint32_t parent_idx = 0;
1795     stream_parent *sp = NULL;
1796
1797     pa_assert(m);
1798     pa_assert(stream);
1799
1800     if (is_new_data)
1801         p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1802     else
1803         p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1804     if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1805         sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1806         if (sp) {
1807             if (is_new_data)
1808                 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_FOCUS_STATUS, "%u", sp->focus_status);
1809             else
1810                 pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_FOCUS_STATUS, "%u", sp->focus_status);
1811             pa_log_debug("p_idx(%s), idx(%u), focus_status(0x%x, 0x1:playback 0x2:capture 0x3:both)", p_idx, parent_idx, sp->focus_status);
1812         } else {
1813             pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
1814             return false;
1815         }
1816     }
1817
1818     return true;
1819 }
1820
1821 static bool update_stream_parent_info(pa_stream_manager *m, process_command_type_t command, stream_type_t type, void *stream) {
1822     const char *p_idx;
1823     uint32_t parent_idx;
1824     stream_parent *sp = NULL;
1825
1826     pa_assert(m);
1827     pa_assert(stream);
1828
1829     p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1830     if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1831         pa_log_debug("p_idx(%s), idx(%u)", p_idx, parent_idx);
1832         sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1833         if (sp) {
1834             uint32_t idx = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)stream)->index : ((pa_source_output*)stream)->index;
1835             if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
1836                 /* append this stream to the parent stream info. */
1837                 pa_log_debug(" - append this stream(%p, %u) to the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1838                 pa_idxset_put(type == STREAM_SINK_INPUT ? (sp->idx_sink_inputs) : (sp->idx_source_outputs), stream, NULL);
1839                 return true;
1840             } else if (command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
1841                 /* remove this stream from the parent stream info. */
1842                 pa_log_debug(" - remove this stream(%p, %u) from the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1843                 pa_idxset_remove_by_data(type == STREAM_SINK_INPUT ? (sp->idx_sink_inputs) : (sp->idx_source_outputs), stream, NULL);
1844                 return true;
1845             } else {
1846                 pa_log_error("invalid command(%d)", command);
1847                 return false;
1848             }
1849         } else {
1850             pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
1851             return false;
1852         }
1853     } else
1854         return false;
1855
1856     return true;
1857 }
1858
1859 static bool update_the_highest_priority_stream(pa_stream_manager *m, process_command_type_t command, void *mine,
1860                                                stream_type_t type, const char *role, bool is_new_data, bool *need_to_update) {
1861     uint32_t idx = 0;
1862     size_t size = 0;
1863     const int32_t *priority = NULL;
1864     const char *route_type_str = NULL;
1865     stream_route_type_t route_type;
1866     const char *focus_status_str = NULL;
1867     const char *active_dev = NULL;
1868     void *cur_max_stream = NULL;
1869     void *cur_max_stream_tmp = NULL;
1870     const int32_t *cur_max_priority = NULL;
1871     const char *cur_max_role = NULL;
1872     int32_t cur_max_focus_status = 0;
1873     int32_t focus_status = 0;
1874     void *i = NULL;
1875     const char *_role = NULL;
1876     pa_idxset *streams = NULL;
1877     pa_sink *sink = NULL;
1878     pa_source *source = NULL;
1879     bool is_vstream = false;
1880
1881     pa_assert(m);
1882     pa_assert(mine);
1883     if (!role) {
1884         pa_log_error("invalid input, role(%s)", role);
1885         return false;
1886     }
1887
1888     *need_to_update = false;
1889
1890     if (type == STREAM_SINK_INPUT) {
1891         cur_max_stream = m->cur_highest_priority.sink_input;
1892     } else if (type == STREAM_SOURCE_OUTPUT) {
1893         cur_max_stream = m->cur_highest_priority.source_output;
1894     }
1895
1896     pa_log_debug("update_the_highest_priority_stream(), stream_type(%d), role(%s), command(%d), is_new_data(%d)",
1897         type, role, command, is_new_data);
1898     if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1899         /* get focus status, route type */
1900         if (is_new_data) {
1901             focus_status_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_FOCUS_STATUS);
1902             route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
1903         } else {
1904             focus_status_str = pa_proplist_gets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_FOCUS_STATUS);
1905             route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
1906         }
1907         if (focus_status_str && !pa_atoi(focus_status_str, &focus_status)) {
1908             pa_log_debug("focus status(0x%x) of mine", focus_status);
1909         }
1910         /* check if this stream is for external device with ROUTE_TYPE_AUTO */
1911         if (IS_ROUTE_TYPE_FOR_AUTO(route_type_str, route_type) && is_new_data) {
1912             if (type == STREAM_SINK_INPUT)
1913                 sink = ((pa_sink_input_new_data*)mine)->sink;
1914             else
1915                 source = ((pa_source_output_new_data*)mine)->source;
1916             is_vstream = check_name_is_vstream(mine, type, is_new_data);
1917             if (!is_vstream && ((sink && !(sink->use_internal_codec)) || (source && !(source->use_internal_codec)))) {
1918                 pa_log_warn("stream(%p) uses external device, skip it", mine);
1919                 *need_to_update = false;
1920                 return true;
1921             }
1922         }
1923         if (cur_max_stream == NULL) {
1924             *need_to_update = true;
1925             pa_log_debug("set cur_highest to mine");
1926         } else {
1927             if (is_new_data) {
1928                 if (pa_proplist_get(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&priority, &size))
1929                     pa_log_error("failed to pa_proplist_get() for priority");
1930             } else {
1931                 if (pa_proplist_get(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&priority, &size))
1932                     pa_log_error("failed to pa_proplist_get() for priority");
1933             }
1934             if (pa_proplist_get(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&cur_max_priority, &size))
1935                 pa_log_error("failed to pa_proplist_get() for priority");
1936             focus_status_str = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_FOCUS_STATUS);
1937             if (focus_status_str && !pa_atoi(focus_status_str, &cur_max_focus_status)) {
1938                 pa_log_debug("cur_max_focus status(0x%x)", cur_max_focus_status);
1939             }
1940             cur_max_role = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE);
1941             if (!cur_max_priority || !cur_max_role) {
1942                 pa_log_error("failed to pa_proplist_gets() for getting current max priority(%p) and it's role(%s)", cur_max_priority, cur_max_role);
1943                 return false;
1944             } else {
1945                 if (priority && cur_max_priority) {
1946                     if (GET_FOCUS_STATUS(focus_status, type) ||
1947                         (!GET_FOCUS_STATUS(cur_max_focus_status, type) && *priority >= *cur_max_priority)) {
1948                         *need_to_update = true;
1949                         pa_log_debug("update cur_highest to mine(%s)", role);
1950                     } else {
1951                         /* no need to trigger,
1952                          * update active device info if possible */
1953                         if ((active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
1954                             if (is_new_data)
1955                                 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_dev);
1956                             else
1957                                 pa_proplist_sets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_dev);
1958                         }
1959                         return true;
1960                     }
1961                 }
1962             }
1963         }
1964     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED ||
1965             command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED) {
1966         if (cur_max_stream == mine || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED) {
1967             if (type == STREAM_SINK_INPUT) {
1968                 streams = m->core->sink_inputs;
1969             } else if (type == STREAM_SOURCE_OUTPUT) {
1970                 streams = m->core->source_outputs;
1971             }
1972             /* find the next highest priority input */
1973             PA_IDXSET_FOREACH(i, streams, idx) {
1974                 if (i == mine)
1975                     continue;
1976                 if (!(_role = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE))) {
1977                     pa_log_error("failed to pa_proplist_gets() for role");
1978                     continue;
1979                 }
1980                 if (pa_proplist_get(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&priority, &size)) {
1981                     pa_log_warn("failed to pa_proplist_get() for priority, skip it");
1982                     continue;
1983                 }
1984                 if (!(route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
1985                     pa_log_warn("failed to pa_proplist_get() for route_type, skip it");
1986                     continue;
1987                 } else if (IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
1988                     pa_log_warn("stream(%p) has the route type for external device, skip it", i);
1989                     continue;
1990                 } else {
1991                     is_vstream = check_name_is_vstream(i, type, false);
1992                     if (!is_vstream &&
1993                        (type == STREAM_SINK_INPUT ? !(((pa_sink_input*)i)->sink->use_internal_codec) :
1994                                                     !(((pa_source_output*)i)->source->use_internal_codec))) {
1995                         pa_log_warn("stream(%p) uses external audio codec, skip it", i);
1996                         continue;
1997                     }
1998                 }
1999                 if (!(focus_status_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_FOCUS_STATUS))) {
2000                     pa_log_warn("failed to pa_proplist_gets() for focus status");
2001                 } else {
2002                     if (!pa_atoi(focus_status_str, &focus_status))
2003                         pa_log_debug("focus status(0x%x)", focus_status);
2004                 }
2005                 pa_log_debug("role(%s)/priority(%p)/route_type(%d)/focus_status(0x%x)/stream(%p)", _role, priority, route_type, focus_status, i);
2006                 if (cur_max_priority == NULL) {
2007                     cur_max_priority = priority;
2008                     cur_max_focus_status = focus_status;
2009                     cur_max_stream_tmp = i;
2010                     cur_max_role = _role;
2011                 }
2012                 if (cur_max_priority && priority) {
2013                     if (GET_FOCUS_STATUS(cur_max_focus_status, type) ||
2014                         (!GET_FOCUS_STATUS(focus_status, type) && (*cur_max_priority > *priority))) {
2015                         /* skip */
2016                     } else  {
2017                         cur_max_priority = priority;
2018                         cur_max_focus_status = focus_status;
2019                         cur_max_stream_tmp = i;
2020                         cur_max_role = _role;
2021                     }
2022                 }
2023             }
2024             pa_log_debug("updated max priority(%p)/stream(%p)", cur_max_priority, cur_max_stream_tmp);
2025             if (cur_max_stream_tmp) {
2026                 if (type == STREAM_SINK_INPUT) {
2027                     m->cur_highest_priority.sink_input = cur_max_stream_tmp;
2028                     m->cur_highest_priority.role_si = cur_max_role;
2029                 } else if (type == STREAM_SOURCE_OUTPUT) {
2030                     m->cur_highest_priority.source_output = cur_max_stream_tmp;
2031                     m->cur_highest_priority.role_so = cur_max_role;
2032                 }
2033             } else {
2034                 if (type == STREAM_SINK_INPUT) {
2035                     m->cur_highest_priority.sink_input = NULL;
2036                     m->cur_highest_priority.role_si = NULL;
2037                 } else if (type == STREAM_SOURCE_OUTPUT) {
2038                     m->cur_highest_priority.source_output = NULL;
2039                     m->cur_highest_priority.role_so = NULL;
2040                 }
2041             }
2042             *need_to_update = true;
2043             pa_log_info("need to update: type(%d), cur_highest_priority(sink_input=%p[%s]/source_output=%p[%s])",
2044                         type, (void*)m->cur_highest_priority.sink_input, m->cur_highest_priority.role_si,
2045                         (void*)m->cur_highest_priority.source_output, m->cur_highest_priority.role_so);
2046         } else {
2047             /* no need to trigger */
2048             pa_log_info("no need to update: type(%d), cur_highest_priority(sink_input=%p[%s]/source_output=%p[%s])",
2049                         type, (void*)m->cur_highest_priority.sink_input, m->cur_highest_priority.role_si,
2050                         (void*)m->cur_highest_priority.source_output, m->cur_highest_priority.role_so);
2051             return true;
2052         }
2053     }
2054     return true;
2055 }
2056
2057 /* Update buffer attributes to new stream */
2058 static void update_buffer_attribute(pa_stream_manager *m, void *new_data, stream_type_t stream_type, bool is_new_data) {
2059     pa_sample_spec *sample_spec;
2060     const char *latency;
2061     latency_info *li;
2062     int32_t maxlength = -1;
2063     /* playback only */
2064     int32_t tlength = -1;
2065     int32_t minreq = -1;
2066     /* Note: pulseaudio recommends to set it to -1, but there's an issue related
2067      * to a stream from gstreamer pulsesink which set this value to 0, so we set
2068      * default value to 0 temporarily. */
2069     int32_t prebuf = 0;
2070     int32_t tlength_ms = -1;
2071     int32_t minreq_ms = -1;
2072     int32_t prebuf_ms = -1;
2073     /* recording  only */
2074     int32_t fragsize = -1;
2075     int32_t fragsize_ms = -1;
2076
2077     pa_assert(m);
2078     pa_assert(new_data);
2079
2080     if (!is_new_data) {
2081         pa_log_warn("updating buffer attribute is only for new data, skip it");
2082         return;
2083     }
2084
2085     if ((latency = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY)))
2086         pa_log_info("audio_latency : %s", latency);
2087     else {
2088         pa_log_warn("failed to get audio_latency");
2089         return;
2090     }
2091
2092     if (!(li = pa_hashmap_get(m->latency_infos, latency))) {
2093         pa_log_warn("not support this latency type[%s]", latency);
2094         return;
2095     }
2096
2097     maxlength = li->maxlength;
2098     pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_MAXLENGTH, "%d", maxlength);
2099
2100     sample_spec = GET_STREAM_NEW_SAMPLE_SPEC_PTR(new_data, stream_type);
2101     pa_log_info("*** sample_spec: format(%d), rate(%u), channels(%u)",
2102                  sample_spec->format, sample_spec->rate, sample_spec->channels);
2103
2104     if (stream_type ==  STREAM_SINK_INPUT) {
2105         tlength_ms = li->tlength_ms;
2106         minreq_ms = li->minreq_ms;
2107         prebuf_ms = li->prebuf_ms;
2108
2109         if (minreq_ms > 0)
2110             minreq = pa_usec_to_bytes(minreq_ms * 1000, sample_spec);
2111         if (tlength_ms > 0)
2112             tlength = pa_usec_to_bytes(tlength_ms * 1000, sample_spec);
2113         if (prebuf_ms >= 0)
2114             prebuf = pa_usec_to_bytes(prebuf_ms * 1000, sample_spec);
2115
2116         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_TLENGTH, "%d", tlength);
2117         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_MINREQ, "%d", minreq);
2118         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_PREBUF, "%d", prebuf);
2119
2120         pa_log_info("*** maxlength:%d, tlength:%d, prebuf:%d, minreq:%d", maxlength, tlength, prebuf, minreq);
2121
2122     } else if (stream_type == STREAM_SOURCE_OUTPUT) {
2123         fragsize_ms = li->fragsize_ms;
2124
2125         if (fragsize_ms > 0)
2126             fragsize = pa_usec_to_bytes(fragsize_ms * 1000, sample_spec);
2127
2128         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_FRAGSIZE, "%d", fragsize);
2129
2130         pa_log_info("*** maxlength:%d, fragsize:%d", maxlength, fragsize);
2131     }
2132 }
2133
2134 static void fill_device_info_to_hook_data(pa_stream_manager *m, void *hook_data, notify_command_type_t command, stream_type_t type, void *stream, bool is_new_data) {
2135     char *device_none = NULL;
2136     const char *p_idx = NULL;
2137     uint32_t parent_idx = 0;
2138     stream_parent *sp = NULL;
2139     pa_stream_manager_hook_data_for_select *select_data = NULL;
2140     pa_stream_manager_hook_data_for_route *route_data = NULL;
2141     stream_info *si;
2142     pa_idxset *avail_devices;
2143     uint32_t list_len = 0;
2144
2145     pa_assert(m);
2146     pa_assert(hook_data);
2147     pa_log_debug("fill_device_info_to_hook_data() for %s", notify_command_type_str[command]);
2148
2149     switch (command) {
2150     case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
2151         select_data = (pa_stream_manager_hook_data_for_select*)hook_data;
2152         if ((si = pa_hashmap_get(m->stream_infos, select_data->stream_role))) {
2153             select_data->route_type = si->route_type;
2154             avail_devices = (type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices;
2155             list_len = pa_idxset_size(avail_devices);
2156             device_none = pa_idxset_get_by_data(avail_devices, "none", NULL);
2157
2158             if (list_len == 0 || device_none) {
2159                 pa_log_warn("  -- there is no available device, stream_type(%d)", type);
2160                 break;
2161             }
2162             select_data->idx_avail_devices = avail_devices;
2163             select_data->origins_from_new_data = is_new_data;
2164             if (si->route_type >= STREAM_ROUTE_TYPE_MANUAL) {
2165                 if (is_new_data)
2166                     p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
2167                 else
2168                     p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
2169                 if (p_idx && !pa_atou(p_idx, &parent_idx)) {
2170                     /* find parent idx, it's device info. and it's stream idxs */
2171                     sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
2172                     if (sp)
2173                         select_data->idx_manual_devices = (type == STREAM_SINK_INPUT) ? (sp->idx_route_out_devices) : (sp->idx_route_in_devices);
2174                     else
2175                         pa_log_warn("  -- failed to get the stream parent of idx(%u)", parent_idx);
2176                 } else
2177                     pa_log_debug("  -- could not get the parent id of this stream, but keep going...");
2178             }
2179         } else
2180             pa_log_error("  -- could not find (%s)", route_data->stream_role);
2181
2182         break;
2183     }
2184     case NOTIFY_COMMAND_CHANGE_ROUTE_START:
2185     case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
2186         route_data = (pa_stream_manager_hook_data_for_route*)hook_data;
2187         if ((si = pa_hashmap_get(m->stream_infos, route_data->stream_role))) {
2188             avail_devices = (type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices;
2189             route_data->route_type = si->route_type;
2190             list_len = pa_idxset_size(avail_devices);
2191             device_none = pa_idxset_get_by_data(avail_devices, "none", NULL);
2192
2193             if (list_len == 0 || device_none) {
2194                 pa_log_warn("  -- there is no available device, stream_type(%d)", type);
2195                 break;
2196             }
2197             if (is_new_data)
2198                 p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
2199             else
2200                 p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
2201             if (p_idx && !pa_atou(p_idx, &parent_idx)) {
2202                 sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
2203                 if (!sp)
2204                     pa_log_warn("  -- failed to get the stream parent of idx(%u)", parent_idx);
2205             } else
2206                pa_log_warn("  -- could not get the parent id of this stream, but keep going...");
2207
2208             route_data->idx_avail_devices = avail_devices;
2209             if (si->route_type >= STREAM_ROUTE_TYPE_MANUAL) {
2210                 if (sp) {
2211                     route_data->idx_manual_devices = (type == STREAM_SINK_INPUT) ? (sp->idx_route_out_devices) : (sp->idx_route_in_devices);
2212                     route_data->idx_streams = (type == STREAM_SINK_INPUT) ? (sp->idx_sink_inputs) : (sp->idx_source_outputs);
2213                 } else
2214                     pa_log_warn("  -- failed to get the stream parent of idx(%u)", parent_idx);
2215             }
2216         } else
2217             pa_log_error("  -- could not find (%s)", route_data->stream_role);
2218
2219         break;
2220     }
2221     default:
2222         break;
2223     }
2224 }
2225
2226 static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, bool is_new_data, void *user_data) {
2227     pa_stream_manager_hook_data_for_select hook_call_select_data;
2228     pa_stream_manager_hook_data_for_route hook_call_route_data;
2229     hal_stream_connection_info stream_conn_info;
2230     hal_route_option route_option;
2231     const char *role = NULL;
2232     void *s = NULL;
2233     const char *modifier_gain = NULL;
2234
2235     pa_assert(m);
2236     pa_log_debug("do_notify(%s): type(%d), is_new_data(%d), user_data(%p)", notify_command_type_str[command], type, is_new_data, user_data);
2237
2238     switch (command) {
2239     case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
2240         pa_assert(user_data);
2241         memset(&hook_call_select_data, 0, sizeof(pa_stream_manager_hook_data_for_select));
2242         hook_call_select_data.stream = s = user_data;
2243         if (s) {
2244             hook_call_select_data.stream_type = type;
2245             hook_call_select_data.origins_from_new_data = is_new_data;
2246             if (is_new_data) {
2247                 hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
2248                 fill_device_info_to_hook_data(m, &hook_call_select_data, command, type, s, is_new_data);
2249                 hook_call_select_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
2250                 if (type == STREAM_SINK_INPUT) {
2251                     hook_call_select_data.occupying_role = m->cur_highest_priority.role_si;
2252                     hook_call_select_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
2253                     /* need to check modifier_gain, because we do not skip a stream that is from module-sound-player */
2254                     modifier_gain = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_TIZEN_VOLUME_GAIN_TYPE);
2255                     if (((pa_sink_input_new_data*)s)->sink && !modifier_gain) {
2256                         pa_log_info("  - sink(%s) has been already selected, skip selecting sink",
2257                                     (((pa_sink_input_new_data*)s)->sink)->name);
2258                         break;
2259                     }
2260                 } else if (type == STREAM_SOURCE_OUTPUT) {
2261                     hook_call_select_data.occupying_role = m->cur_highest_priority.role_si;
2262                     hook_call_select_data.proper_source = &(((pa_source_output_new_data*)s)->source);
2263                     if (((pa_source_output_new_data*)s)->source) {
2264                         pa_log_info("  - source(%s) has been already selected, skip selecting source",
2265                                     (((pa_source_output_new_data*)s)->source)->name);
2266                         break;
2267                     }
2268                 }
2269             } else {
2270                 hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
2271                 fill_device_info_to_hook_data(m, &hook_call_select_data, command, type, s, is_new_data);
2272                 hook_call_select_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
2273                 if (type == STREAM_SINK_INPUT)
2274                     hook_call_select_data.proper_sink = &(((pa_sink_input*)s)->sink);
2275                 else if (type == STREAM_SOURCE_OUTPUT)
2276                     hook_call_select_data.proper_source = &(((pa_source_output*)s)->source);
2277             }
2278             CONVERT_TO_DEVICE_ROLE(hook_call_select_data.stream_role, hook_call_select_data.device_role);
2279             pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_select_data);
2280         }
2281         break;
2282     }
2283     case NOTIFY_COMMAND_CHANGE_ROUTE_START: {
2284         pa_assert(user_data);
2285         memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
2286         hook_call_route_data.stream = s = user_data;
2287         if (s) {
2288             if (is_new_data) {
2289                 hook_call_route_data.origins_from_new_data = true;
2290                 role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
2291                 hook_call_route_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
2292                 if (type == STREAM_SINK_INPUT) {
2293                     hook_call_route_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
2294                 } else if (type == STREAM_SOURCE_OUTPUT) {
2295                     hook_call_route_data.proper_source = &(((pa_source_output_new_data*)s)->source);
2296                 }
2297             } else {
2298                 role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
2299                 hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
2300                 hook_call_route_data.idx_streams = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)s)->sink->inputs :
2301                                                                                  ((pa_source_output*)s)->source->outputs;
2302             }
2303             hook_call_route_data.stream_type = type;
2304             hook_call_route_data.stream_role = role;
2305             CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
2306             fill_device_info_to_hook_data(m, &hook_call_route_data, command, type, s, is_new_data);
2307             if (hook_call_route_data.route_type >= STREAM_ROUTE_TYPE_MANUAL) {
2308                 if (hook_call_route_data.idx_manual_devices && !pa_idxset_size(hook_call_route_data.idx_manual_devices)) {
2309                     pa_log_warn("no manual device for this type(%d), skip it..", type);
2310                     break;
2311                 }
2312             }
2313             pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
2314         }
2315         break;
2316     }
2317     case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
2318         memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
2319         s = (type == STREAM_SINK_INPUT) ? (void*)(m->cur_highest_priority.sink_input) :
2320                                           (void*)(m->cur_highest_priority.source_output);
2321         if (s) {
2322             hook_call_route_data.stream = s;
2323             hook_call_route_data.stream_type = type;
2324             hook_call_route_data.stream_role = (type == STREAM_SINK_INPUT) ? (m->cur_highest_priority.role_si) :
2325                                                                              (m->cur_highest_priority.role_so);
2326             CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
2327             hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
2328             hook_call_route_data.idx_streams = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)s)->sink->inputs :
2329                                                                              ((pa_source_output*)s)->source->outputs;
2330             fill_device_info_to_hook_data(m, &hook_call_route_data, command, type, s, is_new_data);
2331         } else {
2332             pa_log_debug("no stream for this type(%d), need to unset route", type);
2333             hook_call_route_data.stream = NULL;
2334             hook_call_route_data.stream_type = type;
2335         }
2336         pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
2337         break;
2338     }
2339     case NOTIFY_COMMAND_UPDATE_ROUTE_OPTION: {
2340         pa_assert(user_data);
2341         memset(&route_option, 0, sizeof(hal_route_option));
2342         s = (type == STREAM_SINK_INPUT) ? (void*)(m->cur_highest_priority.sink_input) :
2343                                           (void*)(m->cur_highest_priority.source_output);
2344         if (s) {
2345             route_option.role = (type == STREAM_SINK_INPUT) ? (m->cur_highest_priority.role_si) :
2346                                                                               (m->cur_highest_priority.role_so);
2347             route_option.name = ((stream_route_option*)user_data)->name;
2348             route_option.value = ((stream_route_option*)user_data)->value;
2349             pa_hal_interface_update_route_option(m->hal, &route_option);
2350         }
2351         break;
2352     }
2353     case NOTIFY_COMMAND_INFORM_STREAM_CONNECTED:
2354     case NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED: {
2355         pa_assert(user_data);
2356         memset(&stream_conn_info, 0, sizeof(hal_stream_connection_info));
2357         s = user_data;
2358         if (s) {
2359             stream_conn_info.role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
2360             stream_conn_info.direction = (type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN;
2361             stream_conn_info.idx = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)s)->index : ((pa_source_output*)s)->index;
2362             stream_conn_info.is_connected = (command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED) ? true : false;
2363             pa_hal_interface_notify_stream_connection_changed(m->hal, &stream_conn_info);
2364         }
2365         break;
2366     }
2367     }
2368 }
2369
2370 static void update_mirroring_streams(pa_stream_manager *m, pa_source_output *o, bool put) {
2371     const char *role;
2372
2373     pa_assert(m);
2374     pa_assert(o);
2375
2376     if ((role = pa_proplist_gets(GET_STREAM_PROPLIST(o, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE)) &&
2377         pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING)) {
2378         if (put)
2379             pa_idxset_put(m->mirroring_streams, o, NULL);
2380         else
2381             pa_idxset_remove_by_data(m->mirroring_streams, o, NULL);
2382     }
2383 }
2384
2385 /* Load/unload forwarding device */
2386 static int update_forwarding_device(pa_stream_manager *m, bool load) {
2387     pa_assert(m);
2388
2389     if (load) {
2390         if (pa_idxset_size(m->mirroring_streams) == 0) {
2391             if (!pa_device_manager_load_forwarding(m->dm)) {
2392                 pa_log_error("could not load forwarding device");
2393                 return -1;
2394             } else
2395                 pa_log_info("forwarding device is now loaded");
2396         } else
2397             pa_log_debug("forwarding device has been already loaded");
2398
2399     } else {
2400         if (pa_idxset_size(m->mirroring_streams) > 0)
2401             pa_log_debug("no need to unload forwarding device");
2402         else {
2403             pa_device_manager_unload_forwarding(m->dm);
2404             pa_log_info("forwarding device is now unloaded");
2405         }
2406     }
2407
2408     return 0;
2409 }
2410
2411 static process_stream_result_t process_stream(pa_stream_manager *m, void *stream, stream_type_t type, process_command_type_t command, bool is_new_data) {
2412     process_stream_result_t result = PROCESS_STREAM_RESULT_OK;
2413     const char *role = NULL;
2414     const char *route_type_str = NULL;
2415     stream_route_type_t route_type;
2416     bool ret = true;
2417     bool need_update = false;
2418     int32_t volume_ret = 0;
2419     volume_info *v = NULL;
2420     const char *si_volume_type_str = NULL;
2421     const int32_t *prior_priority = NULL;
2422     size_t size = 0;
2423     pa_format_info *req_format = NULL;
2424     char *format_str = NULL;
2425     const char *rate_str = NULL;
2426     const char *ch_str = NULL;
2427
2428     pa_log_info(">>> process_stream(%s): stream(%p), stream_type(%d), is_new_data(%d)",
2429         process_command_type_str[command], stream, type, is_new_data);
2430
2431     pa_assert(m);
2432     pa_assert(stream);
2433
2434     if (check_name_to_skip(m, command, stream, type, is_new_data)) {
2435         result = PROCESS_STREAM_RESULT_SKIP;
2436         /* set it to null sink/source */
2437         if (is_new_data)
2438             SET_NEW_DATA_STREAM_TO_NULL_SINK_SOURCE(m, stream, type);
2439         goto finish;
2440     }
2441
2442     if (command == PROCESS_COMMAND_PREPARE) {
2443         if (type == STREAM_SINK_INPUT) {
2444             /* Parse request formats for samplerate, channel, format infomation */
2445             if (((pa_sink_input_new_data*)stream)->req_formats) {
2446                 req_format = pa_idxset_first(((pa_sink_input_new_data*)stream)->req_formats, NULL);
2447                 if (req_format && req_format->plist) {
2448                     /* set sample_spec */
2449                     if (pa_format_info_get_prop_string(req_format, PA_PROP_FORMAT_SAMPLE_FORMAT, &format_str) == 0)
2450                         ((pa_sink_input_new_data*)stream)->sample_spec.format = pa_parse_sample_format((const char*)format_str);
2451                     if ((rate_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_RATE)))
2452                         ((pa_sink_input_new_data*)stream)->sample_spec.rate = atoi(rate_str);
2453                     if ((ch_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_CHANNELS)))
2454                         ((pa_sink_input_new_data*)stream)->sample_spec.channels = atoi(ch_str);
2455
2456                     pa_log_debug("req rate(%s), req ch(%s), req format(%s)", rate_str, ch_str, format_str);
2457
2458                     /* set channel map if it is not set by client */
2459                     if (!((pa_sink_input_new_data*)stream)->channel_map_is_set) {
2460                         pa_channel_map_init_auto(&(((pa_sink_input_new_data*)stream)->channel_map),
2461                                                 ((pa_sink_input_new_data*)stream)->sample_spec.channels, PA_CHANNEL_MAP_ALSA);
2462                         pa_log_debug("set default channel_map: channels(%u)", ((pa_sink_input_new_data*)stream)->channel_map.channels);
2463                         ((pa_sink_input_new_data*)stream)->channel_map_is_set = true;
2464                     }
2465                 }
2466             } else {
2467                 pa_log_debug("no request formats available");
2468             }
2469         }
2470         role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2471         if (!role) {
2472             /* set default value for role and priority */
2473             role = DEFAULT_ROLE;
2474             pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE, role);
2475             pa_log_warn("role is null, set default to [%s]", role);
2476         } else {
2477             /* skip roles */
2478             if (check_role_to_skip(m, command, role)) {
2479                 result = PROCESS_STREAM_RESULT_SKIP;
2480                 goto finish;
2481             }
2482             /* load forwarding device */
2483             if (type == STREAM_SOURCE_OUTPUT && pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
2484                 update_forwarding_device(m, true);
2485         }
2486         /* update the priority of this stream */
2487         ret = update_priority_of_stream(m, stream, type, role, is_new_data);
2488         if (ret == false) {
2489             pa_log_error("could not update the priority of '%s' role.", role);
2490             result = PROCESS_STREAM_RESULT_STOP;
2491             goto finish;
2492         }
2493         /* update the route type of this stream */
2494         ret = update_route_type_of_stream(m, stream, type, role);
2495         if (ret == false) {
2496             pa_log_error("could not update the route type of '%s' role.", role);
2497             result = PROCESS_STREAM_RESULT_STOP;
2498             goto finish;
2499         }
2500         /* update the volume type of this stream */
2501         ret = update_volume_type_of_stream(m, stream, type, role);
2502         if (ret == false)
2503             pa_log_warn("could not update the volume type of '%s' role.", role);
2504
2505         /* skip route types */
2506         if ((route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2507             if (check_route_type_to_skip(command, route_type_str)) {
2508                 result = PROCESS_STREAM_RESULT_SKIP;
2509                 goto finish;
2510             }
2511         }
2512
2513         /* check if it is a virtual stream */
2514         if (check_name_is_vstream(stream, type, is_new_data)) {
2515             pa_log_debug("skip notifying for selecting sink/source, rather set it to null sink/source");
2516             /* set it to null sink/source */
2517             if (is_new_data)
2518                 SET_NEW_DATA_STREAM_TO_NULL_SINK_SOURCE(m, stream, type);
2519
2520         } else {
2521             /* notify to select sink or source */
2522             do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, true, stream);
2523         }
2524
2525     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
2526         if (is_new_data) {
2527             role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2528             route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2529         } else {
2530             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2531             route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2532         }
2533
2534         /* skip roles */
2535         if (check_role_to_skip(m, command, role)) {
2536             result = PROCESS_STREAM_RESULT_SKIP;
2537             goto finish;
2538         }
2539
2540         /* skip route types */
2541         if (check_route_type_to_skip(command, route_type_str)) {
2542             result = PROCESS_STREAM_RESULT_SKIP;
2543             goto finish;
2544         }
2545
2546         if (!is_new_data) {
2547             /* update the priority of this stream */
2548             ret = update_priority_of_stream(m, stream, type, role, is_new_data);
2549             if (ret == false) {
2550                 pa_log_error("could not update the priority of '%s' role.", role);
2551                 result = PROCESS_STREAM_RESULT_STOP;
2552                 goto finish;
2553             }
2554         }
2555
2556         /* update the focus status */
2557         ret = update_focus_status_of_stream(m, stream, type, is_new_data);
2558         if (ret == false)
2559             pa_log_warn("could not update focus status");
2560
2561         /* update the highest priority */
2562         ret = update_the_highest_priority_stream(m, command, stream, type, role, is_new_data, &need_update);
2563         if (ret == false) {
2564             pa_log_error("could not update the highest priority stream");
2565             result = PROCESS_STREAM_RESULT_SKIP;
2566             goto finish;
2567         }
2568
2569         /* need to skip if this stream does not belong to internal device */
2570         /* if needed, notify to update */
2571         if (need_update) {
2572             if (is_new_data) {
2573                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, true, stream);
2574                 if (type == STREAM_SINK_INPUT)
2575                     m->cur_highest_priority.need_to_update_si = true;
2576                 else
2577                     m->cur_highest_priority.need_to_update_so = true;
2578             } else {
2579                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, false, stream);
2580                 if (type == STREAM_SINK_INPUT) {
2581                     m->cur_highest_priority.sink_input = stream;
2582                     m->cur_highest_priority.role_si = role;
2583                 } else {
2584                     m->cur_highest_priority.source_output = stream;
2585                     m->cur_highest_priority.role_so = role;
2586                 }
2587             }
2588         }
2589
2590         if (!is_new_data)
2591             do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, false, stream);
2592
2593     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED) {
2594         role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2595         if (role) {
2596             /* unload forwarding device */
2597             if (type == STREAM_SOURCE_OUTPUT && pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
2598                 update_forwarding_device(m, false);
2599
2600             /* skip roles */
2601             if (check_role_to_skip(m, command, role)) {
2602                 result = PROCESS_STREAM_RESULT_SKIP;
2603                 goto finish;
2604             }
2605
2606             /* skip route types */
2607             if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2608                 if (check_route_type_to_skip(command, route_type_str)) {
2609                     result = PROCESS_STREAM_RESULT_SKIP;
2610                     goto finish;
2611                 }
2612             }
2613
2614             /* check if it has already been processed (unlink or state_changed_cb) */
2615             if (pa_proplist_get(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&prior_priority, &size)) {
2616                 pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, skip it..");
2617                 result = PROCESS_STREAM_RESULT_SKIP;
2618                 goto finish;
2619             }
2620
2621             pa_proplist_unset(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY);
2622             ret = update_the_highest_priority_stream(m, command, stream, type, role, is_new_data, &need_update);
2623             if (ret == false) {
2624                 pa_log_error("could not update the highest priority stream");
2625                 result = PROCESS_STREAM_RESULT_STOP;
2626                 goto finish;
2627             }
2628
2629             do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED, type, false, stream);
2630
2631             /* need to skip if this stream does not belong to internal device */
2632             /* if needed, notify to update */
2633             if (need_update)
2634                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
2635
2636         } else {
2637             pa_log_error("role is null, skip it");
2638         }
2639
2640     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED) {
2641         role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2642         if (role) {
2643             /* skip roles */
2644             if (check_role_to_skip(m, command, role)) {
2645                 result = PROCESS_STREAM_RESULT_SKIP;
2646                 goto finish;
2647             }
2648
2649             /* skip route types */
2650             if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2651                 if (check_route_type_to_skip(command, route_type_str)) {
2652                     result = PROCESS_STREAM_RESULT_SKIP;
2653                     goto finish;
2654                 }
2655             }
2656
2657             ret = update_the_highest_priority_stream(m, command, stream, type, role, is_new_data, &need_update);
2658             if (ret == false) {
2659                 pa_log_error("could not update the highest priority stream");
2660                 result = PROCESS_STREAM_RESULT_STOP;
2661                 goto finish;
2662             }
2663
2664             /* need to skip if this stream does not belong to internal device */
2665             /* if needed, notify to update */
2666             if (need_update)
2667                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
2668
2669         } else {
2670             pa_log_error("role is null, skip it");
2671         }
2672
2673     } else if (command == PROCESS_COMMAND_UPDATE_VOLUME && is_new_data) {
2674         if ((si_volume_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
2675             v = pa_hashmap_get(m->volume_infos, si_volume_type_str);
2676             if (v && v->values[type].idx_volume_values) {
2677                 /* Update volume-level */
2678                 if ((volume_ret = set_volume_level_with_new_data(m, stream, type, v->values[type].current_level)))
2679                     pa_log_error("failed to set_volume_level_by_idx(), stream_type(%d), level(%u), ret(0x%x)",
2680                                  type, v->values[type].current_level, volume_ret);
2681                 /* Update volume-mute */
2682                 if ((volume_ret = set_volume_mute_with_new_data(m, stream, type, v->values[type].is_muted)))
2683                     pa_log_error("failed to set_volume_mute_by_idx(), stream_type(%d), mute(%d), ret(0x%x)",
2684                                  type, v->values[type].is_muted, volume_ret);
2685             }
2686         }
2687
2688     } else if (command == PROCESS_COMMAND_ADD_PARENT_ID || command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
2689         role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2690         if (role) {
2691             /* skip roles */
2692             if (check_role_to_skip(m, command, role)) {
2693                 result = PROCESS_STREAM_RESULT_SKIP;
2694                 goto finish;
2695             }
2696
2697             /* skip route types */
2698             if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2699                 if (check_route_type_to_skip(command, route_type_str)) {
2700                     result = PROCESS_STREAM_RESULT_SKIP;
2701                     goto finish;
2702                 }
2703             }
2704
2705             if (!IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
2706                 if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
2707                     if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
2708                         m->cur_highest_priority.sink_input = stream;
2709                         m->cur_highest_priority.role_si = role;
2710                         m->cur_highest_priority.need_to_update_si = false;
2711                     }
2712                     if (type == STREAM_SOURCE_OUTPUT && m->cur_highest_priority.need_to_update_so) {
2713                         m->cur_highest_priority.source_output = stream;
2714                         m->cur_highest_priority.role_so = role;
2715                         m->cur_highest_priority.need_to_update_so = false;
2716                     }
2717                     do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, false, stream);
2718                 }
2719             }
2720
2721             /* update parent stream info. */
2722             ret = update_stream_parent_info(m, command, type, stream);
2723             if (ret == false) {
2724                 pa_log_debug("could not update the parent information of this stream");
2725                 //return PROCESS_STREAM_RESULT_STOP;
2726             }
2727         }
2728     } else if (command == PROCESS_COMMAND_UPDATE_BUFFER_ATTR) {
2729         update_buffer_attribute(m, stream, type, is_new_data);
2730     }
2731
2732 finish:
2733     pa_log_debug("<<< process_stream(%s): result(%d), stream(%p)", process_command_type_str[command], result, stream);
2734     return result;
2735 }
2736
2737 /* Remove the sink-input from muted streams */
2738 static void remove_sink_input_from_muted_streams(pa_stream_manager *m, pa_sink_input *i) {
2739     pa_idxset *streams;
2740     pa_sink_input *si;
2741     void *state;
2742     uint32_t idx = 0;
2743
2744     pa_assert(m);
2745
2746     PA_HASHMAP_FOREACH(streams, m->muted_streams, state)
2747         PA_IDXSET_FOREACH(si, streams, idx)
2748             if (si == i)
2749                 pa_idxset_remove_by_data(streams, i, NULL);
2750 }
2751
2752 static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data *new_data, pa_stream_manager *m) {
2753     pa_core_assert_ref(core);
2754
2755     pa_log_debug("start sink_input_new_cb");
2756
2757     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_PREPARE, true);
2758     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_BUFFER_ATTR, true);
2759     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, true);
2760     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, true);
2761
2762     return PA_HOOK_OK;
2763 }
2764
2765 static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2766     pa_core_assert_ref(core);
2767     pa_sink_input_assert_ref(i);
2768
2769     pa_log_debug("start sink_input_put_cb, i(%p, index:%u)", i, i->index);
2770
2771     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_ADD_PARENT_ID, false);
2772
2773     return PA_HOOK_OK;
2774 }
2775
2776 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2777     pa_core_assert_ref(core);
2778     pa_sink_input_assert_ref(i);
2779
2780     pa_log_debug("start sink_input_unlink_cb, i(%p, index:%u)", i, i->index);
2781
2782     remove_sink_input_from_muted_streams(m, i);
2783     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_REMOVE_PARENT_ID, false);
2784     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
2785
2786     return PA_HOOK_OK;
2787 }
2788
2789 static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2790     pa_sink_input_state_t state;
2791
2792     pa_assert(i);
2793     pa_assert(m);
2794
2795     state = pa_sink_input_get_state(i);
2796     pa_log_debug("start sink_input_state_changed_cb(), sink-input(%p), state(%d)", i, state);
2797
2798     switch (state) {
2799     case PA_SINK_INPUT_CORKED: {
2800         process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
2801         break;
2802     }
2803     case PA_SINK_INPUT_DRAINED:
2804     case PA_SINK_INPUT_RUNNING: {
2805         process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
2806         break;
2807     }
2808     default:
2809         break;
2810     }
2811
2812     return PA_HOOK_OK;
2813 }
2814
2815 static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2816     pa_core_assert_ref(core);
2817     pa_sink_input_assert_ref(i);
2818
2819     /* There's no point in doing anything if the core is shut down anyway */
2820     if (core->state == PA_CORE_SHUTDOWN)
2821         return PA_HOOK_OK;
2822
2823     pa_log_debug("sink_input_move_start_cb, i(%p, index:%u)", i, i->index);
2824
2825     set_volume_mute_by_idx(m, i->index, STREAM_SINK_INPUT, true);
2826
2827     return PA_HOOK_OK;
2828 }
2829
2830 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2831     pa_core_assert_ref(core);
2832     pa_sink_input_assert_ref(i);
2833
2834     /* There's no point in doing anything if the core is shut down anyway */
2835     if (core->state == PA_CORE_SHUTDOWN)
2836         return PA_HOOK_OK;
2837
2838     pa_log_debug("sink_input_move_finish_cb, i(%p, index:%u)", i, i->index);
2839
2840     set_volume_mute_by_idx(m, i->index, STREAM_SINK_INPUT, false);
2841
2842     return PA_HOOK_OK;
2843 }
2844
2845 static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new_data *new_data, pa_stream_manager *m) {
2846     pa_core_assert_ref(core);
2847
2848     pa_log_info("start source_output_new_new_cb");
2849
2850     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_PREPARE, true);
2851     if (check_restrictions(m, new_data, STREAM_SOURCE_OUTPUT))
2852         return PA_HOOK_CANCEL;
2853     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_BUFFER_ATTR, true);
2854     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_VOLUME, true);
2855     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, true);
2856
2857     return PA_HOOK_OK;
2858 }
2859
2860 static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2861     pa_core_assert_ref(core);
2862     pa_source_output_assert_ref(o);
2863
2864     pa_log_info("start source_output_put_cb, o(%p, index:%u)", o, o->index);
2865
2866     update_mirroring_streams(m, o, true);
2867     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_PARENT_ID, false);
2868
2869     return PA_HOOK_OK;
2870 }
2871
2872 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2873     pa_core_assert_ref(core);
2874     pa_source_output_assert_ref(o);
2875
2876     pa_log_info("start source_output_unlink_cb, o(%p, index:%u)", o, o->index);
2877
2878     update_mirroring_streams(m, o, false);
2879     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
2880     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_REMOVE_PARENT_ID, false);
2881
2882     return PA_HOOK_OK;
2883 }
2884
2885 static pa_hook_result_t source_output_state_changed_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2886     pa_source_output_state_t state;
2887
2888     pa_assert(o);
2889     pa_assert(m);
2890
2891     state = pa_source_output_get_state(o);
2892     pa_log_debug("start source_output_state_changed_cb(), source-output(%p), state(%d)", o, state);
2893
2894     switch (state) {
2895     case PA_SOURCE_OUTPUT_CORKED: {
2896         process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
2897         break;
2898     }
2899     case PA_SOURCE_OUTPUT_RUNNING: {
2900         process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
2901         break;
2902     }
2903     default:
2904         break;
2905     }
2906
2907     return PA_HOOK_OK;
2908 }
2909
2910 static pa_hook_result_t source_output_move_start_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2911     pa_core_assert_ref(core);
2912     pa_source_output_assert_ref(o);
2913
2914     /* There's no point in doing anything if the core is shut down anyway */
2915     if (core->state == PA_CORE_SHUTDOWN)
2916         return PA_HOOK_OK;
2917
2918     pa_log_debug("source_output_move_start_cb, o(%p, index:%u)", o, o->index);
2919
2920     set_volume_mute_by_idx(m, o->index, STREAM_SINK_INPUT, true);
2921
2922     return PA_HOOK_OK;
2923 }
2924
2925 static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2926     pa_core_assert_ref(core);
2927     pa_source_output_assert_ref(o);
2928
2929     /* There's no point in doing anything if the core is shut down anyway */
2930     if (core->state == PA_CORE_SHUTDOWN)
2931         return PA_HOOK_OK;
2932
2933     pa_log_debug("source_output_move_finish_cb, o(%p, index:%u)", o, o->index);
2934
2935     set_volume_mute_by_idx(m, o->index, STREAM_SINK_INPUT, false);
2936
2937     return PA_HOOK_OK;
2938 }
2939
2940 static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *role, stream_type_t stream_type, const char *cur_device_type, pa_tz_device **next_device) {
2941     stream_info *si = NULL;
2942     pa_idxset *devices = NULL;
2943     uint32_t idx = 0;
2944     char *device_type = NULL;
2945     bool ret_next = false;
2946     pa_usec_t creation_time = 0;
2947     pa_usec_t latest_creation_time = 0;
2948     pa_tz_device* latest_device = NULL;
2949
2950     pa_assert(m);
2951     pa_assert(m->stream_infos);
2952     pa_assert(role);
2953     pa_assert(cur_device_type);
2954     pa_assert(next_device);
2955     pa_assert((route_type == STREAM_ROUTE_TYPE_AUTO || route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED));
2956
2957     *next_device = NULL;
2958
2959     if (!(si = pa_hashmap_get(m->stream_infos, role))) {
2960         pa_log_warn("not support this role[%s]", role);
2961         return;
2962     }
2963     if (si->route_type != route_type) {
2964         pa_log_warn("skip this route_type[%d]", si->route_type);
2965         return;
2966     }
2967
2968     if (!(devices = (stream_type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices)) {
2969         pa_log_error("could not found a device list for this role[%s], stream type[%d]", role, stream_type);
2970         return;
2971     }
2972
2973     if (route_type == STREAM_ROUTE_TYPE_AUTO) {
2974         PA_IDXSET_FOREACH(device_type, devices, idx) {
2975             if (pa_streq(device_type, cur_device_type)) {
2976                 ret_next = true;
2977                 continue;
2978             }
2979             if (ret_next) {
2980                 if ((*next_device = pa_device_manager_get_device(m->dm, device_type))) {
2981                     pa_log_debug("found next device[%s, %p]", device_type, *next_device);
2982                     break;
2983                 } else
2984                     continue;
2985             }
2986         }
2987     } else if (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
2988         PA_IDXSET_FOREACH(device_type, devices, idx) {
2989             if ((*next_device = pa_device_manager_get_device(m->dm, device_type))) {
2990                 creation_time = pa_tz_device_get_creation_time(*next_device);
2991                 if (!latest_device || (latest_creation_time <= creation_time)) {
2992                     latest_device = *next_device;
2993                     latest_creation_time = creation_time;
2994                 }
2995             }
2996         }
2997         *next_device = latest_device;
2998         pa_log_debug("found next device[%s, %p], creation_time[%llu]", device_type, *next_device, latest_creation_time);
2999     }
3000
3001     pa_log_debug("next_device is [%p] for role[%s]/route_type[%d]/stream_type[%d]", *next_device, role, route_type, stream_type);
3002 }
3003
3004 static void is_available_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *cur_device_type, const char *new_device_type, const char *role, stream_type_t stream_type, bool *available) {
3005     stream_info *si = NULL;
3006     pa_idxset *devices = NULL;
3007     uint32_t idx = 0;
3008     char *device_type = NULL;
3009
3010     pa_assert(m);
3011     pa_assert(m->stream_infos);
3012     pa_assert(role);
3013     pa_assert(cur_device_type);
3014     pa_assert(new_device_type);
3015     pa_assert(available);
3016     pa_assert((route_type == STREAM_ROUTE_TYPE_AUTO || route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED));
3017
3018     *available = false;
3019
3020     if (!(si = pa_hashmap_get(m->stream_infos, role))) {
3021         pa_log_warn("not support this role[%s]", role);
3022         return;
3023     }
3024     if (si->route_type != route_type) {
3025         pa_log_warn("skip this route_type[%d]", si->route_type);
3026         return;
3027     }
3028
3029     if (!(devices = (stream_type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices)) {
3030         pa_log_error("could not found a device list for this role[%s], stream type[%d]", role, stream_type);
3031         return;
3032     }
3033
3034     PA_IDXSET_FOREACH(device_type, devices, idx) {
3035         if (route_type == STREAM_ROUTE_TYPE_AUTO) {
3036             if (pa_streq(device_type, cur_device_type)) {
3037                 pa_log_debug("cur_device[%s]'s priority is more higher than new_device[%s]", cur_device_type, new_device_type);
3038                 break;
3039             }
3040         }
3041         if (pa_streq(device_type, new_device_type)) {
3042             *available = true;
3043             break;
3044         }
3045     }
3046
3047     pa_log_debug("is new_device[%s] available for role[%s]/stream_type[%d]:%d", new_device_type, role, stream_type, *available);
3048 }
3049
3050 /* Re-trigger for routing update for streams using auto route type */
3051 static void process_stream_as_device_change_for_auto_route(pa_stream_manager *m, void *stream, stream_type_t stream_type,
3052                                                            bool is_connected, bool use_internal_codec) {
3053     stream_route_type_t route_type;
3054
3055     pa_assert(m);
3056     pa_assert(stream);
3057
3058     pa_log_info("[SM][PROCESS_STREAM_FOR_AUTO] stream(%p), stream_type(%d), is_connected(%d), use_internal_codec(%d)",
3059         stream, stream_type, is_connected, use_internal_codec);
3060
3061     if (get_route_type(stream, stream_type, false, &route_type) ||
3062         (route_type != STREAM_ROUTE_TYPE_AUTO && route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))
3063         return;
3064
3065     if (is_connected) {
3066         /* it is caused by the connection of supported device for the stream */
3067         if (use_internal_codec) {
3068             if (((stream_type == STREAM_SINK_INPUT) && (!m->cur_highest_priority.sink_input || (m->cur_highest_priority.sink_input != stream))) ||
3069                 ((stream_type == STREAM_SOURCE_OUTPUT) && (!m->cur_highest_priority.source_output || (m->cur_highest_priority.source_output != stream))))
3070                 process_stream(m, stream, stream_type, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
3071         } else
3072             process_stream(m, stream, stream_type, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
3073     } else {
3074         /* it is caused by the disconnection of external device
3075          * and the supported next device of this stream using internal audio codec */
3076         if (use_internal_codec)
3077             process_stream(m, stream, stream_type, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
3078     }
3079 }
3080
3081 /* The state of a device using internal audio codec is handled here.
3082  * Regarding the state of an external device, those is handled in device-manager.c */
3083 static void set_device_state_if_using_internal_codec(pa_tz_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
3084     bool use_internal_codec = false;
3085
3086     pa_assert(device);
3087
3088     if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device)))
3089         pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
3090 }
3091
3092 static void update_sink_or_source_as_device_change(stream_route_type_t stream_route_type, pa_idxset *streams,
3093                                                    stream_type_t stream_type, pa_tz_device *device, bool is_connected, pa_stream_manager *m) {
3094     #define MAX_CACHED_LEN 128
3095     typedef struct _cached_device_list {
3096         const char *device_type;
3097         int count;
3098     } cached_device_list;
3099     void *s = NULL;
3100     uint32_t s_idx = 0;
3101     const char *role = NULL;
3102     const char *device_type = NULL;
3103     const char *cur_device_type = NULL;
3104     const char *new_device_type = NULL;
3105     pa_tz_device *next_device = NULL;
3106     pa_tz_device *_device = NULL;
3107     stream_route_type_t route_type;
3108     pa_sink *sink = NULL;
3109     pa_sink *next_sink = NULL;
3110     pa_sink *null_sink = NULL;
3111     pa_source *source = NULL;
3112     pa_source *next_source = NULL;
3113     pa_source *null_source = NULL;
3114     bool available = false;
3115     bool use_internal_codec = false;
3116     cached_device_list cached_prev_dev_list[MAX_CACHED_LEN] = {{NULL, 0}, };
3117     uint32_t cnt = 0;
3118     pa_sink *combine_sink = NULL;
3119
3120     pa_assert(streams);
3121     pa_assert(device);
3122     pa_assert(m);
3123
3124     null_sink = (pa_sink*)pa_namereg_get(m->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
3125     null_source = (pa_source*)pa_namereg_get(m->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE);
3126     if (!null_sink || !null_source) {
3127         pa_log_error("[SM][UPDATE_SINK_SOURCE] could not get null_sink(%p) or null_source(%p)", null_sink, null_source);
3128         return;
3129     }
3130     device_type = pa_tz_device_get_type(device);
3131
3132     if (stream_route_type == STREAM_ROUTE_TYPE_AUTO || stream_route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
3133         pa_log_debug("[SM][UPDATE_SINK_SOURCE][AUTO] route_type(%d), deivce_type(%s), is_connected(%d))",
3134                      stream_route_type, device_type, is_connected);
3135         if (stream_type == STREAM_SINK_INPUT)
3136             sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
3137         else
3138             source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL);
3139
3140         PA_IDXSET_FOREACH(s, streams, s_idx) { /* streams: core->source_outputs/core->sink_inputs */
3141             if (!get_route_type(s, stream_type, false, &route_type) && (route_type == stream_route_type)) {
3142                 role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE);
3143                 pa_log_debug("  -- idx(%u), route_type(%d), role(%s)", s_idx, route_type, role);
3144                 if (is_connected) {
3145                     /* CONNECTED: move a stream to the new device if possible */
3146                     if (sink && (sink != ((pa_sink_input*)s)->sink)) {
3147                         if ((cur_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
3148                             is_available_device_for_auto_route(m, route_type, cur_device_type, device_type, role, stream_type, &available);
3149                             if (available) {
3150                                 pa_sink_input_move_to(s, sink, false);
3151                                 pa_log_debug("  -- *** sink-input(%p,%u) moves to sink(%p,%s), new device(%s)",
3152                                              s, ((pa_sink_input*)s)->index, sink, sink->name, device_type);
3153                                 use_internal_codec = sink->use_internal_codec;
3154                             }
3155                         } else
3156                             pa_log_error("  -- could not find current device type for s->sink(%p)", ((pa_sink_input*)s)->sink);
3157                     } else if (source && (source != ((pa_source_output*)s)->source)) {
3158                         if ((cur_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
3159                             is_available_device_for_auto_route(m, route_type, cur_device_type, device_type, role, stream_type, &available);
3160                             if (available) {
3161                                 pa_source_output_move_to(s, source, false);
3162                                 pa_log_debug("  -- *** source-output(%p,%u) moves to source(%p,%s), new device(%s)",
3163                                              s, ((pa_source_output*)s)->index, source, source->name, device_type);
3164                                 use_internal_codec = source->use_internal_codec;
3165                             }
3166                         } else
3167                             pa_log_error("  -- could not find current device type for s->source(%p)", ((pa_source_output*)s)->source);
3168                     } else
3169                         pa_log_debug("no need to move for stream(%p, idx:%u)", s, (stream_type == STREAM_SINK_INPUT ?
3170                                      ((pa_sink_input*)s)->index : ((pa_source_output*)s)->index));
3171                     if (available) {
3172                         /* update activated device */
3173                         pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
3174                         if ((_device = pa_device_manager_get_device(m->dm, device_type)))
3175                             set_device_state_if_using_internal_codec(_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
3176                         cached_prev_dev_list[cnt++].device_type = cur_device_type;
3177                         /* trigger to update routing path */
3178                         process_stream_as_device_change_for_auto_route(m, s, stream_type, is_connected, use_internal_codec);
3179                     }
3180                 } else if (!is_connected) {
3181                     /* DISCONNECTED: find a connected device that has the next priority */
3182                     if (sink && (sink == ((pa_sink_input*)s)->sink)) {
3183                         find_next_device_for_auto_route(m, route_type, role, stream_type, device_type, &next_device);
3184                         if (next_device) {
3185                             if ((next_sink = pa_tz_device_get_sink(next_device, DEVICE_ROLE_NORMAL))) {
3186                                 new_device_type = pa_tz_device_get_type(next_device);
3187                                 /* update activated device */
3188                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
3189                                 set_device_state_if_using_internal_codec(next_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
3190                                 cached_prev_dev_list[cnt++].device_type = device_type;
3191                                 /* trigger to update routing path if the next device uses internal audio codec */
3192                                 if (next_sink->use_internal_codec)
3193                                     process_stream_as_device_change_for_auto_route(m, s, stream_type, is_connected, next_sink->use_internal_codec);
3194
3195                                 pa_sink_input_move_to(s, next_sink, false);
3196                                 pa_log_debug("  -- *** sink-input(%p,%u) moves to sink(%p,%s), new device(%s)",
3197                                              s, ((pa_sink_input*)s)->index, next_sink, next_sink->name, new_device_type);
3198                                 }
3199                         }
3200
3201                         if (!next_device || !next_sink) {
3202                             pa_sink_input_move_to(s, null_sink, false);
3203                             pa_log_debug("  -- *** sink-input(%p,%u) moves to sink(%p,%s)",
3204                                 s, ((pa_sink_input*)s)->index, null_sink, null_sink->name);
3205                         }
3206
3207                     } else if (source && (source == ((pa_source_output*)s)->source)) {
3208                         find_next_device_for_auto_route(m, route_type, role, stream_type, device_type, &next_device);
3209                         if (next_device) {
3210                             if ((next_source = pa_tz_device_get_source(next_device, DEVICE_ROLE_NORMAL))) {
3211                                 new_device_type = pa_tz_device_get_type(next_device);
3212                                 /* update activated device */
3213                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
3214                                 set_device_state_if_using_internal_codec(next_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
3215                                 cached_prev_dev_list[cnt++].device_type = device_type;
3216                                 /* trigger to update routing path if the next device uses internal audio codec */
3217                                 if (next_source->use_internal_codec)
3218                                     process_stream_as_device_change_for_auto_route(m, s, stream_type, is_connected, next_source->use_internal_codec);
3219
3220                                 pa_source_output_move_to(s, next_source, false);
3221                                 pa_log_debug("  -- *** source-output(%p,%u) moves to source(%p,%s), new device(%s)",
3222                                              s, ((pa_source_output*)s)->index, next_source, next_source->name, new_device_type);
3223                                 }
3224                         }
3225                         if (!next_device || !next_source) {
3226                             pa_source_output_move_to(s, null_source, false);
3227                             pa_log_debug("  -- *** source-output(%p,%u) moves to source(%p,%s)",
3228                                 s, ((pa_source_output*)s)->index, null_source, null_source->name);
3229                         }
3230                     }
3231                 }
3232             }
3233         }
3234
3235         /* set device state to be deactivated */
3236         if (cnt) {
3237             if (stream_type == STREAM_SINK_INPUT) {
3238                 combine_sink = (pa_sink*)pa_namereg_get(m->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
3239                 if (combine_sink && pa_idxset_size(combine_sink->inputs)) {
3240                     pa_log_warn("  -- combine sink has streams, skip it..");
3241                     return;
3242                 }
3243             }
3244             /* retrieve all the streams for checking current activated device */
3245             PA_IDXSET_FOREACH(s, streams, s_idx) { /* streams: core->source_outputs/core->sink_inputs */
3246                 if ((cur_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
3247                     for (cnt = 0; cached_prev_dev_list[cnt].device_type; cnt++) {
3248                         if (pa_streq(cur_device_type, cached_prev_dev_list[cnt].device_type))
3249                             cached_prev_dev_list[cnt].count++;
3250                     }
3251                 }
3252             }
3253             /* if there's no activated device marked in previous device list, set it to be deactivated */
3254             for (cnt = 0; cached_prev_dev_list[cnt].device_type; cnt++) {
3255                 if (cached_prev_dev_list[cnt].count == 0) {
3256                     if ((_device = pa_device_manager_get_device(m->dm, cached_prev_dev_list[cnt].device_type)))
3257                         set_device_state_if_using_internal_codec(_device, stream_type, DM_DEVICE_STATE_DEACTIVATED);
3258                 }
3259             }
3260         }
3261
3262     } else if (stream_route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
3263         pa_log_debug("[SM][UPDATE_SINK_SOURCE][EXT] deivce_type(%s), is_connected(%d))", device_type, is_connected);
3264         if (!is_connected) {
3265             PA_IDXSET_FOREACH(s, streams, s_idx) { /* streams: source->outputs/sink->inputs */
3266                 if (!get_route_type(s, stream_type, false, &route_type) && route_type == stream_route_type) {
3267                     if (stream_type == STREAM_SOURCE_OUTPUT) {
3268                         /* move it to null source if this role is for external device */
3269                         pa_source_output_move_to((pa_source_output*)s, null_source, false);
3270                         pa_log_debug("  -- *** source-output(%p,%u) moves to source(%p,%s)", s, ((pa_source_output*)s)->index, null_source, null_source->name);
3271                     } else {
3272                         /* move it to null sink if this role is for external device */
3273                         pa_sink_input_move_to((pa_sink_input*)s, null_sink, false);
3274                         pa_log_debug("  -- *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, null_sink, null_sink->name);
3275                     }
3276                 }
3277             }
3278         }
3279     } else
3280         pa_log_error("[SM][UPDATE_SINK_SOURCE] could not handle it here, stream_route_type(%d)", stream_route_type);
3281 }
3282
3283 static void mute_sink_inputs_as_device_disconnection(pa_stream_manager *m, uint32_t event_id, bool need_to_mute, void *user_data) {
3284     pa_idxset *muted_streams;
3285     uint32_t s_idx = 0;
3286     pa_cvolume vol;
3287     pa_sink_input *i;
3288     const char *mute_key = "mute_by_device_disconnection";
3289
3290     pa_assert(m);
3291
3292     if (need_to_mute) {
3293         if (!user_data) {
3294             pa_log_error("invalid argument, inputs is needed");
3295             return;
3296         }
3297         vol.channels = 1;
3298         pa_parse_volume("0%", &vol.values[0]);
3299         muted_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3300         PA_IDXSET_FOREACH(i, (pa_idxset *)user_data, s_idx) {
3301             pa_log_debug("found a stream(%p, %u) that should be muted.", i, i->index);
3302             pa_sink_input_add_volume_factor(i, mute_key, &vol);
3303             pa_idxset_put(muted_streams, i, NULL);
3304         }
3305         pa_hashmap_put(m->muted_streams, (void*)event_id, muted_streams);
3306     } else {
3307         if (!(muted_streams = pa_hashmap_get(m->muted_streams, (void*)event_id))) {
3308             pa_log_debug("could not find muted_streams for event_id(%u)", event_id);
3309             return;
3310         }
3311         PA_IDXSET_FOREACH(i, muted_streams, s_idx) {
3312             pa_idxset_remove_by_data(muted_streams, i, NULL);
3313             pa_sink_input_remove_volume_factor(i, mute_key);
3314             pa_log_debug("found a stream(%p, %u) that should be un-muted.", i, i->index);
3315         }
3316         pa_hashmap_remove(m->muted_streams, (void*)event_id);
3317         pa_idxset_free(muted_streams, NULL);
3318     }
3319
3320     return;
3321 }
3322
3323 static pa_hook_result_t event_fully_handled_hook_cb(pa_core *c, pa_subscribe_observer_hook_data_for_event_handled *event_handled_hook_data, pa_stream_manager *m) {
3324     pa_assert(c);
3325     pa_assert(event_handled_hook_data);
3326     pa_assert(m);
3327
3328     pa_log_info("[SM][HANDLED] event_fully_handled_hook_cb is called. event-id(%u), event-type(%d)",
3329                 event_handled_hook_data->event_id, event_handled_hook_data->event_type);
3330
3331     /* un-mute streams */
3332     mute_sink_inputs_as_device_disconnection(m, event_handled_hook_data->event_id, false, NULL);
3333
3334     return PA_HOOK_OK;
3335 }
3336
3337 /* Reorganize routing when a device has been connected or disconnected */
3338 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_conn_changed *data, pa_stream_manager *m) {
3339     const char *active_dev = NULL;
3340     const char *device_type = NULL;
3341     stream_route_type_t route_type;
3342     dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
3343     bool use_internal_codec = false;
3344     void *s = NULL;
3345     uint32_t s_idx = 0;
3346     uint32_t device_id = 0;
3347     pa_sink *sink = NULL;
3348     pa_source *source = NULL;
3349
3350     pa_assert(c);
3351     pa_assert(data);
3352     pa_assert(m);
3353
3354     device_direction = pa_tz_device_get_direction(data->device);
3355     device_type = pa_tz_device_get_type(data->device);
3356     device_id = pa_tz_device_get_id(data->device);
3357     use_internal_codec = pa_tz_device_is_use_internal_codec(data->device);
3358
3359     pa_log_info("[SM][CONN] device_connection_changed_hook_cb is called. evend_id(%u), is_connected(%d), device(%p, %s, %u), direction(0x%x), use_internal_codec(%d)",
3360                 data->event_id, data->is_connected, data->device, device_type, device_id, device_direction, use_internal_codec);
3361
3362     /* mute all the streams belong to this device, those will be un-muted in event_fully_handled_hook_cb */
3363     if (!data->is_connected && (device_direction & DM_DEVICE_DIRECTION_OUT))
3364         if ((sink = pa_tz_device_get_sink(data->device, DEVICE_ROLE_NORMAL)))
3365             mute_sink_inputs_as_device_disconnection(m, data->event_id, true, sink->inputs);
3366
3367     /* Update streams belong to this external device that have MAUAL_EXT route type */
3368     if (!use_internal_codec && (device_direction & DM_DEVICE_DIRECTION_IN)) {
3369         if ((source = pa_tz_device_get_source(data->device, DEVICE_ROLE_NORMAL)))
3370             update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_MANUAL_EXT, source->outputs,
3371                                                    STREAM_SOURCE_OUTPUT, data->device, data->is_connected, m);
3372         else
3373             pa_log_error("[SM][CONN] could not get source");
3374     }
3375     if (!use_internal_codec && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
3376         if ((sink = pa_tz_device_get_sink(data->device, DEVICE_ROLE_NORMAL)))
3377             update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_MANUAL_EXT, sink->inputs,
3378                                                    STREAM_SINK_INPUT, data->device, data->is_connected, m);
3379         else
3380             pa_log_error("[SM][CONN] could not get sink");
3381     }
3382
3383     /* Update all the streams that have AUTO route type */
3384     if (device_direction & DM_DEVICE_DIRECTION_IN) {
3385         update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO, m->core->source_outputs,
3386                                                STREAM_SOURCE_OUTPUT, data->device, data->is_connected, m);
3387         update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->source_outputs,
3388                                                STREAM_SOURCE_OUTPUT, data->device, data->is_connected, m);
3389     }
3390     if (device_direction & DM_DEVICE_DIRECTION_OUT) {
3391         update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO, m->core->sink_inputs,
3392                                                STREAM_SINK_INPUT, data->device, data->is_connected, m);
3393         update_sink_or_source_as_device_change(STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->sink_inputs,
3394                                                STREAM_SINK_INPUT, data->device, data->is_connected, m);
3395     }
3396
3397
3398     /* If the route type of the stream is not manual, notify again */
3399     if (m->cur_highest_priority.source_output && (device_direction & DM_DEVICE_DIRECTION_IN)) {
3400         if (!get_route_type(m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT, false, &route_type)) {
3401             if (route_type < STREAM_ROUTE_TYPE_MANUAL) {
3402                 if (use_internal_codec) {
3403                     PA_IDXSET_FOREACH(s, m->cur_highest_priority.source_output->source->outputs, s_idx) {
3404                         if (!data->is_connected && !get_route_type(s, STREAM_SOURCE_OUTPUT, false, &route_type) &&
3405                             ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
3406                             /* remove activated device info. if it has the AUTO route type */
3407                             active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
3408                             if (active_dev && pa_streq(active_dev, device_type))
3409                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
3410                         }
3411                     }
3412                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, false, m->cur_highest_priority.source_output);
3413                     if (!((pa_source_output*)(m->cur_highest_priority.source_output))->source->use_internal_codec) {
3414                         /* If the source of the cur_highest_priority stream uses external codec, it should be updated.
3415                          * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
3416                          * can update the cur_highest_priority, call it here */
3417                         process_stream(m, m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
3418                     }
3419                 }
3420             }
3421         }
3422     }
3423     if (m->cur_highest_priority.sink_input && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
3424         if (!get_route_type(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT, false, &route_type)) {
3425             if (route_type < STREAM_ROUTE_TYPE_MANUAL) {
3426                 if (use_internal_codec) {
3427                     PA_IDXSET_FOREACH(s, m->cur_highest_priority.sink_input->sink->inputs, s_idx) {
3428                         if (!data->is_connected && !get_route_type(s, STREAM_SINK_INPUT, false, &route_type) &&
3429                             ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
3430                             /* remove activated device info. if it has the AUTO route type */
3431                             active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
3432                             if (active_dev && pa_streq(active_dev, device_type))
3433                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
3434                         }
3435                     }
3436                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
3437                     if (((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED)) &&
3438                        !((pa_sink_input*)(m->cur_highest_priority.sink_input))->sink->use_internal_codec) {
3439                         /* If the sink of the cur_highest_priority stream uses external codec, it should be updated.
3440                          * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
3441                          * can update the cur_highest_priority, call it here */
3442                         process_stream(m, m->cur_highest_priority.sink_input, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
3443                     }
3444                 } else if (route_type == STREAM_ROUTE_TYPE_AUTO_ALL)
3445                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
3446             }
3447         }
3448     }
3449
3450     return PA_HOOK_OK;
3451 }
3452
3453 static void subscribe_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, pa_stream_manager *m) {
3454     pa_client *client = NULL;
3455     stream_parent *sp = NULL;
3456     const char *name = NULL;
3457     uint32_t *device_id = NULL;
3458     uint32_t _idx = 0;
3459
3460     pa_core_assert_ref(core);
3461     pa_assert(m);
3462
3463     pa_log_info("subscribe_cb() is called, t(%x), idx(%u)", t, idx);
3464
3465     if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE)) {
3466         if ((client = pa_idxset_get_by_index(core->clients, idx)) == NULL) {
3467             pa_log_error(" - could not find any client that has idx(%u)", idx);
3468             return;
3469         }
3470         name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);
3471         if (!name || (name && !pa_streq(name, STREAM_MANAGER_CLIENT_NAME))) {
3472             pa_log_warn(" - this is not a client(%s) that we should take care of, skip it", name);
3473             return;
3474         }
3475         /* add a stream parent */
3476         sp = pa_xmalloc0(sizeof(stream_parent));
3477         sp->idx_sink_inputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3478         sp->idx_source_outputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3479         sp->idx_route_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
3480         sp->idx_route_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
3481         pa_hashmap_put(m->stream_parents, (void*)idx, sp);
3482         pa_log_debug(" - add sp(%p), idx(%u)", sp, idx);
3483
3484     } else if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE)) {
3485         /* remove the stream parent */
3486         sp = pa_hashmap_get(m->stream_parents, (const void*)idx);
3487         if (sp) {
3488             pa_log_debug(" - remove sp(%p), idx(%u)", sp, idx);
3489             pa_hashmap_remove(m->stream_parents, (const void*)idx);
3490             if (sp->idx_route_in_devices)
3491                 PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, _idx)
3492                     pa_xfree(device_id);
3493             if (sp->idx_route_out_devices)
3494                 PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, _idx)
3495                     pa_xfree(device_id);
3496             pa_idxset_free(sp->idx_sink_inputs, NULL);
3497             pa_idxset_free(sp->idx_source_outputs, NULL);
3498             pa_idxset_free(sp->idx_route_in_devices, NULL);
3499             pa_idxset_free(sp->idx_route_out_devices, NULL);
3500             pa_xfree(sp);
3501         } else {
3502             pa_log_error(" - could not find any stream_parent that has idx(%u)", idx);
3503         }
3504     }
3505 }
3506
3507 /* Message callback from HAL interface */
3508 static void message_cb(const char *name, int value, void *user_data) {
3509     pa_stream_manager *m;
3510     pa_stream_manager_hook_data_for_update_info hook_call_data;
3511
3512     pa_assert(user_data);
3513     pa_assert(name);
3514
3515     m = (pa_stream_manager*)user_data;
3516
3517     /* For module-loopback parameters */
3518     if (strstr(name, STREAM_ROLE_LOOPBACK)) {
3519         memset(&hook_call_data, 0, sizeof(pa_stream_manager_hook_data_for_update_info));
3520         hook_call_data.stream_role = STREAM_ROLE_LOOPBACK;
3521         hook_call_data.name = name;
3522         hook_call_data.value = value;
3523         pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_UPDATE_INFORMATION), &hook_call_data);
3524     }
3525 #ifdef HAVE_DBUS
3526     /* Others */
3527     else {
3528         send_command_signal(pa_dbus_connection_get(m->dbus_conn), name, value);
3529     }
3530 #endif
3531 }
3532
3533 static int32_t init_ipc(pa_stream_manager *m) {
3534     DBusError err;
3535     pa_dbus_connection *conn = NULL;
3536     static const DBusObjectPathVTable vtable = {
3537         .message_function = method_handler_for_vt,
3538     };
3539
3540     pa_assert(m);
3541
3542     pa_log_info("Initialization for IPC");
3543 #ifdef HAVE_DBUS
3544 #ifdef USE_DBUS_PROTOCOL
3545     m->dbus_protocol = pa_dbus_protocol_get(m->core);
3546     pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
3547     pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
3548 #else
3549
3550     dbus_error_init(&err);
3551
3552     if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
3553         if (conn) {
3554             pa_dbus_connection_unref(conn);
3555         }
3556         pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
3557         goto fail;
3558     } else {
3559         pa_log_notice("Got dbus connection");
3560     }
3561     m->dbus_conn = conn;
3562     pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
3563 #endif
3564 #else
3565     pa_log_error("DBUS is not supported\n");
3566     goto fail;
3567 #endif
3568
3569     return 0;
3570 fail:
3571     pa_log_error("failed to initialize stream manager ipc");
3572     return -1;
3573 }
3574
3575 static void deinit_ipc(pa_stream_manager *m) {
3576     pa_assert(m);
3577
3578 #ifdef HAVE_DBUS
3579 #ifdef USE_DBUS_PROTOCOL
3580     if (m->dbus_protocol) {
3581         pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
3582         pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
3583         pa_dbus_protocol_unref(m->dbus_protocol);
3584         m->dbus_protocol = NULL;
3585     }
3586 #else
3587     if (m->dbus_conn) {
3588         if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
3589             pa_log_error("failed to unregister object path");
3590         m->dbus_conn = NULL;
3591     }
3592 #endif
3593 #endif
3594 }
3595
3596 bool pa_stream_manager_check_name_is_vstream(void *stream, stream_type_t type, bool is_new_data) {
3597     return check_name_is_vstream(stream, type, is_new_data);
3598 }
3599
3600 int32_t pa_stream_manager_get_route_type(void *stream, stream_type_t stream_type, bool is_new_data, stream_route_type_t *stream_route_type) {
3601     return get_route_type(stream, stream_type, is_new_data, stream_route_type);
3602 }
3603
3604 pa_stream_manager* pa_stream_manager_init(pa_core *c) {
3605     pa_stream_manager *m;
3606
3607     pa_assert(c);
3608
3609     m = pa_xnew0(pa_stream_manager, 1);
3610     m->core = c;
3611
3612     m->hal = pa_hal_interface_get(c);
3613     if (pa_hal_interface_add_message_callback(m->hal, message_cb, m))
3614         pa_log_warn("skip adding message callback");
3615     m->dm = pa_device_manager_get(c);
3616     m->subs_ob = pa_subscribe_observer_get(c);
3617 #ifdef HAVE_DBUS
3618 #ifdef USE_DBUS_PROTOCOL
3619     m->dbus_protocol = NULL;
3620 #else
3621     m->dbus_conn = NULL;
3622 #endif
3623 #endif
3624     if (init_ipc(m))
3625         goto fail;
3626     if (init_stream_map(m))
3627         goto fail;
3628     if (init_volumes(m))
3629         goto fail;
3630     m->stream_parents = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3631     m->muted_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3632     m->mirroring_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3633
3634     m->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_cb, m);
3635     m->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_put_cb, m);
3636     m->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_unlink_cb, m);
3637     m->sink_input_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_state_changed_cb, m);
3638     m->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_move_start_cb, m);
3639     m->sink_input_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_move_finish_cb, m);
3640     m->source_output_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_new_cb, m);
3641     m->source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_put_cb, m);
3642     m->source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_cb, m);
3643     m->source_output_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_state_changed_cb, m);
3644     m->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_start_cb, m);
3645     m->sink_input_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_finish_cb, m);
3646
3647     m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, (pa_subscription_cb_t)subscribe_cb, m);
3648
3649     m->comm.comm = pa_communicator_get(c);
3650     m->comm.comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
3651             PA_HOOK_EARLY + 10, (pa_hook_cb_t)device_connection_changed_hook_cb, m);
3652     m->comm.comm_hook_event_fully_handled_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_EVENT_FULLY_HANDLED),
3653             PA_HOOK_EARLY + 10, (pa_hook_cb_t)event_fully_handled_hook_cb, m);
3654
3655     return m;
3656
3657 fail:
3658     pa_log_error("failed to initialize stream-manager");
3659     deinit_volumes(m);
3660     deinit_stream_map(m);
3661     deinit_ipc(m);
3662     if (m->hal) {
3663         pa_hal_interface_remove_message_callback(m->hal, message_cb);
3664         pa_hal_interface_unref(m->hal);
3665     }
3666     if (m->dm)
3667         pa_device_manager_unref(m->dm);
3668     if (m->subs_ob)
3669         pa_subscribe_observer_unref(m->subs_ob);
3670     pa_xfree(m);
3671     return 0;
3672 }
3673
3674 void pa_stream_manager_done(pa_stream_manager *m) {
3675     void *state;
3676     pa_idxset *streams;
3677
3678     pa_assert(m);
3679
3680     if (m->comm.comm) {
3681         if (m->comm.comm_hook_device_connection_changed_slot)
3682             pa_hook_slot_free(m->comm.comm_hook_device_connection_changed_slot);
3683         if (m->comm.comm_hook_event_fully_handled_slot)
3684             pa_hook_slot_free(m->comm.comm_hook_event_fully_handled_slot);
3685         pa_communicator_unref(m->comm.comm);
3686     }
3687
3688     if (m->subscription)
3689         pa_subscription_free(m->subscription);
3690
3691     if (m->sink_input_new_slot)
3692         pa_hook_slot_free(m->sink_input_new_slot);
3693     if (m->sink_input_put_slot)
3694         pa_hook_slot_free(m->sink_input_put_slot);
3695     if (m->sink_input_unlink_slot)
3696         pa_hook_slot_free(m->sink_input_unlink_slot);
3697     if (m->sink_input_state_changed_slot)
3698         pa_hook_slot_free(m->sink_input_state_changed_slot);
3699     if (m->sink_input_move_start_slot)
3700         pa_hook_slot_free(m->sink_input_move_start_slot);
3701     if (m->sink_input_move_finish_slot)
3702         pa_hook_slot_free(m->sink_input_move_finish_slot);
3703     if (m->source_output_new_slot)
3704         pa_hook_slot_free(m->source_output_new_slot);
3705     if (m->source_output_put_slot)
3706         pa_hook_slot_free(m->source_output_put_slot);
3707     if (m->source_output_unlink_slot)
3708         pa_hook_slot_free(m->source_output_unlink_slot);
3709     if (m->source_output_state_changed_slot)
3710         pa_hook_slot_free(m->source_output_state_changed_slot);
3711
3712     if (m->muted_streams) {
3713         PA_HASHMAP_FOREACH(streams, m->muted_streams, state)
3714             pa_idxset_free(streams, NULL);
3715         pa_hashmap_free(m->muted_streams);
3716     }
3717
3718     if (m->mirroring_streams) {
3719         if (pa_idxset_size(m->mirroring_streams))
3720             update_forwarding_device(m, false);
3721         pa_idxset_free(m->mirroring_streams, NULL);
3722     }
3723
3724     if (m->stream_parents)
3725         pa_hashmap_free(m->stream_parents);
3726
3727     deinit_volumes(m);
3728     deinit_stream_map(m);
3729     deinit_ipc(m);
3730
3731     if (m->subs_ob)
3732         pa_subscribe_observer_unref(m->subs_ob);
3733
3734     if (m->dm)
3735         pa_device_manager_unref(m->dm);
3736
3737     if (m->hal) {
3738         pa_hal_interface_remove_message_callback(m->hal, message_cb);
3739         pa_hal_interface_unref(m->hal);
3740     }
3741
3742     pa_xfree(m);
3743 }