audio policy: use client descriptors

First step in implementing use of ClientDescriptor class to keep track
of playback and capture activity:
- update AudioPolicyInterface methods to just use port ID as
client identifier
- add list of clients in input and output descriptors and update list
when clients are added and removed.
- list clients in audio policy manager dump.

Test: Audio smoke tests. CTS tests for AudioTrack, AudioRecord, routing, recording and playback configurations

Change-Id: Ia0f62f295d421fb845d57afcaa0ce77cd2c58775
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index fe49483..c9e99d5 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -124,17 +124,11 @@
                                         audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId) = 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,
-                                 audio_stream_type_t stream,
-                                 audio_session_t session) = 0;
+    virtual status_t startOutput(audio_port_handle_t portId) = 0;
     // indicates to the audio policy manager that the output stops being used by corresponding stream.
-    virtual status_t stopOutput(audio_io_handle_t output,
-                                audio_stream_type_t stream,
-                                audio_session_t session) = 0;
+    virtual status_t stopOutput(audio_port_handle_t portId) = 0;
     // releases the output.
-    virtual void releaseOutput(audio_io_handle_t output,
-                               audio_stream_type_t stream,
-                               audio_session_t session) = 0;
+    virtual void releaseOutput(audio_port_handle_t portId) = 0;
 
     // request an input appropriate for record from the supplied device with supplied parameters.
     virtual status_t getInputForAttr(const audio_attributes_t *attr,
@@ -147,16 +141,13 @@
                                      input_type_t *inputType,
                                      audio_port_handle_t *portId) = 0;
     // indicates to the audio policy manager that the input starts being used.
-    virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session,
+    virtual status_t startInput(audio_port_handle_t portId,
                                 bool silenced,
                                 concurrency_type__mask_t *concurrency) = 0;
     // indicates to the audio policy manager that the input stops being used.
-    virtual status_t stopInput(audio_io_handle_t input,
-                               audio_session_t session) = 0;
+    virtual status_t stopInput(audio_port_handle_t portId) = 0;
     // releases the input.
-    virtual void releaseInput(audio_io_handle_t input,
-                              audio_session_t session) = 0;
+    virtual void releaseInput(audio_port_handle_t portId) = 0;
 
     //
     // volume control functions
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index ca837c4..44662e5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -19,6 +19,7 @@
 #include "AudioIODescriptorInterface.h"
 #include "AudioPort.h"
 #include "AudioSession.h"
+#include "ClientDescriptor.h"
 #include <utils/Errors.h>
 #include <system/audio.h>
 #include <utils/SortedVector.h>
@@ -88,7 +89,10 @@
     void stop();
     void close();
 
-private:
+    RecordClientMap& clients() { return mClients; }
+    RecordClientVector getClientsForSession(audio_session_t session);
+
+ private:
 
     void updateSessionRecordingConfiguration(int event, const sp<AudioSession>& audioSession);
 
@@ -105,6 +109,8 @@
     SortedVector<audio_session_t> mPreemptedSessions;
     AudioPolicyClientInterface *mClientInterface;
     uint32_t mGlobalRefCount;  // non-session-specific ref count
+
+    RecordClientMap mClients;
 };
 
 class AudioInputCollection :
@@ -128,6 +134,8 @@
 
     audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
 
+    sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
+
     status_t dump(int fd) const;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 292e59f..e6112bf 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -17,14 +17,15 @@
 #pragma once
 
 #include <sys/types.h>
-#include "AudioPort.h"
-#include <RoutingStrategy.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
+#include <RoutingStrategy.h>
 #include "AudioIODescriptorInterface.h"
+#include "AudioPort.h"
 #include "AudioSourceDescriptor.h"
+#include "ClientDescriptor.h"
 
 namespace android {
 
@@ -78,7 +79,9 @@
     audio_patch_handle_t getPatchHandle() const override;
     void setPatchHandle(audio_patch_handle_t handle) override;
 
-    sp<AudioPort>       mPort;
+    TrackClientMap& clients() { return mClients; }
+
+    sp<AudioPort> mPort;
     audio_devices_t mDevice;                   // current device this output is routed to
     uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
     nsecs_t mStopTime[AUDIO_STREAM_CNT];
@@ -91,6 +94,7 @@
 protected:
     audio_patch_handle_t mPatchHandle;
     audio_port_handle_t mId;
+    TrackClientMap mClients;
 };
 
 // Audio output driven by a software mixer in audio flinger.
