audio policy: refactor preferred route implementation

Remove SessionRoute class and replace by use of
preferredDevice and active state in ClientDescriptor

Also fix the behavior for other clients using same strategy as
client with preferred route: the preferred route is only used if
no other clients using the same strategy are active without a preferred
route.
If all clients have a preferred route, the route of the last active
client is used.

Also fixed getOutputForAttr() to return correct selected device ID when
dynamic policies are used.

Test: CTS RoutingTest, AudioPlayRoutingNative, AudioRecordRoutingNative
Test: Manual: AudioExplicitRouting, UplinkMusicSampleApp

Change-Id: Id342c2241ace3e1a359ea74f4a539a395f793b86
diff --git a/services/audiopolicy/common/include/RoutingStrategy.h b/services/audiopolicy/common/include/RoutingStrategy.h
index d38967e..f8a1cd6 100644
--- a/services/audiopolicy/common/include/RoutingStrategy.h
+++ b/services/audiopolicy/common/include/RoutingStrategy.h
@@ -23,6 +23,7 @@
 #define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
 
 enum routing_strategy {
+    STRATEGY_NONE = -1,
     STRATEGY_MEDIA,
     STRATEGY_PHONE,
     STRATEGY_SONIFICATION,
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 9b8f095..5ba2d4a 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -17,7 +17,6 @@
     src/AudioCollections.cpp \
     src/EffectDescriptor.cpp \
     src/SoundTriggerSession.cpp \
-    src/SessionRoute.cpp \
     src/VolumeCurve.cpp \
     src/TypeConverter.cpp \
     src/AudioSession.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 44662e5..0d1d8c3 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -89,8 +89,10 @@
     void stop();
     void close();
 
-    RecordClientMap& clients() { return mClients; }
+    RecordClientMap& clientsMap() { return mClients; }
     RecordClientVector getClientsForSession(audio_session_t session);
+    RecordClientVector clientsList(bool activeOnly = false,
+        audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
 
  private:
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index ff0201a..4cf16a0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -78,7 +78,9 @@
     audio_patch_handle_t getPatchHandle() const override;
     void setPatchHandle(audio_patch_handle_t handle) override;
 
-    TrackClientMap& clients() { return mClients; }
+    TrackClientMap& clientsMap() { return mClients; }
+    TrackClientVector clientsList(bool activeOnly = false,
+        routing_strategy strategy = STRATEGY_NONE, bool preferredDeviceOnly = false) const;
 
     sp<AudioPort> mPort;
     audio_devices_t mDevice;                   // current device this output is routed to
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index f861b95..78e7ec9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -28,7 +28,6 @@
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
-#include <SessionRoute.h>
 
 namespace android {
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 9efe57f..cc751b1 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -27,6 +27,7 @@
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include "AudioPatch.h"
+#include "RoutingStrategy.h"
 
 namespace android {
 
@@ -53,8 +54,14 @@
     audio_attributes_t attributes() const { return mAttributes; }
     audio_config_base_t config() const { return mConfig; }
     audio_port_handle_t preferredDeviceId() const { return mPreferredDeviceId; };
+    void setPreferredDeviceId(audio_port_handle_t preferredDeviceId) {
+        mPreferredDeviceId = preferredDeviceId;
+    };
     void setActive(bool active) { mActive = active; }
     bool active() const { return mActive; }
+    bool hasPreferredDevice(bool activeOnly = false) const {
+        return mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
+    }
 
 private:
     const audio_port_handle_t mPortId;  // unique Id for this client
@@ -62,7 +69,7 @@
     const audio_session_t mSessionId;       // audio session ID
     const audio_attributes_t mAttributes; // usage...
     const audio_config_base_t mConfig;
-    const audio_port_handle_t mPreferredDeviceId;  // selected input device port ID
+          audio_port_handle_t mPreferredDeviceId;  // selected input device port ID
           bool mActive;
 
 protected:
@@ -75,10 +82,10 @@
 public:
     TrackClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId,
                    audio_attributes_t attributes, audio_config_base_t config,
-                   audio_port_handle_t preferredDeviceId,
-                   audio_stream_type_t stream, audio_output_flags_t flags) :
+                   audio_port_handle_t preferredDeviceId, audio_stream_type_t stream,
+                          routing_strategy strategy, audio_output_flags_t flags) :
         ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId),
-        mStream(stream), mFlags(flags) {}
+        mStream(stream), mStrategy(strategy), mFlags(flags) {}
     ~TrackClientDescriptor() override = default;
 
     using ClientDescriptor::dump;
@@ -86,9 +93,11 @@
 
     audio_output_flags_t flags() const { return mFlags; }
     audio_stream_type_t stream() const { return mStream; }
+    routing_strategy strategy() const { return mStrategy; }
 
 private:
     const audio_stream_type_t mStream;
+    const routing_strategy mStrategy;
     const audio_output_flags_t mFlags;
 };
 
@@ -119,7 +128,7 @@
 public:
     SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
                            const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
