Adding explicit routing API to AudioTrack

Change-Id: I40c048c7644c46f4e4f7103875206c0785c4b1dc
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 116d0d6..48d0e29 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -110,6 +110,7 @@
                                         audio_format_t format,
                                         audio_channel_mask_t channelMask,
                                         audio_output_flags_t flags,
+                                        int selectedDeviceId,
                                         const audio_offload_info_t *offloadInfo) = 0;
     // indicates to the audio policy manager that the output starts being used by corresponding stream.
     virtual status_t startOutput(audio_io_handle_t output,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 43ee691..c3f584e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -36,6 +36,7 @@
     AudioOutputDescriptor(const sp<IOProfile>& profile);
 
     status_t    dump(int fd);
+    void        log(const char* indent);
 
     audio_devices_t device() const;
     void changeRefCount(audio_stream_type_t stream, int delta);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 4f7f2bc..16eac50 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -78,6 +78,7 @@
     audio_module_handle_t getModuleHandle() const;
 
     void dump(int fd, int spaces) const;
+    void log(const char* indent) const;
 
     String8           mName;
     audio_port_type_t mType;
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index d15f6b4..d6daacd 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -46,6 +46,7 @@
 
     audio_devices_t type() const { return mDeviceType; }
     status_t dump(int fd, int spaces, int index) const;
+    void log() const;
 
     String8 mAddress;
     audio_port_handle_t mId;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index cdb5b51..7207a71 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -226,6 +226,12 @@
     return NO_ERROR;
 }
 
+void AudioOutputDescriptor::log(const char* indent)
+{
+    ALOGI("%sID: %d,0x%X, [rt:%d fmt:0x%X ch:0x%X] hndl:%d",
+          indent, mId, mId, mSamplingRate, mFormat, mChannelMask, mIoHandle);
+}
+
 bool AudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
 {
     nsecs_t sysTime = systemTime();
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 46a119e..2bbcc05 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -694,6 +694,10 @@
     }
 }
 
+void AudioPort::log(const char* indent) const
+{
+    ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.string(), mType, mRole);
+}
 
 // --- AudioPortConfig class implementation
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 7df7d75..9249d47 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -317,4 +317,16 @@
     return NO_ERROR;
 }
 
+void DeviceDescriptor::log() const
+{
+    ALOGI("Device id:%d type:0x%X:%s, addr:%s",
+          mId,
+          mDeviceType,
+          ConfigParsingUtils::enumToString(
+             sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), mDeviceType),
+          mAddress.string());
+
+    AudioPort::log("  ");
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 797a2b4..804a64b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -621,6 +621,7 @@
                                               audio_format_t format,
                                               audio_channel_mask_t channelMask,
                                               audio_output_flags_t flags,
+                                              audio_port_handle_t selectedDeviceId,
                                               const audio_offload_info_t *offloadInfo)
 {
     audio_attributes_t attributes;
@@ -675,6 +676,17 @@
     if (*output == AUDIO_IO_HANDLE_NONE) {
         return INVALID_OPERATION;
     }
+
+    // Explicit routing?
+    sp<DeviceDescriptor> deviceDesc;
+
+    for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
+        if (mAvailableOutputDevices[i]->getHandle() == selectedDeviceId) {
+            deviceDesc = mAvailableOutputDevices[i];
+            break;
+        }
+    }
+    mOutputRoutes.addRoute(session, *stream, deviceDesc);
     return NO_ERROR;
 }
 
@@ -856,7 +868,6 @@
     }
 
 non_direct_output:
-
     // ignoring channel mask due to downmix capability in mixer
 
     // open a non direct output
@@ -874,7 +885,7 @@
     ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d,"
             "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
 
-    ALOGV("getOutput() returns output %d", output);
+    ALOGV("  getOutputForDevice() returns output %d", output);
 
     return output;
 }