@@ -226,6 +230,8 @@
 
     audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
 
+    sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
+
     status_t dump(int fd) const;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index fb09932..221c2e9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -16,12 +16,15 @@
 
 #pragma once
 
+#include <vector>
+#include <map>
 #include <unistd.h>
 #include <sys/types.h>
 
 #include <system/audio.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -35,7 +38,8 @@
         mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false) {}
     ~ClientDescriptor() override = default;
 
-    virtual status_t  dump(int fd);
+    status_t dump(int fd, int spaces, int index);
+    virtual status_t dump(String8& dst, int spaces, int index);
 
     audio_port_handle_t portId() const { return mPortId; }
     uid_t uid() const { return mUid; }
@@ -67,7 +71,8 @@
         mStream(stream), mFlags(flags) {}
     ~TrackClientDescriptor() override = default;
 
-    status_t    dump(int fd) override;
+    using ClientDescriptor::dump;
+    status_t dump(String8& dst, int spaces, int index) override;
 
     audio_output_flags_t flags() const { return mFlags; }
     audio_stream_type_t stream() const { return mStream; }
@@ -88,7 +93,8 @@
         mSource(source), mFlags(flags) {}
     ~RecordClientDescriptor() override = default;
 
-    status_t    dump(int fd) override;
+    using ClientDescriptor::dump;
+    status_t dump(String8& dst, int spaces, int index) override;
 
     audio_source_t source() const { return mSource; }
     audio_input_flags_t flags() const { return mFlags; }
@@ -98,4 +104,9 @@
     const audio_input_flags_t mFlags;
 };
 
+typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
+typedef std::map< audio_port_handle_t, sp<TrackClientDescriptor> > TrackClientMap;
+typedef std::vector< sp<RecordClientDescriptor> > RecordClientVector;
+typedef std::map< audio_port_handle_t, sp<RecordClientDescriptor> > RecordClientMap;
+
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index b9895a9..2770e74 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -340,6 +340,18 @@
                                                      &config, mPatchHandle);
 }
 
+RecordClientVector AudioInputDescriptor::getClientsForSession(
+    audio_session_t session)
+{
+    RecordClientVector clients;
+    for (const auto &client : mClients) {
+        if (client.second->session() == session) {
+            clients.push_back(client.second);
+        }
+    }
+    return clients;
+}
+
 status_t AudioInputDescriptor::dump(int fd)
 {
     const size_t SIZE = 256;
@@ -361,6 +373,13 @@
 
     mSessions.dump(fd, 1);
 
+    size_t index = 0;
+    result = " AudioRecord clients:\n";
+    for (const auto& client: mClients) {
+        client.second->dump(result, 2, index++);
+    }
+    result.append(" \n");
+    write(fd, result.string(), result.size());
     return NO_ERROR;
 }
 
@@ -423,6 +442,19 @@
     return devices;
 }
 
+sp<AudioInputDescriptor> AudioInputCollection::getInputForClient(audio_port_handle_t portId)
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<AudioInputDescriptor> inputDesc = valueAt(i);
+        for (const auto& client : inputDesc->clients()) {
+            if (client.second->portId() == portId) {
+                return inputDesc;
+            }
+        }
+    }
+    return 0;
+}
+
 status_t AudioInputCollection::dump(int fd) const
 {
     const size_t SIZE = 256;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 3c69de5..3dfbe1b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -224,6 +224,13 @@
                  i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
         result.append(buffer);
     }
+
+    result.append(" AudioTrack clients:\n");
+    size_t index = 0;
+    for (const auto& client : mClients) {
+        client.second->dump(result, 2, index++);
+    }
+    result.append(" \n");
     write(fd, result.string(), result.size());
 
     return NO_ERROR;
