device-manager: Fix bug when load sink, and add unload_sink API 03/108403/5
authorJeongho Mok <jho.mok@samsung.com>
Tue, 3 Jan 2017 04:17:05 +0000 (13:17 +0900)
committerJeongho Mok <jho.mok@samsung.com>
Thu, 5 Jan 2017 04:07:11 +0000 (13:07 +0900)
[Version] 5.0.120
[Profile] Common
[Issue Type] Clean Up

Change-Id: I1c2ea08c8d71b9e38f1df0dbdbf8e4e0300392ad

packaging/pulseaudio-modules-tizen.spec
src/device-manager.c
src/device-manager.h

index 5d4c889..f370bf0 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          5.0.119
+Version:          5.0.120
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 5a027cc..cd80945 100644 (file)
     "   <arg name=\"mask_flags\" direction=\"in\" type=\"i\"/>\n"                           \
     "   <arg name=\"ConnectedDeviceList\" direction=\"out\" type=\"a(isiis)\"/>\n"          \
     "  </method>\n"                                                                         \
-    "  <method name=\"IsStreamOnDevice\">\n"                                          \
-    "   <arg name=\"stream_id\" direction=\"in\" type=\"i\"/>\n"                           \
-    "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"          \
-    "   <arg name=\"is_on\" direction=\"out\" type=\"b\"/>\n"          \
+    "  <method name=\"IsStreamOnDevice\">\n"                                                \
+    "   <arg name=\"stream_id\" direction=\"in\" type=\"i\"/>\n"                            \
+    "   <arg name=\"device_id\" direction=\"in\" type=\"i\"/>\n"                            \
+    "   <arg name=\"is_on\" direction=\"out\" type=\"b\"/>\n"                               \
     "  </method>\n"                                                                         \
     "  <method name='GetBTA2DPStatus'>"                                                     \
     "    <arg type='b' name='is_bt_on' direction='out'/>"                                   \
     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>\n"                                 \
     "  </method>\n"                                                                         \
+    "  <method name=\"UnloadSink\">\n"                                                      \
+    "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
+    "   <arg name=\"role\" direction=\"in\" type=\"s\"/>\n"                                 \
+    "  </method>\n"                                                                         \
+    "  <method name=\"DumpDeviceList\">\n"                                                  \
+    "  </method>\n"                                                                         \
     "  <method name=\"TestStatusChange\">\n"                                                \
     "   <arg name=\"device_type\" direction=\"in\" type=\"s\"/>\n"                          \
     "   <arg name=\"status\" direction=\"in\" type=\"i\"/>\n"                               \
@@ -395,6 +401,8 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *
 static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata);
 
 static int method_call_bt_get_name(DBusConnection *conn, const char *device_path, char **name);
@@ -404,6 +412,8 @@ enum method_handler_index {
     METHOD_HANDLER_IS_STREAM_ON_DEVICE,
     METHOD_HANDLER_GET_BT_A2DP_STATUS,
     METHOD_HANDLER_LOAD_SINK,
+    METHOD_HANDLER_UNLOAD_SINK,
+    METHOD_HANDLER_DUMP_DEVICE_LIST,
     METHOD_HANDLER_STATUS_TEST,
     METHOD_HANDLER_MAX
 };
@@ -421,6 +431,12 @@ static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
     [METHOD_HANDLER_LOAD_SINK] = {
         .method_name = "LoadSink",
         .receive_cb = handle_load_sink},
+    [METHOD_HANDLER_UNLOAD_SINK] = {
+        .method_name = "UnloadSink",
+        .receive_cb = handle_unload_sink},
+    [METHOD_HANDLER_DUMP_DEVICE_LIST] = {
+        .method_name = "DumpDeviceList",
+        .receive_cb = handle_dump_device_list},
     [METHOD_HANDLER_STATUS_TEST] = {
         .method_name = "TestStatusChange",
         .receive_cb = handle_test_device_status_change},
@@ -931,9 +947,9 @@ static const char* build_params_to_load_device(const char *device_string, const
             return NULL;
         }
         args_buf = pa_strbuf_new();
