policy: Modifications regarding device role/stream role for coping with a specific... 87/55987/4 accepted/tizen/mobile/20160107.101605 accepted/tizen/tv/20160107.101623 accepted/tizen/wearable/20160107.101648 submit/tizen/20160107.045209
authorSangchul Lee <sc11.lee@samsung.com>
Thu, 31 Dec 2015 00:04:11 +0000 (09:04 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 7 Jan 2016 04:44:01 +0000 (13:44 +0900)
Sets null sink or null source in case of a virtual stream made by sound-manager native API in stream-manager.
Returns a sink or source of normal role when a requested device role is not available in device-manager(pa_device_manager_get_sink/_get_source).
Moves streams if needed at the beginning and end of voice call scenario.
Update active device info. to incoming stream(auto) even if the occupying stream does not need to change.

[Version] 5.0.27
[Profile] Common
[Issue Type] Feature Enhancement and Bug Fix

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

index ace6df4..7828e1a 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          5.0.26
+Version:          5.0.27
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 9ed5ed9..e6662bf 100644 (file)
@@ -9,6 +9,7 @@
 #include <json.h>
 #include <pulse/proplist.h>
 #include <pulse/util.h>
+#include <pulse/rtclock.h>
 #include <pulsecore/core-subscribe.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/log.h>
@@ -536,6 +537,10 @@ static pa_bool_t device_role_is_valid(const char *device_role) {
         return FALSE;
     else if (pa_streq(device_role, DEVICE_ROLE_NORMAL))
         return TRUE;
+    else if (pa_streq(device_role, DEVICE_ROLE_CALL_VOICE))
+        return TRUE;
+    else if (pa_streq(device_role, DEVICE_ROLE_CALL_VIDEO))
+        return TRUE;
     else if (pa_streq(device_role, DEVICE_ROLE_VOIP))
         return TRUE;
     else if (pa_streq(device_role, DEVICE_ROLE_LOW_LATENCY))
@@ -4020,6 +4025,7 @@ dm_device* pa_device_manager_get_device_by_id(pa_device_manager *dm, uint32_t id
 
 pa_sink* pa_device_manager_get_sink(dm_device *device_item, const char *role) {
     dm_device_profile *profile_item;
+    pa_sink *sink;
 
     pa_assert(device_item);
     pa_assert(profile_item = _device_item_get_active_profile(device_item));
@@ -4028,12 +4034,19 @@ pa_sink* pa_device_manager_get_sink(dm_device *device_item, const char *role) {
         pa_log_warn("No playback device in %s", device_item->name);
         return NULL;
     }
+    if ((sink = pa_hashmap_get(profile_item->playback_devices, role)))
+        pa_log_debug("Got sink[%s] for [%s] role", sink->name, role);
+    else {
+        sink = pa_hashmap_get(profile_item->playback_devices, DEVICE_ROLE_NORMAL);
+        pa_log_debug("Could not get sink for [%s] role. so get sink[%s] for normal role", role, sink->name);
+    }
 
-    return pa_hashmap_get(profile_item->playback_devices, role);
+    return sink;
 }
 
 pa_source* pa_device_manager_get_source(dm_device *device_item, const char *role) {
     dm_device_profile *profile_item;
+    pa_source *source;
 
     pa_assert(device_item);
     pa_assert(profile_item = _device_item_get_active_profile(device_item));
@@ -4043,7 +4056,14 @@ pa_source* pa_device_manager_get_source(dm_device *device_item, const char *role
         return NULL;
     }
 
-    return pa_hashmap_get(profile_item->capture_devices, role);
+    if ((source = pa_hashmap_get(profile_item->capture_devices, role)))
+        pa_log_debug("Got source[%s] for [%s] role", source->name, role);
+    else {
+        source = pa_hashmap_get(profile_item->capture_devices, DEVICE_ROLE_NORMAL);
+        pa_log_debug("Could not get source for [%s] role. so get source[%s] for normal role", role, source->name);
+    }
+
+    return source;
 }
 
 dm_device* pa_device_manager_get_device_with_sink(pa_sink *sink) {
index 0e49f68..2d37ba9 100644 (file)
@@ -15,6 +15,8 @@
 #define DEVICE_PROFILE_BT_A2DP              "a2dp"
 
 #define DEVICE_ROLE_NORMAL                  "normal"
+#define DEVICE_ROLE_CALL_VOICE              "call-voice"
+#define DEVICE_ROLE_CALL_VIDEO              "call-video"
 #define DEVICE_ROLE_VOIP                    "voip"
 #define DEVICE_ROLE_LOW_LATENCY             "low-latency"
 #define DEVICE_ROLE_HIGH_LATENCY            "high-latency"
index 1de03eb..3fe8af7 100644 (file)
@@ -321,8 +321,8 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
     pa_assert(data);
     pa_assert(u);
 
-    pa_log_info("[SELECT] select_proper_sink_or_source_hook_cb is called. (%p), stream_type(%d), stream_role(%s), route_type(%d)",
-                data, data->stream_type, data->stream_role, data->route_type);
+    pa_log_info("[SELECT] select_proper_sink_or_source_hook_cb is called. (%p), stream_type(%d), stream_role(%s), device_role(%s), route_type(%d)",
+                data, data->stream_type, data->stream_role, data->device_role, data->route_type);
 
     null_sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_NULL, PA_NAMEREG_SINK);
     null_source = (pa_source*)pa_namereg_get(u->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE);
@@ -331,6 +331,16 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
         return PA_HOOK_OK;
     }
 
+    /* check if the current occupying role is related to call.
+     * some targets use several pcm card as per their purpose.
+     * e.g) using a specific pcm card during voice call. */
+    if (data->occupying_role) {
+        if (pa_streq(data->occupying_role, STREAM_ROLE_CALL_VOICE)) {
+            data->device_role = DEVICE_ROLE_CALL_VOICE;
+            pa_log_info("[SELECT] current occupying stream role is [%s], set deivce role to [%s]", data->occupying_role, data->device_role);
+        }
+    }
+
     if ((data->route_type <= STREAM_ROUTE_TYPE_AUTO_ALL) && data->idx_avail_devices) {
         /* get current connected devices */
         conn_devices = pa_device_manager_get_device_list(u->device_manager);
@@ -352,9 +362,9 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                                 *(data->proper_sink) = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
                                 pa_log_debug("  -- found the combine-sink, set it to the sink");
                             } else
-                                *(data->proper_sink) = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                                *(data->proper_sink) = pa_device_manager_get_sink(device, data->device_role);
                         } else
-                            *(data->proper_source) = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+                            *(data->proper_source) = pa_device_manager_get_source(device, data->device_role);
                         break;
                     }
                 }