@@ -731,6 +738,18 @@
     return devices;
 }
 
+sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_port_handle_t portId)
+{
+    for (size_t i = 0; i < size(); i++) {
+        sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
+        for (const auto& client : outputDesc->clients()) {
+            if (client.second->portId() == portId) {
+                return outputDesc;
+            }
+        }
+    }
+    return 0;
+}
 
 status_t SwAudioOutputCollection::dump(int fd) const
 {
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 1e64d2e..bdc748e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -17,60 +17,50 @@
 #define LOG_TAG "APM_ClientDescriptor"
 //#define LOG_NDEBUG 0
 
+#include <utils/Log.h>
 #include <utils/String8.h>
 #include "ClientDescriptor.h"
 
 namespace android {
 
-status_t ClientDescriptor::dump(int fd)
+status_t ClientDescriptor::dump(int fd, int spaces, int index)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
+    String8 out;
 
-    snprintf(buffer, SIZE, " Port ID: %d Session Id: %d UID: %d\n", mPortId, mSessionId, mUid);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Format: %08x Sampling rate: %d Channels: %08x\n",
+    status_t status = dump(out, spaces, index);
+    if (status == NO_ERROR) {
+        write(fd, out.string(), out.size());
+    }
+
+    return status;
+}
+
+status_t ClientDescriptor::dump(String8& out, int spaces, int index)
+{
+    out.appendFormat("%*sClient %d:\n", spaces, "", index+1);
+    out.appendFormat("%*s- Port ID: %d Session Id: %d UID: %d\n", spaces, "",
+             mPortId, mSessionId, mUid);
+    out.appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
              mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Preferred Device Id: %08x\n", mPreferredDeviceId);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " State: %s\n", mActive ? "Active" : "Inactive");
-    result.append(buffer);
+    out.appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
+    out.appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
+    return NO_ERROR;
+}
 
-    write(fd, result.string(), result.size());
+status_t TrackClientDescriptor::dump(String8& out, int spaces, int index)
+{
+    ClientDescriptor::dump(out, spaces, index);
+
+    out.appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
 
     return NO_ERROR;
 }
 
-status_t TrackClientDescriptor::dump(int fd)
+status_t RecordClientDescriptor::dump(String8& out, int spaces, int index)
 {
-    ClientDescriptor::dump(fd);
+    ClientDescriptor::dump(out, spaces, index);
 
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " Stream: %d flags: %08x\n", mStream, mFlags);
-    result.append(buffer);
-
-    write(fd, result.string(), result.size());
-
-    return NO_ERROR;
-}
-
-status_t RecordClientDescriptor::dump(int fd)
-{
-    ClientDescriptor::dump(fd);
-
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, " Source: %d flags: %08x\n", mSource, mFlags);
-    result.append(buffer);
-
-    write(fd, result.string(), result.size());
+    out.appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
 
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 856bcb3..f343bec 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -505,13 +505,7 @@
         // symmetric to the one in startInput()
         for (const auto& activeDesc : mInputs.getActiveInputs()) {
             if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
-                AudioSessionCollection activeSessions =
-                        activeDesc->getAudioSessions(true /*activeOnly*/);
-                for (size_t j = 0; j < activeSessions.size(); j++) {
-                    audio_session_t activeSession = activeSessions.keyAt(j);
-                    stopInput(activeDesc->mIoHandle, activeSession);
-                    releaseInput(activeDesc->mIoHandle, activeSession);
-                }
+                closeSessions(activeDesc, true  /*activeOnly*/);
             }
         }
     }
