if (!s->use_internal_codec && !pa_safe_streq(s->name, SINK_NAME_NULL))
if ((device = pa_device_manager_get_device_with_sink(s)))
pa_tz_device_set_running_and_notify(device, (state == PA_SINK_RUNNING));
+
} else if (pa_source_isinstance(pdevice)) {
pa_source *s = PA_SOURCE(pdevice);
pa_source_state_t state = pa_source_get_state(s);
/*
Build params for load sink or source, and load it.
*/
-static void* load_module(pa_core *c, bool is_sink, const char *device_string, const char *device_params) {
+static void* load_module(pa_core *c, bool is_sink, const char *device_string, const char *device_params, const char *device_role) {
const char *module_name;
pa_module *module;
pa_sink *sink;
if (is_sink) {
PA_IDXSET_FOREACH(sink, c->sinks, device_idx) {
if (sink->module == module) {
- pa_log_info("sink loaded : %s %u", sink->name, sink->index);
+ pa_log_info("sink loaded : %s %u %s", sink->name, sink->index, pa_strnull(device_role));
+ if (device_role)
+ pa_proplist_sets(sink->proplist, PA_PROP_DEVICE_ROLE, device_role);
return sink;
}
}
} else {
PA_IDXSET_FOREACH(source, c->sources, device_idx) {
if (source->module == module) {
- pa_log_info("source loaded : %s %u", source->name, source->index);
+ pa_log_info("source loaded : %s %u %s", source->name, source->index, pa_strnull(device_role));
+ if (device_role)
+ pa_proplist_sets(source->proplist, PA_PROP_DEVICE_ROLE, device_role);
return source;
}
}
void *state;
char *role;
const char *device_string, *params;
+ bool first_one = true;
+ void *device;
pa_assert(dm);
pa_assert(type_info);
pa_log_error("Failed to get param for %s", device_string);
continue;
}
- if (!(load_module(dm->core, is_playback, device_string, params))) {
+ if (!(device = load_module(dm->core, is_playback, device_string, params, role))) {
pa_log_warn("load device failed %s %s", device_string, params);
+ continue;
+ }
+ if (first_one && !pa_streq(role, DEVICE_ROLE_NORMAL)) {
+ /* NOTE: If the first role is not NORMAL, handle it as external devices.
+ * Because it's not ready to pass this information to audio HAL for now. */
+ if (is_playback)
+ PA_SINK(device)->use_internal_codec = false;
+ else
+ PA_SOURCE(device)->use_internal_codec = false;
+ first_one = false;
}
}
_load_forwarding_device(dm);
} else {
dm_device_direction_t direction;
+ bool use_internal_codec = true;
direction = device_type_get_static_direction(type);
if (direction != DM_DEVICE_DIRECTION_NONE) {
pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, NULL);
- _fill_new_data_basic(&data, type, direction, true, dm);
- if (direction & DM_DEVICE_DIRECTION_OUT)
+
+ if (direction & DM_DEVICE_DIRECTION_OUT) {
_fill_new_data_sinks(&data, type_info, dm);
- if (direction & DM_DEVICE_DIRECTION_IN)
+ if (use_internal_codec && pa_hashmap_size(data.playback_pcms))
+ use_internal_codec = (PA_SINK(pa_hashmap_first(data.playback_pcms)))->use_internal_codec;
+ }
+ if (direction & DM_DEVICE_DIRECTION_IN) {
_fill_new_data_sources(&data, type_info, dm);
+ if (use_internal_codec && pa_hashmap_size(data.capture_pcms))
+ use_internal_codec = (PA_SOURCE(pa_hashmap_first(data.capture_pcms)))->use_internal_codec;
+ }
+ _fill_new_data_basic(&data, type, direction, use_internal_codec, dm);
pa_tz_device_new(&data);
pa_tz_device_new_data_done(&data);
goto fail;
}
- if ((sink = load_module(dm->core, true, device_string, params))) {
+ if ((sink = load_module(dm->core, true, device_string, params, role))) {
pa_log_debug("loaded sink '%s' for '%s,%s' success", sink->name, type, role);
} else {
pa_log_warn("Cannot load playback device with '%s,%s'", device_string, params);
goto fail;
}
- if ((source = load_module(dm->core, false, device_string, params))) {
+ if ((source = load_module(dm->core, false, device_string, params, role))) {
pa_log_debug("loaded source '%s' for '%s,%s' success", source->name, type, role);
} else {
pa_log_warn("Cannot load capture device with '%s,%s'", device_string, params);
return true;
}
+static void update_preferred_device_role(pa_stream_manager *m, void *stream, stream_type_t type) {
+ const char *p_idx_str;
+ uint32_t parent_idx = 0;
+ stream_parent *sp = NULL;
+
+ pa_assert(m);
+ pa_assert(stream);
+
+ p_idx_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
+ if (!p_idx_str || pa_atou(p_idx_str, &parent_idx))
+ return;
+
+ if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx))) {
+ pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
+ return;
+ }
+
+ if (sp->preferred_device_role)
+ pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type),
+ PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE,
+ sp->preferred_device_role);
+}
+
static bool update_stream_parent_info(pa_stream_manager *m, process_command_type_t command, stream_type_t type, void *stream) {
const char *p_idx;
uint32_t parent_idx;
pa_stream_manager_hook_data_for_route hook_call_route_data;
hal_stream_connection_info stream_conn_info;
hal_route_option route_option;
- const char *role = NULL;
void *s = NULL;
const char *modifier_gain = NULL;
ret_msg_t ret = RET_MSG_OK;
hook_call_select_data.stream_type = type;
hook_call_select_data.origins_from_new_data = is_new_data;
if (is_new_data) {
- hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
+ hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type),
+ PA_PROP_MEDIA_ROLE);
+ hook_call_select_data.device_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type),
+ PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
fill_device_info_to_hook_data(m, &hook_call_select_data, command, type, s, is_new_data);
hook_call_select_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
if (type == STREAM_SINK_INPUT) {
}
}
} else {
- hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
+ hook_call_select_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type),
+ PA_PROP_MEDIA_ROLE);
+ hook_call_select_data.device_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type),
+ PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
fill_device_info_to_hook_data(m, &hook_call_select_data, command, type, s, is_new_data);
hook_call_select_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
if (type == STREAM_SINK_INPUT)
else if (type == STREAM_SOURCE_OUTPUT)
hook_call_select_data.proper_source = &(((pa_source_output*)s)->source);
}
- CONVERT_TO_DEVICE_ROLE(hook_call_select_data.stream_role, hook_call_select_data.device_role);
+ if (hook_call_select_data.route_type == STREAM_ROUTE_TYPE_MANUAL)
+ CONVERT_TO_DEVICE_ROLE(hook_call_select_data.stream_role, hook_call_select_data.device_role);
if (pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_select_data))
ret = RET_MSG_ERROR_INTERNAL;
BREAK_WITH_FREE:
if (s) {
if (is_new_data) {
hook_call_route_data.origins_from_new_data = true;
- role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
+ hook_call_route_data.stream_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
+ hook_call_route_data.device_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
hook_call_route_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
if (type == STREAM_SINK_INPUT) {
hook_call_route_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
hook_call_route_data.proper_source = &(((pa_source_output_new_data*)s)->source);
}
} else {
- role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
+ hook_call_route_data.stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
+ hook_call_route_data.device_role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
hook_call_route_data.idx_streams = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)s)->sink->inputs :
((pa_source_output*)s)->source->outputs;
}
hook_call_route_data.stream_type = type;
- hook_call_route_data.stream_role = role;
- CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
+ if (hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL)
+ CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
fill_device_info_to_hook_data(m, &hook_call_route_data, command, type, s, is_new_data);
if (hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL || hook_call_route_data.route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
if (hook_call_route_data.idx_manual_devices && !pa_idxset_size(hook_call_route_data.idx_manual_devices)) {
}
}
+ /* update the preferred device role, it will affect only built-in devices. */
+ update_preferred_device_role(m, stream, type);
+
/* check if it is a virtual stream */
if (check_name_is_vstream(stream, type, is_new_data)) {
pa_log_debug("skip notifying for selecting sink/source, rather set it to null sink/source");
}
} else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
+ const char *preferred_device_role;
+
if (is_new_data) {
role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
route_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
+ preferred_device_role = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type),
+ PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
} else {
role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE);
+ preferred_device_role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type),
+ PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
+ }
+
+ /* skip updating priority, focus status, the highest priority, ucm to HAL */
+ if (preferred_device_role) {
+ pa_log_debug("preferred device role[%s] is found, skip ROUTE_START", preferred_device_role);
+ goto skip_notifying_route_start;
}
/* skip roles */
}
}
+skip_notifying_route_start:
if (!is_new_data)
do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, false, stream);
} 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_safe_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
- update_forwarding_device(m, false);
+ const char *preferred_device_role;
- /* skip roles */
- if (check_role_to_skip(m, command, role)) {
- result = PROCESS_STREAM_RESULT_SKIP;
- goto finish;
- }
+ if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE))) {
+ pa_log_warn("role is null, skip it");
+ goto finish;
+ }
- /* skip route types */
- if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
- if (check_route_type_to_skip(command, route_type_str)) {
- result = PROCESS_STREAM_RESULT_SKIP;
- goto finish;
- }
- }
+ preferred_device_role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type),
+ PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
+ /* skip updating the highest priority, ucm to HAL */
+ if (preferred_device_role) {
+ pa_log_debug("preferred device role[%s] is found, skip ROUTE_END", preferred_device_role);
+ goto skip_notifying_route_end;
+ }
+
+ /* unload forwarding device */
+ if (type == STREAM_SOURCE_OUTPUT && pa_safe_streq(role, STREAM_ROLE_LOOPBACK_MIRRORING))
+ update_forwarding_device(m, false);
- /* check if it has already been processed (unlink or state_changed_cb) */
- if (pa_proplist_get(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&prior_priority, &size)) {
- pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, skip it..");
+ /* skip roles */
+ if (check_role_to_skip(m, command, role)) {
+ result = PROCESS_STREAM_RESULT_SKIP;
+ goto finish;
+ }
+
+ /* skip route types */
+ if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
+ if (check_route_type_to_skip(command, route_type_str)) {
result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
+ }
- ret = update_the_highest_priority_stream(m, command, stream, type, role, is_new_data, &need_update);
- if (ret == false) {
- pa_log_error("could not update the highest priority stream");
- result = PROCESS_STREAM_RESULT_STOP;
- goto finish;
- }
+ /* check if it has already been processed (unlink or state_changed_cb) */
+ if (pa_proplist_get(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_PRIORITY, (const void**)&prior_priority, &size)) {
+ pa_log_debug("it has already been processed for PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, skip it..");
+ result = PROCESS_STREAM_RESULT_SKIP;
+ goto finish;
+ }
- do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED, type, false, stream);
+ ret = update_the_highest_priority_stream(m, command, stream, type, role, is_new_data, &need_update);
+ if (ret == false) {
+ pa_log_error("could not update the highest priority stream");
+ result = PROCESS_STREAM_RESULT_STOP;
+ goto finish;
+ }
- /* need to skip if this stream does not belong to internal device */
- /* if needed, notify to update */
- if (need_update)
- do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
+skip_notifying_route_end:
+ do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_DISCONNECTED, type, false, stream);
- } else {
- pa_log_warn("role is null, skip it");
- }
+ /* need to skip if this stream does not belong to internal device */
+ /* if needed, notify to update */
+ if (need_update)
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
} else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED) {
- role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
- if (role) {
- /* skip roles */
- if (check_role_to_skip(m, command, role)) {
- result = PROCESS_STREAM_RESULT_SKIP;
- goto finish;
- }
+ if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE))) {
+ pa_log_warn("role is null, skip it");
+ goto finish;
+ }
- /* skip route types */
- if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
- if (check_route_type_to_skip(command, route_type_str)) {
- result = PROCESS_STREAM_RESULT_SKIP;
- goto finish;
- }
- }
+ /* skip roles */
+ if (check_role_to_skip(m, command, role)) {
+ result = PROCESS_STREAM_RESULT_SKIP;
+ goto finish;
+ }
- ret = update_the_highest_priority_stream(m, command, stream, type, role, is_new_data, &need_update);
- if (ret == false) {
- pa_log_error("could not update the highest priority stream");
- result = PROCESS_STREAM_RESULT_STOP;
+ /* skip route types */
+ if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
+ if (check_route_type_to_skip(command, route_type_str)) {
+ result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
+ }
- /* need to skip if this stream does not belong to internal device */
- /* if needed, notify to update */
- if (need_update)
- do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
-
- } else {
- pa_log_warn("role is null, skip it");
+ ret = update_the_highest_priority_stream(m, command, stream, type, role, is_new_data, &need_update);
+ if (ret == false) {
+ pa_log_error("could not update the highest priority stream");
+ result = PROCESS_STREAM_RESULT_STOP;
+ goto finish;
}
+ /* need to skip if this stream does not belong to internal device */
+ /* if needed, notify to update */
+ if (need_update)
+ do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_END, type, false, NULL);
+
} else if (command == PROCESS_COMMAND_UPDATE_VOLUME) {
if (is_new_data) {
si_volume_type_str = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_TIZEN_VOLUME_TYPE);
}
} else if (command == PROCESS_COMMAND_ADD_PARENT_ID || command == PROCESS_COMMAND_REMOVE_PARENT_ID) {
- role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
- if (role) {
- /* skip roles */
- if (check_role_to_skip(m, command, role)) {
+ if (!(role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE)))
+ goto finish;
+
+ /* skip roles */
+ if (check_role_to_skip(m, command, role)) {
+ result = PROCESS_STREAM_RESULT_SKIP;
+ goto finish;
+ }
+
+ /* skip route types */
+ if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
+ if (check_route_type_to_skip(command, route_type_str)) {
result = PROCESS_STREAM_RESULT_SKIP;
goto finish;
}
+ }
- /* skip route types */
- if ((route_type_str = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE_ROUTE_TYPE))) {
- if (check_route_type_to_skip(command, route_type_str)) {
- result = PROCESS_STREAM_RESULT_SKIP;
- goto finish;
+ if (!IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
+ if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
+ if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
+ m->cur_highest_priority.sink_input = stream;
+ m->cur_highest_priority.role_si = role;
+ m->cur_highest_priority.need_to_update_si = false;
}
- }
-
- if (!IS_ROUTE_TYPE_FOR_EXTERNAL_DEV(route_type_str, route_type)) {
- if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
- if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
- m->cur_highest_priority.sink_input = stream;
- m->cur_highest_priority.role_si = role;
- m->cur_highest_priority.need_to_update_si = false;
- }
- if (type == STREAM_SOURCE_OUTPUT && m->cur_highest_priority.need_to_update_so) {
- m->cur_highest_priority.source_output = stream;
- m->cur_highest_priority.role_so = role;
- m->cur_highest_priority.need_to_update_so = false;
- }
- do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, false, stream);
+ if (type == STREAM_SOURCE_OUTPUT && m->cur_highest_priority.need_to_update_so) {
+ m->cur_highest_priority.source_output = stream;
+ m->cur_highest_priority.role_so = role;
+ m->cur_highest_priority.need_to_update_so = false;
}
+ do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, false, stream);
}
+ }
- /* update parent stream info. */
- ret = update_stream_parent_info(m, command, type, stream);
- if (ret == false) {
- pa_log_debug("could not update the parent information of this stream");
- //return PROCESS_STREAM_RESULT_STOP;
- }
+ /* update parent stream info. */
+ ret = update_stream_parent_info(m, command, type, stream);
+ if (ret == false) {
+ pa_log_debug("could not update the parent information of this stream");
+ //return PROCESS_STREAM_RESULT_STOP;
}
+
} else if (command == PROCESS_COMMAND_UPDATE_BUFFER_ATTR) {
update_buffer_attribute(m, stream, type, is_new_data);
} else if (command == PROCESS_COMMAND_APPLY_FILTER) {