-        pa_strbuf_printf(args_buf, "device=hw:%s \n", alsa_device_name);
+        pa_strbuf_printf(args_buf, "device=hw:%s ", alsa_device_name);
         if (params) {
-            pa_strbuf_printf(args_buf, "%s\n", params);
+            pa_strbuf_printf(args_buf, "%s", params);
         }
         strncpy(args, pa_strbuf_tostring_free(args_buf), DEVICE_PARAM_STRING_MAX);
     } else {
@@ -1104,11 +1120,17 @@ pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager
     pa_dynarray *ctypes;
     struct composite_type *ctype;
     struct device_type_info *type_info;
-    const char *device_string, *role;
+    const char *device_string, *role, *param;
     uint32_t type_idx;
     pa_device_type_t pdt;
+    pa_idxset *file_infos;
+    pa_hashmap *pcm_devices;
+    void *state;
 
     pa_assert(pdevice);
+    pa_assert(dm);
+
+    pa_log_info("pulse device get belongs type");
 
     if (pulse_device_is_monitor(pdevice))
         return NULL;
@@ -1119,16 +1141,30 @@ pa_dynarray* pulse_device_get_belongs_type(pa_object *pdevice, pa_device_manager
 
     ctypes = pa_dynarray_new(pa_xfree);
 
-    if (pa_sink_isinstance(pdevice))
+    if (pa_sink_isinstance(pdevice)) {
         pdt = PA_DEVICE_TYPE_SINK;
-    else
+        file_infos = dm->file_map->playback;
+    } else {
         pdt = PA_DEVICE_TYPE_SOURCE;
+        file_infos = dm->file_map->capture;
+    }
 
+    /* iterate "device-types" in device-map.json */
     PA_IDXSET_FOREACH(type_info, dm->type_infos, type_idx) {
-        device_string = pulse_device_get_device_string(pdevice);
-        role = device_type_info_get_role(type_info, !pdt, device_string);
-        /* Found type_info which is matching with pulse_device */
-        if (role) {
+        if (pdt == PA_DEVICE_TYPE_SINK)
+            pcm_devices = type_info->playback_devices;
+        else
+            pcm_devices = type_info->capture_devices;
+        if (pcm_devices == NULL)
+            continue;
+        /* iterate "{playback,capture}-devices" in specific device-type */
+        PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
+            if (pulse_device_same_device_string(pdevice, device_string) == false)
+                continue;
+            param = _file_infos_get_param(file_infos, device_string, role);
+            if (pulse_device_params_is_equal(pdevice, param) == false)
+                continue;
+            /* Found type.role which is matching with pulse_device */
             ctype = pa_xmalloc0(sizeof(struct composite_type));
             ctype->type = type_info->type;
             ctype->role = role;
@@ -1239,8 +1275,9 @@ static void _fill_new_data_basic(pa_tz_device_new_data *data, const char *type,
 
 static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
     pa_sink *sink;
-    char *device_string, *role;
+    const char *device_string, *role, *param;
     void *state;
+    pa_idxset *file_infos;
 
     pa_assert(data);
     pa_assert(type_info);
@@ -1250,12 +1287,19 @@ static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_
         return -1;
     }
 
+    file_infos = dm->file_map->playback;
+    if (file_infos == NULL) {
+        pa_log_error("No playback pcm device config");
+        return -1;
+    }
+
     PA_HASHMAP_FOREACH_KV(role, device_string, type_info->playback_devices, state) {
-        sink = _core_get_sink(dm->core, device_string, NULL);
+        param = _file_infos_get_param(file_infos, device_string, role);
+        sink = _core_get_sink(dm->core, device_string, param);
         if (sink)
             pa_tz_device_new_data_add_sink(data, role, sink);
         else
-            pa_log_error("Failed to get matching sink for %s %s", role, device_string);
+            pa_log_warn("No matching sink for %s %s", device_string, role);
     }
 
     return 0;
@@ -1263,8 +1307,9 @@ static int _fill_new_data_sinks(pa_tz_device_new_data *data, struct device_type_
 
 static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_type_info *type_info, pa_device_manager *dm) {
     pa_source *source;
-    char *device_string, *role;
+    const char *device_string, *role, *param;
     void *state;
+    pa_idxset *file_infos;
 
     pa_assert(data);
     pa_assert(type_info);
@@ -1274,12 +1319,19 @@ static int _fill_new_data_sources(pa_tz_device_new_data *data, struct device_typ
         return -1;
     }
 
+    file_infos = dm->file_map->capture;
+    if (file_infos == NULL) {
+        pa_log_error("No capture pcm device config");
+        return -1;
+    }
+
     PA_HASHMAP_FOREACH_KV(role, device_string, type_info->capture_devices, state) {
-        source = _core_get_source(dm->core, device_string, NULL);
+        param = _file_infos_get_param(file_infos, device_string, role);
+        source = _core_get_source(dm->core, device_string, param);
         if (source)
             pa_tz_device_new_data_add_source(data, role, source);
         else
-            pa_log_error("Failed to get matching source for %s %s", role, device_string);
+            pa_log_warn("No matching source for %s %s", device_string, role);
     }
 
     return 0;
@@ -1628,6 +1680,29 @@ static void* load_device(pa_core *c, bool is_sink, const char *device_string, co
     return NULL;
 }
 
+static void unload_device(pa_core *c, bool is_sink, const char *device_string) {
+    pa_assert(c);
+    pa_assert(device_string);
+
+    pa_log_info("Unload %s Device : String'%s'", is_sink ? "Playback" : "Capture", device_string);
+
+    if (is_sink) {
+        pa_sink *sink = _core_get_sink(c, device_string, NULL);
+        if (sink == NULL) {
+            pa_log_warn("No matching sink");
+            return;
+        }
+        pa_module_unload(c, sink->module, true);
+    } else {
+        pa_source *source = _core_get_source(c, device_string, NULL);
+        if (source == NULL) {
+            pa_log_warn("No matching source");
+            return;
+        }
+        pa_module_unload(c, source->module, true);
+    }
+}
+
 static int _load_type_devices(struct device_type_info *type_info, bool is_playback, pa_device_manager *dm) {
     pa_hashmap *pcm_devices;
     pa_idxset *file_infos;
@@ -1654,18 +1729,19 @@ static int _load_type_devices(struct device_type_info *type_info, bool is_playba
     }
 
     PA_HASHMAP_FOREACH_KV(role, device_string, pcm_devices, state) {
-        params = _file_infos_get_param(file_infos, device_string, role);
-        if (params == NULL) {
-            pa_log_error("Failed to get param for %s", device_string);
+        /* skip duplicate load */
+        if (is_playback && _core_get_sink(dm->core, device_string, NULL)) {
+            pa_log_debug("Already loaded %s", device_string);
             continue;
         }
-        /* Check duplicate load */
-        if (is_playback && _core_get_sink(dm->core, device_string, params)) {
-            pa_log_debug("Already loaded %s %s", device_string, params);
+        if (!is_playback && _core_get_source(dm->core, device_string, NULL)) {
+            pa_log_debug("Already loaded %s", device_string);
             continue;
         }
-        if (!is_playback && _core_get_source(dm->core, device_string, params)) {
-            pa_log_debug("Already loaded %s %s", device_string, params);
+
+        params = _file_infos_get_param(file_infos, device_string, role);
+        if (params == NULL) {
+            pa_log_error("Failed to get param for %s", device_string);
             continue;
         }
         if (!(load_device(dm->core, is_playback, device_string, params))) {
@@ -2623,7 +2699,6 @@ static int method_call_bt_get_name(DBusConnection *conn, const char *device_path
     return 0;
 }
 
-
 static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     pa_device_manager *dm;
     DBusMessage *reply = NULL;
@@ -2783,6 +2858,39 @@ static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userd
     dbus_message_unref(reply);
 }
 
+static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+    pa_device_manager *dm;
+    char *type, *role;
+    DBusMessage *reply = NULL;
+
+    pa_assert_se((reply = dbus_message_new_method_return(msg)));
+    dm = (pa_device_manager *) userdata;
+    pa_assert_se(dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_STRING, &type,
+                                       DBUS_TYPE_STRING, &role,
+                                       DBUS_TYPE_INVALID));
+
+    pa_device_manager_unload_sink(dm, type, role);
+    pa_assert_se(dbus_connection_send(conn, reply, NULL));
+    dbus_message_unref(reply);
+}
+
+static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+    pa_device_manager *dm;
+    pa_tz_device *device;
+    uint32_t device_idx;
+    DBusMessage *reply = NULL;
+
+    pa_assert_se((reply = dbus_message_new_method_return(msg)));
+    dm = (pa_device_manager *) userdata;
+
+    PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
+        pa_tz_device_dump_info(device, PA_LOG_INFO);
+    }
+    pa_assert_se(dbus_connection_send(conn, reply, NULL));
+    dbus_message_unref(reply);
+}
+
 static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     pa_device_manager *dm = (pa_device_manager *)userdata;
     char *type;
@@ -2995,7 +3103,7 @@ void pa_device_manager_unload_forwarding(pa_device_manager *dm) {
         pa_log_warn("There is no forwarding device");
 }
 
-int pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
+pa_sink* pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role) {
     const char *device_string, *params;
     struct device_type_info *type_info;
     struct device_file_info *file_info;
@@ -3005,20 +3113,22 @@ int pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const c
 
     pa_assert(dm);
     pa_assert(dm->device_list);
+    pa_assert(type);
+    pa_assert(role);
 
     pa_log_info("Load Sink for '%s.%s'", type, role);
     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
         if (pa_streq(type, pa_tz_device_get_type(device))) {
-            if (pa_tz_device_get_sink(device, role) == NULL) {
+            if (pa_tz_device_get_sink(device, role)) {
                 pa_log_warn("Proper sink for '%s.%s' already loaded", type, role);
-                return -1;
+                return NULL;
             }
         }
     }
 
     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
         pa_log_error("No type map for %s", type);
-        return -1;
+        return NULL;
     }
 
     if (type_info->playback_devices == NULL) {
@@ -3041,20 +3151,49 @@ int pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const c
         goto fail;
     }
 
-    if ((sink = load_device(dm->core, PA_DEVICE_TYPE_SINK, device_string, params))) {
+    if ((sink = load_device(dm->core, true, device_string, params))) {
         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;
     }
 
-    return 0;
+    return sink;
 
 fail:
-    return -1;
+    return NULL;
+}
+
+void pa_device_manager_unload_sink(pa_device_manager *dm, const char *type, const char *role) {
+    const char *device_string;
+    struct device_type_info *type_info;
+
+    pa_assert(dm);
+    pa_assert(dm->device_list);
+    pa_assert(type);
+    pa_assert(role);
+
+    pa_log_info("Unload Sink for '%s.%s'", type, role);
+
+    if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
+        pa_log_error("No type map for %s", type);
+        return;
+    }
+
+    if (type_info->playback_devices == NULL) {
+        pa_log_error("No playback devices for %s", type_info->type);
+        return;
+    }
+
+    if (!(device_string = pa_hashmap_get(type_info->playback_devices, role))) {
+        pa_log_error("No device-string for '%s.%s'", type, role);
+        return;
+    }
+
+    unload_device(dm->core, true, device_string);
 }
 
-int pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
+pa_source* pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role) {
     const char *device_string, *params;
     struct device_type_info *type_info;
     struct device_file_info *file_info;
@@ -3063,21 +3202,24 @@ int pa_device_manager_load_source(pa_device_manager *dm, const char *type, const
     uint32_t device_idx;
 
     pa_assert(dm);
+    pa_assert(dm->device_list);
+    pa_assert(type);
+    pa_assert(role);
 
     pa_log_info("Load Source for '%s.%s'", type, role);
 
     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
         if (pa_streq(type, pa_tz_device_get_type(device))) {
-            if (pa_tz_device_get_source(device, role) == NULL) {
+            if (pa_tz_device_get_source(device, role)) {
                 pa_log_warn("Proper source for '%s.%s' already loaded", type, role);
-                return -1;
+                return NULL;
             }
         }
     }
 
     if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
         pa_log_error("No type map for %s", type);
-        return -1;
+        return NULL;
     }
 
     if (type_info->capture_devices == NULL) {
@@ -3100,17 +3242,46 @@ int pa_device_manager_load_source(pa_device_manager *dm, const char *type, const
         goto fail;
     }
 
-    if ((source = load_device(dm->core, PA_DEVICE_TYPE_SOURCE, device_string, params))) {
+    if ((source = load_device(dm->core, false, device_string, params))) {
         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);
         goto fail;
     }
 
-    return 0;
+    return source;
 
 fail:
-    return -1;
+    return NULL;
+}
+
+void pa_device_manager_unload_source(pa_device_manager *dm, const char *type, const char *role) {
+    const char *device_string;
+    struct device_type_info *type_info;
+
+    pa_assert(dm);
+    pa_assert(dm->device_list);
+    pa_assert(type);
+    pa_assert(role);
+
+    pa_log_info("Unload Source for '%s.%s'", type, role);
+
+    if (!(type_info = _device_manager_get_type_info(dm->type_infos, type))) {
+        pa_log_error("No type map for %s", type);
+        return;
+    }
+
+    if (type_info->capture_devices == NULL) {
+        pa_log_error("No capture devices for %s", type_info->type);
+        return;
+    }
+
+    if (!(device_string = pa_hashmap_get(type_info->capture_devices, role))) {
+        pa_log_error("No device-string for '%s.%s'", type, role);
+        return;
+    }
+
+    unload_device(dm->core, false, device_string);
 }
 
 static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_device_hook_data_for_conn_changed *data, pa_device_manager *dm) {
index 1db9dc0..389a8f8 100644 (file)
@@ -49,7 +49,9 @@ pa_tz_device* pa_device_manager_load_forwarding(pa_device_manager *dm);
 void pa_device_manager_unload_forwarding(pa_device_manager *dm);
 
 /* load pulse device */
-int pa_device_manager_load_sink(pa_device_manager *dm, const char *device_type, const char *role);
-int pa_device_manager_load_source(pa_device_manager *dm, const char *device_type, const char *role);
+pa_sink* pa_device_manager_load_sink(pa_device_manager *dm, const char *type, const char *role);
+pa_source* pa_device_manager_load_source(pa_device_manager *dm, const char *type, const char *role);
+void pa_device_manager_unload_sink(pa_device_manager *dm, const char *type, const char *role);
+void pa_device_manager_unload_source(pa_device_manager *dm, const char *type, const char *role);
 
 #endif