Change state concept 60/105460/6 accepted/tizen/3.0/common/20161221.180741 accepted/tizen/3.0/ivi/20161221.005602 accepted/tizen/3.0/mobile/20161221.005657 accepted/tizen/3.0/tv/20161221.005452 accepted/tizen/3.0/wearable/20161221.005539 submit/tizen_3.0/20161219.120436
authorJeongho Mok <jho.mok@samsung.com>
Fri, 16 Dec 2016 07:48:45 +0000 (16:48 +0900)
committerJeongho Mok <jho.mok@samsung.com>
Tue, 20 Dec 2016 11:17:20 +0000 (20:17 +0900)
[Version] 5.0.110
[Profile] Common
[Issue Type] Enhancement

Change-Id: I931df11ca3d9db5f573c1e876edb5876d4b7f3d4

packaging/pulseaudio-modules-tizen.spec
src/device-manager.c
src/module-tizenaudio-policy.c
src/stream-manager-priv.h
src/stream-manager.c
src/tizen-device.c
src/tizen-device.h

index 23aef73..4db8001 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          5.0.109
+Version:          5.0.110
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 1691005..d6e43d2 100644 (file)
@@ -1572,56 +1572,6 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc
     return PA_HOOK_OK;
 }
 
-
-
-static pa_hook_result_t sink_source_state_changed_hook_cb(pa_core *c, pa_object *pdevice, pa_device_manager *dm) {
-    pa_tz_device *device;
-    uint32_t idx = 0;
-
-    pa_assert(c);
-    pa_object_assert_ref(pdevice);
-    pa_assert(dm);
-
-    if (pa_sink_isinstance(pdevice)) {
-        pa_sink *s = PA_SINK(pdevice);
-        pa_sink_state_t state = pa_sink_get_state(s);
-        pa_log_debug("=========== Sink(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
-        if (s->use_internal_codec && state == PA_SINK_SUSPENDED) {
-            PA_IDXSET_FOREACH(device, dm->device_list, idx) {
-                if (pa_tz_device_is_use_internal_codec(device) && pa_tz_device_is_all_suspended(device))
-                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
-            }
-        } else {
-            if ((device = pa_device_manager_get_device_with_sink(s))) {
-                if (state == PA_SINK_RUNNING)
-                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_ACTIVATED);
-                else if (state == PA_SINK_SUSPENDED)
-                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_OUT, DM_DEVICE_STATE_DEACTIVATED);
-            }
-        }
-    } else if (pa_source_isinstance(pdevice)) {
-        pa_source *s = PA_SOURCE(pdevice);
-        pa_source_state_t state = pa_source_get_state(s);
-        pa_log_debug("=========== Source(%p,%s) state has been changed to [%d](0:RUNNING, 1:IDLE, 2:SUSPEND) ==========", s, s->name, state);
-        if (s->use_internal_codec && state == PA_SOURCE_SUSPENDED) {
-            PA_IDXSET_FOREACH(device, dm->device_list, idx) {
-                if (pa_tz_device_is_use_internal_codec(device) && pa_tz_device_is_all_suspended(device))
-                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
-            }
-        } else {
-            if ((device = pa_device_manager_get_device_with_source(s))) {
-                if (state == PA_SOURCE_RUNNING)
-                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_ACTIVATED);
-                else if (state == PA_SOURCE_SUSPENDED)
-                    pa_tz_device_set_state(device, DM_DEVICE_DIRECTION_IN, DM_DEVICE_STATE_DEACTIVATED);
-            }
-        }
-    }
-    pa_log_debug("========= sink_source_state_changed_hook_cb END =====");
-
-    return PA_HOOK_OK;
-}
-
 /*
     Build params for load sink or source, and load it.
 */
@@ -2483,7 +2433,7 @@ static void fill_signal_msg_with_device(const char *description, DBusMessageIter
     type = pa_tz_device_get_type(device);
     name = pa_tz_device_get_name(device);
     device_id = (dbus_int32_t) pa_tz_device_get_id(device);
-    state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
+    state = pa_tz_device_get_state(device);
 
     simple_device_dump(PA_LOG_INFO, description, device_id, type, name, direction, state);
 
@@ -2590,7 +2540,7 @@ static bool device_is_match_state(pa_tz_device *device, int state_mask) {
     if (state_mask == DEVICE_STATE_FLAGS || state_mask == 0)
         return true;
 
-    state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
+    state = pa_tz_device_get_state(device);
 
     if ((state_mask & DEVICE_STATE_DEACTIVATED_FLAG) && (state == DM_DEVICE_STATE_DEACTIVATED))
         return true;
@@ -2679,7 +2629,7 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *
     DBusMessage *reply = NULL;
     DBusMessageIter msg_iter, array_iter, device_iter;
     pa_tz_device *device;
-    dm_device_state_t compound_state;
+    dm_device_state_t state;
     uint32_t device_idx;
     dbus_int32_t device_id, direction;
     int mask;
@@ -2704,23 +2654,23 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *
     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "(isiis)", &array_iter));
 
     PA_IDXSET_FOREACH(device, dm->device_list, device_idx) {
-        compound_state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
+        state = pa_tz_device_get_state(device);
         direction = pa_tz_device_get_direction(device);
         type = pa_tz_device_get_type(device);
         name = pa_tz_device_get_name(device);
         if (device_is_match_with_mask(device,  mask)) {
             device_id = (dbus_int32_t)pa_tz_device_get_id(device);
 
-            simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, compound_state);
+            simple_device_dump(PA_LOG_INFO, "[MATCH]", device_id, type, name, direction, state);
             pa_assert_se(dbus_message_iter_open_container(&array_iter, DBUS_TYPE_STRUCT, NULL, &device_iter));
             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &device_id);
             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &type);
             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &direction);
