tizenaudio-policy: Support to open Bluetooth SCO link with voice-recognition role
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / module-tizenaudio-policy.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2013-2016 Seungbae Shin, Sangchul Lee, Jeongho Mok
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 <stdbool.h>
27 #include <strings.h>
28 #include <vconf.h> // for mono
29 #include <iniparser.h>
30 #include <unistd.h>
31 #include <pthread.h>
32
33 #include <pulse/proplist.h>
34 #include <pulse/timeval.h>
35 #include <pulse/util.h>
36 #include <pulse/rtclock.h>
37
38 #include <pulsecore/core.h>
39 #include <pulsecore/module.h>
40 #include <pulsecore/modargs.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/core-rtclock.h>
43 #include <pulsecore/core-scache.h>
44 #include <pulsecore/core-subscribe.h>
45 #include <pulsecore/core-util.h>
46 #include <pulsecore/mutex.h>
47 #include <pulsecore/log.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/sink-input.h>
50 #include <pulsecore/source-output.h>
51 #include <pulsecore/pstream-util.h>
52 #include <pulsecore/strbuf.h>
53 #include <pulsecore/sink-input.h>
54 #include <pulsecore/sound-file.h>
55 #include <pulsecore/play-memblockq.h>
56 #include <pulsecore/shared.h>
57
58 #include "module-tizenaudio-policy-symdef.h"
59 #include "communicator.h"
60 #include "hal-interface.h"
61 #include "stream-manager.h"
62 #include "device-manager.h"
63
64 PA_MODULE_AUTHOR("Seungbae Shin, Sangchul Lee, Jeongho Mok");
65 PA_MODULE_DESCRIPTION("Tizen Audio Policy module");
66 PA_MODULE_VERSION(PACKAGE_VERSION);
67 PA_MODULE_LOAD_ONCE(true);
68 PA_MODULE_USAGE(" ");
69
70 static const char* const valid_modargs[] = {
71     NULL
72 };
73
74 struct userdata;
75
76 /* Modules for dynamic loading */
77 #define MODULE_COMBINE_SINK           "module-combine-sink"
78 #define MODULE_NULL_SINK              "module-null-sink"
79 #define MODULE_NULL_SOURCE            "module-null-source"
80 #define MODULE_LOOPBACK               "module-loopback"
81
82 /* Name of combine sink for external route type */
83 #define SINK_NAME_COMBINED_EX         SINK_NAME_COMBINED"_ex"
84
85 /* Default values */
86 #define LOOPBACK_DEFAULT_LATENCY_MSEC    40
87 #define LOOPBACK_DEFAULT_ADJUST_SEC      3
88
89 #define TIMED_BT_SCO_CLOSE_USEC          3000000
90
91 /* Macros */
92 #define CONVERT_TO_HAL_DIRECTION(stream_type) \
93     ((stream_type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN)
94 #define CONVERT_TO_DEVICE_DIRECTION(stream_type) \
95     ((stream_type == STREAM_SINK_INPUT) ? DM_DEVICE_DIRECTION_OUT : DM_DEVICE_DIRECTION_IN)
96 #define IS_AVAILABLE_DIRECTION(stream_type, device_direction) \
97     ((stream_type == STREAM_SINK_INPUT) ? (device_direction & DM_DEVICE_DIRECTION_OUT) : (device_direction & DM_DEVICE_DIRECTION_IN))
98
99 /* PCM Dump */
100 #define PA_DUMP_INI_DEFAULT_PATH                SYSCONFDIR"/multimedia/mmfw_audio_pcm_dump.ini" /* SYSCONFDIR is defined at .spec */
101 #define PA_DUMP_INI_TEMP_PATH                   "/home/owner/media/mmfw_audio_pcm_dump.ini"
102 #define PA_DUMP_VCONF_KEY                       "memory/private/sound/pcm_dump"
103
104 typedef enum _device_type {
105     DEVICE_BUILTIN_SPEAKER,
106     DEVICE_BUILTIN_RECEIVER,
107     DEVICE_BUILTIN_MIC,
108     DEVICE_AUDIO_JACK,
109     DEVICE_BT_A2DP,
110     DEVICE_BT_SCO,
111     DEVICE_HDMI,
112     DEVICE_FORWARDING,
113     DEVICE_USB_AUDIO,
114     DEVICE_UNKNOWN,
115     DEVICE_MAX,
116 } device_type_t;
117
118 enum {
119     CACHED_DEVICE_DIRECTION_IN,
120     CACHED_DEVICE_DIRECTION_OUT,
121     CACHED_DEVICE_DIRECTION_MAX,
122 };
123
124 int cached_connected_devices[DEVICE_MAX][CACHED_DEVICE_DIRECTION_MAX];
125
126 static device_type_t convert_device_type_str(const char *device)
127 {
128     if (pa_streq(device, DEVICE_TYPE_SPEAKER))
129         return DEVICE_BUILTIN_SPEAKER;
130     else if (pa_streq(device, DEVICE_TYPE_RECEIVER))
131         return DEVICE_BUILTIN_RECEIVER;
132     else if (pa_streq(device, DEVICE_TYPE_MIC))
133         return DEVICE_BUILTIN_MIC;
134     else if (pa_streq(device, DEVICE_TYPE_AUDIO_JACK))
135         return DEVICE_AUDIO_JACK;
136     else if (pa_streq(device, DEVICE_TYPE_BT_A2DP))
137         return DEVICE_BT_A2DP;
138     else if (pa_streq(device, DEVICE_TYPE_BT_SCO))
139         return DEVICE_BT_SCO;
140     else if (pa_streq(device, DEVICE_TYPE_HDMI))
141         return DEVICE_HDMI;
142     else if (pa_streq(device, DEVICE_TYPE_FORWARDING))
143         return DEVICE_FORWARDING;
144     else if (pa_streq(device, DEVICE_TYPE_USB_AUDIO))
145         return DEVICE_USB_AUDIO;
146
147     pa_log_warn("unknown device (%s)", device);
148     return DEVICE_UNKNOWN;
149 }
150
151 struct userdata {
152     pa_core *core;
153     pa_module *module;
154
155     struct {
156         pa_communicator *comm;
157         pa_hook_slot *comm_hook_select_proper_sink_or_source_slot;
158         pa_hook_slot *comm_hook_change_route_slot;
159         pa_hook_slot *comm_hook_device_connection_changed_slot;
160         pa_hook_slot *comm_hook_update_info_slot;
161     } communicator;
162
163     pa_hal_interface *hal_interface;
164     pa_stream_manager *stream_manager;
165     pa_device_manager *device_manager;
166
167     pa_module *module_combine_sink;
168     pa_module *module_combine_sink_for_ex;
169     pa_module *module_null_sink;
170     pa_module *module_null_source;
171     pa_module *module_loopback;
172     struct {
173         int32_t latency_msec;
174         int32_t adjust_sec;
175         pa_sink *sink;
176         pa_source *source;
177     } loopback_args;
178     pa_time_event *time_event_bt_sco_close;
179 };
180
181 static void __load_dump_config(struct userdata *u)
182 {
183     dictionary * dict = NULL;
184     int vconf_dump = 0;
185
186     dict = iniparser_load(PA_DUMP_INI_DEFAULT_PATH);
187     if (!dict) {
188         pa_log_debug("%s load failed. Use temporary file", PA_DUMP_INI_DEFAULT_PATH);
189         dict = iniparser_load(PA_DUMP_INI_TEMP_PATH);
190         if (!dict) {
191             pa_log_warn("%s load failed", PA_DUMP_INI_TEMP_PATH);
192             return;
193         }
194     }
195
196     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:decoder_out", 0) ? PA_PCM_DUMP_GST_DECODER_OUT : 0;
197     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:resampler_in", 0) ? PA_PCM_DUMP_GST_RESAMPLER_IN : 0;
198     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:resampler_out", 0) ? PA_PCM_DUMP_GST_RESAMPLER_OUT : 0;
199     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:gst_audio_sink", 0) ? PA_PCM_DUMP_GST_AUDIO_SINK_IN : 0;
200     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:pa_stream_write", 0) ? PA_PCM_DUMP_PA_STREAM_WRITE : 0;
201     u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_sink_input", 0) ? PA_PCM_DUMP_PA_SINK_INPUT : 0;
202     u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_sink", 0) ? PA_PCM_DUMP_PA_SINK : 0;
203     u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_source", 0) ? PA_PCM_DUMP_PA_SOURCE : 0;
204     u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_source_output", 0) ? PA_PCM_DUMP_PA_SOURCE_OUTPUT : 0;
205     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:pa_stream_read", 0) ? PA_PCM_DUMP_PA_STREAM_READ : 0;
206     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:gst_audio_src", 0) ? PA_PCM_DUMP_GST_AUDIO_SRC_OUT : 0;
207     vconf_dump |= iniparser_getboolean(dict, "pcm_dump:encoder_in", 0) ? PA_PCM_DUMP_GST_ENCODER_IN : 0;
208
209     iniparser_freedict(dict);
210
211     if (vconf_set_int(PA_PCM_DUMP_VCONF_KEY, vconf_dump)) {
212         pa_log_warn("vconf_set_int %s=%x failed", PA_PCM_DUMP_VCONF_KEY, vconf_dump);
213     }
214 }
215
216 /* threre is only one sco connected device */
217 static pa_tz_device* _get_sco_connected_device(pa_device_manager *dm) {
218     pa_idxset *device_list;
219     pa_tz_device *device;
220     uint32_t device_idx;
221
222     pa_assert(dm);
223
224     device_list = pa_device_manager_get_device_list(dm);
225
226     PA_IDXSET_FOREACH(device, device_list, device_idx) {
227         if (pa_streq(device->type, DEVICE_TYPE_BT_SCO)) {
228             return device;
229         }
230     }
231     return NULL;
232 }
233
234 static bool is_bt_sco_opened(pa_device_manager *dm) {
235     dm_device_bt_sco_status_t sco_status;
236     pa_tz_device *bt_device;
237
238     pa_assert(dm);
239
240     bt_device = _get_sco_connected_device(dm);
241     if (bt_device == NULL) {
242         pa_log_debug("No SCO connected bt device");
243         return false;
244     }
245     if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
246         pa_log_error("get BT SCO status failed");
247         return false;
248     }
249     if (sco_status != DM_DEVICE_BT_SCO_STATUS_OPENED) {
250         pa_log_error("SCO is not opened");
251         return false;
252     }
253     pa_log_info("SCO is opened");
254
255     return true;
256 }
257
258 static void timed_bt_sco_close_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
259     struct userdata *u = userdata;
260     pa_tz_device *bt_device;
261     dm_device_bt_sco_status_t sco_status;
262
263     pa_assert(u);
264     pa_assert(u->time_event_bt_sco_close == e);
265
266     pa_log_info("timed_bt_sco_close_cb is called");
267
268     u->core->mainloop->time_free(u->time_event_bt_sco_close);
269     u->time_event_bt_sco_close = NULL;
270
271     bt_device = _get_sco_connected_device(u->device_manager);
272     if (bt_device == NULL) {
273         pa_log_debug("No SCO connected bt device");
274         return;
275     }
276     if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
277         pa_log_error("get BT SCO status failed");
278         return;
279     }
280     if (pa_tz_device_sco_close(bt_device) < 0) {
281         pa_log_error("BT SCO was opened, but failed to close SCO");
282         return;
283     }
284     pa_log_info("BT SCO is now closed in timed callback");
285 }
286
287
288 static int bt_sco_open(struct userdata *u) {
289     dm_device_bt_sco_status_t sco_status;
290     pa_tz_device *bt_device;
291
292     pa_assert(u);
293
294     if (u->time_event_bt_sco_close) {
295         u->core->mainloop->time_free(u->time_event_bt_sco_close);
296         u->time_event_bt_sco_close = NULL;
297     }
298
299     bt_device = _get_sco_connected_device(u->device_manager);
300     if (bt_device == NULL) {
301         pa_log_debug("No SCO connected bt device");
302         return 0;
303     }
304     pa_log_info("Got BT SCO connected device(%u)", bt_device->id);
305
306     if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
307         pa_log_error("get BT SCO status failed");
308         return -1;
309     }
310     if (sco_status == DM_DEVICE_BT_SCO_STATUS_OPENED) {
311         pa_log_warn("BT SCO is already opened for this BT device");
312         return 0;
313     }
314     if (pa_tz_device_sco_open(bt_device) < 0) {
315         pa_log_error("failed to open BT SCO");
316         return -1;
317     }
318     pa_log_debug("BT SCO is now opened");
319
320     return 0;
321 }
322
323 static int bt_sco_close(struct userdata *u, bool delayed_close) {
324     dm_device_bt_sco_status_t sco_status;
325     pa_tz_device *bt_device;
326
327     pa_assert(u);
328
329     bt_device = _get_sco_connected_device(u->device_manager);
330     if (bt_device == NULL) {
331         pa_log_debug("No SCO connected bt device");
332         return 0;
333     }
334     pa_log_info("Got BT SCO connected device(%u)", bt_device->id);
335
336     if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
337         pa_log_error("get BT SCO status failed");
338         return -1;
339     }
340     if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED) {
341         pa_log_warn("BT SCO is already closed for this BT device");
342         return 0;
343     }
344     if (delayed_close) {
345         /* request to close SCO after 3 sec. */
346         if (!u->time_event_bt_sco_close) {
347             u->time_event_bt_sco_close = pa_core_rttime_new(u->core, pa_rtclock_now() + TIMED_BT_SCO_CLOSE_USEC, timed_bt_sco_close_cb, u);
348             pa_log_debug("Append time event to close BT SCO");
349         }
350     } else {
351         if (u->time_event_bt_sco_close) {
352             u->core->mainloop->time_free(u->time_event_bt_sco_close);
353             u->time_event_bt_sco_close = NULL;
354         }
355         if (pa_tz_device_sco_close(bt_device) < 0) {
356             pa_log_error("BT SCO was opened, but failed to close SCO");
357             return -1;
358         }
359         pa_log_debug("BT SCO is now closed");
360     }
361
362     return 0;
363 }
364
365 /* Open/Close BT SCO if it is possible */
366 static int update_bt_sco_state(struct userdata *u, bool open, bool delayed_close) {
367     pa_assert(u);
368
369     if (open)
370         return bt_sco_open(u);
371     else
372         return bt_sco_close(u, delayed_close);
373 }
374
375 static int get_bt_property(pa_device_manager *dm, bool *is_wb, bool *is_nrec) {
376     dm_device_bt_sco_status_t sco_status;
377     pa_tz_device *bt_device;
378
379     pa_assert(dm);
380     pa_assert(is_wb);
381     pa_assert(is_nrec);
382
383     bt_device = _get_sco_connected_device(dm);
384     if (bt_device == NULL) {
385         pa_log_error("No SCO connected bt device");
386         return -1;
387     }
388     if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
389         pa_log_error("get BT SCO status failed");
390         return -1;
391     }
392
393     pa_log_info("Got BT SCO connected device(%u), status(%d)", bt_device->id, sco_status);
394     if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED)
395         return -1;
396
397     return pa_tz_device_sco_get_property(bt_device, is_wb, is_nrec);
398 }
399
400 /* Load/Unload module-loopback */
401 static void update_loopback_module(struct userdata *u, bool load) {
402     char *args = NULL;
403
404     pa_assert(u);
405
406     if (load && u->loopback_args.sink && u->loopback_args.source) {
407         if (!u->loopback_args.latency_msec)
408             u->loopback_args.latency_msec = LOOPBACK_DEFAULT_LATENCY_MSEC;
409         if (!u->loopback_args.adjust_sec)
410             u->loopback_args.adjust_sec = LOOPBACK_DEFAULT_ADJUST_SEC;
411
412         args = pa_sprintf_malloc("sink=%s source=%s latency_msec=%d adjust_time=%d",
413                                  u->loopback_args.sink->name, u->loopback_args.source->name,
414                                  u->loopback_args.latency_msec, u->loopback_args.adjust_sec);
415         if (u->module_loopback)
416             pa_module_unload(u->core, u->module_loopback, true);
417
418         u->module_loopback = pa_module_load(u->core, MODULE_LOOPBACK, args);
419
420         pa_log_info("  -- load module-loopback with (%s)", args);
421         pa_xfree(args);
422
423     } else if (!load) {
424         if (u->module_loopback) {
425             pa_module_unload(u->core, u->module_loopback, true);
426             u->module_loopback = NULL;
427             u->loopback_args.sink = NULL;
428             u->loopback_args.source = NULL;
429             pa_log_info("  -- unload module-loopback");
430         }
431     } else {
432         pa_log_error("  -- failed to update loopback module");
433     }
434 }
435
436 static void unload_combine_sink_module(struct userdata *u, const char *combine_sink_name, pa_sink *dst_sink)
437 {
438     pa_module **combine_sink_module = NULL;
439     pa_sink *combine_sink = NULL;
440     pa_sink_input *s = NULL;
441     uint32_t idx = 0;
442
443     pa_assert(u);
444     pa_assert(combine_sink_name);
445     pa_assert(dst_sink);
446
447     if (pa_streq(combine_sink_name, SINK_NAME_COMBINED)) {
448         combine_sink_module = &u->module_combine_sink;
449     } else if (pa_streq(combine_sink_name, SINK_NAME_COMBINED_EX)) {
450         combine_sink_module = &u->module_combine_sink_for_ex;
451     } else {
452         pa_log_error("unknown combine_sink_name(%s)", combine_sink_name);
453         return;
454     }
455
456     if (*combine_sink_module) {
457         combine_sink = (pa_sink*)pa_namereg_get(u->core, combine_sink_name, PA_NAMEREG_SINK);
458         if (!combine_sink)
459             pa_log_error("could not get combine_sink(%s)", combine_sink_name);
460         else {
461             PA_IDXSET_FOREACH(s, combine_sink->inputs, idx) {
462                 pa_sink_input_move_to(s, dst_sink, false);
463                 pa_log_info("[UNLOAD COMBINE SINK MODULE] *** sink-input(%p,%u) of (%s) moves to another sink(%p,%s)",
464                              s, ((pa_sink_input*)s)->index, combine_sink_name, dst_sink, dst_sink->name);
465             }
466             pa_sink_suspend(combine_sink, true, PA_SUSPEND_USER);
467         }
468         pa_log_info("unload combine sink module[%s]", combine_sink_name);
469         pa_module_unload(u->core, *combine_sink_module, true);
470         *combine_sink_module = NULL;
471     } else
472         pa_log_warn("module combine sink(%s) has been already unloaded", combine_sink_name);
473 }
474
475 static bool skip_device(const char *stream_role, const char *device_type)
476 {
477     int sound_on = 1;
478
479     if (pa_streq(device_type, DEVICE_TYPE_FORWARDING))
480         return true;
481
482     /* get sound profile */
483     if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sound_on) < 0) {
484         pa_log_error("failed to get vconf - sound status");
485         return false;
486     }
487
488     if (!sound_on && IS_ROLE_RINGTONE(stream_role) && pa_streq(device_type, DEVICE_TYPE_SPEAKER)) {
489         pa_log_info("sound status is 0 with ringtone-call stream, skip built-in speaker");
490         return true;
491     }
492
493     return false;
494 }
495
496 static bool skip_bt_sco_device(struct userdata *u, const char *stream_role, const char *device_type) {
497     pa_assert(u);
498     pa_assert(stream_role);
499     pa_assert(device_type);
500
501     if (pa_streq(stream_role, STREAM_ROLE_VOICE_INFORMATION) && pa_streq(device_type, DEVICE_TYPE_BT_SCO)) {
502         if (is_bt_sco_opened(u->device_manager)) {
503             /* remove the request of closing SCO */
504             if (u->time_event_bt_sco_close) {
505                 u->core->mainloop->time_free(u->time_event_bt_sco_close);
506                 u->time_event_bt_sco_close = NULL;
507             }
508             pa_log_info("It is VOICE_INFORMATION, BT SCO is already opened, do not skip this device");
509             return false;
510         } else {
511             pa_log_info("It is VOICE_INFORMATION, BT SCO is not opened, skip this device");
512             return true;
513         }
514     }
515
516     return false;
517 }
518
519 static inline bool is_cached_device_connected(const char* device_type, stream_type_t stream_type) {
520     if (cached_connected_devices[convert_device_type_str(device_type)][CONVERT_TO_DEVICE_DIRECTION(stream_type)-1] > 0)
521         return true;
522     return false;
523 }
524
525 /* Set the proper sink(source) according to the data of the parameter.
526  * - ROUTE_TYPE_AUTO(_ALL)
527  *     1. Find the proper sink/source comparing between avail_devices
528  *       and current connected devices.
529  *     2. If not found, set it to null sink/source.
530  * - ROUTE_TYPE_MANUAL(_EXT)
531  *     1. Find the proper sink/source comparing between avail_devices
532  *        and manual_devices that have been set by user.
533  *     2. If not found, set it to null sink/source. */
534 static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_select *data, struct userdata *u) {
535     uint32_t idx = 0;
536     uint32_t m_idx = 0;
537     uint32_t conn_idx = 0;
538     uint32_t *device_id = NULL;
539     uint32_t dm_device_id = 0;
540     const char *device_type = NULL;
541     const char *dm_device_type = NULL;
542     dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
543     pa_tz_device *device = NULL;
544     pa_idxset *conn_devices = NULL;
545     pa_sink *sink = NULL;
546     pa_sink *null_sink = NULL;
547     pa_sink *combine_sink_arg1 = NULL;
548     pa_sink *combine_sink_arg2 = NULL;
549     pa_source *source = NULL;
550     pa_source *null_source = NULL;
551     void *s = NULL;
552
553     pa_assert(c);
554     pa_assert(data);
555     pa_assert(u);
556
557     pa_log_info("[SELECT] select_proper_sink_or_source_hook_cb is called. (%p), stream_type(%d), stream_role(%s), device_role(%s), route_type(%d)",
558                 data, data->stream_type, data->stream_role, data->device_role, data->route_type);
559
560     null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
561     null_source = (pa_source*)pa_namereg_get(u->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE);
562     if (!null_sink || !null_source) {
563         pa_log_error("[SELECT] could not get null_sink(%p) or null_source(%p)", null_sink, null_source);
564         return PA_HOOK_OK;
565     }
566
567     /* check if the current occupying role is related to call.
568      * some targets use several pcm card as per their purpose.
569      * e.g) using a specific pcm card during voice call. */
570     if (data->occupying_role) {
571         if (IS_ROLE_COMMUNICATION(data->occupying_role)) {
572             CONVERT_TO_DEVICE_ROLE(data->occupying_role, data->device_role);
573             pa_log_info("[SELECT] current occupying stream role is [%s], set device role to [%s]", data->occupying_role, data->device_role);
574         }
575     }
576
577     if (!data->idx_avail_devices) {
578         pa_log_error("[SELECT] available devices is NULL, set it to null sink/source");
579         goto not_found;
580     }
581
582     if (IS_MANUAL_ROUTE_TYPE_SERIES(data->route_type) && !data->idx_manual_devices) {
583         pa_log_error("[SELECT] manual devices is NULL, set it to null sink/source");
584         goto not_found;
585     }
586
587     if (IS_AUTO_ROUTE_TYPE_SERIES(data->route_type)) {
588         /* get current connected devices */
589         conn_devices = pa_device_manager_get_device_list(u->device_manager);
590         if (data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
591             PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
592                 pa_log_debug("[SELECT][AUTO(_ALL)] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
593                 if (!is_cached_device_connected(device_type, data->stream_type))
594                     continue;
595                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
596                     dm_device_type = pa_tz_device_get_type(device);
597                     dm_device_direction = pa_tz_device_get_direction(device);
598                     dm_device_id = pa_tz_device_get_id(device);
599                     pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u]",
600                                  dm_device_type, dm_device_direction, dm_device_id);
601                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
602                         pa_log_info("  ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
603                         if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
604                             continue;
605
606                         if (data->stream_type == STREAM_SINK_INPUT) {
607                             if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL && u->module_combine_sink) {
608                                 *(data->proper_sink) = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
609                                 pa_log_info("  -- found the combine-sink, set it to the sink");
610                             } else
611                                 *(data->proper_sink) = pa_tz_device_get_sink(device, data->device_role);
612                         } else
613                             *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
614
615                         if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
616                             pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
617                             return PA_HOOK_OK;
618                         }
619                     }
620                 }
621             }
622         } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
623             pa_tz_device *latest_device = NULL;
624             pa_usec_t creation_time = 0;
625             pa_usec_t latest_creation_time = 0;
626
627             PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
628                 pa_log_debug("[SELECT][AUTO_LAST_CONN] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
629                 if (!is_cached_device_connected(device_type, data->stream_type))
630                     continue;
631                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
632                     dm_device_type = pa_tz_device_get_type(device);
633                     dm_device_direction = pa_tz_device_get_direction(device);
634                     dm_device_id = pa_tz_device_get_id(device);
635                     creation_time = pa_tz_device_get_creation_time(device);
636                     pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u], creation_time[%llu]",
637                                  dm_device_type, dm_device_direction, dm_device_id, creation_time);
638                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
639                         if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
640                             continue;
641
642                         if (!latest_device || (latest_creation_time <= creation_time)) {
643                             latest_device = device;
644                             latest_creation_time = creation_time;
645                             pa_log_info("  ** updated the last connected device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
646                         }
647                     }
648                 }
649             }
650             /* update active device info. */
651             if (latest_device) {
652                 if (data->stream_type == STREAM_SINK_INPUT)
653                     *(data->proper_sink) = pa_tz_device_get_sink(latest_device, data->device_role);
654                 else
655                     *(data->proper_source) = pa_tz_device_get_source(latest_device, data->device_role);
656
657                 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, pa_tz_device_get_type(latest_device));
658             }
659         }
660
661     } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL) {
662         PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
663             pa_log_info("[SELECT][MANUAL] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
664             if (!is_cached_device_connected(device_type, data->stream_type))
665                 continue;
666             PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
667                 if (!(device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
668                     continue;
669                 dm_device_type = pa_tz_device_get_type(device);
670                 dm_device_direction = pa_tz_device_get_direction(device);
671                 pa_log_debug("  -- type[%-16s], direction[0x%x], device id[%u]",
672                              dm_device_type, dm_device_direction, *device_id);
673                 if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
674                     pa_log_info("  ** found a matched device: type[%-16s], direction[0x%x]", device_type, dm_device_direction);
675                     if (data->stream_type == STREAM_SINK_INPUT) {
676                         if ((*(data->proper_sink)) == null_sink)
677                             pa_sink_input_move_to((pa_sink_input*)(data->stream), pa_tz_device_get_sink(device, data->device_role), false);
678                         else
679                             *(data->proper_sink) = pa_tz_device_get_sink(device, data->device_role);
680                     } else {
681                         if ((*(data->proper_source)) == null_source)
682                             pa_source_output_move_to((pa_source_output*)(data->stream), pa_tz_device_get_source(device, data->device_role), false);
683                         else
684                             *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
685                     }
686                 }
687             }
688         }
689
690     } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
691         PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
692             pa_log_info("[SELECT][MANUAL_EXT] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
693             if (!is_cached_device_connected(device_type, data->stream_type))
694                 continue;
695             PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
696                 if (!(device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
697                     continue;
698                 dm_device_type = pa_tz_device_get_type(device);
699                 dm_device_direction = pa_tz_device_get_direction(device);
700                 pa_log_debug("  -- type[%-16s], direction[0x%x], device id[%u]",
701                              dm_device_type, dm_device_direction, *device_id);
702                 if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
703                     pa_log_info("  ** found a matched device: type[%-16s], direction[0x%x]", device_type, dm_device_direction);
704                     /* currently, we support two sinks for combining */
705                     if (data->stream_type == STREAM_SINK_INPUT) {
706                         if (!combine_sink_arg1) {
707                             if ((sink = combine_sink_arg1 = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL)))
708                                 pa_log_info("  -- combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
709                             else
710                                 pa_log_warn("  -- could not get combine_sink_arg1");
711                         } else if (!combine_sink_arg2) {
712                             sink = combine_sink_arg2 = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
713                             if (sink && !pa_streq(sink->name, combine_sink_arg1->name)) {
714                                 uint32_t s_idx = 0;
715
716                                 pa_log_info("  -- combine_sink_arg2[%s]", sink->name);
717                                 /* load combine sink */
718                                 if (!u->module_combine_sink_for_ex) {
719                                     char *args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"", SINK_NAME_COMBINED_EX, combine_sink_arg1->name, combine_sink_arg2->name);
720                                     pa_log_info("  -- combined sink is not prepared, now load module[%s]", args);
721                                     u->module_combine_sink_for_ex = pa_module_load(u->core, MODULE_COMBINE_SINK, args);
722                                     pa_xfree(args);
723                                 }
724                                 sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED_EX, PA_NAMEREG_SINK);
725                                 PA_IDXSET_FOREACH(s, combine_sink_arg1->inputs, s_idx) {
726                                     if (sink && s == data->stream) {
727                                         pa_sink_input_move_to(s, sink, false);
728                                         pa_log_info("  -- *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
729                                         break;
730                                     }
731                                 }
732                             } else if (!sink) {
733                                 pa_log_warn("  -- could not get combine_sink_arg2");
734                             }
735                         }
736                         if (data->origins_from_new_data)
737                             *(data->proper_sink) = sink;
738                         else {
739                             if (((pa_sink_input*)(data->stream))->sink != sink)
740                                 pa_sink_input_move_to(data->stream, sink, false);
741                         }
742
743                     } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
744                         if ((source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL))) {
745                             if (data->origins_from_new_data)
746                                 *(data->proper_source) = source;
747                             else {
748                                 if (((pa_source_output*)(data->stream))->source != source)
749                                     pa_source_output_move_to(data->stream, source, false);
750                             }
751                         } else
752                             pa_log_warn("  -- could not get source");
753                     }
754                 }
755             }
756         }
757     }
758
759 not_found:
760     if ((data->stream_type == STREAM_SINK_INPUT) ? !(*(data->proper_sink)) : !(*(data->proper_source))) {
761         pa_log_warn("[SELECT] could not find a proper sink/source, set it to null sink/source");
762         if (data->stream_type == STREAM_SINK_INPUT)
763             *(data->proper_sink) = null_sink;
764         else
765             *(data->proper_source) = null_source;
766     }
767
768     return PA_HOOK_OK;
769 }
770
771 static void update_bt_route_option(pa_hal_interface *hal_intf, const char *role, const char* name, int value)
772 {
773     hal_route_option route_option;
774
775     memset(&route_option, 0, sizeof(hal_route_option));
776     route_option.role = role;
777     route_option.name = name;
778     route_option.value = value;
779
780     pa_hal_interface_update_route_option(hal_intf, &route_option);
781 }
782
783 static void reset_route(struct userdata *u, stream_type_t stream_type) {
784     hal_route_info route_info = {NULL, NULL, 0};
785     pa_sink *null_sink = NULL;
786
787     pa_assert(u);
788
789     if (u->module_loopback) {
790         if (stream_type == STREAM_SINK_INPUT && u->loopback_args.sink->use_internal_codec)
791             update_loopback_module(u, false);
792         else if (stream_type == STREAM_SOURCE_OUTPUT && u->loopback_args.source->use_internal_codec)
793             update_loopback_module(u, false);
794     }
795
796     /* update BT SCO: close */
797     update_bt_sco_state(u, false, true);
798
799     /* unload combine sink */
800     if (stream_type == STREAM_SINK_INPUT) {
801         null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
802         unload_combine_sink_module(u, SINK_NAME_COMBINED, null_sink);
803     }
804
805     route_info.role = "reset";
806     route_info.num_of_devices = 1;
807     route_info.device_infos = pa_xmalloc0(sizeof(hal_device_info)*route_info.num_of_devices);
808     route_info.device_infos[0].direction = CONVERT_TO_HAL_DIRECTION(stream_type);
809
810     /* send information to HAL to update route */
811     if (pa_hal_interface_update_route(u->hal_interface, &route_info))
812         pa_log_error("[ROUTE] Failed to pa_hal_interface_update_route()");
813
814     pa_xfree(route_info.device_infos);
815 }
816
817 /* Some H/W can have several alsa cards to serve various purposes. Therefore,
818  * a particular stream may have to use a specific card, e.g) during voice call.
819  * Here are codes to move streams to the specific device according to device role.
820  * It has to be set only when the new_data is true - start routing of the new
821  * highest priority stream. */
822 static void route_change_move_streams(struct userdata *u, pa_stream_manager_hook_data_for_route *data, pa_tz_device *device) {
823     const char *device_role;
824     void *s = NULL;
825     uint32_t idx = 0;
826     pa_idxset *streams = NULL;
827     pa_sink *sink = NULL;
828     pa_sink *dst_sink = NULL;
829     pa_source *source = NULL;
830     pa_source *dst_source = NULL;
831
832     pa_assert(u);
833     pa_assert(data);
834
835     /* if it's NOT from new_data, return here */
836     if (!device || !data->origins_from_new_data)
837         return;
838     if (!data->stream)
839         return;
840
841     if (!IS_ROLE_COMMUNICATION(data->stream_role))
842         return;
843
844     CONVERT_TO_DEVICE_ROLE(data->stream_role, device_role);
845     pa_log_info("[ROUTE][MOVE] stream_role[%s], device role[%s]", data->stream_role, device_role);
846     if (data->stream_type == STREAM_SINK_INPUT) {
847         if (!(sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL)) ||
848             !(dst_sink = pa_tz_device_get_sink(device, device_role)) ||
849             sink == dst_sink)
850             pa_log_info("[ROUTE][MOVE][%s] no need to move streams, sink(%p), dst_sink(%p)", data->stream_role, sink, dst_sink);
851         else
852             streams = sink->inputs;
853     } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
854         if (!(source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL)) ||
855             !(dst_source = pa_tz_device_get_source(device, device_role)) ||
856             source == dst_source)
857             pa_log_info("[ROUTE][MOVE][%s] no need to move streams, source(%p), dst_source(%p)", data->stream_role, source, dst_source);
858         else
859             streams = source->outputs;
860     }
861
862     if (!streams)
863         return;
864
865     /* move other streams that belong to the device of NORMAL role */
866     PA_IDXSET_FOREACH(s, streams, idx) {
867         if (data->stream_type == STREAM_SINK_INPUT) {
868             pa_sink_input_move_to(s, dst_sink, false);
869             pa_log_info("[ROUTE][MOVE][%s] *** sink-input(%p,%u) moves to sink(%p,%s)",
870                          data->stream_role, s, ((pa_sink_input*)s)->index, dst_sink, dst_sink->name);
871         } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
872             pa_source_output_move_to(s, dst_source, false);
873             pa_log_info("[ROUTE][MOVE][%s] *** source-output(%p,%u) moves to source(%p,%s)",
874                          data->stream_role, s, ((pa_source_output*)s)->index, dst_source, dst_source->name);
875         }
876     }
877     /* make sure the previous device is closed */
878     if (data->stream_type == STREAM_SINK_INPUT)
879         pa_sink_suspend(sink, true, PA_SUSPEND_INTERNAL);
880     else if (data->stream_type == STREAM_SOURCE_OUTPUT)
881         pa_source_suspend(source, true, PA_SUSPEND_INTERNAL);
882 }
883
884 /* Some H/W can have several alsa cards to serve various purposes. Therefore,
885  * a particular stream may have to use a specific card, e.g) during voice call.
886  * Here are codes to depart from the above situation and move streams to the device
887  * for rollback if needed only when the new_data is false - end of stream or
888  * start routing of the new highest priority stream. */
889 static void route_change_rollback_streams(struct userdata *u, pa_stream_manager_hook_data_for_route *data, pa_tz_device *device) {
890     pa_sink *sink = NULL;
891     pa_source *source = NULL;
892     uint32_t idx = 0;
893     void *s = NULL;
894     pa_sink *combine_sink = NULL;
895
896     pa_assert(u);
897     pa_assert(data);
898
899     /* if it's from new_data, return here */
900     if (!device || data->origins_from_new_data)
901         return;
902     if (!data->stream || !data->idx_streams)
903         return;
904     if (!IS_AUTO_ROUTE_TYPE_SERIES(data->route_type))
905         return;
906
907     if (data->stream_type == STREAM_SINK_INPUT) {
908         if (!(sink = pa_tz_device_get_sink(device, data->device_role)))
909             return;
910     } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
911         if (!(source = pa_tz_device_get_source(device, data->device_role)))
912             return;
913     }
914
915     PA_IDXSET_FOREACH(s, data->idx_streams, idx) {
916         if (sink && sink != ((pa_sink_input*)s)->sink) {
917             if ((pa_stream_manager_check_name_is_vstream(s, STREAM_SINK_INPUT, false)))
918                 continue;
919             if (((combine_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK)) &&
920                 ((pa_sink_input*)s)->sink == combine_sink))
921                 break;
922             if ((pa_stream_manager_check_filter_apply_stream(s, STREAM_SINK_INPUT)))
923                 continue;
924             pa_sink_input_move_to(s, sink, false);
925             pa_log_info("[ROUTE][ROLLBACK] *** sink-input(%p,%u) moves to sink(%p,%s)",
926                          s, ((pa_sink_input*)s)->index, sink, sink->name);
927         } else if (source && source != ((pa_source_output*)s)->source) {
928             pa_source_output_move_to(s, source, false);
929             pa_log_info("[ROUTE][ROLLBACK] *** source-output(%p,%u) moves to source(%p,%s)",
930                          s, ((pa_source_output*)s)->index, source, source->name);
931         }
932     }
933 }
934
935 static void fill_device_info(hal_route_info *route_info, const char *type, uint32_t direction, uint32_t id) {
936     pa_assert(route_info);
937     pa_assert(type);
938
939     route_info->num_of_devices++;
940     route_info->device_infos = pa_xrealloc(route_info->device_infos, sizeof(hal_device_info)*route_info->num_of_devices);
941     route_info->device_infos[route_info->num_of_devices-1].type = type;
942     route_info->device_infos[route_info->num_of_devices-1].direction = direction;
943     route_info->device_infos[route_info->num_of_devices-1].id = id;
944     pa_log_info("  ** filled a matched device to device_infos: type[%-16s], direction[0x%x], id[%u]", type, direction, id);
945 }
946
947 /* Change the route setting according to the data from argument.
948  * This function is called only when it needs to change routing path via HAL.
949  * - stream is null
950  *     1. It will be received when it is needed to terminate playback
951  *       or capture routing path.
952  *     2. Update the state of the device to be deactivated.
953  *     3. Call HAL API to "reset" routing.
954  * - ROUTE_TYPE_AUTO
955  *     1. Find the proper sink/source comparing between avail_devices
956  *       and current connected devices.
957  *      : Need to check the priority of the device list by order of receipt.
958  *     2. Update the state of devices.
959  *     3. Call HAL API to apply the routing setting
960  * - ROUTE_TYPE_AUTO_ALL
961  *     1. Find the proper sink/source comparing between avail_devices
962  *       and current connected devices.
963  *      : Might use combine-sink according to the conditions.
964  *     2. Update the state of devices.
965  *     3. Call HAL API to apply the routing setting
966  * - ROUTE_TYPE_MANUAL
967  *     1. Find the proper sink/source comparing between avail_devices
968  *        and manual_devices that have been set by user.
969  *     2. Update the state of devices.
970  *     3. Call HAL API to apply the routing setting. */
971 static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_route *data, struct userdata *u) {
972     uint32_t idx = 0;
973     hal_route_info route_info = {NULL, NULL, 0};
974     uint32_t *device_id = NULL;
975     uint32_t dm_device_id = 0;
976     stream_route_type_t route_type;
977     const char *device_type = NULL;
978     pa_tz_device *device = NULL;
979     pa_tz_device *latest_device = NULL;
980     const char *dm_device_type = NULL;
981     dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
982     pa_sink *sink = NULL;
983     pa_source *source = NULL;
984     pa_sink *combine_sink_arg1 = NULL;
985     pa_sink *combine_sink_arg2 = NULL;
986     bool use_internal_codec = false;
987
988     pa_assert(c);
989     pa_assert(data);
990     pa_assert(u);
991
992     pa_log_info("[ROUTE] route_change_hook_cb is called. (%p), stream_type(%d), stream_role(%s), route_type(%d)",
993                 data, data->stream_type, data->stream_role, data->route_type);
994
995     if (data->stream == NULL) {
996         reset_route(u, data->stream_type);
997         return PA_HOOK_OK;
998     }
999
1000     if (!data->idx_avail_devices) {
1001         pa_log_error("[ROUTE] available devices is NULL, do nothing...");
1002         return PA_HOOK_OK;
1003     }
1004     route_info.role = data->stream_role;
1005
1006     if (IS_AUTO_ROUTE_TYPE_SERIES(data->route_type)) {
1007         uint32_t conn_idx = 0;
1008         pa_idxset *conn_devices = NULL;
1009
1010         /* unload module-loopback */
1011         if (u->module_loopback) {
1012             if (data->stream_type == STREAM_SINK_INPUT && u->loopback_args.sink->use_internal_codec)
1013                 update_loopback_module(u, false);
1014             else if (data->stream_type == STREAM_SOURCE_OUTPUT && u->loopback_args.source->use_internal_codec)
1015                 update_loopback_module(u, false);
1016         }
1017
1018         /* get current connected devices */
1019         conn_devices = pa_device_manager_get_device_list(u->device_manager);
1020         if (data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
1021             PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
1022                 pa_log_debug("[ROUTE][AUTO(_ALL)] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, route_info.role, device_type);
1023                 if (!is_cached_device_connected(device_type, data->stream_type))
1024                     continue;
1025                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
1026                     dm_device_type = pa_tz_device_get_type(device);
1027                     dm_device_direction = pa_tz_device_get_direction(device);
1028                     dm_device_id = pa_tz_device_get_id(device);
1029                     pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u]",
1030                                  dm_device_type, dm_device_direction, dm_device_id);
1031                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
1032                         pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
1033                         use_internal_codec = pa_tz_device_is_use_internal_codec(device);
1034                         if (use_internal_codec) {
1035                             /* if it needs to skip it, keep going to next device for proper UCM setting */
1036                             if (skip_device(data->stream_role, dm_device_type))
1037                                 continue;
1038                             if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
1039                                 continue;
1040                             fill_device_info(&route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
1041                         } else
1042                             pa_log_debug("  -- it does not use internal audio codec, skip it");
1043                         break;
1044                     }
1045                 }
1046                 if (device == NULL)
1047                     continue;
1048
1049                 if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
1050                     if (data->origins_from_new_data)
1051                         pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1052                     else
1053                         pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1054
1055                     /* unload combine sink */
1056                     if (data->stream_type == STREAM_SINK_INPUT) {
1057                         if ((sink = pa_tz_device_get_sink(device, data->device_role)))
1058                             unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
1059                         else
1060                             pa_log_error("[ROUTE][AUTO] could not get sink");
1061                     }
1062
1063                     if (pa_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
1064                         if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info.role))
1065                             update_bt_sco_state(u, true, false);
1066                     } else {
1067                         update_bt_sco_state(u, false, false);
1068                     }
1069
1070                     break;
1071                 } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
1072                     uint32_t s_idx = 0;
1073                     void *s = NULL;
1074
1075                     update_bt_sco_state(u, false, false);
1076
1077                     /* find the proper sink/source */
1078                     /* currently, we support two sinks for combining */
1079                     if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
1080                         sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
1081                         pa_log_info("[ROUTE][AUTO_ALL] found the combine_sink already existed");
1082                     } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg1) {
1083                         sink = combine_sink_arg1 = pa_tz_device_get_sink(device, data->device_role);
1084                         if (sink)
1085                             pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
1086                         else
1087                             pa_log_error("[ROUTE][AUTO_ALL] could not get sink from pa_device_manager_get_sink");
1088                     } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg2) {
1089                         sink = combine_sink_arg2 = pa_tz_device_get_sink(device, data->device_role);
1090                         if (sink && !pa_streq(sink->name, combine_sink_arg1->name)) {
1091                             pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg2[%s]", sink->name);
1092                             /* load combine sink */
1093                             if (!u->module_combine_sink) {
1094                                 char *args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"", SINK_NAME_COMBINED, combine_sink_arg1->name, combine_sink_arg2->name);
1095                                 pa_log_info("[ROUTE][AUTO_ALL] combined sink is not prepared, now load module[%s]", args);
1096                                 u->module_combine_sink = pa_module_load(u->core, MODULE_COMBINE_SINK, args);
1097                                 pa_xfree(args);
1098                             }
1099                             if ((sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK))) {
1100                                 PA_IDXSET_FOREACH(s, combine_sink_arg1->inputs, s_idx) {
1101                                     if (s == data->stream) {
1102                                         pa_sink_input_move_to(s, sink, false);
1103                                         pa_log_info("[ROUTE][AUTO_ALL] *** sink-nput(%p,%u) moves to sink(%p,%s)",
1104                                                      s, ((pa_sink_input*)s)->index, sink, sink->name);
1105                                     }
1106                                 }
1107                             } else
1108                                 pa_log_error("[ROUTE][AUTO_ALL] could not get combine_sink");
1109                         }
1110                     } else if (data->stream_type == STREAM_SOURCE_OUTPUT)
1111                         source = pa_tz_device_get_source(device, data->device_role);
1112
1113                     if (data->origins_from_new_data) {
1114                         if (data->stream_type == STREAM_SINK_INPUT)
1115                             *(data->proper_sink) = sink;
1116                         else
1117                             *(data->proper_source) = source;
1118                     } else {
1119                         /* move sink-inputs/source-outputs if needed */
1120                         if (!data->idx_streams)
1121                             continue;
1122                         PA_IDXSET_FOREACH(s, data->idx_streams, s_idx) { /* data->idx_streams: null_sink */
1123                             if (pa_stream_manager_get_route_type(s, data->stream_type, false, &route_type))
1124                                 continue;
1125                             if (route_type != STREAM_ROUTE_TYPE_AUTO_ALL)
1126                                 continue;
1127                             if ((data->stream_type == STREAM_SINK_INPUT) && (sink && (sink != ((pa_sink_input*)s)->sink))) {
1128                                 pa_sink_input_move_to(s, sink, false);
1129                                 pa_log_info("[ROUTE][AUTO_ALL] *** sink-input(%p,%u) moves to sink(%p,%s)",
1130                                             s, ((pa_sink_input*)s)->index, sink, sink->name);
1131                             } else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (source && (source != ((pa_source_output*)s)->source))) {
1132                                 pa_source_output_move_to(s, source, false);
1133                                 pa_log_info("[ROUTE][AUTO_ALL] *** source-output(%p,%u) moves to source(%p,%s)",
1134                                             s, ((pa_source_output*)s)->index, source, source->name);
1135                             }
1136                         }
1137                     }
1138                 }
1139             }
1140         } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1141             pa_usec_t creation_time = 0;
1142             pa_usec_t latest_creation_time = 0;
1143
1144             PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
1145                 pa_log_debug("[ROUTE][AUTO_LAST_CONN] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
1146                 if (!is_cached_device_connected(device_type, data->stream_type))
1147                     continue;
1148                 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
1149                     dm_device_type = pa_tz_device_get_type(device);
1150                     dm_device_direction = pa_tz_device_get_direction(device);
1151                     dm_device_id = pa_tz_device_get_id(device);
1152                     creation_time = pa_tz_device_get_creation_time(device);
1153                     pa_log_debug("  -- type[%-16s], direction[0x%x], id[%u], creation_time[%llu]",
1154                                  dm_device_type, dm_device_direction, dm_device_id, creation_time);
1155                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
1156                         use_internal_codec = pa_tz_device_is_use_internal_codec(device);
1157                         if (use_internal_codec) {
1158                             /* if it needs to skip it, keep going to next device for proper UCM setting */
1159                             if (skip_device(data->stream_role, dm_device_type))
1160                                 continue;
1161                             if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
1162                                 continue;
1163                         }
1164                         if (!latest_device || (latest_creation_time <= creation_time)) {
1165                             latest_device = device;
1166                             latest_creation_time = creation_time;
1167                             pa_log_info("  ** updated the last connected device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
1168                         }
1169                     }
1170                 }
1171             }
1172             /* update activated device if it is found */
1173             if (latest_device) {
1174                 dm_device_type = pa_tz_device_get_type(latest_device);
1175                 dm_device_id = pa_tz_device_get_id(latest_device);
1176                 use_internal_codec = pa_tz_device_is_use_internal_codec(latest_device);
1177                 if (use_internal_codec)
1178                     fill_device_info(&route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
1179                 else
1180                     pa_log_debug("  -- it does not use internal audio codec, skip it");
1181
1182                 if (data->origins_from_new_data)
1183                     pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1184                 else
1185                     pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1186
1187                 /* unload combine sink */
1188                 if (data->stream_type == STREAM_SINK_INPUT) {
1189                     if ((sink = pa_tz_device_get_sink(latest_device, data->device_role)))
1190                         unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
1191                     else
1192                         pa_log_error("[ROUTE][AUTO_LAST_CONN] could not get sink");
1193                 }
1194
1195                 if (pa_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
1196                     if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info.role))
1197                         update_bt_sco_state(u, true, false);
1198                 } else {
1199                     update_bt_sco_state(u, false, false);
1200                 }
1201
1202                 /* Update device with latest_device to use be used later in this function */
1203                 device = latest_device;
1204             }
1205         }
1206
1207     } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL) {
1208         uint32_t d_idx = 0;
1209
1210         PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
1211             pa_log_info("[ROUTE][MANUAL] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
1212             if (!is_cached_device_connected(device_type, data->stream_type))
1213                 continue;
1214             PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, d_idx) {
1215                 pa_log_debug("  -- manual_device[%u] for this role[%-16s]: device_id(%u)", idx, data->stream_role, *device_id);
1216                 if (!(device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
1217                     continue;
1218                 dm_device_type = pa_tz_device_get_type(device);
1219                 if (!pa_streq(device_type, dm_device_type))
1220                     continue;
1221                 dm_device_direction = pa_tz_device_get_direction(device);
1222                 pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]",
1223                              dm_device_type, dm_device_direction);
1224                 /* Check for availability for opening Bluetooth SCO */
1225                 if (pa_streq(dm_device_type, DEVICE_TYPE_BT_SCO) && IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info.role)) {
1226                     bool is_wb = false;
1227                     bool is_nrec = false;
1228
1229                     /* update BT SCO: open */
1230                     if (update_bt_sco_state(u, true, false)) {
1231                         pa_log_error("  ** could not open BT SCO");
1232                         return PA_HOOK_CANCEL;
1233                     }
1234
1235                     if (get_bt_property(u->device_manager, &is_wb, &is_nrec) == 0) {
1236                         pa_log_info("bt property : wideband(%d), nrec(%d)", is_wb, is_nrec);
1237                         update_bt_route_option(u->hal_interface, route_info.role, "bt-wideband", (int)is_wb);
1238                         update_bt_route_option(u->hal_interface, route_info.role, "bt-nrec", (int)is_nrec);
1239                     } else
1240                         pa_log_warn("Failed to get property for wideband / nrec....");
1241                 } else {
1242                     /* update BT SCO: close */
1243                     update_bt_sco_state(u, false, false);
1244                 }
1245                 /* Check for in/out devices in case of loopback */
1246                 if (pa_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
1247                     if ((data->stream_type == STREAM_SINK_INPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_OUT))
1248                         u->loopback_args.sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
1249                     else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_IN))
1250                         u->loopback_args.source = pa_tz_device_get_source(device, DEVICE_ROLE_NORMAL);
1251                 }
1252
1253                 if (IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
1254                     use_internal_codec = pa_tz_device_is_use_internal_codec(device);
1255                     if (use_internal_codec)
1256                         fill_device_info(&route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), *device_id);
1257                     else
1258                         pa_log_debug("  -- it does not use internal audio codec, skip it");
1259                 }
1260             }
1261         }
1262         if (pa_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
1263             /* load module-loopback */
1264             if (u->loopback_args.sink && u->loopback_args.source)
1265                 update_loopback_module(u, true);
1266         }
1267     }
1268
1269     route_change_move_streams(u, data, device);
1270
1271     if (route_info.device_infos) {
1272         /* send information to HAL to update route */
1273         if (pa_hal_interface_update_route(u->hal_interface, &route_info))
1274             pa_log_error("[ROUTE] Failed to pa_hal_interface_update_route()");
1275         pa_xfree(route_info.device_infos);
1276     }
1277
1278     route_change_rollback_streams(u, data, device);
1279
1280     return PA_HOOK_OK;
1281 }
1282
1283 static pa_hook_result_t update_info_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_update_info *data, struct userdata *u) {
1284     pa_assert(c);
1285     pa_assert(data);
1286     pa_assert(u);
1287
1288     if (pa_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
1289         pa_log_info("[UPDATE] update_info_hook_cb is called. stream_role(%s) [name(%s)/value(%d)]",
1290             data->stream_role, data->name, data->value);
1291         if (pa_streq(data->name, MSG_FOR_LOOPBACK_ARG_LATENCY))
1292             u->loopback_args.latency_msec = data->value;
1293         else if (pa_streq(data->name, MSG_FOR_LOOPBACK_ARG_ADJUST_TIME))
1294             u->loopback_args.adjust_sec = data->value;
1295     }
1296
1297     return PA_HOOK_OK;
1298 }
1299
1300 /* Update ref. count of each connected device */
1301 static void update_cached_connected_devices(const char *device_type, dm_device_direction_t direction, bool is_connected) {
1302     int32_t val = 0;
1303     int* ptr_in = NULL;
1304     int* ptr_out = NULL;
1305
1306     ptr_in = &cached_connected_devices[convert_device_type_str(device_type)][CACHED_DEVICE_DIRECTION_IN];
1307     ptr_out = &cached_connected_devices[convert_device_type_str(device_type)][CACHED_DEVICE_DIRECTION_OUT];
1308     val = (is_connected) ? 1 : -1;
1309
1310     if (direction & DM_DEVICE_DIRECTION_IN)
1311         *ptr_in += val;
1312     if (direction & DM_DEVICE_DIRECTION_OUT)
1313         *ptr_out += val;
1314
1315     if (*ptr_in < 0)
1316         *ptr_in = 0;
1317     if (*ptr_out < 0)
1318         *ptr_out = 0;
1319 }
1320
1321 static void dump_connected_devices()
1322 {
1323 #if 0
1324     int32_t i = 0;
1325
1326     pa_log_debug("== dump cached current device ==");
1327     for (i = 0; i < DEVICE_MAX-1; i++)
1328         pa_log_debug("in: %d, out: %d", cached_connected_devices[i][CACHED_DEVICE_DIRECTION_IN], cached_connected_devices[i][CACHED_DEVICE_DIRECTION_OUT]);
1329     pa_log_debug("================================");
1330 #endif
1331 }
1332
1333 /* Reorganize routing when a device has been connected or disconnected */
1334 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_conn_changed *conn, struct userdata *u) {
1335     uint32_t idx = 0;
1336     dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
1337     pa_sink *sink = NULL;
1338     pa_sink *null_sink = NULL;
1339     bool use_internal_codec = false;
1340     pa_idxset* conn_devices = NULL;
1341     pa_tz_device *device = NULL;
1342
1343     pa_assert(c);
1344     pa_assert(conn);
1345     pa_assert(u);
1346
1347     device_direction = pa_tz_device_get_direction(conn->device);
1348
1349     pa_log_info("[CONN] device_connection_changed_hook_cb is called. conn(%p), is_connected(%d), device(%p), direction(0x%x)",
1350                 conn, conn->is_connected, conn->device, device_direction);
1351
1352     update_cached_connected_devices(pa_tz_device_get_type(conn->device), device_direction, conn->is_connected);
1353     dump_connected_devices();
1354
1355     sink = null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
1356     if (!null_sink) {
1357         pa_log_error("[CONN] could not get null_sink(%p)", null_sink);
1358         return PA_HOOK_OK;
1359     }
1360
1361     use_internal_codec = pa_tz_device_is_use_internal_codec(conn->device);
1362     /* update for unloading modules when external device is disconnected */
1363     if (!use_internal_codec && !conn->is_connected) {
1364         if (device_direction & DM_DEVICE_DIRECTION_OUT) {
1365            /* unload combine sink */
1366            conn_devices = pa_device_manager_get_device_list(u->device_manager);
1367             PA_IDXSET_FOREACH(device, conn_devices, idx) {
1368                 device_direction = pa_tz_device_get_direction(device);
1369                 if (device_direction == DM_DEVICE_DIRECTION_OUT) {
1370                     if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device))) {
1371                         sink = pa_tz_device_get_sink(device, DEVICE_ROLE_NORMAL);
1372                         break;
1373                     }
1374                 }
1375             }
1376             unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
1377
1378             /* unload combine sink for external devices */
1379             unload_combine_sink_module(u, SINK_NAME_COMBINED_EX, null_sink);
1380
1381             /* unload loopback module */
1382             if (u->module_loopback)
1383                 if (u->loopback_args.sink == pa_tz_device_get_sink(conn->device, DEVICE_ROLE_NORMAL))
1384                     update_loopback_module(u, false);
1385         }
1386     if (device_direction & DM_DEVICE_DIRECTION_IN) {
1387         /* unload loopback module */
1388         if (u->module_loopback)
1389             if (u->loopback_args.source == pa_tz_device_get_source(conn->device, DEVICE_ROLE_NORMAL))
1390                 update_loopback_module(u, false);
1391         }
1392     }
1393
1394     return PA_HOOK_OK;
1395 }
1396
1397 int pa__init(pa_module *m)
1398 {
1399     pa_modargs *ma = NULL;
1400     struct userdata *u;
1401     char *args = NULL;
1402
1403     pa_assert(m);
1404
1405     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1406         pa_log("Failed to parse module arguments");
1407         goto fail;
1408     }
1409
1410     m->userdata = u = pa_xnew0(struct userdata, 1);
1411     u->core = m->core;
1412     u->module = m;
1413
1414     u->hal_interface = pa_hal_interface_get(u->core);
1415
1416     if ((u->communicator.comm = pa_communicator_get(u->core))) {
1417         u->communicator.comm_hook_select_proper_sink_or_source_slot = pa_hook_connect(
1418                 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE),
1419                 PA_HOOK_EARLY, (pa_hook_cb_t)select_proper_sink_or_source_hook_cb, u);
1420         u->communicator.comm_hook_change_route_slot = pa_hook_connect(
1421                 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE),
1422                 PA_HOOK_EARLY, (pa_hook_cb_t)route_change_hook_cb, u);
1423         u->communicator.comm_hook_device_connection_changed_slot = pa_hook_connect(
1424                 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
1425                 PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, u);
1426         u->communicator.comm_hook_update_info_slot = pa_hook_connect(
1427                 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_UPDATE_INFORMATION),
1428                 PA_HOOK_EARLY, (pa_hook_cb_t)update_info_hook_cb, u);
1429     }
1430     u->device_manager = pa_device_manager_get(u->core);
1431
1432     u->stream_manager = pa_stream_manager_init(u->core);
1433
1434     /* load null sink/source */
1435     args = pa_sprintf_malloc("sink_name=%s", SINK_NAME_NULL);
1436     u->module_null_sink = pa_module_load(u->core, MODULE_NULL_SINK, args);
1437     pa_xfree(args);
1438     args = pa_sprintf_malloc("source_name=%s", SOURCE_NAME_NULL);
1439     u->module_null_source = pa_module_load(u->core, MODULE_NULL_SOURCE, args);
1440     pa_xfree(args);
1441
1442     __load_dump_config(u);
1443
1444     pa_log_info("Tizen Audio Policy module is loaded\n");
1445
1446     if (ma)
1447         pa_modargs_free(ma);
1448
1449     return 0;
1450
1451 fail:
1452     pa__done(m);
1453
1454     return -1;
1455 }
1456
1457 void pa__done(pa_module *m)
1458 {
1459     struct userdata* u;
1460
1461     pa_assert(m);
1462
1463     if (!(u = m->userdata))
1464         return;
1465
1466     pa_module_unload(u->core, u->module_null_sink, true);
1467     u->module_null_sink = NULL;
1468     pa_module_unload(u->core, u->module_null_source, true);
1469     u->module_null_source = NULL;
1470
1471     if (u->device_manager)
1472         pa_device_manager_unref(u->device_manager);
1473
1474     if (u->stream_manager)
1475         pa_stream_manager_done(u->stream_manager);
1476
1477     if (u->communicator.comm) {
1478         if (u->communicator.comm_hook_select_proper_sink_or_source_slot)
1479             pa_hook_slot_free(u->communicator.comm_hook_select_proper_sink_or_source_slot);
1480         if (u->communicator.comm_hook_change_route_slot)
1481             pa_hook_slot_free(u->communicator.comm_hook_change_route_slot);
1482         if (u->communicator.comm_hook_device_connection_changed_slot)
1483             pa_hook_slot_free(u->communicator.comm_hook_device_connection_changed_slot);
1484         if (u->communicator.comm_hook_update_info_slot)
1485             pa_hook_slot_free(u->communicator.comm_hook_update_info_slot);
1486         pa_communicator_unref(u->communicator.comm);
1487     }
1488
1489     if (u->hal_interface)
1490         pa_hal_interface_unref(u->hal_interface);
1491
1492     bt_sco_close(u, false);
1493
1494     pa_xfree(u);
1495
1496     pa_log_info("Tizen Audio Policy module is unloaded\n");
1497 }