audio policy: add support for custom mixes

Add support for custom mixes in AudioPolicyManager.

Two methods are added to register or unregister a list of custom mixes
with their attributes and format.

getOutputForAttr() and getInputForAttr() first look for a match in
registered mixes before defaulting to normal output/input selection

Remote submix device connection disconnection now takes address into
account to identify the correspnoding custom mix.

Bug: 16009464.

Change-Id: I3f1c2a485a0fb71b1f984ed0adc9b68aa971e408
diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp
new file mode 100644
index 0000000..d2d0971
--- /dev/null
+++ b/media/libmedia/AudioPolicy.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 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 "AudioPolicy"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include <media/AudioPolicy.h>
+
+namespace android {
+
+//
+//  AttributeMatchCriterion implementation
+//
+AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage,
+                                                 audio_source_t source,
+                                                 uint32_t rule)
+: mRule(rule)
+{
+    if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
+            mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
+        mAttr.mUsage = usage;
+    } else {
+        mAttr.mSource = source;
+    }
+}
+
+status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel)
+{
+    mRule = parcel->readInt32();
+    if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
+            mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
+        mAttr.mUsage = (audio_usage_t)parcel->readInt32();
+    } else {
+        mAttr.mSource = (audio_source_t)parcel->readInt32();
+    }
+    return NO_ERROR;
+}
+
+status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const
+{
+    parcel->writeInt32(mRule);
+    parcel->writeInt32(mAttr.mUsage);
+    return NO_ERROR;
+}
+
+//
+//  AudioMix implementation
+//
+
+status_t AudioMix::readFromParcel(Parcel *parcel)
+{
+    mMixType = parcel->readInt32();
+    mFormat.sample_rate = (uint32_t)parcel->readInt32();
+    mFormat.channel_mask = (audio_channel_mask_t)parcel->readInt32();
+    mFormat.format = (audio_format_t)parcel->readInt32();
+    mRouteFlags = parcel->readInt32();
+    mRegistrationId = parcel->readString8();
+    size_t size = (size_t)parcel->readInt32();
+    if (size > MAX_CRITERIA_PER_MIX) {
+        size = MAX_CRITERIA_PER_MIX;
+    }
+    for (size_t i = 0; i < size; i++) {
+        AttributeMatchCriterion criterion;
+        if (criterion.readFromParcel(parcel) == NO_ERROR) {
+            mCriteria.add(criterion);
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioMix::writeToParcel(Parcel *parcel) const
+{
+    parcel->writeInt32(mMixType);
+    parcel->writeInt32(mFormat.sample_rate);
+    parcel->writeInt32(mFormat.channel_mask);
+    parcel->writeInt32(mFormat.format);
+    parcel->writeInt32(mRouteFlags);
+    parcel->writeString8(mRegistrationId);
+    size_t size = mCriteria.size();
+    if (size > MAX_CRITERIA_PER_MIX) {
+        size = MAX_CRITERIA_PER_MIX;
+    }
+    size_t sizePosition = parcel->dataPosition();
+    parcel->writeInt32(size);
+    size_t finalSize = size;
+    for (size_t i = 0; i < size; i++) {
+        size_t position = parcel->dataPosition();
+        if (mCriteria[i].writeToParcel(parcel) != NO_ERROR) {
+            parcel->setDataPosition(position);
+            finalSize--;
+        }
+    }
+    if (size != finalSize) {
+        size_t position = parcel->dataPosition();
+        parcel->setDataPosition(sizePosition);
+        parcel->writeInt32(finalSize);
+        parcel->setDataPosition(position);
+    }
+    return NO_ERROR;
+}
+
+}; // namespace android