@@ -384,9 +394,9 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
             /* update active device info. */
             if (latest_device) {
                 if (data->stream_type == STREAM_SINK_INPUT)
-                    *(data->proper_sink) = pa_device_manager_get_sink(latest_device, DEVICE_ROLE_NORMAL);
+                    *(data->proper_sink) = pa_device_manager_get_sink(latest_device, data->device_role);
                 else
-                    *(data->proper_source) = pa_device_manager_get_source(latest_device, DEVICE_ROLE_NORMAL);
+                    *(data->proper_source) = pa_device_manager_get_source(latest_device, data->device_role);
 
                 pa_proplist_sets(GET_STREAM_NEW_PROPLIST(data->stream, data->stream_type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, dm_device_type);
             }
@@ -406,14 +416,14 @@ static pa_hook_result_t select_proper_sink_or_source_hook_cb(pa_core *c, pa_stre
                         pa_log_info("  ** found a matched device: type[%-16s], direction[0x%x]", device_type, dm_device_direction);
                         if (data->stream_type == STREAM_SINK_INPUT) {
                             if ((*(data->proper_sink)) == null_sink)
-                                pa_sink_input_move_to((pa_sink_input*)(data->stream), pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL), FALSE);
+                                pa_sink_input_move_to((pa_sink_input*)(data->stream), pa_device_manager_get_sink(device, data->device_role), FALSE);
                             else
-                                *(data->proper_sink) = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                                *(data->proper_sink) = pa_device_manager_get_sink(device, data->device_role);
                         } else {
                             if ((*(data->proper_source)) == null_source)
-                                pa_source_output_move_to((pa_source_output*)(data->stream), pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL), FALSE);
+                                pa_source_output_move_to((pa_source_output*)(data->stream), pa_device_manager_get_source(device, data->device_role), FALSE);
                             else
-                                *(data->proper_source) = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+                                *(data->proper_source) = pa_device_manager_get_source(device, data->device_role);
                         }
                     }
                 }
