c01afbb8d170b81d1199a808008d0f509285b176
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / stream-manager.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2015-2016 Sangchul Lee <sc11.lee@samsung.com>
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <errno.h>
33
34 #include <pulse/timeval.h>
35 #include <pulse/rtclock.h>
36
37 #include <pulse/xmalloc.h>
38 #include <pulse/proplist.h>
39
40 #include <pulsecore/module.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/sink.h>
43 #include <pulsecore/modargs.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/shared.h>
46 #include <pulsecore/core-util.h>
47 #include <pulsecore/proplist-util.h>
48
49 #include <json.h>
50 #include "stream-manager.h"
51 #include "stream-manager-priv.h"
52 #include "stream-manager-volume-priv.h"
53 #include "stream-manager-restriction-priv.h"
54 #include "stream-manager-filter-priv.h"
55 #ifdef HAVE_DBUS
56 #include "stream-manager-dbus-priv.h"
57 #endif
58
59 #define SHARED_STREAM_MANAGER "tizen-stream-manager"
60
61 #define IS_AVAILABLE_DIRECTION(stream_type, device_direction) \
62     ((stream_type == STREAM_SINK_INPUT) ? (device_direction & DM_DEVICE_DIRECTION_OUT) : (device_direction & DM_DEVICE_DIRECTION_IN))
63 #define GET_DIRECTION(stream) \
64     ((pa_sink_input_isinstance(stream)) ? DM_DEVICE_DIRECTION_OUT : DM_DEVICE_DIRECTION_IN)
65 #define CONVERT_TO_DEVICE_DIRECTION(stream_type) \
66     ((stream_type == STREAM_SINK_INPUT) ? DM_DEVICE_DIRECTION_OUT : DM_DEVICE_DIRECTION_IN)
67
68 #define STREAM_MANAGER_CLIENT_INFO    "SOUND_MANAGER_STREAM_INFO"    /* The stream info client via sound-manager */
69 #define STREAM_MANAGER_CLIENT_DUCKING "SOUND_MANAGER_STREAM_DUCKING" /* The ducking client via sound-manager */
70
71 #define DEFAULT_ROLE "media"
72 #define SKIP_ROLE "skip"
73 #define ACTIVE_DEV_REMOVED "removed"
74 #define STRING_NONE "none"
75
76 /* There are some streams that need to be skipped.
77  * In other words, we do not care about streams that have a name of listed as below */
78 #define NAME_FOR_SKIP_MAX 1
79 static const char* stream_manager_media_names_for_skip[NAME_FOR_SKIP_MAX] = {"pulsesink probe"};
80
81 #define MUTE_KEY    "mute_by_device_disconnection"
82 #define TIMED_UNMUTE_USEC    300000
83
84 static const char* process_command_type_str[] = {
85     [PROCESS_COMMAND_PREPARE] = "PREPARE",
86     [PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED] = "CHANGE_ROUTE_BY_STREAM_STARTED",
87     [PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED] = "CHANGE_ROUTE_BY_STREAM_ENDED",
88     [PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_RUNNING] = "CHANGE_ROUTE_BY_STATE_CHANGED_RUNNING",
89     [PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_CORKED] = "CHANGE_ROUTE_BY_STATE_CHANGED_CORKED",
90     [PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED] = "CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED",
91     [PROCESS_COMMAND_UPDATE_VOLUME] = "UPDATE_VOLUME",
92     [PROCESS_COMMAND_ADD_STREAM] = "ADD_STREAM",
93     [PROCESS_COMMAND_REMOVE_STREAM] = "REMOVE_STREAM",
94     [PROCESS_COMMAND_UPDATE_BUFFER_ATTR] = "UPDATE_BUFFER_ATTR",
95     [PROCESS_COMMAND_APPLY_FILTER] = "APPLY_FILTER",
96     [PROCESS_COMMAND_SET_AEC_REFERENCE_DEVICE] = "SET_AEC_REFERENCE",
97 };
98
99 static const char* notify_command_type_str[] = {
100     [NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT] = "SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT",
101     [NOTIFY_COMMAND_CHANGE_ROUTE_START] = "CHANGE_ROUTE_START",
102     [NOTIFY_COMMAND_CHANGE_ROUTE_END] = "CHANGE_ROUTE_END",
103     [NOTIFY_COMMAND_UPDATE_ROUTE_OPTION] = "UPDATE_ROUTE_OPTION",
104     [NOTIFY_COMMAND_INFORM_STREAM_CONNECTED] = "INFORM_STREAM_CONNECTED",
105     [NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED] = "INFORM_STREAM_DISCONNECTED",
106 };
107
108 #define STREAM_MAP_FILE PA_DEFAULT_CONFIG_DIR"/stream-map.json"
109 #define STREAM_MAP_VOLUMES "volumes"
110 #define STREAM_MAP_VOLUME_TYPE "type"
111 #define STREAM_MAP_VOLUME_IS_FOR_HAL "is-hal-volume"
112 #define STREAM_MAP_LATENCIES "latencies"
113 #define STREAM_MAP_LATENCY_TYPE "type"
114 #define STREAM_MAP_LATENCY_FRAGSIZE_MS "fragsize-ms"
115 #define STREAM_MAP_LATENCY_TLENGTH_MS "tlength-ms"
116 #define STREAM_MAP_LATENCY_MINREQ_MS "minreq-ms"
117 #define STREAM_MAP_LATENCY_PREBUF_MS "prebuf-ms"
118 #define STREAM_MAP_LATENCY_MAXLENGTH "maxlength"
119 #define STREAM_MAP_STREAMS "streams"
120 #define STREAM_MAP_STREAM_ROLE "role"
121 #define STREAM_MAP_STREAM_PRIORITY "priority"
122 #define STREAM_MAP_STREAM_ROUTE_TYPE "route-type"
123 #define STREAM_MAP_STREAM_DIRECTIONS "directions"
124 #define STREAM_MAP_STREAM_VOLUME_TYPES "volume-types"
125 #define STREAM_MAP_STREAM_VOLUME_TYPE_IN "in"
126 #define STREAM_MAP_STREAM_VOLUME_TYPE_OUT "out"
127 #define STREAM_MAP_STREAM_CAPTURE_VOLUME_TYPE "capture-volume-type"
128 #define STREAM_MAP_STREAM_PLAYBACK_VOLUME_TYPE "playback-volume-type"
129 #define STREAM_MAP_STREAM_AVAIL_IN_DEVICES "avail-in-devices"
130 #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices"
131 #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks"
132
133 PA_DEFINE_PRIVATE_CLASS(stream_manager_msg, pa_msgobject);
134
135 enum {
136     MESSAGE_RAMP_FINISHED,
137 };
138
139 struct stream_manager_param {
140     pa_stream_manager *m;
141     pa_sink_input *sink_input;
142     uint32_t index;
143 };
144
145 /* Called from main context */
146 static void process_ramp_finish(struct stream_manager_param *param) {
147     stream_ducking *sd;
148     void *state;
149
150     /* Find a context id from all the ducked stream list by this stream index.
151     * Check the number of managed streams of the context id, if it is the last one
152     * then broadcast a signal with context id.*/
153     PA_HASHMAP_FOREACH(sd, param->m->stream_duckings, state) {
154         if (!pa_idxset_get_by_data(sd->idx_ducking_streams, param->sink_input, NULL)) {
155             pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)",
156                         param->sink_input, param->index, sd);
157             continue;
158         }
159
160         pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)",
161             param->sink_input, param->index, sd, sd->ducking_stream_count, sd->state);
162
163         if (sd->ducking_stream_count <= 0)
164             continue;
165
166         /* Remove trigger when unducked */
167         if (sd->state == STREAM_DUCKING_STATE_UNDUCKING)
168             pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)param->sink_input, NULL);
169
170         /* Send signal when all streams are ducked.
171             * Note that the condition of increasing count value below is located in
172             * handle_activate_ducking() of DBus handler. */
173         if (--sd->ducking_stream_count == 0) {
174             if (sd->state == STREAM_DUCKING_STATE_DUCKING) {
175                 sd->state = STREAM_DUCKING_STATE_DUCKED;
176             } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) {
177                 sd->state = STREAM_DUCKING_STATE_UNDUCKED;
178             } else {
179                 pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state);
180                 continue;
181             }
182
183             pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state);
184             send_ducking_state_changed_signal(pa_dbus_connection_get(param->m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
185         }
186     }
187 }
188
189 static bool is_valid_notify_command(notify_command_type_t command) {
190     return (command < sizeof(notify_command_type_str) / sizeof(char *));
191 }
192
193 static bool is_valid_process_command(process_command_type_t command) {
194     return (command < sizeof(process_command_type_str) / sizeof(char *));
195 }
196
197 bool is_stream_related_call_active_routing(pa_object *stream) {
198     const char *stream_role;
199     pa_proplist *prop;
200
201     pa_assert(stream);
202
203     if (pa_sink_input_isinstance(stream))
204         prop = PA_SINK_INPUT(stream)->proplist;
205     else
206         prop = PA_SOURCE_OUTPUT(stream)->proplist;
207
208     if (!(stream_role = pa_proplist_gets(prop, PA_PROP_MEDIA_ROLE)))
209         return false;
210
211     if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE) ||
212         pa_safe_streq(stream_role, STREAM_ROLE_CALL_VIDEO) ||
213         pa_safe_streq(stream_role, STREAM_ROLE_VOIP)) {
214         pa_log_info("%s relates call active routing", stream_role);
215         return true;
216      }
217
218     return false;
219 }
220
221 static int32_t convert_route_type(const char *route_type_str, stream_route_type_t *route_type) {
222     int ret = 0;
223
224     pa_assert(route_type);
225     pa_assert(route_type_str);
226
227     if (pa_safe_streq("auto", route_type_str))
228         *route_type = STREAM_ROUTE_TYPE_AUTO;
229     else if (pa_safe_streq("auto-last-connected", route_type_str))
230         *route_type = STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED;
231     else if (pa_safe_streq("auto-all", route_type_str))
232         *route_type = STREAM_ROUTE_TYPE_AUTO_ALL;
233     else if (pa_safe_streq("manual", route_type_str))
234         *route_type = STREAM_ROUTE_TYPE_MANUAL;
235     else if (pa_safe_streq("manual-ext", route_type_str))
236         *route_type = STREAM_ROUTE_TYPE_MANUAL_EXT;
237     else {
238         ret = -1;
239         pa_log_error("Not supported route_type(%s)", route_type_str);
240     }
241
242     return ret;
243 }
244
245 int32_t get_route_type(void *stream, stream_type_t stream_type, bool is_new_data, stream_route_type_t *stream_route_type) {
246     const char *route_type_str = NULL;
247
248     pa_assert(stream);
249     pa_assert(stream_route_type);
250
251     if (is_new_data)
252         route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, stream_type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
253     else
254         route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, stream_type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
255     if (!route_type_str) {
256         pa_log_warn("could not get route type from the stream(%p)", stream);
257         return -1;
258      }
259
260     if (pa_atoi(route_type_str, (int32_t*)stream_route_type)) {
261         pa_log_error("could not convert route_type_str(%s) to int", route_type_str);
262         return -1;
263     }
264
265     return 0;
266 }
267
268 int32_t get_stream_info(pa_stream_manager *m, const char *stream_role, stream_info_per_type *info) {
269     uint32_t idx = 0;
270     char *name;
271     int i = 0;
272     stream_info *s = NULL;
273     pa_log_info("role[%s]", stream_role);
274     if (m->stream_infos) {
275         s = pa_hashmap_get(m->stream_infos, stream_role);
276         if (s) {
277             info->priority = s->priority;
278             info->route_type = s->route_type;
279             for (i = 0; i < STREAM_DIRECTION_MAX; i++) {
280                 pa_log_debug("  volume_types[%d] name : %s", i, s->volume_types[i]);
281                 info->volume_types[i] = s->volume_types[i];
282             }
283             PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx) {
284                 pa_log_debug("  avail-in-device[%d] name  : %s", idx, name);
285                 if (idx < AVAIL_DEVICES_MAX) {
286                     info->avail_in_devices[idx] = name;
287                 } else {
288                     pa_log_error("  avail-in-devices, out of range, [%d]", idx);
289                     return -1;
290                 }
291             }
292             info->num_of_in_devices = pa_idxset_size(s->idx_avail_in_devices);
293             PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx) {
294                 pa_log_debug("  avail-out-device[%d] name  : %s", idx, name);
295                 if (idx < AVAIL_DEVICES_MAX) {
296                     info->avail_out_devices[idx] = name;
297                 } else {
298                     pa_log_error("  avail-out-devices, out of range, [%d]", idx);
299                     return -1;
300                 }
301             }
302             info->num_of_out_devices = pa_idxset_size(s->idx_avail_out_devices);
303             PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx) {
304                 pa_log_debug("  avail-frameworks[%d] name  : %s", idx, name);
305                 if (idx < AVAIL_FRAMEWORKS_MAX) {
306                     info->avail_frameworks[idx] = name;
307                 } else {
308                     pa_log_error("  avail-frameworks, out of range, [%d]", idx);
309                     return -1;
310                 }
311             }
312             info->num_of_frameworks = pa_idxset_size(s->idx_avail_frameworks);
313         } else {
314             /* set variables for error */
315             info->priority = -1;
316             info->num_of_in_devices = info->num_of_out_devices = info->num_of_frameworks = 1;
317             info->volume_types[0] = info->volume_types[1] = STRING_NONE;
318             info->avail_in_devices[0] = STRING_NONE;
319             info->avail_out_devices[0] = STRING_NONE;
320             info->avail_frameworks[0] = STRING_NONE;
321             pa_log_error("could not find the stream_role : %s", stream_role);
322             return -1;
323         }
324     } else {
325         pa_log_error("stream_map is not initialized..");
326         return -1;
327     }
328     return 0;
329 }
330
331 int32_t get_available_streams(pa_stream_manager *m, stream_list *list) {
332     void *state = NULL;
333     stream_info *s = NULL;
334     char *role = NULL;
335     int i = 0;
336
337     if (m->stream_infos) {
338         while ((s = pa_hashmap_iterate(m->stream_infos, &state, (const void**)&role))) {
339             if (i < AVAIL_STREAMS_MAX) {
340                 list->priorities[i] = s->priority;
341                 list->types[i++] = role;
342                 pa_log_debug("  [%d] stream_type[%s], priority[%d]", i-1, role, s->priority);
343             } else {
344                 pa_log_error("  out of range, [%d]", i);
345                 break;
346             }
347         }
348         list->num_of_streams = i;
349         pa_log_debug("  num_of_streams[%d]", i);
350     } else {
351         pa_log_error("stream_map is not initialized..");
352         return -1;
353     }
354     return 0;
355 }
356
357 static stream_parent* get_stream_parent(pa_stream_manager *m, pa_object *stream) {
358     pa_proplist *prop;
359     const char *parent_id;
360     uint32_t parent_id_u;
361
362     pa_assert(m);
363     pa_assert(stream);
364
365     if (pa_sink_input_isinstance(stream))
366         prop = PA_SINK_INPUT(stream)->proplist;
367     else
368         prop = PA_SOURCE_OUTPUT(stream)->proplist;
369
370     if ((parent_id = pa_proplist_gets(prop, PA_PROP_MEDIA_PARENT_ID)) == NULL) {
371         pa_log_warn("No parent for this stream");
372         return NULL;
373     }
374
375     if (pa_atou(parent_id, &parent_id_u) < 0) {
376         pa_log_warn("Invalid parent id '%s'", parent_id);
377         return NULL;
378     }
379
380     return pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(parent_id_u));
381 }
382
383 static pa_idxset* get_route_devices(pa_stream_manager *m, pa_object *stream) {
384     stream_parent *sp;
385
386     pa_assert(m);
387     pa_assert(stream);
388
389     if ((sp = get_stream_parent(m, stream)) == NULL) {
390         pa_log_error("No stream parent for this stream");
391         return NULL;
392     }
393
394     if (pa_sink_input_isinstance(stream))
395         return sp->idx_route_out_devices;
396     else
397         return sp->idx_route_in_devices;
398 }
399
400 static pa_idxset* get_avail_device_types(pa_stream_manager *m, const char *stream_role, dm_device_direction_t direction) {
401     stream_info *si;
402
403     pa_assert(m);
404     pa_assert(stream_role);
405
406     if (!(si = pa_hashmap_get(m->stream_infos, stream_role))) {
407         pa_log_warn("not supported role[%s]", stream_role);
408         return NULL;
409     }
410
411     if (direction == DM_DEVICE_DIRECTION_IN)
412         return si->idx_avail_in_devices;
413     else
414         return si->idx_avail_out_devices;
415 }
416
417 static void activate_device_only(pa_stream_manager *m, pa_tz_device *device) {
418     pa_idxset *device_list;
419     pa_tz_device *device_iter;
420     uint32_t device_idx, id, others_id;
421     dm_device_direction_t direction, others_direction;
422     dm_device_state_t others_state;
423     char *device_type;
424
425     pa_assert(m);
426     pa_assert(device);
427
428     direction = pa_tz_device_get_direction(device);
429     id = pa_tz_device_get_id(device);
430     device_type = pa_tz_device_get_type(device);
431
432     pa_log_info("activate device(%s/%u)", device_type, id);
433
434     pa_tz_device_set_state(device, DM_DEVICE_STATE_ACTIVATED);
435
436     /* deactivate others */
437     device_list = pa_device_manager_get_device_list(m->dm);
438     PA_IDXSET_FOREACH(device_iter, device_list, device_idx) {
439         if (device_iter != device) {
440             others_state = pa_tz_device_get_state(device_iter);
441             if (others_state == DM_DEVICE_STATE_DEACTIVATED)
442                 continue;
443             others_direction = pa_tz_device_get_direction(device_iter);
444             others_id = pa_tz_device_get_id(device_iter);
445             if (direction & others_direction) {
446                 pa_log_debug("device(%u) is deactivated by device(%u)", others_id, id);
447                 pa_tz_device_set_state(device_iter, DM_DEVICE_STATE_DEACTIVATED);
448             }
449         }
450     }
451
452     return ;
453 }
454
455 pa_tz_device* get_media_auto_device(pa_stream_manager *m, dm_device_direction_t find_direction) {
456     pa_idxset *avail_device_types;
457     char *device_type;
458     pa_tz_device *device;
459     dm_device_direction_t direction;
460     uint32_t idx;
461
462     pa_assert(m);
463
464     pa_log_info("get media auto device for %d", find_direction);
465
466     if (find_direction == DM_DEVICE_DIRECTION_BOTH) {
467         pa_log_error("Invalid direction");
468         return NULL;
469     }
470
471     avail_device_types = get_avail_device_types(m, STREAM_ROLE_MEDIA, find_direction);
472     if (!avail_device_types) {
473         pa_log_error("No avail device types for media");
474         return NULL;
475     }
476
477     PA_IDXSET_FOREACH(device_type, avail_device_types, idx) {
478         device = pa_device_manager_get_device(m->dm, device_type, NULL);
479         if (!device)
480             continue;
481         direction = pa_tz_device_get_direction(device);
482         if (find_direction & direction)
483             return device;
484     }
485
486     return NULL;
487 }
488
489 pa_tz_device* get_media_last_device(pa_stream_manager *m, dm_device_direction_t find_direction) {
490     char *device_type;
491     pa_tz_device *next_device, *latest_device = NULL;
492     pa_usec_t creation_time = 0;
493     pa_usec_t latest_creation_time = 0;
494     dm_device_direction_t direction;
495     pa_idxset *avail_device_types;
496     uint32_t idx, id;
497
498     pa_assert(m);
499
500     pa_log_info("get media last device for %d", find_direction);
501
502     /* Only can get playback or capture device one by one */
503     if (find_direction == DM_DEVICE_DIRECTION_BOTH) {
504         pa_log_error("Invalid direction");
505         return NULL;
506     }
507
508     avail_device_types = get_avail_device_types(m, STREAM_ROLE_MEDIA, find_direction);
509     if (!avail_device_types) {
510         pa_log_error("No avail device types for media");
511         return NULL;
512     }
513
514     PA_IDXSET_FOREACH(device_type, avail_device_types, idx) {
515         if ((next_device = pa_device_manager_get_device(m->dm, device_type, NULL))) {
516             creation_time = pa_tz_device_get_creation_time(next_device);
517             direction = pa_tz_device_get_direction(next_device);
518             if ((find_direction & direction) == 0)
519                 continue;
520             if (!latest_device || (latest_creation_time <= creation_time)) {
521                 latest_device = next_device;
522                 latest_creation_time = creation_time;
523             }
524         }
525     }
526
527     if (latest_device) {
528         id = pa_tz_device_get_id(latest_device);
529         device_type = pa_tz_device_get_type(latest_device);
530         pa_log_info("last %s-device: (%s/%u)", find_direction == DM_DEVICE_DIRECTION_IN ? "in" : "out", device_type, id);
531     } else {
532         pa_log_info("no %s-device", find_direction == DM_DEVICE_DIRECTION_IN ? "in" : "out");
533     }
534
535     return latest_device;
536 }
537
538 /* select device which of type is in avail_device_types, and highest priority in
539  * route_device */
540 static pa_tz_device* select_device_from_avail_device_types(pa_stream_manager *m,
541                                                            pa_idxset *avail_device_types, pa_idxset *route_devices) {
542     char *device_type;
543     uint32_t route_device_idx, device_type_idx;
544     uint32_t *route_device_id;
545     pa_tz_device *device, *candidate = NULL;
546
547     pa_assert(m);
548
549     if (avail_device_types == NULL)
550         return NULL;
551     if (route_devices == NULL)
552         return NULL;
553
554     PA_IDXSET_FOREACH(device_type, avail_device_types, device_type_idx) {
555         PA_IDXSET_FOREACH(route_device_id, route_devices, route_device_idx) {
556             pa_log_warn("device id for call : %u", *route_device_id);
557             device = pa_device_manager_get_device_by_id(m->dm, *route_device_id);
558             if (device) {
559                 pa_log_info("Found higher priority device(%u)", *route_device_id);
560                 candidate = device;
561             }
562         }
563     }
564
565     return candidate;
566 }
567
568 /* stream should be one of 'call-voice' or 'call-video' or 'voip' */
569 int change_active_route_for_call(pa_stream_manager *m, pa_object *stream, bool stream_start) {
570     pa_tz_device *device;
571     pa_idxset *avail_device_types, *route_devices;
572     pa_proplist *prop;
573     const char *stream_role;
574
575     pa_assert(m);
576     pa_assert(m->stream_parents);
577     pa_assert(stream);
578
579     pa_log_info("Call virtual stream %s, change active device", stream_start ? "start" : "change");
580
581     if (pa_sink_input_isinstance(stream))
582         prop = PA_SINK_INPUT(stream)->proplist;
583     else
584         prop = PA_SOURCE_OUTPUT(stream)->proplist;
585
586     stream_role = pa_proplist_gets(prop, PA_PROP_MEDIA_ROLE);
587
588     avail_device_types = get_avail_device_types(m, stream_role, GET_DIRECTION(stream));
589     if (!avail_device_types) {
590         pa_log_error("No avail device typs for [%s]", stream_role);
591         return -1;
592     }
593     route_devices = get_route_devices(m, stream);
594     if (!route_devices) {
595         pa_log_error("No route devices for this stream");
596         return -1;
597     }
598
599     device = select_device_from_avail_device_types(m, avail_device_types, route_devices);
600     if (!device) {
601         pa_log_error("Failed to select device to activate on call state");
602         return -1;
603     }
604     activate_device_only(m, device);
605
606     return 0;
607 }
608
609 bool is_active_device_of_stream(const void *stream, stream_type_t stream_type, const char *device_type) {
610     const char *active_dev;
611
612     pa_assert(stream);
613     pa_assert(device_type);
614
615     active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(stream, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
616     if (pa_safe_streq(active_dev, device_type)) {
617         pa_log_info("stream(%p)'s active_dev(%s) is same as device_type(%s)", stream, active_dev, device_type);
618         return true;
619     }
620
621     return false;
622 }
623
624 bool is_stream_ducked(stream_ducking *sd) {
625     pa_assert(sd);
626
627     pa_log_info("state : %u", sd->state);
628
629     switch (sd->state) {
630     case STREAM_DUCKING_STATE_DUCKED:
631     case STREAM_DUCKING_STATE_UNDUCKING:
632         return true;
633     case STREAM_DUCKING_STATE_UNDUCKED:
634     case STREAM_DUCKING_STATE_DUCKING:
635     default:
636         return false;
637     }
638 }
639
640 static void set_media_active_device(pa_stream_manager *m) {
641     pa_tz_device *playback_device, *capture_device;
642     stream_info *media_info;
643
644     pa_assert(m);
645     pa_assert(m->stream_infos);
646
647     pa_log_info("set media active device");
648
649     media_info = pa_hashmap_get(m->stream_infos, STREAM_ROLE_MEDIA);
650     if (!media_info) {
651         pa_log_warn("No media roles");
652         return;
653     }
654
655     if (media_info->route_type == STREAM_ROUTE_TYPE_AUTO) {
656         playback_device = get_media_auto_device(m, DM_DEVICE_DIRECTION_OUT);
657         capture_device = get_media_auto_device(m, DM_DEVICE_DIRECTION_IN);
658     } else if(media_info->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
659         playback_device = get_media_last_device(m, DM_DEVICE_DIRECTION_OUT);
660         capture_device = get_media_last_device(m, DM_DEVICE_DIRECTION_IN);
661     } else {
662         pa_log_error("unexpected routing type for media[%d]", media_info->route_type);
663         return;
664     }
665
666     if (playback_device)
667         activate_device_only(m, playback_device);
668     else
669         pa_log_info("There is no playback-device");
670
671     if (capture_device)
672         activate_device_only(m, capture_device);
673     else
674         pa_log_info("There is no capture-device");
675 }
676
677 static void set_initial_active_device(pa_stream_manager *m) {
678     pa_assert(m);
679
680     set_media_active_device(m);
681 }
682
683 static void dump_stream_map(pa_stream_manager *m) {
684     stream_info *s = NULL;
685     const char *role = NULL;
686     char *name = NULL;
687     void *state = NULL;
688     uint32_t idx = 0;
689     pa_assert(m);
690     pa_log_debug("==========[START stream-map dump]==========");
691     while (m->stream_infos && (s = pa_hashmap_iterate(m->stream_infos, &state, (const void **)&role))) {
692         pa_log_debug("[role : %s]", role);
693         pa_log_debug("  - priority   : %d", s->priority);
694         pa_log_debug("  - route-type : %d (0:auto,1:auto-last-conn,2:auto-all,3:manual,4:manual-ext)", s->route_type);
695         pa_log_debug("  - volume-types : in[%s], out[%s]", s->volume_types[STREAM_DIRECTION_IN], s->volume_types[STREAM_DIRECTION_OUT]);
696         pa_log_debug("  - avail-in-devices");
697         PA_IDXSET_FOREACH(name, s->idx_avail_in_devices, idx)
698             pa_log_debug("      name[%d]  : %s", idx, name);
699         pa_log_debug("  - avail-out-devices");
700         PA_IDXSET_FOREACH(name, s->idx_avail_out_devices, idx)
701             pa_log_debug("      name[%d]  : %s", idx, name);
702         pa_log_debug("  - avail-frameworks");
703         PA_IDXSET_FOREACH(name, s->idx_avail_frameworks, idx)
704             pa_log_debug("      name[%d]  : %s", idx, name);
705     }
706     pa_log_debug("===========[END stream-map dump]===========");
707 }
708
709 static void stream_info_free(stream_info *s) {
710     pa_assert(s);
711
712     if (s->idx_avail_in_devices)
713         pa_idxset_free(s->idx_avail_in_devices, NULL);
714     if (s->idx_avail_out_devices)
715         pa_idxset_free(s->idx_avail_out_devices, NULL);
716     if (s->idx_avail_frameworks)
717         pa_idxset_free(s->idx_avail_frameworks, NULL);
718
719     pa_xfree(s);
720 }
721
722 static void deinit_stream_map(pa_stream_manager *m) {
723     pa_assert(m);
724
725     if (m->stream_infos) {
726         pa_hashmap_free(m->stream_infos);
727         m->stream_infos = NULL;
728     }
729     if (m->volume_infos) {
730         pa_hashmap_free(m->volume_infos);
731         m->volume_infos = NULL;
732     }
733     if (m->latency_infos) {
734         pa_hashmap_free(m->latency_infos);
735         m->latency_infos = NULL;
736     }
737 }
738
739 static int get_latency_infos(json_object *o, pa_hashmap *latency_infos) {
740     json_object *array_o;
741     json_object *array_item_o;
742     json_object *item_o;
743     int array_length = 0;
744     const char *type = NULL;
745     latency_info *l = NULL;
746     int i;
747
748     pa_assert(latency_infos);
749     pa_assert(o);
750
751     if (json_object_object_get_ex(o, STREAM_MAP_LATENCIES, &array_o) && json_object_is_type(array_o, json_type_array)) {
752         array_length = json_object_array_length(array_o);
753         for (i = 0; i < array_length; i++) {
754             if ((array_item_o = json_object_array_get_idx(array_o, i)) && json_object_is_type(array_item_o, json_type_object)) {
755                 l = pa_xmalloc0(sizeof(latency_info));
756                 pa_log_debug("latency found [%d]", i);
757                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_TYPE, &item_o) || !json_object_is_type(item_o, json_type_string)) {
758                     pa_log_error("Get type failed");
759                     goto fail;
760                 }
761                 type = json_object_get_string(item_o);
762                 pa_log_debug(" - type : %s", type);
763
764                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_FRAGSIZE_MS, &item_o) || !json_object_is_type(item_o, json_type_int)) {
765                     pa_log_error("Get fragsize-ms failed");
766                     goto fail;
767                 }
768                 l->fragsize_ms = json_object_get_int(item_o);
769                 pa_log_debug(" - fragsize-ms : %d", l->fragsize_ms);
770
771                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_TLENGTH_MS, &item_o) || !json_object_is_type(item_o, json_type_int)) {
772                     pa_log_error("Get tlength-ms failed");
773                     goto fail;
774                 }
775                 l->tlength_ms = json_object_get_int(item_o);
776                 pa_log_debug(" - tlength-ms : %d", l->tlength_ms);
777
778                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_MINREQ_MS, &item_o) || !json_object_is_type(item_o, json_type_int)) {
779                     pa_log_error("Get minreq-ms failed");
780                     goto fail;
781                 }
782                 l->minreq_ms = json_object_get_int(item_o);
783                 pa_log_debug(" - minreq-ms : %d", l->minreq_ms);
784
785                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_PREBUF_MS, &item_o) || !json_object_is_type(item_o, json_type_int)) {
786                     pa_log_error("Get prebuf-ms failed");
787                     goto fail;
788                 }
789                 l->prebuf_ms = json_object_get_int(item_o);
790                 pa_log_debug(" - prebuf-ms : %d", l->prebuf_ms);
791
792                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_LATENCY_MAXLENGTH, &item_o) || !json_object_is_type(item_o, json_type_int)) {
793                     pa_log_error("Get maxlength failed");
794                     goto fail;
795                 }
796                 l->maxlength = json_object_get_int(item_o);
797                 pa_log_debug(" - maxlength : %d", l->maxlength);
798
799                 pa_hashmap_put(latency_infos, (void*)type, l);
800                 l = NULL;
801             }
802         }
803     }
804     return 0;
805
806 fail:
807     pa_xfree(l);
808     return -1;
809 }
810
811 static int get_volume_infos(json_object *o, pa_hashmap *volume_infos) {
812     json_object *array_o;
813     json_object *array_item_o;
814     json_object *item_o;
815     int array_length = 0;
816     const char *type = NULL;
817     volume_info *v = NULL;
818     int i;
819
820     pa_assert(volume_infos);
821     pa_assert(o);
822
823     if (json_object_object_get_ex(o, STREAM_MAP_VOLUMES, &array_o) && json_object_is_type(array_o, json_type_array)) {
824         array_length = json_object_array_length(array_o);
825         for (i = 0; i < array_length; i++) {
826             if ((array_item_o = json_object_array_get_idx(array_o, i)) && json_object_is_type(array_item_o, json_type_object)) {
827                 v = pa_xmalloc0(sizeof(volume_info));
828                 pa_log_debug("volume found [%d]", i);
829                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_VOLUME_TYPE, &item_o) || !json_object_is_type(item_o, json_type_string)) {
830                     pa_log_error("Get volume type failed");
831                     goto fail;
832                 }
833                 type = json_object_get_string(item_o);
834                 pa_log_debug(" - type : %s", type);
835
836                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_VOLUME_IS_FOR_HAL, &item_o) || !json_object_is_type(item_o, json_type_int)) {
837                     pa_log_error("Get is-hal-volume failed");
838                     goto fail;
839                 }
840                 v->is_hal_volume_type = (bool)json_object_get_int(item_o);
841                 pa_log_debug(" - is-hal-volume : %d", v->is_hal_volume_type);
842
843                 pa_hashmap_put(volume_infos, (void*)type, v);
844                 v = NULL;
845             }
846         }
847     }
848     return 0;
849
850 fail:
851     pa_xfree(v);
852     return -1;
853 }
854
855 static int get_stream_infos(json_object *o, pa_hashmap *stream_infos) {
856     json_object *array_o;
857     json_object *array_item_o;
858     json_object *item_o;
859     json_object *sub_array_o;
860     int array_length = 0;
861     int sub_array_length = 0;
862     const char *role = NULL;
863     stream_info *s = NULL;
864     json_object *out_device_o;
865     json_object *in_device_o;
866     json_object *framework_o;
867     int i, j;
868
869     pa_assert(stream_infos);
870     pa_assert(o);
871
872     if (json_object_object_get_ex(o, STREAM_MAP_STREAMS, &array_o) && json_object_is_type(array_o, json_type_array)) {
873         array_length = json_object_array_length(array_o);
874         for (i = 0; i < array_length; i++) {
875             if ((array_item_o = json_object_array_get_idx(array_o, i)) && json_object_is_type(array_item_o, json_type_object)) {
876                 s = pa_xmalloc0(sizeof(stream_info));
877                 pa_log_debug("stream found [%d]", i);
878                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_ROLE, &item_o) || !json_object_is_type(item_o, json_type_string)) {
879                     pa_log_error("Get stream role failed");
880                     goto fail;
881                 }
882                 role = json_object_get_string(item_o);
883                 pa_log_debug(" - role : %s", role);
884
885                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_PRIORITY, &item_o) || !json_object_is_type(item_o, json_type_int)) {
886                     pa_log_error("Get stream priority failed");
887                     goto fail;
888                 }
889                 s->priority = json_object_get_int(item_o);
890                 pa_log_debug(" - priority : %d", s->priority);
891
892                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_ROUTE_TYPE, &item_o) || !json_object_is_type(item_o, json_type_string)) {
893                     pa_log_error("Get stream route-type failed");
894                     goto fail;
895                 }
896                 if (convert_route_type(json_object_get_string(item_o), &(s->route_type))) {
897                     pa_log_error("convert stream route-type failed");
898                     goto fail;
899                 }
900                 pa_log_debug(" - route-type : %d", s->route_type);
901
902                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_VOLUME_TYPES, &sub_array_o) || !json_object_is_type(sub_array_o, json_type_object)) {
903                     pa_log_error("Get stream volume-types failed");
904                     goto fail;
905                 }
906                 if (!json_object_object_get_ex(sub_array_o, STREAM_MAP_STREAM_VOLUME_TYPE_IN, &item_o) || !json_object_is_type(item_o, json_type_string)) {
907                     pa_log_error("Get stream volume-type-in failed");
908                     goto fail;
909                 }
910                 s->volume_types[STREAM_DIRECTION_IN] = json_object_get_string(item_o);
911
912                 if (!json_object_object_get_ex(sub_array_o, STREAM_MAP_STREAM_VOLUME_TYPE_OUT, &item_o) || !json_object_is_type(item_o, json_type_string)) {
913                     pa_log_error("Get stream volume-type-out failed");
914                     goto fail;
915                 }
916                 s->volume_types[STREAM_DIRECTION_OUT] = json_object_get_string(item_o);
917
918                 pa_log_debug(" - volume-types : in[%s], out[%s]", s->volume_types[STREAM_DIRECTION_IN], s->volume_types[STREAM_DIRECTION_OUT]);
919
920                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_AVAIL_IN_DEVICES, &sub_array_o) || !json_object_is_type(sub_array_o, json_type_array)) {
921                     pa_log_error("Get stream avail-in-devices failed");
922                     goto fail;
923                 }
924                 s->idx_avail_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
925                 sub_array_length = json_object_array_length(sub_array_o);
926                 pa_log_debug(" - avail-in-devices");
927                 for (j = 0; j < sub_array_length; j++) {
928                     if ((in_device_o = json_object_array_get_idx(sub_array_o, j)) && json_object_is_type(in_device_o, json_type_string)) {
929                         pa_idxset_put(s->idx_avail_in_devices, (void*)json_object_get_string(in_device_o), NULL);
930                         pa_log_debug("      device[%d] : %s", j, json_object_get_string(in_device_o));
931                     }
932                 }
933
934                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_AVAIL_OUT_DEVICES, &sub_array_o) || !json_object_is_type(sub_array_o, json_type_array)) {
935                     pa_log_error("Get stream avail-out-devices failed");
936                     goto fail;
937                 }
938                 s->idx_avail_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
939                 sub_array_length = json_object_array_length(sub_array_o);
940                 pa_log_debug(" - avail-out-devices");
941                 for (j = 0; j < sub_array_length; j++) {
942                     if ((out_device_o = json_object_array_get_idx(sub_array_o, j)) && json_object_is_type(out_device_o, json_type_string)) {
943                         pa_idxset_put(s->idx_avail_out_devices, (void*)json_object_get_string(out_device_o), NULL);
944                         pa_log_debug("      device[%d] : %s", j, json_object_get_string(out_device_o));
945                     }
946                 }
947
948                 if (!json_object_object_get_ex(array_item_o, STREAM_MAP_STREAM_AVAIL_FRAMEWORKS, &sub_array_o) || !json_object_is_type(sub_array_o, json_type_array)) {
949                     pa_log_error("Get stream avail-frameworks failed");
950                     goto fail;
951                 }
952                 s->idx_avail_frameworks = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
953                 sub_array_length = json_object_array_length(sub_array_o);
954                 pa_log_debug(" - avail-frameworks");
955                 for (j = 0; j < sub_array_length; j++) {
956                     if ((framework_o = json_object_array_get_idx(sub_array_o, j)) && json_object_is_type(framework_o, json_type_string)) {
957                         pa_idxset_put(s->idx_avail_frameworks, (void*)json_object_get_string(framework_o), NULL);
958                         pa_log_debug("      framework[%d] : %s", j, json_object_get_string(framework_o));
959                     }
960                 }
961
962                 pa_hashmap_put(stream_infos, (void*)role, s);
963                 s = NULL;
964             }
965         }
966     }
967     return 0;
968
969 fail:
970     pa_xfree(s);
971     return -1;
972 }
973
974 static int init_stream_map(pa_stream_manager *m) {
975     json_object *o;
976
977     pa_assert(m);
978
979     o = json_object_from_file(STREAM_MAP_FILE);
980     if (o == NULL) {
981         pa_log_error("Read stream-map file(%s) failed", STREAM_MAP_FILE);
982         return -1;
983     }
984
985     /* Latencies */
986     m->latency_infos = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
987     if (get_latency_infos(o, m->latency_infos))
988         goto fail;
989
990     /* Volumes */
991     m->volume_infos = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, pa_xfree);
992     if (get_volume_infos(o, m->volume_infos))
993         goto fail;
994
995     /* Streams */
996     m->stream_infos = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t)stream_info_free);
997     if (get_stream_infos(o, m->stream_infos))
998         goto fail;
999
1000     dump_stream_map(m);
1001
1002     return 0;
1003
1004 fail:
1005     pa_log_error("failed to initialize stream-map");
1006     deinit_stream_map(m);
1007
1008     return -1;
1009 }
1010
1011 static bool check_name_to_skip(pa_stream_manager *m, process_command_type_t command, void *stream, stream_type_t type, bool is_new_data) {
1012     bool ret = false;
1013     const char *name = NULL;
1014     const char *role = NULL;
1015     int i = 0;
1016
1017     pa_assert(m);
1018     pa_assert(stream);
1019
1020     if (command == PROCESS_COMMAND_PREPARE && is_new_data) {
1021         if ((name = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_NAME))) {
1022             for (i = 0; i < NAME_FOR_SKIP_MAX; i++)
1023                 if (pa_safe_streq(name, stream_manager_media_names_for_skip[i])) {
1024                     ret = true;
1025                     pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE, SKIP_ROLE);
1026                     break;
1027                 }
1028             pa_log_info("name is [%s], skip(%d) command(%s)", name, ret, process_command_type_str[command]);
1029         }
1030     } else {
1031         if (is_new_data)
1032             role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1033         else
1034             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
1035
1036         if (pa_safe_streq(role, SKIP_ROLE))
1037             ret = true;
1038     }
1039
1040     return ret;
1041 }
1042
1043 static bool is_invalid_role(pa_stream_manager *m, const char *role) {
1044     stream_info *s = NULL;
1045
1046     pa_assert(m);
1047     pa_assert(m->stream_infos);
1048     pa_assert(role);
1049
1050     if (!(s = pa_hashmap_get(m->stream_infos, role))) {
1051         pa_log_warn("invalid role[%s], skip it", role);
1052         return true;
1053     }
1054
1055     return false;
1056 }
1057
1058 static bool is_invalid_route_type(const char *route_type_str, stream_route_type_t *route_type) {
1059     int32_t _route_type;
1060
1061     pa_assert(route_type_str);
1062
1063     if (pa_atoi(route_type_str, &_route_type)) {
1064         pa_log_error("could not convert route_type_str(%s) to int", route_type_str);
1065         return true;
1066     }
1067
1068     if (route_type)
1069         *route_type = (stream_route_type_t)_route_type;
1070
1071     return false;
1072 }
1073
1074 static bool check_name_is_vstream(void *stream, stream_type_t type, bool is_new_data) {
1075     bool ret = false;
1076     const char *name = NULL;
1077
1078     pa_assert(stream);
1079
1080     if (is_new_data)
1081         name = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_NAME);
1082     else
1083         name = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_NAME);
1084
1085     if (pa_safe_streq(name, VIRTUAL_STREAM_NAME)) {
1086         ret = true;
1087         pa_log_debug("name is [%s]", name);
1088     }
1089
1090     return ret;
1091 }
1092
1093 static bool update_priority_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role, bool is_new_data) {
1094     bool ret = false;
1095     stream_info *s = NULL;
1096
1097     pa_assert(m);
1098     pa_assert(stream);
1099     pa_assert(m->stream_infos);
1100     pa_assert(role);
1101
1102     if ((s = pa_hashmap_get(m->stream_infos, role))) {
1103         if (is_new_data)
1104             pa_proplist_set(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void*)&(s->priority), sizeof(s->priority));
1105         else
1106             pa_proplist_set(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void*)&(s->priority), sizeof(s->priority));
1107         ret = true;
1108     }
1109
1110     return ret;
1111 }
1112
1113 static bool update_route_type_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role) {
1114     bool ret = false;
1115     stream_route_type_t route_type = STREAM_ROUTE_TYPE_AUTO;
1116     stream_info *s = NULL;
1117
1118     pa_assert(m);
1119     pa_assert(stream);
1120     pa_assert(m->stream_infos);
1121     pa_assert(role);
1122
1123     if ((s = pa_hashmap_get(m->stream_infos, role))) {
1124         route_type = s->route_type;
1125         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE, "%d", route_type);
1126         ret = true;
1127     }
1128
1129     return ret;
1130 }
1131
1132 static bool update_volume_type_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role) {
1133     bool ret = false;
1134     const char *volume_type = NULL;
1135     stream_info *s = NULL;
1136
1137     pa_assert(m);
1138     pa_assert(stream);
1139     pa_assert(m->stream_infos);
1140     pa_assert(role);
1141
1142     if ((s = pa_hashmap_get(m->stream_infos, role)))
1143         volume_type = s->volume_types[type];
1144
1145     if (volume_type && (!pa_safe_streq(volume_type, "none"))) {
1146         pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type);
1147         ret = true;
1148     } else
1149         pa_log_warn("this stream[%p] does not have any volume type, skip updating volume type. stream_type[%d], role[%s]", stream, type, role);
1150
1151     return ret;
1152 }
1153
1154 static void _set_focus_status_forcedly_if_needed(pa_stream_manager *m, void *stream, stream_type_t type, bool is_new_data)
1155 {
1156     const char *role = NULL;
1157     pa_proplist* p = NULL;
1158
1159     pa_assert(m);
1160     pa_assert(stream);
1161
1162     p = (is_new_data ? GET_STREAM_NEW_PROPLIST(stream, type) : GET_STREAM_PROPLIST(stream, type));
1163     if (!p)
1164         return;
1165
1166     if ((role = pa_proplist_gets(p, PA_PROP_MEDIA_ROLE))) {
1167         if (!pa_hashmap_get(m->stream_infos, role)) {
1168             pa_log_warn("undefined role[%s], skip it", role);
1169             return;
1170         }
1171         if (pa_safe_streq(role, STREAM_ROLE_SOLO)) {
1172             /* skip updating focus status for solo stream during the most important stream type is occupied. */
1173             if (m->cur_highest_priority.sink_input) {
1174                 const char *highest_role;
1175                 pa_proplist *prop = GET_STREAM_PROPLIST(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT);
1176                 if ((highest_role = pa_proplist_gets(prop, PA_PROP_MEDIA_ROLE))) {
1177                     if (IS_ROLE_COMMUNICATION(highest_role)) {
1178                         pa_log_warn("current highest priority role is [%s], skip updating focus for [%s] stream", highest_role, role);
1179                         return;
1180                     }
1181                 }
1182             }
1183             pa_log_info("This stream is [%s], update focus status to STREAM_FOCUS_STATE_ACQUIRED", role);
1184             pa_proplist_setf(p, PA_PROP_MEDIA_FOCUS_STATUS, "%s", STREAM_FOCUS_STATE_ACQUIRED);
1185         }
1186         /* FIXME : this code is workaround code and needed to be revised soon */
1187         else if (pa_safe_streq(role, STREAM_ROLE_RADIO)) {
1188             pa_log_info("This stream is [%s], update focus status to STREAM_FOCUS_STATE_ACQUIRED", role);
1189             pa_proplist_setf(p, PA_PROP_MEDIA_FOCUS_STATUS, "%s", STREAM_FOCUS_STATE_ACQUIRED);
1190         }
1191     }
1192 }
1193
1194 static bool update_focus_status_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, bool is_new_data) {
1195     const char *p_idx;
1196     uint32_t parent_idx = 0;
1197     stream_parent *sp = NULL;
1198
1199     pa_assert(m);
1200     pa_assert(stream);
1201
1202     if (is_new_data)
1203         p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1204     else
1205         p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1206     if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1207         if (!(sp = pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(parent_idx)))) {
1208             pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
1209             return false;
1210         }
1211         if (is_new_data)
1212             pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_FOCUS_STATUS, "%u", sp->focus_status);
1213         else
1214             pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_FOCUS_STATUS, "%u", sp->focus_status);
1215
1216         pa_log_debug("p_idx(%s), idx(%u), focus_status(0x%x, 0x1:playback 0x2:capture 0x3:both)", p_idx, parent_idx, sp->focus_status);
1217     }
1218
1219     /* set focus status regardless of parent id existence */
1220     _set_focus_status_forcedly_if_needed(m, stream, type, is_new_data);
1221
1222     return true;
1223 }
1224
1225 static void update_preferred_device_role(pa_stream_manager *m, void *stream, stream_type_t type) {
1226     const char *p_idx_str;
1227     uint32_t parent_idx = 0;
1228     stream_parent *sp = NULL;
1229
1230     pa_assert(m);
1231     pa_assert(stream);
1232
1233     p_idx_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1234     if (!p_idx_str || pa_atou(p_idx_str, &parent_idx))
1235         return;
1236
1237     if (!(sp = pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(parent_idx)))) {
1238         pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
1239         return;
1240     }
1241
1242     if (sp->preferred_device.roles[type])
1243         pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type),
1244                         PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE,
1245                         sp->preferred_device.roles[type]);
1246 }
1247
1248 static void get_preferred_device_type_and_role(pa_stream_manager *m, void *stream, stream_type_t stream_type, const char **type, const char **role) {
1249     const char *p_idx_str;
1250     uint32_t parent_idx = 100;
1251     stream_parent *sp = NULL;
1252
1253     pa_assert(m);
1254     pa_assert(stream);
1255     pa_assert(type);
1256     pa_assert(role);
1257
1258     p_idx_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, stream_type), PA_PROP_MEDIA_PARENT_ID);
1259     if (!p_idx_str || pa_atou(p_idx_str, &parent_idx)) {
1260         return;
1261     }
1262     if (!(sp = pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(parent_idx)))) {
1263         pa_log_warn("could not find matching client for this parent_id(%u)", parent_idx);
1264         return;
1265     }
1266
1267     *type = sp->preferred_device.types[stream_type];
1268     *role = sp->preferred_device.roles[stream_type];
1269
1270     pa_log_debug("%s(%u), parent_id(%u), preferred type(%s), role(%s)",
1271             stream_type == STREAM_SINK_INPUT ? "sink-input" : "source-output",
1272             stream_type == STREAM_SINK_INPUT ? PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index,
1273             parent_idx, *type, *role);
1274 }
1275
1276 static bool update_stream_parent_info(pa_stream_manager *m, process_command_type_t command, stream_type_t type, void *stream) {
1277     const char *p_idx;
1278     uint32_t parent_idx;
1279     stream_parent *sp = NULL;
1280
1281     pa_assert(m);
1282     pa_assert(stream);
1283
1284     p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1285     if (p_idx && !pa_atou(p_idx, &parent_idx)) {
1286         pa_log_debug("p_idx(%s), idx(%u)", p_idx, parent_idx);
1287         sp = pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(parent_idx));
1288         if (sp) {
1289             uint32_t idx = GET_STREAM_INDEX(stream, type);
1290             if (command == PROCESS_COMMAND_ADD_STREAM) {
1291                 /* append this stream to the parent stream info. */
1292                 pa_log_debug(" - append this stream(%p, %u) to the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1293                 pa_idxset_put(type == STREAM_SINK_INPUT ? (sp->idx_sink_inputs) : (sp->idx_source_outputs), stream, NULL);
1294                 return true;
1295             } else if (command == PROCESS_COMMAND_REMOVE_STREAM) {
1296                 /* remove this stream from the parent stream info. */
1297                 pa_log_debug(" - remove this stream(%p, %u) from the list. sp(%p), stream_type(%d)", stream, idx, sp, type);
1298                 pa_idxset_remove_by_data(type == STREAM_SINK_INPUT ? (sp->idx_sink_inputs) : (sp->idx_source_outputs), stream, NULL);
1299                 return true;
1300             } else {
1301                 pa_log_error("invalid process command(%d)", command);
1302                 return false;
1303             }
1304         } else {
1305             pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
1306             return false;
1307         }
1308     } else
1309         return false;
1310
1311     return true;
1312 }
1313
1314 static bool update_the_highest_priority_stream(pa_stream_manager *m, process_command_type_t command, void *mine,
1315                                                stream_type_t type, const char *role, bool is_new_data, bool *need_to_update) {
1316     uint32_t idx = 0;
1317     size_t size = 0;
1318     const int32_t *priority = NULL;
1319     const char *route_type_str = NULL;
1320     stream_route_type_t route_type;
1321     const char *focus_status_str = NULL;
1322     const char *active_dev = NULL;
1323     void *cur_max_stream = NULL;
1324     void *cur_max_stream_tmp = NULL;
1325     const int32_t *cur_max_priority = NULL;
1326     const char *cur_max_role = NULL;
1327     int32_t cur_max_focus_status = 0;
1328     int32_t focus_status = 0;
1329     void *i = NULL;
1330     const char *_role = NULL;
1331     pa_idxset *streams = NULL;
1332     pa_sink *sink = NULL;
1333     pa_source *source = NULL;
1334     bool is_vstream = false;
1335
1336     pa_assert(m);
1337     pa_assert(mine);
1338     if (!role) {
1339         pa_log_error("invalid input, role(%s)", pa_strnull(role));
1340         return false;
1341     }
1342
1343     *need_to_update = false;
1344
1345     if (type == STREAM_SINK_INPUT) {
1346         cur_max_stream = m->cur_highest_priority.sink_input;
1347     } else if (type == STREAM_SOURCE_OUTPUT) {
1348         cur_max_stream = m->cur_highest_priority.source_output;
1349     }
1350
1351     pa_log_debug("stream_type(%d), role(%s), command(%d), is_new_data(%d)", type, role, command, is_new_data);
1352     if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
1353         /* get focus status, route type */
1354         if (is_new_data) {
1355             focus_status_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_FOCUS_STATUS);
1356             route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
1357         } else {
1358             focus_status_str = pa_proplist_gets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_FOCUS_STATUS);
1359             route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
1360         }
1361         if (focus_status_str && !pa_atoi(focus_status_str, &focus_status)) {
1362             pa_log_debug("focus status(0x%x) of mine", focus_status);
1363         }
1364         /* check if this stream is for external device with ROUTE_TYPE_AUTO */
1365         if (IS_ROUTE_TYPE_FOR_AUTO(route_type_str, route_type) && is_new_data) {
1366             if (type == STREAM_SINK_INPUT)
1367                 sink = ((pa_sink_input_new_data*)mine)->sink;
1368             else
1369                 source = ((pa_source_output_new_data*)mine)->source;
1370             is_vstream = check_name_is_vstream(mine, type, is_new_data);
1371             if (!is_vstream && ((sink && !(sink->use_internal_codec)) || (source && !(source->use_internal_codec)))) {
1372                 pa_log_warn("stream(%p) uses external device, skip it", mine);
1373                 *need_to_update = false;
1374                 return true;
1375             }
1376         }
1377         if (cur_max_stream == NULL) {
1378             *need_to_update = true;
1379             pa_log_debug("set cur_highest to mine");
1380         } else {
1381             if (is_new_data) {
1382                 if (pa_proplist_get(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&priority, &size))
1383                     pa_log_error("failed to pa_proplist_get() for priority");
1384             } else {
1385                 if (pa_proplist_get(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&priority, &size))
1386                     pa_log_error("failed to pa_proplist_get() for priority");
1387             }
1388             if (pa_proplist_get(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&cur_max_priority, &size))
1389                 pa_log_error("failed to pa_proplist_get() for priority");
1390             focus_status_str = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_FOCUS_STATUS);
1391             if (focus_status_str && !pa_atoi(focus_status_str, &cur_max_focus_status)) {
1392                 pa_log_debug("cur_max_focus status(0x%x)", cur_max_focus_status);
1393             }
1394             cur_max_role = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROLE);
1395             if (!cur_max_priority || !cur_max_role) {
1396                 pa_log_error("failed to pa_proplist_gets() for getting current max priority(%p) and it's role(%s)", cur_max_priority, cur_max_role);
1397                 return false;
1398             } else {
1399                 if (priority && cur_max_priority) {
1400                     if (GET_FOCUS_STATUS(focus_status, type) ||
1401                         (!GET_FOCUS_STATUS(cur_max_focus_status, type) && *priority >= *cur_max_priority)) {
1402                         *need_to_update = true;
1403                         pa_log_debug("update cur_highest to mine(%s)", role);
1404                     } else {
1405                         /* no need to trigger,
1406                          * update active device info if possible */
1407                         if (IS_ROUTE_TYPE_FOR_AUTO(route_type_str, route_type) || IS_ROUTE_TYPE_FOR_AUTO_LAST_CONN(route_type_str, route_type)) {
1408                             if ((active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
1409                                 if (is_new_data)
1410                                     pa_proplist_sets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_dev);
1411                                 else
1412                                     pa_proplist_sets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_dev);
1413                             }
1414                         }
1415                         return true;
1416                     }
1417                 }
1418             }
1419         }
1420     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED ||
1421             command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED) {
1422         if (cur_max_stream == mine || command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED) {
1423             if (type == STREAM_SINK_INPUT) {
1424                 streams = m->core->sink_inputs;
1425             } else if (type == STREAM_SOURCE_OUTPUT) {
1426                 streams = m->core->source_outputs;
1427             }
1428             /* find the next highest priority input */
1429             PA_IDXSET_FOREACH(i, streams, idx) {
1430                 if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED && i == mine)
1431                     continue;
1432                 if (!CHECK_STREAM_RUNNING(i, type) || CHECK_STREAM_UNLINKED(i, type))
1433                     continue;
1434                 if (!(_role = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE))) {
1435                     pa_log_error("failed to pa_proplist_gets() for role");
1436                     continue;
1437                 }
1438                 if (pa_proplist_get(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&priority, &size)) {
1439                     pa_log_warn("failed to pa_proplist_get() for priority, skip it");
1440                     continue;
1441                 }
1442                 if (!(route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
1443                     pa_log_warn("failed to pa_proplist_get() for route_type, skip it");
1444                     continue;
1445                 } else if (IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
1446                     pa_log_warn("stream(%p) has the route type for external device, skip it", i);
1447                     continue;
1448                 } else {
1449                     is_vstream = check_name_is_vstream(i, type, false);
1450                     if (!is_vstream &&
1451                        (type == STREAM_SINK_INPUT ? !(((pa_sink_input*)i)->sink->use_internal_codec) :
1452                                                     !(((pa_source_output*)i)->source->use_internal_codec))) {
1453                         pa_log_warn("stream(%p) uses external audio codec, skip it", i);
1454                         continue;
1455                     }
1456                 }
1457                 if (!(focus_status_str = pa_proplist_gets(GET_STREAM_PROPLIST(i, type), PA_PROP_MEDIA_FOCUS_STATUS))) {
1458                     pa_log_warn("failed to pa_proplist_gets() for focus status");
1459                 } else {
1460                     if (!pa_atoi(focus_status_str, &focus_status))
1461                         pa_log_debug("focus status(0x%x)", focus_status);
1462                 }
1463                 pa_log_debug("role(%s)/priority(%p)/route_type(%d)/focus_status(0x%x)/stream(%p)", _role, priority, route_type, focus_status, i);
1464                 if (cur_max_priority == NULL) {
1465                     cur_max_priority = priority;
1466                     cur_max_focus_status = focus_status;
1467                     cur_max_stream_tmp = i;
1468                     cur_max_role = _role;
1469                 }
1470                 if (cur_max_priority && priority) {
1471                     if (GET_FOCUS_STATUS(cur_max_focus_status, type) ||
1472                         (!GET_FOCUS_STATUS(focus_status, type) && (*cur_max_priority > *priority))) {
1473                         /* skip */
1474                     } else  {
1475                         cur_max_priority = priority;
1476                         cur_max_focus_status = focus_status;
1477                         cur_max_stream_tmp = i;
1478                         cur_max_role = _role;
1479                     }
1480                 }
1481             }
1482             pa_log_debug("updated max priority(%p)/stream(%p)", cur_max_priority, cur_max_stream_tmp);
1483             if (cur_max_stream_tmp) {
1484                 if (type == STREAM_SINK_INPUT) {
1485                     m->cur_highest_priority.sink_input = cur_max_stream_tmp;
1486                     m->cur_highest_priority.role_si = cur_max_role;
1487                 } else if (type == STREAM_SOURCE_OUTPUT) {
1488                     m->cur_highest_priority.source_output = cur_max_stream_tmp;
1489                     m->cur_highest_priority.role_so = cur_max_role;
1490                 }
1491             } else {
1492                 if (type == STREAM_SINK_INPUT) {
1493                     m->cur_highest_priority.sink_input = NULL;
1494                     m->cur_highest_priority.role_si = NULL;
1495                 } else if (type == STREAM_SOURCE_OUTPUT) {
1496                     m->cur_highest_priority.source_output = NULL;
1497                     m->cur_highest_priority.role_so = NULL;
1498                 }
1499             }
1500             *need_to_update = true;
1501             pa_log_info("need to update: type(%d), cur_highest_priority(sink_input=%p[%s]/source_output=%p[%s])",
1502                         type, (void*)m->cur_highest_priority.sink_input, m->cur_highest_priority.role_si,
1503                         (void*)m->cur_highest_priority.source_output, m->cur_highest_priority.role_so);
1504         } else {
1505             /* no need to trigger */
1506             pa_log_info("no need to update: type(%d), cur_highest_priority(sink_input=%p[%s]/source_output=%p[%s])",
1507                         type, (void*)m->cur_highest_priority.sink_input, m->cur_highest_priority.role_si,
1508                         (void*)m->cur_highest_priority.source_output, m->cur_highest_priority.role_so);
1509             return true;
1510         }
1511     }
1512     return true;
1513 }
1514
1515 /* Update buffer attributes to new stream */
1516 static void update_buffer_attribute(pa_stream_manager *m, void *new_data, stream_type_t stream_type, bool is_new_data) {
1517     pa_sample_spec *sample_spec;
1518     const char *latency;
1519     latency_info *li;
1520     int32_t maxlength = -1;
1521     /* playback only */
1522     int32_t tlength = -1;
1523     int32_t minreq = -1;
1524     /* Note: pulseaudio recommends to set it to -1, but there's an issue related
1525      * to a stream from gstreamer pulsesink which set this value to 0, so we set
1526      * default value to 0 temporarily. */
1527     int32_t prebuf = 0;
1528     int32_t tlength_ms = -1;
1529     int32_t minreq_ms = -1;
1530     int32_t prebuf_ms = -1;
1531     /* recording  only */
1532     int32_t fragsize = -1;
1533     int32_t fragsize_ms = -1;
1534
1535     pa_assert(m);
1536     pa_assert(new_data);
1537
1538     if (!is_new_data) {
1539         pa_log_warn("updating buffer attribute is only for new data, skip it");
1540         return;
1541     }
1542
1543     if ((latency = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_MEDIA_TIZEN_AUDIO_LATENCY)))
1544         pa_log_info("audio_latency : %s", latency);
1545     else {
1546         pa_log_warn("failed to get audio_latency");
1547         return;
1548     }
1549
1550     if (!(li = pa_hashmap_get(m->latency_infos, latency))) {
1551         pa_log_warn("not support this latency type[%s]", latency);
1552         return;
1553     }
1554
1555     maxlength = li->maxlength;
1556     pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_MAXLENGTH, "%d", maxlength);
1557
1558     sample_spec = GET_STREAM_NEW_SAMPLE_SPEC_PTR(new_data, stream_type);
1559     pa_log_info("*** sample_spec: format(%d), rate(%u), channels(%u)",
1560                  sample_spec->format, sample_spec->rate, sample_spec->channels);
1561
1562     if (stream_type ==  STREAM_SINK_INPUT) {
1563         tlength_ms = li->tlength_ms;
1564         minreq_ms = li->minreq_ms;
1565         prebuf_ms = li->prebuf_ms;
1566
1567         if (minreq_ms > 0)
1568             minreq = pa_usec_to_bytes(minreq_ms * 1000, sample_spec);
1569         if (tlength_ms > 0)
1570             tlength = pa_usec_to_bytes(tlength_ms * 1000, sample_spec);
1571         if (prebuf_ms >= 0)
1572             prebuf = pa_usec_to_bytes(prebuf_ms * 1000, sample_spec);
1573         else
1574             prebuf = -1;
1575
1576         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_TLENGTH, "%d", tlength);
1577         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_MINREQ, "%d", minreq);
1578         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_PREBUF, "%d", prebuf);
1579
1580         pa_log_info("*** maxlength:%d, tlength:%d, prebuf:%d, minreq:%d", maxlength, tlength, prebuf, minreq);
1581
1582     } else if (stream_type == STREAM_SOURCE_OUTPUT) {
1583         fragsize_ms = li->fragsize_ms;
1584
1585         if (fragsize_ms > 0)
1586             fragsize = pa_usec_to_bytes(fragsize_ms * 1000, sample_spec);
1587
1588         pa_proplist_setf(GET_STREAM_NEW_PROPLIST(new_data, stream_type), PA_PROP_BUFFER_ATTR_FRAGSIZE, "%d", fragsize);
1589
1590         pa_log_info("*** maxlength:%d, fragsize:%d", maxlength, fragsize);
1591     }
1592 }
1593
1594 static int exclude_device_filter_func(const void *device_type, const void *exclude_device_type) {
1595     pa_assert(device_type);
1596     pa_assert(exclude_device_type);
1597
1598     if (pa_safe_streq((const char*)device_type, (const char*)exclude_device_type)) {
1599         pa_log_info("[%s] is excluded", (const char*)device_type);
1600         return 0;
1601     }
1602
1603     return 1;
1604 }
1605
1606 static pa_idxset* get_avail_devices_except_bt_a2dp(pa_idxset *avail_devices) {
1607     pa_idxset *filtered_devices;
1608
1609     pa_assert(avail_devices);
1610
1611     filtered_devices = pa_idxset_filtered_copy(avail_devices, NULL, exclude_device_filter_func, DEVICE_TYPE_BT_A2DP);
1612
1613     return filtered_devices;
1614 }
1615
1616 static void fill_device_info_to_hook_data(pa_stream_manager *m, void *hook_data, notify_command_type_t command, stream_type_t type, void *stream, bool is_new_data) {
1617     char *device_none = NULL;
1618     const char *p_idx = NULL;
1619     uint32_t parent_idx = 0;
1620     stream_parent *sp = NULL;
1621     pa_stream_manager_hook_data_for_select *select_data = NULL;
1622     pa_stream_manager_hook_data_for_route *route_data = NULL;
1623     stream_info *si;
1624     pa_idxset *avail_devices;
1625     uint32_t list_len = 0;
1626
1627     pa_assert(m);
1628     pa_assert(hook_data);
1629
1630     if (!is_valid_notify_command(command)) {
1631         pa_log_error("invalid notify command: %d", command);
1632         return;
1633     }
1634     pa_log_info("command: %s", notify_command_type_str[command]);
1635
1636     switch (command) {
1637     case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT: {
1638         select_data = (pa_stream_manager_hook_data_for_select*)hook_data;
1639         if (!(si = pa_hashmap_get(m->stream_infos, select_data->stream_role))) {
1640             pa_log_error("  -- could not find (%s)", select_data->stream_role);
1641             break;
1642         }
1643         select_data->route_type = si->route_type;
1644         avail_devices = (type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices;
1645         list_len = pa_idxset_size(avail_devices);
1646         device_none = pa_idxset_get_by_data(avail_devices, "none", NULL);
1647         if (list_len == 0 || device_none) {
1648             pa_log_warn("  -- there is no available device, stream_type(%d)", type);
1649             break;
1650         }
1651         select_data->idx_avail_devices = avail_devices;
1652         select_data->origins_from_new_data = is_new_data;
1653
1654         if (si->route_type != STREAM_ROUTE_TYPE_MANUAL && si->route_type != STREAM_ROUTE_TYPE_MANUAL_EXT)
1655             break;
1656
1657         if (is_new_data)
1658             p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1659         else
1660             p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1661         if (!p_idx || pa_atou(p_idx, &parent_idx)) {
1662             pa_log_debug("  -- could not get the parent id of this stream, but keep going...");
1663             break;
1664         }
1665         /* find parent idx, it's device info. and it's stream idxs */
1666         if ((sp = pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(parent_idx)))) {
1667             select_data->idx_manual_devices = (type == STREAM_SINK_INPUT) ? (sp->idx_route_out_devices) : (sp->idx_route_in_devices);
1668             break;
1669         }
1670         pa_log_warn("  -- failed to get the stream parent of idx(%u)", parent_idx);
1671         break;
1672     }
1673     case NOTIFY_COMMAND_CHANGE_ROUTE_START:
1674     case NOTIFY_COMMAND_CHANGE_ROUTE_END: {
1675         route_data = (pa_stream_manager_hook_data_for_route*)hook_data;
1676         if (!(si = pa_hashmap_get(m->stream_infos, route_data->stream_role))) {
1677             pa_log_error("  -- could not find (%s)", route_data->stream_role);
1678             break;
1679         }
1680         avail_devices = (type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices;
1681         route_data->route_type = si->route_type;
1682         list_len = pa_idxset_size(avail_devices);
1683         device_none = pa_idxset_get_by_data(avail_devices, "none", NULL);
1684
1685         if (list_len == 0 || device_none) {
1686             pa_log_warn("  -- there is no available device, stream_type(%d)", type);
1687             break;
1688         }
1689
1690         route_data->idx_avail_devices = avail_devices;
1691
1692         if (si->route_type != STREAM_ROUTE_TYPE_MANUAL && si->route_type != STREAM_ROUTE_TYPE_MANUAL_EXT)
1693             break;
1694
1695         if (is_new_data)
1696             p_idx = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1697         else
1698             p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
1699         if (!p_idx || pa_atou(p_idx, &parent_idx)) {
1700             pa_log_warn("  -- could not get the parent id of this stream, but keep going...");
1701             break;
1702         }
1703         if (!(sp = pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(parent_idx)))) {
1704             pa_log_warn("  -- failed to get the stream parent of idx(%u)", parent_idx);
1705             break;
1706         }
1707         route_data->idx_manual_devices = (type == STREAM_SINK_INPUT) ? (sp->idx_route_out_devices) : (sp->idx_route_in_devices);
1708         route_data->idx_streams = (type == STREAM_SINK_INPUT) ? (sp->idx_sink_inputs) : (sp->idx_source_outputs);
1709         break;
1710     }
1711     default:
1712         break;
1713     }
1714 }
1715
1716 static ret_msg_t prepare_and_invoke_hook_to_select_device(pa_stream_manager *m, notify_command_type_t command, stream_type_t type,
1717                                                         bool is_new_data, void *user_data) {
1718     ret_msg_t ret = RET_MSG_OK;
1719     pa_stream_manager_hook_data_for_select hook_call_select_data;
1720     pa_idxset *filtered_avail_devices = NULL;
1721     void *s = NULL;
1722     const char *parent_id;
1723     uint32_t parent_id_u;
1724
1725     pa_assert(m);
1726     pa_assert(user_data);
1727
1728     if (command != NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT)
1729         return RET_MSG_ERROR_INVALID_ARGUMENT;
1730
1731     memset(&hook_call_select_data, 0, sizeof(pa_stream_manager_hook_data_for_select));
1732     hook_call_select_data.stream = s = user_data;
1733     hook_call_select_data.stream_type = type;
1734     hook_call_select_data.origins_from_new_data = is_new_data;
1735     if (is_new_data) {
1736         hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type),
1737                                                         PA_PROP_MEDIA_ROLE);
1738         hook_call_select_data.device_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type),
1739                                                         PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
1740         fill_device_info_to_hook_data(m, &hook_call_select_data, command, type, s, is_new_data);
1741         hook_call_select_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
1742         if (type == STREAM_SINK_INPUT) {
1743             hook_call_select_data.occupying_role = m->cur_highest_priority.role_si;
1744             if (IS_ROLE_COMMUNICATION(hook_call_select_data.occupying_role)) {
1745                 /* Currently, if bt-sco is used by communication stream, other streams can not go with bt-a2dp.
1746                     Here we exclude bt-a2dp device type, therefore this stream can be mixed together by using another device */
1747                 filtered_avail_devices = get_avail_devices_except_bt_a2dp(hook_call_select_data.idx_avail_devices);
1748                 hook_call_select_data.idx_avail_devices = filtered_avail_devices;
1749             }
1750             hook_call_select_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
1751         } else if (type == STREAM_SOURCE_OUTPUT) {
1752             hook_call_select_data.occupying_role = m->cur_highest_priority.role_so;
1753             hook_call_select_data.proper_source = &(((pa_source_output_new_data*)s)->source);
1754         }
1755     } else {
1756         hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type),
1757                                                         PA_PROP_MEDIA_ROLE);
1758         hook_call_select_data.device_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type),
1759                                                         PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
1760         fill_device_info_to_hook_data(m, &hook_call_select_data, command, type, s, is_new_data);
1761         hook_call_select_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
1762     }
1763     if (hook_call_select_data.route_type == STREAM_ROUTE_TYPE_MANUAL)
1764         CONVERT_TO_DEVICE_ROLE(hook_call_select_data.stream_role, hook_call_select_data.device_role);
1765
1766     parent_id = is_new_data ? pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID) :
1767                               pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID);
1768     if (parent_id && pa_atou(parent_id, &parent_id_u) == 0)
1769         hook_call_select_data.parent_id = parent_id_u;
1770     else
1771         hook_call_select_data.parent_id = -1;
1772
1773     if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_select_data)) {
1774         ret = RET_MSG_ERROR_INTERNAL;
1775     } else {
1776         if (!is_new_data) {
1777             if (type == STREAM_SINK_INPUT)
1778                 pa_sink_input_move_to(PA_SINK_INPUT(s), hook_call_select_data.new_sink, false);
1779             else
1780                 pa_source_output_move_to(PA_SOURCE_OUTPUT(s), hook_call_select_data.new_source, false);
1781         }
1782     }
1783
1784     pa_xfree(filtered_avail_devices);
1785
1786     return ret;
1787 }
1788
1789 static ret_msg_t prepare_and_invoke_hook_to_change_route(pa_stream_manager *m, notify_command_type_t command, stream_type_t type,
1790                                                         bool is_new_data, void *user_data) {
1791     ret_msg_t ret = RET_MSG_OK;
1792     pa_stream_manager_hook_data_for_route hook_call_route_data;
1793     void *s = NULL;
1794
1795     pa_assert(m);
1796
1797     if (command != NOTIFY_COMMAND_CHANGE_ROUTE_START &&
1798         command != NOTIFY_COMMAND_CHANGE_ROUTE_END)
1799         return RET_MSG_ERROR_INVALID_ARGUMENT;
1800
1801     if (command == NOTIFY_COMMAND_CHANGE_ROUTE_START) {
1802         pa_assert(user_data);
1803         memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
1804         hook_call_route_data.stream = s = user_data;
1805
1806         if (is_new_data) {
1807             hook_call_route_data.origins_from_new_data = true;
1808             hook_call_route_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1809             hook_call_route_data.device_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
1810             hook_call_route_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
1811             if (type == STREAM_SINK_INPUT) {
1812                 hook_call_route_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
1813             } else if (type == STREAM_SOURCE_OUTPUT) {
1814                 hook_call_route_data.proper_source = &(((pa_source_output_new_data*)s)->source);
1815             }
1816         } else {
1817             hook_call_route_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1818             hook_call_route_data.device_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
1819             hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
1820             hook_call_route_data.idx_streams = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)s)->sink->inputs :
1821                                                                                 ((pa_source_output*)s)->source->outputs;
1822         }
1823         hook_call_route_data.stream_type = type;
1824         if (hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL)
1825             CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
1826         fill_device_info_to_hook_data(m, &hook_call_route_data, command, type, s, is_new_data);
1827         if (hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL || hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
1828             if (hook_call_route_data.idx_manual_devices && !pa_idxset_size(hook_call_route_data.idx_manual_devices)) {
1829                 pa_log_warn("no manual device for this type(%d)", type);
1830                 hook_call_route_data.stream = NULL;
1831             }
1832         }
1833
1834     } else {
1835         memset(&hook_call_route_data, 0, sizeof(pa_stream_manager_hook_data_for_route));
1836         s = (type == STREAM_SINK_INPUT) ? (void*)(m->cur_highest_priority.sink_input) :
1837                                           (void*)(m->cur_highest_priority.source_output);
1838         if (s) {
1839             hook_call_route_data.stream = s;
1840             hook_call_route_data.stream_type = type;
1841             hook_call_route_data.stream_role = (type == STREAM_SINK_INPUT) ? (m->cur_highest_priority.role_si) :
1842                                                                              (m->cur_highest_priority.role_so);
1843             CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
1844             hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
1845             hook_call_route_data.idx_streams = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)s)->sink->inputs :
1846                                                                              ((pa_source_output*)s)->source->outputs;
1847             fill_device_info_to_hook_data(m, &hook_call_route_data, command, type, s, is_new_data);
1848         } else {
1849             pa_log_debug("no stream for this type(%d), need to unset route", type);
1850             hook_call_route_data.stream = NULL;
1851             hook_call_route_data.stream_type = type;
1852         }
1853     }
1854
1855     if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data))
1856         ret = RET_MSG_ERROR_INTERNAL;
1857
1858     return ret;
1859 }
1860
1861 static ret_msg_t prepare_and_invoke_hook_to_inform_stream_connection(pa_stream_manager *m, bool is_connected,
1862                                                         stream_type_t type, void *s) {
1863     pa_stream_manager_hook_data_for_stream hook_call_stream_data;
1864     const char *parent_id;
1865     uint32_t parent_id_u;
1866
1867     pa_assert(m);
1868     pa_assert(s);
1869
1870     memset(&hook_call_stream_data, 0, sizeof(pa_stream_manager_hook_data_for_stream));
1871     hook_call_stream_data.stream = s;
1872     hook_call_stream_data.stream_type = type;
1873     hook_call_stream_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1874     parent_id = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_PARENT_ID);
1875     if (parent_id && pa_atou(parent_id, &parent_id_u) == 0)
1876         hook_call_stream_data.parent_id = parent_id_u;
1877     else
1878         hook_call_stream_data.parent_id = -1;
1879     hook_call_stream_data.is_connected = is_connected;
1880
1881     if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_STREAM_CONNECTION_CHANGED), &hook_call_stream_data))
1882         return RET_MSG_ERROR_INTERNAL;
1883
1884     return RET_MSG_OK;
1885 }
1886
1887 ret_msg_t do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, bool is_new_data, void *user_data) {
1888     hal_stream_connection_info stream_conn_info;
1889     hal_route_option route_option;
1890     void *s = NULL;
1891     ret_msg_t ret = RET_MSG_OK;
1892
1893     pa_assert(m);
1894
1895     if (!is_valid_notify_command(command)) {
1896         pa_log_error("invalid notify command: %d", command);
1897         return RET_MSG_ERROR_INVALID_ARGUMENT;
1898     }
1899     pa_log_info("command: %s", notify_command_type_str[command]);
1900
1901     switch (command) {
1902     case NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT:
1903         ret = prepare_and_invoke_hook_to_select_device(m, command, type, is_new_data, user_data);
1904         break;
1905
1906     case NOTIFY_COMMAND_CHANGE_ROUTE_START:
1907     case NOTIFY_COMMAND_CHANGE_ROUTE_END:
1908         ret = prepare_and_invoke_hook_to_change_route(m, command, type, is_new_data, user_data);
1909         break;
1910
1911     case NOTIFY_COMMAND_UPDATE_ROUTE_OPTION: {
1912         pa_assert(user_data);
1913         memset(&route_option, 0, sizeof(hal_route_option));
1914         s = (type == STREAM_SINK_INPUT) ? (void*)(m->cur_highest_priority.sink_input) :
1915                                           (void*)(m->cur_highest_priority.source_output);
1916         /* route_option.role can be null if there's no occupied stream */
1917         if (s)
1918             route_option.role = (type == STREAM_SINK_INPUT) ? (m->cur_highest_priority.role_si) :
1919                                                               (m->cur_highest_priority.role_so);
1920         route_option.name = ((stream_route_option*)user_data)->name;
1921         route_option.value = ((stream_route_option*)user_data)->value;
1922         if (pa_hal_interface_update_route_option(m->hal, &route_option))
1923             ret = RET_MSG_ERROR_INTERNAL;
1924         break;
1925     }
1926
1927     case NOTIFY_COMMAND_INFORM_STREAM_CONNECTED:
1928     case NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED: {
1929         pa_assert(user_data);
1930         memset(&stream_conn_info, 0, sizeof(hal_stream_connection_info));
1931         s = user_data;
1932
1933         ret = prepare_and_invoke_hook_to_inform_stream_connection(m, command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, s);
1934         if (ret != RET_MSG_OK)
1935             pa_log_error("failed to prepare_and_invoke_hook_to_inform_stream_connection()");
1936         stream_conn_info.role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
1937         stream_conn_info.direction = (type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN;
1938         stream_conn_info.idx = GET_STREAM_INDEX(s, type);
1939         stream_conn_info.is_connected = (command == NOTIFY_COMMAND_INFORM_STREAM_CONNECTED);
1940         if (pa_hal_interface_notify_stream_connection_changed(m->hal, &stream_conn_info))
1941             ret = RET_MSG_ERROR_INTERNAL;
1942
1943         break;
1944     }
1945     }
1946
1947     return ret;
1948 }
1949
1950 #ifndef __TIZEN_TV_EXTERNAL_TV_SOURCE__
1951 static void update_mirroring_streams(pa_stream_manager *m, pa_source_output *o, bool put) {
1952     const char *role;
1953
1954     pa_assert(m);
1955     pa_assert(o);
1956
1957     if ((role = pa_proplist_gets(GET_STREAM_PROPLIST(o, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE)) &&
1958         pa_safe_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING)) {
1959         if (put)
1960             pa_idxset_put(m->mirroring_streams, o, NULL);
1961         else
1962             pa_idxset_remove_by_data(m->mirroring_streams, o, NULL);
1963     }
1964 }
1965
1966 /* Load/unload forwarding device */
1967 static int update_forwarding_device(pa_stream_manager *m, bool load) {
1968     pa_assert(m);
1969
1970     if (load) {
1971         if (pa_idxset_size(m->mirroring_streams) == 0) {
1972             if (!pa_device_manager_load_forwarding(m->dm)) {
1973                 pa_log_error("could not load forwarding device");
1974                 return -1;
1975             } else
1976                 pa_log_info("forwarding device is now loaded");
1977         } else
1978             pa_log_debug("forwarding device has been already loaded");
1979
1980     } else {
1981         if (pa_idxset_size(m->mirroring_streams) > 0)
1982             pa_log_debug("no need to unload forwarding device");
1983         else {
1984             pa_device_manager_unload_forwarding(m->dm);
1985             pa_log_info("forwarding device is now unloaded");
1986         }
1987     }
1988
1989     return 0;
1990 }
1991 #endif
1992
1993 static void set_new_data_stream_to_null_sink_source(pa_stream_manager *m, void *stream, stream_type_t type) {
1994     pa_sink *null_sink;
1995     pa_source *null_source;
1996
1997     pa_assert(m);
1998     pa_assert(stream);
1999
2000     if (type == STREAM_SINK_INPUT && !((pa_sink_input_new_data*)stream)->sink) {
2001         if ((null_sink = (pa_sink*)pa_namereg_get(m->core, SINK_NAME_NULL, PA_NAMEREG_SINK)))
2002             ((pa_sink_input_new_data*)stream)->sink = null_sink;
2003         else
2004             pa_log_warn("could not get null_sink");
2005     } else if (type == STREAM_SOURCE_OUTPUT && !((pa_source_output_new_data*)stream)->source) {
2006         if ((null_source = (pa_source*)pa_namereg_get(m->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE)))
2007             ((pa_source_output_new_data*)stream)->source = null_source;
2008         else
2009             pa_log_warn("could not get null_source");
2010     }
2011 }
2012
2013 static bool check_preferred_role_of_active_device_exist(pa_stream_manager *m, void *stream, stream_type_t type, const char *preferred_role) {
2014     const char *active_device_type;
2015     pa_tz_device *device;
2016
2017     pa_assert(m);
2018     pa_assert(stream);
2019     pa_assert(preferred_role);
2020
2021     if ((active_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
2022         if ((device = pa_device_manager_get_device(m->dm, active_device_type, preferred_role))) {
2023             pa_log_debug("preferred device role[%s] of active device[%s] is found", preferred_role, pa_tz_device_get_type(device));
2024             return true;
2025         }
2026     }
2027
2028     return false;
2029 }
2030
2031 static process_stream_result_t handle_command_prepare(pa_stream_manager *m, void *stream, stream_type_t type, bool is_new_data) {
2032     pa_format_info *req_format = NULL;
2033     char *format_str = NULL;
2034     const char *rate_str = NULL;
2035     const char *ch_str = NULL;
2036     const char *role = NULL;
2037     const char *route_type_str = NULL;
2038
2039     pa_assert(m);
2040     pa_assert(stream);
2041
2042     if (type == STREAM_SINK_INPUT) {
2043         /* Parse request formats for samplerate, channel, format information */
2044         if (((pa_sink_input_new_data*)stream)->req_formats) {
2045             req_format = pa_idxset_first(((pa_sink_input_new_data*)stream)->req_formats, NULL);
2046             if (req_format && req_format->plist) {
2047                 /* set sample_spec */
2048                 if (pa_format_info_get_prop_string(req_format, PA_PROP_FORMAT_SAMPLE_FORMAT, &format_str) == 0)
2049                     ((pa_sink_input_new_data*)stream)->sample_spec.format = pa_parse_sample_format((const char*)format_str);
2050                 if ((rate_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_RATE)))
2051                     ((pa_sink_input_new_data*)stream)->sample_spec.rate = atoi(rate_str);
2052                 if ((ch_str = pa_proplist_gets(req_format->plist, PA_PROP_FORMAT_CHANNELS)))
2053                     ((pa_sink_input_new_data*)stream)->sample_spec.channels = atoi(ch_str);
2054
2055                 pa_log_debug("req rate(%s), req ch(%s), req format(%s)", rate_str, ch_str, format_str);
2056
2057                 /* set channel map if it is not set by client */
2058                 if (!((pa_sink_input_new_data*)stream)->channel_map_is_set) {
2059                     pa_channel_map_init_auto(&(((pa_sink_input_new_data*)stream)->channel_map),
2060                                             ((pa_sink_input_new_data*)stream)->sample_spec.channels, PA_CHANNEL_MAP_ALSA);
2061                     pa_log_debug("set default channel_map: channels(%u)", ((pa_sink_input_new_data*)stream)->channel_map.channels);
2062                     ((pa_sink_input_new_data*)stream)->channel_map_is_set = true;
2063                 }
2064                 pa_xfree(format_str);
2065             }
2066         } else {
2067             pa_log_debug("no request formats available");
2068         }
2069     }
2070     role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2071     if (!role) {
2072         /* set default value for role and priority */
2073         role = DEFAULT_ROLE;
2074         pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE, role);
2075         pa_log_warn("role is null, set default to [%s]", role);
2076     } else {
2077         /* skip roles */
2078         if (is_invalid_role(m, role))
2079             return PROCESS_STREAM_RESULT_SKIP;
2080
2081 #ifndef __TIZEN_TV_EXTERNAL_TV_SOURCE__
2082         /* load forwarding device */
2083         if (type == STREAM_SOURCE_OUTPUT && pa_safe_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
2084             update_forwarding_device(m, true);
2085 #endif
2086     }
2087     /* update the priority of this stream */
2088     if (!update_priority_of_stream(m, stream, type, role, is_new_data)) {
2089         pa_log_error("could not update the priority of '%s' role.", role);
2090         return PROCESS_STREAM_RESULT_STOP;
2091     }
2092     /* update the route type of this stream */
2093     if (!update_route_type_of_stream(m, stream, type, role)) {
2094         pa_log_error("could not update the route type of '%s' role.", role);
2095         return PROCESS_STREAM_RESULT_STOP;
2096     }
2097     /* update the volume type of this stream */
2098     if (!update_volume_type_of_stream(m, stream, type, role))
2099         pa_log_warn("could not update the volume type of '%s' role.", role);
2100
2101     /* skip route types */
2102     if ((route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2103         if (is_invalid_route_type(route_type_str, NULL))
2104             return PROCESS_STREAM_RESULT_SKIP;
2105     }
2106
2107     /* update the preferred device role, it will affect only built-in devices. */
2108     update_preferred_device_role(m, stream, type);
2109
2110     /* check if it is a virtual stream */
2111     if (check_name_is_vstream(stream, type, is_new_data) && !pa_safe_streq(role, STREAM_ROLE_LOOPBACK)) {
2112         pa_log_debug("skip notifying for selecting sink/source, rather set it to null sink/source");
2113         /* set it to null sink/source */
2114         if (is_new_data)
2115             set_new_data_stream_to_null_sink_source(m, stream, type);
2116
2117     } else {
2118         /* notify to select sink or source */
2119         do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, true, stream);
2120     }
2121
2122     return PROCESS_STREAM_RESULT_OK;
2123 }
2124
2125 static process_stream_result_t handle_command_change_route_by_stream_started(pa_stream_manager *m, void *stream,
2126                                                                         stream_type_t type, bool is_new_data) {
2127     const char *role = NULL;
2128     const char *route_type_str = NULL;
2129     stream_route_type_t route_type;
2130     const char *preferred_device_role;
2131     bool need_update = false;
2132
2133     pa_assert(m);
2134     pa_assert(stream);
2135
2136     if (is_new_data) {
2137         role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2138         route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2139         preferred_device_role =  pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type),
2140                                                             PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
2141     } else {
2142         role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2143         route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
2144         preferred_device_role =  pa_proplist_gets(GET_STREAM_PROPLIST(stream, type),
2145                                                             PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
2146     }
2147
2148     /* skip updating priority, focus status, the highest priority, ucm to HAL */
2149     if (preferred_device_role) {
2150         if (is_new_data) {
2151             pa_log_debug("skip updating priority, focus status, the highest priority, ucm to HAL");
2152             goto skip_notifying_route_start;
2153         } else {
2154             if (check_preferred_role_of_active_device_exist(m, stream, type, preferred_device_role)) {
2155                 pa_log_debug("skip updating priority, focus status, the highest priority, ucm to HAL");
2156                 goto skip_notifying_route_start;
2157             }
2158         }
2159     }
2160
2161     /* skip roles */
2162     if (is_invalid_role(m, role))
2163         return PROCESS_STREAM_RESULT_SKIP;
2164     if (pa_safe_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING)) {
2165         pa_log_debug("role is [%s], skip it", role);
2166         return PROCESS_STREAM_RESULT_SKIP;
2167     }
2168
2169     /* skip route types */
2170     if (is_invalid_route_type(route_type_str, &route_type))
2171         return PROCESS_STREAM_RESULT_SKIP;
2172     if (route_type == STREAM_ROUTE_TYPE_MANUAL_EXT)
2173         return PROCESS_STREAM_RESULT_SKIP;
2174
2175     if (!is_new_data) {
2176         /* update the priority of this stream */
2177         if (!update_priority_of_stream(m, stream, type, role, is_new_data)) {
2178             pa_log_error("could not update the priority of '%s' role.", role);
2179             return PROCESS_STREAM_RESULT_STOP;
2180         }
2181     }
2182
2183     /* update the focus status */
2184     if (!update_focus_status_of_stream(m, stream, type, is_new_data))
2185         pa_log_warn("could not update focus status");
2186
2187     /* update the highest priority */
2188     if (!update_the_highest_priority_stream(m, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, stream, type, role, is_new_data, &need_update)) {
2189         pa_log_error("could not update the highest priority stream");
2190         return PROCESS_STREAM_RESULT_SKIP;
2191     }
2192
2193     /* need to skip if this stream does not belong to internal device */
2194     /* if needed, notify to update */
2195     if (need_update) {
2196         if (is_new_data) {
2197             do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, true, stream);
2198             if (type == STREAM_SINK_INPUT)
2199                 m->cur_highest_priority.need_to_update_si = true;
2200             else
2201                 m->cur_highest_priority.need_to_update_so = true;
2202         } else {
2203             do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, false, stream);
2204             if (type == STREAM_SINK_INPUT) {
2205                 m->cur_highest_priority.sink_input = stream;
2206                 m->cur_highest_priority.role_si = role;
2207             } else {
2208                 m->cur_highest_priority.source_output = stream;
2209                 m->cur_highest_priority.role_so = role;
2210             }
2211         }
2212     }
2213
2214 skip_notifying_route_start:
2215     if (!is_new_data)
2216         do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, false, stream);
2217
2218     return PROCESS_STREAM_RESULT_OK;
2219 }
2220
2221 static process_stream_result_t handle_command_change_route_by_stream_ended(pa_stream_manager *m, void *stream,
2222                                                                         stream_type_t type, bool is_new_data, bool by_corked) {
2223     const char *role = NULL;
2224     const char *route_type_str = NULL;
2225     const char *preferred_device_role;
2226     bool need_update = false;
2227     const int32_t *prior_priority = NULL;
2228     size_t size = 0;
2229
2230     pa_assert(m);
2231     pa_assert(stream);
2232
2233     if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE))) {
2234         pa_log_warn("role is null, skip it");
2235         return PROCESS_STREAM_RESULT_SKIP;
2236     }
2237
2238     preferred_device_role =  pa_proplist_gets(GET_STREAM_PROPLIST(stream, type),
2239                                             PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
2240     /* skip updating the highest priority, ucm to HAL */
2241     if (preferred_device_role) {
2242         if (check_preferred_role_of_active_device_exist(m, stream, type, preferred_device_role)) {
2243             pa_log_debug("skip updating the highest priority, ucm to HAL");
2244             goto skip_notifying_route_end;
2245         }
2246     }
2247
2248 #ifndef __TIZEN_TV_EXTERNAL_TV_SOURCE__
2249     /* unload forwarding device */
2250     if (type == STREAM_SOURCE_OUTPUT && pa_safe_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
2251         update_forwarding_device(m, false);
2252 #endif
2253
2254     /* skip roles */
2255     if (is_invalid_role(m, role))
2256         return PROCESS_STREAM_RESULT_SKIP;
2257     if (pa_safe_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING)) {
2258         pa_log_debug("role is [%s], skip it", role);
2259         return PROCESS_STREAM_RESULT_SKIP;
2260     }
2261
2262     /* skip route types */
2263     if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2264         stream_route_type_t route_type;
2265         if (is_invalid_route_type(route_type_str, &route_type))
2266             return PROCESS_STREAM_RESULT_SKIP;
2267         if (route_type == STREAM_ROUTE_TYPE_MANUAL_EXT)
2268             return PROCESS_STREAM_RESULT_SKIP;
2269     }
2270
2271     /* check if it has already been processed (unlink or state_changed_cb) */
2272     if (pa_proplist_get(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&prior_priority, &size)) {
2273         pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, skip it..");
2274         return PROCESS_STREAM_RESULT_SKIP;
2275     }
2276
2277     if (!update_the_highest_priority_stream(m, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, stream, type,
2278                                         role, is_new_data, &need_update)) {
2279         pa_log_error("could not update the highest priority stream");
2280         return PROCESS_STREAM_RESULT_STOP;
2281     }
2282
2283 skip_notifying_route_end:
2284     if (by_corked || CHECK_STREAM_RUNNING(stream, type))
2285         do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED, type, false, stream);
2286
2287     /* need to skip if this stream does not belong to internal device */
2288     /* if needed, notify to update */
2289     if (need_update)
2290         do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
2291
2292     return PROCESS_STREAM_RESULT_OK;
2293 }
2294
2295 static process_stream_result_t handle_command_change_route_by_stream_focus_changed(pa_stream_manager *m, void *stream,
2296                                                                                 stream_type_t type, bool is_new_data) {
2297     const char *role = NULL;
2298     const char *route_type_str = NULL;
2299     bool need_update = false;
2300
2301     pa_assert(m);
2302     pa_assert(stream);
2303
2304     if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE))) {
2305         pa_log_warn("role is null, skip it");
2306         return PROCESS_STREAM_RESULT_SKIP;
2307     }
2308
2309     /* skip roles */
2310     if (is_invalid_role(m, role))
2311         return PROCESS_STREAM_RESULT_SKIP;
2312
2313     /* skip route types */
2314     if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2315         stream_route_type_t route_type;
2316         if (is_invalid_route_type(route_type_str, &route_type))
2317             return PROCESS_STREAM_RESULT_SKIP;
2318         if (route_type == STREAM_ROUTE_TYPE_MANUAL_EXT)
2319             return PROCESS_STREAM_RESULT_SKIP;
2320     }
2321
2322     if (!update_the_highest_priority_stream(m, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, stream, type, role,
2323                                             is_new_data, &need_update)) {
2324         pa_log_error("could not update the highest priority stream");
2325         return PROCESS_STREAM_RESULT_STOP;
2326     }
2327
2328     /* need to skip if this stream does not belong to internal device */
2329     /* if needed, notify to update */
2330     if (need_update)
2331         do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
2332
2333     return PROCESS_STREAM_RESULT_OK;
2334 }
2335
2336 static process_stream_result_t handle_command_update_volume(pa_stream_manager *m, void *stream, stream_type_t type, bool is_new_data) {
2337     int32_t volume_ret = 0;
2338     volume_info *v = NULL;
2339     const char *si_volume_type_str = NULL;
2340
2341     pa_assert(m);
2342     pa_assert(stream);
2343
2344     if (is_new_data) {
2345         si_volume_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
2346     } else {
2347         si_volume_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
2348         if (si_volume_type_str && is_active_device_of_stream(stream, STREAM_SINK_INPUT, DEVICE_TYPE_NETWORK)) {
2349             /* In case of network device, reset the volume of this sink-input. */
2350             pa_cvolume cv;
2351             pa_cvolume_reset(&cv, ((pa_sink_input*)stream)->sample_spec.channels) ;
2352             pa_sink_input_set_volume((pa_sink_input*)stream, &cv, true, true);
2353             pa_log_debug("This stream belongs to a network device, reset volume.");
2354             return PROCESS_STREAM_RESULT_OK;
2355         }
2356     }
2357
2358     if (!si_volume_type_str)
2359         return PROCESS_STREAM_RESULT_SKIP;
2360
2361     v = pa_hashmap_get(m->volume_infos, si_volume_type_str);
2362     if (v && v->values[type].idx_volume_values) {
2363         if (is_new_data) {
2364             /* Update volume-level */
2365             if ((volume_ret = set_volume_level_with_new_data(m, stream, type, v->values[type].current_level)))
2366                 pa_log_error("failed to set_volume_level_with_new_data(), stream_type(%d), level(%u), ret(0x%x)",
2367                                 type, v->values[type].current_level, volume_ret);
2368             /* Update volume-mute */
2369             if ((volume_ret = set_volume_mute_with_new_data(m, stream, type, v->values[type].is_muted)))
2370                 pa_log_error("failed to set_volume_mute_with_new_data(), stream_type(%d), mute(%d), ret(0x%x)",
2371                                 type, v->values[type].is_muted, volume_ret);
2372         } else {
2373             /* Update volume-level by stream index*/
2374             if ((volume_ret = set_volume_level_by_idx(m, type, GET_STREAM_INDEX(stream, type), v->values[type].current_level)))
2375                 pa_log_error("failed to set_volume_level_by_idx(), stream_type(%d), index(%u), level(%u), ret(0x%x)",
2376                                 type, GET_STREAM_INDEX(stream, type), v->values[type].current_level, volume_ret);
2377         }
2378     }
2379
2380     return PROCESS_STREAM_RESULT_OK;
2381 }
2382
2383 static process_stream_result_t handle_command_add_remove_stream(pa_stream_manager *m, process_command_type_t command,
2384                                             void *stream, stream_type_t type, bool is_new_data) {
2385     const char *role = NULL;
2386     const char *route_type_str = NULL;
2387     stream_route_type_t route_type;
2388
2389     pa_assert(m);
2390     pa_assert(stream);
2391
2392     if (command != PROCESS_COMMAND_ADD_STREAM &&
2393         command != PROCESS_COMMAND_REMOVE_STREAM)
2394         return PROCESS_STREAM_RESULT_SKIP;
2395
2396     if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE))) {
2397         pa_log_warn("role is null, skip it");
2398         return PROCESS_STREAM_RESULT_SKIP;
2399     }
2400
2401     /* skip roles */
2402     if (is_invalid_role(m, role))
2403         return PROCESS_STREAM_RESULT_SKIP;
2404
2405     /* skip route types */
2406     if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
2407         if (is_invalid_route_type(route_type_str, NULL))
2408             return PROCESS_STREAM_RESULT_SKIP;
2409     }
2410
2411     if (!IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
2412         if (command == PROCESS_COMMAND_ADD_STREAM && CHECK_STREAM_RUNNING(stream, type)) {
2413             if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
2414                 m->cur_highest_priority.sink_input = stream;
2415                 m->cur_highest_priority.role_si = role;
2416                 m->cur_highest_priority.need_to_update_si = false;
2417             }
2418             if (type == STREAM_SOURCE_OUTPUT && m->cur_highest_priority.need_to_update_so) {
2419                 m->cur_highest_priority.source_output = stream;
2420                 m->cur_highest_priority.role_so = role;
2421                 m->cur_highest_priority.need_to_update_so = false;
2422             }
2423             do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, false, stream);
2424         }
2425     }
2426
2427     /* update parent stream info. */
2428     if (!update_stream_parent_info(m, command, type, stream)) {
2429         pa_log_debug("could not update the parent information of this stream");
2430         //return PROCESS_STREAM_RESULT_STOP;
2431     }
2432
2433     return PROCESS_STREAM_RESULT_OK;
2434 }
2435
2436 process_stream_result_t process_stream(pa_stream_manager *m, void *stream, stream_type_t type, process_command_type_t command, bool is_new_data) {
2437     process_stream_result_t result = PROCESS_STREAM_RESULT_OK;
2438
2439     pa_assert(m);
2440     pa_assert(stream);
2441
2442     if (!is_valid_process_command(command)) {
2443         pa_log_error("invalid process command: %d", command);
2444         return PROCESS_STREAM_RESULT_SKIP;
2445     }
2446     pa_log_info(">>> [%s]: stream(%p), stream_type(%d), is_new_data(%d)",
2447                 process_command_type_str[command], stream, type, is_new_data);
2448
2449     if (check_name_to_skip(m, command, stream, type, is_new_data)) {
2450         result = PROCESS_STREAM_RESULT_SKIP;
2451         /* set it to null sink/source */
2452         if (is_new_data)
2453             set_new_data_stream_to_null_sink_source(m, stream, type);
2454         goto finish;
2455     }
2456
2457     switch (command) {
2458     case PROCESS_COMMAND_PREPARE:
2459         result = handle_command_prepare(m, stream, type, is_new_data);
2460         break;
2461     case PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED:
2462     case PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_RUNNING:
2463         result = handle_command_change_route_by_stream_started(m, stream, type, is_new_data);
2464         break;
2465     case PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED:
2466     case PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_CORKED:
2467         result = handle_command_change_route_by_stream_ended(m, stream, type, is_new_data,
2468                             (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_CORKED));
2469         break;
2470     case PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED:
2471         result = handle_command_change_route_by_stream_focus_changed(m, stream, type, is_new_data);
2472         break;
2473     case PROCESS_COMMAND_UPDATE_VOLUME:
2474         result = handle_command_update_volume(m, stream, type, is_new_data);
2475         break;
2476     case PROCESS_COMMAND_ADD_STREAM:
2477     case PROCESS_COMMAND_REMOVE_STREAM:
2478         result = handle_command_add_remove_stream(m, command, stream, type, is_new_data);
2479         break;
2480     case PROCESS_COMMAND_UPDATE_BUFFER_ATTR:
2481         update_buffer_attribute(m, stream, type, is_new_data);
2482         break;
2483     case PROCESS_COMMAND_APPLY_FILTER: {
2484         const char *role = NULL;
2485         filter_info *f = NULL;
2486         /* Apply filter using module-filter-apply when put sink-input. */
2487         if (type == STREAM_SINK_INPUT) {
2488             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
2489             if (role) {
2490                 f = pa_hashmap_get(m->filter_infos, (const void*)role);
2491                 if (f)
2492                     apply_filter_to_sink_input((pa_sink_input *)stream, f, false);
2493             }
2494         }
2495         break;
2496     }
2497     case PROCESS_COMMAND_SET_AEC_REFERENCE_DEVICE: {
2498         int32_t id;
2499         pa_tz_device *device;
2500         const char *ref_device;
2501         pa_proplist *p = ((pa_source_output_new_data*)stream)->proplist;
2502         pa_sink *s;
2503
2504         result = PROCESS_STREAM_RESULT_SKIP;
2505
2506         ref_device = pa_proplist_gets(p, PA_PROP_MEDIA_ECHO_CANCEL_REFERENCE_DEVICE);
2507         if (!ref_device)
2508             break;
2509
2510         result = PROCESS_STREAM_RESULT_STOP;
2511
2512         if (pa_atoi(ref_device, &id) < 0) {
2513             pa_log_error("Can't convert ref_device(%s) to integer", ref_device);
2514             break;
2515         }
2516
2517         device = pa_device_manager_get_device_by_id(m->dm, id);
2518         if (!device) {
2519             pa_log_error("Can't find device by id(%d)", id);
2520             break;
2521         }
2522
2523         s = pa_tz_device_get_sink(device, "normal");
2524         if (!s) {
2525             pa_log_error("Can't find sink by device");
2526             break;
2527         }
2528
2529         pa_proplist_setf(p, PA_PROP_MEDIA_ECHO_CANCEL_REFERENCE_SINK, "%d", s->index);
2530
2531         result = PROCESS_STREAM_RESULT_OK;
2532
2533         break;
2534     }
2535     }
2536
2537 finish:
2538     pa_log_debug("<<< [%s]: result(%d), stream(%p)", process_command_type_str[command], result, stream);
2539     return result;
2540 }
2541
2542 /* Remove the sink-input from muted streams */
2543 static void remove_sink_input_from_muted_streams(pa_stream_manager *m, pa_sink_input *i) {
2544     pa_idxset *streams;
2545     pa_sink_input *si;
2546     void *state;
2547     uint32_t idx = 0;
2548
2549     pa_assert(m);
2550
2551     PA_HASHMAP_FOREACH(streams, m->muted_streams, state)
2552         PA_IDXSET_FOREACH(si, streams, idx)
2553             if (si == i)
2554                 pa_idxset_remove_by_data(streams, i, NULL);
2555 }
2556
2557 /* It can be utilized when it requires to invoke the ramp finish hook forcedly */
2558 static stream_ducking* fire_ramp_finish_hook_when_ducking_or_unducking_state(pa_stream_manager *m, pa_sink_input *i) {
2559     uint32_t idx = 0;
2560     stream_ducking *sd = NULL;
2561     void *stream = NULL;
2562     void *state;
2563
2564     pa_assert(m);
2565
2566     PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) {
2567         PA_IDXSET_FOREACH(stream, sd->idx_ducking_streams, idx) {
2568             if (stream != i)
2569                 continue;
2570             if (sd->state == STREAM_DUCKING_STATE_DUCKING ||
2571                 sd->state == STREAM_DUCKING_STATE_UNDUCKING) {
2572                 pa_log_debug("stream(%p, index:%u) ducking state[%s]",
2573                             i, i->index, sd->state == STREAM_DUCKING_STATE_DUCKING ? "DUCKING" : "UNDUCKING");
2574                 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_RAMP_FINISH], i);
2575             }
2576             return sd;
2577         }
2578     }
2579
2580     return NULL;
2581 }
2582
2583 /* Remove the sink-input from ducking streams */
2584 static void remove_sink_input_from_ducking_streams(pa_stream_manager *m, pa_sink_input *i) {
2585     stream_ducking *sd;
2586
2587     pa_assert(m);
2588
2589     if ((sd = fire_ramp_finish_hook_when_ducking_or_unducking_state(m, i))) {
2590         pa_log_error("remove stream(%p, index:%u) from idx_ducking_streams, trigger_index(%u)",
2591                     i, i->index, sd->trigger_index);
2592         pa_idxset_remove_by_data(sd->idx_ducking_streams, i, NULL);
2593     }
2594 }
2595
2596 /* Add the sink-input to ducking streams */
2597 static void add_sink_input_to_ducking_streams(pa_stream_manager *m, pa_sink_input *i) {
2598     stream_ducking *sd = NULL;
2599     void *state;
2600
2601     pa_assert(m);
2602
2603     PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) {
2604         pa_cvolume_ramp vol_ramp;
2605         pa_cvolume vol;
2606
2607         if (!pa_safe_streq(sd->target_role, pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
2608             continue;
2609
2610         pa_log_error("add stream(idx:%u,%p) to idx_ducking_streams, trigger_index(%u), volume(%u)",
2611             i->index, i, sd->trigger_index, sd->set_vol);
2612
2613         pa_idxset_put(sd->idx_ducking_streams, (void *)i, NULL);
2614
2615         pa_cvolume_ramp_set(&vol_ramp, i->volume.channels,
2616             PA_VOLUME_RAMP_TYPE_LINEAR, (long)sd->duration, sd->set_vol);
2617
2618         pa_cvolume_set(&vol, i->volume.channels, sd->set_vol);
2619
2620         pa_sink_input_add_volume_factor(i, sd->vol_key, &vol);
2621         pa_sink_input_add_volume_ramp_factor(i, sd->vol_key, &vol_ramp, false);
2622
2623         return;
2624     }
2625 }
2626
2627 static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data *new_data, pa_stream_manager *m) {
2628     pa_core_assert_ref(core);
2629
2630     pa_log_debug("sink-input-new-data(%p)", new_data);
2631
2632     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_PREPARE, true);
2633     if (is_remote_restricted(new_data, STREAM_SINK_INPUT))
2634         return PA_HOOK_CANCEL;
2635     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_BUFFER_ATTR, true);
2636     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, true);
2637     process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, true);
2638
2639     return PA_HOOK_OK;
2640 }
2641
2642 static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2643     pa_core_assert_ref(core);
2644     pa_sink_input_assert_ref(i);
2645
2646     pa_log_info("sink-input(%p, index:%u)", i, i->index);
2647
2648     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_ADD_STREAM, false);
2649     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_APPLY_FILTER, false);
2650     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, false);
2651     if (is_stream_related_call_active_routing(PA_OBJECT(i))) {
2652         change_active_route_for_call(m, PA_OBJECT(i), true);
2653         m->on_call = true;
2654     }
2655
2656     add_sink_input_to_ducking_streams(m, i);
2657
2658     return PA_HOOK_OK;
2659 }
2660
2661 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2662     pa_core_assert_ref(core);
2663     pa_sink_input_assert_ref(i);
2664
2665     pa_log_info("sink-input(%p, index:%u)", i, i->index);
2666
2667     if (is_stream_related_call_active_routing(PA_OBJECT(i))) {
2668         m->on_call = false;
2669         set_media_active_device(m);
2670     }
2671
2672     remove_sink_input_from_muted_streams(m, i);
2673     remove_sink_input_from_ducking_streams(m, i);
2674
2675     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_REMOVE_STREAM, false);
2676     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
2677
2678     return PA_HOOK_OK;
2679 }
2680
2681 static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2682     pa_assert(i);
2683     pa_assert(m);
2684
2685     pa_log_debug("sink-input(%p, index:%u, state:%d)", i, i->index, i->state);
2686
2687     switch (i->state) {
2688     case PA_SINK_INPUT_CORKED:
2689         process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_CORKED, false);
2690         fire_ramp_finish_hook_when_ducking_or_unducking_state(m, i);
2691         break;
2692     case PA_SINK_INPUT_RUNNING:
2693         process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STATE_CHANGED_RUNNING, false);
2694         break;
2695     default:
2696         break;
2697     }
2698
2699     return PA_HOOK_OK;
2700 }
2701
2702 static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2703     pa_core_assert_ref(core);
2704     pa_sink_input_assert_ref(i);
2705
2706     /* There's no point in doing anything if the core is shut down anyway */
2707     if (core->state == PA_CORE_SHUTDOWN)
2708         return PA_HOOK_OK;
2709
2710     pa_log_debug("sink-input(%p, index:%u)", i, i->index);
2711
2712     set_volume_mute_by_idx(m, i->index, STREAM_SINK_INPUT, true);
2713     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, false);
2714
2715     return PA_HOOK_OK;
2716 }
2717
2718 static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2719     pa_core_assert_ref(core);
2720     pa_sink_input_assert_ref(i);
2721
2722     /* There's no point in doing anything if the core is shut down anyway */
2723     if (core->state == PA_CORE_SHUTDOWN)
2724         return PA_HOOK_OK;
2725
2726     pa_log_debug("sink-input(%p, index:%u)", i, i->index);
2727
2728     set_volume_mute_by_idx(m, i->index, STREAM_SINK_INPUT, false);
2729
2730     return PA_HOOK_OK;
2731 }
2732
2733 static bool is_in_main_thread()
2734 {
2735     return (getpid() == gettid());
2736 }
2737
2738 /* Called from either IO thread context or main context */
2739 /* FIXME : make this callback be invoked from the main context only */
2740 static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
2741     struct stream_manager_param param;
2742
2743     pa_core_assert_ref(core);
2744     pa_sink_input_assert_ref(i);
2745
2746     /* There's no point in doing anything if the core is shut down anyway */
2747     if (core->state == PA_CORE_SHUTDOWN)
2748         return PA_HOOK_OK;
2749
2750     param.m = m;
2751     param.sink_input = i;
2752     param.index = i->index;
2753
2754     pa_log_info("sink-input(%p, index:%u)", i, i->index);
2755
2756     if (is_in_main_thread()) {
2757         process_ramp_finish(&param);
2758         pa_log_info("sink-input(%p, index:%u) : direct process_ramp_finish() done", i, i->index);
2759     } else {
2760         /* Post message to make process_ramp_finish() run from main thread */
2761         pa_asyncmsgq_post(m->thread_mq.outq, PA_MSGOBJECT(m->msg), MESSAGE_RAMP_FINISHED,
2762                         pa_xmemdup(&param, sizeof(struct stream_manager_param)), 0, NULL, pa_xfree);
2763         pa_log_info("sink-input(%p, index:%u) : posting MESSAGE_RAMP_FINISHED done", i, i->index);
2764     }
2765
2766     return PA_HOOK_OK;
2767 }
2768
2769 static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new_data *new_data, pa_stream_manager *m) {
2770     pa_core_assert_ref(core);
2771
2772     pa_log_debug("source-output-new-data(%p)", new_data);
2773
2774     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_PREPARE, true);
2775     if (is_restricted(m, new_data, STREAM_SOURCE_OUTPUT) ||
2776         is_remote_restricted(new_data, STREAM_SOURCE_OUTPUT))
2777         return PA_HOOK_CANCEL;
2778     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_BUFFER_ATTR, true);
2779     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_VOLUME, true);
2780     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, true);
2781     process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_SET_AEC_REFERENCE_DEVICE, true);
2782
2783     return PA_HOOK_OK;
2784 }
2785
2786 static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2787     pa_core_assert_ref(core);
2788     pa_source_output_assert_ref(o);
2789
2790     pa_log_info("source-output(%p, index:%u)", o, o->index);
2791
2792 #ifndef __TIZEN_TV_EXTERNAL_TV_SOURCE__
2793     update_mirroring_streams(m, o, true);
2794 #endif
2795     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_STREAM, false);
2796     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_VOLUME, false);
2797     if (is_stream_related_call_active_routing(PA_OBJECT(o))) {
2798         change_active_route_for_call(m, PA_OBJECT(o), true);
2799         m->on_call = true;
2800     }
2801
2802     return PA_HOOK_OK;
2803 }
2804
2805 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2806     pa_core_assert_ref(core);
2807     pa_source_output_assert_ref(o);
2808
2809     pa_log_info("source-output(%p, index:%u)", o, o->index);
2810
2811     if (is_stream_related_call_active_routing(PA_OBJECT(o))) {
2812         m->on_call = false;
2813         set_media_active_device(m);
2814     }
2815 #ifndef __TIZEN_TV_EXTERNAL_TV_SOURCE__
2816     update_mirroring_streams(m, o, false);
2817 #endif
2818     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
2819     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_REMOVE_STREAM, false);
2820
2821     return PA_HOOK_OK;
2822 }
2823
2824 static pa_hook_result_t source_output_state_changed_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2825     pa_assert(o);
2826     pa_assert(m);
2827
2828     pa_log_debug("source-output(%p, index:%u), state(%d)", o, o->index, o->state);
2829
2830     switch (o->state) {
2831     case PA_SOURCE_OUTPUT_CORKED:
2832         process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
2833         break;
2834     case PA_SOURCE_OUTPUT_RUNNING:
2835         process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
2836         break;
2837     default:
2838         break;
2839     }
2840
2841     return PA_HOOK_OK;
2842 }
2843
2844 static pa_hook_result_t source_output_move_start_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2845     pa_core_assert_ref(core);
2846     pa_source_output_assert_ref(o);
2847
2848     /* There's no point in doing anything if the core is shut down anyway */
2849     if (core->state == PA_CORE_SHUTDOWN)
2850         return PA_HOOK_OK;
2851
2852     pa_log_debug("source-output(%p, index:%u)", o, o->index);
2853
2854     set_volume_mute_by_idx(m, o->index, STREAM_SOURCE_OUTPUT, true);
2855
2856     return PA_HOOK_OK;
2857 }
2858
2859 static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
2860     pa_core_assert_ref(core);
2861     pa_source_output_assert_ref(o);
2862
2863     /* There's no point in doing anything if the core is shut down anyway */
2864     if (core->state == PA_CORE_SHUTDOWN)
2865         return PA_HOOK_OK;
2866
2867     pa_log_debug("source-output(%p, index:%u)", o, o->index);
2868
2869     set_volume_mute_by_idx(m, o->index, STREAM_SOURCE_OUTPUT, false);
2870
2871     return PA_HOOK_OK;
2872 }
2873
2874 static void notify_remote_connection(pa_core *core, pa_object *obj, pa_stream_manager *m, bool connected) {
2875     pa_proplist *p;
2876     pa_sink_input *i;
2877     pa_source_output *o;
2878     unsigned int index;
2879
2880     if (pa_source_output_isinstance(obj)) {
2881         o = PA_SOURCE_OUTPUT(obj);
2882         pa_assert(o);
2883         p = o->proplist;
2884         index = o->index;
2885     } else {
2886         i = PA_SINK_INPUT(obj);
2887         pa_assert(i);
2888         p = i->proplist;
2889         index = i->index;
2890     }
2891
2892     if (!p) {
2893         pa_log_error("unknown remote client");
2894         return;
2895     }
2896
2897     if (pa_proplist_has_remote_name(p)) {
2898         send_remote_found_signal(pa_dbus_connection_get(m->dbus_conn),
2899                 pa_source_output_isinstance(obj) ? 1 : 0, connected, index,
2900                 pa_proplist_gets(p, PA_PROP_MEDIA_REMOTE_NAME),
2901                 pa_proplist_gets(p, "native-protocol.peer"));
2902     }
2903 }
2904
2905 static pa_hook_result_t remote_client_put_cb(pa_core *core, pa_object *o, pa_stream_manager *m) {
2906     pa_core_assert_ref(core);
2907     pa_object_assert_ref(o);
2908
2909     notify_remote_connection(core, o, m, true);
2910
2911     return PA_HOOK_OK;
2912 }
2913
2914 static pa_hook_result_t remote_client_unlink_cb(pa_core *core, pa_object *o, pa_stream_manager *m) {
2915     pa_core_assert_ref(core);
2916     pa_object_assert_ref(o);
2917
2918     notify_remote_connection(core, o, m, false);
2919
2920     return PA_HOOK_OK;
2921 }
2922
2923 static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *stream_role,
2924                                         stream_type_t stream_type, const char *cur_device_type, const char *preferred_device_role, pa_tz_device **next_device) {
2925     stream_info *si = NULL;
2926     pa_idxset *devices = NULL;
2927     uint32_t idx = 0;
2928     char *device_type = NULL;
2929     bool ret_next = false;
2930     pa_usec_t creation_time = 0;
2931     pa_usec_t latest_creation_time = 0;
2932     pa_tz_device* latest_device = NULL;
2933
2934     pa_assert(m);
2935     pa_assert(m->stream_infos);
2936     pa_assert(stream_role);
2937     pa_assert(cur_device_type);
2938     pa_assert(next_device);
2939     pa_assert((route_type == STREAM_ROUTE_TYPE_AUTO || route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED));
2940
2941     *next_device = NULL;
2942
2943     if (!(si = pa_hashmap_get(m->stream_infos, stream_role))) {
2944         pa_log_warn("not support this stream_role[%s]", stream_role);
2945         return;
2946     }
2947     if (si->route_type != route_type) {
2948         pa_log_warn("skip this route_type[%d]", si->route_type);
2949         return;
2950     }
2951
2952     if (!(devices = (stream_type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices)) {
2953         pa_log_error("could not found a device list for this stream_role[%s], stream type[%d]", stream_role, stream_type);
2954         return;
2955     }
2956
2957     if (route_type == STREAM_ROUTE_TYPE_AUTO) {
2958         PA_IDXSET_FOREACH(device_type, devices, idx) {
2959             if (pa_safe_streq(device_type, cur_device_type)) {
2960                 ret_next = true;
2961                 continue;
2962             }
2963             if (ret_next) {
2964                 if ((*next_device = pa_device_manager_get_device(m->dm, device_type, preferred_device_role))) {
2965                     pa_log_debug("found next device[%s, %s, %p]", device_type, preferred_device_role, *next_device);
2966                     break;
2967                 }
2968             }
2969         }
2970     } else if (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
2971         const char *device_role;
2972         PA_IDXSET_FOREACH(device_type, devices, idx) {
2973             device_role = device_type_is_builtin(device_type) ? preferred_device_role : NULL;
2974             if ((*next_device = pa_device_manager_get_device(m->dm, device_type, device_role))) {
2975                 creation_time = pa_tz_device_get_creation_time(*next_device);
2976                 if (!latest_device || (latest_creation_time <= creation_time)) {
2977                     latest_device = *next_device;
2978                     latest_creation_time = creation_time;
2979                 }
2980             }
2981         }
2982         *next_device = latest_device;
2983         pa_log_debug("found next device[%p], creation_time[%" PRIu64 "]", *next_device, latest_creation_time);
2984     }
2985
2986     pa_log_debug("next_device is [%p] for stream_role[%s]/route_type[%d]/stream_type[%d]", *next_device, stream_role, route_type, stream_type);
2987 }
2988
2989 static void is_available_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *cur_device_type, const char *new_device_type, const char *role, stream_type_t stream_type, bool *available) {
2990     stream_info *si = NULL;
2991     pa_idxset *devices = NULL;
2992     uint32_t idx = 0;
2993     char *device_type = NULL;
2994
2995     pa_assert(m);
2996     pa_assert(m->stream_infos);
2997     pa_assert(role);
2998     pa_assert(cur_device_type);
2999     pa_assert(new_device_type);
3000     pa_assert(available);
3001     pa_assert((route_type == STREAM_ROUTE_TYPE_AUTO || route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED));
3002
3003     *available = false;
3004
3005     if (!(si = pa_hashmap_get(m->stream_infos, role))) {
3006         pa_log_warn("not support this role[%s]", role);
3007         return;
3008     }
3009     if (si->route_type != route_type) {
3010         pa_log_warn("skip this route_type[%d]", si->route_type);
3011         return;
3012     }
3013
3014     if (!(devices = (stream_type == STREAM_SINK_INPUT) ? si->idx_avail_out_devices : si->idx_avail_in_devices)) {
3015         pa_log_error("could not found a device list for this role[%s], stream type[%d]", role, stream_type);
3016         return;
3017     }
3018
3019     PA_IDXSET_FOREACH(device_type, devices, idx) {
3020         if (route_type == STREAM_ROUTE_TYPE_AUTO) {
3021             if (pa_safe_streq(device_type, cur_device_type)) {
3022                 pa_log_debug("cur_device[%s]'s priority is more higher than new_device[%s]", cur_device_type, new_device_type);
3023                 break;
3024             }
3025         }
3026         if (pa_safe_streq(device_type, new_device_type)) {
3027             *available = true;
3028             break;
3029         }
3030     }
3031
3032     pa_log_debug("is new_device[%s] available for role[%s]/stream_type[%d]:%d", new_device_type, role, stream_type, *available);
3033 }
3034
3035 /* Re-trigger for routing update for streams using auto route type */
3036 static void process_stream_as_device_change_for_auto_route(pa_stream_manager *m, void *stream, stream_type_t stream_type,
3037                                                            bool is_connected, pa_tz_device *device) {
3038     stream_route_type_t route_type;
3039     const char *device_type;
3040     bool use_internal_codec = false;
3041
3042     pa_assert(m);
3043     pa_assert(stream);
3044     pa_assert(device);
3045
3046     device_type = pa_tz_device_get_type(device);
3047     if (stream_type == STREAM_SINK_INPUT) {
3048         pa_sink *sink;
3049         if ((sink = pa_tz_device_get_sink(device, NULL)))
3050             use_internal_codec = sink->use_internal_codec;
3051         else
3052             pa_log_warn("sink is null");
3053     } else {
3054         pa_source *source;
3055         if ((source = pa_tz_device_get_source(device, NULL)))
3056             use_internal_codec = source->use_internal_codec;
3057         else
3058             pa_log_warn("source is null");
3059     }
3060
3061     pa_log_info("[SM][PROCESS_STREAM_FOR_AUTO] stream(%p), stream_type(%d), is_connected(%d), device_type(%s), use_internal_codec(%d)",
3062         stream, stream_type, is_connected, device_type, use_internal_codec);
3063
3064     if (get_route_type(stream, stream_type, false, &route_type) ||
3065         (route_type != STREAM_ROUTE_TYPE_AUTO && route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))
3066         return;
3067
3068     if (is_connected) {
3069         /* it is caused by the connection of supported device for the stream */
3070         if (use_internal_codec) {
3071             if (((stream_type == STREAM_SINK_INPUT) && (!m->cur_highest_priority.sink_input || (m->cur_highest_priority.sink_input != stream))) ||
3072                 ((stream_type == STREAM_SOURCE_OUTPUT) && (!m->cur_highest_priority.source_output || (m->cur_highest_priority.source_output != stream))))
3073                 process_stream(m, stream, stream_type, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
3074         } else {
3075             process_stream(m, stream, stream_type, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
3076             pa_proplist_sets(GET_STREAM_PROPLIST(stream, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
3077         }
3078     } else {
3079         /* it is caused by the disconnection of external device
3080          * and the supported next device of this stream using internal audio codec */
3081         if (use_internal_codec)
3082             process_stream(m, stream, stream_type, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
3083     }
3084 }
3085
3086 static bool is_filter_apply_stream(void *s, stream_type_t stream_type) {
3087     const char *filter_apply = NULL;
3088
3089     pa_assert(s);
3090
3091     if ((filter_apply = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_FILTER_APPLY))) {
3092         pa_log_info("stream index(%u) is for filter.apply(%s)", GET_STREAM_INDEX(s, stream_type), filter_apply);
3093         return true;
3094     }
3095     return false;
3096 }
3097
3098 static bool manage_filter_apply_stream(pa_stream_manager *m, pa_sink_input *si, pa_tz_device *device, bool is_connected) {
3099     stream_route_type_t route_type;
3100
3101     pa_assert(m);
3102     pa_assert(si);
3103     pa_assert(device);
3104
3105     if (get_route_type(si, STREAM_SINK_INPUT, false, &route_type))
3106         return false;
3107     if (route_type != STREAM_ROUTE_TYPE_AUTO && route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED)
3108         return false;
3109
3110     if (is_filter_apply_stream(si, STREAM_SINK_INPUT)) {
3111         const char *stream_role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
3112         const char *cur_device_type = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
3113         char *device_type = pa_tz_device_get_type(device);
3114         pa_tz_device *cur_device = pa_device_manager_get_device(m->dm, cur_device_type, NULL);
3115         pa_sink *sink = pa_tz_device_get_sink(device, NULL);
3116
3117         if (is_connected) {
3118             bool available = false;
3119             pa_sink *cur_sink = pa_tz_device_get_sink(cur_device, NULL);
3120             if (cur_sink == sink)
3121                 return true;
3122
3123             is_available_device_for_auto_route(m, route_type, cur_device_type, device_type,
3124                                                stream_role, STREAM_SINK_INPUT, &available);
3125             if (available) {
3126                 if (!reload_filter(m, stream_role, sink)) {
3127                     pa_proplist_sets(si->proplist, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
3128                     pa_log_info("[%s] is CONNECTED and will be set for the next device", device_type);
3129                     process_stream_as_device_change_for_auto_route(m, si, STREAM_SINK_INPUT, is_connected, device);
3130                 } else
3131                     pa_log_error("failed to reload filter");
3132             }
3133         } else {
3134             pa_tz_device *next_device = NULL;
3135             char *new_device_type = NULL;
3136             pa_sink *cur_sink = NULL;
3137
3138             if (cur_device)
3139                 cur_sink = pa_tz_device_get_sink(cur_device, NULL);
3140             if (cur_sink && (cur_sink != sink))
3141                 return true;
3142
3143             if (is_active_device_of_stream(si, STREAM_SINK_INPUT, device_type)) {
3144                 pa_sink *next_sink = NULL;
3145                 find_next_device_for_auto_route(m, route_type, stream_role, STREAM_SINK_INPUT, cur_device_type, NULL, &next_device);
3146                 if (!next_device) {
3147                     pa_log_error("failed to get next_device");
3148                     return true;
3149                 }
3150                 next_sink = pa_tz_device_get_sink(next_device, NULL);
3151                 if (!reload_filter(m, stream_role, next_sink)) {
3152                     new_device_type = pa_tz_device_get_type(next_device);
3153                     pa_proplist_sets(si->proplist, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
3154                     pa_log_info("[%s] is DISCONNECTED and [%s] will be set for the next device", device_type, new_device_type);
3155                     process_stream_as_device_change_for_auto_route(m, si, STREAM_SINK_INPUT, is_connected, next_device);
3156                 } else
3157                     pa_log_error("failed to reload filter");
3158             }
3159         }
3160         return true;
3161     }
3162
3163     return false;
3164 }
3165
3166 static void check_and_move_streams_by_device_connection_change(pa_stream_manager *m, stream_route_type_t stream_route_type,
3167                                                         pa_idxset *streams, stream_type_t stream_type, pa_tz_device *device, bool is_connected) {
3168     #define MAX_CACHED_LEN 128
3169     typedef struct _cached_device_list {
3170         const char *device_type;
3171         int count;
3172     } cached_device_list;
3173     void *s = NULL;
3174     uint32_t s_idx = 0;
3175     const char *stream_role = NULL;
3176     const char *device_type = NULL;
3177     const char *cur_device_type = NULL;
3178     const char *new_device_type = NULL;
3179     pa_tz_device *next_device = NULL;
3180     stream_route_type_t route_type;
3181     pa_sink *sink = NULL;
3182     pa_sink *next_sink = NULL;
3183     pa_sink *null_sink = NULL;
3184     pa_source *source = NULL;
3185     pa_source *next_source = NULL;
3186     pa_source *null_source = NULL;
3187     bool available = false;
3188     cached_device_list cached_prev_dev_list[MAX_CACHED_LEN] = {{NULL, 0}, };
3189     uint32_t cnt = 0;
3190     pa_sink *combine_sink = NULL;
3191
3192     pa_assert(m);
3193     pa_assert(streams);
3194     pa_assert(device);
3195
3196     null_sink = (pa_sink*)pa_namereg_get(m->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
3197     null_source = (pa_source*)pa_namereg_get(m->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE);
3198     if (!null_sink || !null_source) {
3199         pa_log_error("[SM][UPDATE_SINK_SOURCE] could not get null_sink(%p) or null_source(%p)", null_sink, null_source);
3200         return;
3201     }
3202     device_type = pa_tz_device_get_type(device);
3203
3204     if (stream_route_type == STREAM_ROUTE_TYPE_AUTO || stream_route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
3205         pa_log_debug("[SM][UPDATE_SINK_SOURCE][AUTO] route_type(%d), deivce_type(%s), is_connected(%d))",
3206                      stream_route_type, device_type, is_connected);
3207         if (stream_type == STREAM_SINK_INPUT)
3208             sink = pa_tz_device_get_sink(device, NULL);
3209         else
3210             source = pa_tz_device_get_source(device, NULL);
3211
3212         PA_IDXSET_FOREACH(s, streams, s_idx) { /* streams: core->source_outputs/core->sink_inputs */
3213             if (get_route_type(s, stream_type, false, &route_type))
3214                 continue;
3215             if (route_type != stream_route_type)
3216                 continue;
3217             if (stream_type == STREAM_SINK_INPUT && manage_filter_apply_stream(m, s, device, is_connected))
3218                 continue;
3219
3220             stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROLE);
3221             pa_log_debug("  -- idx(%u), route_type(%d), stream_role(%s)", s_idx, route_type, stream_role);
3222             if (is_connected) {
3223                 uint32_t preemptive_device_id = 0;
3224                 if (!pa_stream_manager_get_preemptive_device_id(m, stream_type, stream_role, &preemptive_device_id)) {
3225                     pa_tz_device *_device = pa_device_manager_get_device_by_id(m->dm, preemptive_device_id);
3226                     if (_device) {
3227                         pa_log_debug("Skip moving this stream[%s, idx:%u] set to the preemptive device(%s, id:%u)", stream_role,
3228                                      (stream_type == STREAM_SINK_INPUT) ? PA_SINK_INPUT(s)->index : PA_SOURCE_OUTPUT(s)->index,
3229                                      _device->type, preemptive_device_id);
3230                         continue;
3231                     }
3232                 }
3233                 /* CONNECTED: move a stream to the new device if possible */
3234                 if (sink && (sink != ((pa_sink_input*)s)->sink)) {
3235                     if ((cur_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
3236                         is_available_device_for_auto_route(m, route_type, cur_device_type, device_type, stream_role, stream_type, &available);
3237                         if (available) {
3238                             if (check_name_is_vstream(s, STREAM_SINK_INPUT, false)) {
3239                                 pa_log_debug("  -- *** keep null sink for a virtual stream");
3240                             } else {
3241                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
3242                                 pa_sink_input_move_to(s, sink, false);
3243                                 pa_log_debug("  -- *** sink-input(%p,%u) moves to sink(%p,%s), new device(%s)",
3244                                             s, ((pa_sink_input*)s)->index, sink, sink->name, device_type);
3245                             }
3246                         }
3247                     } else
3248                         pa_log_error("  -- could not find current device type for s->sink(%p)", ((pa_sink_input*)s)->sink);
3249                 } else if (source && (source != ((pa_source_output*)s)->source)) {
3250                     if ((cur_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
3251                         is_available_device_for_auto_route(m, route_type, cur_device_type, device_type, stream_role, stream_type, &available);
3252                         if (available) {
3253                             if (check_name_is_vstream(s, STREAM_SOURCE_OUTPUT, false)) {
3254                                 pa_log_debug("  -- *** keep null source for a virtual stream");
3255                             } else {
3256                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
3257                                 pa_source_output_move_to(s, source, false);
3258                                 pa_log_debug("  -- *** source-output(%p,%u) moves to source(%p,%s), new device(%s)",
3259                                             s, ((pa_source_output*)s)->index, source, source->name, device_type);
3260                             }
3261                         }
3262                     } else
3263                         pa_log_error("  -- could not find current device type for s->source(%p)", ((pa_source_output*)s)->source);
3264                 } else
3265                     pa_log_debug("no need to move for stream(%p, idx:%u)", s, GET_STREAM_INDEX(s, stream_type));
3266
3267                 if (available) {
3268                     cached_prev_dev_list[cnt++].device_type = cur_device_type;
3269                     /* trigger to update routing path */
3270                     process_stream_as_device_change_for_auto_route(m, s, stream_type, is_connected, device);
3271                 }
3272             } else if (!is_connected) {
3273                 const char *pref_device_type = NULL;
3274                 const char *pref_device_role = NULL;
3275                 const char *device_role = NULL;
3276
3277                 /* get preferred role */
3278                 get_preferred_device_type_and_role(m, s, stream_type, &pref_device_type, &pref_device_role);
3279
3280                 /* DISCONNECTED: find a connected device that has the next priority */
3281                 if (sink && ((sink == ((pa_sink_input*)s)->sink) || check_name_is_vstream(s, STREAM_SINK_INPUT, false))) {
3282                     if (!is_active_device_of_stream(s, stream_type, device_type))
3283                         continue;
3284                     find_next_device_for_auto_route(m, route_type, stream_role, stream_type, device_type, pref_device_role, &next_device);
3285                     if (next_device) {
3286                         if (pref_device_type && pa_safe_streq(pa_tz_device_get_type(next_device), pref_device_type))
3287                             device_role = pref_device_role;
3288
3289                         if ((next_sink = pa_tz_device_get_sink(next_device, device_role))) {
3290                             new_device_type = pa_tz_device_get_type(next_device);
3291                             /* update activated device */
3292                             pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
3293                             cached_prev_dev_list[cnt++].device_type = device_type;
3294                             /* trigger to update routing path if the next device uses internal audio codec */
3295                             process_stream_as_device_change_for_auto_route(m, s, stream_type, is_connected, next_device);
3296
3297                             if (check_name_is_vstream(s, STREAM_SINK_INPUT, false)) {
3298                                 pa_log_debug("  -- *** keep null sink for a virtual stream");
3299                             } else {
3300                                 pa_sink_input_move_to(s, next_sink, false);
3301                                 pa_log_debug("  -- *** sink-input(%p,%u) moves to sink(%p,%s), new device(%s)",
3302                                             s, ((pa_sink_input*)s)->index, next_sink, next_sink->name, new_device_type);
3303                             }
3304                         }
3305                     }
3306
3307                     if (!next_device || !next_sink) {
3308                         pa_sink_input_move_to(s, null_sink, false);
3309                         pa_log_warn("  -- *** sink-input(%p,%u) moves to sink(%p,%s)",
3310                             s, ((pa_sink_input*)s)->index, null_sink, null_sink->name);
3311                     }
3312
3313                 } else if (source && ((source == ((pa_source_output*)s)->source) || check_name_is_vstream(s, STREAM_SOURCE_OUTPUT, false))) {
3314                     if (!is_active_device_of_stream(s, stream_type, device_type))
3315                         continue;
3316                     find_next_device_for_auto_route(m, route_type, stream_role, stream_type, device_type, pref_device_role, &next_device);
3317                     if (next_device) {
3318                         if (pref_device_type && pa_safe_streq(pa_tz_device_get_type(next_device), pref_device_type))
3319                             device_role = pref_device_role;
3320
3321                         if ((next_source = pa_tz_device_get_source(next_device, device_role))) {
3322                             new_device_type = pa_tz_device_get_type(next_device);
3323                             /* update activated device */
3324                             pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
3325                             cached_prev_dev_list[cnt++].device_type = device_type;
3326                             /* trigger to update routing path if the next device uses internal audio codec */
3327                             if (next_source->use_internal_codec)
3328                                 process_stream_as_device_change_for_auto_route(m, s, stream_type, is_connected, next_device);
3329
3330                             if (check_name_is_vstream(s, STREAM_SOURCE_OUTPUT, false)) {
3331                                 pa_log_debug("  -- *** keep null source for a virtual stream");
3332                             } else {
3333                                 pa_source_output_move_to(s, next_source, false);
3334                                 pa_log_warn("  -- *** source-output(%p,%u) moves to source(%p,%s), new device(%s)",
3335                                              s, ((pa_source_output*)s)->index, next_source, next_source->name, new_device_type);
3336                             }
3337                         }
3338                     }
3339                     if (!next_device || !next_source) {
3340                         pa_source_output_move_to(s, null_source, false);
3341                         pa_log_debug("  -- *** source-output(%p,%u) moves to source(%p,%s)",
3342                             s, ((pa_source_output*)s)->index, null_source, null_source->name);
3343                     }
3344                 }
3345             }
3346         }
3347
3348         /* set device state to be deactivated */
3349         if (cnt) {
3350             if (stream_type == STREAM_SINK_INPUT) {
3351                 combine_sink = (pa_sink*)pa_namereg_get(m->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
3352                 if (combine_sink && pa_idxset_size(combine_sink->inputs)) {
3353                     pa_log_warn("  -- combine sink has streams, skip it..");
3354                     return;
3355                 }
3356             }
3357             /* retrieve all the streams for checking current activated device */
3358             PA_IDXSET_FOREACH(s, streams, s_idx) { /* streams: core->source_outputs/core->sink_inputs */
3359                 if ((cur_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
3360                     for (cnt = 0; cached_prev_dev_list[cnt].device_type; cnt++) {
3361                         if (pa_safe_streq(cur_device_type, cached_prev_dev_list[cnt].device_type))
3362                             cached_prev_dev_list[cnt].count++;
3363                     }
3364                 }
3365             }
3366         }
3367
3368     } else if (stream_route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
3369         pa_log_debug("[SM][UPDATE_SINK_SOURCE][EXT] deivce_type(%s), is_connected(%d))", device_type, is_connected);
3370         if (!is_connected) {
3371             PA_IDXSET_FOREACH(s, streams, s_idx) { /* streams: source->outputs/sink->inputs */
3372                 if (!get_route_type(s, stream_type, false, &route_type) && route_type == stream_route_type) {
3373                     if (stream_type == STREAM_SOURCE_OUTPUT) {
3374                         /* move it to null source if this role is for external device */
3375                         pa_source_output_move_to((pa_source_output*)s, null_source, false);
3376                         pa_log_debug("  -- *** source-output(%p,%u) moves to source(%p,%s)", s, ((pa_source_output*)s)->index, null_source, null_source->name);
3377                     } else {
3378                         /* move it to null sink if this role is for external device */
3379                         pa_sink_input_move_to((pa_sink_input*)s, null_sink, false);
3380                         pa_log_debug("  -- *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, null_sink, null_sink->name);
3381                     }
3382                 }
3383             }
3384         }
3385     } else
3386         pa_log_error("[SM][UPDATE_SINK_SOURCE] could not handle it here, stream_route_type(%d)", stream_route_type);
3387 }
3388
3389 static void apply_volume_factor_to_streams(pa_idxset *all_streams, pa_idxset **applied_streams) {
3390     pa_cvolume vol;
3391     pa_sink_input *i;
3392     uint32_t idx = 0;
3393
3394     pa_assert(all_streams);
3395     pa_assert(applied_streams);
3396
3397     pa_log_debug("apply volume factor");
3398
3399     vol.channels = 1;
3400     pa_parse_volume("0%", &vol.values[0]);
3401     *applied_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3402     PA_IDXSET_FOREACH(i, all_streams, idx) {
3403         pa_log_info("found a stream(%p, %u) that should be muted.", i, i->index);
3404         /* remove MUTE_KEY before adding to avoid abort-case in pa_sink_input_add_volume_factor */
3405         pa_hashmap_remove(i->volume_factor_items, MUTE_KEY);
3406         pa_sink_input_add_volume_factor(i, MUTE_KEY, &vol);
3407         pa_idxset_put(*applied_streams, i, NULL);
3408     }
3409 }
3410
3411 static void clear_volume_factor_from_streams(pa_idxset *applied_streams) {
3412     pa_sink_input *i;
3413     uint32_t idx = 0;
3414
3415     pa_assert(applied_streams);
3416
3417     pa_log_debug("clear volume factor");
3418
3419     PA_IDXSET_FOREACH(i, applied_streams, idx) {
3420         pa_idxset_remove_by_data(applied_streams, i, NULL);
3421         pa_sink_input_remove_volume_factor(i, MUTE_KEY);
3422         pa_log_info("found a stream(%p, %u) that should be un-muted.", i, i->index);
3423     }
3424     pa_idxset_free(applied_streams, NULL);
3425 }
3426
3427 static void timed_unmute_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
3428     pa_stream_manager *m = userdata;
3429     pa_idxset *applied_streams;
3430     void *state;
3431
3432     pa_assert(m);
3433     pa_assert(m->time_event_for_unmute == e);
3434
3435     pa_log_info("time event(%p)", e);
3436
3437     PA_HASHMAP_FOREACH(applied_streams, m->muted_streams, state) {
3438         clear_volume_factor_from_streams(applied_streams);
3439         pa_log_warn("remove volume factors forcedly...");
3440     }
3441     pa_hashmap_remove_all(m->muted_streams);
3442
3443     m->core->mainloop->time_free(m->time_event_for_unmute);
3444     m->time_event_for_unmute = NULL;
3445 }
3446
3447 static int active_device_filter_func(const void *i, const void *device_type) {
3448     pa_assert(i);
3449     pa_assert(device_type);
3450
3451     if (is_active_device_of_stream(i, STREAM_SINK_INPUT, (const char *)device_type))
3452         return 1;
3453
3454     return 0;
3455 }
3456
3457 static pa_idxset* get_streams_for_matching_active_device(pa_idxset *streams, const char *device_type) {
3458     pa_idxset *filtered_streams;
3459
3460     pa_assert(streams);
3461
3462     filtered_streams = pa_idxset_filtered_copy(streams, NULL, active_device_filter_func, device_type);
3463
3464     return filtered_streams;
3465 }
3466
3467 static void mute_sink_inputs_as_device_disconnection(pa_stream_manager *m, uint32_t event_id, bool need_to_mute, pa_idxset *streams_of_disconnected_device) {
3468     pa_idxset *applied_streams;
3469
3470     pa_assert(m);
3471
3472     pa_log_info("event_id(%u), need_to_mute(%d)", event_id, need_to_mute);
3473
3474     if (need_to_mute) {
3475         if (!streams_of_disconnected_device) {
3476             pa_log_error("invalid argument, inputs are needed");
3477             return;
3478         }
3479         apply_volume_factor_to_streams(streams_of_disconnected_device, &applied_streams);
3480         pa_hashmap_put(m->muted_streams, PA_UINT_TO_PTR(event_id), applied_streams);
3481
3482         /* If PA_COMMUNICATOR_HOOK_EVENT_FULLY_HANDLED is not called for some reason,
3483         * volume factor should be removed forcedly. */
3484         if (!m->time_event_for_unmute)
3485             m->time_event_for_unmute = pa_core_rttime_new(m->core, pa_rtclock_now() + TIMED_UNMUTE_USEC, timed_unmute_cb, m);
3486     } else {
3487         if (!(applied_streams = pa_hashmap_get(m->muted_streams, PA_UINT_TO_PTR(event_id)))) {
3488             pa_log_debug("could not find applied_streams for event_id(%u)", event_id);
3489             return;
3490         }
3491         clear_volume_factor_from_streams(applied_streams);
3492         pa_hashmap_remove(m->muted_streams, PA_UINT_TO_PTR(event_id));
3493     }
3494
3495     return;
3496 }
3497
3498 static pa_hook_result_t event_fully_handled_hook_cb(pa_core *c, pa_subscribe_observer_hook_data_for_event_handled *event_handled_hook_data, pa_stream_manager *m) {
3499     pa_assert(c);
3500     pa_assert(event_handled_hook_data);
3501     pa_assert(m);
3502
3503     pa_log_info("[SM][HANDLED] event-id(%u), event-type(%d)",
3504                 event_handled_hook_data->event_id, event_handled_hook_data->event_type);
3505
3506     /* un-mute streams */
3507     mute_sink_inputs_as_device_disconnection(m, event_handled_hook_data->event_id, false, NULL);
3508
3509     return PA_HOOK_OK;
3510 }
3511
3512 static void update_sink_or_source_by_device_connection_change(pa_stream_manager *m, pa_tz_device_hook_data_for_conn_changed *data,
3513                                         bool use_internal_codec, dm_device_direction_t device_direction) {
3514     pa_sink *sink = NULL;
3515     pa_source *source = NULL;
3516
3517     pa_assert(m);
3518     pa_assert(data);
3519
3520     /* Update streams belong to this external device that have MAUAL_EXT route type */
3521     if (!use_internal_codec) {
3522         if ((device_direction & DM_DEVICE_DIRECTION_IN) &&
3523             (source = pa_tz_device_get_source(data->device, NULL)))
3524             check_and_move_streams_by_device_connection_change(m, STREAM_ROUTE_TYPE_MANUAL_EXT, source->outputs,
3525                                                    STREAM_SOURCE_OUTPUT, data->device, data->is_connected);
3526         if ((device_direction & DM_DEVICE_DIRECTION_OUT) &&
3527             (sink = pa_tz_device_get_sink(data->device, NULL)))
3528             check_and_move_streams_by_device_connection_change(m, STREAM_ROUTE_TYPE_MANUAL_EXT, sink->inputs,
3529                                                    STREAM_SINK_INPUT, data->device, data->is_connected);
3530     }
3531
3532     /* Update all the streams that have AUTO route type */
3533     if (device_direction & DM_DEVICE_DIRECTION_IN) {
3534         check_and_move_streams_by_device_connection_change(m, STREAM_ROUTE_TYPE_AUTO, m->core->source_outputs,
3535                                                STREAM_SOURCE_OUTPUT, data->device, data->is_connected);
3536         check_and_move_streams_by_device_connection_change(m, STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->source_outputs,
3537                                                STREAM_SOURCE_OUTPUT, data->device, data->is_connected);
3538     }
3539     if (device_direction & DM_DEVICE_DIRECTION_OUT) {
3540         check_and_move_streams_by_device_connection_change(m, STREAM_ROUTE_TYPE_AUTO, m->core->sink_inputs,
3541                                                STREAM_SINK_INPUT, data->device, data->is_connected);
3542         check_and_move_streams_by_device_connection_change(m, STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED, m->core->sink_inputs,
3543                                                STREAM_SINK_INPUT, data->device, data->is_connected);
3544     }
3545 }
3546
3547 /* Reorganize routing when a device has been connected or disconnected */
3548 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_conn_changed *data, pa_stream_manager *m) {
3549     const char *active_dev = NULL;
3550     const char *device_type = NULL;
3551     stream_route_type_t route_type;
3552     dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
3553     bool use_internal_codec = false;
3554     void *s = NULL;
3555     uint32_t s_idx = 0;
3556     uint32_t device_id = 0;
3557     pa_sink *sink = NULL;
3558     pa_sink_input *si = NULL;
3559     pa_sink_input *highest_prior_si = NULL;
3560     pa_source_output *highest_prior_so = NULL;
3561
3562     pa_assert(c);
3563     pa_assert(data);
3564     pa_assert(m);
3565
3566     device_direction = pa_tz_device_get_direction(data->device);
3567     device_type = pa_tz_device_get_type(data->device);
3568     device_id = pa_tz_device_get_id(data->device);
3569     use_internal_codec = pa_tz_device_is_use_internal_codec(data->device);
3570
3571     pa_log_info("[SM][CONN] evend_id(%u), is_connected(%d), device(%p, %s, %u), direction(0x%x), use_internal_codec(%d)",
3572                 data->event_id, data->is_connected, data->device, device_type, device_id, device_direction, use_internal_codec);
3573
3574     /* mute all the streams belong to this device, those will be un-muted in event_fully_handled_hook_cb */
3575     if (!data->is_connected && (device_direction & DM_DEVICE_DIRECTION_OUT)) {
3576         const char *media_role = NULL;
3577         hal_route_option route_option;
3578
3579         if ((sink = pa_tz_device_get_sink(data->device, NULL))) {
3580             pa_idxset *filtered_streams = get_streams_for_matching_active_device(sink->inputs, device_type);
3581             mute_sink_inputs_as_device_disconnection(m, data->event_id, true, filtered_streams);
3582             pa_xfree(filtered_streams);
3583         }
3584
3585         /* If Earjack is disconnected, search for sink-input which has radio role,
3586            if found, let radio mute to avoid intermediate noise */
3587         if (pa_safe_streq(device_type, DEVICE_TYPE_AUDIO_JACK)) {
3588             PA_IDXSET_FOREACH(si, c->sink_inputs, s_idx) {
3589                 media_role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
3590                 if (pa_safe_streq(media_role, STREAM_ROLE_RADIO)) {
3591                     pa_log_info(" sink-input(%d) is radio, let HAL mute for disconnect of earjack", si->index);
3592                     memset(&route_option, 0, sizeof(hal_route_option));
3593                     route_option.role = STREAM_ROLE_RADIO;
3594                     route_option.name = "mute";
3595                     route_option.value = 1;
3596                     pa_hal_interface_update_route_option(m->hal, &route_option);
3597                 }
3598             }
3599         }
3600     }
3601
3602     update_sink_or_source_by_device_connection_change(m, data, use_internal_codec, device_direction);
3603
3604     /* If the route type is AUTO SERIES, notify again */
3605     highest_prior_so = m->cur_highest_priority.source_output;
3606     if ((device_direction & DM_DEVICE_DIRECTION_IN) && highest_prior_so &&
3607         !get_route_type(highest_prior_so, STREAM_SOURCE_OUTPUT, false, &route_type)) {
3608         if (IS_AUTO_ROUTE_TYPE_SERIES(route_type) && use_internal_codec) {
3609             PA_IDXSET_FOREACH(s, highest_prior_so->source->outputs, s_idx) {
3610                 if (!data->is_connected && !get_route_type(s, STREAM_SOURCE_OUTPUT, false, &route_type) &&
3611                     ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
3612                     /* remove activated device info. if it has the AUTO route type */
3613                     active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
3614                     if (pa_safe_streq(active_dev, device_type))
3615                         pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
3616                 }
3617             }
3618             do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, false, highest_prior_so);
3619             if (!highest_prior_so->source->use_internal_codec &&
3620                 !check_name_is_vstream(highest_prior_so, STREAM_SOURCE_OUTPUT, false)) {
3621                 /* If the source of the cur_highest_priority stream uses external codec, it should be updated.
3622                  * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
3623                  * can update the cur_highest_priority, call it here */
3624                 process_stream(m, highest_prior_so, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
3625             }
3626         }
3627     }
3628
3629     highest_prior_si = m->cur_highest_priority.sink_input;
3630     if ((device_direction & DM_DEVICE_DIRECTION_OUT) && highest_prior_si &&
3631         !get_route_type(highest_prior_si, STREAM_SINK_INPUT, false, &route_type)) {
3632         if (IS_AUTO_ROUTE_TYPE_SERIES(route_type) && use_internal_codec) {
3633             PA_IDXSET_FOREACH(s, highest_prior_si->sink->inputs, s_idx) {
3634                 if (!data->is_connected && !get_route_type(s, STREAM_SINK_INPUT, false, &route_type) &&
3635                     ((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED))) {
3636                     /* remove activated device info. if it has the AUTO route type */
3637                     active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
3638                     if (pa_safe_streq(active_dev, device_type))
3639                         pa_proplist_sets(GET_STREAM_PROPLIST(s, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, ACTIVE_DEV_REMOVED);
3640                 }
3641             }
3642             do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, highest_prior_si);
3643             if (((route_type == STREAM_ROUTE_TYPE_AUTO) || (route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED)) &&
3644                 !highest_prior_si->sink->use_internal_codec &&
3645                 !check_name_is_vstream(highest_prior_si, STREAM_SINK_INPUT, false) &&
3646                 !is_filter_apply_stream(highest_prior_si, STREAM_SINK_INPUT)) {
3647                 /* If the sink of the cur_highest_priority stream uses external codec, it should be updated.
3648                  * As only the process_stream(PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED)
3649                  * can update the cur_highest_priority, call it here */
3650                 process_stream(m, highest_prior_si, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
3651             }
3652         } else if (route_type == STREAM_ROUTE_TYPE_AUTO_ALL)
3653             do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, highest_prior_si);
3654     }
3655
3656     if (m->on_call) {
3657         pa_log_info("This is on_call state, do nothing about active device");
3658     } else {
3659         pa_log_info("This is not on_call state, figure out to change active device");
3660         set_media_active_device(m);
3661     }
3662
3663     return PA_HOOK_OK;
3664 }
3665
3666 static void subscribe_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, pa_stream_manager *m) {
3667     stream_parent *sp = NULL;
3668     stream_ducking *sd = NULL;
3669     const char *name = NULL;
3670
3671     pa_core_assert_ref(core);
3672     pa_assert(m);
3673
3674     pa_log_info("subscribe_cb() is called, t(%x), idx(%u)", t, idx);
3675
3676     if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE)) {
3677         pa_client *client = NULL;
3678
3679         if ((client = pa_idxset_get_by_index(core->clients, idx)) == NULL) {
3680             pa_log_error(" - could not find any client that has idx(%u)", idx);
3681             return;
3682         }
3683
3684         name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);
3685
3686         if (pa_safe_streq(name, STREAM_MANAGER_CLIENT_INFO)) {
3687             /* add a stream parent */
3688             sp = pa_xmalloc0(sizeof(stream_parent));
3689             sp->idx_sink_inputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3690             sp->idx_source_outputs = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3691             sp->idx_route_in_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
3692             sp->idx_route_out_devices = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
3693             pa_hashmap_put(m->stream_parents, PA_UINT_TO_PTR(idx), sp);
3694             pa_log_debug(" - add sp(%p), idx(%u)", sp, idx);
3695             return;
3696         } else if (pa_safe_streq(name, STREAM_MANAGER_CLIENT_DUCKING)) {
3697             /* add a stream ducking */
3698             sd = pa_xmalloc0(sizeof(stream_ducking));
3699             sd->idx_ducking_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3700             sd->trigger_index = idx;
3701             pa_hashmap_put(m->stream_duckings, PA_UINT_TO_PTR(idx), sd);
3702             pa_log_debug(" - add sd(%p), trigger_index(%u)", sd, idx);
3703             return;
3704         }
3705     } else if (t == (PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE)) {
3706         /* try to find stream parent with idx */
3707         sp = pa_hashmap_get(m->stream_parents, PA_UINT_TO_PTR(idx));
3708         if (sp) {
3709             pa_log_debug(" - remove sp(%p), idx(%u)", sp, idx);
3710             pa_hashmap_remove(m->stream_parents, PA_UINT_TO_PTR(idx));
3711             pa_idxset_free(sp->idx_sink_inputs, NULL);
3712             pa_idxset_free(sp->idx_source_outputs, NULL);
3713             if (sp->idx_route_in_devices)
3714                 pa_idxset_free(sp->idx_route_in_devices, pa_xfree);
3715             if (sp->idx_route_out_devices)
3716                 pa_idxset_free(sp->idx_route_out_devices, pa_xfree);
3717             pa_xfree(sp);
3718             return;
3719         }
3720
3721         /* try to find sd with idx */
3722         sd = pa_hashmap_get(m->stream_duckings, PA_UINT_TO_PTR(idx));
3723         if (sd) {
3724             uint32_t ducking_idx = 0;
3725             pa_sink_input *stream = NULL;
3726             hal_ducking_activation_info ducking_activation_info = {
3727                 sd->target_role, sd->duration, sd->ratio, false
3728             };
3729
3730             pa_log_info(" - remove sd(%p) state(%d), trigger_index(%u)", sd, sd->state, idx);
3731
3732             if (sd->state == STREAM_DUCKING_STATE_UNDUCKED || sd->state == STREAM_DUCKING_STATE_UNDUCKING)
3733                 goto skip_unducking;
3734
3735             PA_IDXSET_FOREACH(stream, sd->idx_ducking_streams, ducking_idx) {
3736                 /* Note: It is added temporarily to find missing index of idx_ducking_streams */
3737                 if (!pa_idxset_get_by_data(m->core->sink_inputs, stream, NULL)) {
3738                     pa_log_error("could not find stream(%p), skip it", stream);
3739                     continue;
3740                 }
3741
3742                 pa_log_info(" -- remove volume ramp, key(%s) from remained stream(idx:%u)", sd->vol_key, stream->index);
3743                 pa_sink_input_remove_volume_factor(stream, sd->vol_key);
3744                 pa_sink_input_remove_volume_ramp_factor(stream, sd->vol_key, true);
3745             }
3746
3747             pa_hal_interface_notify_ducking_activation_changed(m->hal, &ducking_activation_info);
3748
3749         skip_unducking:
3750             pa_idxset_free(sd->idx_ducking_streams, NULL);
3751             pa_hashmap_remove(m->stream_duckings, PA_UINT_TO_PTR(idx));
3752             pa_xfree(sd);
3753             return;
3754         }
3755     }
3756
3757     pa_log_warn(" - this is not a client(%s) that we should take care of, skip it", name ? name : "NULL");
3758 }
3759
3760 /* Message callback from HAL interface */
3761 static void message_cb_func(const char *name, int value, void *user_data) {
3762     pa_stream_manager *m;
3763     pa_stream_manager_hook_data_for_update_info hook_call_data;
3764
3765     pa_assert(user_data);
3766     pa_assert(name);
3767
3768     m = (pa_stream_manager*)user_data;
3769
3770     /* For module-loopback parameters */
3771     if (strstr(name, STREAM_ROLE_LOOPBACK)) {
3772         memset(&hook_call_data, 0, sizeof(pa_stream_manager_hook_data_for_update_info));
3773         hook_call_data.stream_role = STREAM_ROLE_LOOPBACK;
3774         hook_call_data.name = name;
3775         hook_call_data.value = value;
3776         pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_UPDATE_INFORMATION), &hook_call_data);
3777     }
3778 #ifdef HAVE_DBUS
3779     /* Others */
3780     else {
3781         send_command_signal(pa_dbus_connection_get(m->dbus_conn), name, value);
3782     }
3783 #endif
3784 }
3785
3786 static int32_t init_ipc(pa_stream_manager *m) {
3787     pa_assert(m);
3788
3789     pa_log_info("Initialization for IPC");
3790 #ifdef HAVE_DBUS
3791     if ((init_sm_dbus(m)))
3792       return -1;
3793 #else
3794     pa_log_error("DBUS is not supported");
3795     return -1
3796 #endif
3797     return 0;
3798 }
3799
3800 static void deinit_ipc(pa_stream_manager *m) {
3801     pa_assert(m);
3802
3803 #ifdef HAVE_DBUS
3804     deinit_sm_dbus(m);
3805 #endif
3806 }
3807
3808 bool pa_stream_manager_check_name_is_vstream(void *stream, stream_type_t type, bool is_new_data) {
3809     return check_name_is_vstream(stream, type, is_new_data);
3810 }
3811
3812 int32_t pa_stream_manager_get_route_type(void *stream, stream_type_t stream_type, bool is_new_data, stream_route_type_t *stream_route_type) {
3813     return get_route_type(stream, stream_type, is_new_data, stream_route_type);
3814 }
3815
3816 int32_t pa_stream_manager_get_preemptive_device_id(pa_stream_manager *m, stream_type_t stream_type, const char *role, uint32_t *id) {
3817     stream_info *s = NULL;
3818
3819     pa_assert(m);
3820     pa_assert(role);
3821     pa_assert(id);
3822
3823     if (!(s = pa_hashmap_get(m->stream_infos, role))) {
3824         pa_log_warn("%s is not valid role, return false", role);
3825         return -1;
3826     }
3827
3828     if (s->preemptive_device[stream_type == STREAM_SINK_INPUT ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN].type) {
3829         *id = s->preemptive_device[stream_type == STREAM_SINK_INPUT ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN].id;
3830         return 0;
3831     }
3832
3833     return -1;
3834 }
3835
3836 bool pa_stream_manager_check_filter_apply_stream(void *stream, stream_type_t stream_type) {
3837     return is_filter_apply_stream(stream, stream_type);
3838 }
3839
3840 bool pa_stream_manager_is_valid_stream_role(pa_core *c, const char *role) {
3841     pa_stream_manager *m;
3842
3843     pa_assert(c);
3844     pa_assert(role);
3845
3846     if (!(m = pa_shared_get(c, SHARED_STREAM_MANAGER))) {
3847         pa_log_error("could not get shared data");
3848         return false;
3849     }
3850     if (!pa_hashmap_get(m->stream_infos, role)) {
3851         pa_log_error("%s is not valid role", role);
3852         return false;
3853     }
3854
3855     return true;
3856 }
3857
3858 const char* pa_stream_manager_get_volume_type(pa_stream_manager *m, stream_type_t stream_type, const char *role) {
3859     stream_info *s = NULL;
3860
3861     pa_assert(m);
3862     pa_assert(role);
3863
3864     if (!(s = pa_hashmap_get(m->stream_infos, role))) {
3865         pa_log_warn("%s is not valid role, return NULL", role);
3866         return NULL;
3867     }
3868
3869     return s->volume_types[stream_type == STREAM_SINK_INPUT ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN];
3870 }
3871
3872 static int stream_manager_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
3873     struct stream_manager_param *param = (struct stream_manager_param *)data;
3874
3875     pa_assert(param);
3876     pa_assert(param->m);
3877     pa_assert(param->m->core);
3878
3879     pa_log_info("code(%d), sink-input(%p, index:%u)", code, param->sink_input, param->index);
3880
3881     if (param->m->core->state == PA_CORE_SHUTDOWN)
3882         return 0;
3883
3884     switch (code) {
3885         case MESSAGE_RAMP_FINISHED:
3886             process_ramp_finish(param);
3887             break;
3888
3889         default:
3890             pa_assert_not_reached();
3891     }
3892
3893     return 0;
3894 }
3895
3896 pa_stream_manager* pa_stream_manager_get(pa_core *c) {
3897     pa_stream_manager *m;
3898
3899     pa_assert(c);
3900
3901     pa_log_debug("pa_stream_manager_get");
3902
3903     if ((m = pa_shared_get(c, SHARED_STREAM_MANAGER)))
3904         return pa_stream_manager_ref(m);
3905
3906     m = pa_xnew0(pa_stream_manager, 1);
3907     PA_REFCNT_INIT(m);
3908     m->core = c;
3909
3910     m->rtpoll = pa_rtpoll_new();
3911     if (pa_thread_mq_init(&m->thread_mq, m->core->mainloop, m->rtpoll) < 0) {
3912         pa_log("pa_thread_mq_init() failed.");
3913         goto fail;
3914     }
3915     m->msg = pa_msgobject_new(stream_manager_msg);
3916     m->msg->parent.process_msg = stream_manager_process_msg;
3917
3918     if (!(m->hal = pa_hal_interface_get(c)))
3919         goto fail;
3920
3921     if (pa_hal_interface_add_message_callback(m->hal, message_cb_func, m))
3922         pa_log_warn("skip adding message callback");
3923     m->dm = pa_device_manager_get(c);
3924     m->subs_ob = pa_subscribe_observer_get(c);
3925 #ifdef HAVE_DBUS
3926 #ifdef USE_DBUS_PROTOCOL
3927     m->dbus_protocol = NULL;
3928 #else
3929     m->dbus_conn = NULL;
3930 #endif
3931 #endif
3932     if (init_ipc(m))
3933         goto fail;
3934     if (init_stream_map(m))
3935         goto fail;
3936     if (init_volumes(m))
3937         goto fail;
3938     init_filters(m);
3939     m->stream_parents = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3940     m->muted_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3941 #ifndef __TIZEN_TV_EXTERNAL_TV_SOURCE__
3942     m->mirroring_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3943 #endif
3944     m->stream_duckings = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
3945
3946     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);
3947     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);
3948     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);
3949     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);
3950     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);
3951     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);
3952     m->sink_input_ramp_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_RAMP_FINISH], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_ramp_finish_cb, m);
3953     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);
3954     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);
3955     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);
3956     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);
3957     m->source_output_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_start_cb, m);
3958     m->source_output_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_finish_cb, m);
3959
3960     m->remote_sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) remote_client_put_cb, m);
3961     m->remote_sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) remote_client_unlink_cb, m);
3962     m->remote_source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) remote_client_put_cb, m);
3963     m->remote_source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_NORMAL, (pa_hook_cb_t) remote_client_unlink_cb, m);
3964
3965     m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, (pa_subscription_cb_t)subscribe_cb, m);
3966
3967     m->comm.comm = pa_communicator_get(c);
3968     m->comm.comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
3969             PA_HOOK_EARLY + 10, (pa_hook_cb_t)device_connection_changed_hook_cb, m);
3970     m->comm.comm_hook_event_fully_handled_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_EVENT_FULLY_HANDLED),
3971             PA_HOOK_EARLY + 10, (pa_hook_cb_t)event_fully_handled_hook_cb, m);
3972
3973     set_initial_active_device(m);
3974
3975     pa_shared_set(c, SHARED_STREAM_MANAGER, m);
3976
3977     return m;
3978
3979 fail:
3980     pa_log_error("failed to initialize stream-manager");
3981
3982     pa_thread_mq_done(&m->thread_mq);
3983     pa_rtpoll_free(m->rtpoll);
3984     pa_xfree(m->msg);
3985
3986     deinit_volumes(m);
3987     deinit_stream_map(m);
3988     deinit_filters(m);
3989     deinit_ipc(m);
3990     if (m->hal) {
3991         pa_hal_interface_remove_message_callback(m->hal, message_cb_func);
3992         pa_hal_interface_unref(m->hal);
3993     }
3994     if (m->dm)
3995         pa_device_manager_unref(m->dm);
3996     if (m->subs_ob)
3997         pa_subscribe_observer_unref(m->subs_ob);
3998     pa_xfree(m);
3999     return 0;
4000 }
4001
4002 pa_stream_manager* pa_stream_manager_ref(pa_stream_manager *m) {
4003     pa_assert(m);
4004     pa_assert(PA_REFCNT_VALUE(m) > 0);
4005
4006     PA_REFCNT_INC(m);
4007     pa_log_info("pa_stream_manager_ref to %d", PA_REFCNT_VALUE(m));
4008
4009     return m;
4010 }
4011
4012 static void free_hook_slots(pa_stream_manager *m) {
4013     pa_assert(m);
4014
4015     if (m->comm.comm_hook_device_connection_changed_slot)
4016         pa_hook_slot_free(m->comm.comm_hook_device_connection_changed_slot);
4017     if (m->comm.comm_hook_event_fully_handled_slot)
4018         pa_hook_slot_free(m->comm.comm_hook_event_fully_handled_slot);
4019     if (m->sink_input_new_slot)
4020         pa_hook_slot_free(m->sink_input_new_slot);
4021     if (m->sink_input_put_slot)
4022         pa_hook_slot_free(m->sink_input_put_slot);
4023     if (m->remote_sink_input_put_slot)
4024         pa_hook_slot_free(m->remote_sink_input_put_slot);
4025     if (m->sink_input_unlink_slot)
4026         pa_hook_slot_free(m->sink_input_unlink_slot);
4027     if (m->remote_sink_input_unlink_slot)
4028         pa_hook_slot_free(m->remote_sink_input_unlink_slot);
4029     if (m->sink_input_state_changed_slot)
4030         pa_hook_slot_free(m->sink_input_state_changed_slot);
4031     if (m->sink_input_move_start_slot)
4032         pa_hook_slot_free(m->sink_input_move_start_slot);
4033     if (m->sink_input_move_finish_slot)
4034         pa_hook_slot_free(m->sink_input_move_finish_slot);
4035     if (m->sink_input_ramp_finish_slot)
4036         pa_hook_slot_free(m->sink_input_ramp_finish_slot);
4037
4038     if (m->source_output_new_slot)
4039         pa_hook_slot_free(m->source_output_new_slot);
4040     if (m->source_output_put_slot)
4041         pa_hook_slot_free(m->source_output_put_slot);
4042     if (m->remote_source_output_put_slot)
4043         pa_hook_slot_free(m->remote_source_output_put_slot);
4044     if (m->source_output_unlink_slot)
4045         pa_hook_slot_free(m->source_output_unlink_slot);
4046     if (m->remote_source_output_unlink_slot)
4047         pa_hook_slot_free(m->remote_source_output_unlink_slot);
4048     if (m->source_output_state_changed_slot)
4049         pa_hook_slot_free(m->source_output_state_changed_slot);
4050     if (m->source_output_move_start_slot)
4051         pa_hook_slot_free(m->source_output_move_start_slot);
4052     if (m->source_output_move_finish_slot)
4053         pa_hook_slot_free(m->source_output_move_finish_slot);
4054 }
4055
4056 void pa_stream_manager_unref(pa_stream_manager *m) {
4057     void *state;
4058     pa_idxset *streams;
4059
4060     pa_assert(m);
4061     pa_assert(PA_REFCNT_VALUE(m) > 0);
4062
4063     pa_log_info("pa_stream_manager_unref to %d", PA_REFCNT_VALUE(m) - 1);
4064     if (PA_REFCNT_DEC(m) > 0)
4065         return;
4066
4067     pa_thread_mq_done(&m->thread_mq);
4068     pa_rtpoll_free(m->rtpoll);
4069     pa_xfree(m->msg);
4070
4071     free_hook_slots(m);
4072
4073     if (m->comm.comm)
4074         pa_communicator_unref(m->comm.comm);
4075
4076     if (m->subscription)
4077         pa_subscription_free(m->subscription);
4078
4079     if (m->muted_streams) {
4080         PA_HASHMAP_FOREACH(streams, m->muted_streams, state)
4081             pa_idxset_free(streams, NULL);
4082         pa_hashmap_free(m->muted_streams);
4083     }
4084
4085 #ifndef __TIZEN_TV_EXTERNAL_TV_SOURCE__
4086     if (m->mirroring_streams) {
4087         if (pa_idxset_size(m->mirroring_streams))
4088             update_forwarding_device(m, false);
4089         pa_idxset_free(m->mirroring_streams, NULL);
4090     }
4091 #endif
4092
4093     if (m->stream_parents)
4094         pa_hashmap_free(m->stream_parents);
4095
4096     if (m->stream_duckings)
4097         pa_hashmap_free(m->stream_duckings);
4098
4099     deinit_volumes(m);
4100     deinit_stream_map(m);
4101     deinit_ipc(m);
4102     deinit_filters(m);
4103
4104     if (m->subs_ob)
4105         pa_subscribe_observer_unref(m->subs_ob);
4106
4107     if (m->dm)
4108         pa_device_manager_unref(m->dm);
4109
4110     if (m->hal) {
4111         pa_hal_interface_remove_message_callback(m->hal, message_cb_func);
4112         pa_hal_interface_unref(m->hal);
4113     }
4114
4115     pa_shared_remove(m->core, SHARED_STREAM_MANAGER);
4116
4117     pa_xfree(m);
4118 }