-            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &compound_state);
+            dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_INT32, &state);
             dbus_message_iter_append_basic(&device_iter, DBUS_TYPE_STRING, &name);
             pa_assert_se(dbus_message_iter_close_container(&array_iter, &device_iter));
         } else {
-            simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, compound_state);
+            simple_device_dump(PA_LOG_INFO, "[UNMATCH]", device_id, type, name, direction, state);
         }
     }
 
@@ -2758,7 +2708,7 @@ static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, v
     if ((device = _device_list_get_device_with_id(manager, device_id))) {
         pa_assert_se((reply = dbus_message_new_method_return(msg)));
 
-        state = pa_tz_device_get_state(device, DM_DEVICE_DIRECTION_BOTH);
+        state = pa_tz_device_get_state(device);
         if (state == DM_DEVICE_STATE_ACTIVATED) {
             stream_id_set = pa_tz_device_get_stream_list(device);
             PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) {
@@ -3193,10 +3143,8 @@ pa_device_manager* pa_device_manager_get(pa_core *c) {
     dbus_init(dm);
 
     dm->sink_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_put_hook_callback, dm);
-    dm->sink_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm);
     dm->sink_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_callback, dm);
     dm->source_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) source_put_hook_callback, dm);
-    dm->source_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm);
     dm->source_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_unlink_hook_callback, dm);
     dm->comm = pa_communicator_get(dm->core);
     dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED),
index 6ce8615..de4358f 100644 (file)
@@ -210,19 +210,6 @@ static void __load_dump_config(struct userdata *u)
     }
 }
 
-/* The state of a device using internal audio codec is handled here.
- * Regarding the state of an external device, it is handled in device-manager.c */
-static void set_device_state_if_using_internal_codec(pa_tz_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
-    dm_device_direction_t direction;
-
-    pa_assert(device);
-
-    direction = pa_tz_device_get_direction(device);
-    if (IS_AVAILABLE_DIRECTION(stream_type, direction))
-        if (pa_tz_device_is_use_internal_codec(device))
-            pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
-}
-
 /* threre is only one sco connected device */
 static pa_tz_device* _get_sco_connected_device(pa_device_manager *dm) {
     pa_idxset *device_list;
@@ -674,7 +661,6 @@ static void _update_bt_route_option(pa_hal_interface *hal_intf, const char *role
  *     2. Update the state of devices.
  *     3. Call HAL API to apply the routing setting. */
 static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_data_for_route *data, struct userdata *u) {
-    uint32_t i = 0;
     uint32_t idx = 0;
     uint32_t d_idx = 0;
     uint32_t s_idx = 0;
@@ -685,10 +671,8 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
     stream_route_type_t route_type;
     const char *device_type = NULL;
     pa_tz_device *device = NULL;
-    pa_tz_device *_device = NULL;
     pa_tz_device *latest_device = NULL;
     const char *dm_device_type = NULL;
-    dm_device_state_t dm_device_state = DM_DEVICE_STATE_DEACTIVATED;
     dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
     io_direction_t hal_direction;
     void *s = NULL;
@@ -730,19 +714,6 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
         /* update BT SCO: close */
         update_bt_sco_state(u->device_manager, false);
 
-        /* get current connected devices */
-        conn_devices = pa_device_manager_get_device_list(u->device_manager);
-        /* set device state to deactivate */
-        PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-            dm_device_type = pa_tz_device_get_type(device);
-            dm_device_state = pa_tz_device_get_state(device, CONVERT_TO_DEVICE_DIRECTION(data->stream_type));
-            dm_device_direction = pa_tz_device_get_direction(device);
-            if (dm_device_state == DM_DEVICE_STATE_ACTIVATED && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
-                pa_log_info("[ROUTE][RESET] found a matched device and set state to DE-ACTIVATED: type[%s], direction[0x%x]",
-                            dm_device_type, dm_device_direction);
-                set_device_state_if_using_internal_codec(device, data->stream_type, DM_DEVICE_STATE_DEACTIVATED);
-            }
-        }
         route_info.role = "reset";
         route_info.num_of_devices = 1;
         route_info.device_infos = pa_xmalloc0(sizeof(hal_device_info)*route_info.num_of_devices);
@@ -794,8 +765,6 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                             route_info.device_infos[route_info.num_of_devices-1].id = dm_device_id;
                             pa_log_info("  ** found a matched device and set state to ACTIVATED: type[%-16s], direction[0x%x], id[%u]",
                                         route_info.device_infos[route_info.num_of_devices-1].type, hal_direction, dm_device_id);
-                            /* set device state to activated */
-                            set_device_state_if_using_internal_codec(device, data->stream_type, DM_DEVICE_STATE_ACTIVATED);
                         } else
                             pa_log_debug("  -- it does not use internal audio codec, skip it");
                         break;