@@ -548,11 +558,11 @@ static int set_bt_sco_state(pa_device_manager *dm, pa_bool_t open) {
 
 /* Change the route setting according to the data from argument.
  * This function is called only when it needs to change routing path via HAL.
- * - role is "reset"
+ * - stream is null
  *     1. It will be received when it is needed to terminate playback
  *       or capture routing path.
  *     2. Update the state of the device to be deactivated.
- *     3. Call HAL API to reset routing.
+ *     3. Call HAL API to "reset" routing.
  * - ROUTE_TYPE_AUTO
  *     1. Find the proper sink/source comparing between avail_devices
  *       and current connected devices.
@@ -590,8 +600,11 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
     dm_device_direction_t dm_device_direction = DM_DEVICE_DIRECTION_NONE;
     io_direction_t hal_direction;
     void *s = NULL;
+    pa_idxset *streams = NULL;
     pa_sink *sink = NULL;
+    pa_sink *dst_sink = NULL;
     pa_source *source = NULL;
+    pa_source *dst_source = NULL;
     pa_idxset *conn_devices = NULL;
     pa_sink *combine_sink_arg1 = NULL;
     pa_sink *combine_sink_arg2 = NULL;
@@ -611,7 +624,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
 
     route_info.role = data->stream_role;
 
-    if (pa_streq(data->stream_role, "reset")) {
+    if (data->stream == NULL) {
         /* update BT SCO: close */
         set_bt_sco_state(u->device_manager, FALSE);
 
@@ -627,6 +640,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                 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);
         route_info.device_infos[0].direction = (data->stream_type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN;
@@ -667,7 +681,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                                  dm_device_type, dm_device_subtype, dm_device_direction, dm_device_id);
                     if (pa_streq(device_type, dm_device_type) && IS_AVAILABLE_DIRECTION(data->stream_type, dm_device_direction)) {
                         pa_log_debug("  ** found a matched device: type[%-16s], direction[0x%x]", dm_device_type, dm_device_direction);
-                        use_internal_codec = pa_device_manager_is_device_use_internal_codec(device, CONVERT_TO_DEVICE_DIRECTION(data->stream_type), DEVICE_ROLE_NORMAL);
+                        use_internal_codec = pa_device_manager_is_device_use_internal_codec(device, CONVERT_TO_DEVICE_DIRECTION(data->stream_type), data->device_role);
                         if (use_internal_codec) {
                             hal_direction = (data->stream_type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN;
                             route_info.num_of_devices++;
@@ -705,7 +719,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
 
                 /* move sink-inputs/source-outputs if needed */
                 if (data->stream_type == STREAM_SINK_INPUT)
-                    sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                    sink = pa_device_manager_get_sink(device, data->device_role);
 
                     /* unload combine sink */
                     if (data->stream_type == STREAM_SINK_INPUT && u->module_combine_sink) {
@@ -731,10 +745,10 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                         sink = (pa_sink*)pa_namereg_get(u->core, SINK_NAME_COMBINED, PA_NAMEREG_SINK);
                         pa_log_info("[ROUTE][AUTO_ALL] found the combine_sink already existed");
                     } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg1) {
-                        sink = combine_sink_arg1 = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                        sink = combine_sink_arg1 = pa_device_manager_get_sink(device, data->device_role);
                         pa_log_debug("[ROUTE][AUTO_ALL] combine_sink_arg1[%s], combine_sink_arg2[%p]", sink->name, combine_sink_arg2);
                     } else if (data->stream_type == STREAM_SINK_INPUT && !combine_sink_arg2) {
-                        sink = combine_sink_arg2 = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
+                        sink = combine_sink_arg2 = pa_device_manager_get_sink(device, data->device_role);
                         if (sink && !pa_streq(sink->name, combine_sink_arg1->name)) {
                             pa_log_debug("[ROUTE][AUTO_ALL] combine_sink_arg2[%s]", sink->name);
                             /* load combine sink */
@@ -756,7 +770,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                                 pa_log_error("[ROUTE][AUTO_ALL] could not get combine_sink");
                         }
                     } else if (data->stream_type == STREAM_SOURCE_OUTPUT)
-                        source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
+                        source = pa_device_manager_get_source(device, data->device_role);
 
                     if (data->origins_from_new_data) {
                         if (data->stream_type == STREAM_SINK_INPUT)
@@ -808,7 +822,7 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
             if (latest_device) {
                 dm_device_type = pa_device_manager_get_device_type(latest_device);
                 dm_device_id = pa_device_manager_get_device_id(latest_device);
-                use_internal_codec = pa_device_manager_is_device_use_internal_codec(latest_device, CONVERT_TO_DEVICE_DIRECTION(data->stream_type), DEVICE_ROLE_NORMAL);
+                use_internal_codec = pa_device_manager_is_device_use_internal_codec(latest_device, CONVERT_TO_DEVICE_DIRECTION(data->stream_type), data->device_role);
                 if (use_internal_codec) {
                     hal_direction = (data->stream_type == STREAM_SINK_INPUT) ? DIRECTION_OUT : DIRECTION_IN;
                     route_info.num_of_devices++;
@@ -909,21 +923,61 @@ static pa_hook_result_t route_change_hook_cb(pa_core *c, pa_stream_manager_hook_
                 }
             }
         }
-
-        /* move sink-inputs/source-outputs if needed */
-        if (device && !data->origins_from_new_data) {
-            if (data->stream_type == STREAM_SINK_INPUT)
-                sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL);
-            else if (data->stream_type == STREAM_SOURCE_OUTPUT)
-                source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL);
-            if (data->idx_streams) {
-                PA_IDXSET_FOREACH(s, data->idx_streams, idx) {
-                    if (sink && (sink != ((pa_sink_input*)s)->sink)) {
-                        pa_sink_input_move_to(s, sink, FALSE);
-                        pa_log_debug("[ROUTE][MANUAL] *** sink-input(%p,%u) moves to sink(%p,%s)", s, ((pa_sink_input*)s)->index, sink, sink->name);
-                    } else if (source && (source != ((pa_source_output*)s)->source)) {
-                        pa_source_output_move_to(s, source, FALSE);
-                        pa_log_debug("[ROUTE][MANUAL] *** source-output(%p,%u) moves to source(%p,%s)", s, ((pa_source_output*)s)->index, source, source->name);
+    }
+    /* move streams to a proper sink/source if needed.
+     * some targets use several pcm card as per their purpose.
+     * e.g) using a specific pcm card during voice call.
+     * here is the code for roll-back. */
+    if (device && data->stream && !data->origins_from_new_data &&
+        data->route_type != STREAM_ROUTE_TYPE_MANUAL) {
+        if (data->stream_type == STREAM_SINK_INPUT)
+            sink = pa_device_manager_get_sink(device, data->device_role);
+        else if (data->stream_type == STREAM_SOURCE_OUTPUT)
+            source = pa_device_manager_get_source(device, data->device_role);
+        if (data->idx_streams) {
+            PA_IDXSET_FOREACH(s, data->idx_streams, idx) {
+                if (sink && sink != ((pa_sink_input*)s)->sink) {
+                    pa_sink_input_move_to(s, sink, FALSE);
+                    pa_log_debug("[ROUTE][ROLLBACK] *** sink-input(%p,%u) moves to sink(%p,%s)",
+                                 s, ((pa_sink_input*)s)->index, sink, sink->name);
+                } else if (source && source != ((pa_source_output*)s)->source) {
+                    pa_source_output_move_to(s, source, FALSE);
+                    pa_log_debug("[ROUTE][ROLLBACK] *** source-output(%p,%u) moves to source(%p,%s)",
+                                 s, ((pa_source_output*)s)->index, source, source->name);
+                }
+            }
+        }
+    }
+    /* move other streams that are belong to device of NORMAL role
+     * to a proper sink/source if needed */
+    if (device && data->stream && data->origins_from_new_data &&
+        data->route_type == STREAM_ROUTE_TYPE_MANUAL) {
+        if (pa_streq(data->stream_role, STREAM_ROLE_CALL_VOICE)) {
+            if (data->stream_type == STREAM_SINK_INPUT) {
+                if (!(sink = pa_device_manager_get_sink(device, DEVICE_ROLE_NORMAL)) ||
+                    !(dst_sink = pa_device_manager_get_sink(device, DEVICE_ROLE_CALL_VOICE)) ||
+                    sink == dst_sink)
+                    pa_log_debug("[ROUTE][CALL-VOICE] no need to move streams, sink(%p), dst_sink(%p)", sink, dst_sink);
+                else
+                    streams = sink->inputs;
+            } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
+                if (!(source = pa_device_manager_get_source(device, DEVICE_ROLE_NORMAL)) ||
+                    !(dst_source = pa_device_manager_get_source(device, DEVICE_ROLE_CALL_VOICE)) ||
+                    source == dst_source)
+                    pa_log_debug("[ROUTE][CALL-VOICE] no need to move streams, source(%p), dst_source(%p)", source, dst_source);
+                else
+                    streams = source->outputs;
+            }
+            if (streams) {
+                PA_IDXSET_FOREACH(s, streams, idx) {
+                    if (data->stream_type == STREAM_SINK_INPUT) {
+                        pa_sink_input_move_to(s, dst_sink, FALSE);
+                        pa_log_debug("[ROUTE][CALL-VOICE] *** sink-input(%p,%u) moves to sink(%p,%s)",
+                                     s, ((pa_sink_input*)s)->index, dst_sink, dst_sink->name);
+                    } else if (data->stream_type == STREAM_SOURCE_OUTPUT) {
+                        pa_source_output_move_to(s, dst_source, FALSE);
+                        pa_log_debug("[ROUTE][CALL-VOICE] *** source-output(%p,%u) moves to source(%p,%s)",
+                                     s, ((pa_source_output*)s)->index, dst_source, dst_source->name);
                     }
                 }
             }
index b7cd18f..f883c61 100644 (file)
@@ -61,6 +61,8 @@ typedef struct _prior_max_priority_stream {
     pa_source_output *source_output;
     pa_bool_t need_to_update_si;
     pa_bool_t need_to_update_so;
+    const char *role_si;
+    const char *role_so;
 } cur_max_priority_stream;
 
 struct _stream_manager {
index 822dc5c..fd8eb83 100644 (file)
@@ -297,7 +297,8 @@ static pa_dbus_interface_info stream_manager_interface_info = {
 
 #endif
 
-#define STREAM_MANAGER_CLIENT_NAME "SOUND_MANAGER_STREAM_INFO"
+#define STREAM_MANAGER_CLIENT_NAME "SOUND_MANAGER_STREAM_INFO" /* The client via sound-manager */
+#define VIRTUAL_STREAM_NAME "VIRTUAL_STREAM" /* The virtual stream created by sound-manager */
 #define DEFAULT_ROLE "media"
 #define SKIP_ROLE "skip"
 #define ACTIVE_DEV_REMOVED "removed"
@@ -405,9 +406,39 @@ typedef struct _stream_route_option {
     int32_t value;
 } stream_route_option;
 
-#define CONVERT_TO_DEVICE_DIRECTION(stream_type)\
+#define CONVERT_TO_DEVICE_DIRECTION(stream_type) \
     ((stream_type == STREAM_SINK_INPUT) ? DM_DEVICE_DIRECTION_OUT : DM_DEVICE_DIRECTION_IN)
 
+#define CONVERT_TO_DEVICE_ROLE(x_stream_role, x_device_role) { \
+    pa_assert(x_stream_role); \
+    if (pa_streq(x_stream_role, STREAM_ROLE_CALL_VOICE)) \
+        x_device_role = DEVICE_ROLE_CALL_VOICE; \
+    else if (pa_streq(x_stream_role, STREAM_ROLE_CALL_VIDEO)) \
+        x_device_role = DEVICE_ROLE_CALL_VIDEO; \
+    else if (pa_streq(x_stream_role, STREAM_ROLE_VOIP)) \
+        x_device_role = DEVICE_ROLE_VOIP; \
+    else \
+        x_device_role = DEVICE_ROLE_NORMAL; \
+} \
+
+#define SET_NEW_DATA_STREAM_TO_NULL_SINK_SOURCE(x_m, x_stream, x_stream_type) { \
+    pa_sink *null_sink; \
+    pa_source *null_source; \
+    if (x_stream_type == STREAM_SINK_INPUT && \
+        (!((pa_sink_input_new_data*)x_stream)->sink)) { \
+        if ((null_sink = (pa_sink*)pa_namereg_get(x_m->core, SINK_NAME_NULL, PA_NAMEREG_SINK))) \
+            ((pa_sink_input_new_data*)x_stream)->sink = null_sink; \
+        else \
+            pa_log_warn("could not get null_sink"); \
+    } else if (x_stream_type == STREAM_SOURCE_OUTPUT && \
+               (!((pa_source_output_new_data*)x_stream)->source)) { \
+        if ((null_source = (pa_source*)pa_namereg_get(x_m->core, SOURCE_NAME_NULL, PA_NAMEREG_SOURCE))) \
+            ((pa_source_output_new_data*)x_stream)->source = null_source; \
+        else \
+            pa_log_warn("could not get null_source"); \
+    } \
+} \
+
 static void do_notify(pa_stream_manager *m, notify_command_type_t command, stream_type_t type, pa_bool_t is_new_data, void *user_data);
 static process_stream_result_t process_stream(pa_stream_manager *m, void *stream, stream_type_t type, process_command_type_t command, pa_bool_t is_new_data);
 
@@ -477,6 +508,16 @@ static int get_stream_info(pa_stream_manager *m, const char *stream_role, stream
                     pa_log_error("  avail-frameworks, out of range, [%d]", idx);
             }
             info->num_of_frameworks = pa_idxset_size(s->idx_avail_frameworks);
+        } else {
+            /* set variables for error */
+            info->priority = -1;
+            info->num_of_in_devices = info->num_of_out_devices = info->num_of_frameworks = 1;
+            info->volume_types[0] = info->volume_types[1] = dbus_str_none;
+            info->avail_in_devices[0] = dbus_str_none;
+            info->avail_out_devices[0] = dbus_str_none;
+            info->avail_frameworks[0] = dbus_str_none;
+            pa_log_error("could not find the stream_role : %s", stream_role);
+            return -1;
         }
     } else {
         pa_log_error("stream_map is not initialized..");
@@ -552,21 +593,14 @@ static void handle_get_stream_info(DBusConnection *conn, DBusMessage *msg, void
     memset(&info, 0, sizeof(stream_info_per_type));
     pa_assert_se((reply = dbus_message_new_method_return(msg)));
     dbus_message_iter_init_append(reply, &msg_iter);
-    if (!get_stream_info(m, type, &info)) {
-        pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
-        pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.volume_types, STREAM_DIRECTION_MAX);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
-    } else {
-        pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, 0);
-        pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, 0);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
-        pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, NULL, 0);
-    }
+    get_stream_info(m, type, &info);
+    pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.priority);
+    pa_dbus_append_basic_variant(&msg_iter, DBUS_TYPE_INT32, &info.route_type);
+    pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.volume_types, STREAM_DIRECTION_MAX);
+    pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_in_devices, info.num_of_in_devices);
+    pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_out_devices, info.num_of_out_devices);
+    pa_dbus_append_basic_array_variant(&msg_iter, DBUS_TYPE_STRING, &info.avail_frameworks, info.num_of_frameworks);
+
     pa_assert_se(dbus_connection_send(conn, reply, NULL));
     dbus_message_unref(reply);
 }
