pulseaudio changed latency type to string
[platform/upstream/pulseaudio.git] / src / modules / tizen / stream-manager.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2015 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
48 #ifdef HAVE_DBUS
49 #define ARR_ARG_MAX  32
50 #define STREAM_MANAGER_OBJECT_PATH "/org/pulseaudio/StreamManager"
51 #define STREAM_MANAGER_INTERFACE   "org.pulseaudio.StreamManager"
52 #define STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO            "GetStreamInfo"
53 #define STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST            "GetStreamList"
54 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES   "SetStreamRouteDevices"
55 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION    "SetStreamRouteOption"
56 #define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL           "SetVolumeLevel"
57 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL           "GetVolumeLevel"
58 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL       "GetVolumeMaxLevel"
59 #define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE            "SetVolumeMute"
60 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE            "GetVolumeMute"
61 #define STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE    "GetCurrentVolumeType" /* the type that belongs to the stream of the current max priority */
62
63 #define GET_STREAM_NEW_PROPLIST(stream, type) \
64       (type == STREAM_SINK_INPUT? ((pa_sink_input_new_data*)stream)->proplist : ((pa_source_output_new_data*)stream)->proplist)
65
66 #define GET_STREAM_PROPLIST(stream, type) \
67       (type == STREAM_SINK_INPUT? ((pa_sink_input*)stream)->proplist : ((pa_source_output*)stream)->proplist)
68
69 #define GET_STREAM_NEW_SAMPLE_SPEC(stream, type) \
70       (type == STREAM_SINK_INPUT? ((pa_sink_input_new_data*)stream)->sample_spec : ((pa_source_output_new_data*)stream)->sample_spec)
71
72 #define GET_STREAM_SAMPLE_SPEC(stream, type) \
73       (type == STREAM_SINK_INPUT? ((pa_sink_input*)stream)->sample_spec : ((pa_source_output*)stream)->sample_spec)
74
75
76 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata);
77 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
78 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
79 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata);
80 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
81 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
82 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
83 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
84 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
85 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
86 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
87 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
88 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata);
89
90 enum method_handler_index {
91     METHOD_HANDLER_GET_STREAM_INFO,
92     METHOD_HANDLER_GET_STREAM_LIST,
93     METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES,
94     METHOD_HANDLER_SET_STREAM_ROUTE_OPTION,
95     METHOD_HANDLER_SET_VOLUME_LEVEL,
96     METHOD_HANDLER_GET_VOLUME_LEVEL,
97     METHOD_HANDLER_GET_VOLUME_MAX_LEVEL,
98     METHOD_HANDLER_SET_VOLUME_MUTE,
99     METHOD_HANDLER_GET_VOLUME_MUTE,
100     METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE,
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                                              { "avail_in_devices", "as", "out" },
108                                             { "avail_out_devices", "as", "out" },
109                                             { "avail_frameworks", "as", "out"} };
110 static pa_dbus_arg_info get_stream_list_args[]  = { { "stream_type", "as", "out" },
111                                                      { "priority", "ai", "out" } };
112 static pa_dbus_arg_info set_stream_route_devices_args[]  = { { "parent_id", "u", "in" },
113                                                      { "route_in_devices", "au", "in" },
114                                                     { "route_out_devices", "au", "in" },
115                                                             { "ret_msg", "s", "out" } };
116 static pa_dbus_arg_info set_stream_route_option_args[]  = { { "parent_id", "u", "in" },
117                                                               { "name", "s", "in" },
118                                                               { "value", "i", "in" },
119                                                             { "ret_msg", "s", "out" } };
120 static pa_dbus_arg_info set_volume_level_args[]  = { { "io_direction", "s", "in" },
121                                                              { "type", "s", "in" },
122                                                             { "level", "u", "in" },
123                                                        { "ret_msg", "s", "out" } };
124 static pa_dbus_arg_info get_volume_level_args[]  = { { "io_direction", "s", "in" },
125                                                              { "type", "s", "in" },
126                                                            { "level", "u", "out" },
127                                                        { "ret_msg", "s", "out" } };
128 static pa_dbus_arg_info get_volume_max_level_args[]  = { { "io_direction", "s", "in" },
129                                                                  { "type", "s", "in" },
130                                                                { "level", "u", "out" },
131                                                            { "ret_msg", "s", "out" } };
132 static pa_dbus_arg_info set_volume_mute_args[]  = { { "io_direction", "s", "in" },
133                                                              { "type", "s", "in" },
134                                                            { "on/off", "u", "in" },
135                                                        { "ret_msg", "s", "out" } };
136 static pa_dbus_arg_info get_volume_mute_args[]  = { { "io_direction", "s", "in" },
137                                                             { "type", "s", "in" },
138                                                          { "on/off", "u", "out" },
139                                                       { "ret_msg", "s", "out" } };
140 static pa_dbus_arg_info get_current_volume_type_args[]  = { { "io_direction", "s", "in" },
141                                                             { "type", "s", "out" },
142                                                       { "ret_msg", "s", "out" } };
143 static const char* signature_args_for_in[] = { "s", "", "uauau", "usi", "ssu", "ss", "ss", "ssu", "ss", "s"};
144
145 static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
146     [METHOD_HANDLER_GET_STREAM_INFO] = {
147         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO,
148         .arguments = get_stream_info_args,
149         .n_arguments = sizeof(get_stream_info_args) / sizeof(pa_dbus_arg_info),
150         .receive_cb = handle_get_stream_info },
151     [METHOD_HANDLER_GET_STREAM_LIST] = {
152         .method_name = STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
153         .arguments = get_stream_list_args,
154         .n_arguments = sizeof(get_stream_list_args) / sizeof(pa_dbus_arg_info),
155         .receive_cb = handle_get_stream_list },
156     [METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES] = {
157         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES,
158         .arguments = set_stream_route_devices_args,
159         .n_arguments = sizeof(set_stream_route_devices_args) / sizeof(pa_dbus_arg_info),
160         .receive_cb = handle_set_stream_route_devices },
161     [METHOD_HANDLER_SET_STREAM_ROUTE_OPTION] = {
162         .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION,
163         .arguments = set_stream_route_option_args,
164         .n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
165         .receive_cb = handle_set_stream_route_option },
166     [METHOD_HANDLER_SET_VOLUME_LEVEL] = {
167         .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
168         .arguments = set_volume_level_args,
169         .n_arguments = sizeof(set_volume_level_args) / sizeof(pa_dbus_arg_info),
170         .receive_cb = handle_set_volume_level },
171     [METHOD_HANDLER_GET_VOLUME_LEVEL] = {
172         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL,
173         .arguments = get_volume_level_args,
174         .n_arguments = sizeof(get_volume_level_args) / sizeof(pa_dbus_arg_info),
175         .receive_cb = handle_get_volume_level },
176     [METHOD_HANDLER_GET_VOLUME_MAX_LEVEL] = {
177         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL,
178         .arguments = get_volume_max_level_args,
179         .n_arguments = sizeof(get_volume_max_level_args) / sizeof(pa_dbus_arg_info),
180         .receive_cb = handle_get_volume_max_level },
181     [METHOD_HANDLER_SET_VOLUME_MUTE] = {
182         .method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE,
183         .arguments = set_volume_mute_args,
184         .n_arguments = sizeof(set_volume_mute_args) / sizeof(pa_dbus_arg_info),
185         .receive_cb = handle_set_volume_mute },
186     [METHOD_HANDLER_GET_VOLUME_MUTE] = {
187         .method_name = STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE,
188         .arguments = get_volume_mute_args,
189         .n_arguments = sizeof(get_volume_mute_args) / sizeof(pa_dbus_arg_info),
190         .receive_cb = handle_get_volume_mute },
191     [METHOD_HANDLER_GET_CURRENT_VOLUME_TYPE] = {
192         .method_name = STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE,
193         .arguments = get_current_volume_type_args,
194         .n_arguments = sizeof(get_current_volume_type_args) / sizeof(pa_dbus_arg_info),
195         .receive_cb = handle_get_current_volume_type },
196 };
197
198 const char *dbus_str_none = "none";
199 const char* stream_manager_dbus_ret_str[] = {"STREAM_MANAGER_RETURN_OK","STREAM_MANAGER_RETURN_ERROR", "STREAM_MANAGER_RETURN_ERROR_NO_STREAM"};
200 enum {
201     RET_MSG_INDEX_OK,
202     RET_MSG_INDEX_ERROR,
203     RET_MSG_INDEX_ERROR_NO_STREAM,
204 };
205
206 #ifdef USE_DBUS_PROTOCOL
207
208 static pa_dbus_interface_info stream_manager_interface_info = {
209     .name = STREAM_MANAGER_INTERFACE,
210     .method_handlers = method_handlers,
211     .n_method_handlers = METHOD_HANDLER_MAX,
212     .property_handlers = ,
213     .n_property_handlers = ,
214     .get_all_properties_cb =,
215     .signals =,
216     .n_signals =
217 };
218
219 #else
220
221 #define STREAM_MGR_INTROSPECT_XML                                            \
222     DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE                                \
223     "<node>"                                                                 \
224     " <interface name=\"STREAM_MANAGER_INTERFACE\">"                         \
225     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_INFO\">"         \
226     "   <arg name=\"stream_type\" direction=\"in\" type=\"s\"/>"             \
227     "   <arg name=\"priority\" direction=\"out\" type=\"i\"/>"               \
228     "   <arg name=\"route_type\" direction=\"out\" type=\"i\"/>"             \
229     "   <arg name=\"avail_in_devices\" direction=\"out\" type=\"as\"/>"      \
230     "   <arg name=\"avail_out_devices\" direction=\"out\" type=\"as\"/>"     \
231     "   <arg name=\"avail_frameworks\" direction=\"out\" type=\"as\"/>"      \
232     "  </method>"                                                            \
233     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST\">"         \
234     "   <arg name=\"stream_type\" direction=\"in\" type=\"as\"/>"            \
235     "   <arg name=\"priority\" direction=\"in\" type=\"ai\"/>"               \
236     "  </method>"                                                            \
237     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES\">"\
238     "   <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>"               \
239     "   <arg name=\"route_in_devices\" direction=\"in\" type=\"au\"/>"       \
240     "   <arg name=\"route_out_devices\" direction=\"in\" type=\"au\"/>"      \
241     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
242     "  </method>"                                                            \
243     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION\">" \
244     "   <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>"               \
245     "   <arg name=\"name\" direction=\"in\" type=\"s\"/>"                    \
246     "   <arg name=\"value\" direction=\"in\" type=\"i\"/>"                   \
247     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
248     "  </method>"                                                            \
249     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL\">"        \
250     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
251     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
252     "   <arg name=\"level\" direction=\"in\" type=\"u\"/>"                   \
253     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
254     "  </method>"                                                            \
255     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL\">"        \
256     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
257     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
258     "   <arg name=\"level\" direction=\"out\" type=\"u\"/>"                  \
259     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
260     "  </method>"                                                            \
261     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL\">"    \
262     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
263     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
264     "   <arg name=\"level\" direction=\"out\" type=\"u\"/>"                  \
265     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
266     "  </method>"                                                            \
267     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_VOLUME_MUTE\">"         \
268     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
269     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
270     "   <arg name=\"on/off\" direction=\"in\" type=\"u\"/>"                  \
271     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
272     "  </method>"                                                            \
273     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MUTE\">"         \
274     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
275     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
276     "   <arg name=\"on/off\" direction=\"out\" type=\"u\"/>"                 \
277     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
278     "  </method>"                                                            \
279     "  <method name=\"STREAM_MANAGER_METHOD_NAME_GET_CURRENT_VOLUME_TYPE\">" \
280     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
281     "   <arg name=\"type\" direction=\"out\" type=\"s\"/>"                    \
282     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
283     "  </method>"                                                            \
284     " </interface>"                                                          \
285     " <interface name=\"org.freedesktop.DBus.Introspectable\">"              \
286     "  <method name=\"Introspect\">"                                         \
287     "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"                   \
288     "  </method>"                                                            \
289     " </interface>"                                                          \
290     "</node>"
291 #endif
292
293 #endif
294
295 #define STREAM_MANAGER_CLIENT_NAME "SOUND_MANAGER_STREAM_INFO"
296
297 typedef enum pa_process_stream_result {
298     PA_PROCESS_STREAM_OK,
299     PA_PROCESS_STREAM_STOP,
300     PA_PROCESS_STREAM_SKIP,
301 } pa_process_stream_result_t;
302
303 typedef enum _process_command_type {
304     PROCESS_COMMAND_PREPARE,
305     PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA,
306     PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED,
307     PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED,
308     PROCESS_COMMAND_UPDATE_VOLUME,
309     PROCESS_COMMAND_ADD_PARENT_ID,
310     PROCESS_COMMAND_REMOVE_PARENT_ID,
311 } process_command_type_t;
312
313 typedef enum _notify_command_type {
314     NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT,
315     NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA,
316     NOTIFY_COMMAND_CHANGE_ROUTE_START,
317     NOTIFY_COMMAND_CHANGE_ROUTE_END,
318     NOTIFY_COMMAND_UPDATE_ROUTE_OPTION,
319     NOTIFY_COMMAND_INFORM_STREAM_CONNECTED,
320     NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED,
321 } notify_command_type_t;
322
323 const char* process_command_type_str[] = {
324     "PREPARE",
325     "CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA",
326     "CHANGE_ROUTE_BY_STREAM_STARTED",
327     "CHANGE_ROUTE_BY_STREAM_ENDED",
328     "UPDATE_VOLUME",
329     "ADD_PARENT_ID",
330     "REMOVE_PARENT_ID",
331 };
332
333 const char* notify_command_type_str[] = {
334     "SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT",
335     "CHANGE_ROUTE_START_WITH_NEW_DATA",
336     "CHANGE_ROUTE_START",
337     "CHANGE_ROUTE_END",
338     "UPDATE_ROUTE_OPTION",
339     "INFORM_STREAM_CONNECTED",
340     "INFORM_STREAM_DISCONNECTED",
341 };
342
343 #define STREAM_MAP_FILE "/etc/pulse/stream-map.json"
344 #define STREAM_MAP_STREAMS "streams"
345 #define STREAM_MAP_STREAM_ROLE "role"
346 #define STREAM_MAP_STREAM_PRIORITY "priority"
347 #define STREAM_MAP_STREAM_ROUTE_TYPE "route-type"
348 #define STREAM_MAP_STREAM_DIRECTIONS "directions"
349 #define STREAM_MAP_STREAM_VOLUME_TYPES "volume-types"
350 #define STREAM_MAP_STREAM_VOLUME_TYPE_IN "in"
351 #define STREAM_MAP_STREAM_VOLUME_TYPE_OUT "out"
352 #define STREAM_MAP_STREAM_VOLUME_IS_FOR_HAL "is-hal-volume"
353 #define STREAM_MAP_STREAM_CAPTURE_VOLUME_TYPE "capture-volume-type"
354 #define STREAM_MAP_STREAM_PLAYBACK_VOLUME_TYPE "playback-volume-type"
355 #define STREAM_MAP_STREAM_AVAIL_IN_DEVICES "avail-in-devices"
356 #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices"
357 #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks"
358
359 typedef struct _stream_parent {
360     pa_idxset *idx_sink_inputs;
361     pa_idxset *idx_source_outputs;
362     pa_idxset *idx_route_in_devices;
363     pa_idxset *idx_route_out_devices;
364 } stream_parent;
365
366 #define AVAIL_DEVICES_MAX 16
367 #define AVAIL_FRAMEWORKS_MAX 16
368 #define AVAIL_STREAMS_MAX 32
369 typedef struct _stream_info_per_type {
370     int32_t priority;
371     int32_t route_type;
372     int32_t num_of_in_devices;
373     int32_t num_of_out_devices;
374     int32_t num_of_frameworks;
375     char *avail_in_devices[AVAIL_DEVICES_MAX];
376     char *avail_out_devices[AVAIL_DEVICES_MAX];
377     char *avail_frameworks[AVAIL_FRAMEWORKS_MAX];
378 } stream_info_per_type;
379 typedef struct _stream_list {
380     int32_t num_of_streams;
381     char* types[AVAIL_STREAMS_MAX];
382     int32_t priorities[AVAIL_STREAMS_MAX];
383 } stream_list;
384 typedef struct _stream_route_option {
385     const char *name;
386     int32_t value;
387 } stream_route_option;
388
389 static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, void *user_data);
390 static pa_process_stream_result_t process_stream(stream_type_t type, void *stream, process_command_type_t command, pa_stream_manager *m);
391
392 static int get_available_streams_from_map(pa_stream_manager *m, stream_list *list) {
393     void *state = NULL;
394     stream_info *s = NULL;
395     char *role = NULL;
396     int i = 0;
397
398     pa_log_info("get_available_streams_from_map");
399     if (m->stream_map) {
400         while ((s = pa_hashmap_iterate(m->stream_map, &state, (const void**)&role))) {
401             if (i < AVAIL_STREAMS_MAX) {
402                 list->priorities[i] = s->priority;
403                 list->types[i++] = role;
404                 pa_log_debug("  [%d] stream_type[%s], priority[%d]", i-1, role, s->priority);
405             } else {
406                 pa_log_error("  out of range, [%d]", i);
407                 break;
408             }
409         }
410         list->num_of_streams = i;
411         pa_log_debug("  num_of_streams[%d]",i);
412     } else {
413         pa_log_error("stream_map is not initialized..");
414         return -1;
415     }
416     return 0;
417 }
418
419 static int get_stream_info_from_map(pa_stream_manager *m, const char *stream_role, stream_info_per_type *info) {
420     uint32_t idx = 0;
421     char *name;
422     stream_info *s = NULL;
423     int i = 0;
424     int j = 0;
425     int k = 0;
426     pa_log_info("get_stream_info_from_map : role[%s]", stream_role);
427     if (m->stream_map) {
428         s = pa_hashmap_get(m->stream_map, stream_role);
429         if (s) {
430             info->priority = s->priority;
431             info->route_type = s->route_type;
432             PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx) {
433                 pa_log_debug("  avail-in-device[%d] name  : %s", i, name);
434                 if (i < AVAIL_DEVICES_MAX)
435                     info->avail_in_devices[i++] = name;
436                 else
437                     pa_log_error("  avail-in-devices, out of range, [%d]", i);
438             }
439             info->num_of_in_devices = i;
440             PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx) {
441                 pa_log_debug("  avail-out-device[%d] name  : %s", j, name);
442                 if (j < AVAIL_DEVICES_MAX)
443                     info->avail_out_devices[j++] = name;
444                 else
445                     pa_log_error("  avail-out-devices, out of range, [%d]", j);
446             }
447             info->num_of_out_devices = j;
448             PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx) {
449                 pa_log_debug("  avail-frameworks[%d] name  : %s", k, name);
450                 if (k < AVAIL_FRAMEWORKS_MAX)
451                     info->avail_frameworks[k++] = name;
452                 else
453                     pa_log_error("  avail-frameworks, out of range, [%d]", k);
454             }
455             info->num_of_frameworks = k;
456         }
457     } else {
458         pa_log_error("stream_map is not initialized..");
459         return -1;
460     }
461     return 0;
462 }
463
464 #ifdef HAVE_DBUS
465 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
466     const char *xml = STREAM_MGR_INTROSPECT_XML;
467     DBusMessage *r = NULL;
468
469     pa_assert(conn);
470     pa_assert(msg);
471     pa_assert(userdata);
472
473     pa_assert_se(r = dbus_message_new_method_return(msg));
474     pa_assert_se(dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID));
475
476     if (r) {
477         pa_assert_se(dbus_connection_send((conn), r, NULL));
478         dbus_message_unref(r);
479     }
480
481     return DBUS_HANDLER_RESULT_HANDLED;
482 }
483
484 static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
485     stream_list list;
486     DBusMessage *reply = NULL;
487     DBusMessageIter msg_iter;
488     pa_stream_manager *m = (pa_stream_manager*)userdata;
489     pa_assert(conn);
490     pa_assert(msg);
491     pa_assert(m);
492
493     pa_assert_se(dbus_message_get_args(msg, NULL,
494                                        DBUS_TYPE_INVALID));
495     pa_log_info("handle_get_stream_list() dbus method is called");
496
497     memset(&list, 0, sizeof(stream_list));
498     pa_assert_se((reply = dbus_message_new_method_return(msg)));
499     dbus_message_iter_init_append(reply, &msg_iter);
500     if(!get_available_streams_from_map(m, &list)) {
501         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &list.types, list.num_of_streams);
502         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, &list.priorities, list.num_of_streams);
503     } else {
504         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
505         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_INT32, NULL, 0);
506     }
507     pa_assert_se(dbus_connection_send(conn, reply, NULL));
508     dbus_message_unref(reply);
509 }
510
511 static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void *userdata) {
512     char *type;
513     stream_info_per_type info;
514     DBusMessage *reply = NULL;
515     DBusMessageIter msg_iter;
516     pa_stream_manager *m = (pa_stream_manager*)userdata;
517
518     pa_assert(conn);
519     pa_assert(msg);
520     pa_assert(m);
521
522     pa_assert_se(dbus_message_get_args(msg, NULL,
523                                        DBUS_TYPE_STRING, &type,
524                                        DBUS_TYPE_INVALID));
525     pa_log_info("handle_get_stream_info(), type[%s]", type);
526     memset(&info, 0, sizeof(stream_info_per_type));
527     pa_assert_se((reply = dbus_message_new_method_return(msg)));
528     dbus_message_iter_init_append(reply, &msg_iter);
529     if(!get_stream_info_from_map(m, type, &info)) {
530         pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
531         pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
532         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
533         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
534         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
535     } else {
536         pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, 0);
537         pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, 0);
538         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
539         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
540         pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
541     }
542     pa_assert_se(dbus_connection_send(conn, reply, NULL));
543     dbus_message_unref(reply);
544 }
545
546 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
547     uint32_t id = 0;
548     int i = 0;
549     uint32_t *in_device_list = NULL;
550     uint32_t *out_device_list = NULL;
551     int list_len_in = 0;
552     int list_len_out = 0;
553     uint32_t idx = 0;
554     uint32_t *device_id = NULL;
555     stream_parent *sp = NULL;
556     DBusMessage *reply = NULL;
557     pa_stream_manager *m = (pa_stream_manager*)userdata;
558
559     pa_assert(conn);
560     pa_assert(msg);
561     pa_assert(m);
562
563     pa_assert_se(dbus_message_get_args(msg, NULL,
564                                        DBUS_TYPE_UINT32, &id,
565                                        DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &in_device_list, &list_len_in,
566                                        DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &out_device_list, &list_len_out,
567                                        DBUS_TYPE_INVALID));
568     pa_log_info("handle_set_stream_route_devices(), id[%u], in_device_list[%p]:length[%d], out_device_list[%p]:length[%d]",
569             id, in_device_list, list_len_in, out_device_list, list_len_out);
570
571     pa_assert_se((reply = dbus_message_new_method_return(msg)));
572
573     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
574     if (sp) {
575         if (!in_device_list && !out_device_list) {
576             pa_log_error("invalid arguments");
577             goto FAILURE;
578         }
579
580         if (sp->idx_route_in_devices) {
581             PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, idx) {
582                 pa_idxset_remove_by_data(sp->idx_route_in_devices, device_id, NULL);
583                 pa_xfree(device_id);
584             }
585             if (in_device_list && list_len_in) {
586                 for (i = 0; i < list_len_in; i++) {
587                     pa_idxset_put(sp->idx_route_in_devices, pa_xmemdup(&in_device_list[i], sizeof(uint32_t)), NULL);
588                     pa_log_debug(" -- [in] device id:%u", in_device_list[i]);
589                 }
590             }
591             if (m->cur_highest_priority.source_output) {
592             /* if any stream that belongs to this id has been activated, do notify right away */
593                 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
594                     pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the route change",
595                             (m->cur_highest_priority.source_output)->index, id);
596                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m->cur_highest_priority.source_output);
597                 }
598             }
599         } else {
600             pa_log_error("failed to update, idx_route_in_devices[%p]", sp->idx_route_in_devices);
601             goto FAILURE;
602         }
603
604         if (sp->idx_route_out_devices) {
605             PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, idx) {
606                 pa_idxset_remove_by_data(sp->idx_route_out_devices, device_id, NULL);
607                 pa_xfree(device_id);
608             }
609             if (out_device_list && list_len_out) {
610                 for (i = 0; i < list_len_out; i++) {
611                     pa_idxset_put(sp->idx_route_out_devices, pa_xmemdup(&out_device_list[i], sizeof(uint32_t)), NULL);
612                     pa_log_debug(" -- [out] device id:%u", out_device_list[i]);
613                 }
614             }
615             if (m->cur_highest_priority.sink_input) {
616             /* if any stream that belongs to this id has been activated, do notify right away */
617                 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
618                     pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the route change",
619                             (m->cur_highest_priority.sink_input)->index, id);
620                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m->cur_highest_priority.sink_input);
621                 }
622             }
623         } else {
624             pa_log_error("failed to update, idx_route_out_devices[%p]", sp->idx_route_out_devices);
625             goto FAILURE;
626         }
627         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
628     } else {
629         pa_log_error("could not find matching client for this parent_id[%u]", id);
630         goto FAILURE;
631     }
632
633     pa_assert_se(dbus_connection_send(conn, reply, NULL));
634     dbus_message_unref(reply);
635     return;
636 FAILURE:
637     pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
638     pa_assert_se(dbus_connection_send(conn, reply, NULL));
639     dbus_message_unref(reply);
640     return;
641 }
642
643 static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
644     uint32_t id = 0;
645     const char *name = NULL;
646     int32_t value = 0;
647     pa_bool_t updated = FALSE;
648     stream_parent *sp = NULL;
649     stream_route_option route_option;
650     DBusMessage *reply = NULL;
651     pa_stream_manager *m = (pa_stream_manager*)userdata;
652
653     pa_assert(conn);
654     pa_assert(msg);
655     pa_assert(m);
656
657     pa_assert_se(dbus_message_get_args(msg, NULL,
658                                        DBUS_TYPE_UINT32, &id,
659                                        DBUS_TYPE_STRING, &name,
660                                        DBUS_TYPE_INT32, &value,
661                                        DBUS_TYPE_INVALID));
662     pa_log_info("handle_set_stream_route_option(), name[%s], value[%d]", name, value);
663
664     pa_assert_se((reply = dbus_message_new_method_return(msg)));
665
666     sp = pa_hashmap_get(m->stream_parents, (const void*)id);
667     if (sp) {
668         if (name) {
669             route_option.name = name;
670             route_option.value = value;
671
672             /* if any stream that belongs to this id has been activated, do notify right away */
673             if (m->cur_highest_priority.sink_input) {
674                 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
675                     pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the options",
676                         (m->cur_highest_priority.sink_input)->index, id);
677                     do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SINK_INPUT, &route_option);
678                     updated = TRUE;
679                 }
680             }
681             if (m->cur_highest_priority.source_output) {
682                 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
683                     pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the options",
684                         (m->cur_highest_priority.source_output)->index, id);
685                     do_notify(m, NOTIFY_COMMAND_UPDATE_ROUTE_OPTION, STREAM_SOURCE_OUTPUT, &route_option);
686                     updated = TRUE;
687                 }
688             }
689             if (!updated) {
690                 pa_log_error("invalid state");
691                 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));
692             } else
693                 pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
694         } else {
695             pa_log_error("invalid arguments");
696             pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
697         }
698
699     } else {
700         pa_log_error("could not find matching client for this parent_id[%u]", id);
701         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
702     }
703
704     pa_assert_se(dbus_connection_send(conn, reply, NULL));
705     dbus_message_unref(reply);
706     return;
707 }
708
709 static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level) {
710     DBusMessage *signal_msg;
711     DBusMessageIter msg_iter;
712
713     pa_assert(conn);
714     pa_assert(volume_type);
715
716     pa_log_debug("Send volume changed signal : direction %s, type %s, level %d", direction, volume_type, volume_level);
717
718     pa_assert_se(signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, "VolumeChanged"));
719     dbus_message_iter_init_append(signal_msg, &msg_iter);
720
721     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &direction);
722     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &volume_type);
723     dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &volume_level);
724
725     pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
726     dbus_message_unref(signal_msg);
727     return;
728 }
729
730 static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
731     const char *direction = NULL;
732     const char *type = NULL;
733     uint32_t level = 0;
734     stream_type_t stream_type = STREAM_SINK_INPUT;
735     DBusMessage *reply = NULL;
736     pa_stream_manager *m = (pa_stream_manager*)userdata;
737     int ret = 0;
738
739     pa_assert(conn);
740     pa_assert(msg);
741     pa_assert(m);
742
743     pa_assert_se(dbus_message_get_args(msg, NULL,
744                                        DBUS_TYPE_STRING, &direction,
745                                        DBUS_TYPE_STRING, &type,
746                                        DBUS_TYPE_UINT32, &level,
747                                        DBUS_TYPE_INVALID));
748     pa_log_info("handle_set_volume_level(), direction[%s], type[%s], level[%u]", direction, type, level);
749
750     pa_assert_se((reply = dbus_message_new_method_return(msg)));
751
752     if (pa_streq(direction, "in"))
753         stream_type = STREAM_SOURCE_OUTPUT;
754     else if (pa_streq(direction, "out"))
755         stream_type = STREAM_SINK_INPUT;
756     else {
757         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
758         goto FAILURE;
759     }
760
761     if ((ret = set_volume_level_by_type(m, stream_type, type, level)))
762         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
763     else
764         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
765
766 FAILURE:
767     pa_assert_se(dbus_connection_send(conn, reply, NULL));
768     dbus_message_unref(reply);
769
770     if (!ret)
771         send_volume_changed_signal(conn, direction, type, level);
772     return;
773 }
774
775 static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
776     const char *direction = NULL;
777     const char *type = NULL;
778     uint32_t level = 0;
779     stream_type_t stream_type = STREAM_SINK_INPUT;
780     DBusMessage *reply = NULL;
781     pa_stream_manager *m = (pa_stream_manager*)userdata;
782     pa_assert(conn);
783     pa_assert(msg);
784     pa_assert(m);
785
786     pa_assert_se(dbus_message_get_args(msg, NULL,
787                                        DBUS_TYPE_STRING, &direction,
788                                        DBUS_TYPE_STRING, &type,
789                                        DBUS_TYPE_INVALID));
790     pa_log_info("handle_get_volume_level(), direction(%s), type(%s)", direction, type);
791
792     pa_assert_se((reply = dbus_message_new_method_return(msg)));
793
794     if (pa_streq(direction, "in"))
795         stream_type = STREAM_SOURCE_OUTPUT;
796     else if (pa_streq(direction, "out"))
797         stream_type = STREAM_SINK_INPUT;
798     else {
799         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
800         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
801         goto FAILURE;
802     }
803
804     if (get_volume_level_by_type(m, GET_VOLUME_CURRENT_LEVEL, stream_type, type, &level)) {
805         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
806         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
807     } else {
808         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
809         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
810     }
811
812 FAILURE:
813     pa_assert_se(dbus_connection_send(conn, reply, NULL));
814     dbus_message_unref(reply);
815     return;
816 }
817
818 static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
819     const char *direction = NULL;
820     const char *type = NULL;
821     uint32_t level = 0;
822     stream_type_t stream_type = STREAM_SINK_INPUT;
823     DBusMessage *reply = NULL;
824     pa_stream_manager *m = (pa_stream_manager*)userdata;
825
826     pa_assert(conn);
827     pa_assert(msg);
828     pa_assert(m);
829
830     pa_assert_se(dbus_message_get_args(msg, NULL,
831                                        DBUS_TYPE_STRING, &direction,
832                                        DBUS_TYPE_STRING, &type,
833                                        DBUS_TYPE_INVALID));
834     pa_log_info("handle_get_volume_max_level(), direction[%s], type[%s]", direction, type);
835
836     pa_assert_se((reply = dbus_message_new_method_return(msg)));
837
838     if (pa_streq(direction, "in"))
839         stream_type = STREAM_SOURCE_OUTPUT;
840     else if (pa_streq(direction, "out"))
841         stream_type = STREAM_SINK_INPUT;
842     else {
843         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
844         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
845         goto FAILURE;
846     }
847
848     if (get_volume_level_by_type(m, GET_VOLUME_MAX_LEVEL, stream_type, type, &level)) {
849         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
850         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
851     } else {
852         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID));
853         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
854     }
855 FAILURE:
856     pa_assert_se(dbus_connection_send(conn, reply, NULL));
857     dbus_message_unref(reply);
858     return;
859 }
860
861 static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
862     const char *direction = NULL;
863     const char *type = NULL;
864     uint32_t do_mute = 0;
865     stream_type_t stream_type = STREAM_SINK_INPUT;
866     DBusMessage *reply = NULL;
867     pa_stream_manager *m = (pa_stream_manager*)userdata;
868
869     pa_assert(conn);
870     pa_assert(msg);
871     pa_assert(m);
872
873     pa_assert_se(dbus_message_get_args(msg, NULL,
874                                        DBUS_TYPE_STRING, &direction,
875                                        DBUS_TYPE_STRING, &type,
876                                        DBUS_TYPE_UINT32, &do_mute,
877                                        DBUS_TYPE_INVALID));
878     pa_log_info("handle_set_volume_mute(), direction[%s], type[%s], do_mute[%u]", direction, type, do_mute);
879
880     pa_assert_se((reply = dbus_message_new_method_return(msg)));
881
882     if (pa_streq(direction, "in"))
883         stream_type = STREAM_SOURCE_OUTPUT;
884     else if (pa_streq(direction, "out"))
885         stream_type = STREAM_SINK_INPUT;
886     else {
887         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
888         goto FAILURE;
889     }
890
891     if (set_volume_mute_by_type(m, stream_type, type, (pa_bool_t)do_mute))
892         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
893     else
894         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
895
896 FAILURE:
897     pa_assert_se(dbus_connection_send(conn, reply, NULL));
898     dbus_message_unref(reply);
899     return;
900 }
901
902 static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
903     const char *direction = NULL;
904     const char *type = NULL;
905     uint32_t is_muted = 0;
906     stream_type_t stream_type = STREAM_SINK_INPUT;
907
908     DBusMessage *reply = NULL;
909     pa_stream_manager *m = (pa_stream_manager*)userdata;
910     pa_assert(conn);
911     pa_assert(msg);
912     pa_assert(m);
913
914     pa_assert_se(dbus_message_get_args(msg, NULL,
915                                        DBUS_TYPE_STRING, &direction,
916                                        DBUS_TYPE_STRING, &type,
917                                        DBUS_TYPE_INVALID));
918     pa_log_info("handle_get_volume_mute(), direction[%s], type[%s]", direction, type);
919
920     pa_assert_se((reply = dbus_message_new_method_return(msg)));
921
922     if (pa_streq(direction, "in"))
923         stream_type = STREAM_SOURCE_OUTPUT;
924     else if (pa_streq(direction, "out"))
925         stream_type = STREAM_SINK_INPUT;
926     else {
927         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
928         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
929         goto FAILURE;
930     }
931
932     if (get_volume_mute_by_type(m, stream_type, type, (pa_bool_t*)&is_muted)) {
933         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, 0, DBUS_TYPE_INVALID));
934         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
935     } else {
936         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &is_muted, DBUS_TYPE_INVALID));
937         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
938     }
939
940 FAILURE:
941     pa_assert_se(dbus_connection_send(conn, reply, NULL));
942     dbus_message_unref(reply);
943     return;
944 }
945
946 static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
947     const char *direction = NULL;
948     const char *type = NULL;
949     void *s = NULL;
950     stream_type_t stream_type = STREAM_SINK_INPUT;
951
952     DBusMessage *reply = NULL;
953     pa_stream_manager *m = (pa_stream_manager*)userdata;
954     pa_assert(conn);
955     pa_assert(msg);
956     pa_assert(m);
957
958     pa_assert_se(dbus_message_get_args(msg, NULL,
959                                        DBUS_TYPE_STRING, &direction,
960                                        DBUS_TYPE_INVALID));
961     pa_log_info("handle_get_current_volume_type(), direction[%s]", direction);
962
963     pa_assert_se((reply = dbus_message_new_method_return(msg)));
964
965     if (pa_streq(direction, "in"))
966         stream_type = STREAM_SOURCE_OUTPUT;
967     else if (pa_streq(direction, "out"))
968         stream_type = STREAM_SINK_INPUT;
969     else {
970         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
971         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
972         goto FAILURE;
973     }
974
975     s = (stream_type == STREAM_SINK_INPUT)?(void*)(m->cur_highest_priority.sink_input):(void*)(m->cur_highest_priority.source_output);
976     if (s) {
977         type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
978         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID));
979         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_OK], DBUS_TYPE_INVALID));
980     } else {
981         pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &dbus_str_none, DBUS_TYPE_INVALID));
982         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));
983     }
984
985 FAILURE:
986     pa_assert_se(dbus_connection_send(conn, reply, NULL));
987     dbus_message_unref(reply);
988     return;
989 }
990
991 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
992         int idx = 0;
993     pa_stream_manager *m = (pa_stream_manager*)userdata;
994
995     pa_assert(conn);
996     pa_assert(msg);
997     pa_assert(m);
998
999     for (idx = 0; idx < METHOD_HANDLER_MAX; idx++) {
1000         if (dbus_message_is_method_call(msg, STREAM_MANAGER_INTERFACE, method_handlers[idx].method_name )) {
1001             pa_log_debug("Message signature [%s] (Expected [%s])", dbus_message_get_signature(msg), signature_args_for_in[idx]);
1002             if (pa_streq(dbus_message_get_signature(msg), signature_args_for_in[idx])) {
1003                 method_handlers[idx].receive_cb(conn, msg, userdata);
1004                 return DBUS_HANDLER_RESULT_HANDLED;
1005             } else {
1006                 pa_log_warn("Wrong Argument Signature");
1007                 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_SIGNATURE,  "Wrong Signature, Expected %s", signature_args_for_in[idx]);
1008                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1009             }
1010         }
1011     }
1012
1013     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1014 }
1015
1016 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata) {
1017     pa_stream_manager *u = (pa_stream_manager*)userdata;
1018     const char *path, *interface, *member;
1019
1020     pa_assert(c);
1021     pa_assert(m);
1022     pa_assert(u);
1023
1024     path = dbus_message_get_path(m);
1025     interface = dbus_message_get_interface(m);
1026     member = dbus_message_get_member(m);
1027
1028     pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member);
1029
1030     if (!pa_streq(path, STREAM_MANAGER_OBJECT_PATH))
1031         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1032
1033     if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1034         return handle_introspect(c, m, u);
1035     } else {
1036         return handle_methods(c, m, u);
1037     }
1038
1039     return DBUS_HANDLER_RESULT_HANDLED;
1040 }
1041 #endif
1042
1043 static int convert_route_type(stream_route_type_t *route_type, const char *route_type_string) {
1044     int ret = 0;
1045
1046     pa_assert(route_type);
1047     pa_assert(route_type_string);
1048
1049     if (pa_streq("auto", route_type_string))
1050         *route_type = STREAM_ROUTE_TYPE_AUTO;
1051     else if (pa_streq("auto-all", route_type_string))
1052         *route_type = STREAM_ROUTE_TYPE_AUTO_ALL;
1053     else if (pa_streq("manual", route_type_string))
1054         *route_type = STREAM_ROUTE_TYPE_MANUAL;
1055     else {
1056         ret = -1;
1057         pa_log_error("Not supported route_type(%s)", route_type_string);
1058     }
1059
1060     return ret;
1061 }
1062
1063 static void dump_stream_map (pa_stream_manager *m) {
1064     stream_info *s = NULL;
1065     const char *role = NULL;
1066     char *name = NULL;
1067     void *state = NULL;
1068     uint32_t idx = 0;
1069     pa_assert(m);
1070     pa_log_debug("==========[START stream-map dump]==========");
1071     while (m->stream_map && (s = pa_hashmap_iterate(m->stream_map, &state, (const void **)&role))) {
1072         pa_log_debug("[role : %s]", role);
1073         pa_log_debug("  - priority   : %d", s->priority);
1074         pa_log_debug("  - route-type : %d (0:auto,1:auto-all,2:manual,3:manual-all)", s->route_type);
1075         pa_log_debug("  - volume-types : in[%s], out[%s]", s->volume_type[STREAM_DIRECTION_IN], s->volume_type[STREAM_DIRECTION_OUT]);
1076         pa_log_debug("  - avail-in-devices");
1077         PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx)
1078             pa_log_debug("      name[%d]  : %s", idx, name);
1079         pa_log_debug("  - avail-out-devices");
1080         PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx)
1081             pa_log_debug("      name[%d]  : %s", idx, name);
1082         pa_log_debug("  - avail-frameworks");
1083         PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx)
1084             pa_log_debug("      name[%d]  : %s", idx, name);
1085     }
1086     pa_log_debug("===========[END stream-map dump]===========");
1087     return;
1088 }
1089
1090 static int init_stream_map (pa_stream_manager *m) {
1091     stream_info *s;
1092     json_object *o;
1093     json_object *stream_array_o;
1094     json_object *role_o;
1095     json_object *priority_o;
1096     json_object *route_type_o;
1097     json_object *volume_types_o;
1098     json_object *is_hal_volume_o;
1099     json_object *avail_in_devices_o;
1100     json_object *avail_out_devices_o;
1101     json_object *avail_frameworks_o;
1102     int num_of_stream_types = 0;
1103     const char *role = NULL;
1104     int i = 0, j = 0;
1105     int num_of_avail_in_devices;
1106     int num_of_avail_out_devices;
1107     int num_of_avail_frameworks;
1108     json_object *out_device_o;
1109     json_object *in_device_o;
1110     json_object *framework_o;
1111     json_object *stream_o;
1112     json_object *is_hal_volume_in_o;
1113     json_object *is_hal_volume_out_o;
1114     const char *volume_type_in_str = NULL;
1115     const char *volume_type_out_str = NULL;
1116     json_object *volume_type_in_o;
1117     json_object *volume_type_out_o;
1118     void *state = NULL;
1119
1120     pa_assert(m);
1121
1122     o = json_object_from_file(STREAM_MAP_FILE);
1123     if(is_error(o)) {
1124         pa_log_error("Read stream-map file(%s) failed", STREAM_MAP_FILE);
1125         return -1;
1126     }
1127     m->stream_map = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1128
1129     if((stream_array_o = json_object_object_get(o, STREAM_MAP_STREAMS)) && json_object_is_type(stream_array_o, json_type_array)){
1130         num_of_stream_types = json_object_array_length(stream_array_o);
1131         for (i = 0; i < num_of_stream_types; i++) {
1132
1133             if((stream_o = json_object_array_get_idx(stream_array_o, i)) && json_object_is_type(stream_o, json_type_object)) {
1134                 s = pa_xmalloc0(sizeof(stream_info));
1135                 pa_log_debug("stream found [%d]", i);
1136                 if((role_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_ROLE)) && json_object_is_type(role_o, json_type_string)) {
1137                     role = json_object_get_string(role_o);
1138                     pa_log_debug(" - role : %s", role);
1139                 } else {
1140                     pa_log_error("Get stream role failed");
1141                     goto failed;
1142                 }
1143                 if((priority_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_PRIORITY)) && json_object_is_type(priority_o, json_type_int)) {
1144                     s->priority = json_object_get_int(priority_o);
1145                     pa_log_debug(" - priority : %d", s->priority);
1146                 } else {
1147                     pa_log_error("Get stream priority failed");
1148                     goto failed;
1149                 }
1150                 if((route_type_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_ROUTE_TYPE)) && json_object_is_type(route_type_o, json_type_string)) {
1151                     if (convert_route_type(&(s->route_type), json_object_get_string(route_type_o))) {
1152                         pa_log_error("convert stream route-type failed");
1153                         goto failed;
1154                     }
1155                     pa_log_debug(" - route-type : %d", s->route_type);
1156                 } else {
1157                     pa_log_error("Get stream route-type failed");
1158                     goto failed;
1159                 }
1160                 if((volume_types_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_VOLUME_TYPES)) && json_object_is_type(volume_types_o, json_type_object)) {
1161                     if((volume_type_in_o = json_object_object_get(volume_types_o, STREAM_MAP_STREAM_VOLUME_TYPE_IN)) && json_object_is_type(volume_type_in_o, json_type_string)) {
1162                         volume_type_in_str = json_object_get_string(volume_type_in_o);
1163                         if (!pa_streq(volume_type_in_str, "none"))
1164                             s->volume_type[STREAM_DIRECTION_IN] = volume_type_in_str;
1165                     } else {
1166                         pa_log_error("Get stream volume-type-in failed");
1167                         goto failed;
1168                     }
1169                     if((volume_type_out_o = json_object_object_get(volume_types_o, STREAM_MAP_STREAM_VOLUME_TYPE_OUT)) && json_object_is_type(volume_type_out_o, json_type_string)) {
1170                         volume_type_out_str = json_object_get_string(volume_type_out_o);
1171                         if (!pa_streq(volume_type_out_str, "none"))
1172                             s->volume_type[STREAM_DIRECTION_OUT] = volume_type_out_str;
1173                     } else {
1174                         pa_log_error("Get stream volume-type-out failed");
1175                         goto failed;
1176                     }
1177                     pa_log_debug(" - volume-types : in[%s], out[%s]", s->volume_type[STREAM_DIRECTION_IN], s->volume_type[STREAM_DIRECTION_OUT]);
1178                 } else {
1179                     pa_log_error("Get stream volume-types failed");
1180                     goto failed;
1181                 }
1182                 if((is_hal_volume_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_VOLUME_IS_FOR_HAL)) && json_object_is_type(is_hal_volume_o, json_type_object)) {
1183                     if((is_hal_volume_in_o = json_object_object_get(is_hal_volume_o, STREAM_MAP_STREAM_VOLUME_TYPE_IN)) && json_object_is_type(is_hal_volume_in_o, json_type_int))
1184                         s->is_hal_volume[STREAM_DIRECTION_IN] = (pa_bool_t)json_object_get_int(is_hal_volume_in_o);
1185                     else {
1186                         pa_log_error("Get stream is-hal-volume-in failed");
1187                         goto failed;
1188                     }
1189                     if((is_hal_volume_out_o = json_object_object_get(is_hal_volume_o, STREAM_MAP_STREAM_VOLUME_TYPE_OUT)) && json_object_is_type(is_hal_volume_out_o, json_type_int))
1190                         s->is_hal_volume[STREAM_DIRECTION_OUT] = (pa_bool_t)json_object_get_int(is_hal_volume_out_o);
1191                     else {
1192                         pa_log_error("Get stream is-hal-volume-out failed");
1193                         goto failed;
1194                     }
1195                     pa_log_debug(" - is-hal-volume : in[%d], out[%d]", s->is_hal_volume[STREAM_DIRECTION_IN], s->is_hal_volume[STREAM_DIRECTION_OUT]);
1196                 } else {
1197                     pa_log_error("Get stream volume-types failed");
1198                     goto failed;
1199                 }
1200                 if((avail_in_devices_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_IN_DEVICES)) && json_object_is_type(avail_in_devices_o, json_type_array)) {
1201                     j = 0;
1202                     s->idx_avail_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1203                     num_of_avail_in_devices = json_object_array_length(avail_in_devices_o);
1204                     pa_log_debug(" - avail-in-devices");
1205                     for (j = 0; j < num_of_avail_in_devices; j++) {
1206                         if((in_device_o = json_object_array_get_idx(avail_in_devices_o, j)) && json_object_is_type(in_device_o, json_type_string)) {
1207                             pa_idxset_put(s->idx_avail_in_devices, (void*)json_object_get_string(in_device_o), NULL);
1208                             pa_log_debug("      device[%d] : %s", j, json_object_get_string(in_device_o));
1209                            }
1210                        }
1211                 } else {
1212                     pa_log_error("Get stream avail-in-devices failed");
1213                     goto failed;
1214                 }
1215                 if((avail_out_devices_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_OUT_DEVICES)) && json_object_is_type(avail_out_devices_o, json_type_array)) {
1216                     j = 0;
1217                     s->idx_avail_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1218                     num_of_avail_out_devices = json_object_array_length(avail_out_devices_o);
1219                     pa_log_debug(" - avail-out-devices");
1220                     for (j = 0; j < num_of_avail_out_devices; j++) {
1221                         if((out_device_o = json_object_array_get_idx(avail_out_devices_o, j)) && json_object_is_type(out_device_o, json_type_string)) {
1222                             pa_idxset_put(s->idx_avail_out_devices, (void*)json_object_get_string(out_device_o), NULL);
1223                             pa_log_debug("      device[%d] : %s", j, json_object_get_string(out_device_o));
1224                            }
1225                        }
1226                 } else {
1227                     pa_log_error("Get stream avail-out-devices failed");
1228                     goto failed;
1229                 }
1230                 if((avail_frameworks_o = json_object_object_get(stream_o, STREAM_MAP_STREAM_AVAIL_FRAMEWORKS)) && json_object_is_type(avail_frameworks_o, json_type_array)) {
1231                     j = 0;
1232                     s->idx_avail_frameworks = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
1233                     num_of_avail_frameworks = json_object_array_length(avail_frameworks_o);
1234                     pa_log_debug(" - avail-frameworks");
1235                     for (j = 0; j < num_of_avail_frameworks; j++) {
1236                         if((framework_o = json_object_array_get_idx(avail_frameworks_o, j)) && json_object_is_type(framework_o, json_type_string)) {
1237                             pa_idxset_put(s->idx_avail_frameworks, (void*)json_object_get_string(framework_o), NULL);
1238                             pa_log_debug("      framework[%d] : %s", j, json_object_get_string(framework_o));
1239                            }
1240                        }
1241                 } else {
1242                     pa_log_error("Get stream avail-frameworks failed");
1243                     goto failed;
1244                 }
1245                 pa_hashmap_put(m->stream_map,(void*)role, s);
1246             }
1247         }
1248     } else {
1249         pa_log_error("Get streams object failed");
1250         goto failed;
1251     }
1252
1253     dump_stream_map(m);
1254
1255     return 0;
1256 failed:
1257     pa_log_error("Failed to initialize stream map");
1258     if (m->stream_map) {
1259         PA_HASHMAP_FOREACH(s, m->stream_map, state) {
1260             if (s->idx_avail_in_devices)
1261                 pa_idxset_free(s->idx_avail_in_devices, NULL);
1262             if (s->idx_avail_out_devices)
1263                 pa_idxset_free(s->idx_avail_out_devices, NULL);
1264             if (s->idx_avail_frameworks)
1265                 pa_idxset_free(s->idx_avail_frameworks, NULL);
1266             pa_xfree(s);
1267         }
1268         pa_hashmap_free(m->stream_map);
1269     }
1270     return -1;
1271 }
1272
1273 static void deinit_stream_map (pa_stream_manager *m) {
1274     stream_info *s = NULL;
1275     void *state = NULL;
1276
1277     pa_assert(m);
1278     if (m->stream_map) {
1279         PA_HASHMAP_FOREACH(s, m->stream_map, state) {
1280             if (s->idx_avail_in_devices)
1281                 pa_idxset_free(s->idx_avail_in_devices, NULL);
1282             if (s->idx_avail_out_devices)
1283                 pa_idxset_free(s->idx_avail_out_devices, NULL);
1284             if (s->idx_avail_frameworks)
1285                 pa_idxset_free(s->idx_avail_frameworks, NULL);
1286             pa_xfree(s);
1287         }
1288         pa_hashmap_free(m->stream_map);
1289     }
1290
1291     return;
1292 }
1293
1294 static pa_bool_t check_role_to_skip(pa_stream_manager *m, const char *role) {
1295     pa_bool_t ret = TRUE;
1296     stream_info *s = NULL;
1297
1298     pa_assert(m);
1299     pa_assert(role);
1300
1301     if (m->stream_map) {
1302         s = pa_hashmap_get(m->stream_map, role);
1303         if (s)
1304             ret = FALSE;
1305     }
1306
1307     pa_log_info("role is [%s], skip(%d)", role, ret);
1308
1309     return ret;
1310 }
1311
1312 static pa_bool_t update_priority_of_stream(pa_stream_manager *m, process_command_type_t command, stream_type_t type, void *stream, const char *role) {
1313     stream_info *s = NULL;
1314
1315     pa_assert(m);
1316     pa_assert(role);
1317
1318     if (m->stream_map)
1319         s = pa_hashmap_get(m->stream_map, role);
1320     else
1321         return FALSE;
1322
1323     if (s) {
1324         if (command == PROCESS_COMMAND_PREPARE)
1325             pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, "%d", s->priority);
1326         else
1327             pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, "%d", s->priority);
1328     }
1329
1330     return TRUE;
1331 }
1332
1333 static pa_bool_t update_routing_type_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role) {
1334     stream_route_type_t route_type = STREAM_ROUTE_TYPE_AUTO;
1335     stream_info *s = NULL;
1336
1337     pa_assert(m);
1338     pa_assert(role);
1339
1340     if (m->stream_map) {
1341         s = pa_hashmap_get(m->stream_map, role);
1342         if (s)
1343             route_type = s->route_type;
1344     } else
1345         return FALSE;
1346
1347     pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE, "%d", route_type);
1348
1349     return TRUE;
1350 }
1351
1352 static pa_bool_t update_volume_type_of_stream(pa_stream_manager *m, stream_type_t type, void *stream, const char *role) {
1353     const char *volume_type = NULL;
1354     stream_info *s = NULL;
1355
1356     pa_assert(m);
1357     pa_assert(role);
1358
1359     if (m->stream_map) {
1360         s = pa_hashmap_get(m->stream_map, role);
1361         if (s)
1362             volume_type = s->volume_type[!type];
1363     } else
1364         return FALSE;
1365
1366     if (volume_type)
1367         pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type);
1368     else
1369         pa_log_warn("this stream[%p] does not have any volume type, skip updating volume type. stream_type[%d], role[%s]", stream, type, role);
1370
1371     return TRUE;
1372 }
1373
1374 static pa_bool_t update_stream_parent_info(pa_stream_manager *m, process_command_type_t command, stream_type_t type, void *stream) {
1375     const char *p_idx;
1376     uint32_t parent_idx;
1377     stream_parent *sp = NULL;
1378
1379     pa_assert(m);
1380     pa_assert(stream);
1381
1382     p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1383     if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1384         pa_log_debug("p_idx(%s), idx(%u)", p_idx, parent_idx);
1385         sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1386         if (sp) {
1387             uint32_t idx = (type==STREAM_SINK_INPUT)?((pa_sink_input*)stream)->index:((pa_source_output*)stream)->index;
1388             if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
1389                 /* append this stream to the parent stream info. */
1390                 pa_log_debug(" - append this stream(%p, %u) to the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1391                 pa_idxset_put(type==STREAM_SINK_INPUT?(sp->idx_sink_inputs):(sp->idx_source_outputs), stream, NULL);
1392                 return TRUE;
1393             } else if (command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
1394                 /* remove this stream from the parent stream info. */
1395                 pa_log_debug(" - remove this stream(%p, %u) from the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1396                 pa_idxset_remove_by_data(type==STREAM_SINK_INPUT?(sp->idx_sink_inputs):(sp->idx_source_outputs), stream, NULL);
1397                 return TRUE;
1398             } else {
1399                 pa_log_error("invalid command(%d)", command);
1400                 return FALSE;
1401             }
1402         } else {
1403             pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
1404             return FALSE;
1405         }
1406     } else {
1407         pa_log_warn("p_idx(%s) or idx(%u) is not valid", p_idx, parent_idx);
1408         return FALSE;
1409     }
1410     return TRUE;
1411 }
1412
1413 static pa_bool_t update_the_highest_priority_stream(pa_stream_manager *m, process_command_type_t command, void *mine,
1414                                                     stream_type_t type, const char *role, pa_bool_t *need_to_update) {
1415     uint32_t idx = 0;
1416     int32_t p_max = 0;
1417     int32_t p_mine = 0;
1418     const char *priority = NULL;
1419     void *cur_max_stream = NULL;
1420     const char *cur_max_priority = NULL;
1421     const char *cur_max_role = NULL;
1422
1423     pa_assert(m);
1424     pa_assert(mine);
1425     if (!role) {
1426         pa_log_error("invalid input, role(%s)", role);
1427         return FALSE;
1428     }
1429
1430     *need_to_update = FALSE;
1431
1432     if (type == STREAM_SINK_INPUT) {
1433         cur_max_stream = m->cur_highest_priority.sink_input;
1434     } else if (type == STREAM_SOURCE_OUTPUT) {
1435         cur_max_stream = m->cur_highest_priority.source_output;
1436     }
1437
1438     pa_log_info("update_the_highest_priority_stream(), stream_type(%d), role(%s), command(%d)", type, role, command);
1439     if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1440         if (cur_max_stream == NULL) {
1441             *need_to_update = TRUE;
1442             pa_log_debug("set cur_highest to mine");
1443         } else {
1444             /* TODO : need to check if this stream should be played to external devices */
1445             if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA)
1446                 priority = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY);
1447             else {
1448                 if (cur_max_stream == mine) {
1449                     pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, skip it..");
1450                     return FALSE;
1451                 }
1452                 priority = pa_proplist_gets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY);
1453             }
1454             cur_max_priority = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE_PRIORITY);
1455             cur_max_role = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE);
1456             if (!cur_max_priority || !cur_max_role) {
1457                 pa_log_error("Failed to pa_proplist_gets() for getting current max priority(%s) and it's role(%s)", cur_max_priority, cur_max_role);
1458                 return FALSE;
1459             } else {
1460                 if (pa_atoi(priority, &p_mine)) {
1461                     pa_log_error("Failed to pa_atoi(), priority(%s)", priority);
1462                     return FALSE;
1463                 }
1464                 if (pa_atoi(cur_max_priority, &p_max)) {
1465                     pa_log_error("Failed to pa_atoi(), cur_max_priority(%s)", cur_max_priority);
1466                     return FALSE;
1467                 }
1468                 if (p_mine < p_max) {
1469                     /* no need to trigger */
1470                     return TRUE;
1471                 } else {
1472                     *need_to_update = TRUE;
1473                     pa_log_debug("update cur_highest to mine(%s)", role);
1474                 }
1475             }
1476         }
1477     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED) {
1478         void *cur_max_stream_tmp = NULL;
1479         void *i = NULL;
1480         const char *_role = NULL;
1481         int32_t p;
1482         pa_idxset *streams = NULL;
1483         if (cur_max_stream == mine) {
1484             if (type == STREAM_SINK_INPUT) {
1485                 streams = ((pa_sink_input*)mine)->sink->inputs;
1486             } else if (type == STREAM_SOURCE_OUTPUT) {
1487                 streams = ((pa_source_output*)mine)->source->outputs;
1488             }
1489             /* find the next highest priority input */
1490             //PA_IDXSET_FOREACH(i, m->core->sinks, idx) { /* need to check a sink which this stream belongs to */
1491             PA_IDXSET_FOREACH(i, streams, idx) {
1492                 if (!(_role = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE))){
1493                     pa_log_error("Failed to pa_proplist_gets() for role");
1494                     continue;
1495                 }
1496                 if (!(priority = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE_PRIORITY))){
1497                     pa_log_error("Failed to pa_proplist_gets() for priority");
1498                     continue;
1499                 }
1500                 pa_log_debug("role(%s)/priority(%s)/stream(%p)", _role, priority, i);
1501                 if (cur_max_priority == NULL) {
1502                     cur_max_priority = priority;
1503                     cur_max_stream_tmp = i;
1504                 }
1505                 if (pa_atoi(cur_max_priority, &p_max)) {
1506                     pa_log_error("Failed to pa_atoi(), cur_max_priority(%s)", cur_max_priority);
1507                     continue;
1508                 }
1509                 if (pa_atoi(priority, &p)) {
1510                     pa_log_error("Failed to pa_atoi(), priority(%s)", priority);
1511                     continue;
1512                 }
1513                 if (p_max <= p) {
1514                     cur_max_priority = priority;
1515                     cur_max_stream_tmp = i;
1516                     p_max = p;
1517                 }
1518             }
1519             pa_log_debug("updated max priority(%s)/stream(%p)", cur_max_priority, cur_max_stream_tmp);
1520             if ((p_max > -1) && cur_max_stream_tmp) {
1521                 if (type == STREAM_SINK_INPUT) {
1522                     m->cur_highest_priority.sink_input = cur_max_stream_tmp;
1523                 } else if (type == STREAM_SOURCE_OUTPUT) {
1524                     m->cur_highest_priority.source_output = cur_max_stream_tmp;
1525                 }
1526             } else {
1527                 if (type == STREAM_SINK_INPUT) {
1528                     m->cur_highest_priority.sink_input = NULL;
1529                 } else if (type == STREAM_SOURCE_OUTPUT) {
1530                     m->cur_highest_priority.source_output = NULL;
1531                 }
1532             }
1533             *need_to_update = TRUE;
1534             pa_log_info("need to update: type(%d), cur_highest_priority(sink_input=%p/source_output=%p)",
1535                         type, (void*)m->cur_highest_priority.sink_input, (void*)m->cur_highest_priority.sink_input);
1536         } else {
1537             /* no need to trigger */
1538             return TRUE;
1539         }
1540     }
1541     return TRUE;
1542 }
1543
1544 static void fill_device_info_to_hook_data(void *hook_data, notify_command_type_t command, stream_type_t type, void *stream, pa_stream_manager *m) {
1545     char *device_name = NULL;
1546     const char *p_idx = NULL;
1547     uint32_t parent_idx = 0;
1548     stream_parent *sp = NULL;
1549     uint32_t idx = 0;
1550     pa_stream_manager_hook_data_for_select *select_data = NULL;
1551     pa_stream_manager_hook_data_for_route *route_data = NULL;
1552     stream_info *si;
1553     pa_idxset *avail_devices;
1554     int list_len;
1555
1556     pa_assert(hook_data);
1557     pa_assert(m);
1558     pa_log_warn("fill_device_info_to_hook_data() for %s", notify_command_type_str[command]);
1559
1560     switch (command) {
1561     case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
1562         select_data = (pa_stream_manager_hook_data_for_select*)hook_data;
1563         si = pa_hashmap_get(m->stream_map, select_data->stream_role);
1564         avail_devices = (type==STREAM_SINK_INPUT)?si->idx_avail_out_devices:si->idx_avail_in_devices;
1565         list_len = pa_idxset_size(avail_devices);
1566         select_data->route_type = si->route_type;
1567         device_name = pa_idxset_get_by_data(avail_devices, "none", NULL);
1568         if (list_len == 1 && pa_streq(device_name, "none")) {
1569             /* no available devices for this role */
1570         } else {
1571             select_data->idx_avail_devices = avail_devices;
1572             if (si->route_type == STREAM_ROUTE_TYPE_MANUAL) {
1573                 p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1574                 if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1575                     /* find parent idx, it's device info. and it's stream idxs */
1576                     sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1577                     if (sp)
1578                         select_data->idx_manual_devices = (type==STREAM_SINK_INPUT)?(sp->idx_route_out_devices):(sp->idx_route_in_devices);
1579                     else
1580                         pa_log_warn("Failed to get the stream parent of idx(%u)", idx);
1581                 }
1582             }
1583         }
1584         break;
1585     }
1586     case NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA:
1587     case NOTIFY_COMMAND_CHANGE_ROUTE_START:
1588     case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
1589         route_data = (pa_stream_manager_hook_data_for_route*)hook_data;
1590         si = pa_hashmap_get(m->stream_map, route_data->stream_role);
1591         avail_devices = (type==STREAM_SINK_INPUT)?si->idx_avail_out_devices:si->idx_avail_in_devices;
1592         list_len = pa_idxset_size(avail_devices);
1593         route_data->route_type = si->route_type;
1594
1595         if (command == NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA)
1596             p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1597         else if (command == NOTIFY_COMMAND_CHANGE_ROUTE_START || command == NOTIFY_COMMAND_CHANGE_ROUTE_END)
1598             p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1599         if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1600             sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
1601             if (!sp)
1602                 pa_log_warn("Failed to get the stream parent of idx(%u)", parent_idx);
1603         } else
1604            pa_log_warn("Could not get the parent id of this stream, but keep going...");
1605
1606         device_name = pa_idxset_get_by_data(avail_devices, "none", NULL);
1607         if (list_len == 1 && pa_streq(device_name, "none")) {
1608             /* no available devices for this role */
1609         } else {
1610             route_data->idx_avail_devices = avail_devices;
1611             if (si->route_type == STREAM_ROUTE_TYPE_MANUAL) {
1612                 if (sp) {
1613                     route_data->idx_manual_devices = (type==STREAM_SINK_INPUT)?(sp->idx_route_out_devices):(sp->idx_route_in_devices);
1614                     route_data->idx_streams = (type==STREAM_SINK_INPUT)?(sp->idx_sink_inputs):(sp->idx_source_outputs);
1615                 } else
1616                     pa_log_warn("Failed to get the stream parent of idx(%u)", parent_idx);
1617             }
1618         }
1619         break;
1620     }
1621     default:
1622         break;
1623     }
1624     return;
1625 }
1626
1627 static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, void *user_data) {
1628     pa_stream_manager_hook_data_for_select hook_call_select_data;
1629     pa_stream_manager_hook_data_for_route hook_call_route_data;
1630     pa_stream_manager_hook_data_for_option hook_call_option_data;
1631     hal_stream_connection_info stream_conn_info;
1632     const char *role = NULL;
1633     void *s = NULL;
1634
1635     pa_assert(m);
1636     pa_log_debug("do_notify(%s): type(%d), user_data(%p)", notify_command_type_str[command], type, user_data);
1637
1638     switch (command) {
1639     case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
1640         pa_assert(user_data);
1641         memset(&hook_call_select_data, 0, sizeof(pa_stream_manager_hook_data_for_select));
1642         s = user_data;
1643         if (s) {
1644             hook_call_select_data.stream_type = type;
1645             hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1646             fill_device_info_to_hook_data(&hook_call_select_data, command, type, s, m);
1647             hook_call_select_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
1648             if (type == STREAM_SINK_INPUT)
1649                 hook_call_select_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
1650             else if (type == STREAM_SOURCE_OUTPUT)
1651                 hook_call_select_data.proper_source = &(((pa_source_output_new_data*)s)->source);
1652             pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_select_data);
1653         }
1654         break;
1655     }
1656     case NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA:
1657     case NOTIFY_COMMAND_CHANGE_ROUTE_START: {
1658         pa_assert(user_data);
1659         memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
1660         s = user_data;
1661         if (s) {
1662             if (command == NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA) {
1663                 hook_call_route_data.origins_from_new_data = TRUE;
1664                 role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1665                 hook_call_route_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
1666                 if (type == STREAM_SINK_INPUT) {
1667                     hook_call_route_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
1668                 } else if (type == STREAM_SOURCE_OUTPUT) {
1669                     hook_call_route_data.proper_source = &(((pa_source_output_new_data*)s)->source);
1670                 }
1671             } else {
1672                 role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1673                 hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
1674                 if (type == STREAM_SINK_INPUT) {
1675                     if (((pa_sink_input*)s)->sink)
1676                         hook_call_route_data.idx_streams = ((pa_sink_input*)s)->sink->inputs;
1677                 } else if (type == STREAM_SOURCE_OUTPUT) {
1678                     if (((pa_source_output*)s)->source)
1679                         hook_call_route_data.idx_streams = ((pa_source_output*)s)->source->outputs;
1680                 }
1681             }
1682             hook_call_route_data.stream_type = type;
1683             hook_call_route_data.stream_role = role;
1684             fill_device_info_to_hook_data(&hook_call_route_data, command, type, s, m);
1685             if (hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL) {
1686                 if (hook_call_route_data.idx_manual_devices && !pa_idxset_size(hook_call_route_data.idx_manual_devices)) {
1687                     pa_log_info("no manual device for this type(%d), need to unset route", type);
1688                     hook_call_route_data.stream_role = "reset";
1689                 }
1690             }
1691             pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
1692         }
1693         break;
1694     }
1695     case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
1696         memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
1697         s = (type==STREAM_SINK_INPUT)?(void*)(m->cur_highest_priority.sink_input):(void*)(m->cur_highest_priority.source_output);
1698         if (s) {
1699             role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1700             hook_call_route_data.stream_type = type;
1701             hook_call_route_data.stream_role = role;
1702             hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
1703             hook_call_route_data.idx_streams = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->sink->inputs:((pa_source_output*)s)->source->outputs;
1704             fill_device_info_to_hook_data(&hook_call_route_data, command, type, s, m);
1705         } else {
1706             pa_log_info("no stream for this type(%d), need to unset route", type);
1707             hook_call_route_data.stream_type = type;
1708             hook_call_route_data.stream_role = "reset";
1709         }
1710         pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
1711         break;
1712     }
1713     case NOTIFY_COMMAND_UPDATE_ROUTE_OPTION: {
1714         pa_assert(user_data);
1715         memset(&hook_call_option_data, 0, sizeof(pa_stream_manager_hook_data_for_option));
1716         s = (type==STREAM_SINK_INPUT)?(void*)(m->cur_highest_priority.sink_input):(void*)(m->cur_highest_priority.source_output);
1717         if (s) {
1718             role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1719             hook_call_option_data.stream_role = role;
1720             hook_call_option_data.name = ((stream_route_option*)user_data)->name;
1721             hook_call_option_data.value = ((stream_route_option*)user_data)->value;
1722             pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_UPDATE_ROUTE_OPTION), &hook_call_option_data);
1723         }
1724         break;
1725     }
1726     case NOTIFY_COMMAND_INFORM_STREAM_CONNECTED:
1727     case NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED: {
1728         pa_assert(user_data);
1729         memset(&stream_conn_info, 0, sizeof(hal_stream_connection_info));
1730         s = user_data;
1731         if (s) {
1732             stream_conn_info.role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1733             stream_conn_info.direction = (type==STREAM_SINK_INPUT)?DIRECTION_OUT:DIRECTION_IN;
1734             stream_conn_info.idx = (type==STREAM_SINK_INPUT)?((pa_sink_input*)s)->index:((pa_source_output*)s)->index;
1735             stream_conn_info.is_connected = (command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED)?TRUE:FALSE;
1736             pa_hal_manager_update_stream_connection_info(m->hal, &stream_conn_info);
1737         }
1738         break;
1739     }
1740     }
1741     return;
1742 }
1743
1744 static pa_process_stream_result_t process_stream(stream_type_t type, void *stream, process_command_type_t command, pa_stream_manager *m) {
1745     pa_process_stream_result_t result = PA_PROCESS_STREAM_OK;
1746     const char *role = NULL;
1747     pa_bool_t ret = TRUE;
1748     pa_bool_t need_update = FALSE;
1749     int32_t volume_ret = 0;
1750     volume_info *v = NULL;
1751     const char *si_volume_type_str = NULL;
1752     const char *prior_priority = NULL;
1753     int32_t prior_p = 0;
1754     pa_format_info *req_format = NULL;
1755     char *format_str = NULL;
1756     const char *rate_str = NULL;
1757     const char *ch_str = NULL;
1758
1759     pa_log_info("START process_stream(%s): stream_type(%d), stream(%p), m(%p)", process_command_type_str[command], type, stream, m);
1760     pa_assert(stream);
1761     pa_assert(m);
1762
1763     if (command == PROCESS_COMMAND_PREPARE) {
1764         if (type == STREAM_SINK_INPUT) {
1765             /* Parse request formats for samplerate, channel, format infomation */
1766             if (((pa_sink_input_new_data*)stream)->req_formats) {
1767                 req_format = pa_idxset_first(((pa_sink_input_new_data*)stream)->req_formats, NULL);
1768                 if (req_format && req_format->plist) {
1769                     /* set sample_spec */
1770                     rate_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_RATE);
1771                     ch_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_CHANNELS);
1772                     if (pa_format_info_get_prop_string(req_format, PA_PROP_FORMAT_SAMPLE_FORMAT, &format_str)==0)
1773                         ((pa_sink_input_new_data*)stream)->sample_spec.format = pa_parse_sample_format((const char*)format_str);
1774                     pa_log_info("req rate(%s), req ch(%s), req format(%s)", rate_str, ch_str, format_str);
1775                     if (ch_str)
1776                         ((pa_sink_input_new_data*)stream)->sample_spec.channels = atoi (ch_str);
1777                     if (rate_str)
1778                         ((pa_sink_input_new_data*)stream)->sample_spec.rate = atoi (rate_str);
1779                     /* set channel map if it is not set by client */
1780                     if (!((pa_sink_input_new_data*)stream)->channel_map_is_set) {
1781                         pa_channel_map_init_auto(&(((pa_sink_input_new_data*)stream)->channel_map), ((pa_sink_input_new_data*)stream)->sample_spec.channels, PA_CHANNEL_MAP_ALSA);
1782                         pa_log_info("set default channel_map: channels(%u)",((pa_sink_input_new_data*)stream)->channel_map.channels);
1783                         ((pa_sink_input_new_data*)stream)->channel_map_is_set = TRUE;
1784                     }
1785                 }
1786             } else {
1787                 pa_log_debug("no request formats available");
1788             }
1789         }
1790         role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1791         if (!role) {
1792             /* set default value for role and priority */
1793             #define DEFAULT_ROLE "media"
1794             role = DEFAULT_ROLE;
1795             pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE, DEFAULT_ROLE);
1796             pa_log_warn("role is null, set default to [%s]", role);
1797         } else {
1798             /* skip roles */
1799             if (check_role_to_skip(m, role)) {
1800                 result = PA_PROCESS_STREAM_SKIP;
1801                 goto FAILURE;
1802             }
1803         }
1804         /* update the priority of this stream */
1805         ret = update_priority_of_stream(m, command, type, stream, role);
1806         if (ret == FALSE) {
1807             pa_log_error("could not update the priority of '%s' role.", role);
1808             result = PA_PROCESS_STREAM_STOP;
1809             goto FAILURE;
1810         }
1811         /* update the volume type of this stream */
1812         ret = update_volume_type_of_stream(m, type, stream, role);
1813         if (ret == FALSE) {
1814             pa_log_error("could not update the volume type of '%s' role.", role);
1815             result = PA_PROCESS_STREAM_STOP;
1816             goto FAILURE;
1817         }
1818         /* update the routing type of this stream */
1819         ret = update_routing_type_of_stream(m, stream, type, role);
1820         if (ret == FALSE) {
1821             pa_log_error("could not update the route type of '%s' role.", role);
1822             result = PA_PROCESS_STREAM_STOP;
1823             goto FAILURE;
1824         }
1825
1826         /* notify to select sink or source */
1827         do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, stream);
1828
1829     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1830         if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA)
1831             role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1832         else
1833             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1834
1835         /* skip roles */
1836         if (check_role_to_skip(m, role)) {
1837             result = PA_PROCESS_STREAM_SKIP;
1838             goto FAILURE;
1839         }
1840
1841         if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1842             /* update the priority of this stream */
1843             ret = update_priority_of_stream(m, command, type, stream, role);
1844             if (ret == FALSE) {
1845                 pa_log_error("could not update the priority of '%s' role.", role);
1846                 result = PA_PROCESS_STREAM_STOP;
1847                 goto FAILURE;
1848             }
1849         }
1850
1851         /* update the highest priority */
1852         ret = update_the_highest_priority_stream(m, command, stream, type,  role, &need_update);
1853         if (ret == FALSE) {
1854             pa_log_error("could not update the highest priority stream");
1855             result = PA_PROCESS_STREAM_SKIP;
1856             goto FAILURE;
1857         }
1858
1859         /* need to skip if this stream does not belong to internal device */
1860         /* if needed, notify to update */
1861         if (need_update) {
1862             if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA) {
1863                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START_WITH_NEW_DATA, type, stream);
1864                 if (type==STREAM_SINK_INPUT)
1865                     m->cur_highest_priority.need_to_update_si = TRUE;
1866                 else
1867                     m->cur_highest_priority.need_to_update_so = TRUE;
1868             } else {
1869                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, stream);
1870                 if (type==STREAM_SINK_INPUT)
1871                     m->cur_highest_priority.sink_input = stream;
1872                 else
1873                     m->cur_highest_priority.source_output = stream;
1874             }
1875         }
1876         if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED)
1877             do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, stream);
1878
1879     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED) {
1880         role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1881         if (role) {
1882             /* skip roles */
1883             if (check_role_to_skip(m, role)) {
1884                 result = PA_PROCESS_STREAM_SKIP;
1885                 goto FAILURE;
1886             }
1887
1888             /* check if it has already been processed (unlink or state_changed_cb) */
1889             prior_priority = pa_proplist_gets(type==STREAM_SINK_INPUT?((pa_sink_input*)stream)->proplist:((pa_source_output*)stream)->proplist, PA_PROP_MEDIA_ROLE_PRIORITY);
1890             if (prior_priority && !pa_atoi(prior_priority, &prior_p) && (prior_p == -1)) {
1891                 pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, skip it..");
1892                 result = PA_PROCESS_STREAM_SKIP;
1893                 goto FAILURE;
1894             }
1895
1896             /* mark the priority of this stream to -1 */
1897             pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, "%d", -1);
1898             ret = update_the_highest_priority_stream(m, command, stream, type, role, &need_update);
1899             if (ret == FALSE) {
1900                 pa_log_error("could not update the highest priority stream");
1901                 result = PA_PROCESS_STREAM_STOP;
1902                 goto FAILURE;
1903             }
1904
1905             do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED, type, stream);
1906
1907             /* need to skip if this stream does not belong to internal device */
1908             /* if needed, notify to update */
1909             if (need_update)
1910                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, NULL);
1911
1912         } else {
1913             pa_log_error("role is null, skip it");
1914         }
1915
1916     } else if (command == PROCESS_COMMAND_UPDATE_VOLUME) {
1917         if ((si_volume_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE))) {
1918             v = pa_hashmap_get(m->volume_map.out_volumes, si_volume_type_str);
1919             if (v && v->idx_volume_values) {
1920                 /* Update volume-level */
1921                 volume_ret = set_volume_level_with_new_data(m, type, stream, v->current_level);
1922                 if (volume_ret)
1923                     pa_log_error("failed to set_volume_level_by_idx(), stream_type(%d), level(%u), ret(0x%x)",
1924                             STREAM_SINK_INPUT, v->current_level, volume_ret);
1925                 /* Update volume-mute */
1926                 volume_ret = set_volume_mute_with_new_data(m, type, stream, v->is_muted);
1927                 if (volume_ret)
1928                     pa_log_error("failed to set_volume_mute_by_idx(), stream_type(%d), mute(%d), ret(0x%x)",
1929                             STREAM_SINK_INPUT, v->is_muted, volume_ret);
1930             }
1931         }
1932
1933     } else if (command == PROCESS_COMMAND_ADD_PARENT_ID || command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
1934         if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
1935             if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
1936                 m->cur_highest_priority.sink_input = stream;
1937                 m->cur_highest_priority.need_to_update_si = FALSE;
1938             }
1939             if (type == STREAM_SOURCE_OUTPUT && m->cur_highest_priority.need_to_update_so) {
1940                 m->cur_highest_priority.source_output = stream;
1941                 m->cur_highest_priority.need_to_update_so = FALSE;
1942             }
1943             if (command == PROCESS_COMMAND_ADD_PARENT_ID)
1944                 do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, stream);
1945         }
1946         /* update parent stream info. */
1947         ret = update_stream_parent_info(m, command, type, stream);
1948         if (ret == FALSE) {
1949             pa_log_warn("could not update the parent information of this stream");
1950             //return PA_PROCESS_STREAM_STOP;
1951         }
1952     }
1953
1954 FAILURE:
1955     pa_log_info("END process_stream(%s): result(%d)", process_command_type_str[command], result);
1956     return result;
1957 }
1958
1959 static void update_buffer_attribute(stream_type_t stream_type, void *new_data, pa_stream_manager *m) {
1960     int32_t maxlength = -1;
1961     int32_t tlength = -1;
1962     int32_t prebuf = -1;
1963     int32_t minreq = -1;
1964     int32_t fragsize = -1;
1965     const char* audio_latency = NULL;
1966
1967     pa_assert(m);
1968     pa_assert(new_data);
1969
1970     if (m->hal == NULL)
1971         return;
1972
1973     audio_latency = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY);
1974     pa_log_info("audio_latency : %s", audio_latency);
1975     if (audio_latency == NULL)
1976         return;
1977
1978     if (!pa_hal_manager_get_buffer_attribute(m->hal, (io_direction_t)!stream_type, audio_latency, new_data, (uint32_t*)&maxlength, (uint32_t*)&tlength, (uint32_t*)&prebuf, (uint32_t*)&minreq, (uint32_t*)&fragsize)) {
1979         pa_log_info(" - maxlength:%d, tlength:%d, prebuf:%d, minreq:%d, fragsize:%d", maxlength, tlength, prebuf, minreq, fragsize);
1980         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "maxlength", "%d", maxlength);
1981         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "tlength",   "%d", tlength);
1982         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "prebuf",    "%d", prebuf);
1983         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "minreq",    "%d", minreq);
1984         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), "fragsize",  "%d", fragsize);
1985     }
1986
1987     return;
1988 }
1989
1990 static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data *new_data, pa_stream_manager *m) {
1991     pa_core_assert_ref(core);
1992
1993     pa_log_info("start sink_input_new_cb");
1994
1995     process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_PREPARE, m);
1996     /* Update buffer attributes from HAL */
1997     update_buffer_attribute(STREAM_SINK_INPUT, new_data, m);
1998     process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_UPDATE_VOLUME, m);
1999     process_stream(STREAM_SINK_INPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA, m);
2000
2001     return PA_HOOK_OK;
2002 }
2003
2004 static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2005     pa_core_assert_ref(core);
2006     pa_sink_input_assert_ref(i);
2007
2008     pa_log_info("start sink_input_put_cb, i(%p, index:%u)", i, i->index);
2009
2010     process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_ADD_PARENT_ID, m);
2011
2012     return PA_HOOK_OK;
2013 }
2014
2015 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2016     pa_core_assert_ref(core);
2017     pa_sink_input_assert_ref(i);
2018
2019     pa_log_info("start sink_input_unlink_cb, i(%p, index:%u)", i, i->index);
2020     process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_REMOVE_PARENT_ID, m);
2021     process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2022
2023     return PA_HOOK_OK;
2024 }
2025
2026 static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2027     pa_sink_input_state_t state;
2028
2029     pa_assert(i);
2030     pa_assert(m);
2031
2032     state = pa_sink_input_get_state(i);
2033     pa_log_info("start sink_input_state_changed_cb(), sink-input(%p), state(%d)", i, state);
2034
2035     switch(state) {
2036     case PA_SINK_INPUT_CORKED: {
2037         process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2038         break;
2039     }
2040     case PA_SINK_INPUT_DRAINED:
2041     case PA_SINK_INPUT_RUNNING: {
2042         process_stream(STREAM_SINK_INPUT, i, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
2043         break;
2044     }
2045     default:
2046         break;
2047     }
2048
2049     return PA_HOOK_OK;
2050 }
2051
2052 static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2053     pa_core_assert_ref(core);
2054     pa_sink_input_assert_ref(i);
2055
2056     /* There's no point in doing anything if the core is shut down anyway */
2057     if (core->state == PA_CORE_SHUTDOWN)
2058         return PA_HOOK_OK;
2059
2060     pa_log_debug ("sink_input_move_start_cb, i(%p, index:%u)", i, i->index);
2061
2062     set_volume_mute_by_idx(m, STREAM_SINK_INPUT, i->index, TRUE);
2063
2064     return PA_HOOK_OK;
2065 }
2066
2067 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2068     pa_core_assert_ref(core);
2069     pa_sink_input_assert_ref(i);
2070
2071     /* There's no point in doing anything if the core is shut down anyway */
2072     if (core->state == PA_CORE_SHUTDOWN)
2073         return PA_HOOK_OK;
2074
2075     pa_log_debug ("sink_input_move_finish_cb, i(%p, index:%u)", i, i->index);
2076
2077     set_volume_mute_by_idx(m, STREAM_SINK_INPUT, i->index, FALSE);
2078
2079     return PA_HOOK_OK;
2080 }
2081
2082 static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new_data *new_data, pa_stream_manager *m) {
2083     pa_core_assert_ref(core);
2084
2085     pa_log_info("start source_output_new_new_cb");
2086
2087     process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_PREPARE, m);
2088     /* Update buffer attributes from HAL */
2089     update_buffer_attribute(STREAM_SOURCE_OUTPUT, new_data, m);
2090     process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_UPDATE_VOLUME, m);
2091     process_stream(STREAM_SOURCE_OUTPUT, new_data, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED_WITH_NEW_DATA, m);
2092
2093     return PA_HOOK_OK;
2094 }
2095
2096 static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2097     pa_core_assert_ref(core);
2098     pa_source_output_assert_ref(o);
2099
2100     pa_log_info("start source_output_put_cb, o(%p, index:%u)", o, o->index);
2101
2102     process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_ADD_PARENT_ID, m);
2103
2104     return PA_HOOK_OK;
2105 }
2106
2107 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2108     pa_core_assert_ref(core);
2109     pa_source_output_assert_ref(o);
2110
2111     pa_log_info("start source_output_unlink_cb, o(%p, index:%u)", o, o->index);
2112
2113     process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_REMOVE_PARENT_ID, m);
2114     process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2115
2116     return PA_HOOK_OK;
2117 }
2118
2119 static pa_hook_result_t source_output_state_changed_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2120     pa_source_output_state_t state;
2121
2122     pa_assert(o);
2123     pa_assert(m);
2124
2125     state = pa_source_output_get_state(o);
2126     pa_log_debug("start source_output_state_changed_cb(), source-output(%p), state(%d)", o, state);
2127
2128     switch(state) {
2129     case PA_SOURCE_OUTPUT_CORKED: {
2130         process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, m);
2131         break;
2132     }
2133     case PA_SOURCE_OUTPUT_RUNNING: {
2134         process_stream(STREAM_SOURCE_OUTPUT, o, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, m);
2135         break;
2136     }
2137     default:
2138         break;
2139     }
2140
2141     return PA_HOOK_OK;
2142 }
2143
2144 /* Reorganize routing when a device has been connected or disconnected */
2145 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_device_manager_hook_data_for_conn_changed *conn, pa_stream_manager *m) {
2146     const char *route_type_str = NULL;
2147     stream_route_type_t route_type;
2148     dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
2149
2150     device_direction = pa_device_manager_get_device_direction(conn->device);
2151     pa_log_info("device_connection_changed_hook_cb is called. conn(%p), is_connected(%d), device(%p), direction(0x%x)",
2152             conn, conn->is_connected, conn->device, device_direction);
2153
2154     /* If the route type of the stream is not manual, notify again */
2155     if (m->cur_highest_priority.source_output && (device_direction & DM_DEVICE_DIRECTION_IN)) {
2156         route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2157         if(!pa_atoi(route_type_str, (int32_t*)&route_type))
2158             if (route_type != STREAM_ROUTE_TYPE_MANUAL)
2159                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, m->cur_highest_priority.source_output);
2160     } if (m->cur_highest_priority.sink_input && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
2161         route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2162         if(!pa_atoi(route_type_str, (int32_t*)&route_type))
2163             if (route_type != STREAM_ROUTE_TYPE_MANUAL)
2164                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, m->cur_highest_priority.sink_input);
2165     }
2166
2167     return PA_HOOK_OK;
2168 }
2169
2170 /* Reorganize routing when device information has been changed */
2171 static pa_hook_result_t device_information_changed_hook_cb(pa_core *c, pa_device_manager_hook_data_for_info_changed *info, pa_stream_manager *m) {
2172     pa_log_info("device_information_changed_hook_cb is called. info(%p), changed_info(%d), device(%p)",
2173             info, info->changed_info, info->device);
2174
2175     return PA_HOOK_OK;
2176 }
2177
2178 static void subscribe_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, pa_stream_manager *m) {
2179     pa_client *client = NULL;
2180     stream_parent *sp = NULL;
2181     const char *name = NULL;
2182     uint32_t *device_id = NULL;
2183     uint32_t _idx = 0;
2184     pa_core_assert_ref(core);
2185     pa_assert(m);
2186     pa_log_info("subscribe_cb() is called, t(%x), idx(%u)", t, idx);
2187
2188     if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE)) {
2189         client = pa_idxset_get_by_index(core->clients, idx);
2190         if (client == NULL) {
2191             pa_log_error(" - could not find any client that has idx(%u)", idx);
2192             return;
2193         }
2194         name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);
2195         if (strncmp (name, STREAM_MANAGER_CLIENT_NAME, strlen(STREAM_MANAGER_CLIENT_NAME))) {
2196             pa_log_warn(" - this is not a client(%s) that we should take care of, skip it", name);
2197             return;
2198         }
2199         /* add a stream parent */
2200         sp = pa_xmalloc0(sizeof(stream_parent));
2201         sp->idx_sink_inputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2202         sp->idx_source_outputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2203         sp->idx_route_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2204         sp->idx_route_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
2205         pa_hashmap_put(m->stream_parents, (void*)idx, sp);
2206         pa_log_debug(" - add sp(%p), idx(%u)", sp, idx);
2207      } else if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE)) {
2208         /* remove the stream parent */
2209         sp = pa_hashmap_get(m->stream_parents, (const void*)idx);
2210         if (sp) {
2211             pa_log_debug(" - remove sp(%p), idx(%u)", sp, idx);
2212             pa_hashmap_remove(m->stream_parents, (const void*)idx);
2213             if (sp->idx_route_in_devices)
2214                 PA_IDXSET_FOREACH(device_id, sp->idx_route_in_devices, _idx)
2215                     pa_xfree(device_id);
2216             if (sp->idx_route_out_devices)
2217                 PA_IDXSET_FOREACH(device_id, sp->idx_route_out_devices, _idx)
2218                     pa_xfree(device_id);
2219             pa_idxset_free(sp->idx_sink_inputs, NULL);
2220             pa_idxset_free(sp->idx_source_outputs, NULL);
2221             pa_idxset_free(sp->idx_route_in_devices, NULL);
2222             pa_idxset_free(sp->idx_route_out_devices, NULL);
2223             pa_xfree(sp);
2224         } else {
2225             pa_log_error(" - could not find any stream_parent that has idx(%u)", idx);
2226         }
2227     }
2228 }
2229
2230 static int init_ipc (pa_stream_manager *m) {
2231 #ifdef HAVE_DBUS
2232 #ifdef USE_DBUS_PROTOCOL
2233     pa_assert(m);
2234     pa_log_info("Initialization for IPC");
2235     m->dbus_protocol = pa_dbus_protocol_get(m->core);
2236     pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, &stream_manager_interface_info, m) >= 0);
2237     pa_assert_se(pa_dbus_protocol_register_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2238 #else
2239     DBusError err;
2240     pa_dbus_connection *conn = NULL;
2241     static const DBusObjectPathVTable vtable = {
2242         .message_function = method_handler_for_vt,
2243     };
2244
2245     pa_assert(m);
2246     pa_log_info("Initialization for IPC");
2247
2248     dbus_error_init(&err);
2249
2250     if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err)) || dbus_error_is_set(&err)) {
2251         if (conn) {
2252             pa_dbus_connection_unref(conn);
2253         }
2254         pa_log_error("Unable to contact D-Bus system bus: %s: %s", err.name, err.message);
2255         goto fail;
2256     } else {
2257         pa_log_notice("Got dbus connection");
2258     }
2259     m->dbus_conn = conn;
2260     pa_assert_se(dbus_connection_register_object_path(pa_dbus_connection_get(conn), STREAM_MANAGER_OBJECT_PATH, &vtable, m));
2261 #endif
2262 #else
2263     pa_log_error("DBUS is not supported\n");
2264     goto fail;
2265 #endif
2266
2267     return 0;
2268 fail:
2269     pa_log_error("Failed to initialize stream manager ipc");
2270     return -1;
2271 }
2272
2273 static void deinit_ipc (pa_stream_manager *m) {
2274     pa_assert(m);
2275
2276 #ifdef HAVE_DBUS
2277 #ifdef USE_DBUS_PROTOCOL
2278     if (m->dbus_protocol) {
2279         pa_assert_se(pa_dbus_protocol_unregister_extension(m->dbus_protocol, STREAM_MANAGER_INTERFACE) >= 0);
2280         pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, STREAM_MANAGER_OBJECT_PATH, stream_manager_interface_info.name) >= 0);
2281         pa_dbus_protocol_unref(m->dbus_protocol);
2282         m->dbus_protocol = NULL;
2283     }
2284 #else
2285     if (m->dbus_conn) {
2286         if(!dbus_connection_unregister_object_path(pa_dbus_connection_get(m->dbus_conn), STREAM_MANAGER_OBJECT_PATH))
2287             pa_log_error("Failed to unregister object path");
2288         m->dbus_conn = NULL;
2289     }
2290 #endif
2291 #endif
2292     return;
2293 }
2294
2295 pa_stream_manager* pa_stream_manager_init(pa_core *c) {
2296     pa_stream_manager *m;
2297
2298     pa_assert(c);
2299
2300     m = pa_xnew0(pa_stream_manager, 1);
2301     m->core = c;
2302
2303     m->hal = pa_hal_manager_get(c, NULL);
2304
2305 #ifdef HAVE_DBUS
2306 #ifdef USE_DBUS_PROTOCOL
2307     m->dbus_protocol = NULL;
2308 #else
2309     m->dbus_conn = NULL;
2310 #endif
2311 #endif
2312     if (init_ipc(m))
2313         goto fail;
2314
2315     if (init_stream_map(m))
2316         goto fail;
2317
2318     if (init_volume_map(m))
2319         goto fail;
2320
2321     m->stream_parents = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
2322
2323     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);
2324     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);
2325     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);
2326     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);
2327     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);
2328     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);
2329     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);
2330     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);
2331     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);
2332     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);
2333
2334
2335     m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, (pa_subscription_cb_t)subscribe_cb, m);
2336
2337     m->comm.comm = pa_communicator_get(c);
2338     m->comm.comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm,PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
2339             PA_HOOK_EARLY + 10, (pa_hook_cb_t) device_connection_changed_hook_cb, m);
2340     m->comm.comm_hook_device_information_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm,PA_COMMUNICATOR_HOOK_DEVICE_INFORMATION_CHANGED),
2341             PA_HOOK_EARLY, (pa_hook_cb_t) device_information_changed_hook_cb, m);
2342
2343     return m;
2344
2345 fail:
2346     pa_log_error("Failed to initialize stream-manager");
2347     deinit_volume_map(m);
2348     deinit_stream_map(m);
2349     deinit_ipc(m);
2350     if (m->hal)
2351         pa_hal_manager_unref(m->hal);
2352     pa_xfree(m);
2353     return 0;
2354 }
2355
2356 void pa_stream_manager_done(pa_stream_manager *m) {
2357     pa_assert(m);
2358
2359     if (m->comm.comm) {
2360         if (m->comm.comm_hook_device_connection_changed_slot)
2361             pa_hook_slot_free(m->comm.comm_hook_device_connection_changed_slot);
2362         if (m->comm.comm_hook_device_information_changed_slot)
2363             pa_hook_slot_free(m->comm.comm_hook_device_information_changed_slot);
2364         pa_communicator_unref(m->comm.comm);
2365     }
2366
2367     if (m->subscription)
2368         pa_subscription_free(m->subscription);
2369
2370     if (m->sink_input_new_slot)
2371         pa_hook_slot_free(m->sink_input_new_slot);
2372     if (m->sink_input_put_slot)
2373         pa_hook_slot_free(m->sink_input_put_slot);
2374     if (m->sink_input_unlink_slot)
2375         pa_hook_slot_free(m->sink_input_unlink_slot);
2376     if (m->sink_input_state_changed_slot)
2377         pa_hook_slot_free(m->sink_input_state_changed_slot);
2378     if (m->sink_input_move_start_slot)
2379         pa_hook_slot_free(m->sink_input_move_start_slot);
2380     if (m->sink_input_move_finish_slot)
2381         pa_hook_slot_free(m->sink_input_move_finish_slot);
2382     if (m->source_output_new_slot)
2383         pa_hook_slot_free(m->source_output_new_slot);
2384     if (m->source_output_put_slot)
2385         pa_hook_slot_free(m->source_output_put_slot);
2386     if (m->source_output_unlink_slot)
2387         pa_hook_slot_free(m->source_output_unlink_slot);
2388     if (m->source_output_state_changed_slot)
2389         pa_hook_slot_free(m->source_output_state_changed_slot);
2390
2391     if (m->stream_parents)
2392         pa_hashmap_free(m->stream_parents);
2393
2394     deinit_volume_map(m);
2395     deinit_stream_map(m);
2396     deinit_ipc(m);
2397
2398     if (m->hal)
2399         pa_hal_manager_unref(m->hal);
2400
2401     pa_xfree(m);
2402 }