@@ -805,16 +774,6 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                     continue;
 
                 if (data->route_type == STREAM_ROUTE_TYPE_AUTO) {
-                    /* check if this device uses internal codec */
-                    use_internal_codec = pa_tz_device_is_use_internal_codec(device);
-                    if (use_internal_codec) {
-                        /* set other device's state to be deactivated */
-                        PA_IDXSET_FOREACH(_device, conn_devices, conn_idx) {
-                            if (device == _device)
-                                continue;
-                            set_device_state_if_using_internal_codec(_device, data->stream_type, DM_DEVICE_STATE_DEACTIVATED);
-                        }
-                    }
                     if (data->origins_from_new_data)
                         pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
                     else
@@ -929,15 +888,6 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                     route_info.device_infos[route_info.num_of_devices-1].id = dm_device_id;
                     pa_log_info("  ** found a matched device and set state to ACTIVATED: type[%-16s], direction[0x%x], id[%u]",
                     route_info.device_infos[route_info.num_of_devices-1].type, hal_direction, dm_device_id);
-                    /* set device state to activated */
-                    set_device_state_if_using_internal_codec(latest_device, data->stream_type, DM_DEVICE_STATE_ACTIVATED);
-
-                    /* set other device's state to be deactivated */
-                    PA_IDXSET_FOREACH(device, conn_devices, conn_idx) {
-                        if (latest_device == device)
-                            continue;
-                        set_device_state_if_using_internal_codec(device, data->stream_type, DM_DEVICE_STATE_DEACTIVATED);
-                    }
                 } else
                     pa_log_debug("  -- it does not use internal audio codec, skip it");
 
@@ -956,22 +906,6 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
             }
         }
 
-        if (data->route_type == STREAM_ROUTE_TYPE_AUTO_ALL && route_info.num_of_devices) {
-            /* set other device's state to be deactivated */
-            PA_IDXSET_FOREACH(_device, conn_devices, conn_idx) {
-                bool need_to_deactive = true;
-                dm_device_id = pa_tz_device_get_id(_device);
-                for (i = 0; i < route_info.num_of_devices; i++) {
-                    if (dm_device_id == route_info.device_infos[i].id) {
-                        need_to_deactive = false;
-                        break;
-                    }
-                }
-                if (need_to_deactive)
-                    set_device_state_if_using_internal_codec(_device, data->stream_type, DM_DEVICE_STATE_DEACTIVATED);
-            }
-        }
-
     } else if (data->route_type == STREAM_ROUTE_TYPE_MANUAL && data->idx_manual_devices && data->idx_avail_devices) {
         PA_IDXSET_FOREACH(device_type, data->idx_avail_devices, idx) {
             pa_log_info("[ROUTE][MANUAL] avail_device[%u] for this role[%-16s]: type[%-16s]", idx, data->stream_role, device_type);
@@ -1034,8 +968,6 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                                 route_info.device_infos[route_info.num_of_devices-1].id = *device_id;
                                 pa_log_info("  ** found a matched device and set state to be ACTIVATED: type[%-16s], direction[0x%x], id[%u]",
                                             route_info.device_infos[route_info.num_of_devices-1].type, dm_device_direction, *device_id);
-                                /* set device state to be activated */
-                                set_device_state_if_using_internal_codec(device, data->stream_type, DM_DEVICE_STATE_ACTIVATED);
                             } else
                                 pa_log_debug("  -- it does not use internal audio codec, skip it");
                         }
