Merge "C2SoftHevcEnc: Add support for dynamic bitrate change" into qt-dev
diff --git a/media/bufferpool/1.0/BufferPoolClient.cpp b/media/bufferpool/1.0/BufferPoolClient.cpp
index 41520ca..d712398 100644
--- a/media/bufferpool/1.0/BufferPoolClient.cpp
+++ b/media/bufferpool/1.0/BufferPoolClient.cpp
@@ -528,6 +528,10 @@
                         (void) outStatus;
                         (void) outBuffer;
                     });
+            if(!transResult.isOk()) {
+                ALOGD("sync from client %lld failed: bufferpool process died.",
+                      (long long)mConnectionId);
+            }
         }
         mRemoteSyncLock.unlock();
     }
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 5260909..94cf006 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -261,13 +261,19 @@
         mBufferPool.mInvalidation.onHandleAck(&observers, &invalidationId);
     }
     // Do not hold lock for send invalidations
+    size_t deadClients = 0;
     for (auto it = observers.begin(); it != observers.end(); ++it) {
         const sp<IObserver> observer = it->second;
         if (observer) {
             Return<void> transResult = observer->onMessage(it->first, invalidationId);
-            (void) transResult;
+            if (!transResult.isOk()) {
+                ++deadClients;
+            }
         }
     }
+    if (deadClients > 0) {
+        ALOGD("During invalidation found %zu dead clients", deadClients);
+    }
 }
 
 bool Accessor::Impl::isValid() {
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index f907de5..342fef6 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -582,6 +582,10 @@
                         (void) outStatus;
                         (void) outBuffer;
                     });
+            if (!transResult.isOk()) {
+                ALOGD("sync from client %lld failed: bufferpool process died.",
+                      (long long)mConnectionId);
+            }
         }
         mRemoteSyncLock.unlock();
     }
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.cpp b/media/codec2/components/flac/C2SoftFlacEnc.cpp
index cf34dff..408db7e 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.cpp
+++ b/media/codec2/components/flac/C2SoftFlacEnc.cpp
@@ -74,6 +74,14 @@
                 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
                 .build());
         addParameter(
+                DefineParam(mComplexity, C2_PARAMKEY_COMPLEXITY)
+                .withDefault(new C2StreamComplexityTuning::output(0u,
+                    FLAC_COMPRESSION_LEVEL_DEFAULT))
+                .withFields({C2F(mComplexity, value).inRange(
+                    FLAC_COMPRESSION_LEVEL_MIN, FLAC_COMPRESSION_LEVEL_MAX)})
+                .withSetter(Setter<decltype(*mComplexity)>::NonStrictValueWithNoDeps)
+                .build());
+        addParameter(
                 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
                 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 4608))
                 .build());
@@ -93,12 +101,14 @@
     uint32_t getSampleRate() const { return mSampleRate->value; }
     uint32_t getChannelCount() const { return mChannelCount->value; }
     uint32_t getBitrate() const { return mBitrate->value; }
+    uint32_t getComplexity() const { return mComplexity->value; }
     int32_t getPcmEncodingInfo() const { return mPcmEncodingInfo->value; }
 
 private:
     std::shared_ptr<C2StreamSampleRateInfo::input> mSampleRate;
     std::shared_ptr<C2StreamChannelCountInfo::input> mChannelCount;
     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
+    std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
     std::shared_ptr<C2StreamPcmEncodingInfo::input> mPcmEncodingInfo;
 };
@@ -127,7 +137,6 @@
 
     mSignalledError = false;
     mSignalledOutputEos = false;
-    mCompressionLevel = FLAC_COMPRESSION_LEVEL_DEFAULT;
     mIsFirstFrame = true;
     mAnchorTimeStamp = 0ull;
     mProcessedSamples = 0u;
@@ -153,7 +162,6 @@
 }
 
 void C2SoftFlacEnc::onReset() {
-    mCompressionLevel = FLAC_COMPRESSION_LEVEL_DEFAULT;
     (void) onStop();
 }
 
@@ -369,7 +377,8 @@
     ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mIntf->getChannelCount());
     ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mIntf->getSampleRate());
     ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, bitsPerSample);