@@ -1445,15 +1479,14 @@ static pa_bool_t check_name_to_skip(pa_stream_manager *m, process_command_type_t
     pa_assert(stream);
 
     if (command == PROCESS_COMMAND_PREPARE && is_new_data) {
-        name = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_NAME);
-        if (name) {
+        if ((name = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_NAME))) {
             for (i = 0; i < NAME_FOR_SKIP_MAX; i++)
                 if (pa_streq(name, stream_manager_media_names_for_skip[i])) {
                     ret = TRUE;
                     pa_proplist_sets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE, SKIP_ROLE);
                     break;
                 }
-            pa_log_info("name is [%s], skip(%d)", name, ret);
+            pa_log_info("name is [%s], skip(%d) command(%s)", name, ret, process_command_type_str[command]);
         }
     } else {
         if (is_new_data)
@@ -1461,7 +1494,7 @@ static pa_bool_t check_name_to_skip(pa_stream_manager *m, process_command_type_t
         else
             role = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_ROLE);
 
-        if (role && pa_streq(role, "skip"))
+        if (role && pa_streq(role, SKIP_ROLE))
             ret = TRUE;
     }
 
@@ -1503,6 +1536,30 @@ static pa_bool_t check_route_type_to_skip(process_command_type_t command, const
     return ret;
 }
 