@@ -779,6 +773,11 @@
                                               audio_port_handle_t *portId)
 {
     audio_attributes_t attributes;
+    DeviceVector outputDevices;
+    routing_strategy strategy;
+    audio_devices_t device;
+    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+
     if (attr != NULL) {
         if (!isValidAttributes(attr)) {
             ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
@@ -820,7 +819,7 @@
             *stream = streamTypefromAttributesInt(&attributes);
             *output = desc->mIoHandle;
             ALOGV("getOutputForAttr() returns output %d", *output);
-            return NO_ERROR;
+            goto exit;
         }
 
         // Virtual sources must always be dynamicaly or explicitly routed
@@ -844,8 +843,8 @@
     // explicit route.  Is that the intended and necessary behavior?
     mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
 
-    routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
-    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    strategy = (routing_strategy) getStrategyForAttr(&attributes);
+    device = getDeviceForStrategy(strategy, false /*fromCache*/);
 
     if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
         *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
@@ -876,11 +875,22 @@
         return INVALID_OPERATION;
     }
 
-    DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
+    outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
     *selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
             : AUDIO_PORT_HANDLE_NONE;
 
-    ALOGV("  getOutputForAttr() returns output %d selectedDeviceId %d", *output, *selectedDeviceId);
+exit:
+    audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+        .format = config->format,
+        .channel_mask = config->channel_mask };
+    sp<TrackClientDescriptor> clientDesc =
+        new TrackClientDescriptor(*portId, uid, session,
+                                  attributes, clientConfig, requestedDeviceId, *stream, *flags);
+    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
+    outputDesc->clients().emplace(*portId, clientDesc);
+
+    ALOGV("  getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
+          *output, *selectedDeviceId, *portId);
 
     return NO_ERROR;
 }
@@ -1122,19 +1132,21 @@
     return outputs[0];
 }
 
-status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
-                                             audio_stream_type_t stream,
-                                             audio_session_t session)
+status_t AudioPolicyManager::startOutput(audio_port_handle_t portId)
 {
-    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);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+    if (outputDesc == 0) {
+        ALOGW("startOutput() no output for client %d", portId);
         return BAD_VALUE;
     }
+    sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+    audio_stream_type_t stream = client->stream();
+    audio_session_t session = client->session();
 
-    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+    ALOGV("startOutput() output %d, stream %d, session %d",
+          outputDesc->mIoHandle, stream, session);
 
     status_t status = outputDesc->start();
     if (status != NO_ERROR) {
@@ -1158,7 +1170,7 @@
     } else if (mOutputRoutes.getAndClearRouteChanged(session)) {
         newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
         if (newDevice != outputDesc->device()) {
-            checkStrategyRoute(getStrategy(stream), output);
+            checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle);
         }
     } else {
         newDevice = AUDIO_DEVICE_NONE;
@@ -1326,19 +1338,20 @@
     return NO_ERROR;
 }
 
-
-status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
-                                            audio_stream_type_t stream,
-                                            audio_session_t session)
+status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
 {
-    ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        ALOGW("stopOutput() unknown output %d", output);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+    if (outputDesc == 0) {
+        ALOGW("stopOutput() no output for client %d", portId);
         return BAD_VALUE;
     }
+    sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+    audio_stream_type_t stream = client->stream();
+    audio_session_t session = client->session();
 
-    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+    ALOGV("stopOutput() output %d, stream %d, session %d", outputDesc->mIoHandle, stream, session);
 
     if (outputDesc->mRefCount[stream] == 1) {
         // Automatically disable the remote submix input when output is stopped on a
@@ -1435,32 +1448,35 @@
     }
 }
 
