static void handle_get_stream_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_volume_max_level(DBusConnection *conn, DBusMessage *msg, void *userdata);
{ "name", "s", "in" },
{ "value", "i", "in" },
{ "ret_msg", "s", "out" } };
+static pa_dbus_arg_info set_stream_preferred_device_args[] = { { "parent_id", "u", "in" },
+ { "device_id", "u", "in" },
+ { "ret_msg", "s", "out" } };
static pa_dbus_arg_info set_volume_level_args[] = { { "io_direction", "s", "in" },
{ "type", "s", "in" },
{ "level", "u", "in" },
{ "stream_types", "as", "in" },
{ "pid", "u", "out" },
{ "ret_msg", "s", "out" } };
-static const char* signature_args_for_in[] = { "s", "", "uauau", "usi", "ssu", "ss", "ss", "ssu", "ss", "sud", "su", "s", "s", "uu", "iu", "su", "s", "ssss", "s", "sss", "uss","sas"};
+static const char* signature_args_for_in[] = { "s", "", "uauau", "usi", "uu","ssu", "ss", "ss", "ssu", "ss", "sud", "su", "s", "s", "uu", "iu", "su", "s", "ssss", "s", "sss", "uss","sas"};
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
[METHOD_HANDLER_GET_STREAM_INFO] = {
.arguments = set_stream_route_option_args,
.n_arguments = sizeof(set_stream_route_option_args) / sizeof(pa_dbus_arg_info),
.receive_cb = handle_set_stream_route_option },
+ [METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE] = {
+ .method_name = STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREFERRED_DEVICE,
+ .arguments = set_stream_preferred_device_args,
+ .n_arguments = sizeof(set_stream_preferred_device_args) / sizeof(pa_dbus_arg_info),
+ .receive_cb = handle_set_stream_preferred_device },
[METHOD_HANDLER_SET_VOLUME_LEVEL] = {
.method_name = STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL,
.arguments = set_volume_level_args,
dbus_message_unref(reply);
}
+static void handle_set_stream_preferred_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ uint32_t sp_id = 0;
+ uint32_t device_id = 0;
+ uint32_t idx;
+ uint32_t count = 0;
+ pa_tz_device *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;
+ DBusMessage *reply = NULL;
+
+ pa_stream_manager *m = (pa_stream_manager*)userdata;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(m);
+
+ pa_assert_se(dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_UINT32, &sp_id,
+ DBUS_TYPE_UINT32, &device_id,
+ DBUS_TYPE_INVALID));
+ pa_log_info("stream parent id[%u], device_id[%u]", sp_id, device_id);
+
+ pa_assert_se((reply = dbus_message_new_method_return(msg)));
+
+ if (!(sp = pa_hashmap_get(m->stream_parents, (const void*)sp_id))) {
+ pa_log_error("could not find matching client for this parent_id[%u]", sp_id);
+ ret = RET_MSG_ERROR_INTERNAL;
+ goto finish;
+ }
+
+ if (device_id == 0) {
+ /* in case of unset */
+ if (!sp->preferred_device.type) {
+ 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);
+ ret = RET_MSG_ERROR_DEVICE_NOT_FOUND;
+ goto finish;
+ }
+ pa_log_debug("unset preferred device, rollback to type(%s), id(%u)", pa_tz_device_get_type(device), pa_tz_device_get_id(device));
+ } else {
+ /* get device role from device id */
+ if (!(device = pa_device_manager_get_device_by_id(m->dm, device_id))) {
+ pa_log_error("could not get device by id[%u]", device_id);
+ 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));
+ }
+
+ /* only allow built-in device types */
+ if (!device_type_is_builtin(device->type)) {
+ pa_log_error("This device(id:%u, type:%s) is not built-in type", device_id, device->type);
+ ret = RET_MSG_ERROR_POLICY;
+ goto finish;
+ }
+
+ /* allow only auto routing type */
+ if (sp->route_type != STREAM_ROUTE_TYPE_AUTO &&
+ sp->route_type != STREAM_ROUTE_TYPE_AUTO_LAST_CONNECTED) {
+ pa_log_error("not allowed this route type[%d] of this parent_id[%u]", sp->route_type, sp_id);
+ ret = RET_MSG_ERROR_POLICY;
+ goto finish;
+ }
+
+ /* 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);
+
+ 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);
+
+ 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--;
+ }
+ count = pa_idxset_size(sp->idx_source_outputs);
+ PA_IDXSET_FOREACH(stream, sp->idx_source_outputs, idx) {
+ 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);
+ else
+ pa_proplist_sets(GET_STREAM_PROPLIST(stream, STREAM_SOURCE_OUTPUT),
+ PA_PROP_MEDIA_ROUTE_AUTO_PREFERRED_DEVICE_ROLE,
+ 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 (!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);
+ }
+ }
+ count--;
+ }
+
+finish:
+ pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &stream_manager_dbus_ret_str[ret], DBUS_TYPE_INVALID));
+ pa_assert_se(dbus_connection_send(conn, reply, NULL));
+ dbus_message_unref(reply);
+}
+
static void handle_set_volume_level(DBusConnection *conn, DBusMessage *msg, void *userdata) {
const char *direction = NULL;
const char *type = NULL;