Merge "send kDumpFromAudioServerArgument to the HAL modules" into 24D1-dev
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index ed11056..a44ba8b 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -506,27 +506,31 @@
                 "%s %s: must be invoked from the worker thread (%d)",
                 __func__, command.toString().c_str(), workerTid);
     }
-    if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
-        ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
-        return NOT_ENOUGH_DATA;
-    }
     StreamDescriptor::Reply localReply{};
-    if (reply == nullptr) {
-        reply = &localReply;
-    }
-    if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
-        ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
-        return NOT_ENOUGH_DATA;
-    }
     {
-        std::lock_guard l(mLock);
-        // Not every command replies with 'latencyMs' field filled out, substitute the last
-        // returned value in that case.
-        if (reply->latencyMs <= 0) {
-            reply->latencyMs = mLastReply.latencyMs;
+        std::lock_guard l(mCommandReplyLock);
+        if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
+            ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
+            return NOT_ENOUGH_DATA;
         }
-        mLastReply = *reply;
-        mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
+        if (reply == nullptr) {
+            reply = &localReply;
+        }
+        if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
+            ALOGE("%s: failed to read from reply MQ, command %s",
+                    __func__, command.toString().c_str());
+            return NOT_ENOUGH_DATA;
+        }
+        {
+            std::lock_guard l(mLock);
+            // Not every command replies with 'latencyMs' field filled out, substitute the last
+            // returned value in that case.
+            if (reply->latencyMs <= 0) {
+                reply->latencyMs = mLastReply.latencyMs;
+            }
+            mLastReply = *reply;
+            mLastReplyExpirationNs = uptimeNanos() + mLastReplyLifeTimeNs;
+        }
     }
     switch (reply->status) {
         case STATUS_OK: return OK;
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 53d46e5..b20eb00 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -243,6 +243,15 @@
     const bool mIsInput;
     const audio_config_base_t mConfig;
     const StreamContextAidl mContext;
+    // This lock is used to make sending of a command and receiving a reply an atomic
+    // operation. Otherwise, when two threads are trying to send a command, they may both advance to
+    // reading of the reply once the HAL has consumed the command from the MQ, and that creates a
+    // race condition between them.
+    //
+    // Note that only access to command and reply MQs needs to be protected because the data MQ is
+    // only accessed by the I/O thread. Also, there is no need to protect lookup operations on the
+    // queues as they are thread-safe, only send/receive operation must be protected.
+    std::mutex mCommandReplyLock;
 
   private:
     static audio_config_base_t configToBase(const audio_config& config) {
@@ -256,6 +265,8 @@
         std::lock_guard l(mLock);
         return mLastReply.state;
     }
+    // Note: Since `sendCommand` takes mLock while holding mCommandReplyLock, never call
+    // it with `mLock` being held.
     status_t sendCommand(
             const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
             ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr,
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
index da28204..a88ef83 100644
--- a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
@@ -147,8 +147,12 @@
                 return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
             }
             default: {
-                ALOGE("%s %d invalid command %u", __func__, __LINE__, command);
-                return BAD_VALUE;
+                // for vendor extension, copy data area to the DefaultExtension, parameter ignored
+                VendorExtension ext = VALUE_OR_RETURN_STATUS(
+                        aidl::android::legacy2aidl_EffectParameterReader_VendorExtension(param));
+                aidlParam =
+                        MAKE_SPECIFIC_PARAMETER(Spatializer, spatializer, vendor, ext);
+                break;
             }
         }
     } else {
@@ -317,8 +321,7 @@
                 return OK;
             }
             default: {
-                ALOGE("%s %d invalid command %u", __func__, __LINE__, command);
-                return BAD_VALUE;
+                VENDOR_EXTENSION_GET_AND_RETURN(Spatializer, spatializer, param);
             }
         }
     } else {
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index 90406e9..fff2feb 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -564,10 +564,40 @@
 
 RetCode BundleContext::setForcedDevice(
         const ::aidl::android::media::audio::common::AudioDeviceDescription& device) {
-    RETURN_VALUE_IF(true != isDeviceSupportedVirtualizer({device}), RetCode::ERROR_EFFECT_LIB_ERROR,
-                    " deviceNotSupportVirtualizer");
-    mForceDevice = device;
-    return RetCode::SUCCESS;
+    RetCode ret = RetCode::SUCCESS;
+    bool enableVirtualizer = mType == lvm::BundleEffectType::VIRTUALIZER && mEnabled;
+
+    if (isDeviceSupportedVirtualizer({device})) {
+        mVirtualizerForcedDevice = device;
+    } else {
+        // disabling forced virtualization mode
+        AudioDeviceDescription noneDevice;
+        if (device != noneDevice) {
+            // device is not supported, make it behave as a reset of forced mode but return an error
+            ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // verify whether the virtualization should be enabled or disabled
+        if (!isDeviceSupportedVirtualizer(mOutputDevice)) {
+            enableVirtualizer = false;
+        }
+        mVirtualizerForcedDevice = noneDevice;
+    }
+
+    if (enableVirtualizer) {
+        if (mVirtualizerTempDisabled) {
+            LOG(VERBOSE) << __func__ << " re-enable virtualizer";
+            enableOperatingMode();
+            mVirtualizerTempDisabled = false;
+        }
+    } else {
+        if (!mVirtualizerTempDisabled) {
+            LOG(VERBOSE) << __func__ << " disable virtualizer";
+            disableOperatingMode();
+            mVirtualizerTempDisabled = true;
+        }
+    }
+
+    return ret;
 }
 
 RetCode BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index ba3997a..044c8dd 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -76,7 +76,7 @@
     RetCode setForcedDevice(
             const ::aidl::android::media::audio::common::AudioDeviceDescription& device);
     aidl::android::media::audio::common::AudioDeviceDescription getForcedDevice() const {
-        return mForceDevice;
+        return mVirtualizerForcedDevice;
     }
     std::vector<Virtualizer::ChannelAngle> getSpeakerAngles(
             const Virtualizer::SpeakerAnglesPayload payload);
@@ -93,8 +93,6 @@
     bool mEnabled = false;
     LVM_Handle_t mInstance;
 
-    aidl::android::media::audio::common::AudioDeviceDescription mVirtualizerForcedDevice;
-
     int mSamplesPerSecond = 0;
     int mSamplesToExitCountEq = 0;
     int mSamplesToExitCountBb = 0;
@@ -120,7 +118,7 @@
     // Virtualizer
     int mVirtStrengthSaved = 0; /* Conversion between Get/Set */
     bool mVirtualizerTempDisabled = false;
-    ::aidl::android::media::audio::common::AudioDeviceDescription mForceDevice;
+    ::aidl::android::media::audio::common::AudioDeviceDescription mVirtualizerForcedDevice;
     // Volume
     float mLevelSaveddB = 0; /* for when mute is set, level must be saved */
     float mVolumedB = 0;
diff --git a/services/audioflinger/datapath/AudioStreamOut.cpp b/services/audioflinger/datapath/AudioStreamOut.cpp
index 9851f3a..aad538f 100644
--- a/services/audioflinger/datapath/AudioStreamOut.cpp
+++ b/services/audioflinger/datapath/AudioStreamOut.cpp
@@ -64,7 +64,7 @@
     int32_t deltaHalPosition; // initialization not needed, overwitten by __builtin_sub_overflow()
     (void) __builtin_sub_overflow(halPosition, truncatedPosition, &deltaHalPosition);
 
-    if (deltaHalPosition > 0) {
+    if (deltaHalPosition >= 0) {
         mRenderPosition += deltaHalPosition;
     } else if (mExpectRetrograde) {
         mExpectRetrograde = false;
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index c2e4b11..b92cd70 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -32,11 +32,15 @@
 class EffectDescriptor : public RefBase
 {
 public:
-    EffectDescriptor(const effect_descriptor_t *desc, bool isMusicEffect,
-                     int id, audio_io_handle_t io, audio_session_t session) :
-        mId(id), mIo(io), mSession(session), mEnabled(false), mSuspended(false),
-        mIsMusicEffect(isMusicEffect)
-    {
+  EffectDescriptor(const effect_descriptor_t* desc, bool isMusicEffect, int id,
+                   audio_io_handle_t io, audio_session_t session)
+      : mId(id),
+        mIo(io),
+        mIsOrphan(io == AUDIO_IO_HANDLE_NONE),
+        mSession(session),
+        mEnabled(false),
+        mSuspended(false),
+        mIsMusicEffect(isMusicEffect) {
         memcpy (&mDesc, desc, sizeof(effect_descriptor_t));
     }
 
@@ -95,11 +99,22 @@
      * @return ioHandle if found, AUDIO_IO_HANDLE_NONE otherwise.
      */
     audio_io_handle_t getIoForSession(audio_session_t sessionId,
-                                      const effect_uuid_t *effectType = nullptr);
-    bool hasOrphansForSession(audio_session_t sessionId);
+                                      const effect_uuid_t *effectType = nullptr) const;
+    bool hasOrphansForSession(audio_session_t sessionId) const;
     EffectDescriptorCollection getOrphanEffectsForSession(audio_session_t sessionId) const;
     void dump(String8 *dst, int spaces = 0, bool verbose = true) const;
 
+    /**
+     * @brief Checks if there is at least one orphan effect with given sessionId and effect type
+     * uuid.
+     * @param sessionId Session ID.
+     * @param effectType Effect type UUID, the implementation will be same as hasOrphansForSession
+     * if null.
+     * @return True if there is an orphan effect for given sessionId and type UUID, false otherwise.
+     */
+    bool hasOrphanEffectsForSessionAndType(audio_session_t sessionId,
+                                           const effect_uuid_t* effectType) const;
+
 private:
     status_t setEffectEnabled(const sp<EffectDescriptor> &effectDesc, bool enabled);
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index c85df0f..7971b61 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -210,7 +210,7 @@
     }
 }
 
-bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId)
+bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId) const
 {
     for (size_t i = 0; i < size(); ++i) {
         sp<EffectDescriptor> effect = valueAt(i);
@@ -221,6 +221,22 @@
     return false;
 }
 
+bool EffectDescriptorCollection::hasOrphanEffectsForSessionAndType(
+        audio_session_t sessionId, const effect_uuid_t* effectType) const {
+    if (effectType == nullptr) {
+        return hasOrphansForSession(sessionId);
+    }
+
+    for (size_t i = 0; i < size(); ++i) {
+        sp<EffectDescriptor> effect = valueAt(i);
+        if (effect->mIsOrphan && effect->mSession == sessionId &&
+            memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
 EffectDescriptorCollection EffectDescriptorCollection::getOrphanEffectsForSession(
         audio_session_t sessionId) const
 {
@@ -235,7 +251,7 @@
 }
 
 audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId,
-                                                              const effect_uuid_t *effectType)
+                                                              const effect_uuid_t *effectType) const
 {
     for (size_t i = 0; i < size(); ++i) {
         sp<EffectDescriptor> effect = valueAt(i);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 8ef76c6..f767522 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2069,6 +2069,8 @@
     // matching criteria values in priority order for best matching output so far
     std::vector<uint32_t> bestMatchCriteria(8, 0);
 
+    const bool hasOrphanHaptic =
+            mEffects.hasOrphanEffectsForSessionAndType(sessionId, FX_IID_HAPTICGENERATOR);
     const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
     const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
         channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
@@ -2089,13 +2091,20 @@
         // When using haptic output, same audio format and sample rate are required.
         const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
             outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
-        if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
+        // skip if haptic channel specified but output does not support it, or output support haptic
+        // but there is no haptic channel requested AND no orphan haptic effect exist
+        if ((hapticChannelCount != 0 && outputHapticChannelCount == 0) ||
+            (hapticChannelCount == 0 && outputHapticChannelCount != 0 && !hasOrphanHaptic)) {
             continue;
         }
-        if (outputHapticChannelCount >= hapticChannelCount
-            && format == outputDesc->getFormat()
-            && samplingRate == outputDesc->getSamplingRate()) {
-                currentMatchCriteria[0] = outputHapticChannelCount;
+        // In the case of audio-coupled-haptic playback, there is no format conversion and
+        // resampling in the framework, same format/channel/sampleRate for client and the output
+        // thread is required. In the case of HapticGenerator effect, do not require format
+        // matching.
+        if ((outputHapticChannelCount >= hapticChannelCount && format == outputDesc->getFormat() &&
+             samplingRate == outputDesc->getSamplingRate()) ||
+            (hapticChannelCount == 0 && hasOrphanHaptic)) {
+            currentMatchCriteria[0] = outputHapticChannelCount;
         }
 
         // functional flags match