}
}
+/* The state of a device using internal audio codec is handled here.
+ * Regarding the state of an external device, it is handled in device-manager.c */
+static void set_device_state_if_using_internal_codec(pa_tz_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
+ dm_device_direction_t direction;
+
+ pa_assert(device);
+
+ direction = pa_tz_device_get_direction(device);
+ if (IS_AVAILABLE_DIRECTION(stream_type, direction))
+ if (pa_tz_device_is_use_internal_codec(device))
+ pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
+}
+
+/* threre is only one sco connected device */
+static pa_tz_device* _get_sco_connected_device(pa_device_manager *dm) {
+ pa_idxset *device_list;
+ pa_tz_device *device;
+ uint32_t device_idx;
+
+ pa_assert(dm);
+
+ device_list = pa_device_manager_get_device_list(dm);
+
+ PA_IDXSET_FOREACH(device, device_list, device_idx) {
+ if (pa_streq(device->type, DEVICE_TYPE_BT)) {
+ /* FIXME : not works */
+ if (pa_tz_device_have_profile(device, DEVICE_PROFILE_BT_SCO)) {
+ return device;
+ }
+ }
+ }
+ return NULL;
+}
+
+/* Open/Close BT SCO if it is possible */
+static int update_bt_sco_state(pa_device_manager *dm, bool open) {
+ dm_device_bt_sco_status_t sco_status;
+ pa_tz_device *bt_device;
+
+ pa_assert(dm);
+
+ bt_device = _get_sco_connected_device(dm);
+ if (bt_device == NULL) {
+ pa_log_debug("No SCO connected bt device");
+ return 0;
+ } else
+ pa_log_info("Got BT SCO connected device(%u)", bt_device->id);
+
+ if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
+ pa_log_error("get BT SCO status failed");
+ return -1;
+ }
+
+ if (sco_status == DM_DEVICE_BT_SCO_STATUS_DISCONNECTED) {
+ pa_log_info("BT SCO is not available for this BT device");
+ return 0;
+ }
+ if (open) {
+ if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED) {
+ if (pa_tz_device_sco_open(bt_device) < 0) {
+ pa_log_error("failed to open BT SCO");
+ return -1;
+ } else
+ pa_log_debug("BT SCO is now opened");
+ } else
+ pa_log_error("BT SCO is already opened for this BT device");
+ } else {
+ if (sco_status == DM_DEVICE_BT_SCO_STATUS_OPENED) {
+ if (pa_tz_device_sco_close(bt_device) < 0) {
+ pa_log_error("BT SCO was opened, but failed to close SCO");
+ return -1;
+ } else
+ pa_log_debug("BT SCO is now closed");
+ } else
+ pa_log_error("BT SCO is already closed for this BT device");
+ }
+
+ return 0;
+}
+
+/* Load/Unload module-loopback */
+static void update_loopback_module(struct userdata *u, bool load) {
+ char *args = NULL;
+
+ pa_assert(u);
+
+ if (load && u->loopback_args.sink && u->loopback_args.source) {
+ if (!u->loopback_args.latency_msec || !u->loopback_args.latency_msec) {
+ u->loopback_args.latency_msec = LOOPBACK_DEFAULT_LATENCY_MSEC;
+ u->loopback_args.adjust_sec = LOOPBACK_DEFAULT_ADJUST_SEC;
+ }
+ args = pa_sprintf_malloc("sink=%s source=%s latency_msec=%d adjust_time=%d",
+ u->loopback_args.sink->name, u->loopback_args.source->name,
+ u->loopback_args.latency_msec, u->loopback_args.adjust_sec);
+ if (u->module_loopback)
+ pa_module_unload(u->core, u->module_loopback, true);
+
+ u->module_loopback = pa_module_load(u->core, MODULE_LOOPBACK, args);
+
+ pa_log_info(" -- load module-loopback with (%s)", args);
+ pa_xfree(args);
+
+ } else if (!load) {
+ if (u->module_loopback) {
+ pa_module_unload(u->core, u->module_loopback, true);
+ u->module_loopback = NULL;
+ u->loopback_args.sink = NULL;
+ u->loopback_args.source = NULL;
+ pa_log_info(" -- unload module-loopback");
+ }
+ } else {
+ pa_log_error(" -- failed to update loopback module");
+ }
+}
+
/* Set the proper sink(source) according to the data of the parameter.
* - ROUTE_TYPE_AUTO(_ALL)
* 1. Find the proper sink/source comparing between avail_devices
return PA_HOOK_OK;
}
-/* The state of a device using internal audio codec is handled here.
- * Regarding the state of an external device, those is handled in device-manager.c */
-static void set_device_state_if_using_internal_codec(pa_tz_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
- bool use_internal_codec = false;
- dm_device_direction_t direction;
-
- pa_assert(device);
-
- direction = pa_tz_device_get_direction(device);
- if (IS_AVAILABLE_DIRECTION(stream_type, direction))
- if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device)))
- pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
-
- return;
-}
-
-/* threre is only one sco connected device */
-static pa_tz_device* _get_sco_connected_device(pa_device_manager *dm) {
- pa_idxset *device_list;
- pa_tz_device *device;
- uint32_t device_idx;
-
- pa_assert(dm);
-
- device_list = pa_device_manager_get_device_list(dm);
-
- PA_IDXSET_FOREACH(device, device_list, device_idx) {
- if (pa_streq(device->type, DEVICE_TYPE_BT)) {
- /* FIXME : not works */
- if (pa_tz_device_have_profile(device, DEVICE_PROFILE_BT_SCO)) {
- return device;
- }
- }
- }
- return NULL;
-}
-
-/* Open/Close BT SCO if it is possible */
-static int update_bt_sco_state(pa_device_manager *dm, bool open) {
- dm_device_bt_sco_status_t sco_status;
- pa_tz_device *bt_device;
-
- pa_assert(dm);
-
- bt_device = _get_sco_connected_device(dm);
- if (bt_device == NULL) {
- pa_log_debug("No SCO connected bt device");
- return 0;
- } else
- pa_log_info("Got BT SCO connected device(%u)", bt_device->id);
-
- if (pa_tz_device_sco_get_status(bt_device, &sco_status) < 0) {
- pa_log_error("get BT SCO status failed");
- return -1;
- }
-
- if (sco_status == DM_DEVICE_BT_SCO_STATUS_DISCONNECTED) {
- pa_log_info("BT SCO is not available for this BT device");
- return 0;
- }
- if (open) {
- if (sco_status == DM_DEVICE_BT_SCO_STATUS_CONNECTED) {
- if (pa_tz_device_sco_open(bt_device) < 0) {
- pa_log_error("failed to open BT SCO");
- return -1;
- } else
- pa_log_debug("BT SCO is now opened");
- } else
- pa_log_error("BT SCO is already opened for this BT device");
- } else {
- if (sco_status == DM_DEVICE_BT_SCO_STATUS_OPENED) {
- if (pa_tz_device_sco_close(bt_device) < 0) {
- pa_log_error("BT SCO was opened, but failed to close SCO");
- return -1;
- } else
- pa_log_debug("BT SCO is now closed");
- } else
- pa_log_error("BT SCO is already closed for this BT device");
- }
-
- return 0;
-}
-
-/* Load/Unload module-loopback */
-static void update_loopback_module(struct userdata *u, bool load) {
- char *args = NULL;
-
- pa_assert(u);
-
- if (load && u->loopback_args.sink && u->loopback_args.source) {
- if (!u->loopback_args.latency_msec || !u->loopback_args.latency_msec) {
- u->loopback_args.latency_msec = LOOPBACK_DEFAULT_LATENCY_MSEC;
- u->loopback_args.adjust_sec = LOOPBACK_DEFAULT_ADJUST_SEC;
- }
- args = pa_sprintf_malloc("sink=%s source=%s latency_msec=%d adjust_time=%d",
- u->loopback_args.sink->name, u->loopback_args.source->name,
- u->loopback_args.latency_msec, u->loopback_args.adjust_sec);
- if (u->module_loopback)
- pa_module_unload(u->core, u->module_loopback, true);
-
- u->module_loopback = pa_module_load(u->core, MODULE_LOOPBACK, args);
-
- pa_log_info(" -- load module-loopback with (%s)", args);
- pa_xfree(args);
-
- } else if (!load) {
- if (u->module_loopback) {
- pa_module_unload(u->core, u->module_loopback, true);
- u->module_loopback = NULL;
- u->loopback_args.sink = NULL;
- u->loopback_args.source = NULL;
- pa_log_info(" -- unload module-loopback");
- }
- } else {
- pa_log_error(" -- failed to update loopback module");
- }
-}
-
/* Change the route setting according to the data from argument.
* This function is called only when it needs to change routing path via HAL.
* - stream is null
pa_log_debug(" ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
use_internal_codec = pa_tz_device_is_use_internal_codec(device);
if (use_internal_codec) {
+ /* if the device type is forwarding, keep going to next device for proper UCM setting */
+ if (pa_streq(dm_device_type, DEVICE_TYPE_FORWARDING))
+ continue;
hal_direction = CONVERT_TO_HAL_DIRECTION(data->stream_type);
route_info.num_of_devices++;
route_info.device_infos = pa_xrealloc(route_info.device_infos, sizeof(hal_device_info)*route_info.num_of_devices);
*ptr_in = 0;
if (*ptr_out < 0)
*ptr_out = 0;
-
- return;
}
static void dump_connected_devices()
pa_log_debug("in: %d, out: %d", cached_connected_devices[i][CACHED_DEVICE_DIRECTION_IN], cached_connected_devices[i][CACHED_DEVICE_DIRECTION_OUT]);
pa_log_debug("================================");
#endif
- return;
}
/* Reorganize routing when a device has been connected or disconnected */
pa_xfree(u);
-
pa_log_info("Tizen Audio Policy module is unloaded\n");
}
pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[RET_MSG_INDEX_ERROR], DBUS_TYPE_INVALID));
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata) {
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
if (!ret)
send_volume_changed_signal(conn, direction, type, level);
-
- return;
}
static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
finish:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
finish:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_set_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
finish:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_get_volume_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
fail:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_get_current_volume_type(DBusConnection *conn, DBusMessage *msg, void *userdata) {
fail:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_update_focus_status(DBusConnection *conn, DBusMessage *msg, void *userdata) {
fail:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static void handle_update_restriction(DBusConnection *conn, DBusMessage *msg, void *userdata) {
fail:
pa_assert_se(dbus_connection_send(conn, reply, NULL));
dbus_message_unref(reply);
- return;
}
static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
pa_log_debug(" name[%d] : %s", idx, name);
}
pa_log_debug("===========[END stream-map dump]===========");
- return;
}
static int init_stream_map(pa_stream_manager *m) {
}
pa_hashmap_free(m->latency_infos);
}
-
- return;
}
static bool check_name_to_skip(pa_stream_manager *m, process_command_type_t command, void *stream, stream_type_t type, bool is_new_data) {
return ret;
}
-static bool check_role_to_skip(pa_stream_manager *m, const char *role) {
+static bool check_role_to_skip(pa_stream_manager *m, process_command_type_t command, const char *role) {
bool ret = true;
stream_info *s = NULL;
pa_assert(role);
if ((s = pa_hashmap_get(m->stream_infos, role)))
- ret = false;
+ ret = false;
+ if (s && pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING) &&
+ (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED ||
+ command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED))
+ ret = true;
pa_log_debug("role is [%s], skip(%d)", role, ret);
pa_log_info("*** maxlength:%d, fragsize:%d", maxlength, fragsize);
}
-
- return;
}
static void fill_device_info_to_hook_data(pa_stream_manager *m, void *hook_data, notify_command_type_t command, stream_type_t type, void *stream, bool is_new_data) {
default:
break;
}
- return;
}
static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, bool is_new_data, void *user_data) {
break;
}
}
- return;
+}
+
+static void update_mirroring_streams(pa_stream_manager *m, pa_source_output *o, bool put) {
+ const char *role;
+
+ pa_assert(m);
+ pa_assert(o);
+
+ if ((role = pa_proplist_gets(GET_STREAM_PROPLIST(o, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE)) &&
+ pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING)) {
+ if (put)
+ pa_idxset_put(m->mirroring_streams, o, NULL);
+ else
+ pa_idxset_remove_by_data(m->mirroring_streams, o, NULL);
+ }
+}
+
+/* Load/unload forwarding device */
+static int update_forwarding_device(pa_stream_manager *m, bool load) {
+ pa_assert(m);
+
+ if (load) {
+ if (pa_idxset_size(m->mirroring_streams) == 0) {
+ if (!pa_device_manager_load_forwarding(m->dm)) {
+ pa_log_error("could not load forwarding device");
+ return -1;
+ } else
+ pa_log_info("forwarding device is now loaded");
+ } else
+ pa_log_debug("forwarding device has been already loaded");
+
+ } else {
+ if (pa_idxset_size(m->mirroring_streams) > 0)
+ pa_log_debug("no need to unload forwarding device");
+ else {
+ pa_device_manager_unload_forwarding(m->dm);
+ pa_log_info("forwarding device is now unloaded");
+ }
+ }
+
+ return 0;
}
static process_stream_result_t process_stream(pa_stream_manager *m, void *stream, stream_type_t type, process_command_type_t command, bool is_new_data) {
pa_log_warn("role is null, set default to [%s]", role);
} else {
/* skip roles */
- if (check_role_to_skip(m, role)) {
+ if (check_role_to_skip(m, command, role)) {
result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
+ /* load forwarding device */
+ if (type == STREAM_SOURCE_OUTPUT && pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
+ update_forwarding_device(m, true);
}
/* update the priority of this stream */
ret = update_priority_of_stream(m, stream, type, role, is_new_data);
}
/* skip roles */
- if (check_role_to_skip(m, role)) {
+ if (check_role_to_skip(m, command, role)) {
result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
} else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED) {
role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
if (role) {
+ /* unload forwarding device */
+ if (type == STREAM_SOURCE_OUTPUT && pa_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
+ update_forwarding_device(m, false);
+
/* skip roles */
- if (check_role_to_skip(m, role)) {
+ if (check_role_to_skip(m, command, role)) {
result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
if (role) {
/* skip roles */
- if (check_role_to_skip(m, role)) {
+ if (check_role_to_skip(m, command, role)) {
result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
if (role) {
/* skip roles */
- if (check_role_to_skip(m, role)) {
+ if (check_role_to_skip(m, command, role)) {
result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
PA_IDXSET_FOREACH(si, streams, idx)
if (si == i)
pa_idxset_remove_by_data(streams, i, NULL);
-
- return;
}
static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data *new_data, pa_stream_manager *m) {
pa_log_info("start source_output_put_cb, o(%p, index:%u)", o, o->index);
+ update_mirroring_streams(m, o, true);
process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_PARENT_ID, false);
return PA_HOOK_OK;
pa_log_info("start source_output_unlink_cb, o(%p, index:%u)", o, o->index);
+ update_mirroring_streams(m, o, false);
process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_REMOVE_PARENT_ID, false);
}
pa_log_debug("next_device is [%p] for role[%s]/route_type[%d]/stream_type[%d]", *next_device, role, route_type, stream_type);
-
- return;
}
static void is_available_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *cur_device_type, const char *new_device_type, const char *role, stream_type_t stream_type, bool *available) {
}
pa_log_debug("is new_device[%s] available for role[%s]/stream_type[%d]:%d", new_device_type, role, stream_type, *available);
-
- return;
}
/* Re-trigger for routing update for streams using auto route type */
if (use_internal_codec)
process_stream(m, stream, stream_type, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, false);
}
-
- return;
}
/* The state of a device using internal audio codec is handled here.
if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device)))
pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
-
- return;
}
static void update_sink_or_source_as_device_change(stream_route_type_t stream_route_type, pa_idxset *streams,
}
} else
pa_log_error("[SM][UPDATE_SINK_SOURCE] could not handle it here, stream_route_type(%d)", stream_route_type);
-
- return;
}
static void mute_sink_inputs_as_device_disconnection(pa_stream_manager *m, uint32_t event_id, bool need_to_mute, void *user_data) {
PA_IDXSET_FOREACH(i, muted_streams, s_idx) {
pa_idxset_remove_by_data(muted_streams, i, NULL);
pa_sink_input_remove_volume_factor(i, mute_key);
+ pa_log_debug("found a stream(%p, %u) that should be un-muted.", i, i->index);
}
pa_hashmap_remove(m->muted_streams, (void*)event_id);
pa_idxset_free(muted_streams, NULL);
send_command_signal(pa_dbus_connection_get(m->dbus_conn), name, value);
}
#endif
-
- return;
}
static int32_t init_ipc(pa_stream_manager *m) {
}
#endif
#endif
- return;
}
bool pa_stream_manager_check_name_is_vstream(void *stream, stream_type_t type, bool is_new_data) {
goto fail;
m->stream_parents = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
m->muted_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+ m->mirroring_streams = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
m->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_new_cb, m);
m->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_put_cb, m);
pa_hashmap_free(m->muted_streams);
}
+ if (m->mirroring_streams) {
+ if (pa_idxset_size(m->mirroring_streams))
+ update_forwarding_device(m, false);
+ pa_idxset_free(m->mirroring_streams, NULL);
+ }
+
if (m->stream_parents)
pa_hashmap_free(m->stream_parents);