-                           audio_stream_type_t stream);
+                           audio_stream_type_t stream, routing_strategy strategy);
     ~SourceClientDescriptor() override = default;
 
     sp<AudioPatch> patchDesc() const { return mPatchDesc; }
diff --git a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h b/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
deleted file mode 100644
index 32b4440..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/SessionRoute.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <system/audio.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class DeviceDescriptor;
-class DeviceVector;
-
-class SessionRoute : public RefBase
-{
-public:
-    // For Input (Source) routes, use STREAM_TYPE_NA ("NA" = "not applicable)for the
-    // streamType argument
-    static const audio_stream_type_t STREAM_TYPE_NA = AUDIO_STREAM_DEFAULT;
-
-    // For Output (Sink) routes, use SOURCE_TYPE_NA ("NA" = "not applicable") for the
-    // source argument
-
-    static const audio_source_t SOURCE_TYPE_NA = AUDIO_SOURCE_DEFAULT;
-
-    SessionRoute(audio_session_t session,
-                 audio_stream_type_t streamType,
-                 audio_source_t source,
-                 sp<DeviceDescriptor> deviceDescriptor,
-                 uid_t uid)
-        : mUid(uid),
-          mSession(session),
-          mDeviceDescriptor(deviceDescriptor),
-          mRefCount(0),
-          mActivityCount(0),
-          mChanged(false),
-          mStreamType(streamType),
-          mSource(source)
-    {}
-
-    void log(const char* prefix);
-
-    bool isActiveOrChanged() {
-        return (mDeviceDescriptor != 0) && (mChanged || (mActivityCount > 0));
-    }
-
-    uid_t                       mUid;
-    audio_session_t             mSession;
-    sp<DeviceDescriptor>        mDeviceDescriptor;
-
-    // "reference" counting
-    int                         mRefCount;      // +/- on references
-    int                         mActivityCount; // +/- on start/stop
-    bool                        mChanged;
-    // for outputs
-    const audio_stream_type_t   mStreamType;
-    // for inputs
-    const audio_source_t        mSource;
-};
-
-class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute> >
-{
-public:
-    // These constants identify the SessionRoutMap as holding EITHER input routes,
-    // or output routes.  An error will occur if an attempt is made to add a SessionRoute
-    // object with mStreamType == STREAM_TYPE_NA (i.e. an input SessionRoute) to a
-    // SessionRoutMap that is marked for output (i.e. mMapType == SESSION_ROUTE_MAP_OUTPUT)
-    // and similarly  for output SessionRoutes and Input SessionRouteMaps.
-    typedef enum
-    {
-        MAPTYPE_INPUT = 0,
-        MAPTYPE_OUTPUT = 1
-    } session_route_map_type_t;
-
-    explicit SessionRouteMap(session_route_map_type_t mapType) :
-        mMapType(mapType)
-    {}
-
-    bool hasRoute(audio_session_t session);
-
-    void removeRoute(audio_session_t session);
-
-    int incRouteActivity(audio_session_t session);
-    int decRouteActivity(audio_session_t session);
-    bool getAndClearRouteChanged(audio_session_t session); // also clears the changed flag
-    void log(const char* caption);
-    audio_devices_t getActiveDeviceForStream(audio_stream_type_t streamType,
-                                             const DeviceVector& availableDevices);
-    // Specify an Output(Sink) route by passing SessionRoute::SOURCE_TYPE_NA in the
-    // source argument.
-    // Specify an Input(Source) rout by passing SessionRoute::AUDIO_STREAM_DEFAULT
-    // in the streamType argument.
-    void addRoute(audio_session_t session,
-                  audio_stream_type_t streamType,
-                  audio_source_t source,
-                  const sp<DeviceDescriptor>& deviceDescriptor,
-                  uid_t uid);
-
-private:
-    // Used to mark a SessionRoute as for either inputs (mMapType == kSessionRouteMap_Input)
-    // or outputs (mMapType == kSessionRouteMap_Output)
-    const session_route_map_type_t mMapType;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 2770e74..3c7562e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -352,6 +352,20 @@
     return clients;
 }
 