-    ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder, mCompressionLevel);
+    ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
+                    mIntf->getComplexity());
     ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
     if (!ok) {
         ALOGE("unknown error when configuring encoder");
diff --git a/media/codec2/components/flac/C2SoftFlacEnc.h b/media/codec2/components/flac/C2SoftFlacEnc.h
index cdf305e..b3f01d5 100644
--- a/media/codec2/components/flac/C2SoftFlacEnc.h
+++ b/media/codec2/components/flac/C2SoftFlacEnc.h
@@ -69,7 +69,6 @@
     std::shared_ptr<C2LinearBlock> mOutputBlock;
     bool mSignalledError;
     bool mSignalledOutputEos;
-    uint32_t mCompressionLevel;
     uint32_t mBlockSize;
     bool mIsFirstFrame;
     uint64_t mAnchorTimeStamp;
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index fb2da7c..b129b1b 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -390,27 +390,23 @@
 }
 
 C2SoftHevcEnc::~C2SoftHevcEnc() {
-    releaseEncoder();
+    onRelease();
 }
 
 c2_status_t C2SoftHevcEnc::onInit() {
-    return initEncoder();
+    return C2_OK;
 }
 
 c2_status_t C2SoftHevcEnc::onStop() {
-    if (!mStarted) {
-        return C2_OK;
-    }
-    return releaseEncoder();
+    return C2_OK;
 }
 
 void C2SoftHevcEnc::onReset() {
-    onStop();
-    initEncoder();
+    releaseEncoder();
 }
 
 void C2SoftHevcEnc::onRelease() {
-    onStop();
+    releaseEncoder();
 }
 
 c2_status_t C2SoftHevcEnc::onFlush_sm() {
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index e01fc90..f54690d 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1772,7 +1772,7 @@
                 int64_t codecDelay = pre_skip * 1000000000ll / kOpusSampleRate;
 
                 AMediaFormat_setBuffer(mLastTrack->meta,
-                            AMEDIAFORMAT_KEY_CSD_0, opusInfo, sizeof(opusInfo));
+                            AMEDIAFORMAT_KEY_CSD_0, opusInfo, opusInfoSize);
                 AMediaFormat_setBuffer(mLastTrack->meta,
                         AMEDIAFORMAT_KEY_CSD_1, &codecDelay, sizeof(codecDelay));
                 AMediaFormat_setBuffer(mLastTrack->meta,
diff --git a/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp b/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
index 1f53978..ae5c020 100644
--- a/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
+++ b/media/libeffects/dynamicsproc/dsp/DPFrequency.cpp
@@ -62,11 +62,6 @@
     cBInput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
     cBOutput.resize(mBlockSize * CIRCULAR_BUFFER_UPSAMPLE);
 
-    //fill input with half block size...
-    for (unsigned int k = 0; k < mBlockSize/2; k++) {
-        cBInput.write(0);
-    }
-
     //temp vectors
     input.resize(mBlockSize);
     output.resize(mBlockSize);
@@ -170,6 +165,11 @@
 
     fill_window(mVWindow, RDSP_WINDOW_HANNING_FLAT_TOP, mBlockSize, mOverlapSize);
 
+    //split window into analysis and synthesis. Both are the sqrt() of original
+    //window
+    Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
+    eWindow = eWindow.array().sqrt();
+
     //compute window rms for energy compensation
     mWindowRms = 0;
     for (size_t i = 0; i < mVWindow.size(); i++) {
@@ -666,6 +666,11 @@
     //##ifft directly to output.
     Eigen::Map<Eigen::VectorXf> eOutput(&cb.output[0], cb.output.size());
     mFftServer.inv(eOutput, cb.complexTemp);
+
+    //apply rest of window for resynthesis
+    Eigen::Map<Eigen::VectorXf> eWindow(&mVWindow[0], mVWindow.size());
+    eOutput = eOutput.cwiseProduct(eWindow);
+
     return mBlockSize;
 }
 
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index be2404d..509f7a9 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -112,7 +112,7 @@
             <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
             <Limit name="bitrate" range="500-512000" />
             <Limit name="complexity" range="0-10"  default="5" />
-            <Feature name="bitrate-modes" value="CQ" />
+            <Feature name="bitrate-modes" value="CBR" />
         </MediaCodec>
     </Encoders>
 </Included>
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 37f3f61..67d3f1a 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -237,7 +237,7 @@
             <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
             <Limit name="bitrate" range="500-512000" />
             <Limit name="complexity" range="0-10"  default="5" />
-            <Feature name="bitrate-modes" value="CQ" />
+            <Feature name="bitrate-modes" value="CBR" />
         </MediaCodec>
         <MediaCodec name="c2.android.h263.encoder" type="video/3gpp">
             <Alias name="OMX.google.h263.encoder" />
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index acb9ccf..513e41f 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -208,7 +208,7 @@
     headerLen += AOPUS_LENGTH_SIZE;
 
     int headerSize = WriteOpusHeader(header, inputSampleRate, output + headerLen,
-        outputSize);
+        outputSize - headerLen);
     if (headerSize < 0) {
         ALOGD("%s: WriteOpusHeader failed", __func__);
         return -1;
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index f7f4c36..9d7c57d 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -68,16 +68,26 @@
   public class MediaCodec {
     ctor public MediaCodec();
     method public java.util.List<media.codecs.Alias> getAlias_optional();
+    method public java.util.List<media.codecs.Quirk> getAttribute_optional();
+    method public String getDomain();
+    method public String getEnabled();
     method public java.util.List<media.codecs.Feature> getFeature_optional();
     method public java.util.List<media.codecs.Limit> getLimit_optional();
     method public String getName();
     method public java.util.List<media.codecs.Quirk> getQuirk_optional();
+    method public String getRank();
     method public String getType();
     method public java.util.List<media.codecs.Type> getType_optional();
     method public String getUpdate();
+    method public String getVariant();
+    method public java.util.List<media.codecs.Variant> getVariant_optional();
+    method public void setDomain(String);
+    method public void setEnabled(String);
     method public void setName(String);
+    method public void setRank(String);
     method public void setType(String);
     method public void setUpdate(String);
+    method public void setVariant(String);
   }
 
   public class MediaCodecs {
@@ -91,14 +101,18 @@
   public class Quirk {
     ctor public Quirk();
     method public String getName();
+    method public String getValue();
     method public void setName(String);
+    method public void setValue(String);
   }
 
   public class Setting {
     ctor public Setting();
+    method public String getEnabled();
     method public String getName();
     method public String getUpdate();
     method public String getValue();
+    method public void setEnabled(String);
     method public void setName(String);
     method public void setUpdate(String);
     method public void setValue(String);
@@ -106,7 +120,9 @@
 
   public class Settings {
     ctor public Settings();
-    method public java.util.List<media.codecs.Setting> getSetting();
+    method public java.util.List<media.codecs.Setting> getDomain_optional();
+    method public java.util.List<media.codecs.Setting> getSetting_optional();
+    method public java.util.List<media.codecs.Setting> getVariant_optional();
   }
 
   public class Type {
@@ -120,6 +136,12 @@
     method public void setUpdate(String);
   }
 
+  public class Variant {
+    ctor public Variant();
+    method public String getName();
+    method public void setName(String);
+  }
+
   public class XmlParser {
     ctor public XmlParser();
     method public static media.codecs.Included readIncluded(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
index 77193a2..63ec5d0 100644
--- a/media/libstagefright/xmlparser/media_codecs.xsd
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -49,24 +49,33 @@
         </xs:sequence>
     </xs:complexType>
     <xs:complexType name="Settings">
-        <xs:sequence>
-            <xs:element name="Setting" type="Setting" maxOccurs="unbounded"/>
-        </xs:sequence>
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="Setting" type="Setting"/>
+            <xs:element name="Variant" type="Setting"/>
+            <xs:element name="Domain" type="Setting"/>
+        </xs:choice>
     </xs:complexType>
     <xs:complexType name="MediaCodec">
         <xs:choice minOccurs="0" maxOccurs="unbounded">
             <xs:element name="Quirk" type="Quirk" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Attribute" type="Quirk" minOccurs="0" maxOccurs="unbounded"/>
             <xs:element name="Type" type="Type" minOccurs="0" maxOccurs="unbounded"/>
             <xs:element name="Alias" type="Alias" minOccurs="0" maxOccurs="unbounded"/>
             <xs:element name="Limit" type="Limit" minOccurs="0" maxOccurs="unbounded"/>
             <xs:element name="Feature" type="Feature" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="Variant" type="Variant" minOccurs="0" maxOccurs="unbounded"/>
         </xs:choice>
         <xs:attribute name="name" type="xs:string"/>
         <xs:attribute name="type" type="xs:string"/>
         <xs:attribute name="update" type="xs:string"/>
+        <xs:attribute name="rank" type="xs:string"/>
+        <xs:attribute name="domain" type="xs:string"/>
+        <xs:attribute name="variant" type="xs:string"/>
+        <xs:attribute name="enabled" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="Quirk">
         <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="value" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="Type">
         <xs:sequence>
@@ -97,9 +106,13 @@
         <xs:attribute name="required" type="xs:string"/>
         <xs:attribute name="value" type="xs:string"/>
     </xs:complexType>
+    <xs:complexType name="Variant">
+        <xs:attribute name="name" type="xs:string"/>
+    </xs:complexType>
     <xs:complexType name="Setting">
         <xs:attribute name="name" type="xs:string"/>
         <xs:attribute name="value" type="xs:string"/>
+        <xs:attribute name="enabled" type="xs:string"/>
         <xs:attribute name="update" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="Include">
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 7008cee..a093893 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -31,6 +31,7 @@
 private:
     OpPlayAudioMonitor(uid_t uid, audio_usage_t usage, int id);
     void onFirstRef() override;
+    static void getPackagesForUid(uid_t uid, Vector<String16>& packages);
 
     AppOpsManager mAppOpsManager;
 
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b0817ed..78db80c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -389,9 +389,16 @@
 AudioFlinger::PlaybackThread::OpPlayAudioMonitor::createIfNeeded(
             uid_t uid, const audio_attributes_t& attr, int id, audio_stream_type_t streamType)
 {
-    if (isAudioServerOrRootUid(uid)) {
-        ALOGD("OpPlayAudio: not muting track:%d usage:%d root or audioserver", id, attr.usage);
-        return nullptr;
+    if (isServiceUid(uid)) {
+        Vector <String16> packages;
+        getPackagesForUid(uid, packages);
+        if (packages.isEmpty()) {
+            ALOGD("OpPlayAudio: not muting track:%d usage:%d for service UID %d",
+                  id,
+                  attr.usage,
+                  uid);
+            return nullptr;
+        }
     }
     // stream type has been filtered by audio policy to indicate whether it can be muted
     if (streamType == AUDIO_STREAM_ENFORCED_AUDIBLE) {
@@ -423,8 +430,7 @@
 
 void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::onFirstRef()
 {
-    PermissionController permissionController;
-    permissionController.getPackagesForUid(mUid, mPackages);
+    getPackagesForUid(mUid, mPackages);
     checkPlayAudioForUsage();
     if (!mPackages.isEmpty()) {
         mOpCallback = new PlayAudioOpCallback(this);
@@ -475,6 +481,14 @@
     }
 }
 
+// static
+void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::getPackagesForUid(
+    uid_t uid, Vector<String16>& packages)
+{
+    PermissionController permissionController;
+    permissionController.getPackagesForUid(uid, packages);
+}
+
 // ----------------------------------------------------------------------------
 #undef LOG_TAG
 #define LOG_TAG "AF::Track"
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 12b5e7d..094f506 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -19,7 +19,7 @@
 #include "DeviceDescriptor.h"
 #include <utils/RefBase.h>
 #include <media/AudioPolicy.h>
-#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
 #include <system/audio.h>
 #include <utils/String8.h>
 
@@ -48,14 +48,15 @@
 };
 
 
-class AudioPolicyMixCollection : public DefaultKeyedVector<String8, sp<AudioPolicyMix> >
+class AudioPolicyMixCollection : public Vector<sp<AudioPolicyMix>>
 {
 public:
-    status_t getAudioPolicyMix(const String8& address, sp<AudioPolicyMix> &policyMix) const;
+    status_t getAudioPolicyMix(audio_devices_t deviceType,
+            const String8& address, sp<AudioPolicyMix> &policyMix) const;
 
-    status_t registerMix(const String8& address, AudioMix mix, sp<SwAudioOutputDescriptor> desc);
+    status_t registerMix(AudioMix mix, sp<SwAudioOutputDescriptor> desc);
 
-    status_t unregisterMix(const String8& address);
+    status_t unregisterMix(const AudioMix& mix);
 
     void closeOutput(sp<SwAudioOutputDescriptor> &desc);
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 98a7800..dca84c0 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -73,16 +73,21 @@
     }
 }
 
-status_t AudioPolicyMixCollection::registerMix(const String8& address, AudioMix mix,
-                                               sp<SwAudioOutputDescriptor> desc)
+status_t AudioPolicyMixCollection::registerMix(AudioMix mix, sp<SwAudioOutputDescriptor> desc)
 {
-    ssize_t index = indexOfKey(address);
-    if (index >= 0) {
-        ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
-        return BAD_VALUE;
+    for (size_t i = 0; i < size(); i++) {
+        const sp<AudioPolicyMix>& registeredMix = itemAt(i);
+        if (mix.mDeviceType == registeredMix->mDeviceType
+                && mix.mDeviceAddress.compare(registeredMix->mDeviceAddress) == 0) {
+            ALOGE("registerMix(): mix already registered for dev=0x%x addr=%s",
+                    mix.mDeviceType, mix.mDeviceAddress.string());
+            return BAD_VALUE;
+        }
     }
     sp<AudioPolicyMix> policyMix = new AudioPolicyMix(mix);
-    add(address, policyMix);
+    add(policyMix);
+    ALOGD("registerMix(): adding mix for dev=0x%x addr=%s",
+            policyMix->mDeviceType, policyMix->mDeviceAddress.string());
 
     if (desc != 0) {
         desc->mPolicyMix = policyMix;
@@ -91,34 +96,48 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyMixCollection::unregisterMix(const String8& address)
+status_t AudioPolicyMixCollection::unregisterMix(const AudioMix& mix)
 {
-    ssize_t index = indexOfKey(address);
-    if (index < 0) {
-        ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
-        return BAD_VALUE;
+    for (size_t i = 0; i < size(); i++) {
+        const sp<AudioPolicyMix>& registeredMix = itemAt(i);
+        if (mix.mDeviceType == registeredMix->mDeviceType
+                && mix.mDeviceAddress.compare(registeredMix->mDeviceAddress) == 0) {
+            ALOGD("unregisterMix(): removing mix for dev=0x%x addr=%s",
+                    mix.mDeviceType, mix.mDeviceAddress.string());
+            removeAt(i);
+            return NO_ERROR;
+        }
     }
 
-    removeItemsAt(index);
-    return NO_ERROR;
+    ALOGE("unregisterMix(): mix not registered for dev=0x%x addr=%s",
+            mix.mDeviceType, mix.mDeviceAddress.string());
+    return BAD_VALUE;
 }
 
-status_t AudioPolicyMixCollection::getAudioPolicyMix(const String8& address,
-                                                     sp<AudioPolicyMix> &policyMix) const
+status_t AudioPolicyMixCollection::getAudioPolicyMix(audio_devices_t deviceType,
+        const String8& address, sp<AudioPolicyMix> &policyMix) const
 {
-    ssize_t index = indexOfKey(address);
-    if (index < 0) {
-        ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
-        return BAD_VALUE;
+
+    ALOGV("getAudioPolicyMix() for dev=0x%x addr=%s", deviceType, address.string());
+    for (ssize_t i = 0; i < size(); i++) {
+        if (itemAt(i)->mDeviceType == deviceType
+                && itemAt(i)->mDeviceAddress.compare(address) == 0) {
+            policyMix = itemAt(i);
+            ALOGV("getAudioPolicyMix: found mix %zu match (devType=0x%x addr=%s)",
+                    i, deviceType, address.string());
+            return NO_ERROR;
+        }
     }
-    policyMix = valueAt(index);
-    return NO_ERROR;
+
+    ALOGE("getAudioPolicyMix(): mix not registered for dev=0x%x addr=%s",
+            deviceType, address.string());
+    return BAD_VALUE;
 }
 
 void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc)
 {
     for (size_t i = 0; i < size(); i++) {
-        sp<AudioPolicyMix> policyMix = valueAt(i);
+        sp<AudioPolicyMix> policyMix = itemAt(i);
         if (policyMix->getOutput() == desc) {
             policyMix->clearOutput();
         }
@@ -134,7 +153,7 @@
     ALOGV("getOutputForAttr() querying %zu mixes:", size());
     primaryDesc = 0;
     for (size_t i = 0; i < size(); i++) {
-        sp<AudioPolicyMix> policyMix = valueAt(i);
+        sp<AudioPolicyMix> policyMix = itemAt(i);
         const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
         if (!primaryOutputMix && (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) {
             // AAudio does not support MMAP_NO_IRQ loopback render, and there is no way with
@@ -320,10 +339,10 @@
         const DeviceVector &availableOutputDevices)
 {
     for (size_t i = 0; i < size(); i++) {
-        if (valueAt(i)->getOutput() == output) {
+        if (itemAt(i)->getOutput() == output) {
             // This Desc is involved in a Mix, which has the highest prio
-            audio_devices_t deviceType = valueAt(i)->mDeviceType;
-            String8 address = valueAt(i)->mDeviceAddress;
+            audio_devices_t deviceType = itemAt(i)->mDeviceType;
+            String8 address = itemAt(i)->mDeviceAddress;
             ALOGV("%s: device (0x%x, addr=%s) forced by mix",
                   __FUNCTION__, deviceType, address.c_str());
             return availableOutputDevices.getDevice(deviceType, address, AUDIO_FORMAT_DEFAULT);
@@ -338,7 +357,7 @@
         sp<AudioPolicyMix> *policyMix) const
 {
     for (size_t i = 0; i < size(); i++) {
-        AudioPolicyMix *mix = valueAt(i).get();
+        AudioPolicyMix *mix = itemAt(i).get();
         if (mix->mMixType != MIX_TYPE_RECORDERS) {
             continue;
         }
@@ -374,19 +393,28 @@
     String8 address(attr.tags + strlen("addr="));
 
 #ifdef LOG_NDEBUG
-    ALOGV("getInputMixForAttr looking for address %s\n  mixes available:", address.string());
+    ALOGV("getInputMixForAttr looking for address %s for source %d\n  mixes available:",
+            address.string(), attr.source);
     for (size_t i = 0; i < size(); i++) {
-            sp<AudioPolicyMix> audioPolicyMix = valueAt(i);
-            ALOGV("\tmix %zu address=%s", i, audioPolicyMix->mDeviceAddress.string());
+        const sp<AudioPolicyMix> audioPolicyMix = itemAt(i);
+        ALOGV("\tmix %zu address=%s", i, audioPolicyMix->mDeviceAddress.string());
     }
 #endif
 
-    ssize_t index = indexOfKey(address);
-    if (index < 0) {
+    size_t index;
+    for (index = 0; index < size(); index++) {
+        const sp<AudioPolicyMix>& registeredMix = itemAt(index);
+        if (registeredMix->mDeviceAddress.compare(address) == 0) {
+            ALOGD("getInputMixForAttr found addr=%s dev=0x%x",
+                    registeredMix->mDeviceAddress.string(), registeredMix->mDeviceType);
+            break;
+        }
+    }
+    if (index == size()) {
         ALOGW("getInputMixForAttr() no policy for address %s", address.string());
         return BAD_VALUE;
     }
-    sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
+    const sp<AudioPolicyMix> audioPolicyMix = itemAt(index);
 
     if (audioPolicyMix->mMixType != MIX_TYPE_PLAYERS) {
         ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string());
@@ -404,7 +432,7 @@
     //    "match uid" rule for this uid, return an error
     //    (adding a uid-device affinity would result in contradictory rules)
     for (size_t i = 0; i < size(); i++) {
-        const AudioPolicyMix* mix = valueAt(i).get();
+        const AudioPolicyMix* mix = itemAt(i).get();
         if (!mix->isDeviceAffinityCompatible()) {
             continue;
         }
@@ -421,7 +449,7 @@
     //     AND it doesn't have a "match uid" rule
     //   THEN add a rule to exclude the uid
     for (size_t i = 0; i < size(); i++) {
-        const AudioPolicyMix *mix = valueAt(i).get();
+        const AudioPolicyMix *mix = itemAt(i).get();
         if (!mix->isDeviceAffinityCompatible()) {
             continue;
         }
@@ -452,7 +480,7 @@
     // for each player mix: remove existing rules that match or exclude this uid
     for (size_t i = 0; i < size(); i++) {
         bool foundUidRule = false;
-        const AudioPolicyMix *mix = valueAt(i).get();
+        const AudioPolicyMix *mix = itemAt(i).get();
         if (!mix->isDeviceAffinityCompatible()) {
             continue;
         }
@@ -481,7 +509,7 @@
     // for each player mix: find rules that don't exclude this uid, and add the device to the list
     for (size_t i = 0; i < size(); i++) {
         bool ruleAllowsUid = true;
-        const AudioPolicyMix *mix = valueAt(i).get();
+        const AudioPolicyMix *mix = itemAt(i).get();
         if (mix->mMixType != MIX_TYPE_PLAYERS) {
             continue;
         }
@@ -504,7 +532,7 @@
 {
     dst->append("\nAudio Policy Mix:\n");
     for (size_t i = 0; i < size(); i++) {
-        valueAt(i)->dump(dst, 2, i);
+        itemAt(i)->dump(dst, 2, i);
     }
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 575a6c2..3ca7591 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2868,13 +2868,16 @@
             }
 
             String8 address = mix.mDeviceAddress;
+            audio_devices_t deviceTypeToMakeAvailable;
             if (mix.mMixType == MIX_TYPE_PLAYERS) {
-                mix.mDeviceType = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
-            } else {
                 mix.mDeviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+                deviceTypeToMakeAvailable = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+            } else {
+                mix.mDeviceType = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+                deviceTypeToMakeAvailable = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
             }
 
-            if (mPolicyMixes.registerMix(address, mix, 0 /*output desc*/) != NO_ERROR) {
+            if (mPolicyMixes.registerMix(mix, 0 /*output desc*/) != NO_ERROR) {
                 ALOGE("Error registering mix %zu for address %s", i, address.string());
                 res = INVALID_OPERATION;
                 break;
@@ -2890,7 +2893,7 @@
             rSubmixModule->addInputProfile(address, &inputConfig,
                     AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
 
-            if ((res = setDeviceConnectionStateInt(mix.mDeviceType,
+            if ((res = setDeviceConnectionStateInt(deviceTypeToMakeAvailable,
                     AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                     address.string(), "remote-submix", AUDIO_FORMAT_DEFAULT)) != NO_ERROR) {
                 ALOGE("Failed to set remote submix device available, type %u, address %s",
@@ -2916,7 +2919,7 @@
                 sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(j);
 
                 if (desc->supportedDevices().contains(device)) {
-                    if (mPolicyMixes.registerMix(address, mix, desc) != NO_ERROR) {
+                    if (mPolicyMixes.registerMix(mix, desc) != NO_ERROR) {
                         ALOGE("Could not register mix RENDER,  dev=0x%X addr=%s", type,
                               address.string());
                         res = INVALID_OPERATION;
@@ -2966,7 +2969,7 @@
 
             String8 address = mix.mDeviceAddress;
 
-            if (mPolicyMixes.unregisterMix(address) != NO_ERROR) {
+            if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
                 res = INVALID_OPERATION;
                 continue;
             }
@@ -2987,7 +2990,7 @@
             rSubmixModule->removeInputProfile(address);
 
         } else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
-            if (mPolicyMixes.unregisterMix(mix.mDeviceAddress) != NO_ERROR) {
+            if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
                 res = INVALID_OPERATION;
                 continue;
             }
@@ -3924,6 +3927,8 @@
 
         if (status != NO_ERROR) {
             mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
+            outputDesc->removeClient(sourceDesc->portId());
+            outputDesc->stop();
             return status;
         }
         sourceDesc->setSwOutput(outputDesc);
@@ -4188,6 +4193,7 @@
         if (status == NO_ERROR) {
             swOutputDesc->stop();
         }
+        swOutputDesc->removeClient(sourceDesc->portId());
         mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
     } else {
         sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
@@ -4650,7 +4656,8 @@
                     addOutput(output, desc);
                     if (device_distinguishes_on_address(deviceType) && address != "0") {
                         sp<AudioPolicyMix> policyMix;
-                        if (mPolicyMixes.getAudioPolicyMix(address, policyMix) == NO_ERROR) {
+                        if (mPolicyMixes.getAudioPolicyMix(deviceType, address, policyMix)
+                                == NO_ERROR) {
                             policyMix->setOutput(desc);
                             desc->mPolicyMix = policyMix;
                         } else {
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 743c816..5a87134 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -330,9 +330,9 @@
 }
 
 bool HeicCompositeStream::isSizeSupportedByHeifEncoder(int32_t width, int32_t height,
-        bool* useHeic, bool* useGrid, int64_t* stall) {
+        bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName) {
     static HeicEncoderInfoManager& heicManager = HeicEncoderInfoManager::getInstance();
-    return heicManager.isSizeSupported(width, height, useHeic, useGrid, stall);
+    return heicManager.isSizeSupported(width, height, useHeic, useGrid, stall, hevcName);
 }
 
 bool HeicCompositeStream::isInMemoryTempFileSupported() {
@@ -1115,8 +1115,9 @@
     ALOGV("%s", __FUNCTION__);
 
     bool useGrid = false;
+    AString hevcName;
     bool isSizeSupported = isSizeSupportedByHeifEncoder(width, height,
-            &mUseHeic, &useGrid, nullptr);
+            &mUseHeic, &useGrid, nullptr, &hevcName);
     if (!isSizeSupported) {
         ALOGE("%s: Encoder doesnt' support size %u x %u!",
                 __FUNCTION__, width, height);
@@ -1138,7 +1139,11 @@
     }
 
     // Create HEIC/HEVC codec.
-    mCodec = MediaCodec::CreateByType(mCodecLooper, desiredMime, true /*encoder*/);
+    if (mUseHeic) {
+        mCodec = MediaCodec::CreateByType(mCodecLooper, desiredMime, true /*encoder*/);
+    } else {
+        mCodec = MediaCodec::CreateByComponentName(mCodecLooper, hevcName);
+    }
     if (mCodec == nullptr) {
         ALOGE("%s: Failed to create codec for %s", __FUNCTION__, desiredMime);
         return NO_INIT;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index 2aa3c38..260c68e 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -71,7 +71,7 @@
             const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/);
 
     static bool isSizeSupportedByHeifEncoder(int32_t width, int32_t height,
-            bool* useHeic, bool* useGrid, int64_t* stall);
+            bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName = nullptr);
     static bool isInMemoryTempFileSupported();
 protected:
 
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
index ed9be6e..d7cc2bf 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
@@ -49,7 +49,7 @@
 }
 
 bool HeicEncoderInfoManager::isSizeSupported(int32_t width, int32_t height, bool* useHeic,
-        bool* useGrid, int64_t* stall) const {
+        bool* useGrid, int64_t* stall, AString* hevcName) const {
     if (useHeic == nullptr || useGrid == nullptr) {
         ALOGE("%s: invalid parameters: useHeic %p, useGrid %p",
                 __FUNCTION__, useHeic, useGrid);
@@ -72,6 +72,9 @@
                 (width <= 1920 && height <= 1080))) {
             enableGrid = false;
         }
+        if (hevcName != nullptr) {
+            *hevcName = mHevcName;
+        }
     } else {
         // No encoder available for the requested size.
         return false;
@@ -113,9 +116,8 @@
     }
 
     sp<AMessage> heicDetails = getCodecDetails(codecsList, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
-    sp<AMessage> hevcDetails = getCodecDetails(codecsList, MEDIA_MIMETYPE_VIDEO_HEVC);
 
-    if (hevcDetails == nullptr) {
+    if (!getHevcCodecDetails(codecsList, MEDIA_MIMETYPE_VIDEO_HEVC)) {
         if (heicDetails != nullptr) {
             ALOGE("%s: Device must support HEVC codec if HEIC codec is available!",
                     __FUNCTION__);
@@ -123,22 +125,7 @@
         }
         return OK;
     }
-
-    // Check CQ mode for HEVC codec
-    {
-        AString bitrateModes;
-        auto hasItem = hevcDetails->findString("feature-bitrate-modes", &bitrateModes);
-        if (!hasItem) {
-            ALOGE("%s: Failed to query bitrate modes for HEVC codec", __FUNCTION__);
-            return BAD_VALUE;
-        }
-        ALOGV("%s: HEVC codec's feature-bitrate-modes value is %d, %s",
-                __FUNCTION__, hasItem, bitrateModes.c_str());
-        std::regex pattern("(^|,)CQ($|,)", std::regex_constants::icase);
-        if (!std::regex_search(bitrateModes.c_str(), pattern)) {
-            return OK;
-        }
-    }
+    mHasHEVC = true;
 
     // HEIC size range
     if (heicDetails != nullptr) {
@@ -152,19 +139,6 @@
         mHasHEIC = true;
     }
 
-    // HEVC size range
-    {
-        auto res = getCodecSizeRange(MEDIA_MIMETYPE_VIDEO_HEVC,
-                hevcDetails, &mMinSizeHevc, &mMaxSizeHevc, &mHevcFrameRateMaps);
-        if (res != OK) {
-            ALOGE("%s: Failed to get HEVC codec size range: %s (%d)", __FUNCTION__,
-                    strerror(-res), res);
-            return BAD_VALUE;
-        }
-
-        mHasHEVC = true;
-    }
-
     return OK;
 }
 
@@ -290,5 +264,80 @@
 
     return details;
 }
+
+bool HeicEncoderInfoManager::getHevcCodecDetails(
+        sp<IMediaCodecList> codecsList, const char* mime) {
+    bool found = false;
+    ssize_t idx = 0;
+    while ((idx = codecsList->findCodecByType(mime, true /*encoder*/, idx)) >= 0) {
+        const sp<MediaCodecInfo> info = codecsList->getCodecInfo(idx++);
+        if (info == nullptr) {
+            ALOGE("%s: Failed to get codec info for %s", __FUNCTION__, mime);
+            break;
+        }
+
+        // Filter out software ones as they may be too slow
+        if (!(info->getAttributes() & MediaCodecInfo::kFlagIsHardwareAccelerated)) {
+            continue;
+        }
+
+        const sp<MediaCodecInfo::Capabilities> caps =
+                info->getCapabilitiesFor(mime);
+        if (caps == nullptr) {
+            ALOGE("%s: [%s] Failed to get capabilities", __FUNCTION__,
+                    info->getCodecName());
+            break;
+        }
+        const sp<AMessage> details = caps->getDetails();
+        if (details == nullptr) {
+            ALOGE("%s: [%s] Failed to get details", __FUNCTION__,
+                    info->getCodecName());
+            break;
+        }
+
+        // Check CQ mode
+        AString bitrateModes;
+        auto hasItem = details->findString("feature-bitrate-modes", &bitrateModes);
+        if (!hasItem) {
+            ALOGE("%s: [%s] Failed to query bitrate modes", __FUNCTION__,
+                    info->getCodecName());
+            break;
+        }
+        ALOGV("%s: [%s] feature-bitrate-modes value is %d, %s",
+                __FUNCTION__, info->getCodecName(), hasItem, bitrateModes.c_str());
+        std::regex pattern("(^|,)CQ($|,)", std::regex_constants::icase);
+        if (!std::regex_search(bitrateModes.c_str(), pattern)) {
+            continue; // move on to next encoder
+        }
+
+        std::pair<int32_t, int32_t> minSizeHevc, maxSizeHevc;
+        FrameRateMaps hevcFrameRateMaps;
+        auto res = getCodecSizeRange(MEDIA_MIMETYPE_VIDEO_HEVC,
+                details, &minSizeHevc, &maxSizeHevc, &hevcFrameRateMaps);
+        if (res != OK) {
+            ALOGE("%s: [%s] Failed to get size range: %s (%d)", __FUNCTION__,
+                    info->getCodecName(), strerror(-res), res);
+            break;
+        }
+        if (kGridWidth < minSizeHevc.first
+                || kGridWidth > maxSizeHevc.first
+                || kGridHeight < minSizeHevc.second
+                || kGridHeight > maxSizeHevc.second) {
+            continue; // move on to next encoder
+        }
+
+        // Found: save name, size, frame rate
+        mHevcName = info->getCodecName();
+        mMinSizeHevc = minSizeHevc;
+        mMaxSizeHevc = maxSizeHevc;
+        mHevcFrameRateMaps = hevcFrameRateMaps;
+
+        found = true;
+        break;
+    }
+
+    return found;
+}
+
 } //namespace camera3
 } // namespace android
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
index fb0b914..58edba2 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.h
@@ -36,7 +36,7 @@
     }
 
     bool isSizeSupported(int32_t width, int32_t height,
-            bool* useHeic, bool* useGrid, int64_t* stall) const;
+            bool* useHeic, bool* useGrid, int64_t* stall, AString* hevcName) const;
 
     static const auto kGridWidth = 512;
     static const auto kGridHeight = 512;
@@ -61,11 +61,13 @@
     FrameRateMaps::const_iterator findClosestSize(const FrameRateMaps& maps,
             int32_t width, int32_t height) const;
     sp<AMessage> getCodecDetails(sp<IMediaCodecList> codecsList, const char* name);
+    bool getHevcCodecDetails(sp<IMediaCodecList> codecsList, const char* mime);
 
     bool mIsInited;
     std::pair<int32_t, int32_t> mMinSizeHeic, mMaxSizeHeic;
     std::pair<int32_t, int32_t> mMinSizeHevc, mMaxSizeHevc;
     bool mHasHEVC, mHasHEIC;
+    AString mHevcName;
     FrameRateMaps mHeicFrameRateMaps, mHevcFrameRateMaps;
     bool mDisableGrid;