-void AudioPolicyManager::releaseOutput(audio_io_handle_t output,
-                                       audio_stream_type_t stream __unused,
-                                       audio_session_t session __unused)
+void AudioPolicyManager::releaseOutput(audio_port_handle_t portId)
 {
-    ALOGV("releaseOutput() %d", output);
-    ssize_t index = mOutputs.indexOfKey(output);
-    if (index < 0) {
-        ALOGW("releaseOutput() releasing unknown output %d", output);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+    if (outputDesc == 0) {
+        ALOGW("releaseOutput() no output for client %d", portId);
         return;
     }
+    sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+    audio_session_t session = client->session();
+
+    ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
 
     // Routing
     mOutputRoutes.removeRoute(session);
 
-    sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(index);
-    if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
-        if (desc->mDirectOpenCount <= 0) {
+    if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+        if (outputDesc->mDirectOpenCount <= 0) {
             ALOGW("releaseOutput() invalid open count %d for output %d",
-                                                              desc->mDirectOpenCount, output);
+                  outputDesc->mDirectOpenCount, outputDesc->mIoHandle);
             return;
         }
-        if (--desc->mDirectOpenCount == 0) {
-            closeOutput(output);
+        if (--outputDesc->mDirectOpenCount == 0) {
+            closeOutput(outputDesc->mIoHandle);
             mpClientInterface->onAudioPortListUpdate();
         }
     }
+    outputDesc->clients().erase(portId);
 }
 
 
@@ -1485,6 +1501,9 @@
     audio_source_t inputSource = attr->source;
     AudioMix *policyMix = NULL;
     DeviceVector inputDevices;
+    sp<AudioInputDescriptor> inputDesc;
+    sp<RecordClientDescriptor> clientDesc;
+    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
 
     if (inputSource == AUDIO_SOURCE_DEFAULT) {
         inputSource = AUDIO_SOURCE_MIC;
@@ -1540,7 +1559,7 @@
                 : AUDIO_PORT_HANDLE_NONE;
         ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
 
-        return NO_ERROR;
+        goto exit;
     }
 
     *input = AUDIO_IO_HANDLE_NONE;
@@ -1606,8 +1625,14 @@
     *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
             : AUDIO_PORT_HANDLE_NONE;
 
-    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d",
-            *input, *inputType, *selectedDeviceId);
+exit:
+    clientDesc = new RecordClientDescriptor(*portId, uid, session,
+                                  *attr, *config, requestedDeviceId, inputSource, flags);
+    inputDesc = mInputs.valueFor(*input);
+    inputDesc->clients().emplace(*portId, clientDesc);
+
+    ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
+            *input, *inputType, *selectedDeviceId, *portId);
 
     return NO_ERROR;
 
@@ -1810,24 +1835,26 @@
 }
 
 
-status_t AudioPolicyManager::startInput(audio_io_handle_t input,
-                                        audio_session_t session,
+status_t AudioPolicyManager::startInput(audio_port_handle_t portId,
                                         bool silenced,
                                         concurrency_type__mask_t *concurrency)
 {
+    *concurrency = API_INPUT_CONCURRENCY_NONE;
+
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+    if (inputDesc == 0) {
+        ALOGW("startInput() no input for client %d", portId);
+        return BAD_VALUE;
+    }
+    sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+    audio_session_t session = client->session();
+    audio_io_handle_t input = inputDesc->mIoHandle;
 
     ALOGV("AudioPolicyManager::startInput(input:%d, session:%d, silenced:%d, concurrency:%d)",
             input, session, silenced, *concurrency);
 
-    *concurrency = API_INPUT_CONCURRENCY_NONE;
-
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        ALOGW("startInput() unknown input %d", input);
-        return BAD_VALUE;
-    }
-    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-
     sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
     if (audioSession == 0) {
         ALOGW("startInput() unknown session %d on input %d", session, input);
@@ -1858,11 +1885,8 @@
                         true /*activeOnly*/);
                 sp<AudioSession> activeSession = activeSessions.valueAt(0);
                 if (activeSession->isSilenced()) {
-                    audio_io_handle_t activeInput = activeDesc->mIoHandle;
-                    audio_session_t activeSessionId = activeSession->session();
-                    stopInput(activeInput, activeSessionId);
-                    releaseInput(activeInput, activeSessionId);
-                    ALOGV("startInput(%d) stopping silenced input %d", input, activeInput);
+                    closeSession(activeDesc, activeSession);
+                    ALOGV("startInput() session %d stopping silenced session %d", session, activeSession->session());
                     activeInputs = mInputs.getActiveInputs();
                 }
             }
@@ -1916,14 +1940,12 @@
             if (activeSource == AUDIO_SOURCE_HOTWORD) {
                 AudioSessionCollection activeSessions =
                         activeDesc->getAudioSessions(true /*activeOnly*/);
-                audio_session_t activeSession = activeSessions.keyAt(0);
-                audio_io_handle_t activeHandle = activeDesc->mIoHandle;
+                sp<AudioSession> activeSession = activeSessions[0];
                 SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
                 *concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
-                sessions.add(activeSession);
+                sessions.add(activeSession->session());
                 inputDesc->setPreemptedSessions(sessions);
-                stopInput(activeHandle, activeSession);
-                releaseInput(activeHandle, activeSession);
+                closeSession(inputDesc, activeSession);
                 ALOGV("startInput(%d) for HOTWORD preempting HOTWORD input %d",
                       input, activeDesc->mIoHandle);
             }