@@ -941,7 +952,8 @@
                                              audio_stream_type_t stream,
                                              audio_session_t session)
 {
-    ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+    ALOGV("startOutput() output %d, stream %d, session %d",
+          output, stream, session);
     ssize_t index = mOutputs.indexOfKey(output);
     if (index < 0) {
         ALOGW("startOutput() unknown output %d", output);
@@ -963,12 +975,14 @@
     }
 
     sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
-
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
     // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
     outputDesc->changeRefCount(stream, 1);
 
+    // Routing?
+    mOutputRoutes.incRouteActivity(session);
+
     if (outputDesc->mRefCount[stream] == 1) {
         // starting an output being rerouted?
         audio_devices_t newDevice;
@@ -1067,6 +1081,10 @@
     if (outputDesc->mRefCount[stream] > 0) {
         // decrement usage count of this stream on the output
         outputDesc->changeRefCount(stream, -1);
+
+        // Routing?
+        mOutputRoutes.decRouteActivity(session);
+
         // store time at which the stream was stopped - see isStreamActive()
         if (outputDesc->mRefCount[stream] == 0) {
             // Automatically disable the remote submix input when output is stopped on a
@@ -1138,6 +1156,9 @@
     }
 #endif //AUDIO_POLICY_TEST
 
+    // Routing
+    mOutputRoutes.removeRoute(session);
+
     sp<AudioOutputDescriptor> desc = mOutputs.valueAt(index);
     if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
         if (desc->mDirectOpenCount <= 0) {
@@ -3779,6 +3800,21 @@
 audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
                                                          bool fromCache)
 {
+    // Routing
+    // see if we have an explicit route
+    // scan the whole RouteMap, for each entry, convert the stream type to a strategy
+    // (getStrategy(stream)).
+    // if the strategy from the stream type in the RouteMap is the same as the argument above,
+    // and activity count is non-zero
+    // the device = the device from the descriptor in the RouteMap, and exit.
+    for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
+        sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
+        routing_strategy strat = getStrategy(route->mStreamType);
+        if (strat == strategy && route->mDeviceDescriptor != 0 /*&& route->mActivityCount != 0*/) {
+            return route->mDeviceDescriptor->type();
+        }
+    }
+
     if (fromCache) {
         ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
               strategy, mDeviceForStrategy[strategy]);
@@ -3895,8 +3931,8 @@
     }
     // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
     // output profile
-    if ((device != AUDIO_DEVICE_NONE) &&
-            ((device & outputDesc->mProfile->mSupportedDevices.types()) == 0)) {
+    if (device != AUDIO_DEVICE_NONE &&
+        (device & outputDesc->mProfile->mSupportedDevices.types()) == 0) {
         return 0;
     }
 
@@ -3905,7 +3941,7 @@
 
     audio_devices_t prevDevice = outputDesc->mDevice;
 
-    ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+    ALOGV("setOutputDevice() prevDevice 0x%04x", prevDevice);
 
     if (device != AUDIO_DEVICE_NONE) {
         outputDesc->mDevice = device;
@@ -3918,9 +3954,10 @@
     //  AND force is not specified
     //  AND the output is connected by a valid audio patch.
     // Doing this check here allows the caller to call setOutputDevice() without conditions
-    if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force &&
-            outputDesc->mPatchHandle != 0) {
-        ALOGV("setOutputDevice() setting same device %04x or null device for output %d",
+    if ((device == AUDIO_DEVICE_NONE || device == prevDevice) &&
+        !force &&
+        outputDesc->mPatchHandle != 0) {
+        ALOGV("setOutputDevice() setting same device 0x%04x or null device for output %d",
               device, output);
         return muteWaitMs;
     }
@@ -4406,6 +4443,70 @@
     }
 }
 
+// --- SessionRoute class implementation
+void AudioPolicyManager::SessionRoute::log(const char* prefix) {
+    ALOGI("%s[SessionRoute strm:0x%X, sess:0x%X, dev:0x%X refs:%d act:%d",
+          prefix, mStreamType, mSession,
+          mDeviceDescriptor != 0 ? mDeviceDescriptor->type() : AUDIO_DEVICE_NONE,
+          mRefCount, mActivityCount);
+}
+
+// --- SessionRouteMap class implementation
+bool AudioPolicyManager::SessionRouteMap::hasRoute(audio_session_t session)
+{
+    return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
+}
+
+void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session,
+                                                   audio_stream_type_t streamType,
+                                                   sp<DeviceDescriptor> deviceDescriptor)
+{
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+    if (route != NULL) {
+        route->mRefCount++;
+        route->mDeviceDescriptor = deviceDescriptor;
+    } else {
+        route = new AudioPolicyManager::SessionRoute(session, streamType, deviceDescriptor);
+        route->mRefCount++;
+        add(session, route);
+    }
+}
+
+void AudioPolicyManager::SessionRouteMap::removeRoute(audio_session_t session)
+{
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+    if (route != 0) {
+        ALOG_ASSERT(route->mRefCount > 0);
+        --route->mRefCount;
+        if (route->mRefCount <= 0) {
+            removeItem(session);
+        }
+    }
+}
+
+int AudioPolicyManager::SessionRouteMap::incRouteActivity(audio_session_t session)
+{
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+    return route != 0 ? ++(route->mActivityCount) : -1;
+}
+
+int AudioPolicyManager::SessionRouteMap::decRouteActivity(audio_session_t session)
+{
+    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
+    if (route != 0 && route->mActivityCount > 0) {
+        return --(route->mActivityCount);
+    } else {
+        return -1;
+    }
+}
+
+void AudioPolicyManager::SessionRouteMap::log(const char* caption) {
+    ALOGI("%s ----", caption);
+    for(size_t index = 0; index < size(); index++) {
+        valueAt(index)->log("  ");
+    }
+}
+
 void AudioPolicyManager::defaultAudioPolicyConfig(void)
 {
     sp<HwModule> module;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 02b678a..9fab9ef 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -110,6 +110,7 @@
                                           audio_format_t format,
                                           audio_channel_mask_t channelMask,
                                           audio_output_flags_t flags,
+                                          audio_port_handle_t selectedDeviceId,
                                           const audio_offload_info_t *offloadInfo);
         virtual status_t startOutput(audio_io_handle_t output,
                                      audio_stream_type_t stream,
@@ -227,6 +228,46 @@
         // return the strategy corresponding to a given stream type
         routing_strategy getStrategy(audio_stream_type_t stream) const;
 
+protected:
+        class SessionRoute : public RefBase
+        {
+        public:
+            friend class SessionRouteMap;
+            SessionRoute(audio_session_t session,
+                         audio_stream_type_t streamType,
+                         sp<DeviceDescriptor> deviceDescriptor)
+                : mSession(session),
+                  mStreamType(streamType),
+                  mDeviceDescriptor(deviceDescriptor),
+                  mRefCount(0),
+                  mActivityCount(0) {}
+
+            audio_session_t         mSession;
+            audio_stream_type_t     mStreamType;
+
+            sp<DeviceDescriptor>    mDeviceDescriptor;
+
+            // "reference" counting
+            int mRefCount;       // +/- on references
+            int mActivityCount;  // +/- on start/stop
+
+            void log(const char* prefix);
+        };
+
+        class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>>
+        {
+         public:
+            bool hasRoute(audio_session_t session);
+            void addRoute(audio_session_t session, audio_stream_type_t streamType,
+                          sp<DeviceDescriptor> deviceDescriptor);
+            void removeRoute(audio_session_t session);
+
+            int incRouteActivity(audio_session_t session);
+            int decRouteActivity(audio_session_t session);
+
+            void log(const char* caption);
+        };
+
         // From AudioPolicyManagerObserver
         virtual const AudioPatchCollection &getAudioPatches() const
         {
@@ -475,6 +516,9 @@
         DeviceVector  mAvailableOutputDevices; // all available output devices
         DeviceVector  mAvailableInputDevices;  // all available input devices
 
+        SessionRouteMap mOutputRoutes;
+        SessionRouteMap mInputRoutes;
+
         StreamDescriptorCollection mStreams; // stream descriptors for volume control
         bool    mLimitRingtoneVolume;        // limit ringtone volume to music volume if headset connected
         audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index e9ff8389..a763151 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -150,6 +150,7 @@
                                               audio_format_t format,
                                               audio_channel_mask_t channelMask,
                                               audio_output_flags_t flags,
+                                              int mSelectedDeviceId,
                                               const audio_offload_info_t *offloadInfo)
 {
     if (mAudioPolicyManager == NULL) {
@@ -158,7 +159,7 @@
     ALOGV("getOutput()");
     Mutex::Autolock _l(mLock);
     return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, samplingRate,
-                                    format, channelMask, flags, offloadInfo);
+                                    format, channelMask, flags, mSelectedDeviceId, offloadInfo);
 }
 
 status_t AudioPolicyService::startOutput(audio_io_handle_t output,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 5a91192..372a9fa 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -569,6 +569,7 @@
                                               audio_format_t format,
                                               audio_channel_mask_t channelMask,
                                               audio_output_flags_t flags,
+                                              int selectedDeviceId __unused,
                                               const audio_offload_info_t *offloadInfo)
 {
     if (attr != NULL) {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 0378384..f8dabd3 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -84,6 +84,7 @@
                                       audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                       audio_channel_mask_t channelMask = 0,
                                       audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                      int selectedDeviceId = AUDIO_PORT_HANDLE_NONE,
                                       const audio_offload_info_t *offloadInfo = NULL);
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,