stream-manager-dbus: Add new DBus methods to set preferred device 76/209476/6 accepted/tizen/unified/20190715.111909 submit/tizen/20190712.062844
authorSangchul Lee <sc11.lee@samsung.com>
Mon, 8 Jul 2019 06:44:27 +0000 (15:44 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 10 Jul 2019 02:15:00 +0000 (11:15 +0900)
  server          : org.pulseaudio.Server
  object path     : /org/pulseaudio/StreamManager
  interface       : org.pulseaudio.StreamManager

  method name     : SetStreamPreferredDevice
  method argument : unsigned int for stream index
                    unsidned int for device id
  return value    : string for return message
                    - success          : "STREAM_MANAGER_RETURN_OK"
                    - no match found   : "STREAM_MANAGER_RETURN_ERROR_DEVICE_NOT_FOUND"
                    - policy error     : "STREAM_MANAGER_RETURN_ERROR_POLICY"
                    - internal error   : "STREAM_MANAGER_RETURN_ERROR_INTERNAL"

[Version] 11.1.57
[Issue type] New feature

Change-Id: I2830efed90c7a76ca720766f1f01ab47db55ef03
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/pulseaudio-modules-tizen.spec
src/stream-manager-dbus-priv.h
src/stream-manager-dbus.c
src/stream-manager-priv.h
src/stream-manager.c

index 50cbbd6..c5d741a 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          11.1.56
+Version:          11.1.57
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 92f0ecd..8023f82 100644 (file)
@@ -30,6 +30,7 @@
 #define STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST                   "GetStreamList"
 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_DEVICES          "SetStreamRouteDevices"
 #define STREAM_MANAGER_METHOD_NAME_SET_STREAM_ROUTE_OPTION           "SetStreamRouteOption"
+#define STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREFERRED_DEVICE       "SetStreamPreferredDevice"
 #define STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL                  "SetVolumeLevel"
 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_LEVEL                  "GetVolumeLevel"
 #define STREAM_MANAGER_METHOD_NAME_GET_VOLUME_MAX_LEVEL              "GetVolumeMaxLevel"
@@ -57,6 +58,7 @@ enum method_handler_index {
     METHOD_HANDLER_GET_STREAM_LIST,
     METHOD_HANDLER_SET_STREAM_ROUTE_DEVICES,
     METHOD_HANDLER_SET_STREAM_ROUTE_OPTION,
+    METHOD_HANDLER_SET_STREAM_PREFERRED_DEVICE,
     METHOD_HANDLER_SET_VOLUME_LEVEL,
     METHOD_HANDLER_GET_VOLUME_LEVEL,
     METHOD_HANDLER_GET_VOLUME_MAX_LEVEL,
@@ -122,6 +124,11 @@ pa_dbus_interface_info stream_manager_interface_info = {
     "   <arg name=\"value\" direction=\"in\" type=\"i\"/>"                   \
     "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
     "  </method>"                                                            \
+    "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_STREAM_PREFERRED_DEVICE\">" \
+    "   <arg name=\"parent_id\" direction=\"in\" type=\"u\"/>"               \
+    "   <arg name=\"device_id\" direction=\"in\" type=\"u\"/>"               \
+    "   <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>"                \
+    "  </method>"                                                            \
     "  <method name=\"STREAM_MANAGER_METHOD_NAME_SET_VOLUME_LEVEL\">"        \
     "   <arg name=\"io_direction\" direction=\"in\" type=\"s\"/>"            \
     "   <arg name=\"type\" direction=\"in\" type=\"s\"/>"                    \
index 84789ee..5e7c715 100644 (file)
@@ -45,6 +45,7 @@ static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void
 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);
@@ -82,6 +83,9 @@ static pa_dbus_arg_info set_stream_route_option_args[]  = { { "parent_id", "u",
                                                                  { "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" },
@@ -146,7 +150,7 @@ static pa_dbus_arg_info get_pid_of_latest_stream_args[]  = { { "io_direction", "
                                                             { "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] = {
@@ -169,6 +173,11 @@ static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
         .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,
@@ -576,6 +585,149 @@ static void handle_set_stream_route_option(DBusConnection *conn, DBusMessage *ms
     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;
index a89b0c3..72ff199 100644 (file)
@@ -185,7 +185,10 @@ typedef struct _stream_parent {
     pa_idxset *idx_route_out_devices;
     focus_acquired_status_t focus_status;
     stream_route_type_t route_type;
-    const char *preferred_device_role;
+    struct _preferred_device {
+        const char *role;
+        const char *type;
+    } preferred_device;
 } stream_parent;
 
 typedef struct _filter_info {
index 8894a2c..ca4638c 100644 (file)
@@ -1116,10 +1116,10 @@ static void update_preferred_device_role(pa_stream_manager *m, void *stream, str
         return;
     }
 
-    if (sp->preferred_device_role)
+    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);
+                        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) {