@@ -1991,22 +2013,22 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
-                                       audio_session_t session)
+status_t AudioPolicyManager::stopInput(audio_port_handle_t portId)
 {
-    ALOGV("stopInput() input %d", input);
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        ALOGW("stopInput() unknown input %d", input);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+    if (inputDesc == 0) {
+        ALOGW("stopInput() no input for client %d", portId);
         return BAD_VALUE;
     }
-    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+    sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+    audio_session_t session = client->session();
+    audio_io_handle_t input = inputDesc->mIoHandle;
+
+    ALOGV("stopInput() input %d", input);
 
     sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-    if (index < 0) {
-        ALOGW("stopInput() unknown session %d on input %d", session, input);
-        return BAD_VALUE;
-    }
 
     if (audioSession->activeCount() == 0) {
         ALOGW("stopInput() input %d already stopped", input);
@@ -2062,22 +2084,24 @@
     return NO_ERROR;
 }
 
-void AudioPolicyManager::releaseInput(audio_io_handle_t input,
-                                      audio_session_t session)
+void AudioPolicyManager::releaseInput(audio_port_handle_t portId)
 {
-    ALOGV("releaseInput() %d", input);
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        ALOGW("releaseInput() releasing unknown input %d", input);
+    ALOGV("%s portId %d", __FUNCTION__, portId);
+
+    sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+    if (inputDesc == 0) {
+        ALOGW("releaseInput() no input for client %d", portId);
         return;
     }
+    sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+    audio_session_t session = client->session();
+    audio_io_handle_t input = inputDesc->mIoHandle;
+
+    ALOGV("releaseInput() %d", input);
 
     // Routing
     mInputRoutes.removeRoute(session);
 
-    sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-    ALOG_ASSERT(inputDesc != 0);
-
     sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
     if (audioSession == 0) {
         ALOGW("releaseInput() unknown session %d on input %d", session, input);
@@ -2100,10 +2124,31 @@
     }
 
     closeInput(input);
+    inputDesc->clients().erase(portId);
     mpClientInterface->onAudioPortListUpdate();
     ALOGV("releaseInput() exit");
 }
 
+void AudioPolicyManager::closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly)
+{
+    AudioSessionCollection sessions = input->getAudioSessions(activeOnly /*activeOnly*/);
+    for (size_t i = 0; i < sessions.size(); i++) {
+        closeSession(input, sessions[i]);
+    }
+}
+
+void AudioPolicyManager::closeSession(const sp<AudioInputDescriptor>& input,
+                                      const sp<AudioSession>& session)
+{
+    RecordClientVector clients = input->getClientsForSession(session->session());
+
+    for (const auto& client : clients) {
+        stopInput(client->portId());
+        releaseInput(client->portId());
+    }
+}
+
+
 void AudioPolicyManager::closeAllInputs() {
     bool patchRemoved = false;
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index e412645..a92223f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -120,15 +120,9 @@
                                           audio_output_flags_t *flags,
                                           audio_port_handle_t *selectedDeviceId,
                                           audio_port_handle_t *portId);
-        virtual status_t startOutput(audio_io_handle_t output,
-                                     audio_stream_type_t stream,
-                                     audio_session_t session);
-        virtual status_t stopOutput(audio_io_handle_t output,
-                                    audio_stream_type_t stream,
-                                    audio_session_t session);
-        virtual void releaseOutput(audio_io_handle_t output,
-                                   audio_stream_type_t stream,
-                                   audio_session_t session);
+        virtual status_t startOutput(audio_port_handle_t portId);
+        virtual status_t stopOutput(audio_port_handle_t portId);
+        virtual void releaseOutput(audio_port_handle_t portId);
         virtual status_t getInputForAttr(const audio_attributes_t *attr,
                                          audio_io_handle_t *input,
                                          audio_session_t session,
@@ -140,16 +134,13 @@
                                          audio_port_handle_t *portId);
 
         // indicates to the audio policy manager that the input starts being used.
