2 This file is part of PulseAudio.
4 Copyright 2013-2016 Seungbae Shin, Sangchul Lee, Jeongho Mok
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.
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.
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
28 #include <vconf.h> // for mono
29 #include <iniparser.h>
33 #include <pulse/proplist.h>
34 #include <pulse/timeval.h>
35 #include <pulse/util.h>
36 #include <pulse/rtclock.h>
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>
58 #include "communicator.h"
59 #include "hal-interface.h"
60 #include "stream-manager.h"
61 #include "device-manager.h"
63 PA_MODULE_AUTHOR("Seungbae Shin, Sangchul Lee, Jeongho Mok");
64 PA_MODULE_DESCRIPTION("Tizen Audio Policy module");
65 PA_MODULE_VERSION(PACKAGE_VERSION);
66 PA_MODULE_LOAD_ONCE(true);
69 static const char* const valid_modargs[] = {
75 /* Modules for dynamic loading */
76 #define MODULE_COMBINE_SINK "module-combine-sink"
77 #define MODULE_NULL_SINK "module-null-sink"
78 #define MODULE_NULL_SOURCE "module-null-source"
79 #define MODULE_LOOPBACK "module-loopback"
81 /* Name of combine sink for external route type */
82 #define SINK_NAME_COMBINED_EX SINK_NAME_COMBINED"_ex"
85 #define LOOPBACK_DEFAULT_LATENCY_MSEC 40
86 #define LOOPBACK_DEFAULT_ADJUST_SEC 3
88 #define TIMED_BT_SCO_CLOSE_USEC 3000000
91 #define CONVERT_TO_HAL_DIRECTION(stream_type) \
92 ((stream_type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN)
93 #define CONVERT_TO_DEVICE_DIRECTION(stream_type) \
94 ((stream_type == STREAM_SINK_INPUT) ? DM_DEVICE_DIRECTION_OUT : DM_DEVICE_DIRECTION_IN)
95 #define IS_AVAILABLE_DIRECTION(stream_type, device_direction) \
96 ((stream_type == STREAM_SINK_INPUT) ? (device_direction & DM_DEVICE_DIRECTION_OUT) : (device_direction & DM_DEVICE_DIRECTION_IN))
99 #define PA_DUMP_INI_DEFAULT_PATH SYSCONFDIR"/multimedia/mmfw_audio_pcm_dump.ini" /* SYSCONFDIR is defined at .spec */
100 #define PA_DUMP_INI_TEMP_PATH "/home/owner/media/mmfw_audio_pcm_dump.ini"
101 #define PA_DUMP_VCONF_KEY "memory/private/sound/pcm_dump"
103 typedef enum _device_type {
104 DEVICE_BUILTIN_SPEAKER,
105 DEVICE_BUILTIN_RECEIVER,
119 CACHED_DEVICE_DIRECTION_IN,
120 CACHED_DEVICE_DIRECTION_OUT,
121 CACHED_DEVICE_DIRECTION_MAX,
124 static int cached_connected_devices[DEVICE_MAX][CACHED_DEVICE_DIRECTION_MAX];
126 static device_type_t convert_device_type_str(const char *device)
128 if (pa_safe_streq(device, DEVICE_TYPE_SPEAKER))
129 return DEVICE_BUILTIN_SPEAKER;
130 else if (pa_safe_streq(device, DEVICE_TYPE_RECEIVER))
131 return DEVICE_BUILTIN_RECEIVER;
132 else if (pa_safe_streq(device, DEVICE_TYPE_MIC))
133 return DEVICE_BUILTIN_MIC;
134 else if (pa_safe_streq(device, DEVICE_TYPE_AUDIO_JACK))
135 return DEVICE_AUDIO_JACK;
136 else if (pa_safe_streq(device, DEVICE_TYPE_BT_A2DP))
137 return DEVICE_BT_A2DP;
138 else if (pa_safe_streq(device, DEVICE_TYPE_BT_SCO))
139 return DEVICE_BT_SCO;
140 else if (pa_safe_streq(device, DEVICE_TYPE_HDMI))
142 else if (pa_safe_streq(device, DEVICE_TYPE_FORWARDING))
143 return DEVICE_FORWARDING;
144 else if (pa_safe_streq(device, DEVICE_TYPE_USB_AUDIO))
145 return DEVICE_USB_AUDIO;
146 else if (pa_safe_streq(device, DEVICE_TYPE_NETWORK))
147 return DEVICE_NETWORK;
149 pa_log_warn("unknown device (%s)", device);
150 return DEVICE_UNKNOWN;
158 pa_communicator *comm;
159 pa_hook_slot *comm_hook_select_proper_sink_or_source_slot;
160 pa_hook_slot *comm_hook_change_route_slot;
161 pa_hook_slot *comm_hook_device_connection_changed_slot;
162 pa_hook_slot *comm_hook_update_info_slot;
165 pa_hal_interface *hal_interface;
166 pa_stream_manager *stream_manager;
167 pa_device_manager *device_manager;
169 pa_module *module_combine_sink;
170 pa_module *module_combine_sink_for_ex;
171 uint32_t module_null_sink_index;
172 uint32_t module_null_source_index;
173 pa_module *module_loopback;
175 int32_t latency_msec;
180 pa_time_event *time_event_bt_sco_close;
183 static void __load_dump_config(struct userdata *u)
185 dictionary * dict = NULL;
187 dict = iniparser_load(PA_DUMP_INI_DEFAULT_PATH);
189 pa_log_debug("%s load failed. Use temporary file", PA_DUMP_INI_DEFAULT_PATH);
190 dict = iniparser_load(PA_DUMP_INI_TEMP_PATH);
192 pa_log_warn("%s load failed", PA_DUMP_INI_TEMP_PATH);
197 u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_sink_input", 0) ? PA_PCM_DUMP_SINK_INPUT : 0;
198 u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_sink", 0) ? PA_PCM_DUMP_SINK : 0;
199 u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_source", 0) ? PA_PCM_DUMP_SOURCE : 0;
200 u->core->pcm_dump |= (bool)iniparser_getboolean(dict, "pcm_dump:pa_source_output", 0) ? PA_PCM_DUMP_SOURCE_OUTPUT : 0;
202 iniparser_freedict(dict);
205 /* threre is only one sco connected device */
206 static pa_tz_device* _get_sco_connected_device(pa_device_manager *dm) {
207 pa_idxset *device_list;
208 pa_tz_device *device;
213 device_list = pa_device_manager_get_device_list(dm);
215 PA_IDXSET_FOREACH(device, device_list, device_idx) {
216 if (pa_safe_streq(device->type, DEVICE_TYPE_BT_SCO)) {
223 static bool is_bt_sco_connected(pa_device_manager *dm) {
224 pa_tz_device *bt_device;
228 if ((bt_device = _get_sco_connected_device(dm)))
234 static bool is_bt_a2dp_connected(pa_device_manager *dm) {
235 pa_idxset *device_list;
236 pa_tz_device *device;
241 device_list = pa_device_manager_get_device_list(dm);
243 PA_IDXSET_FOREACH(device, device_list, device_idx) {
244 if (pa_safe_streq(device->type, DEVICE_TYPE_BT_A2DP)) {
252 static bool is_bt_sco_opened(pa_device_manager *dm) {
253 dm_device_bt_sco_status_t sco_status;
254 pa_tz_device *bt_device;
258 bt_device = _get_sco_connected_device(dm);
259 if (bt_device == NULL) {
260 pa_log_debug("No SCO connected bt device");
263 if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
264 pa_log_error("get BT SCO status failed");
267 if (sco_status != DM_DEVICE_BT_SCO_STATUS_OPENED) {
268 pa_log_error("SCO is not opened");
271 pa_log_info("SCO is opened");
276 static void timed_bt_sco_close_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) {
277 struct userdata *u = userdata;
278 pa_tz_device *bt_device;
279 dm_device_bt_sco_status_t sco_status;
282 pa_assert(u->time_event_bt_sco_close == e);
284 pa_log_info("timed_bt_sco_close_cb is called");
286 u->core->mainloop->time_free(u->time_event_bt_sco_close);
287 u->time_event_bt_sco_close = NULL;
289 bt_device = _get_sco_connected_device(u->device_manager);
290 if (bt_device == NULL) {
291 pa_log_debug("No SCO connected bt device");
294 if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
295 pa_log_error("get BT SCO status failed");
298 if (pa_tz_device_sco_close(bt_device) < 0) {
299 pa_log_error("BT SCO was opened, but failed to close SCO");
302 pa_log_info("BT SCO is now closed in timed callback");
306 static int bt_sco_open(struct userdata *u, const char *role) {
307 dm_device_bt_sco_status_t sco_status;
308 pa_tz_device *bt_device;
313 if (u->time_event_bt_sco_close) {
314 u->core->mainloop->time_free(u->time_event_bt_sco_close);
315 u->time_event_bt_sco_close = NULL;
318 bt_device = _get_sco_connected_device(u->device_manager);
319 if (bt_device == NULL) {
320 pa_log_debug("No SCO connected bt device");
323 pa_log_info("Got BT SCO connected device(%u)", bt_device->id);
325 if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
326 pa_log_error("get BT SCO status failed");
329 if (sco_status == DM_DEVICE_BT_SCO_STATUS_OPENED) {
330 pa_log_warn("BT SCO is already opened for this BT device");
334 if (pa_safe_streq(role, STREAM_ROLE_VOICE_RECOGNITION) ||
335 pa_safe_streq(role, STREAM_ROLE_VOICE_RECOGNITION_SERVICE))
336 pa_tz_device_sco_enable_pcm(bt_device, true);
338 if (pa_tz_device_sco_open(bt_device) < 0) {
339 pa_log_error("failed to open BT SCO");
342 pa_log_debug("BT SCO is now opened");
347 static int bt_sco_close(struct userdata *u, bool delayed_close) {
348 dm_device_bt_sco_status_t sco_status;
349 pa_tz_device *bt_device;
353 if (!u->device_manager) {
354 pa_log_error("device_manager is null");
358 bt_device = _get_sco_connected_device(u->device_manager);
359 if (bt_device == NULL) {
360 pa_log_debug("No SCO connected bt device");
363 pa_log_info("Got BT SCO connected device(%u)", bt_device->id);
365 if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
366 pa_log_error("get BT SCO status failed");
369 if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED) {
370 pa_log_warn("BT SCO is already closed for this BT device");
374 pa_tz_device_sco_enable_pcm(bt_device, false);
377 /* request to close SCO after 3 sec. */
378 if (!u->time_event_bt_sco_close) {
379 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);
380 pa_log_debug("Append time event to close BT SCO");
383 if (u->time_event_bt_sco_close) {
384 u->core->mainloop->time_free(u->time_event_bt_sco_close);
385 u->time_event_bt_sco_close = NULL;
387 if (pa_tz_device_sco_close(bt_device) < 0) {
388 pa_log_error("BT SCO was opened, but failed to close SCO");
391 pa_log_debug("BT SCO is now closed");
397 /* Open/Close BT SCO if it is possible */
398 static int update_bt_sco_state(struct userdata *u, bool open, bool delayed_close, const char *role) {
402 return bt_sco_open(u, role);
404 return bt_sco_close(u, delayed_close);
407 static int get_bt_property(pa_device_manager *dm, bool *is_wb, bool *is_nrec) {
408 dm_device_bt_sco_status_t sco_status;
409 pa_tz_device *bt_device;
415 bt_device = _get_sco_connected_device(dm);
416 if (bt_device == NULL) {
417 pa_log_error("No SCO connected bt device");
420 if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
421 pa_log_error("get BT SCO status failed");
425 pa_log_info("Got BT SCO connected device(%u), status(%d)", bt_device->id, sco_status);
426 if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED)
429 return pa_tz_device_sco_get_property(bt_device, is_wb, is_nrec);
432 static void update_bt_sco_option(struct userdata *u, const char* role) {
434 bool is_nrec = false;
439 if (get_bt_property(u->device_manager, &is_wb, &is_nrec) == 0) {
440 pa_log_info("bt property : wideband(%d), nrec(%d)", is_wb, is_nrec);
441 UPDATE_HAL_ROUTE_OPTION(u->hal_interface, role, "bt-wideband", (int)is_wb);
442 UPDATE_HAL_ROUTE_OPTION(u->hal_interface, role, "bt-nrec", (int)is_nrec);
444 pa_log_warn("Failed to get property for wideband / nrec....");
448 /* Load/Unload module-loopback */
449 static void update_loopback_module(struct userdata *u, bool load) {
451 const char *volume_type;
455 if (load && u->loopback_args.sink && u->loopback_args.source) {
456 if (!u->loopback_args.latency_msec)
457 u->loopback_args.latency_msec = LOOPBACK_DEFAULT_LATENCY_MSEC;
458 if (!u->loopback_args.adjust_sec)
459 u->loopback_args.adjust_sec = LOOPBACK_DEFAULT_ADJUST_SEC;
461 volume_type = pa_stream_manager_get_volume_type(u->stream_manager, STREAM_SINK_INPUT, STREAM_ROLE_LOOPBACK);
462 args = pa_sprintf_malloc("sink=%s source=%s latency_msec=%d adjust_time=%d sink_input_properties=%s=%s",
463 u->loopback_args.sink->name, u->loopback_args.source->name,
464 u->loopback_args.latency_msec, u->loopback_args.adjust_sec,
465 PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, volume_type);
466 if (u->module_loopback)
467 pa_module_unload(u->module_loopback, true);
469 if (pa_module_load(&u->module_loopback, u->core, MODULE_LOOPBACK, args))
470 pa_log_error("failed to load module-loopback with (%s)", args);
472 pa_log_info(" -- load module-loopback with (%s)", args);
476 if (u->module_loopback) {
477 pa_module_unload(u->module_loopback, true);
478 u->module_loopback = NULL;
479 u->loopback_args.sink = NULL;
480 u->loopback_args.source = NULL;
481 pa_log_info(" -- unload module-loopback");
484 pa_log_error(" -- failed to update loopback module");
488 static pa_sink *load_combine_sink_module(struct userdata *u, const char *combine_sink_name, pa_sink *sink1, pa_sink *sink2, pa_sink_input *stream)
490 pa_module **combine_sink_module = NULL;
495 pa_assert(combine_sink_name);
499 if (pa_safe_streq(combine_sink_name, SINK_NAME_COMBINED)) {
500 combine_sink_module = &u->module_combine_sink;
501 } else if (pa_safe_streq(combine_sink_name, SINK_NAME_COMBINED_EX)) {
502 combine_sink_module = &u->module_combine_sink_for_ex;
504 pa_log_error("unknown combine_sink_name(%s)", combine_sink_name);
508 if (!*combine_sink_module) {
509 char *args = pa_sprintf_malloc("sink_name=%s slaves=\"%s,%s\"", combine_sink_name, sink1->name, sink2->name);
510 pa_log_info("load combine sink module[%s]", args);
511 /* FIXME: load combine module per each stream role. */
512 if (pa_module_load(combine_sink_module, u->core, MODULE_COMBINE_SINK, args))
513 pa_log_error("failed to load module-combine-sink with args(%s)", args);
517 sink = (pa_sink *)pa_namereg_get(u->core, combine_sink_name, PA_NAMEREG_SINK);
519 pa_log_error("failed to pa_namereg_get() for [%s]", combine_sink_name);
523 sink->use_internal_codec = pa_safe_streq(combine_sink_name, SINK_NAME_COMBINED);
526 if ((i = pa_idxset_get_by_data(sink1->inputs, stream, NULL)) ||
527 (i = pa_idxset_get_by_data(sink2->inputs, stream, NULL))) {
528 pa_sink_input_move_to(i, sink, false);
529 pa_log_info("*** sink-input(%p,%u) moves to sink(%p,%s)", i, i->index, sink, sink->name);
536 static void unload_combine_sink_module(struct userdata *u, const char *combine_sink_name, pa_sink *dst_sink)
538 pa_module **combine_sink_module = NULL;
539 pa_sink *combine_sink = NULL;
540 pa_sink_input *s = NULL;
544 pa_assert(combine_sink_name);
547 if (pa_safe_streq(combine_sink_name, SINK_NAME_COMBINED)) {
548 combine_sink_module = &u->module_combine_sink;
549 } else if (pa_safe_streq(combine_sink_name, SINK_NAME_COMBINED_EX)) {
550 combine_sink_module = &u->module_combine_sink_for_ex;
552 pa_log_error("unknown combine_sink_name(%s)", combine_sink_name);
556 if (!*combine_sink_module) {
557 pa_log_warn("module combine sink(%s) has been already unloaded", combine_sink_name);
561 combine_sink = (pa_sink*)pa_namereg_get(u->core, combine_sink_name, PA_NAMEREG_SINK);
563 pa_log_error("could not get combine_sink(%s)", combine_sink_name);
565 PA_IDXSET_FOREACH(s, combine_sink->inputs, idx) {
566 pa_sink_input_move_to(s, dst_sink, false);
567 pa_log_info("*** sink-input(%p,%u) of (%s) moves to another sink(%p,%s)",
568 s, ((pa_sink_input*)s)->index, combine_sink_name, dst_sink, dst_sink->name);
570 pa_sink_suspend(combine_sink, true, PA_SUSPEND_USER);
573 pa_log_info("unload combine sink module[%s]", combine_sink_name);
574 pa_module_unload(*combine_sink_module, true);
575 *combine_sink_module = NULL;
578 static bool skip_device(const char *stream_role, const char *device_type)
582 if (pa_safe_streq(device_type, DEVICE_TYPE_FORWARDING))
585 /* get sound profile */
586 if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sound_on) < 0) {
587 pa_log_error("failed to get vconf - sound status");
591 if (!sound_on && IS_ROLE_RINGTONE(stream_role) && pa_safe_streq(device_type, DEVICE_TYPE_SPEAKER)) {
592 pa_log_info("sound status is 0 with ringtone-call stream, skip built-in speaker");
599 static bool skip_bt_sco_device(struct userdata *u, const char *stream_role, const char *device_type) {
601 pa_assert(stream_role);
602 pa_assert(device_type);
604 if (pa_safe_streq(stream_role, STREAM_ROLE_VOICE_INFORMATION) && pa_safe_streq(device_type, DEVICE_TYPE_BT_SCO)) {
605 if (!is_bt_sco_connected(u->device_manager)) {
606 pa_log_warn("It is VOICE_INFORMATION, BT SCO is not connected, skip this device");
609 if (is_bt_sco_opened(u->device_manager)) {
610 /* remove the request of closing SCO */
611 if (u->time_event_bt_sco_close) {
612 u->core->mainloop->time_free(u->time_event_bt_sco_close);
613 u->time_event_bt_sco_close = NULL;
615 pa_log_info("It is VOICE_INFORMATION, BT SCO is already opened, use BT SCO");
617 } else if (!is_bt_a2dp_connected(u->device_manager)) {
618 pa_log_info("It is VOICE_INFORMATION, BT SCO is connected, BT A2DP is not available, use BT SCO");
621 pa_log_info("It is VOICE_INFORMATION, BT SCO is not opened, skip this device");
629 static bool is_supported_stream_role_for_usb(const char *role) {
632 if (pa_safe_streq(STREAM_ROLE_MEDIA, role))
635 pa_log_error("not supported role for usb(%s)", role);
640 static bool skip_usb_device(const char *stream_role, pa_tz_device *device) {
641 char *specified_stream_role;
643 pa_assert(stream_role);
646 if (!pa_safe_streq(pa_tz_device_get_type(device), DEVICE_TYPE_USB_AUDIO))
649 if (!(specified_stream_role = pa_tz_device_get_specified_stream_role(device)))
652 if (is_supported_stream_role_for_usb(specified_stream_role) &&
653 pa_safe_streq(stream_role, specified_stream_role))
656 pa_log_info("skip this usb device, stream role(%s), specified stream role(%s)", stream_role, specified_stream_role);
661 static inline bool is_cached_device_connected(const char* device_type, stream_type_t stream_type) {
662 if (cached_connected_devices[convert_device_type_str(device_type)][CONVERT_TO_DEVICE_DIRECTION(stream_type)-1] > 0)
667 static int32_t select_device_by_preemptive_device(struct userdata *u, pa_stream_manager_hook_data_for_select *data) {
668 uint32_t dm_device_id = 0;
669 pa_tz_device *device = NULL;
670 const char *device_type;
675 if (pa_stream_manager_get_preemptive_device_id(u->stream_manager, data->stream_type, data->stream_role, &dm_device_id))
678 device = pa_device_manager_get_device_by_id(u->device_manager, dm_device_id);
679 device_type = pa_tz_device_get_type(device);
680 pa_log_debug("preemptive device is type:[%s] id:[%u]", device_type, dm_device_id);
681 if (data->stream_type == STREAM_SINK_INPUT)
682 *(data->proper_sink) = pa_tz_device_get_sink(device, data->device_role);
684 *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
686 if (data->origins_from_new_data)
687 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type),
688 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
690 pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type),
691 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
696 static void select_device_by_auto_or_auto_all_routing(struct userdata *u, pa_stream_manager_hook_data_for_select *data, pa_idxset *conn_devices) {
697 const char *device_type = NULL;
699 uint32_t conn_idx = 0;
700 uint32_t dm_device_id = 0;
701 const char *dm_device_type = NULL;
702 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
703 pa_tz_device *device = NULL;
707 pa_assert(conn_devices);
709 if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
710 if (!select_device_by_preemptive_device(u, data))
714 PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
715 pa_log_debug("[SELECT][AUTO(_ALL)] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
716 if (!is_cached_device_connected(device_type, data->stream_type))
719 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
720 dm_device_type = pa_tz_device_get_type(device);
721 dm_device_direction = pa_tz_device_get_direction(device);
722 dm_device_id = pa_tz_device_get_id(device);
723 pa_log_debug(" -- type[%-16s], direction[0x%x], id[%u]",
724 dm_device_type, dm_device_direction, dm_device_id);
725 if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
727 pa_log_info(" ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
728 if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
730 if (skip_usb_device(data->stream_role, device))
733 if (data->stream_type == STREAM_SINK_INPUT) {
734 if (data->origins_from_new_data) {
735 if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL && u->module_combine_sink) {
736 *(data->proper_sink) = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
737 pa_log_info(" -- found the combine-sink, set it to the sink");
739 *(data->proper_sink) = pa_tz_device_get_sink(device, data->device_role);
742 if (data->route_type == STREAM_ROUTE_TYPE_AUTO)
743 data->new_sink = pa_tz_device_get_sink(device, data->device_role);
746 if (data->origins_from_new_data) {
747 *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
749 if (data->route_type == STREAM_ROUTE_TYPE_AUTO)
750 data->new_source = pa_tz_device_get_source(device, data->device_role);
753 if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
754 if (data->origins_from_new_data)
755 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type),
756 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
758 pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type),
759 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
766 static void select_device_by_auto_last_connected_routing(struct userdata *u, pa_stream_manager_hook_data_for_select *data, pa_idxset *conn_devices) {
767 const char *device_type = NULL;
768 pa_tz_device *latest_device = NULL;
769 const char *latest_device_type = NULL;
770 pa_tz_device *device = NULL;
772 uint32_t conn_idx = 0;
773 uint32_t dm_device_id = 0;
774 const char *dm_device_type = NULL;
775 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
776 pa_usec_t creation_time = 0;
777 pa_usec_t latest_creation_time = 0;
781 pa_assert(conn_devices);
783 if (!select_device_by_preemptive_device(u, data))
786 PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
787 pa_log_debug("[SELECT][AUTO_LAST_CONN] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
788 if (!is_cached_device_connected(device_type, data->stream_type))
791 PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
792 dm_device_type = pa_tz_device_get_type(device);
793 dm_device_direction = pa_tz_device_get_direction(device);
794 dm_device_id = pa_tz_device_get_id(device);
795 creation_time = pa_tz_device_get_creation_time(device);
796 pa_log_debug(" -- type[%-16s], direction[0x%x], id[%u], creation_time[%llu]",
797 dm_device_type, dm_device_direction, dm_device_id, creation_time);
798 if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
800 if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
802 if (skip_usb_device(data->stream_role, device))
805 if (!latest_device || (latest_creation_time <= creation_time)) {
806 if (device_type_is_builtin(dm_device_type) && pa_safe_streq(latest_device_type, dm_device_type)) {
807 pa_log_info("%s %s", latest_device_type, dm_device_type);
808 if (data->stream_type == STREAM_SINK_INPUT ?
809 (void*)pa_tz_device_get_sink(latest_device, data->device_role) :
810 (void*)pa_tz_device_get_source(latest_device, data->device_role))
813 latest_device = device;
814 latest_creation_time = creation_time;
815 latest_device_type = dm_device_type;
816 pa_log_info(" ** updated the last connected device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
820 /* update active device info. */
822 dm_device_type = pa_tz_device_get_type(latest_device);
823 if (data->origins_from_new_data) {
824 if (data->stream_type == STREAM_SINK_INPUT)
825 *(data->proper_sink) = pa_tz_device_get_sink(latest_device, data->device_role);
827 *(data->proper_source) = pa_tz_device_get_source(latest_device, data->device_role);
829 if (data->stream_type == STREAM_SINK_INPUT)
830 data->new_sink = pa_tz_device_get_sink(latest_device, data->device_role);
832 data->new_source = pa_tz_device_get_source(latest_device, data->device_role);
834 if (data->origins_from_new_data)
835 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type),
836 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
838 pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type),
839 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
843 static void select_device_by_manual_routing(struct userdata *u, pa_stream_manager_hook_data_for_select *data, pa_sink *null_sink, pa_source *null_source) {
844 const char *device_type = NULL;
845 pa_tz_device *device = NULL;
846 uint32_t *device_id = NULL;
849 const char *dm_device_type = NULL;
850 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
854 pa_assert(null_sink);
855 pa_assert(null_source);
857 PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
858 pa_log_info("[SELECT][MANUAL] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
859 if (!is_cached_device_connected(device_type, data->stream_type))
862 PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
863 if (!(device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
865 dm_device_type = pa_tz_device_get_type(device);
866 dm_device_direction = pa_tz_device_get_direction(device);
867 pa_log_debug(" -- type[%-16s], direction[0x%x], device id[%u]",
868 dm_device_type, dm_device_direction, *device_id);
869 if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
871 pa_log_info(" ** found a matched device: type[%-16s], direction[0x%x]", device_type, dm_device_direction);
872 if (data->stream_type == STREAM_SINK_INPUT) {
873 if ((*(data->proper_sink)) == null_sink)
874 pa_sink_input_move_to((pa_sink_input*)(data->stream), pa_tz_device_get_sink(device, data->device_role), false);
876 *(data->proper_sink) = pa_tz_device_get_sink(device, data->device_role);
878 if ((*(data->proper_source)) == null_source)
879 pa_source_output_move_to((pa_source_output*)(data->stream), pa_tz_device_get_source(device, data->device_role), false);
881 *(data->proper_source) = pa_tz_device_get_source(device, data->device_role);
887 static void select_device_by_manual_external_routing(struct userdata *u, pa_stream_manager_hook_data_for_select *data) {
888 const char *device_type = NULL;
889 pa_tz_device *device = NULL;
890 uint32_t *device_id = NULL;
893 const char *dm_device_type = NULL;
894 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
895 pa_sink *sink = NULL;
896 pa_source *source = NULL;
897 pa_sink *combine_sink_arg1 = NULL;
898 pa_sink *combine_sink_arg2 = NULL;
903 PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
904 pa_log_info("[SELECT][MANUAL_EXT] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
905 if (!is_cached_device_connected(device_type, data->stream_type))
908 PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, m_idx) {
909 if (!(device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
911 dm_device_type = pa_tz_device_get_type(device);
912 dm_device_direction = pa_tz_device_get_direction(device);
913 pa_log_debug(" -- type[%-16s], direction[0x%x], device id[%u]", dm_device_type, dm_device_direction, *device_id);
914 if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
916 pa_log_info(" ** found a matched device: type[%-16s], direction[0x%x]", device_type, dm_device_direction);
917 /* currently, we support two sinks for combining */
918 if (data->stream_type == STREAM_SINK_INPUT) {
919 if (!combine_sink_arg1) {
920 if ((sink = combine_sink_arg1 = pa_tz_device_get_sink(device, NULL)))
921 pa_log_info(" -- combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
923 pa_log_warn(" -- could not get combine_sink_arg1");
924 } else if (!combine_sink_arg2) {
925 sink = combine_sink_arg2 = pa_tz_device_get_sink(device, NULL);
926 if (sink && !pa_safe_streq(sink->name, combine_sink_arg1->name)) {
927 pa_log_info(" -- combine_sink_arg2[%s]", sink->name);
928 sink = load_combine_sink_module(u, SINK_NAME_COMBINED_EX, combine_sink_arg1, combine_sink_arg2, data->stream);
931 pa_log_warn(" -- could not get combine_sink_arg2");
934 if (data->origins_from_new_data)
935 *(data->proper_sink) = sink;
937 if (((pa_sink_input*)(data->stream))->sink != sink)
938 pa_sink_input_move_to(data->stream, sink, false);
942 /* source-output case */
943 if ((source = pa_tz_device_get_source(device, NULL))) {
944 if (data->origins_from_new_data)
945 *(data->proper_source) = source;
947 if (((pa_source_output*)(data->stream))->source != source)
948 pa_source_output_move_to(data->stream, source, false);
955 /* Set the proper sink(source) according to the data of the parameter.
956 * - ROUTE_TYPE_AUTO(_ALL)
957 * 1. Find the proper sink/source comparing between avail_devices
958 * and current connected devices.
959 * 2. If not found, set it to null sink/source.
960 * - ROUTE_TYPE_MANUAL(_EXT)
961 * 1. Find the proper sink/source comparing between avail_devices
962 * and manual_devices that have been set by user.
963 * 2. If not found, set it to null sink/source. */
964 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) {
965 pa_idxset *conn_devices = NULL;
966 pa_sink *null_sink = NULL;
967 pa_source *null_source = NULL;
973 pa_log_info("[SELECT] data(%p), stream_type(%d), stream_role(%s), device_role(%s), route_type(%d)",
974 data, data->stream_type, data->stream_role, data->device_role, data->route_type);
976 null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
977 null_source = (pa_source*)pa_namereg_get(u->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE);
978 if (!null_sink || !null_source) {
979 pa_log_error("[SELECT] could not get null_sink(%p) or null_source(%p)", null_sink, null_source);
983 /* check if the current occupying role is related to call.
984 * some targets use several pcm card as per their purpose.
985 * e.g) using a specific pcm card during voice call. */
986 if (data->occupying_role) {
987 if (IS_ROLE_COMMUNICATION(data->occupying_role)) {
988 CONVERT_TO_DEVICE_ROLE(data->occupying_role, data->device_role);
989 pa_log_info("[SELECT] current occupying stream role is [%s], set device role to [%s]", data->occupying_role, data->device_role);
993 if (!data->idx_avail_devices) {
994 pa_log_error("[SELECT] available devices is NULL, set it to null sink/source");
998 if (IS_MANUAL_ROUTE_TYPE_SERIES(data->route_type) && !data->idx_manual_devices) {
999 pa_log_error("[SELECT] manual devices is NULL, set it to null sink/source");
1003 if (IS_AUTO_ROUTE_TYPE_SERIES(data->route_type)) {
1004 /* get current connected devices */
1005 conn_devices = pa_device_manager_get_device_list(u->device_manager);
1006 if (data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL)
1007 select_device_by_auto_or_auto_all_routing(u, data, conn_devices);
1008 else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED)
1009 select_device_by_auto_last_connected_routing(u, data, conn_devices);
1011 } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL) {
1012 select_device_by_manual_routing(u, data, null_sink, null_source);
1014 } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
1015 select_device_by_manual_external_routing(u, data);
1019 if (data->origins_from_new_data) {
1020 if ((data->stream_type == STREAM_SINK_INPUT) ? !(*(data->proper_sink)) : !(*(data->proper_source))) {
1021 pa_log_warn("[SELECT] could not find a proper sink/source, set it to null sink/source");
1022 if (data->stream_type == STREAM_SINK_INPUT)
1023 *(data->proper_sink) = null_sink;
1025 *(data->proper_source) = null_source;
1032 static void reset_route(struct userdata *u, stream_type_t stream_type) {
1033 hal_route_info route_info = {NULL, NULL, 0};
1034 pa_sink *null_sink = NULL;
1038 if (u->module_loopback) {
1039 if (stream_type == STREAM_SINK_INPUT && u->loopback_args.sink->use_internal_codec)
1040 update_loopback_module(u, false);
1041 else if (stream_type == STREAM_SOURCE_OUTPUT && u->loopback_args.source->use_internal_codec)
1042 update_loopback_module(u, false);
1045 /* update BT SCO: close */
1046 update_bt_sco_state(u, false, true, NULL);
1048 /* unload combine sink */
1049 if (stream_type == STREAM_SINK_INPUT) {
1050 if (null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK))
1051 unload_combine_sink_module(u, SINK_NAME_COMBINED, null_sink);
1054 route_info.role = "reset";
1055 route_info.num_of_devices = 1;
1056 route_info.device_infos = pa_xmalloc0(sizeof(hal_device_info)*route_info.num_of_devices);
1057 route_info.device_infos[0].direction = CONVERT_TO_HAL_DIRECTION(stream_type);
1059 /* send information to HAL to update route */
1060 if (pa_hal_interface_update_route(u->hal_interface, &route_info))
1061 pa_log_error("[ROUTE] Failed to pa_hal_interface_update_route()");
1063 pa_xfree(route_info.device_infos);
1066 /* Some H/W can have several alsa cards to serve various purposes. Therefore,
1067 * a particular stream may have to use a specific card, e.g) during voice call.
1068 * Here are codes to move streams to the specific device according to device role.
1069 * It has to be set only when the new_data is true - start routing of the new
1070 * highest priority stream. */
1071 static void route_change_move_streams(struct userdata *u, pa_stream_manager_hook_data_for_route *data, pa_tz_device *device) {
1072 const char *device_role;
1075 pa_idxset *streams = NULL;
1076 pa_sink *sink = NULL;
1077 pa_sink *dst_sink = NULL;
1078 pa_source *source = NULL;
1079 pa_source *dst_source = NULL;
1084 /* if it's NOT from new_data, return here */
1085 if (!device || !data->origins_from_new_data)
1089 if (!IS_ROLE_COMMUNICATION(data->stream_role))
1092 CONVERT_TO_DEVICE_ROLE(data->stream_role, device_role);
1093 pa_log_info("[ROUTE][MOVE] stream_role[%s], device role[%s]", data->stream_role, device_role);
1094 if (data->stream_type == STREAM_SINK_INPUT) {
1095 if (!(sink = pa_tz_device_get_sink(device, NULL)) ||
1096 !(dst_sink = pa_tz_device_get_sink(device, device_role)) ||
1098 pa_log_info("[ROUTE][MOVE][%s] no need to move streams, sink(%p), dst_sink(%p)", data->stream_role, sink, dst_sink);
1101 streams = sink->inputs;
1102 } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
1103 if (!(source = pa_tz_device_get_source(device, NULL)) ||
1104 !(dst_source = pa_tz_device_get_source(device, device_role)) ||
1105 source == dst_source) {
1106 pa_log_info("[ROUTE][MOVE][%s] no need to move streams, source(%p), dst_source(%p)", data->stream_role, source, dst_source);
1109 streams = source->outputs;
1112 if (!streams || (pa_idxset_size(streams) == 0))
1115 /* move other streams that belong to the device of NORMAL role */
1116 PA_IDXSET_FOREACH(s, streams, idx) {
1117 if (data->stream_type == STREAM_SINK_INPUT) {
1118 pa_sink_input_move_to(s, dst_sink, false);
1119 pa_log_info("[ROUTE][MOVE][%s] *** sink-input(%p,%u) moves to sink(%p,%s)",
1120 data->stream_role, s, ((pa_sink_input*)s)->index, dst_sink, dst_sink->name);
1121 } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
1122 pa_source_output_move_to(s, dst_source, false);
1123 pa_log_info("[ROUTE][MOVE][%s] *** source-output(%p,%u) moves to source(%p,%s)",
1124 data->stream_role, s, ((pa_source_output*)s)->index, dst_source, dst_source->name);
1127 /* make sure the previous device is closed */
1128 if (data->stream_type == STREAM_SINK_INPUT)
1129 pa_sink_suspend(sink, true, PA_SUSPEND_INTERNAL);
1130 else if (data->stream_type == STREAM_SOURCE_OUTPUT)
1131 pa_source_suspend(source, true, PA_SUSPEND_INTERNAL);
1134 /* Some H/W can have several alsa cards to serve various purposes. Therefore,
1135 * a particular stream may have to use a specific card, e.g) during voice call.
1136 * Here are codes to depart from the above situation and move streams to the device
1137 * for rollback if needed only when the new_data is false - end of stream or
1138 * start routing of the new highest priority stream. */
1139 static void route_change_rollback_streams(struct userdata *u, pa_stream_manager_hook_data_for_route *data, pa_tz_device *device) {
1140 pa_sink *sink = NULL;
1141 pa_source *source = NULL;
1144 pa_sink *combine_sink = NULL;
1149 /* if it's from new_data, return here */
1150 if (!device || data->origins_from_new_data)
1152 if (!data->stream || !data->idx_streams || pa_idxset_size(data->idx_streams) == 0)
1154 if (!IS_AUTO_ROUTE_TYPE_SERIES(data->route_type))
1156 if (data->stream_type == STREAM_SINK_INPUT) {
1157 if (!(sink = pa_tz_device_get_sink(device, data->device_role)))
1159 pa_sink_suspend(sink, false, PA_SUSPEND_INTERNAL);
1160 } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
1161 if (!(source = pa_tz_device_get_source(device, data->device_role)))
1163 pa_source_suspend(source, false, PA_SUSPEND_INTERNAL);
1166 PA_IDXSET_FOREACH(s, data->idx_streams, idx) {
1167 if (sink && sink != ((pa_sink_input*)s)->sink) {
1168 if ((pa_stream_manager_check_name_is_vstream(s, STREAM_SINK_INPUT, false)))
1170 if (((combine_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK)) &&
1171 ((pa_sink_input*)s)->sink == combine_sink))
1173 if ((pa_stream_manager_check_filter_apply_stream(s, STREAM_SINK_INPUT)))
1175 pa_sink_input_move_to(s, sink, false);
1176 pa_log_info("[ROUTE][ROLLBACK] *** sink-input(%p,%u) moves to sink(%p,%s)",
1177 s, ((pa_sink_input*)s)->index, sink, sink->name);
1178 } else if (source && source != ((pa_source_output*)s)->source) {
1179 pa_source_output_move_to(s, source, false);
1180 pa_log_info("[ROUTE][ROLLBACK] *** source-output(%p,%u) moves to source(%p,%s)",
1181 s, ((pa_source_output*)s)->index, source, source->name);
1186 static void fill_device_info(hal_route_info *route_info, const char *type, uint32_t direction, uint32_t id) {
1187 pa_assert(route_info);
1190 route_info->num_of_devices++;
1191 route_info->device_infos = pa_xrealloc(route_info->device_infos, sizeof(hal_device_info)*route_info->num_of_devices);
1192 route_info->device_infos[route_info->num_of_devices-1].type = type;
1193 route_info->device_infos[route_info->num_of_devices-1].direction = direction;
1194 route_info->device_infos[route_info->num_of_devices-1].id = id;
1195 pa_log_info(" ** filled a matched device to device_infos[%d]: type[%-16s], direction[0x%x], id[%u]",
1196 route_info->num_of_devices -1, type, direction, id);
1199 static pa_hook_result_t update_combine_sink_and_bt_sco(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
1200 pa_tz_device *device, const char *stream_role, const char *dm_device_type,
1201 pa_sink **combine_sink_arg1, pa_sink **combine_sink_arg2) {
1202 pa_sink *sink = NULL;
1208 switch (data->route_type) {
1209 case STREAM_ROUTE_TYPE_AUTO: {
1210 /* unload combine sink */
1211 if (data->stream_type == STREAM_SINK_INPUT) {
1212 if ((sink = pa_tz_device_get_sink(device, data->device_role)))
1213 unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
1215 pa_log_error("[ROUTE][AUTO] could not get sink");
1217 if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
1218 if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(stream_role)) {
1219 if (update_bt_sco_state(u, true, false, stream_role)) {
1220 pa_log_error(" ** could not open BT SCO");
1221 return PA_HOOK_CANCEL;
1223 update_bt_sco_option(u, stream_role);
1227 update_bt_sco_state(u, false, false, NULL);
1230 case STREAM_ROUTE_TYPE_AUTO_ALL: {
1231 pa_source *source = NULL;
1234 stream_route_type_t route_type;
1236 update_bt_sco_state(u, false, false, NULL);
1238 /* find the proper sink/source */
1239 /* currently, we support two sinks for combining */
1240 if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
1241 sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
1242 pa_log_info("[ROUTE][AUTO_ALL] found the combine_sink already existed");
1244 } else if (data->stream_type == STREAM_SINK_INPUT && !*combine_sink_arg1) {
1245 sink = *combine_sink_arg1 = pa_tz_device_get_sink(device, data->device_role);
1247 pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, *combine_sink_arg2);
1249 } else if (data->stream_type == STREAM_SINK_INPUT && !*combine_sink_arg2) {
1250 sink = *combine_sink_arg2 = pa_tz_device_get_sink(device, data->device_role);
1251 if (sink && !pa_safe_streq(sink->name, (*combine_sink_arg1)->name)) {
1252 pa_log_info("[ROUTE][AUTO_ALL] combine_sink_arg2[%s]", sink->name);
1253 sink = load_combine_sink_module(u, SINK_NAME_COMBINED, *combine_sink_arg1, *combine_sink_arg2, data->stream);
1256 } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
1257 source = pa_tz_device_get_source(device, data->device_role);
1260 if (data->origins_from_new_data) {
1261 if (data->stream_type == STREAM_SINK_INPUT)
1262 *(data->proper_sink) = sink;
1264 *(data->proper_source) = source;
1267 /* move sink-inputs/source-outputs if needed */
1268 if (!data->idx_streams)
1270 PA_IDXSET_FOREACH(s, data->idx_streams, s_idx) { /* data->idx_streams: null_sink */
1271 if (pa_stream_manager_get_route_type(s, data->stream_type, false, &route_type) ||
1272 (route_type != STREAM_ROUTE_TYPE_AUTO_ALL))
1274 if ((data->stream_type == STREAM_SINK_INPUT) && (sink && (sink != ((pa_sink_input*)s)->sink))) {
1275 pa_sink_input_move_to(s, sink, false);
1276 pa_log_info("[ROUTE][AUTO_ALL] *** sink-input(%p,%u) moves to sink(%p,%s)",
1277 s, ((pa_sink_input*)s)->index, sink, sink->name);
1278 } else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (source && (source != ((pa_source_output*)s)->source))) {
1279 pa_source_output_move_to(s, source, false);
1280 pa_log_info("[ROUTE][AUTO_ALL] *** source-output(%p,%u) moves to source(%p,%s)",
1281 s, ((pa_source_output*)s)->index, source, source->name);
1287 pa_log_error("it can not be here, route_type(%d)", data->route_type);
1293 static int32_t update_route_by_preemptive_device(struct userdata *u, pa_stream_manager_hook_data_for_route *data, hal_route_info *route_info, pa_tz_device **device) {
1294 uint32_t dm_device_id = 0;
1295 const char *dm_device_type = NULL;
1296 bool use_internal_codec = false;
1300 pa_assert(route_info);
1303 if (pa_stream_manager_get_preemptive_device_id(u->stream_manager, data->stream_type, data->stream_role, &dm_device_id))
1306 /* if this device id is no longer valid - disconnected. */
1307 if (!(*device = pa_device_manager_get_device_by_id(u->device_manager, dm_device_id)))
1310 dm_device_type = pa_tz_device_get_type(*device);
1311 pa_log_debug("preemptive device is type:[%s] id:[%u]", dm_device_type, dm_device_id);
1313 if (skip_usb_device(data->stream_role, *device))
1316 if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device))) {
1317 /* if it needs to skip it, keep going to next device for proper UCM setting */
1318 if (skip_device(data->stream_role, dm_device_type))
1320 if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
1322 fill_device_info(route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
1329 static pa_hook_result_t handle_auto_or_auto_all_routing(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
1330 hal_route_info *route_info, pa_idxset *conn_devices, pa_tz_device **device) {
1331 const char *device_type = NULL;
1332 const char *dm_device_type = NULL;
1333 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
1334 uint32_t dm_device_id = 0;
1336 uint32_t conn_idx = 0;
1337 bool use_internal_codec = false;
1338 pa_sink *combine_sink_arg1 = NULL;
1339 pa_sink *combine_sink_arg2 = NULL;
1343 pa_assert(route_info);
1344 pa_assert(conn_devices);
1347 if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
1348 if (!update_route_by_preemptive_device(u, data, route_info, device)) {
1349 dm_device_type = pa_tz_device_get_type(*device);
1350 goto update_auto_active_dev;
1354 PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
1355 pa_log_debug("[ROUTE][AUTO(_ALL)] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, route_info->role, device_type);
1356 if (!is_cached_device_connected(device_type, data->stream_type))
1359 PA_IDXSET_FOREACH(*device, conn_devices, conn_idx) {
1360 dm_device_type = pa_tz_device_get_type(*device);
1361 dm_device_direction = pa_tz_device_get_direction(*device);
1362 dm_device_id = pa_tz_device_get_id(*device);
1363 pa_log_debug(" -- type[%-16s], direction[0x%x], id[%u]",
1364 dm_device_type, dm_device_direction, dm_device_id);
1365 if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
1367 pa_log_debug(" ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
1368 if (skip_usb_device(data->stream_role, *device))
1370 if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device))) {
1371 /* if it needs to skip it, keep going to next device for proper UCM setting */
1372 if (skip_device(data->stream_role, dm_device_type))
1374 if (skip_bt_sco_device(u, data->stream_role, dm_device_type))
1376 fill_device_info(route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
1379 pa_log_debug(" -- it does not use internal audio codec, skip it");
1382 if (*device == NULL)
1385 if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
1386 update_auto_active_dev:
1387 if (data->origins_from_new_data)
1388 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type),
1389 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1391 pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type),
1392 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1393 return update_combine_sink_and_bt_sco(u, data, *device, route_info->role, dm_device_type, NULL, NULL);
1395 } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
1396 update_combine_sink_and_bt_sco(u, data, *device, NULL, NULL, &combine_sink_arg1, &combine_sink_arg2);
1402 static pa_hook_result_t handle_auto_last_connected_routing(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
1403 hal_route_info *route_info, pa_idxset *conn_devices, pa_tz_device **device) {
1404 pa_tz_device *latest_device = NULL;
1405 const char *device_type = NULL;
1406 const char *latest_device_type = NULL;
1407 const char *dm_device_type = NULL;
1408 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
1409 uint32_t dm_device_id = 0;
1411 uint32_t conn_idx = 0;
1412 pa_usec_t creation_time = 0;
1413 pa_usec_t latest_creation_time = 0;
1414 bool use_internal_codec = false;
1415 pa_sink *sink = NULL;
1419 pa_assert(route_info);
1420 pa_assert(conn_devices);
1423 if (!update_route_by_preemptive_device(u, data, route_info, device)) {
1424 latest_device = *device;
1425 dm_device_type = pa_tz_device_get_type(*device);
1426 goto update_auto_active_dev;
1429 PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
1430 pa_log_debug("[ROUTE][AUTO_LAST_CONN] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
1431 if (!is_cached_device_connected(device_type, data->stream_type))
1434 PA_IDXSET_FOREACH(*device, conn_devices, conn_idx) {
1435 dm_device_type = pa_tz_device_get_type(*device);
1436 dm_device_direction = pa_tz_device_get_direction(*device);
1437 dm_device_id = pa_tz_device_get_id(*device);
1438 creation_time = pa_tz_device_get_creation_time(*device);
1439 pa_log_debug(" -- type[%-16s], direction[0x%x], id[%u], creation_time[%llu]",
1440 dm_device_type, dm_device_direction, dm_device_id, creation_time);
1441 if (!pa_safe_streq(device_type, dm_device_type) || !IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction))
1443 if (skip_usb_device(data->stream_role, *device))
1445 if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device))) {
1446 /* if it needs to skip it, keep going to next device for proper UCM setting */
1447 if (skip_device(data->stream_role, dm_device_type) ||
1448 skip_bt_sco_device(u, data->stream_role, dm_device_type))
1451 if (!latest_device || (latest_creation_time <= creation_time)) {
1452 if (device_type_is_builtin(dm_device_type) && pa_safe_streq(latest_device_type, dm_device_type)) {
1453 if (data->stream_type == STREAM_SINK_INPUT ?
1454 (void*)pa_tz_device_get_sink(latest_device, data->device_role) :
1455 (void*)pa_tz_device_get_source(latest_device, data->device_role))
1458 latest_device = *device;
1459 latest_creation_time = creation_time;
1460 latest_device_type = dm_device_type;
1461 pa_log_info(" ** updated the last connected device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
1465 /* update activated device if it is found */
1466 if (latest_device) {
1467 dm_device_type = pa_tz_device_get_type(latest_device);
1468 dm_device_id = pa_tz_device_get_id(latest_device);
1469 if ((use_internal_codec = pa_tz_device_is_use_internal_codec(latest_device)))
1470 fill_device_info(route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), dm_device_id);
1472 pa_log_debug(" -- it does not use internal audio codec, skip it");
1474 update_auto_active_dev:
1475 if (data->origins_from_new_data)
1476 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type),
1477 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1479 pa_proplist_sets(GET_STREAM_PROPLIST(data->stream, data->stream_type),
1480 PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
1482 /* unload combine sink */
1483 if (data->stream_type == STREAM_SINK_INPUT) {
1484 if ((sink = pa_tz_device_get_sink(latest_device, data->device_role)))
1485 unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
1487 pa_log_error("[ROUTE][AUTO_LAST_CONN] could not get sink");
1490 if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO)) {
1491 if (IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info->role)) {
1492 if (update_bt_sco_state(u, true, false, route_info->role)) {
1493 pa_log_error(" ** could not open BT SCO");
1494 return PA_HOOK_CANCEL;
1496 update_bt_sco_option(u, route_info->role);
1499 update_bt_sco_state(u, false, false, NULL);
1502 /* Update device with latest_device to use be used later in this function */
1503 *device = latest_device;
1509 static pa_hook_result_t handle_manual_routing(struct userdata *u, pa_stream_manager_hook_data_for_route *data,
1510 hal_route_info *route_info, pa_tz_device **device) {
1511 const char *device_type = NULL;
1512 const char *dm_device_type = NULL;
1513 dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
1514 bool use_internal_codec = false;
1517 uint32_t *device_id = NULL;
1521 pa_assert(route_info);
1524 PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
1525 pa_log_info("[ROUTE][MANUAL] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
1526 if (!is_cached_device_connected(device_type, data->stream_type))
1529 PA_IDXSET_FOREACH(device_id, data->idx_manual_devices, d_idx) {
1530 pa_log_debug(" -- manual_device[%u] for this role[%-16s]: device_id(%u)", idx, data->stream_role, *device_id);
1531 if (!(*device = pa_device_manager_get_device_by_id(u->device_manager, *device_id)))
1533 dm_device_type = pa_tz_device_get_type(*device);
1534 if (!pa_safe_streq(device_type, dm_device_type))
1536 dm_device_direction = pa_tz_device_get_direction(*device);
1537 pa_log_debug(" ** found a matched device: type[%-16s], direction[0x%x]",
1538 dm_device_type, dm_device_direction);
1539 /* Check for availability for opening Bluetooth SCO */
1540 if (pa_safe_streq(dm_device_type, DEVICE_TYPE_BT_SCO) && IS_ROLE_AVAILABLE_BT_SCO_OPEN(route_info->role)) {
1541 /* update BT SCO: open */
1542 if (update_bt_sco_state(u, true, false, route_info->role)) {
1543 pa_log_error(" ** could not open BT SCO");
1544 return PA_HOOK_CANCEL;
1546 update_bt_sco_option(u, route_info->role);
1548 /* update BT SCO: close */
1549 update_bt_sco_state(u, false, false, NULL);
1551 /* Check for in/out devices in case of loopback */
1552 if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
1553 if ((data->stream_type == STREAM_SINK_INPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_OUT))
1554 u->loopback_args.sink = pa_tz_device_get_sink(*device, NULL);
1555 else if ((data->stream_type == STREAM_SOURCE_OUTPUT) && (dm_device_direction & DM_DEVICE_DIRECTION_IN))
1556 u->loopback_args.source = pa_tz_device_get_source(*device, NULL);
1559 if (IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
1560 if ((use_internal_codec = pa_tz_device_is_use_internal_codec(*device)))
1561 fill_device_info(route_info, dm_device_type, CONVERT_TO_HAL_DIRECTION(data->stream_type), *device_id);
1563 pa_log_debug(" -- it does not use internal audio codec, skip it");
1567 if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
1568 /* load module-loopback */
1569 if (u->loopback_args.sink && u->loopback_args.source)
1570 update_loopback_module(u, true);
1576 /* Change the route setting according to the data from argument.
1577 * This function is called only when it needs to change routing path via HAL.
1579 * 1. It will be received when it is needed to terminate playback
1580 * or capture routing path.
1581 * 2. Update the state of the device to be deactivated.
1582 * 3. Call HAL API to "reset" routing.
1584 * 1. Find the proper sink/source comparing between avail_devices
1585 * and current connected devices.
1586 * : Need to check the priority of the device list by order of receipt.
1587 * 2. Update the state of devices.
1588 * 3. Call HAL API to apply the routing setting
1589 * - ROUTE_TYPE_AUTO_ALL
1590 * 1. Find the proper sink/source comparing between avail_devices
1591 * and current connected devices.
1592 * : Might use combine-sink according to the conditions.
1593 * 2. Update the state of devices.
1594 * 3. Call HAL API to apply the routing setting
1595 * - ROUTE_TYPE_MANUAL
1596 * 1. Find the proper sink/source comparing between avail_devices
1597 * and manual_devices that have been set by user.
1598 * 2. Update the state of devices.
1599 * 3. Call HAL API to apply the routing setting. */
1600 static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_route *data, struct userdata *u) {
1601 hal_route_info route_info = {NULL, NULL, 0};
1602 pa_tz_device *device = NULL;
1603 pa_hook_result_t result;
1609 pa_log_info("[ROUTE] data(%p), stream_type(%d), stream_role(%s), route_type(%d)",
1610 data, data->stream_type, data->stream_role, data->route_type);
1612 if (data->stream == NULL) {
1613 reset_route(u, data->stream_type);
1614 pa_device_manager_update_device_running_state(u->device_manager,
1617 (data->stream_type == STREAM_SINK_INPUT) ? true : false);
1621 if (!data->idx_avail_devices) {
1622 pa_log_error("[ROUTE] available devices is NULL, do nothing...");
1626 if (IS_MANUAL_ROUTE_TYPE_SERIES(data->route_type) && !data->idx_manual_devices) {
1627 pa_log_error("[ROUTE] manual devices is NULL, do nothing...");
1631 route_info.role = data->stream_role;
1633 if (IS_AUTO_ROUTE_TYPE_SERIES(data->route_type)) {
1634 pa_idxset *conn_devices = NULL;
1636 /* unload module-loopback */
1637 if (u->module_loopback) {
1638 if (data->stream_type == STREAM_SINK_INPUT && u->loopback_args.sink->use_internal_codec)
1639 update_loopback_module(u, false);
1640 else if (data->stream_type == STREAM_SOURCE_OUTPUT && u->loopback_args.source->use_internal_codec)
1641 update_loopback_module(u, false);
1644 /* get current connected devices */
1645 conn_devices = pa_device_manager_get_device_list(u->device_manager);
1646 if (data->route_type == STREAM_ROUTE_TYPE_AUTO || data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL) {
1647 if ((result = handle_auto_or_auto_all_routing(u, data, &route_info, conn_devices, &device)))
1650 } else if (data->route_type == STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
1651 if ((result = handle_auto_last_connected_routing(u, data, &route_info, conn_devices, &device)))
1655 } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL) {
1656 if ((result = handle_manual_routing(u, data, &route_info, &device)))
1660 route_change_move_streams(u, data, device);
1662 if (route_info.device_infos) {
1663 /* send information to HAL to update route */
1664 if (pa_hal_interface_update_route(u->hal_interface, &route_info))
1665 pa_log_error("[ROUTE] Failed to pa_hal_interface_update_route()");
1666 pa_device_manager_update_device_running_state(u->device_manager,
1667 route_info.num_of_devices,
1668 (pa_device_info*)route_info.device_infos,
1669 (data->stream_type == STREAM_SINK_INPUT) ? true : false);
1670 pa_xfree(route_info.device_infos);
1673 route_change_rollback_streams(u, data, device);
1678 static pa_hook_result_t update_info_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_update_info *data, struct userdata *u) {
1683 if (pa_safe_streq(data->stream_role, STREAM_ROLE_LOOPBACK)) {
1684 pa_log_info("[UPDATE] stream_role(%s) [name(%s)/value(%d)]", data->stream_role, data->name, data->value);
1685 if (pa_safe_streq(data->name, MSG_FOR_LOOPBACK_ARG_LATENCY))
1686 u->loopback_args.latency_msec = data->value;
1687 else if (pa_safe_streq(data->name, MSG_FOR_LOOPBACK_ARG_ADJUST_TIME))
1688 u->loopback_args.adjust_sec = data->value;
1694 /* Update ref. count of each connected device */
1695 static void update_cached_connected_devices(const char *device_type, dm_device_direction_t direction, bool is_connected) {
1698 int* ptr_out = NULL;
1700 ptr_in = &cached_connected_devices[convert_device_type_str(device_type)][CACHED_DEVICE_DIRECTION_IN];
1701 ptr_out = &cached_connected_devices[convert_device_type_str(device_type)][CACHED_DEVICE_DIRECTION_OUT];
1702 val = (is_connected) ? 1 : -1;
1704 if (direction & DM_DEVICE_DIRECTION_IN)
1706 if (direction & DM_DEVICE_DIRECTION_OUT)
1715 static void dump_connected_devices()
1720 pa_log_debug("== dump cached current device ==");
1721 for (i = 0; i < DEVICE_MAX-1; i++)
1722 pa_log_debug("in: %d, out: %d", cached_connected_devices[i][CACHED_DEVICE_DIRECTION_IN], cached_connected_devices[i][CACHED_DEVICE_DIRECTION_OUT]);
1723 pa_log_debug("================================");
1727 /* Reorganize routing when a device has been connected or disconnected */
1728 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) {
1730 dm_device_direction_t device_direction = DM_DEVICE_DIRECTION_OUT;
1731 pa_sink *sink = NULL;
1732 pa_sink *null_sink = NULL;
1733 bool use_internal_codec = false;
1734 pa_idxset* conn_devices = NULL;
1735 pa_tz_device *device = NULL;
1741 device_direction = pa_tz_device_get_direction(conn->device);
1743 pa_log_info("[CONN] conn(%p), is_connected(%d), device(%p), direction(0x%x)",
1744 conn, conn->is_connected, conn->device, device_direction);
1746 update_cached_connected_devices(pa_tz_device_get_type(conn->device), device_direction, conn->is_connected);
1747 dump_connected_devices();
1749 sink = null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
1751 pa_log_error("[CONN] could not get null_sink(%p)", null_sink);
1755 use_internal_codec = pa_tz_device_is_use_internal_codec(conn->device);
1756 /* update for unloading modules when external device is disconnected */
1757 if (!use_internal_codec && !conn->is_connected) {
1758 if (device_direction & DM_DEVICE_DIRECTION_OUT) {
1759 /* unload combine sink */
1760 conn_devices = pa_device_manager_get_device_list(u->device_manager);
1761 PA_IDXSET_FOREACH(device, conn_devices, idx) {
1762 device_direction = pa_tz_device_get_direction(device);
1763 if (device_direction == DM_DEVICE_DIRECTION_OUT) {
1764 if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device))) {
1765 sink = pa_tz_device_get_sink(device, NULL);
1770 unload_combine_sink_module(u, SINK_NAME_COMBINED, sink);
1772 /* unload combine sink for external devices */
1773 unload_combine_sink_module(u, SINK_NAME_COMBINED_EX, null_sink);
1775 /* unload loopback module */
1776 if (u->module_loopback)
1777 if (u->loopback_args.sink == pa_tz_device_get_sink(conn->device, NULL))
1778 update_loopback_module(u, false);
1780 if (device_direction & DM_DEVICE_DIRECTION_IN) {
1781 /* unload loopback module */
1782 if (u->module_loopback)
1783 if (u->loopback_args.source == pa_tz_device_get_source(conn->device, NULL))
1784 update_loopback_module(u, false);
1791 int pa__init(pa_module *m)
1793 pa_modargs *ma = NULL;
1796 pa_module *module_loaded;
1800 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
1801 pa_log("Failed to parse module arguments");
1805 m->userdata = u = pa_xnew0(struct userdata, 1);
1808 u->module_null_sink_index = PA_INVALID_INDEX;
1809 u->module_null_source_index = PA_INVALID_INDEX;
1811 if (!(u->hal_interface = pa_hal_interface_get(u->core))) {
1812 pa_log("Failed to get hal interface");
1813 pa_modargs_free(ma);
1817 if ((u->communicator.comm = pa_communicator_get(u->core))) {
1818 u->communicator.comm_hook_select_proper_sink_or_source_slot = pa_hook_connect(
1819 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE),
1820 PA_HOOK_EARLY, (pa_hook_cb_t)select_proper_sink_or_source_hook_cb, u);
1821 u->communicator.comm_hook_change_route_slot = pa_hook_connect(
1822 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE),
1823 PA_HOOK_EARLY, (pa_hook_cb_t)route_change_hook_cb, u);
1824 u->communicator.comm_hook_device_connection_changed_slot = pa_hook_connect(
1825 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
1826 PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, u);
1827 u->communicator.comm_hook_update_info_slot = pa_hook_connect(
1828 pa_communicator_hook(u->communicator.comm, PA_COMMUNICATOR_HOOK_UPDATE_INFORMATION),
1829 PA_HOOK_EARLY, (pa_hook_cb_t)update_info_hook_cb, u);
1831 u->device_manager = pa_device_manager_get(u->core);
1832 u->stream_manager = pa_stream_manager_get(u->core);
1834 /* load null sink/source */
1835 args = pa_sprintf_malloc("sink_name=%s norewinds=1", SINK_NAME_NULL);
1836 if (pa_module_load(&module_loaded, u->core, MODULE_NULL_SINK, args))
1837 pa_log_error("failed to load module-null-sink");
1839 u->module_null_sink_index = module_loaded->index;
1842 args = pa_sprintf_malloc("source_name=%s max_latency_msec=100", SOURCE_NAME_NULL);
1843 if (pa_module_load(&module_loaded, u->core, MODULE_NULL_SOURCE, args))
1844 pa_log_error("failed to load module-null-source");
1846 u->module_null_source_index = module_loaded->index;
1849 __load_dump_config(u);
1851 pa_log_info("Tizen Audio Policy module is loaded\n");
1854 pa_modargs_free(ma);
1864 void pa__done(pa_module *m)
1870 if (!(u = m->userdata))
1873 bt_sco_close(u, false);
1875 if (u->module_null_sink_index != PA_INVALID_INDEX)
1876 pa_module_unload_by_index(m->core, u->module_null_sink_index, true);
1878 if (u->module_null_source_index != PA_INVALID_INDEX)
1879 pa_module_unload_by_index(m->core, u->module_null_source_index, true);
1881 if (u->device_manager)
1882 pa_device_manager_unref(u->device_manager);
1884 if (u->stream_manager)
1885 pa_stream_manager_unref(u->stream_manager);
1887 if (u->communicator.comm) {
1888 if (u->communicator.comm_hook_select_proper_sink_or_source_slot)
1889 pa_hook_slot_free(u->communicator.comm_hook_select_proper_sink_or_source_slot);
1890 if (u->communicator.comm_hook_change_route_slot)
1891 pa_hook_slot_free(u->communicator.comm_hook_change_route_slot);
1892 if (u->communicator.comm_hook_device_connection_changed_slot)
1893 pa_hook_slot_free(u->communicator.comm_hook_device_connection_changed_slot);
1894 if (u->communicator.comm_hook_update_info_slot)
1895 pa_hook_slot_free(u->communicator.comm_hook_update_info_slot);
1896 pa_communicator_unref(u->communicator.comm);
1899 if (u->hal_interface)
1900 pa_hal_interface_unref(u->hal_interface);
1904 pa_log_info("Tizen Audio Policy module is unloaded\n");