+RecordClientVector AudioInputDescriptor::clientsList(bool activeOnly, audio_source_t source,
+                                                     bool preferredDeviceOnly) const
+{
+    RecordClientVector clients;
+    for (const auto &client : mClients) {
+        if ((!activeOnly || client.second->active())
+            && (source == AUDIO_SOURCE_DEFAULT || source == client.second->source())
+            && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
+            clients.push_back(client.second);
+        }
+    }
+    return clients;
+}
+
 status_t AudioInputDescriptor::dump(int fd)
 {
     const size_t SIZE = 256;
@@ -446,7 +460,7 @@
 {
     for (size_t i = 0; i < size(); i++) {
         sp<AudioInputDescriptor> inputDesc = valueAt(i);
-        for (const auto& client : inputDesc->clients()) {
+        for (const auto& client : inputDesc->clientsMap()) {
             if (client.second->portId() == portId) {
                 return inputDesc;
             }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 39fce4d..a39ac6d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -201,6 +201,20 @@
     port->ext.mix.hw_module = getModuleHandle();
 }
 
+TrackClientVector AudioOutputDescriptor::clientsList(bool activeOnly, routing_strategy strategy,
+                                                     bool preferredDeviceOnly) const
+{
+    TrackClientVector clients;
+    for (const auto &client : mClients) {
+        if ((!activeOnly || client.second->active())
+            && (strategy == STRATEGY_NONE || strategy == client.second->strategy())
+            && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
+            clients.push_back(client.second);
+        }
+    }
+    return clients;
+}
+
 status_t AudioOutputDescriptor::dump(int fd)
 {
     const size_t SIZE = 256;
@@ -742,7 +756,7 @@
 {
     for (size_t i = 0; i < size(); i++) {
         sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-        for (const auto& client : outputDesc->clients()) {
+        for (const auto& client : outputDesc->clientsMap()) {
             if (client.second->portId() == portId) {
                 return outputDesc;
             }
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 5aca3cc..0cf206d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -29,6 +29,7 @@
 
 namespace android {
 
+
 status_t ClientDescriptor::dump(int fd, int spaces, int index)
 {
     String8 out;
@@ -76,9 +77,11 @@
 
 SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
          audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
-         const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream) :
+         const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
+         routing_strategy strategy) :
     TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
-        AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE, stream, AUDIO_OUTPUT_FLAG_NONE),
+        AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
+        stream, strategy, AUDIO_OUTPUT_FLAG_NONE),
         mPatchDesc(patchDesc), mSrcDevice(srcDevice)
 {
 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
deleted file mode 100644
index 440a4e7..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/SessionRoute.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM_SessionRoute"
-//#define LOG_NDEBUG 0
-
-#include "SessionRoute.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include "DeviceDescriptor.h"
-#include <utils/Log.h>
-
-namespace android {
-
-// --- SessionRoute class implementation
-void SessionRoute::log(const char* prefix)
-{
-    ALOGI("%s[SessionRoute strm:0x%X, src:%d, sess:0x%X, dev:0x%X refs:%d act:%d",
-          prefix, mStreamType, mSource, mSession,
-          mDeviceDescriptor != 0 ? mDeviceDescriptor->type() : AUDIO_DEVICE_NONE,
-          mRefCount, mActivityCount);
-}
-
-// --- SessionRouteMap class implementation
-bool SessionRouteMap::hasRoute(audio_session_t session)
-{
-    return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
-}
-
-bool SessionRouteMap::getAndClearRouteChanged(audio_session_t session)
-{
-    if (indexOfKey(session) >= 0) {
-        if (valueFor(session)->mChanged) {
-            valueFor(session)->mChanged = false;
-            return true;
-        }
-    }
-    return false;
-}
-
-void 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 SessionRouteMap::incRouteActivity(audio_session_t session)
-{
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-    return route != 0 ? ++(route->mActivityCount) : -1;
-}
-
-int 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 SessionRouteMap::log(const char* caption)
-{
-    ALOGI("%s ----", caption);
-    for (size_t index = 0; index < size(); index++) {
-        valueAt(index)->log("  ");
-    }
-}
-
-void SessionRouteMap::addRoute(audio_session_t session,
-                               audio_stream_type_t streamType,
-                               audio_source_t source,
-                               const sp<DeviceDescriptor>& descriptor,
-                               uid_t uid)
-{
-    if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) {
-        ALOGE("Adding Output Route to InputRouteMap");
-        return;
-    } else if (mMapType == MAPTYPE_OUTPUT && source != SessionRoute::SOURCE_TYPE_NA) {
-        ALOGE("Adding Input Route to OutputRouteMap");
-        return;
-    }
-
-    sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
-
-    if (route != 0) {
-        if (descriptor != 0 || route->mDeviceDescriptor != 0) {
-            route->mChanged = true;
-        }
-        route->mRefCount++;
-        route->mDeviceDescriptor = descriptor;
-    } else {
-        route = new SessionRoute(session, streamType, source, descriptor, uid);
-        route->mRefCount++;
-        if (descriptor != 0) {
-            route->mChanged = true;
-        }
-        add(session, route);
-    }
-}
-
-audio_devices_t SessionRouteMap::getActiveDeviceForStream(audio_stream_type_t streamType,
-                                                          const DeviceVector& availableDevices)
-{
-    for (size_t index = 0; index < size(); index++) {
-        sp<SessionRoute> route = valueAt(index);
-        if (streamType == route->mStreamType && route->isActiveOrChanged()
-                && route->mDeviceDescriptor != 0) {
-            audio_devices_t device = route->mDeviceDescriptor->type();
-            if (!availableDevices.getDevicesFromTypeMask(device).isEmpty()) {
-                return device;
-            }
-        }
-    }
-    return AUDIO_DEVICE_NONE;
-}
-
-} // namespace android