index ec71b6e..00af023 100644 (file)
@@ -114,6 +114,7 @@ struct _stream_manager {
     pa_idxset *mirroring_streams;
     cur_max_priority_stream cur_highest_priority;
     stream_restrictions restrictions;
+    bool on_call;
 
     pa_hook_slot
         *sink_input_new_slot,
index 6b503dc..179807a 100644 (file)
@@ -70,6 +70,8 @@
 
 #define IS_AVAILABLE_DIRECTION(stream_type, device_direction) \
     ((stream_type == STREAM_SINK_INPUT) ? (device_direction & DM_DEVICE_DIRECTION_OUT) : (device_direction & DM_DEVICE_DIRECTION_IN))
+#define GET_DIRECTION(stream) \
+    ((pa_sink_input_isinstance(stream)) ? DM_DEVICE_DIRECTION_OUT : DM_DEVICE_DIRECTION_IN)
 
 static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata);
 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
@@ -647,6 +649,229 @@ static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void
     dbus_message_unref(reply);
 }
 
+
+static stream_parent* get_stream_parent(pa_object *stream, pa_stream_manager *m) {
+    pa_proplist *prop;
+    const char *parent_id;
+    uint32_t parent_id_u;
+
+    pa_assert(stream);
+    pa_assert(m);
+
+    if (pa_sink_input_isinstance(stream))
+        prop = PA_SINK_INPUT(stream)->proplist;
+    else
+        prop = PA_SOURCE_OUTPUT(stream)->proplist;
+
+    if ((parent_id = pa_proplist_gets(prop, PA_PROP_MEDIA_PARENT_ID)) == NULL) {
+        pa_log_warn("No parent for this stream");
+        return NULL;
+    }
+
+    if (pa_atou(parent_id, &parent_id_u) < 0) {
+        pa_log_warn("Invalid parent id '%s'", parent_id);
+        return NULL;
+    }
+
+    return pa_hashmap_get(m->stream_parents, (const void*)parent_id_u);
+}
+
+static pa_idxset* get_route_devices(pa_object *stream, pa_stream_manager *m) {
+    stream_parent *sp;
+
+    pa_assert(stream);
+    pa_assert(m);
+
+    if ((sp = get_stream_parent(stream, m)) == NULL) {
+        pa_log_error("No stream parent for this stream");
+        return NULL;
+    }
+
+    if (pa_sink_input_isinstance(stream))
+        return sp->idx_route_out_devices;
+    else
+        return sp->idx_route_in_devices;
+}
+
+static pa_idxset* get_avail_device_types(const char *stream_role, dm_device_direction_t direction, pa_stream_manager *m) {
+    stream_info *si;
+
+    pa_assert(stream_role);
+    pa_assert(m);
+
+    if (!(si = pa_hashmap_get(m->stream_infos, stream_role))) {
+        pa_log_warn("not supported role[%s]", stream_role);
+        return NULL;
+    }
+
+    if (direction == DM_DEVICE_DIRECTION_IN)
+        return si->idx_avail_in_devices;
+    else
+        return si->idx_avail_out_devices;
+}
+
+static void activate_device_only(pa_tz_device *device, pa_stream_manager *m) {
+    pa_idxset *device_list;
+    pa_tz_device *device_iter;
+    uint32_t device_idx, id, others_id;
+    dm_device_direction_t direction, others_direction;
+    dm_device_state_t others_state;
+    char *device_type;
+
+    pa_assert(device);
+    pa_assert(m);
+
+    direction = pa_tz_device_get_direction(device);
+    id = pa_tz_device_get_id(device);
+    device_type = pa_tz_device_get_type(device);
+
+    pa_log_info("activate device(%s/%u)", device_type, id);
+
+    pa_tz_device_set_state(device, DM_DEVICE_STATE_ACTIVATED);
+
+    /* deactivate others */
+    device_list = pa_device_manager_get_device_list(m->dm);
+    PA_IDXSET_FOREACH(device_iter, device_list, device_idx) {
+        if (device_iter != device) {
+            others_state = pa_tz_device_get_state(device_iter);
+            if (others_state == DM_DEVICE_STATE_DEACTIVATED)
+                continue;
+            others_direction = pa_tz_device_get_direction(device_iter);
+            others_id = pa_tz_device_get_id(device_iter);
+            if (direction & others_direction) {
+                pa_log_debug("device(%u) is deactivated by device(%u)", others_id, id);
+                pa_tz_device_set_state(device_iter, DM_DEVICE_STATE_DEACTIVATED);
+            }
+        }
+    }
+
+    return ;
+}
+
+static pa_tz_device* get_media_last_device(dm_device_direction_t direction, pa_stream_manager *m) {
+    char *device_type;
+    pa_tz_device *next_device, *latest_device = NULL;
+    pa_usec_t creation_time = 0;
+    pa_usec_t latest_creation_time = 0;
+    dm_device_direction_t direction2;
+    pa_idxset *avail_device_types;
+    uint32_t idx, id;
+
+    /* Only can get playback or capture device one by one */
+    if (direction == DM_DEVICE_DIRECTION_BOTH)
+        return NULL;
+
+    avail_device_types = get_avail_device_types(STREAM_ROLE_MEDIA, direction, m);
+
+    PA_IDXSET_FOREACH(device_type, avail_device_types, idx) {
+        if ((next_device = pa_device_manager_get_device(m->dm, device_type))) {
+            creation_time = pa_tz_device_get_creation_time(next_device);
+            direction2 = pa_tz_device_get_direction(next_device);
+            if ((direction & direction2) == 0)
+                continue;
+            if (!latest_device || (latest_creation_time <= creation_time)) {
+                latest_device = next_device;
+                latest_creation_time = creation_time;
+            }
+        }
+    }
+
+    if (latest_device) {
+        id = pa_tz_device_get_id(latest_device);
+        device_type = pa_tz_device_get_type(latest_device);
+        pa_log_info("last %s-device to activate : (%s/%u)", direction == DM_DEVICE_DIRECTION_IN ? "in" : "out", device_type, id);
+    } else {
+        pa_log_info("no %s-device", direction == DM_DEVICE_DIRECTION_IN ? "in" : "out");
+    }
+
+    return latest_device;
+}
+
+/* select device which of type is in avail_device_types, and highest priority in
+ * route_device */
+static pa_tz_device* select_device_from_avail_device_types(pa_idxset *avail_device_types,
+        pa_idxset *route_devices, pa_stream_manager *m) {
+    char *device_type;
+    uint32_t route_device_idx, device_type_idx;
+    uint32_t *route_device_id;
+    pa_tz_device *device, *candidate = NULL;
+
+    if (avail_device_types == NULL)
+        return NULL;
+    if (route_devices == NULL)
+        return NULL;
+
+    PA_IDXSET_FOREACH(device_type, avail_device_types, device_type_idx) {
+        PA_IDXSET_FOREACH(route_device_id, route_devices, route_device_idx) {
+            pa_log_warn("device id for call : %u", *route_device_id);
+            device = pa_device_manager_get_device_by_id(m->dm, *route_device_id);
+            if (device) {
+                pa_log_info("Found higher priority device(%u)", *route_device_id);
+                candidate = device;
+            }
+        }
+    }
+
+    return candidate;
+}
+
+static int change_active_route_for_call(pa_object *stream, bool stream_start, pa_stream_manager *m) {
+    pa_tz_device *device;
+    pa_idxset *avail_device_types, *route_devices;
+
+    pa_assert(stream);
+    pa_assert(m);
+    pa_assert(m->stream_parents);
+
+    pa_log_info("Call virtual stream %s, change active device", stream_start ? "start" : "change");
+
+    avail_device_types = get_avail_device_types(STREAM_ROLE_CALL_VOICE, GET_DIRECTION(stream), m);
+    if (!avail_device_types) {
+        pa_log_error("No avail device typs for call");
+        return -1;
+    }
+    route_devices = get_route_devices(stream, m);
+    if (!route_devices) {
+        pa_log_error("No route devices for this stream");
+        return -1;
+    }
+
+    device = select_device_from_avail_device_types(avail_device_types, route_devices, m);
+    if (!device) {
+        pa_log_error("Failed to select device to activate on call state");
+        return -1;
+    }
+    activate_device_only(device, m);
+
+    return 0;
+}
+
+static void set_media_active_device(pa_stream_manager *m) {
+    pa_tz_device *device;
+
+    pa_assert(m);
+
+    pa_log_info("set media active device");
+
+    device = get_media_last_device(DM_DEVICE_DIRECTION_IN, m);
+    if (device)
+        activate_device_only(device, m);
+    else
+        pa_log_info("There is no in-device");
+
+    device = get_media_last_device(DM_DEVICE_DIRECTION_OUT, m);
+    if (device)
+        activate_device_only(device, m);
+    else
+        pa_log_info("There is no out-device");
+}
+
+static void set_initial_active_device(pa_stream_manager *m) {
+    pa_assert(m);
+
+    set_media_active_device(m);
+}
+
 static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     uint32_t id = 0;
     int i = 0;