+static pa_bool_t check_name_is_vstream(pa_stream_manager *m, process_command_type_t command, void *stream, stream_type_t type, pa_bool_t is_new_data) {
+    pa_bool_t ret = FALSE;
+    const char *name = NULL;
+
+    pa_assert(m);
+    pa_assert(stream);
+
+    if (command == PROCESS_COMMAND_PREPARE) {
+        if (is_new_data)
+            name = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_NAME);
+        else
+            name = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_NAME);
+        if (name) {
+            if (pa_streq(name, VIRTUAL_STREAM_NAME)) {
+                ret = TRUE;
+                pa_log_info("name is [%s]", name);
+            }
+        }
+    } else
+        pa_log_warn("not supported command(%d)", command);
+
+    return ret;
+}
+
 static pa_bool_t update_priority_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, const char *role, pa_bool_t is_new_data) {
     pa_bool_t ret = FALSE;
     stream_info *s = NULL;
@@ -1566,7 +1623,7 @@ static pa_bool_t update_volume_type_of_stream(pa_stream_manager *m, void *stream
 
 static pa_bool_t update_focus_status_of_stream(pa_stream_manager *m, void *stream, stream_type_t type, pa_bool_t is_new_data) {
     const char *p_idx;
-    uint32_t parent_idx;
+    uint32_t parent_idx = 0;
     stream_parent *sp = NULL;
 
     pa_assert(m);
@@ -1577,20 +1634,17 @@ static pa_bool_t update_focus_status_of_stream(pa_stream_manager *m, void *strea
     else
         p_idx = pa_proplist_gets(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_PARENT_ID);
     if (p_idx && !pa_atou(p_idx, &parent_idx)) {
-        pa_log_debug("p_idx(%s), idx(%u)", p_idx, parent_idx);
         sp = pa_hashmap_get(m->stream_parents, (const void*)parent_idx);
         if (sp) {
             if (is_new_data)
                 pa_proplist_setf(GET_STREAM_NEW_PROPLIST(stream, type), PA_PROP_MEDIA_FOCUS_STATUS, "%u", sp->focus_status);
             else
                 pa_proplist_setf(GET_STREAM_PROPLIST(stream, type), PA_PROP_MEDIA_FOCUS_STATUS, "%u", sp->focus_status);
+            pa_log_debug("p_idx(%s), idx(%u), focus_status(0x%x, 0x1:playback 0x2:capture 0x3:both)", p_idx, parent_idx, sp->focus_status);
         } else {
             pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
             return FALSE;
         }
-    } else {
-        pa_log_warn("p_idx(%s) or idx(%u) is not valid", p_idx, parent_idx);
-        return FALSE;
     }
 
     return TRUE;
@@ -1628,10 +1682,9 @@ static pa_bool_t update_stream_parent_info(pa_stream_manager *m, process_command
             pa_log_error("could not find matching client for this parent_id(%u)", parent_idx);
             return FALSE;
         }
-    } else {
-        pa_log_warn("p_idx(%s) or idx(%u) is not valid", p_idx, parent_idx);
+    } else
         return FALSE;
-    }
+
     return TRUE;
 }
 
@@ -1643,6 +1696,7 @@ static pa_bool_t update_the_highest_priority_stream(pa_stream_manager *m, proces
     const char *route_type_str = NULL;
     stream_route_type_t route_type;
     const char *focus_status_str = NULL;
+    const char *active_dev = NULL;
     void *cur_max_stream = NULL;
     void *cur_max_stream_tmp = NULL;
     const int32_t *cur_max_priority = NULL;
@@ -1724,7 +1778,14 @@ static pa_bool_t update_the_highest_priority_stream(pa_stream_manager *m, proces
                         *need_to_update = TRUE;
                         pa_log_debug("update cur_highest to mine(%s)", role);
                     } else {
-                        /* no need to trigger */
+                        /* no need to trigger,
+                         * update active device info if possible */
+                        if ((active_dev = pa_proplist_gets(GET_STREAM_PROPLIST(cur_max_stream, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV))) {
+                            if (is_new_data)
+                                pa_proplist_sets(GET_STREAM_NEW_PROPLIST(mine, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_dev);
+                            else
+                                pa_proplist_sets(GET_STREAM_PROPLIST(mine, type), PA_PROP_MEDIA_ROUTE_AUTO_ACTIVE_DEV, active_dev);
+                        }
                         return TRUE;
                     }
                 }
@@ -1773,6 +1834,7 @@ static pa_bool_t update_the_highest_priority_stream(pa_stream_manager *m, proces
                     cur_max_priority = priority;
                     cur_max_focus_status = focus_status;
                     cur_max_stream_tmp = i;
+                    cur_max_role = _role;
                 }
                 if (cur_max_priority && priority) {
                     if (IS_FOCUS_ACQUIRED(cur_max_focus_status, type) ||
@@ -1782,6 +1844,7 @@ static pa_bool_t update_the_highest_priority_stream(pa_stream_manager *m, proces
                         cur_max_priority = priority;
                         cur_max_focus_status = focus_status;
                         cur_max_stream_tmp = i;
+                        cur_max_role = _role;
                     }
                 }
             }
@@ -1789,21 +1852,29 @@ static pa_bool_t update_the_highest_priority_stream(pa_stream_manager *m, proces
             if (cur_max_stream_tmp) {
                 if (type == STREAM_SINK_INPUT) {
                     m->cur_highest_priority.sink_input = cur_max_stream_tmp;
+                    m->cur_highest_priority.role_si = cur_max_role;
                 } else if (type == STREAM_SOURCE_OUTPUT) {
                     m->cur_highest_priority.source_output = cur_max_stream_tmp;
+                    m->cur_highest_priority.role_so = cur_max_role;
                 }
             } else {
                 if (type == STREAM_SINK_INPUT) {
                     m->cur_highest_priority.sink_input = NULL;
+                    m->cur_highest_priority.role_si = NULL;
                 } else if (type == STREAM_SOURCE_OUTPUT) {
                     m->cur_highest_priority.source_output = NULL;
+                    m->cur_highest_priority.role_so = NULL;
                 }
             }
             *need_to_update = TRUE;
-            pa_log_info("need to update: type(%d), cur_highest_priority(sink_input=%p/source_output=%p)",
-                type, (void*)m->cur_highest_priority.sink_input, (void*)m->cur_highest_priority.source_output);
+            pa_log_info("need to update: type(%d), cur_highest_priority(sink_input=%p[%s]/source_output=%p[%s])",
+                        type, (void*)m->cur_highest_priority.sink_input, m->cur_highest_priority.role_si,
+                        (void*)m->cur_highest_priority.source_output, m->cur_highest_priority.role_so);
         } else {
             /* no need to trigger */
+            pa_log_info("no need to update: type(%d), cur_highest_priority(sink_input=%p[%s]/source_output=%p[%s])",
+                        type, (void*)m->cur_highest_priority.sink_input, m->cur_highest_priority.role_si,
+                        (void*)m->cur_highest_priority.source_output, m->cur_highest_priority.role_so);
             return TRUE;
         }
     }
@@ -1928,6 +1999,7 @@ static void do_notify(pa_stream_manager *m, notify_command_type_t command, strea
                 fill_device_info_to_hook_data(m, &hook_call_select_data, command, type, s, is_new_data);
                 hook_call_select_data.sample_spec = GET_STREAM_NEW_SAMPLE_SPEC(s, type);
                 if (type == STREAM_SINK_INPUT) {
+                    hook_call_select_data.occupying_role = m->cur_highest_priority.role_si;
                     hook_call_select_data.proper_sink = &(((pa_sink_input_new_data*)s)->sink);
                     /* need to check modifier_gain, because we do not skip a stream that is from module-sound-player */
                     modifier_gain = pa_proplist_gets(GET_STREAM_NEW_PROPLIST(s, type), PA_PROP_MEDIA_TIZEN_VOLUME_GAIN_TYPE);
@@ -1937,6 +2009,7 @@ static void do_notify(pa_stream_manager *m, notify_command_type_t command, strea
                         break;
                     }
                 } else if (type == STREAM_SOURCE_OUTPUT) {
+                    hook_call_select_data.occupying_role = m->cur_highest_priority.role_si;
                     hook_call_select_data.proper_source = &(((pa_source_output_new_data*)s)->source);
                     if (((pa_source_output_new_data*)s)->source) {
                         pa_log_info("  - source(%s) has been already selected, skip selecting source",
@@ -1953,6 +2026,7 @@ static void do_notify(pa_stream_manager *m, notify_command_type_t command, strea
                 else if (type == STREAM_SOURCE_OUTPUT)
                     hook_call_select_data.proper_source = &(((pa_source_output*)s)->source);
             }
+            CONVERT_TO_DEVICE_ROLE(hook_call_select_data.stream_role, hook_call_select_data.device_role);
             pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_SELECT_INIT_SINK_OR_SOURCE), &hook_call_select_data);
         }
         break;
@@ -1979,6 +2053,7 @@ static void do_notify(pa_stream_manager *m, notify_command_type_t command, strea
             }
             hook_call_route_data.stream_type = type;
             hook_call_route_data.stream_role = role;
+            CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
             fill_device_info_to_hook_data(m, &hook_call_route_data, command, type, s, is_new_data);
             if (hook_call_route_data.route_type >= STREAM_ROUTE_TYPE_MANUAL) {
                 if (hook_call_route_data.idx_manual_devices && !pa_idxset_size(hook_call_route_data.idx_manual_devices)) {
@@ -1995,18 +2070,19 @@ static void do_notify(pa_stream_manager *m, notify_command_type_t command, strea
         s = (type == STREAM_SINK_INPUT) ? (void*)(m->cur_highest_priority.sink_input) :
                                           (void*)(m->cur_highest_priority.source_output);
         if (s) {
-            role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
             hook_call_route_data.stream = s;
             hook_call_route_data.stream_type = type;
-            hook_call_route_data.stream_role = role;
+            hook_call_route_data.stream_role = (type == STREAM_SINK_INPUT) ? (m->cur_highest_priority.role_si) :
+                                                                             (m->cur_highest_priority.role_so);
+            CONVERT_TO_DEVICE_ROLE(hook_call_route_data.stream_role, hook_call_route_data.device_role);
             hook_call_route_data.sample_spec = GET_STREAM_SAMPLE_SPEC(s, type);
             hook_call_route_data.idx_streams = (type == STREAM_SINK_INPUT) ? ((pa_sink_input*)s)->sink->inputs :
                                                                              ((pa_source_output*)s)->source->outputs;
             fill_device_info_to_hook_data(m, &hook_call_route_data, command, type, s, is_new_data);
         } else {
             pa_log_info("no stream for this type(%d), need to unset route", type);
+            hook_call_route_data.stream = NULL;
             hook_call_route_data.stream_type = type;
-            hook_call_route_data.stream_role = "reset";
         }
         pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_CHANGE_ROUTE), &hook_call_route_data);
         break;
@@ -2017,8 +2093,8 @@ static void do_notify(pa_stream_manager *m, notify_command_type_t command, strea
         s = (type == STREAM_SINK_INPUT) ? (void*)(m->cur_highest_priority.sink_input) :
                                           (void*)(m->cur_highest_priority.source_output);
         if (s) {
-            role = pa_proplist_gets(GET_STREAM_PROPLIST(s, type), PA_PROP_MEDIA_ROLE);
-            hook_call_option_data.stream_role = role;
+            hook_call_option_data.stream_role = (type == STREAM_SINK_INPUT) ? (m->cur_highest_priority.role_si) :
+                                                                              (m->cur_highest_priority.role_so);
             hook_call_option_data.name = ((stream_route_option*)user_data)->name;
             hook_call_option_data.value = ((stream_route_option*)user_data)->value;
             pa_hook_fire(pa_communicator_hook(m->comm.comm, PA_COMMUNICATOR_HOOK_UPDATE_ROUTE_OPTION), &hook_call_option_data);
@@ -2068,6 +2144,9 @@ static process_stream_result_t process_stream(pa_stream_manager *m, void *stream
 
     if (check_name_to_skip(m, command, stream, type, is_new_data)) {
         result = PROCESS_STREAM_RESULT_SKIP;
+        /* set it to null sink/source */
+        if (is_new_data)
+            SET_NEW_DATA_STREAM_TO_NULL_SINK_SOURCE(m, stream, type);
         goto FAILURE;
     }
 
@@ -2139,8 +2218,17 @@ static process_stream_result_t process_stream(pa_stream_manager *m, void *stream
             }
         }
 
-        /* notify to select sink or source */
-        do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, TRUE, stream);
+        /* check if it is a virtual stream */
+        if (check_name_is_vstream(m, command, stream, type, is_new_data)) {
+            pa_log_debug("skip notifying for selecting sink/source, rather set it to null sink/source");
+            /* set it to null sink/source */
+            if (is_new_data)
+                SET_NEW_DATA_STREAM_TO_NULL_SINK_SOURCE(m, stream, type);
+
+        } else {
+            /* notify to select sink or source */
+            do_notify(m, NOTIFY_COMMAND_SELECT_PROPER_SINK_OR_SOURCE_FOR_INIT, type, TRUE, stream);
+        }
 
     } else if (command == PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED) {
         if (is_new_data) {
@@ -2197,10 +2285,13 @@ static process_stream_result_t process_stream(pa_stream_manager *m, void *stream
                     m->cur_highest_priority.need_to_update_so = TRUE;
             } else {
                 do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, FALSE, stream);
-                if (type == STREAM_SINK_INPUT)
+                if (type == STREAM_SINK_INPUT) {
                     m->cur_highest_priority.sink_input = stream;
-                else
+                    m->cur_highest_priority.role_si = role;
+                } else {
                     m->cur_highest_priority.source_output = stream;
+                    m->cur_highest_priority.role_so = role;
+                }
             }
         }
         if (!is_new_data)
@@ -2320,10 +2411,12 @@ static process_stream_result_t process_stream(pa_stream_manager *m, void *stream
                 if (command == PROCESS_COMMAND_ADD_PARENT_ID) {
                     if (type == STREAM_SINK_INPUT && m->cur_highest_priority.need_to_update_si) {
                         m->cur_highest_priority.sink_input = stream;
+                        m->cur_highest_priority.role_si = role;
                         m->cur_highest_priority.need_to_update_si = FALSE;
                     }
                     if (type == STREAM_SOURCE_OUTPUT && m->cur_highest_priority.need_to_update_so) {
                         m->cur_highest_priority.source_output = stream;
+                        m->cur_highest_priority.role_so = role;
                         m->cur_highest_priority.need_to_update_so = FALSE;
                     }
                     do_notify(m, NOTIFY_COMMAND_INFORM_STREAM_CONNECTED, type, FALSE, stream);
@@ -2333,7 +2426,7 @@ static process_stream_result_t process_stream(pa_stream_manager *m, void *stream
             /* update parent stream info. */
             ret = update_stream_parent_info(m, command, type, stream);
             if (ret == FALSE) {
-                pa_log_warn("could not update the parent information of this stream");
+                pa_log_debug("could not update the parent information of this stream");
                 //return PROCESS_STREAM_RESULT_STOP;
             }
         }
@@ -3045,7 +3138,7 @@ static void subscribe_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t
         return;
     }
     name = pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME);
-    if (name && strncmp(name, STREAM_MANAGER_CLIENT_NAME, strlen(STREAM_MANAGER_CLIENT_NAME))) {
+    if (name && !pa_streq(name, STREAM_MANAGER_CLIENT_NAME)) {
         pa_log_warn(" - this is not a client(%s) that we should take care of, skip it", name);
         return;
     }
index 93b3c3d..c63e2da 100644 (file)
 #define GET_STREAM_PROPLIST(stream, type) \
       (type == STREAM_SINK_INPUT ? ((pa_sink_input*)stream)->proplist : ((pa_source_output*)stream)->proplist)
 
+#define STREAM_ROLE_CALL_VOICE        "call-voice"
+#define STREAM_ROLE_CALL_VIDEO        "call-video"
+#define STREAM_ROLE_VOIP              "voip"
+
 #define SINK_NAME_COMBINED            "sink_combined"
 #define SINK_NAME_NULL                "sink_null"
 #define SOURCE_NAME_NULL              "source_null"
@@ -36,6 +40,8 @@ typedef enum stream_route_type {
 typedef struct _hook_call_data_for_select {
     void *stream;
     const char *stream_role;
+    const char *device_role;
+    const char *occupying_role;
     stream_type_t stream_type;
     stream_route_type_t route_type;
     pa_sink **proper_sink;
@@ -49,6 +55,7 @@ typedef struct _hook_call_data_for_select {
 typedef struct _hook_call_data_for_route {
     void *stream;
     const char *stream_role;
+    const char *device_role;
     stream_type_t stream_type;
     stream_route_type_t route_type;
     pa_sink **proper_sink;