-        virtual status_t startInput(audio_io_handle_t input,
-                                    audio_session_t session,
+        virtual status_t startInput(audio_port_handle_t portId,
                                     bool silenced,
                                     concurrency_type__mask_t *concurrency);
 
         // indicates to the audio policy manager that the input stops being used.
-        virtual status_t stopInput(audio_io_handle_t input,
-                                   audio_session_t session);
-        virtual void releaseInput(audio_io_handle_t input,
-                                  audio_session_t session);
+        virtual status_t stopInput(audio_port_handle_t portId);
+        virtual void releaseInput(audio_port_handle_t portId);
         virtual void closeAllInputs();
         virtual void initStreamVolume(audio_stream_type_t stream,
                                                     int indexMin,
@@ -551,6 +542,10 @@
         static bool streamsMatchForvolume(audio_stream_type_t stream1,
                                           audio_stream_type_t stream2);
 
+        void closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly);
+        void closeSession(const sp<AudioInputDescriptor>& input,
+                          const sp<AudioSession>& session);
+
         const uid_t mUidCached;                         // AID_AUDIOSERVER
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 859072b..fdfd573 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -200,7 +200,7 @@
         !modifyPhoneStateAllowed(pid, uid)) {
         // If the app tries to play music through the telephony device and doesn't have permission
         // the fallback to the default output device.
-        mAudioPolicyManager->releaseOutput(*output, *stream, session);
+        mAudioPolicyManager->releaseOutput(*portId);
         flags = originalFlags;
         *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
         *portId = AUDIO_PORT_HANDLE_NONE;
@@ -245,8 +245,7 @@
     }
     Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
-    status_t status = mAudioPolicyManager->startOutput(
-        client->io, client->stream, client->session);
+    status_t status = mAudioPolicyManager->startOutput(portId);
     if (status == NO_ERROR) {
         client->active = true;
     }
@@ -298,8 +297,7 @@
     }
     Mutex::Autolock _l(mLock);
     AutoCallerClear acc;
-    status_t status = mAudioPolicyManager->stopOutput(
-        client->io, client->stream, client->session);
+    status_t status = mAudioPolicyManager->stopOutput(portId);
     if (status == NO_ERROR) {
         client->active = false;
     }
@@ -328,8 +326,7 @@
     mAudioRecordClients.removeItem(portId);
 
     // called from internal thread: no need to clear caller identity
-    mAudioPolicyManager->releaseOutput(
-        client->io, client->stream, client->session);
+    mAudioPolicyManager->releaseOutput(portId);
 }
 
 status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
@@ -433,7 +430,7 @@
         if (status != NO_ERROR) {
             if (status == PERMISSION_DENIED) {
                 AutoCallerClear acc;
-                mAudioPolicyManager->releaseInput(*input, session);
+                mAudioPolicyManager->releaseInput(*portId);
             }
             return status;
         }
@@ -527,8 +524,7 @@
     status_t status;
     {
         AutoCallerClear acc;
-        status = mAudioPolicyManager->startInput(
-                    client->io, client->session, *silenced, &concurrency);
+        status = mAudioPolicyManager->startInput(portId, *silenced, &concurrency);
 
     }
 
@@ -641,7 +637,7 @@
     // finish the recording app op
     finishRecording(client->opPackageName, client->uid);
     AutoCallerClear acc;
-    return mAudioPolicyManager->stopInput(client->io, client->session);
+    return mAudioPolicyManager->stopInput(portId);
 }
 
 void AudioPolicyService::releaseInput(audio_port_handle_t portId)
@@ -674,7 +670,7 @@
     {
         Mutex::Autolock _l(mLock);
         AutoCallerClear acc;
-        mAudioPolicyManager->releaseInput(client->io, client->session);
+        mAudioPolicyManager->releaseInput(portId);
     }
 }