@@ -711,9 +936,15 @@ static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *m
                 }
             } else if (m->cur_highest_priority.source_output) {
                 if (pa_idxset_get_by_data(sp->idx_source_outputs, m->cur_highest_priority.source_output, NULL)) {
+                    const char *stream_role;
                     pa_log_debug(" -- cur_highest_priority.source_output->index[%u] belongs to this parent id[%u], do notify for the route change",
                             (m->cur_highest_priority.source_output)->index, id);
                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SOURCE_OUTPUT, false, m->cur_highest_priority.source_output);
+                    stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.source_output, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE);
+                    if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE) && m->on_call) {
+                        pa_log_info("set active device for new call route device");
+                        change_active_route_for_call(PA_OBJECT(m->cur_highest_priority.source_output), false, m);
+                    }
                 }
             }
         } else {
@@ -748,9 +979,15 @@ static void handle_set_stream_route_devices(DBusConnection *conn, DBusMessage *m
                 }
             } else if (m->cur_highest_priority.sink_input) {
                 if (pa_idxset_get_by_data(sp->idx_sink_inputs, m->cur_highest_priority.sink_input, NULL)) {
+                    const char *stream_role;
                     pa_log_debug(" -- cur_highest_priority.sink_input->index[%u] belongs to this parent id[%u], do notify for the route change",
                             (m->cur_highest_priority.sink_input)->index, id);
                     do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, STREAM_SINK_INPUT, false, m->cur_highest_priority.sink_input);
+                    stream_role = pa_proplist_gets(GET_STREAM_PROPLIST(m->cur_highest_priority.sink_input, STREAM_SINK_INPUT), PA_PROP_MEDIA_ROLE);
+                    if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE) && m->on_call) {
+                        pa_log_info("set active device for new call route device");
+                        change_active_route_for_call(PA_OBJECT(m->cur_highest_priority.sink_input), false, m);
+                    }
                 }
             }
         } else {
@@ -2898,22 +3135,35 @@ static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data
 }
 
 static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+    const char *stream_role;
