audio policy: remove audio patch when closing input or output

Make sure that an audio patch having an output as source or input as sink
is removed when this input or output is closed.

Bug: 17303725.

Change-Id: I234d54a25ce0b579eeeafdcfda3a0594f048768c
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 14fdec5..cd8d0de 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -1454,19 +1454,31 @@
         return;
     }
 
-    mpClientInterface->closeInput(input);
-    mInputs.removeItem(input);
-    nextAudioPortGeneration();
+    closeInput(input);
     mpClientInterface->onAudioPortListUpdate();
     ALOGV("releaseInput() exit");
 }
 
 void AudioPolicyManager::closeAllInputs() {
+    bool patchRemoved = false;
+
     for(size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(input_index);
+        ssize_t patch_index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
+        if (patch_index >= 0) {
+            sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patch_index);
+            status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+            mAudioPatches.removeItemsAt(patch_index);
+            patchRemoved = true;
+        }
         mpClientInterface->closeInput(mInputs.keyAt(input_index));
     }
     mInputs.clear();
     nextAudioPortGeneration();
+
+    if (patchRemoved) {
+        mpClientInterface->onAudioPatchListUpdate();
+    }
 }
 
 void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream,
@@ -3497,6 +3509,16 @@
         }
     }
 
+    nextAudioPortGeneration();
+
+    ssize_t index = mAudioPatches.indexOfKey(outputDesc->mPatchHandle);
+    if (index >= 0) {
+        sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
+        status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+        mAudioPatches.removeItemsAt(index);
+        mpClientInterface->onAudioPatchListUpdate();
+    }
+
     AudioParameter param;
     param.add(String8("closing"), String8("true"));
     mpClientInterface->setParameters(output, param.toString());
@@ -3504,7 +3526,30 @@
     mpClientInterface->closeOutput(output);
     mOutputs.removeItem(output);
     mPreviousOutputs = mOutputs;
+}
+
+void AudioPolicyManager::closeInput(audio_io_handle_t input)
+{
+    ALOGV("closeInput(%d)", input);
+
+    sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
+    if (inputDesc == NULL) {
+        ALOGW("closeInput() unknown input %d", input);
+        return;
+    }
+
     nextAudioPortGeneration();
+
+    ssize_t index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
+    if (index >= 0) {
+        sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
+        status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+        mAudioPatches.removeItemsAt(index);
+        mpClientInterface->onAudioPatchListUpdate();
+    }
+
+    mpClientInterface->closeInput(input);
+    mInputs.removeItem(input);
 }
 
 SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(audio_devices_t device,