{ "value", "i", "in" },
{ "ret_msg", "s", "out" } };
static pa_dbus_arg_info set_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
+ { "io_direction", "s", "in" },
{ "device_id", "u", "in" },
{ "ret_msg", "s", "out" } };
static pa_dbus_arg_info set_volume_level_args[] = { { "io_direction", "s", "in" },
"", /* METHOD_HANDLER_GET_STREAM_LIST */
"uauau", /* METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES */
"usi", /* METHOD_HANDLER_SET_STREAM_ROUTE_OPTION */
- "uu", /* METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE */
+ "usu", /* METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE */
"ssu", /* METHOD_HANDLER_SET_VOLUME_LEVEL */
"ss", /* METHOD_HANDLER_GET_VOLUME_LEVEL */
"ss", /* METHOD_HANDLER_GET_VOLUME_MAX_LEVEL */
}
static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ const char *device_direction = NULL;
uint32_t sp_id = 0;
uint32_t device_id = 0;
uint32_t idx;
uint32_t count = 0;
+ stream_direction_t direction;
pa_tz_device *device;
+ pa_tz_device *prev_device;
const char *device_role;
const char *prev_device_type;
const char *prev_device_role;
stream_parent *sp = NULL;
void *stream;
- ret_msg_t ret = RET_MSG_OK;
+ pa_idxset *streams;
+ pa_proplist *props;
+ pa_proplist *device_props;
+ uint32_t stream_index;
+ pa_hashmap *devices;
+ void *new_device = NULL;
+ ret_msg_t ret = RET_MSG_OK;
DBusMessage *reply = NULL;
pa_stream_manager *m = (pa_stream_manager*)userdata;
pa_assert_se(dbus_message_get_args(msg, NULL,
DBUS_TYPE_UINT32, &sp_id,
+ DBUS_TYPE_STRING, &device_direction,
DBUS_TYPE_UINT32, &device_id,
DBUS_TYPE_INVALID));
- pa_log_info("stream parent id[%u], device_id[%u]", sp_id, device_id);
+ pa_log_info("stream parent id[%u], device direction[%s], device_id[%u]", sp_id, device_direction, device_id);
pa_assert_se((reply = dbus_message_new_method_return(msg)));
goto finish;
}
+ if (pa_safe_streq(device_direction, "in"))
+ direction = STREAM_DIRECTION_IN;
+ else if (pa_safe_streq(device_direction, "out"))
+ direction = STREAM_DIRECTION_OUT;
+ else {
+ ret = RET_MSG_ERROR_INVALID_ARGUMENT;
+ goto finish;
+ }
+
if (device_id == 0) {
/* in case of unset */
- if (!sp->preferred_device.type) {
+ if (!sp->preferred_device.types[direction]) {
pa_log_debug("it is already unset");
goto finish;
}
/* get a device of default role from previous device type */
- if (!(device = pa_device_manager_get_device(m->dm, sp->preferred_device.type))) {
- pa_log_error("could not get device[%s]", sp->preferred_device.type);
+ if (!(device = pa_device_manager_get_device(m->dm, sp->preferred_device.types[direction]))) {
+ pa_log_error("could not get device[%s]", sp->preferred_device.types[direction]);
ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
goto finish;
}
ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
goto finish;
}
- if (sp->preferred_device.type && !pa_streq(sp->preferred_device.type, device->type)) {
- pa_log_error("already set preferred device(%s, %s), unset it first", sp->preferred_device.type, sp->preferred_device.role);
- ret = RET_MSG_ERROR_INTERNAL;
- goto finish;
- }
pa_log_debug("requested preferred device type(%s), id(%u)", pa_tz_device_get_type(device), pa_tz_device_get_id(device));
}
/* get default role of the device */
device_role = pa_tz_device_get_role(device, NULL);
- sp->preferred_device.role = pa_safe_streq(device_role, DEVICE_ROLE_NORMAL) ? NULL : device_role;
- sp->preferred_device.type = sp->preferred_device.role ? device->type : NULL;
- pa_log_info("preferred device role is set to [%s] of device type[%s]", sp->preferred_device.role, device->type);
+ sp->preferred_device.roles[direction] = pa_safe_streq(device_role, DEVICE_ROLE_NORMAL) ? NULL : device_role;
+ sp->preferred_device.types[direction] = sp->preferred_device.roles[direction] ? device->type : NULL;
- count = pa_idxset_size(sp->idx_sink_inputs);
- PA_IDXSET_FOREACH(stream, sp->idx_sink_inputs, idx) {
- if (pa_safe_streq(device_role, DEVICE_ROLE_NORMAL))
- pa_proplist_unset(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT),
- PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
- else
- pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT),
- PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE,
- device_role);
+ pa_log_info("preferred device role is set to [%s] of device type[%s], direction[%s]",
+ sp->preferred_device.roles[direction], device->type, direction == STREAM_DIRECTION_OUT ? "out" : "in");
- prev_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(stream, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
- if (pa_safe_streq(prev_device_type, device->type)) {
- prev_device_role = pa_proplist_gets(PA_SINK_INPUT(stream)->sink->proplist, PA_PROP_DEVICE_ROLE);
- pa_log_debug("move stream[%u]: [%s][%s -> %s]",
- PA_SINK_INPUT(stream)->index, prev_device_type, prev_device_role, device_role);
- if (!pa_safe_streq(prev_device_role, device_role)) {
- pa_sink *new_sink = pa_hashmap_get(device->playback_devices, device_role);
- pa_sink_input_move_to(stream, new_sink, false);
- if (count == 1)
- /* Use PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED here.
- * It's not about the focus change, but this command exactly does what is needed here
- * including updating the highest priority, find the next stream to be set to HAL as well as
- * change the state of the builtin-device that use internal codec. */
- process_stream(m, stream, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
- }
- }
- count--;
+ if (direction == STREAM_DIRECTION_OUT) {
+ streams = sp->idx_sink_inputs;
+ devices = device->playback_devices;
+ } else {
+ streams = sp->idx_source_outputs;
+ devices = device->capture_devices;
}
- count = pa_idxset_size(sp->idx_source_outputs);
- PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
+
+ count = pa_idxset_size(streams);
+ PA_IDXSET_FOREACH(stream, streams, idx) {
+ props = GET_STREAM_PROPLIST(stream, (direction == STREAM_DIRECTION_OUT) ?
+ STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT);
+ pa_log_info("stream index(%u), props %p", (direction == STREAM_DIRECTION_OUT) ? PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index, props);
+ device_props = (direction == STREAM_DIRECTION_OUT) ?
+ PA_SINK_INPUT(stream)->sink->proplist : PA_SOURCE_OUTPUT(stream)->source->proplist;
+ stream_index = (direction == STREAM_DIRECTION_OUT) ?
+ PA_SINK_INPUT(stream)->index : PA_SOURCE_OUTPUT(stream)->index;
+
if (pa_safe_streq(device_role, DEVICE_ROLE_NORMAL))
- pa_proplist_unset(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT),
- PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
+ pa_proplist_unset(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE);
else
- pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT),
- PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE,
- device_role);
+ pa_proplist_sets(props, PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE, device_role);
+
+ prev_device_type = pa_proplist_gets(props, PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
+ prev_device_role = pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE);
- prev_device_type = pa_proplist_gets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV);
if (pa_safe_streq(prev_device_type, device->type)) {
- prev_device_role = pa_proplist_gets(PA_SOURCE_OUTPUT(stream)->source->proplist, PA_PROP_DEVICE_ROLE);
- pa_log_debug("move stream[%u]: [%s][%s -> %s]",
- PA_SOURCE_OUTPUT(stream)->index, prev_device_type, prev_device_role, device_role);
+ /* If the request is for the same device type,
+ * new device role should be applied - move streams. */
if (!pa_safe_streq(prev_device_role, device_role)) {
- pa_source *new_source = pa_hashmap_get(device->capture_devices, device_role);
- pa_source_output_move_to(stream, new_source, false);
- if (count == 1)
- process_stream(m, stream, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
+ new_device = pa_hashmap_get(devices, device_role);
+ pa_log_debug("move stream[%u]: [%s][%s -> %s]",
+ stream_index, prev_device_type, prev_device_role, device_role);
}
+ } else {
+ /* If the request is for a different device type,
+ * check the previous device role and move streams to default role if needed. */
+ prev_device = pa_device_manager_get_device(m->dm, prev_device_type);
+ new_device = pa_hashmap_first((direction == STREAM_DIRECTION_OUT) ?
+ prev_device->playback_devices : prev_device->capture_devices);
+ device_props = (direction == STREAM_DIRECTION_OUT) ? PA_SINK(new_device)->proplist : PA_SOURCE(new_device)->proplist;
+ pa_log_debug("may move stream[%u] to default role: [%s][%s -> %s]",
+ stream_index, prev_device_type, prev_device_role, pa_proplist_gets(device_props, PA_PROP_DEVICE_ROLE));
+ }
+ if (new_device) {
+ if (direction == STREAM_DIRECTION_OUT)
+ pa_sink_input_move_to(stream, PA_SINK(new_device), false);
+ else
+ pa_source_output_move_to(stream, PA_SOURCE(new_device), false);
}
+ if (count == 1)
+ /* Use PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED here.
+ * It's not about the focus change, but this command exactly does what is needed here
+ * including updating the highest priority, find the next stream to be set to HAL as well as
+ * change the state of the builtin-device that use internal codec. */
+ process_stream(m, stream, (direction == STREAM_DIRECTION_OUT) ? STREAM_SINK_INPUT : STREAM_SOURCE_OUTPUT,
+ PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_FOCUS_CHANGED, false);
count--;
}