+
     pa_core_assert_ref(core);
     pa_sink_input_assert_ref(i);
 
     pa_log_debug("start sink_input_put_cb, i(%p, index:%u)", i, i->index);
 
     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_ADD_PARENT_ID, false);
+    stream_role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE);
+    if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE)) {
+        change_active_route_for_call(PA_OBJECT(i), true, m);
+        m->on_call = true;
+    }
 
     return PA_HOOK_OK;
 }
 
 static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
+    const char *stream_role;
     pa_core_assert_ref(core);
     pa_sink_input_assert_ref(i);
 
     pa_log_debug("start sink_input_unlink_cb, i(%p, index:%u)", i, i->index);
 
+    stream_role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE);
+    if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE)) {
+        m->on_call = false;
+        set_media_active_device(m);
+    }
     remove_sink_input_from_muted_streams(m, i);
     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_REMOVE_PARENT_ID, false);
     process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
@@ -2993,6 +3243,7 @@ static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new
 }
 
 static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
+    const char *stream_role;
     pa_core_assert_ref(core);
     pa_source_output_assert_ref(o);
 
@@ -3000,16 +3251,27 @@ static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o,
 
     update_mirroring_streams(m, o, true);
     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_PARENT_ID, false);
+    stream_role = pa_proplist_gets(o->proplist, PA_PROP_MEDIA_ROLE);
+    if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE)) {
+        change_active_route_for_call(PA_OBJECT(o), true, m);
+        m->on_call = true;
+    }
 
     return PA_HOOK_OK;
 }
 
 static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output *o, pa_stream_manager *m) {
+    const char *stream_role;
     pa_core_assert_ref(core);
     pa_source_output_assert_ref(o);
 
     pa_log_info("start source_output_unlink_cb, o(%p, index:%u)", o, o->index);
 
+    stream_role = pa_proplist_gets(o->proplist, PA_PROP_MEDIA_ROLE);
+    if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE)) {
+        m->on_call = false;
+        set_media_active_device(m);
+    }
     update_mirroring_streams(m, o, false);
     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_ENDED, false);
     process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_REMOVE_PARENT_ID, false);
@@ -3213,17 +3475,6 @@ static void process_stream_as_device_change_for_auto_route(pa_stream_manager *m,
     }
 }
 
-/* The state of a device using internal audio codec is handled here.
- * Regarding the state of an external device, those is handled in device-manager.c */
-static void set_device_state_if_using_internal_codec(pa_tz_device *device, stream_type_t stream_type, dm_device_state_t device_state) {
-    bool use_internal_codec = false;
-
-    pa_assert(device);
-
-    if ((use_internal_codec = pa_tz_device_is_use_internal_codec(device)))
-        pa_tz_device_set_state(device, CONVERT_TO_DEVICE_DIRECTION(stream_type), device_state);
-}
-
 static void update_sink_or_source_as_device_change(stream_route_type_t stream_route_type, pa_idxset *streams,
                                                    stream_type_t stream_type, pa_tz_device *device, bool is_connected, pa_stream_manager *m) {
     #define MAX_CACHED_LEN 128
@@ -3238,7 +3489,6 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
     const char *cur_device_type = NULL;
     const char *new_device_type = NULL;
     pa_tz_device *next_device = NULL;
-    pa_tz_device *_device = NULL;
     stream_route_type_t route_type;
     pa_sink *sink = NULL;
     pa_sink *next_sink = NULL;
@@ -3304,10 +3554,6 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
                         pa_log_debug("no need to move for stream(%p, idx:%u)", s, (stream_type == STREAM_SINK_INPUT ?
                                      ((pa_sink_input*)s)->index : ((pa_source_output*)s)->index));
                     if (available) {
-                        /* update activated device */
-                        pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, device_type);
-                        if ((_device = pa_device_manager_get_device(m->dm, device_type)))
-                            set_device_state_if_using_internal_codec(_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
                         cached_prev_dev_list[cnt++].device_type = cur_device_type;
                         /* trigger to update routing path */
                         process_stream_as_device_change_for_auto_route(m, s, stream_type, is_connected, use_internal_codec);
@@ -3321,7 +3567,6 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
                                 new_device_type = pa_tz_device_get_type(next_device);
                                 /* update activated device */
                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
-                                set_device_state_if_using_internal_codec(next_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
                                 cached_prev_dev_list[cnt++].device_type = device_type;
                                 /* trigger to update routing path if the next device uses internal audio codec */
                                 if (next_sink->use_internal_codec)
@@ -3346,7 +3591,6 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
                                 new_device_type = pa_tz_device_get_type(next_device);
                                 /* update activated device */
                                 pa_proplist_sets(GET_STREAM_PROPLIST(s, stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, new_device_type);
-                                set_device_state_if_using_internal_codec(next_device, stream_type, DM_DEVICE_STATE_ACTIVATED);
                                 cached_prev_dev_list[cnt++].device_type = device_type;
                                 /* trigger to update routing path if the next device uses internal audio codec */
                                 if (next_source->use_internal_codec)
@@ -3385,13 +3629,6 @@ static void update_sink_or_source_as_device_change(stream_route_type_t stream_ro
                     }
                 }
             }
-            /* if there's no activated device marked in previous device list, set it to be deactivated */
-            for (cnt = 0; cached_prev_dev_list[cnt].device_type; cnt++) {
-                if (cached_prev_dev_list[cnt].count == 0) {
-                    if ((_device = pa_device_manager_get_device(m->dm, cached_prev_dev_list[cnt].device_type)))
-                        set_device_state_if_using_internal_codec(_device, stream_type, DM_DEVICE_STATE_DEACTIVATED);
-                }
-            }
         }
 
     } else if (stream_route_type == STREAM_ROUTE_TYPE_MANUAL_EXT) {
@@ -3604,6 +3841,13 @@ static pa_hook_result_t device_connection_changed_hook_cb(pa_core *c, pa_tz_devi
         }
     }
 
+    if (m->on_call) {
+        pa_log_info("This is on_call state, do nothing about active device");
+    } else {
+        pa_log_info("This is not on_call state, figure out to change active device");
+        set_media_active_device(m);
+    }
+
     return PA_HOOK_OK;
 }
 
@@ -3809,6 +4053,8 @@ pa_stream_manager* pa_stream_manager_init(pa_core *c) {
     m->comm.comm_hook_event_fully_handled_slot = pa_hook_connect(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_EVENT_FULLY_HANDLED),
             PA_HOOK_EARLY + 10, (pa_hook_cb_t)event_fully_handled_hook_cb, m);
 
+    set_initial_active_device(m);
+
     return m;
 
 fail:
index 9b3c36d..29503ec 100644 (file)
@@ -19,8 +19,6 @@
 #define BT_CVSD_CODEC_ID 1 // narrow-band
 #define BT_MSBC_CODEC_ID 2 // wide-band
 
-#define COMPOUND_STATE(d) (((pa_tz_device*)d)->playback_state | ((pa_tz_device*)d)->capture_state)
-
 struct pa_intset {
     int values[MAX_INTSET_NUM];
     uint32_t write_index;
@@ -140,7 +138,7 @@ static char* _device_get_info_str(pa_tz_device *device) {
     pa_strbuf_printf(buf, "  Name         : %s\n", device->name);
     pa_strbuf_printf(buf, "  System ID    : %s\n", device->system_id);
     pa_strbuf_printf(buf, "  Direction    : %s\n", device_direction_to_string(device->direction));
-    pa_strbuf_printf(buf, "  Is activated : %s\n", pa_yes_no(COMPOUND_STATE(device) == DM_DEVICE_STATE_ACTIVATED));
+    pa_strbuf_printf(buf, "  Is activated : %s\n", pa_yes_no(device->state == DM_DEVICE_STATE_ACTIVATED));
     pa_strbuf_printf(buf, "  Internal     : %s\n", pa_yes_no(device->use_internal_codec));
     if (device_type_is_equal(device->type, DEVICE_TYPE_BT_SCO))
         pa_strbuf_printf(buf, "    SCO opened   : %s\n", pa_yes_no(device->sco_opened));
@@ -328,36 +326,22 @@ static pa_source* device_get_source(pa_tz_device *device, const char *role) {
     return source;
 }
 
-static void device_set_state(pa_tz_device *device, dm_device_direction_t direction, dm_device_state_t state) {
-    dm_device_state_t prev_state, new_state;
+static void device_set_state(pa_tz_device *device, dm_device_state_t new_state) {
     pa_assert(device);
 
-    prev_state = COMPOUND_STATE(device);
-    pa_log_debug("previous playback_state : %d, capture_state : %d => state %d", device->playback_state, device->capture_state, prev_state);
-    if (direction & DM_DEVICE_DIRECTION_IN)
-        device->capture_state = state;
-    if (direction & DM_DEVICE_DIRECTION_OUT)
-        device->playback_state = state;
-    new_state = COMPOUND_STATE(device);
-    pa_log_debug("new playback_state : %d, capture_state : %d => state %d", device->playback_state, device->capture_state, new_state);
-
-    if (prev_state != new_state) {
+    if (device->state != new_state) {
+        pa_log_debug("change state %d -> %d", device->state, new_state);
+        device->state = new_state;
         notify_device_state_changed(device, new_state);
         pa_tz_device_dump_info(device, PA_LOG_DEBUG);
+    } else {
+        pa_log_debug("same state, not change it");
     }
 }
 
-static dm_device_state_t device_get_state(pa_tz_device *device, dm_device_direction_t direction) {
+static dm_device_state_t device_get_state(pa_tz_device *device) {
     pa_assert(device);
-
-    if (direction == DM_DEVICE_DIRECTION_BOTH)
-        return COMPOUND_STATE(device);
-    else if (direction == DM_DEVICE_DIRECTION_OUT)
-        return device->playback_state;
-    else if (direction == DM_DEVICE_DIRECTION_IN)
-        return device->capture_state;
-    else
-        return DM_DEVICE_STATE_DEACTIVATED;
+    return device->state;
 }
 
 static int device_remove_sink_with_role(pa_tz_device *device, const char *role) {
@@ -438,8 +422,7 @@ pa_tz_device* pa_tz_device_new(pa_tz_device_new_data *data) {
     device->playback_devices = data->playback_pcms;
     device->capture_devices = data->capture_pcms;
     device->direction = data->direction;
-    device->playback_state = DM_DEVICE_STATE_DEACTIVATED;
-    device->capture_state = DM_DEVICE_STATE_DEACTIVATED;
+    device->state = DM_DEVICE_STATE_DEACTIVATED;
     device->creation_time = pa_rtclock_now();
     device->use_internal_codec = data->use_internal_codec;
     device->sco_opened = false;
@@ -583,18 +566,18 @@ pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role) {
 
 /* TODO : Change param dm_device_state_t to bool or pa_tz_device_state_t,
  * Because this state represent pa_tz_device's own state */
-void pa_tz_device_set_state(pa_tz_device *device, dm_device_direction_t direction, dm_device_state_t state) {
+void pa_tz_device_set_state(pa_tz_device *device, dm_device_state_t state) {
     pa_assert(device);
 
-    pa_log_info("device set state, device(%u) type(%s) direction(%s) -> %d",
-            device->id, device->type, device_direction_to_string(direction), state);
-    device_set_state(device, direction, state);
+    pa_log_info("device set state, device(%u) type(%s) -> %d",
+            device->id, device->type, state);
+    device_set_state(device, state);
 }
 
-dm_device_state_t pa_tz_device_get_state(pa_tz_device *device, dm_device_direction_t direction) {
+dm_device_state_t pa_tz_device_get_state(pa_tz_device *device) {
     pa_assert(device);
 
-    return device_get_state(device, direction);
+    return device_get_state(device);
 }
 
 uint32_t pa_tz_device_get_id(pa_tz_device *device) {
index 6a1a027..2642e25 100644 (file)
@@ -36,8 +36,7 @@ struct pa_tz_device {
 
     /* Set by stream-manager
      * If this is changed, will be notifacted */
-    dm_device_state_t playback_state;
-    dm_device_state_t capture_state;
+    dm_device_state_t state;
 
     /* Can get proper sink/source in hashmaps with key(=device_role) */
     pa_hashmap *playback_devices;
@@ -117,8 +116,8 @@ int pa_tz_device_remove_source_with_role(pa_tz_device *device, const char *role)
 /* Exported API for other modules */
 pa_sink* pa_tz_device_get_sink(pa_tz_device *device, const char *role);
 pa_source* pa_tz_device_get_source(pa_tz_device *device, const char *role);
-void pa_tz_device_set_state(pa_tz_device *device, dm_device_direction_t direction, dm_device_state_t state);
-dm_device_state_t pa_tz_device_get_state(pa_tz_device *device, dm_device_direction_t direction);
+void pa_tz_device_set_state(pa_tz_device *device, dm_device_state_t state);
+dm_device_state_t pa_tz_device_get_state(pa_tz_device *device);
 uint32_t pa_tz_device_get_id(pa_tz_device *device);
 char* pa_tz_device_get_type(pa_tz_device *device);
 char* pa_tz_device_get_name(pa_tz_device *device);