/*
**
** Copyright 2012, 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.
*/

#pragma once

// ADD_BATTERY_DATA AUDIO_WATCHDOG FAST_THREAD_STATISTICS STATE_QUEUE_DUMP TEE_SINK
#include "Configuration.h"
#include "IAfThread.h"
#include "IAfTrack.h"

#include <android-base/macros.h>  // DISALLOW_COPY_AND_ASSIGN
#include <android/os/IPowerManager.h>
#include <afutils/AudioWatchdog.h>
#include <afutils/NBAIO_Tee.h>
#include <audio_utils/Balance.h>
#include <audio_utils/SimpleLog.h>
#include <datapath/ThreadMetrics.h>
#include <fastpath/FastCapture.h>
#include <fastpath/FastMixer.h>
#include <mediautils/Synchronization.h>
#include <mediautils/ThreadSnapshot.h>
#include <timing/MonotonicFrameCounter.h>
#include <utils/Log.h>

namespace android {

class AsyncCallbackThread;

class ThreadBase : public virtual IAfThreadBase, public Thread {
public:
    static const char *threadTypeToString(type_t type);

    // ThreadBase_ThreadLoop is a virtual mutex (always nullptr) that
    // guards methods and variables that ONLY run and are accessed
    // on the single threaded threadLoop().
    //
    // As access is by a single thread, the variables are thread safe.
    static audio_utils::mutex* ThreadBase_ThreadLoop;

    IAfThreadCallback* afThreadCallback() const final { return mAfThreadCallback.get(); }

    ThreadBase(const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
               type_t type, bool systemReady, bool isOut);
    ~ThreadBase() override;

    status_t readyToRun() final;
    void clearPowerManager() final EXCLUDES_ThreadBase_Mutex;

    // base for record and playback
    enum {
        CFG_EVENT_IO,
        CFG_EVENT_PRIO,
        CFG_EVENT_SET_PARAMETER,
        CFG_EVENT_CREATE_AUDIO_PATCH,
        CFG_EVENT_RELEASE_AUDIO_PATCH,
        CFG_EVENT_UPDATE_OUT_DEVICE,
        CFG_EVENT_RESIZE_BUFFER,
        CFG_EVENT_CHECK_OUTPUT_STAGE_EFFECTS,
        CFG_EVENT_HAL_LATENCY_MODES_CHANGED,
    };

    class ConfigEventData: public RefBase {
    public:
        virtual  void dump(char *buffer, size_t size) = 0;
    protected:
        ConfigEventData() = default;
    };

    // Config event sequence by client if status needed (e.g binder thread calling setParameters()):
    //  1. create SetParameterConfigEvent. This sets mWaitStatus in config event
    //  2. Lock mutex()
    //  3. Call sendConfigEvent_l(): Append to mConfigEvents and mWaitWorkCV.signal
    //  4. sendConfigEvent_l() reads status from event->mStatus;
    //  5. sendConfigEvent_l() returns status
    //  6. Unlock
    //
    // Parameter sequence by server: threadLoop calling processConfigEvents_l():
    // 1. Lock mutex()
    // 2. If there is an entry in mConfigEvents proceed ...
    // 3. Read first entry in mConfigEvents
    // 4. Remove first entry from mConfigEvents
    // 5. Process
    // 6. Set event->mStatus
    // 7. event->mCondition.notify_one()
    // 8. Unlock

    class ConfigEvent: public RefBase {
    public:
        void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "Event type: %d\n", mType);
            if (mData != nullptr) {
                snprintf(buffer, size, "Data:\n");
                mData->dump(buffer, size);
            }
        }

        audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::ConfigEvent_Mutex) {
            return mMutex;
        }
        const int mType; // event type e.g. CFG_EVENT_IO
        // mutex associated with mCondition
        mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kConfigEvent_Mutex};
        audio_utils::condition_variable mCondition; // condition for status return

        // NO_THREAD_SAFETY_ANALYSIS Can we add GUARDED_BY?
        status_t mStatus; // status communicated to sender

        bool mWaitStatus GUARDED_BY(mutex()); // true if sender is waiting for status
        // true if must wait for system ready to enter event queue
        bool mRequiresSystemReady GUARDED_BY(mutex());

        // NO_THREAD_SAFETY_ANALYSIS Can we add GUARDED_BY?
        sp<ConfigEventData> mData; // event specific parameter data

    protected:
        explicit ConfigEvent(int type, bool requiresSystemReady = false) :
            mType(type), mStatus(NO_ERROR), mWaitStatus(false),
            mRequiresSystemReady(requiresSystemReady), mData(NULL) {}
    };

    class IoConfigEventData : public ConfigEventData {
    public:
        IoConfigEventData(audio_io_config_event_t event, pid_t pid,
                          audio_port_handle_t portId) :
            mEvent(event), mPid(pid), mPortId(portId) {}

        virtual  void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "- IO event: event %d\n", mEvent);
        }

        const audio_io_config_event_t mEvent;
        const pid_t                 mPid;
        const audio_port_handle_t   mPortId;
    };

    class IoConfigEvent : public ConfigEvent {
    public:
        IoConfigEvent(audio_io_config_event_t event, pid_t pid, audio_port_handle_t portId) :
            ConfigEvent(CFG_EVENT_IO) {
            mData = new IoConfigEventData(event, pid, portId);
        }
    };

    class PrioConfigEventData : public ConfigEventData {
    public:
        PrioConfigEventData(pid_t pid, pid_t tid, int32_t prio, bool forApp) :
            mPid(pid), mTid(tid), mPrio(prio), mForApp(forApp) {}

        virtual  void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "- Prio event: pid %d, tid %d, prio %d, for app? %d\n",
                    mPid, mTid, mPrio, mForApp);
        }

        const pid_t mPid;
        const pid_t mTid;
        const int32_t mPrio;
        const bool mForApp;
    };

    class PrioConfigEvent : public ConfigEvent {
    public:
        PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp) :
            ConfigEvent(CFG_EVENT_PRIO, true) {
            mData = new PrioConfigEventData(pid, tid, prio, forApp);
        }
    };

    class SetParameterConfigEventData : public ConfigEventData {
    public:
        explicit SetParameterConfigEventData(const String8& keyValuePairs) :
            mKeyValuePairs(keyValuePairs) {}

        virtual  void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "- KeyValue: %s\n", mKeyValuePairs.c_str());
        }

        const String8 mKeyValuePairs;
    };

    class SetParameterConfigEvent : public ConfigEvent {
    public:
        explicit SetParameterConfigEvent(const String8& keyValuePairs) :
            ConfigEvent(CFG_EVENT_SET_PARAMETER) {
            mData = new SetParameterConfigEventData(keyValuePairs);
            mWaitStatus = true;
        }
    };

    class CreateAudioPatchConfigEventData : public ConfigEventData {
    public:
        CreateAudioPatchConfigEventData(const struct audio_patch patch,
                                        audio_patch_handle_t handle) :
            mPatch(patch), mHandle(handle) {}

        virtual  void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "- Patch handle: %u\n", mHandle);
        }

        const struct audio_patch mPatch;
        audio_patch_handle_t mHandle;  // cannot be const
    };

    class CreateAudioPatchConfigEvent : public ConfigEvent {
    public:
        CreateAudioPatchConfigEvent(const struct audio_patch patch,
                                    audio_patch_handle_t handle) :
            ConfigEvent(CFG_EVENT_CREATE_AUDIO_PATCH) {
            mData = new CreateAudioPatchConfigEventData(patch, handle);
            mWaitStatus = true;
        }
    };

    class ReleaseAudioPatchConfigEventData : public ConfigEventData {
    public:
        explicit ReleaseAudioPatchConfigEventData(const audio_patch_handle_t handle) :
            mHandle(handle) {}

        virtual  void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "- Patch handle: %u\n", mHandle);
        }

        const audio_patch_handle_t mHandle;
    };

    class ReleaseAudioPatchConfigEvent : public ConfigEvent {
    public:
        explicit ReleaseAudioPatchConfigEvent(const audio_patch_handle_t handle) :
            ConfigEvent(CFG_EVENT_RELEASE_AUDIO_PATCH) {
            mData = new ReleaseAudioPatchConfigEventData(handle);
            mWaitStatus = true;
        }
    };

    class UpdateOutDevicesConfigEventData : public ConfigEventData {
    public:
        explicit UpdateOutDevicesConfigEventData(const DeviceDescriptorBaseVector& outDevices) :
            mOutDevices(outDevices) {}

        virtual void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "- Devices: %s", android::toString(mOutDevices).c_str());
        }

        const DeviceDescriptorBaseVector mOutDevices;
    };

    class UpdateOutDevicesConfigEvent : public ConfigEvent {
    public:
        explicit UpdateOutDevicesConfigEvent(const DeviceDescriptorBaseVector& outDevices) :
            ConfigEvent(CFG_EVENT_UPDATE_OUT_DEVICE) {
            mData = new UpdateOutDevicesConfigEventData(outDevices);
        }
    };

    class ResizeBufferConfigEventData : public ConfigEventData {
    public:
        explicit ResizeBufferConfigEventData(int32_t maxSharedAudioHistoryMs) :
            mMaxSharedAudioHistoryMs(maxSharedAudioHistoryMs) {}

        virtual void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "- mMaxSharedAudioHistoryMs: %d", mMaxSharedAudioHistoryMs);
        }

        const int32_t mMaxSharedAudioHistoryMs;
    };

    class ResizeBufferConfigEvent : public ConfigEvent {
    public:
        explicit ResizeBufferConfigEvent(int32_t maxSharedAudioHistoryMs) :
            ConfigEvent(CFG_EVENT_RESIZE_BUFFER) {
            mData = new ResizeBufferConfigEventData(maxSharedAudioHistoryMs);
        }
    };

    class CheckOutputStageEffectsEvent : public ConfigEvent {
    public:
        CheckOutputStageEffectsEvent() :
            ConfigEvent(CFG_EVENT_CHECK_OUTPUT_STAGE_EFFECTS) {
        }
    };

    class HalLatencyModesChangedEvent : public ConfigEvent {
    public:
        HalLatencyModesChangedEvent() :
            ConfigEvent(CFG_EVENT_HAL_LATENCY_MODES_CHANGED) {
        }
    };


    class PMDeathRecipient : public IBinder::DeathRecipient {
    public:
        explicit    PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}

        // IBinder::DeathRecipient
        void binderDied(const wp<IBinder>& who) final;

    private:
        DISALLOW_COPY_AND_ASSIGN(PMDeathRecipient);

        const wp<ThreadBase> mThread;
    };

    type_t type() const final { return mType; }
    bool isDuplicating() const final { return (mType == DUPLICATING); }
    audio_io_handle_t id() const final { return mId;}

    uint32_t sampleRate() const final { return mSampleRate; }
    audio_channel_mask_t channelMask() const final { return mChannelMask; }
    audio_channel_mask_t mixerChannelMask() const override { return mChannelMask; }
    audio_format_t format() const final { return mHALFormat; }
    uint32_t channelCount() const final { return mChannelCount; }
    audio_channel_mask_t hapticChannelMask() const override { return AUDIO_CHANNEL_NONE; }
    uint32_t hapticChannelCount() const override { return 0; }
    uint32_t latency_l() const override { return 0; }  // NO_THREAD_SAFETY_ANALYSIS
    void setVolumeForOutput_l(float /* left */, float /* right */) const override
            REQUIRES(mutex()) {}

                // Return's the HAL's frame count i.e. fast mixer buffer size.
    size_t frameCountHAL() const final { return mFrameCount; }
    size_t frameSize() const final { return mFrameSize; }

    // Should be "virtual status_t requestExitAndWait()" and override same
    // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
    void exit() final EXCLUDES_ThreadBase_Mutex;
    status_t setParameters(const String8& keyValuePairs) final EXCLUDES_ThreadBase_Mutex;

                // sendConfigEvent_l() must be called with ThreadBase::mutex() held
                // Can temporarily release the lock if waiting for a reply from
                // processConfigEvents_l().
    status_t sendConfigEvent_l(sp<ConfigEvent>& event) REQUIRES(mutex());
    void sendIoConfigEvent(audio_io_config_event_t event, pid_t pid = 0,
            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final EXCLUDES_ThreadBase_Mutex;
    void sendIoConfigEvent_l(audio_io_config_event_t event, pid_t pid = 0,
            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final REQUIRES(mutex());
    void sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp) final
            EXCLUDES_ThreadBase_Mutex;
    void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio, bool forApp) final
            REQUIRES(mutex());
    status_t sendSetParameterConfigEvent_l(const String8& keyValuePair) final REQUIRES(mutex());
    status_t sendCreateAudioPatchConfigEvent(const struct audio_patch* patch,
            audio_patch_handle_t* handle) final EXCLUDES_ThreadBase_Mutex;
    status_t sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle) final
            EXCLUDES_ThreadBase_Mutex;
    status_t sendUpdateOutDeviceConfigEvent(
            const DeviceDescriptorBaseVector& outDevices) final EXCLUDES_ThreadBase_Mutex;
    void sendResizeBufferConfigEvent_l(int32_t maxSharedAudioHistoryMs) final REQUIRES(mutex());
    void sendCheckOutputStageEffectsEvent() final EXCLUDES_ThreadBase_Mutex;
    void sendCheckOutputStageEffectsEvent_l() final REQUIRES(mutex());
    void sendHalLatencyModesChangedEvent_l() final REQUIRES(mutex());

    void processConfigEvents_l() final REQUIRES(mutex());
    void setCheckOutputStageEffects() override {}
    void updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override;
    void toAudioPortConfig(struct audio_port_config* config) override;
    void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs) override REQUIRES(mutex());

    // see note at declaration of mStandby, mOutDevice and mInDevice
    bool inStandby() const override { return mStandby; }
    const DeviceTypeSet outDeviceTypes_l() const final REQUIRES(mutex()) {
        return getAudioDeviceTypes(mOutDeviceTypeAddrs);
    }
    audio_devices_t inDeviceType_l() const final REQUIRES(mutex()) {
        return mInDeviceTypeAddr.mType;
    }
    DeviceTypeSet getDeviceTypes_l() const final REQUIRES(mutex()) {
        return isOutput() ? outDeviceTypes_l() : DeviceTypeSet({inDeviceType_l()});
    }

    const AudioDeviceTypeAddrVector& outDeviceTypeAddrs() const final REQUIRES(mutex()) {
        return mOutDeviceTypeAddrs;
    }
    const AudioDeviceTypeAddr& inDeviceTypeAddr() const final REQUIRES(mutex()) {
        return mInDeviceTypeAddr;
    }

    bool isOutput() const final { return mIsOut; }

    bool isOffloadOrMmap() const final {
        switch (mType) {
        case OFFLOAD:
        case MMAP_PLAYBACK:
        case MMAP_CAPTURE:
            return true;
        default:
            return false;
        }
    }

    sp<IAfEffectHandle> createEffect_l(
                                    const sp<Client>& client,
                                    const sp<media::IEffectClient>& effectClient,
                                    int32_t priority,
                                    audio_session_t sessionId,
                                    effect_descriptor_t *desc,
                                    int *enabled,
                                    status_t *status /*non-NULL*/,
                                    bool pinned,
                                    bool probe,
                                    bool notifyFramesProcessed) final
            REQUIRES(audio_utils::AudioFlinger_Mutex);

                // return values for hasAudioSession (bit field)
                enum effect_state {
                    EFFECT_SESSION = 0x1,   // the audio session corresponds to at least one
                                            // effect
                    TRACK_SESSION = 0x2,    // the audio session corresponds to at least one
                                            // track
                    FAST_SESSION = 0x4,     // the audio session corresponds to at least one
                                            // fast track
                    SPATIALIZED_SESSION = 0x8, // the audio session corresponds to at least one
                                               // spatialized track
                    BIT_PERFECT_SESSION = 0x10 // the audio session corresponds to at least one
                                               // bit-perfect track
                };

    // get effect chain corresponding to session Id.
    sp<IAfEffectChain> getEffectChain(audio_session_t sessionId) const final;
    // same as getEffectChain() but must be called with ThreadBase mutex locked
    sp<IAfEffectChain> getEffectChain_l(audio_session_t sessionId) const final REQUIRES(mutex());
    std::vector<int> getEffectIds_l(audio_session_t sessionId) const final REQUIRES(mutex());

                // lock all effect chains Mutexes. Must be called before releasing the
                // ThreadBase mutex before processing the mixer and effects. This guarantees the
                // integrity of the chains during the process.
                // Also sets the parameter 'effectChains' to current value of mEffectChains.
    void lockEffectChains_l(Vector<sp<IAfEffectChain>>& effectChains) final
            REQUIRES(audio_utils::ThreadBase_Mutex) ACQUIRE(audio_utils::EffectChain_Mutex);
                // unlock effect chains after process
    void unlockEffectChains(const Vector<sp<IAfEffectChain>>& effectChains) final
            RELEASE(audio_utils::EffectChain_Mutex);
                // get a copy of mEffectChains vector
    Vector<sp<IAfEffectChain>> getEffectChains_l() const final REQUIRES(mutex()) {
        return mEffectChains;
    }
                // set audio mode to all effect chains
    void setMode(audio_mode_t mode) final;
                // get effect module with corresponding ID on specified audio session
    sp<IAfEffectModule> getEffect(audio_session_t sessionId, int effectId) const final;
    sp<IAfEffectModule> getEffect_l(audio_session_t sessionId, int effectId) const final
            REQUIRES(mutex());
                // add and effect module. Also creates the effect chain is none exists for
                // the effects audio session. Only called in a context of moving an effect
                // from one thread to another
    status_t addEffect_ll(const sp<IAfEffectModule>& effect) final
            REQUIRES(audio_utils::AudioFlinger_Mutex, mutex());
                // remove and effect module. Also removes the effect chain is this was the last
                // effect
    void removeEffect_l(const sp<IAfEffectModule>& effect, bool release = false) final
            REQUIRES(mutex());
                // disconnect an effect handle from module and destroy module if last handle
    void disconnectEffectHandle(IAfEffectHandle* handle, bool unpinIfLast) final;
                // detach all tracks connected to an auxiliary effect
    void detachAuxEffect_l(int /* effectId */) override REQUIRES(mutex()) {}
    // TODO(b/291317898) - remove hasAudioSession_l below.
    uint32_t hasAudioSession_l(audio_session_t sessionId) const override REQUIRES(mutex()) = 0;
    uint32_t hasAudioSession(audio_session_t sessionId) const final EXCLUDES_ThreadBase_Mutex {
        audio_utils::lock_guard _l(mutex());
        return hasAudioSession_l(sessionId);
    }

                template <typename T>
    uint32_t hasAudioSession_l(audio_session_t sessionId, const T& tracks) const
            REQUIRES(mutex()) {
                    uint32_t result = 0;
                    if (getEffectChain_l(sessionId) != 0) {
                        result = EFFECT_SESSION;
                    }
                    for (size_t i = 0; i < tracks.size(); ++i) {
                        const sp<IAfTrackBase>& track = tracks[i];
                        if (sessionId == track->sessionId()
                                && !track->isInvalid()       // not yet removed from tracks.
                                && !track->isTerminated()) {
                            result |= TRACK_SESSION;
                            if (track->isFastTrack()) {
                                result |= FAST_SESSION;  // caution, only represents first track.
                            }
                            if (track->isSpatialized()) {
                                result |= SPATIALIZED_SESSION;  // caution, only first track.
                            }
                            if (track->isBitPerfect()) {
                                result |= BIT_PERFECT_SESSION;
                            }
                            break;
                        }
                    }
                    return result;
                }

                // the value returned by default implementation is not important as the
                // strategy is only meaningful for PlaybackThread which implements this method
    product_strategy_t getStrategyForSession_l(
            audio_session_t /* sessionId */) const override REQUIRES(mutex()){
        return static_cast<product_strategy_t>(0);
    }

                // check if some effects must be suspended/restored when an effect is enabled
                // or disabled
    void checkSuspendOnEffectEnabled(bool enabled,
                                                 audio_session_t sessionId,
                                                 bool threadLocked) final;


                // Return a reference to a per-thread heap which can be used to allocate IMemory
                // objects that will be read-only to client processes, read/write to mediaserver,
                // and shared by all client processes of the thread.
                // The heap is per-thread rather than common across all threads, because
                // clients can't be trusted not to modify the offset of the IMemory they receive.
                // If a thread does not have such a heap, this method returns 0.
    sp<MemoryDealer> readOnlyHeap() const override { return nullptr; }

    sp<IMemory> pipeMemory() const override { return nullptr; }

    void systemReady() final EXCLUDES_ThreadBase_Mutex;

    void broadcast_l() final REQUIRES(mutex());

    bool isTimestampCorrectionEnabled_l() const override REQUIRES(mutex()) { return false; }

    bool isMsdDevice() const final { return mIsMsdDevice; }

    void dump(int fd, const Vector<String16>& args) override;

                // deliver stats to mediametrics.
    void sendStatistics(bool force) final
            REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;

    audio_utils::mutex& mutex() const final RETURN_CAPABILITY(audio_utils::ThreadBase_Mutex) {
        return mMutex;
    }
    mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kThreadBase_Mutex};

    void onEffectEnable(const sp<IAfEffectModule>& effect) final EXCLUDES_ThreadBase_Mutex;
    void onEffectDisable() final EXCLUDES_ThreadBase_Mutex;

                // invalidateTracksForAudioSession_l must be called with holding mutex().
    void invalidateTracksForAudioSession_l(audio_session_t /* sessionId */) const override
            REQUIRES(mutex()) {}
                // Invalidate all the tracks with the given audio session.
    void invalidateTracksForAudioSession(audio_session_t sessionId) const final
            EXCLUDES_ThreadBase_Mutex {
        audio_utils::lock_guard _l(mutex());
                    invalidateTracksForAudioSession_l(sessionId);
                }

                template <typename T>
    void invalidateTracksForAudioSession_l(audio_session_t sessionId,
            const T& tracks) const REQUIRES(mutex()) {
                    for (size_t i = 0; i < tracks.size(); ++i) {
                        const sp<IAfTrackBase>& track = tracks[i];
                        if (sessionId == track->sessionId()) {
                            track->invalidate();
                        }
                    }
                }

    void startMelComputation_l(const sp<audio_utils::MelProcessor>& processor) override
            REQUIRES(audio_utils::AudioFlinger_Mutex);
    void stopMelComputation_l() override
            REQUIRES(audio_utils::AudioFlinger_Mutex);

    audio_utils::DeferredExecutor& getThreadloopExecutor() override {
        return mThreadloopExecutor;
    }

protected:

                // entry describing an effect being suspended in mSuspendedSessions keyed vector
                class SuspendedSessionDesc : public RefBase {
                public:
                    SuspendedSessionDesc() : mRefCount(0) {}

                    int mRefCount;          // number of active suspend requests
                    effect_uuid_t mType;    // effect type UUID
                };

    void acquireWakeLock() EXCLUDES_ThreadBase_Mutex;
    virtual void acquireWakeLock_l() REQUIRES(mutex());
    void releaseWakeLock() EXCLUDES_ThreadBase_Mutex;
    void releaseWakeLock_l() REQUIRES(mutex());
    void updateWakeLockUids_l(const SortedVector<uid_t> &uids) REQUIRES(mutex());
    void getPowerManager_l() REQUIRES(mutex());
                // suspend or restore effects of the specified type (or all if type is NULL)
                // on a given session. The number of suspend requests is counted and restore
                // occurs when all suspend requests are cancelled.
    void setEffectSuspended_l(const effect_uuid_t *type,
                                          bool suspend,
            audio_session_t sessionId) final REQUIRES(mutex());
                // updated mSuspendedSessions when an effect is suspended or restored
    void updateSuspendedSessions_l(const effect_uuid_t *type,
                                                      bool suspend,
            audio_session_t sessionId) REQUIRES(mutex());
                // check if some effects must be suspended when an effect chain is added
    void checkSuspendOnAddEffectChain_l(const sp<IAfEffectChain>& chain) REQUIRES(mutex());

    /**
     * waitWhileThreadBusy_l() serves as a mutex gate, which does not allow
     * progress beyond the method while the PlaybackThread is busy (see setThreadBusy_l()).
     * During the wait, the ThreadBase_Mutex is temporarily unlocked.
     *
     * This implementation uses a condition variable.  Alternative methods to gate
     * the thread may use a second mutex (i.e. entry based on scoped_lock(mutex, gating_mutex)),
     * but those have less flexibility and more lock order issues.
     *
     * Current usage by Track::destroy(), Track::start(), Track::stop(), Track::pause(),
     * and Track::flush() block this way, and the primary caller is through TrackHandle
     * with no other mutexes held.
     *
     * Special tracks like PatchTrack and OutputTrack may also hold the another thread's
     * ThreadBase_Mutex during this time.  No other mutex is held.
     */

    void waitWhileThreadBusy_l(audio_utils::unique_lock& ul) final REQUIRES(mutex()) {
        // the wait returns immediately if the predicate is satisfied.
        mThreadBusyCv.wait(ul, [&]{ return mThreadBusy == false;});
    }

    void setThreadBusy_l(bool busy) REQUIRES(mutex()) {
        if (busy == mThreadBusy) return;
        mThreadBusy = busy;
        if (busy == true) return;  // no need to wake threads if we become busy.
        mThreadBusyCv.notify_all();
    }

                // sends the metadata of the active tracks to the HAL
                struct MetadataUpdate {
                    std::vector<playback_track_metadata_v7_t> playbackMetadataUpdate;
                    std::vector<record_track_metadata_v7_t>   recordMetadataUpdate;
                };
    // NO_THREAD_SAFETY_ANALYSIS, updateMetadata_l() should include ThreadBase_ThreadLoop
    // but MmapThread::start() -> exitStandby_l() -> updateMetadata_l() prevents this.
    virtual MetadataUpdate updateMetadata_l() REQUIRES(mutex()) = 0;

                String16 getWakeLockTag();

    virtual void preExit() EXCLUDES_ThreadBase_Mutex {}
    virtual void setMasterMono_l(bool mono __unused) REQUIRES(mutex()) {}
    virtual     bool        requireMonoBlend() { return false; }

                            // called within the threadLoop to obtain timestamp from the HAL.
    virtual status_t threadloop_getHalTimestamp_l(
            ExtendedTimestamp *timestamp __unused) const
            REQUIRES(mutex(), ThreadBase_ThreadLoop) {
                                return INVALID_OPERATION;
                            }
public:
// TODO(b/291317898) organize with publics
                product_strategy_t getStrategyForStream(audio_stream_type_t stream) const;
protected:

    virtual void onHalLatencyModesChanged_l() REQUIRES(mutex()) {}

    virtual void dumpInternals_l(int fd __unused, const Vector<String16>& args __unused)
            REQUIRES(mutex()) {}
    virtual void dumpTracks_l(int fd __unused, const Vector<String16>& args __unused)
            REQUIRES(mutex()) {}

                const type_t            mType;

                // Used by parameters, config events, addTrack_l, exit
                audio_utils::condition_variable mWaitWorkCV;

                const sp<IAfThreadCallback>  mAfThreadCallback;
                ThreadMetrics           mThreadMetrics;
                const bool              mIsOut;

    // mThreadBusy is checked under the ThreadBase_Mutex to ensure that
    // TrackHandle operations do not proceed while the ThreadBase is busy
    // with the track.  mThreadBusy is only true if the track is active.
    //
    bool mThreadBusy = false; // GUARDED_BY(ThreadBase_Mutex) but read in lambda.
    audio_utils::condition_variable mThreadBusyCv;

                // updated by PlaybackThread::readOutputParameters_l() or
                // RecordThread::readInputParameters_l()
                uint32_t                mSampleRate;
                size_t                  mFrameCount;       // output HAL, direct output, record
                audio_channel_mask_t    mChannelMask;
                uint32_t                mChannelCount;
                size_t                  mFrameSize;
                // not HAL frame size, this is for output sink (to pipe to fast mixer)
                audio_format_t          mFormat;           // Source format for Recording and
                                                           // Sink format for Playback.
                                                           // Sink format may be different than
                                                           // HAL format if Fastmixer is used.
                audio_format_t          mHALFormat;
                size_t                  mBufferSize;       // HAL buffer size for read() or write()

     // output device types and addresses
    AudioDeviceTypeAddrVector mOutDeviceTypeAddrs GUARDED_BY(mutex());
    AudioDeviceTypeAddr mInDeviceTypeAddr GUARDED_BY(mutex());   // input device type and address
    Vector<sp<ConfigEvent>> mConfigEvents GUARDED_BY(mutex());

    // events awaiting system ready
    Vector<sp<ConfigEvent>> mPendingConfigEvents GUARDED_BY(mutex());

                // These fields are written and read by thread itself without lock or barrier,
                // and read by other threads without lock or barrier via standby(), outDeviceTypes()
                // and inDeviceType().
                // Because of the absence of a lock or barrier, any other thread that reads
                // these fields must use the information in isolation, or be prepared to deal
                // with possibility that it might be inconsistent with other information.
                bool                    mStandby;     // Whether thread is currently in standby.

    // NO_THREAD_SAFETY_ANALYSIS - mPatch and mAudioSource should be guarded by mutex().
                struct audio_patch      mPatch;
                audio_source_t          mAudioSource;

                const audio_io_handle_t mId;
    Vector<sp<IAfEffectChain>> mEffectChains GUARDED_BY(mutex());

                static const int        kThreadNameLength = 16; // prctl(PR_SET_NAME) limit
                char                    mThreadName[kThreadNameLength]; // guaranteed NUL-terminated
    sp<os::IPowerManager> mPowerManager GUARDED_BY(mutex());
    sp<IBinder> mWakeLockToken GUARDED_BY(mutex());
                const sp<PMDeathRecipient> mDeathRecipient;
                // list of suspended effects per session and per type. The first (outer) vector is
                // keyed by session ID, the second (inner) by type UUID timeLow field
                // Updated by updateSuspendedSessions_l() only.
                KeyedVector< audio_session_t, KeyedVector< int, sp<SuspendedSessionDesc> > >
                                        mSuspendedSessions;
                // TODO: add comment and adjust size as needed
                static const size_t     kLogSize = 4 * 1024;
                sp<NBLog::Writer>       mNBLogWriter;
                bool                    mSystemReady;

    // NO_THREAD_SAFETY_ANALYSIS - mTimestamp and mTimestampVerifier should be
    // accessed under mutex for the RecordThread.
    ExtendedTimestamp mTimestamp;
    TimestampVerifier<int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
                // DIRECT and OFFLOAD threads should reset frame count to zero on stop/flush
                // TODO: add confirmation checks:
                // 1) DIRECT threads and linear PCM format really resets to 0?
                // 2) Is frame count really valid if not linear pcm?
                // 3) Are all 64 bits of position returned, not just lowest 32 bits?
                // Timestamp corrected device should be a single device.

    audio_devices_t mTimestampCorrectedDevice = AUDIO_DEVICE_NONE;  // CONST set in ctor

                // ThreadLoop statistics per iteration.
    std::atomic<int64_t> mLastIoBeginNs = -1;  // set in threadLoop, read by dump()
    int64_t mLastIoEndNs GUARDED_BY(ThreadBase_ThreadLoop) = -1;

                // ThreadSnapshot is thread-safe (internally locked)
                mediautils::ThreadSnapshot mThreadSnapshot;

    audio_utils::Statistics<double> mIoJitterMs GUARDED_BY(mutex()) {0.995 /* alpha */};
    audio_utils::Statistics<double> mProcessTimeMs GUARDED_BY(mutex()) {0.995 /* alpha */};

    // NO_THREAD_SAFETY_ANALYSIS  GUARDED_BY(mutex())
                audio_utils::Statistics<double> mLatencyMs{0.995 /* alpha */};
                audio_utils::Statistics<double> mMonopipePipeDepthStats{0.999 /* alpha */};

                // Save the last count when we delivered statistics to mediametrics.
                int64_t                 mLastRecordedTimestampVerifierN = 0;
                int64_t                 mLastRecordedTimeNs = 0;  // BOOTTIME to include suspend.

                bool                    mIsMsdDevice = false;
                // A condition that must be evaluated by the thread loop has changed and
                // we must not wait for async write callback in the thread loop before evaluating it
                bool                    mSignalPending;

#ifdef TEE_SINK
                NBAIO_Tee               mTee;
#endif
                // ActiveTracks is a sorted vector of track type T representing the
                // active tracks of threadLoop() to be considered by the locked prepare portion.
                // ActiveTracks should be accessed with the ThreadBase lock held.
                //
                // During processing and I/O, the threadLoop does not hold the lock;
                // hence it does not directly use ActiveTracks.  Care should be taken
                // to hold local strong references or defer removal of tracks
                // if the threadLoop may still be accessing those tracks due to mix, etc.
                //
                // This class updates power information appropriately.
                //

                template <typename T>
                class ActiveTracks {
                public:
                    explicit ActiveTracks(SimpleLog *localLog = nullptr)
                        : mActiveTracksGeneration(0)
                        , mLastActiveTracksGeneration(0)
                        , mLocalLog(localLog)
                    { }

                    ~ActiveTracks() {
                        ALOGW_IF(!mActiveTracks.isEmpty(),
                                "ActiveTracks should be empty in destructor");
                    }
                    // returns the last track added (even though it may have been
                    // subsequently removed from ActiveTracks).
                    //
                    // Used for DirectOutputThread to ensure a flush is called when transitioning
                    // to a new track (even though it may be on the same session).
                    // Used for OffloadThread to ensure that volume and mixer state is
                    // taken from the latest track added.
                    //
                    // The latest track is saved with a weak pointer to prevent keeping an
                    // otherwise useless track alive. Thus the function will return nullptr
                    // if the latest track has subsequently been removed and destroyed.
                    sp<T> getLatest() {
                        return mLatestActiveTrack.promote();
                    }

                    // SortedVector methods
                    ssize_t         add(const sp<T> &track);
                    ssize_t         remove(const sp<T> &track);
                    size_t          size() const {
                        return mActiveTracks.size();
                    }
                    bool            isEmpty() const {
                        return mActiveTracks.isEmpty();
                    }
                    ssize_t indexOf(const sp<T>& item) const {
                        return mActiveTracks.indexOf(item);
                    }
                    sp<T>           operator[](size_t index) const {
                        return mActiveTracks[index];
                    }
                    typename SortedVector<sp<T>>::iterator begin() {
                        return mActiveTracks.begin();
                    }
                    typename SortedVector<sp<T>>::iterator end() {
                        return mActiveTracks.end();
                    }

                    // Due to Binder recursion optimization, clear() and updatePowerState()
                    // cannot be called from a Binder thread because they may call back into
                    // the original calling process (system server) for BatteryNotifier
                    // (which requires a Java environment that may not be present).
                    // Hence, call clear() and updatePowerState() only from the
                    // ThreadBase thread.
                    void            clear();
                    // periodically called in the threadLoop() to update power state uids.
                    void updatePowerState_l(const sp<ThreadBase>& thread, bool force = false)
                            REQUIRES(audio_utils::ThreadBase_Mutex);

                    /** @return true if one or move active tracks was added or removed since the
                     *          last time this function was called or the vector was created.
                     *          true if volume of one of active tracks was changed.
                     */
                    bool            readAndClearHasChanged();

                    /** Force updating track metadata to audio HAL stream next time
                     * readAndClearHasChanged() is called.
                     */
                    void            setHasChanged() { mHasChanged = true; }

                private:
                    void            logTrack(const char *funcName, const sp<T> &track) const;

                    SortedVector<uid_t> getWakeLockUids() {
                        SortedVector<uid_t> wakeLockUids;
                        for (const sp<T> &track : mActiveTracks) {
                            wakeLockUids.add(track->uid());
                        }
                        return wakeLockUids; // moved by underlying SharedBuffer
                    }

                    SortedVector<sp<T>> mActiveTracks;
                    int                 mActiveTracksGeneration;
                    int                 mLastActiveTracksGeneration;
                    wp<T>               mLatestActiveTrack; // latest track added to ActiveTracks
                    SimpleLog * const   mLocalLog;
                    // If the vector has changed since last call to readAndClearHasChanged
                    bool                mHasChanged = false;
                };

                SimpleLog mLocalLog;  // locked internally

    // mThreadloopExecutor contains deferred functors and object (dtors) to
    // be executed at the end of the processing period, without any
    // mutexes held.
    //
    // mThreadloopExecutor is locked internally, so its methods are thread-safe
    // for access.
    audio_utils::DeferredExecutor mThreadloopExecutor;

    private:
    void dumpBase_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
    void dumpEffectChains_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
};

// --- PlaybackThread ---
class PlaybackThread : public ThreadBase, public virtual IAfPlaybackThread,
                       public StreamOutHalInterfaceCallback,
                       public virtual VolumeInterface, public StreamOutHalInterfaceEventCallback {
public:
    sp<IAfPlaybackThread> asIAfPlaybackThread() final {
        return sp<IAfPlaybackThread>::fromExisting(this);
    }

    // retry count before removing active track in case of underrun on offloaded thread:
    // we need to make sure that AudioTrack client has enough time to send large buffers
    //FIXME may be more appropriate if expressed in time units. Need to revise how underrun is
    // handled for offloaded tracks
    static const int8_t kMaxTrackRetriesOffload = 20;
    static const int8_t kMaxTrackStartupRetriesOffload = 100;
    static constexpr uint32_t kMaxTracksPerUid = 40;
    static constexpr size_t kMaxTracks = 256;

    // Maximum delay (in nanoseconds) for upcoming buffers in suspend mode, otherwise
    // if delay is greater, the estimated time for timeLoopNextNs is reset.
    // This allows for catch-up to be done for small delays, while resetting the estimate
    // for initial conditions or large delays.
    static const nsecs_t kMaxNextBufferDelayNs = 100000000;

    PlaybackThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut* output,
                   audio_io_handle_t id, type_t type, bool systemReady,
                   audio_config_base_t *mixerConfig = nullptr);
    ~PlaybackThread() override;

    // Thread virtuals
    bool threadLoop() final REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;

    // RefBase
    void onFirstRef() override;

    status_t checkEffectCompatibility_l(
            const effect_descriptor_t* desc, audio_session_t sessionId) final REQUIRES(mutex());

    void addOutputTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex()) {
        mTracks.add(track);
    }

protected:
    // Code snippets that were lifted up out of threadLoop()
    virtual void threadLoop_mix() REQUIRES(ThreadBase_ThreadLoop) = 0;
    virtual void threadLoop_sleepTime() REQUIRES(ThreadBase_ThreadLoop) = 0;
    virtual ssize_t threadLoop_write() REQUIRES(ThreadBase_ThreadLoop);
    virtual void threadLoop_drain() REQUIRES(ThreadBase_ThreadLoop);
    virtual void threadLoop_standby() REQUIRES(ThreadBase_ThreadLoop);
    virtual void threadLoop_exit() REQUIRES(ThreadBase_ThreadLoop);
    virtual void threadLoop_removeTracks(const Vector<sp<IAfTrack>>& tracksToRemove)
            REQUIRES(ThreadBase_ThreadLoop);

                // prepareTracks_l reads and writes mActiveTracks, and returns
                // the pending set of tracks to remove via Vector 'tracksToRemove'.  The caller
                // is responsible for clearing or destroying this Vector later on, when it
                // is safe to do so. That will drop the final ref count and destroy the tracks.
    virtual mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove)
            REQUIRES(mutex(), ThreadBase_ThreadLoop) = 0;

    void removeTracks_l(const Vector<sp<IAfTrack>>& tracksToRemove) REQUIRES(mutex());
    status_t handleVoipVolume_l(float *volume) REQUIRES(mutex());

    // StreamOutHalInterfaceCallback implementation
    virtual     void        onWriteReady();
    virtual     void        onDrainReady();
    virtual     void        onError(bool /*isHardError*/);

public: // AsyncCallbackThread
                void        resetWriteBlocked(uint32_t sequence);
                void        resetDraining(uint32_t sequence);
protected:

    virtual     bool        waitingAsyncCallback();
    virtual bool waitingAsyncCallback_l() REQUIRES(mutex());
    virtual bool shouldStandby_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
    virtual void onAddNewTrack_l() REQUIRES(mutex());
public:  // AsyncCallbackThread
                void        onAsyncError(bool isHardError); // error reported by AsyncCallbackThread
protected:
    // StreamHalInterfaceCodecFormatCallback implementation
                void        onCodecFormatChanged(
            const std::vector<uint8_t>& metadataBs) final;

    // ThreadBase virtuals
    void preExit() final EXCLUDES_ThreadBase_Mutex;

    virtual     bool        keepWakeLock() const { return true; }
    virtual void acquireWakeLock_l() REQUIRES(mutex()) {
                                ThreadBase::acquireWakeLock_l();
        mActiveTracks.updatePowerState_l(this, true /* force */);
                            }

    virtual void checkOutputStageEffects()
            REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex {}
    virtual     void        setHalLatencyMode_l() {}


    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
    void dumpTracks_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());

public:

    status_t initCheck() const final { return mOutput == nullptr ? NO_INIT : NO_ERROR; }

                // return estimated latency in milliseconds, as reported by HAL
    uint32_t latency() const final;
                // same, but lock must already be held
    uint32_t latency_l() const final /* REQUIRES(mutex()) */;  // NO_THREAD_SAFETY_ANALYSIS

                // VolumeInterface
    void setMasterVolume(float value) final;
    void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex;
    void setMasterMute(bool muted) final;
    void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
    void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
    float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;
    void setVolumeForOutput_l(float left, float right) const final;

    sp<IAfTrack> createTrack_l(
                                const sp<Client>& client,
                                audio_stream_type_t streamType,
                                const audio_attributes_t& attr,
                                uint32_t *sampleRate,
                                audio_format_t format,
                                audio_channel_mask_t channelMask,
                                size_t *pFrameCount,
                                size_t *pNotificationFrameCount,
                                uint32_t notificationsPerBuffer,
                                float speed,
                                const sp<IMemory>& sharedBuffer,
                                audio_session_t sessionId,
                                audio_output_flags_t *flags,
                                pid_t creatorPid,
                                const AttributionSourceState& attributionSource,
                                pid_t tid,
                                status_t *status /*non-NULL*/,
                                audio_port_handle_t portId,
                                const sp<media::IAudioTrackCallback>& callback,
                                bool isSpatialized,
                                bool isBitPerfect,
                                audio_output_flags_t* afTrackFlags) final
            REQUIRES(audio_utils::AudioFlinger_Mutex);

    bool isTrackActive(const sp<IAfTrack>& track) const final {
        return mActiveTracks.indexOf(track) >= 0;
    }

    AudioStreamOut* getOutput_l() const final REQUIRES(mutex()) { return mOutput; }
    AudioStreamOut* getOutput() const final EXCLUDES_ThreadBase_Mutex;
    AudioStreamOut* clearOutput() final EXCLUDES_ThreadBase_Mutex;

    // NO_THREAD_SAFETY_ANALYSIS -- probably needs a lock.
    sp<StreamHalInterface> stream() const final;

    // suspend(), restore(), and isSuspended() are implemented atomically.
    void suspend() final { ++mSuspended; }
    void restore() final {
        // if restore() is done without suspend(), get back into
        // range so that the next suspend() will operate correctly
        while (true) {
            int32_t suspended = mSuspended;
            if (suspended <= 0) {
                ALOGW("%s: invalid mSuspended %d <= 0", __func__, suspended);
                return;
            }
            const int32_t desired = suspended - 1;
            if (mSuspended.compare_exchange_weak(suspended, desired)) return;
        }
    }
    bool isSuspended() const final { return mSuspended > 0; }

    String8 getParameters(const String8& keys) EXCLUDES_ThreadBase_Mutex;

    // Hold either the AudioFlinger::mutex or the ThreadBase::mutex
    void ioConfigChanged_l(audio_io_config_event_t event, pid_t pid = 0,
            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final;
    status_t getRenderPosition(uint32_t* halFrames, uint32_t* dspFrames) const final
            EXCLUDES_ThreadBase_Mutex;
                // Consider also removing and passing an explicit mMainBuffer initialization
                // parameter to AF::IAfTrack::Track().
    float* sinkBuffer() const final {
                    return reinterpret_cast<float *>(mSinkBuffer); };

    void detachAuxEffect_l(int effectId) final REQUIRES(mutex());

    status_t attachAuxEffect(const sp<IAfTrack>& track, int EffectId) final
            EXCLUDES_ThreadBase_Mutex;
    status_t attachAuxEffect_l(const sp<IAfTrack>& track, int EffectId) final REQUIRES(mutex());

    status_t addEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
    size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
    uint32_t hasAudioSession_l(audio_session_t sessionId) const final REQUIRES(mutex()) {
                            return ThreadBase::hasAudioSession_l(sessionId, mTracks);
                        }
    product_strategy_t getStrategyForSession_l(audio_session_t sessionId) const final
            REQUIRES(mutex());


    status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) final
            EXCLUDES_ThreadBase_Mutex;
    // could be static.
    bool isValidSyncEvent(const sp<audioflinger::SyncEvent>& event) const final;

    // Does this require the AudioFlinger mutex as well?
    bool invalidateTracks_l(audio_stream_type_t streamType) final
            REQUIRES(mutex());
    bool invalidateTracks_l(std::set<audio_port_handle_t>& portIds) final
            REQUIRES(mutex());
    void invalidateTracks(audio_stream_type_t streamType) override;
                // Invalidate tracks by a set of port ids. The port id will be removed from
                // the given set if the corresponding track is found and invalidated.
    void invalidateTracks(std::set<audio_port_handle_t>& portIds) override
            EXCLUDES_ThreadBase_Mutex;

    size_t frameCount() const final { return mNormalFrameCount; }

    audio_channel_mask_t mixerChannelMask() const final {
                    return mMixerChannelMask;
                }

    status_t getTimestamp_l(AudioTimestamp& timestamp) final
            REQUIRES(mutex(), ThreadBase_ThreadLoop);

    void addPatchTrack(const sp<IAfPatchTrack>& track) final EXCLUDES_ThreadBase_Mutex;
    void deletePatchTrack(const sp<IAfPatchTrack>& track) final EXCLUDES_ThreadBase_Mutex;

    // NO_THREAD_SAFETY_ANALYSIS - fix this to use atomics.
    void toAudioPortConfig(struct audio_port_config* config) final;

                // Return the asynchronous signal wait time.
    int64_t computeWaitTimeNs_l() const override REQUIRES(mutex()) { return INT64_MAX; }
                // returns true if the track is allowed to be added to the thread.
    bool isTrackAllowed_l(
                                    audio_channel_mask_t channelMask __unused,
                                    audio_format_t format __unused,
                                    audio_session_t sessionId __unused,
            uid_t uid) const override REQUIRES(mutex()) {
                                return trackCountForUid_l(uid) < PlaybackThread::kMaxTracksPerUid
                                       && mTracks.size() < PlaybackThread::kMaxTracks;
                            }

    bool isTimestampCorrectionEnabled_l() const final REQUIRES(mutex()) {
        return audio_is_output_devices(mTimestampCorrectedDevice)
                && outDeviceTypes_l().count(mTimestampCorrectedDevice) != 0;
                            }

    // NO_THREAD_SAFETY_ANALYSIS - fix this to be atomic.
    bool isStreamInitialized() const final {
                                return !(mOutput == nullptr || mOutput->stream == nullptr);
                            }

    audio_channel_mask_t hapticChannelMask() const final {
                                         return mHapticChannelMask;
                                     }

    uint32_t hapticChannelCount() const final {
        return mHapticChannelCount;
    }

    bool supportsHapticPlayback() const final {
                    return (mHapticChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE;
                }

    void setDownStreamPatch(const struct audio_patch* patch) final EXCLUDES_ThreadBase_Mutex {
        audio_utils::lock_guard _l(mutex());
                    mDownStreamPatch = *patch;
                }

    IAfTrack* getTrackById_l(audio_port_handle_t trackId) final REQUIRES(mutex());

    bool hasMixer() const final {
                    return mType == MIXER || mType == DUPLICATING || mType == SPATIALIZER;
                }

    status_t setRequestedLatencyMode(
            audio_latency_mode_t /* mode */) override { return INVALID_OPERATION; }

    status_t getSupportedLatencyModes(
            std::vector<audio_latency_mode_t>* /* modes */) override {
                    return INVALID_OPERATION;
                }

    status_t setBluetoothVariableLatencyEnabled(bool /* enabled */) override{
                    return INVALID_OPERATION;
                }

    void startMelComputation_l(const sp<audio_utils::MelProcessor>& processor) override
            REQUIRES(audio_utils::AudioFlinger_Mutex);
    void stopMelComputation_l() override
            REQUIRES(audio_utils::AudioFlinger_Mutex);

    void setStandby() final EXCLUDES_ThreadBase_Mutex {
        audio_utils::lock_guard _l(mutex());
                    setStandby_l();
                }

    void setStandby_l() final REQUIRES(mutex()) {
                    mStandby = true;
                    mHalStarted = false;
                    mKernelPositionOnStandby =
                        mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
                }

    bool waitForHalStart() final EXCLUDES_ThreadBase_Mutex {
                    audio_utils::unique_lock _l(mutex());
                    static const nsecs_t kWaitHalTimeoutNs = seconds(2);
                    nsecs_t endWaitTimetNs = systemTime() + kWaitHalTimeoutNs;
                    while (!mHalStarted) {
                        nsecs_t timeNs = systemTime();
                        if (timeNs >= endWaitTimetNs) {
                            break;
                        }
                        nsecs_t waitTimeLeftNs = endWaitTimetNs - timeNs;
                        mWaitHalStartCV.wait_for(_l, std::chrono::nanoseconds(waitTimeLeftNs));
                    }
                    return mHalStarted;
                }

    void setTracksInternalMute(std::map<audio_port_handle_t, bool>* /* tracksInternalMute */)
            override EXCLUDES_ThreadBase_Mutex {
        // Do nothing. It is only used for bit perfect thread
    }
protected:
    // updated by readOutputParameters_l()
    size_t                          mNormalFrameCount;  // normal mixer and effects

    // throttle the thread processing
    bool mThreadThrottle GUARDED_BY(ThreadBase_ThreadLoop);

    // throttle time for MIXER threads - atomic as read by dump()
    std::atomic<uint32_t> mThreadThrottleTimeMs;

    // notify once per throttling
    uint32_t mThreadThrottleEndMs GUARDED_BY(ThreadBase_ThreadLoop);

    // half the buffer size in milliseconds
    uint32_t mHalfBufferMs GUARDED_BY(ThreadBase_ThreadLoop);

    void*                           mSinkBuffer;         // frame size aligned sink buffer

    // TODO:
    // Rearrange the buffer info into a struct/class with
    // clear, copy, construction, destruction methods.
    //
    // mSinkBuffer also has associated with it:
    //
    // mSinkBufferSize: Sink Buffer Size
    // mFormat: Sink Buffer Format

    // Mixer Buffer (mMixerBuffer*)
    //
    // In the case of floating point or multichannel data, which is not in the
    // sink format, it is required to accumulate in a higher precision or greater channel count
    // buffer before downmixing or data conversion to the sink buffer.

    // Set to "true" to enable the Mixer Buffer otherwise mixer output goes to sink buffer.
    bool mMixerBufferEnabled GUARDED_BY(ThreadBase_ThreadLoop);

    // Storage, 32 byte aligned (may make this alignment a requirement later).
    // Due to constraints on mNormalFrameCount, the buffer size is a multiple of 16 frames.
    void* mMixerBuffer GUARDED_BY(ThreadBase_ThreadLoop);

    // Size of mMixerBuffer in bytes: mNormalFrameCount * #channels * sampsize.
    size_t mMixerBufferSize GUARDED_BY(ThreadBase_ThreadLoop);

    // The audio format of mMixerBuffer. Set to AUDIO_FORMAT_PCM_(FLOAT|16_BIT) only.
    audio_format_t mMixerBufferFormat GUARDED_BY(ThreadBase_ThreadLoop);

    // An internal flag set to true by MixerThread::prepareTracks_l()
    // when mMixerBuffer contains valid data after mixing.
    bool mMixerBufferValid GUARDED_BY(ThreadBase_ThreadLoop);

    // Effects Buffer (mEffectsBuffer*)
    //
    // In the case of effects data, which is not in the sink format,
    // it is required to accumulate in a different buffer before data conversion
    // to the sink buffer.

    // Set to "true" to enable the Effects Buffer otherwise effects output goes to sink buffer.
    bool mEffectBufferEnabled;
    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()

    // Storage, 32 byte aligned (may make this alignment a requirement later).
    // Due to constraints on mNormalFrameCount, the buffer size is a multiple of 16 frames.
    void* mEffectBuffer;
    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()

    // Size of mEffectsBuffer in bytes: mNormalFrameCount * #channels * sampsize.
    size_t mEffectBufferSize;
    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()

    // The audio format of mEffectsBuffer. Set to AUDIO_FORMAT_PCM_16_BIT only.
    // NO_THREAD_SAFETY_ANALYSIS: Spatializer access this in addEffectChain_l()
    audio_format_t mEffectBufferFormat;

    // An internal flag set to true by MixerThread::prepareTracks_l()
    // when mEffectsBuffer contains valid data after mixing.
    //
    // When this is set, all mixer data is routed into the effects buffer
    // for any processing (including output processing).
    bool mEffectBufferValid GUARDED_BY(ThreadBase_ThreadLoop);

    // Set to "true" to enable when data has already copied to sink
    bool mHasDataCopiedToSinkBuffer GUARDED_BY(ThreadBase_ThreadLoop) = false;

    // Frame size aligned buffer used as input and output to all post processing effects
    // except the Spatializer in a SPATIALIZER thread. Non spatialized tracks are mixed into
    // this buffer so that post processing effects can be applied.
    void* mPostSpatializerBuffer GUARDED_BY(mutex()) = nullptr;

    // Size of mPostSpatializerBuffer in bytes
    size_t mPostSpatializerBufferSize GUARDED_BY(mutex());

    // suspend count, > 0 means suspended.  While suspended, the thread continues to pull from
    // tracks and mix, but doesn't write to HAL.  A2DP and SCO HAL implementations can't handle
    // concurrent use of both of them, so Audio Policy Service suspends one of the threads to
    // workaround that restriction.
    // 'volatile' means accessed via atomic operations and no lock.
    std::atomic<int32_t> mSuspended;

    int64_t                         mBytesWritten;
    std::atomic<int64_t> mFramesWritten;  // not reset on standby
    int64_t                         mLastFramesWritten = -1; // track changes in timestamp
                                                             // server frames written.
    int64_t                         mSuspendedFrames; // not reset on standby

    // mHapticChannelMask and mHapticChannelCount will only be valid when the thread support
    // haptic playback.
    audio_channel_mask_t            mHapticChannelMask = AUDIO_CHANNEL_NONE;
    uint32_t                        mHapticChannelCount = 0;

    audio_channel_mask_t            mMixerChannelMask = AUDIO_CHANNEL_NONE;

    // mMasterMute is in both PlaybackThread and in AudioFlinger.  When a
    // PlaybackThread needs to find out if master-muted, it checks it's local
    // copy rather than the one in AudioFlinger.  This optimization saves a lock.
    bool mMasterMute GUARDED_BY(mutex());
    void setMasterMute_l(bool muted) REQUIRES(mutex()) { mMasterMute = muted; }

                auto discontinuityForStandbyOrFlush() const { // call on threadLoop or with lock.
                    return ((mType == DIRECT && !audio_is_linear_pcm(mFormat))
                                    || mType == OFFLOAD)
                            ? mTimestampVerifier.DISCONTINUITY_MODE_ZERO
                            : mTimestampVerifier.DISCONTINUITY_MODE_CONTINUOUS;
                }

    ActiveTracks<IAfTrack> mActiveTracks;

    // Time to sleep between cycles when:
    virtual uint32_t        activeSleepTimeUs() const;      // mixer state MIXER_TRACKS_ENABLED
    virtual uint32_t        idleSleepTimeUs() const = 0;    // mixer state MIXER_IDLE
    virtual uint32_t        suspendSleepTimeUs() const = 0; // audio policy manager suspended us
    // No sleep when mixer state == MIXER_TRACKS_READY; relies on audio HAL stream->write()
    // No sleep in standby mode; waits on a condition

    // Code snippets that are temporarily lifted up out of threadLoop() until the merge

    // consider unification with MMapThread
    virtual void checkSilentMode_l() final REQUIRES(mutex());

    // Non-trivial for DUPLICATING only
    virtual void saveOutputTracks() REQUIRES(ThreadBase_ThreadLoop) {}
    virtual void clearOutputTracks() REQUIRES(ThreadBase_ThreadLoop) {}

    // Cache various calculated values, at threadLoop() entry and after a parameter change
    virtual void cacheParameters_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);
                void        setCheckOutputStageEffects() override {
                                mCheckOutputStageEffects.store(true);
                            }

    virtual uint32_t correctLatency_l(uint32_t latency) const REQUIRES(mutex());

    virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
            audio_patch_handle_t *handle) REQUIRES(mutex());
    virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle)
            REQUIRES(mutex());

    // NO_THREAD_SAFETY_ANALYSIS - fix this to use atomics
    bool usesHwAvSync() const final { return mType == DIRECT && mOutput != nullptr
                                    && mHwSupportsPause
                                    && (mOutput->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC); }

                uint32_t    trackCountForUid_l(uid_t uid) const;

                void        invalidateTracksForAudioSession_l(
            audio_session_t sessionId) const override REQUIRES(mutex()) {
                                ThreadBase::invalidateTracksForAudioSession_l(sessionId, mTracks);
                            }

    DISALLOW_COPY_AND_ASSIGN(PlaybackThread);

    status_t addTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex());
    bool destroyTrack_l(const sp<IAfTrack>& track) final REQUIRES(mutex());

    void removeTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex());
    std::set<audio_port_handle_t> getTrackPortIds_l() REQUIRES(mutex());
    std::set<audio_port_handle_t> getTrackPortIds();

    void readOutputParameters_l() REQUIRES(mutex());
    MetadataUpdate updateMetadata_l() final REQUIRES(mutex());
    virtual void sendMetadataToBackend_l(const StreamOutHalInterface::SourceMetadata& metadata)
            REQUIRES(mutex()) ;

    void collectTimestamps_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);

    // The Tracks class manages tracks added and removed from the Thread.
    template <typename T>
    class Tracks {
    public:
        explicit Tracks(bool saveDeletedTrackIds) :
            mSaveDeletedTrackIds(saveDeletedTrackIds) { }

        // SortedVector methods
        ssize_t         add(const sp<T> &track) {
            const ssize_t index = mTracks.add(track);
            LOG_ALWAYS_FATAL_IF(index < 0, "cannot add track");
            return index;
        }
        ssize_t         remove(const sp<T> &track);
        size_t          size() const {
            return mTracks.size();
        }
        bool            isEmpty() const {
            return mTracks.isEmpty();
        }
        ssize_t         indexOf(const sp<T> &item) {
            return mTracks.indexOf(item);
        }
        sp<T>           operator[](size_t index) const {
            return mTracks[index];
        }
        typename SortedVector<sp<T>>::iterator begin() {
            return mTracks.begin();
        }
        typename SortedVector<sp<T>>::iterator end() {
            return mTracks.end();
        }

        size_t          processDeletedTrackIds(const std::function<void(int)>& f) {
            for (const int trackId : mDeletedTrackIds) {
                f(trackId);
            }
            return mDeletedTrackIds.size();
        }

        void            clearDeletedTrackIds() { mDeletedTrackIds.clear(); }

    private:
        // Tracks pending deletion for MIXER type threads
        const bool mSaveDeletedTrackIds; // true to enable tracking
        std::set<int> mDeletedTrackIds;

        SortedVector<sp<T>> mTracks; // wrapped SortedVector.
    };

    Tracks<IAfTrack>                   mTracks;

    stream_type_t                   mStreamTypes[AUDIO_STREAM_CNT];

    AudioStreamOut                  *mOutput;

    float                           mMasterVolume;
    std::atomic<float>              mMasterBalance{};
    audio_utils::Balance            mBalance;
    int                             mNumWrites;
    int                             mNumDelayedWrites;
    bool                            mInWrite;

    // FIXME rename these former local variables of threadLoop to standard "m" names
    nsecs_t                         mStandbyTimeNs;
    size_t                          mSinkBufferSize;

    // cached copies of activeSleepTimeUs() and idleSleepTimeUs() made by cacheParameters_l()
    uint32_t                        mActiveSleepTimeUs;
    uint32_t                        mIdleSleepTimeUs;

    uint32_t                        mSleepTimeUs;

    // mixer status returned by prepareTracks_l()
    mixer_state mMixerStatus GUARDED_BY(ThreadBase_ThreadLoop); // current cycle
                                                  // previous cycle when in prepareTracks_l()
    mixer_state mMixerStatusIgnoringFastTracks GUARDED_BY(ThreadBase_ThreadLoop);
                                                  // FIXME or a separate ready state per track

    // FIXME move these declarations into the specific sub-class that needs them
    // MIXER only
    uint32_t sleepTimeShift GUARDED_BY(ThreadBase_ThreadLoop);

    // same as AudioFlinger::mStandbyTimeInNsecs except for DIRECT which uses a shorter value
    nsecs_t mStandbyDelayNs;  // GUARDED_BY(mutex());

    // MIXER only
    nsecs_t                         maxPeriod;

    // DUPLICATING only
    uint32_t                        writeFrames;

    size_t mBytesRemaining GUARDED_BY(ThreadBase_ThreadLoop);
    size_t mCurrentWriteLength GUARDED_BY(ThreadBase_ThreadLoop);
    bool                            mUseAsyncWrite;
    // mWriteAckSequence contains current write sequence on bits 31-1. The write sequence is
    // incremented each time a write(), a flush() or a standby() occurs.
    // Bit 0 is set when a write blocks and indicates a callback is expected.
    // Bit 0 is reset by the async callback thread calling resetWriteBlocked(). Out of sequence
    // callbacks are ignored.
    uint32_t                        mWriteAckSequence;
    // mDrainSequence contains current drain sequence on bits 31-1. The drain sequence is
    // incremented each time a drain is requested or a flush() or standby() occurs.
    // Bit 0 is set when the drain() command is called at the HAL and indicates a callback is
    // expected.
    // Bit 0 is reset by the async callback thread calling resetDraining(). Out of sequence
    // callbacks are ignored.
    uint32_t                        mDrainSequence;

    sp<AsyncCallbackThread>         mCallbackThread;

    audio_utils::mutex& audioTrackCbMutex() const { return mAudioTrackCbMutex; }
    mutable audio_utils::mutex mAudioTrackCbMutex{
            audio_utils::MutexOrder::kPlaybackThread_AudioTrackCbMutex};
    // Record of IAudioTrackCallback
    std::map<sp<IAfTrack>, sp<media::IAudioTrackCallback>> mAudioTrackCallbacks;

    // The HAL output sink is treated as non-blocking, but current implementation is blocking
    sp<NBAIO_Sink>          mOutputSink;
    // If a fast mixer is present, the blocking pipe sink, otherwise clear
    sp<NBAIO_Sink>          mPipeSink;
    // The current sink for the normal mixer to write it's (sub)mix, mOutputSink or mPipeSink
    sp<NBAIO_Sink>          mNormalSink;

    uint32_t                mScreenState;   // cached copy of gScreenState
    // TODO: add comment and adjust size as needed
    static const size_t     kFastMixerLogSize = 8 * 1024;
    sp<NBLog::Writer>       mFastMixerNBLogWriter;

    // Downstream patch latency, available if mDownstreamLatencyStatMs.getN() > 0.
    audio_utils::Statistics<double> mDownstreamLatencyStatMs{0.999};

    // output stream start detection based on render position returned by the kernel
    // condition signalled when the output stream has started
    audio_utils::condition_variable mWaitHalStartCV;
    // true when the output stream render position has moved, reset to false in standby
    bool                     mHalStarted = false;
    // last kernel render position saved when entering standby
    int64_t                  mKernelPositionOnStandby = 0;

public:
    FastTrackUnderruns getFastTrackUnderruns(size_t /* fastIndex */) const override
        { return {}; }
    const std::atomic<int64_t>& framesWritten() const final { return mFramesWritten; }

protected:
                // accessed by both binder threads and within threadLoop(), lock on mutex needed
     uint32_t& fastTrackAvailMask_l() final REQUIRES(mutex()) { return mFastTrackAvailMask; }
     uint32_t mFastTrackAvailMask;  // bit i set if fast track [i] is available
                bool        mHwSupportsPause;
                bool        mHwPaused;
                bool        mFlushPending;
                // volumes last sent to audio HAL with stream->setVolume()
                float mLeftVolFloat;
                float mRightVolFloat;

                // audio patch used by the downstream software patch.
                // Only used if ThreadBase::mIsMsdDevice is true.
                struct audio_patch mDownStreamPatch;

                std::atomic_bool mCheckOutputStageEffects{};


                // Provides periodic checking for timestamp advancement for underrun detection.
                class IsTimestampAdvancing {
                public:
                    // The timestamp will not be checked any faster than the specified time.
                    explicit IsTimestampAdvancing(nsecs_t minimumTimeBetweenChecksNs)
                        :   mMinimumTimeBetweenChecksNs(minimumTimeBetweenChecksNs)
                    {
                        clear();
                    }
                    // Check if the presentation position has advanced in the last periodic time.
                    bool check(AudioStreamOut * output);
                    // Clear the internal state when the playback state changes for the output
                    // stream.
                    void clear();
                private:
                    // The minimum time between timestamp checks.
                    const nsecs_t mMinimumTimeBetweenChecksNs;
                    // Add differential check on the timestamps to see if there is a change in the
                    // timestamp frame position between the last call to check.
                    uint64_t mPreviousPosition;
                    // The time at which the last check occurred, to ensure we don't check too
                    // frequently, giving the Audio HAL enough time to update its timestamps.
                    nsecs_t mPreviousNs;
                    // The valued is latched so we don't check timestamps too frequently.
                    bool mLatchedValue;
                };
                IsTimestampAdvancing mIsTimestampAdvancing;

    virtual     void flushHw_l() {
                    mIsTimestampAdvancing.clear();
                }
};

class MixerThread : public PlaybackThread,
                    public StreamOutHalInterfaceLatencyModeCallback  {
public:
    MixerThread(const sp<IAfThreadCallback>& afThreadCallback,
                AudioStreamOut* output,
                audio_io_handle_t id,
                bool systemReady,
                type_t type = MIXER,
                audio_config_base_t *mixerConfig = nullptr);
    ~MixerThread() override;

    // RefBase
    void onFirstRef() override;

                // StreamOutHalInterfaceLatencyModeCallback
                void        onRecommendedLatencyModeChanged(
            std::vector<audio_latency_mode_t> modes) final;

    // Thread virtuals

    bool checkForNewParameter_l(const String8& keyValuePair, status_t& status) final
            REQUIRES(mutex());

    bool isTrackAllowed_l(
                                    audio_channel_mask_t channelMask, audio_format_t format,
            audio_session_t sessionId, uid_t uid) const final REQUIRES(mutex());
protected:
    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) override
            REQUIRES(mutex(), ThreadBase_ThreadLoop);
    uint32_t idleSleepTimeUs() const final;
    uint32_t suspendSleepTimeUs() const final;
    void cacheParameters_l() override REQUIRES(mutex(), ThreadBase_ThreadLoop);

    void acquireWakeLock_l() final REQUIRES(mutex()) {
        PlaybackThread::acquireWakeLock_l();
        if (hasFastMixer()) {
            mFastMixer->setBoottimeOffset(
                    mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME]);
        }
    }

    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());

    // threadLoop snippets
    ssize_t threadLoop_write() override REQUIRES(ThreadBase_ThreadLoop);
    void threadLoop_standby() override REQUIRES(ThreadBase_ThreadLoop);
    void threadLoop_mix() override REQUIRES(ThreadBase_ThreadLoop);
    void threadLoop_sleepTime() override REQUIRES(ThreadBase_ThreadLoop);
    uint32_t correctLatency_l(uint32_t latency) const final REQUIRES(mutex());

    status_t createAudioPatch_l(
            const struct audio_patch* patch, audio_patch_handle_t* handle)
            final REQUIRES(mutex());
    status_t releaseAudioPatch_l(const audio_patch_handle_t handle) final REQUIRES(mutex());

                AudioMixer* mAudioMixer;    // normal mixer

            // Support low latency mode by default as unless explicitly indicated by the audio HAL
            // we assume the audio path is compatible with the head tracking latency requirements
            std::vector<audio_latency_mode_t> mSupportedLatencyModes = {AUDIO_LATENCY_MODE_LOW};
            // default to invalid value to force first update to the audio HAL
            audio_latency_mode_t mSetLatencyMode =
                    (audio_latency_mode_t)AUDIO_LATENCY_MODE_INVALID;

            // Bluetooth Variable latency control logic is enabled or disabled for this thread
            std::atomic_bool mBluetoothLatencyModesEnabled;

private:
                // one-time initialization, no locks required
                sp<FastMixer>     mFastMixer;     // non-0 if there is also a fast mixer
                sp<AudioWatchdog> mAudioWatchdog; // non-0 if there is an audio watchdog thread

                // contents are not guaranteed to be consistent, no locks required
                FastMixerDumpState mFastMixerDumpState;
#ifdef STATE_QUEUE_DUMP
                StateQueueObserverDump mStateQueueObserverDump;
                StateQueueMutatorDump  mStateQueueMutatorDump;
#endif
                AudioWatchdogDump mAudioWatchdogDump;

                // accessible only within the threadLoop(), no locks required
                //          mFastMixer->sq()    // for mutating and pushing state
    int32_t mFastMixerFutex GUARDED_BY(ThreadBase_ThreadLoop);  // for cold idle

                std::atomic_bool mMasterMono;
public:
    virtual     bool        hasFastMixer() const { return mFastMixer != 0; }
    virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const {
                              ALOG_ASSERT(fastIndex < FastMixerState::sMaxFastTracks);
                              return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
                            }

    status_t threadloop_getHalTimestamp_l(
            ExtendedTimestamp *timestamp) const override
            REQUIRES(mutex(), ThreadBase_ThreadLoop) {
                                if (mNormalSink.get() != nullptr) {
                                    return mNormalSink->getTimestamp(*timestamp);
                                }
                                return INVALID_OPERATION;
                            }

                status_t    getSupportedLatencyModes(
                                    std::vector<audio_latency_mode_t>* modes) override;

                status_t    setBluetoothVariableLatencyEnabled(bool enabled) override;

protected:
    virtual     void       setMasterMono_l(bool mono) {
                               mMasterMono.store(mono);
                               if (mFastMixer != nullptr) { /* hasFastMixer() */
                                   mFastMixer->setMasterMono(mMasterMono);
                               }
                           }
                // the FastMixer performs mono blend if it exists.
                // Blending with limiter is not idempotent,
                // and blending without limiter is idempotent but inefficient to do twice.
    virtual     bool       requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }

    void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex {
                               mMasterBalance.store(balance);
                               if (hasFastMixer()) {
                                   mFastMixer->setMasterBalance(balance);
                               }
                           }

    void updateHalSupportedLatencyModes_l() REQUIRES(mutex());
    void onHalLatencyModesChanged_l() override REQUIRES(mutex());
    void setHalLatencyMode_l() override REQUIRES(mutex());
};

class DirectOutputThread : public PlaybackThread, public virtual IAfDirectOutputThread {
public:

    sp<IAfDirectOutputThread> asIAfDirectOutputThread() final {
        return sp<IAfDirectOutputThread>::fromExisting(this);
    }

    DirectOutputThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut* output,
                       audio_io_handle_t id, bool systemReady,
                       const audio_offload_info_t& offloadInfo)
        : DirectOutputThread(afThreadCallback, output, id, DIRECT, systemReady, offloadInfo) { }

    ~DirectOutputThread() override;

    status_t selectPresentation(int presentationId, int programId) final;

    // Thread virtuals

    virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
            status_t& status) REQUIRES(mutex());

    void flushHw_l() override REQUIRES(mutex(), ThreadBase_ThreadLoop);

    void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex;

protected:
    virtual     uint32_t    activeSleepTimeUs() const;
    virtual     uint32_t    idleSleepTimeUs() const;
    virtual     uint32_t    suspendSleepTimeUs() const;
    virtual void cacheParameters_l() REQUIRES(mutex(), ThreadBase_ThreadLoop);

    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());

    // threadLoop snippets
    virtual mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove)
            REQUIRES(mutex(), ThreadBase_ThreadLoop);
    virtual void threadLoop_mix() REQUIRES(ThreadBase_ThreadLoop);
    virtual void threadLoop_sleepTime() REQUIRES(ThreadBase_ThreadLoop);
    virtual void threadLoop_exit() REQUIRES(ThreadBase_ThreadLoop);
    virtual bool shouldStandby_l() REQUIRES(mutex());

    virtual void onAddNewTrack_l() REQUIRES(mutex());

    const       audio_offload_info_t mOffloadInfo;

    audioflinger::MonotonicFrameCounter mMonotonicFrameCounter;  // for VolumeShaper
    bool mVolumeShaperActive = false;

    DirectOutputThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut* output,
                       audio_io_handle_t id, ThreadBase::type_t type, bool systemReady,
                       const audio_offload_info_t& offloadInfo);
    void processVolume_l(IAfTrack *track, bool lastTrack) REQUIRES(mutex());
    bool isTunerStream() const { return (mOffloadInfo.content_id > 0); }

    // prepareTracks_l() tells threadLoop_mix() the name of the single active track
    sp<IAfTrack>               mActiveTrack;

    wp<IAfTrack>               mPreviousTrack;         // used to detect track switch

    // This must be initialized for initial condition of mMasterBalance = 0 (disabled).
    float                   mMasterBalanceLeft = 1.f;
    float                   mMasterBalanceRight = 1.f;

public:
    virtual     bool        hasFastMixer() const { return false; }

    virtual int64_t computeWaitTimeNs_l() const override REQUIRES(mutex());

    status_t    threadloop_getHalTimestamp_l(ExtendedTimestamp *timestamp) const override {
                    // For DIRECT and OFFLOAD threads, query the output sink directly.
                    if (mOutput != nullptr) {
                        uint64_t uposition64;
                        struct timespec time;
                        if (mOutput->getPresentationPosition(
                                &uposition64, &time) == OK) {
                            timestamp->mPosition[ExtendedTimestamp::LOCATION_KERNEL]
                                    = (int64_t)uposition64;
                            timestamp->mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]
                                    = audio_utils_ns_from_timespec(&time);
                            return NO_ERROR;
                        }
                    }
                    return INVALID_OPERATION;
                }
};

class OffloadThread : public DirectOutputThread {
public:

    OffloadThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut* output,
                  audio_io_handle_t id, bool systemReady,
                  const audio_offload_info_t& offloadInfo);
    virtual                 ~OffloadThread() {};
    void flushHw_l() final REQUIRES(mutex(), ThreadBase_ThreadLoop);

protected:
    // threadLoop snippets
    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) final
            REQUIRES(mutex(), ThreadBase_ThreadLoop);
    void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);

    bool waitingAsyncCallback() final;
    bool waitingAsyncCallback_l() final REQUIRES(mutex());
    void invalidateTracks(audio_stream_type_t streamType) final EXCLUDES_ThreadBase_Mutex;
    void invalidateTracks(std::set<audio_port_handle_t>& portIds) final EXCLUDES_ThreadBase_Mutex;

    bool keepWakeLock() const final { return (mKeepWakeLock || (mDrainSequence & 1)); }

private:
    size_t      mPausedWriteLength;     // length in bytes of write interrupted by pause
    size_t      mPausedBytesRemaining;  // bytes still waiting in mixbuffer after resume
    bool        mKeepWakeLock;          // keep wake lock while waiting for write callback
};

class AsyncCallbackThread : public Thread {
public:
    explicit AsyncCallbackThread(const wp<PlaybackThread>& playbackThread);

    // Thread virtuals
    bool threadLoop() final;

    // RefBase
    void onFirstRef() final;

            void        exit();
            void        setWriteBlocked(uint32_t sequence);
            void        resetWriteBlocked();
            void        setDraining(uint32_t sequence);
            void        resetDraining();
            void        setAsyncError(bool isHardError);

private:
    const wp<PlaybackThread>   mPlaybackThread;
    // mWriteAckSequence corresponds to the last write sequence passed by the offload thread via
    // setWriteBlocked(). The sequence is shifted one bit to the left and the lsb is used
    // to indicate that the callback has been received via resetWriteBlocked()
    uint32_t                   mWriteAckSequence;
    // mDrainSequence corresponds to the last drain sequence passed by the offload thread via
    // setDraining(). The sequence is shifted one bit to the left and the lsb is used
    // to indicate that the callback has been received via resetDraining()
    uint32_t                   mDrainSequence;
    audio_utils::condition_variable mWaitWorkCV;
    mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kAsyncCallbackThread_Mutex};
    enum AsyncError { ASYNC_ERROR_NONE, ASYNC_ERROR_SOFT, ASYNC_ERROR_HARD };
    AsyncError                 mAsyncError;

    audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::AsyncCallbackThread_Mutex) {
        return mMutex;
    }
};

class DuplicatingThread : public MixerThread, public IAfDuplicatingThread {
public:
    DuplicatingThread(const sp<IAfThreadCallback>& afThreadCallback,
            IAfPlaybackThread* mainThread,
                      audio_io_handle_t id, bool systemReady);
    ~DuplicatingThread() override;

    sp<IAfDuplicatingThread> asIAfDuplicatingThread() final {
        return sp<IAfDuplicatingThread>::fromExisting(this);
    }

    // Thread virtuals
    void addOutputTrack(IAfPlaybackThread* thread) final EXCLUDES_ThreadBase_Mutex;
    void removeOutputTrack(IAfPlaybackThread* thread) final EXCLUDES_ThreadBase_Mutex;
    uint32_t waitTimeMs() const final { return mWaitTimeMs; }

                void        sendMetadataToBackend_l(
            const StreamOutHalInterface::SourceMetadata& metadata) final REQUIRES(mutex());
protected:
    virtual     uint32_t    activeSleepTimeUs() const;
    void dumpInternals_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());

private:
    bool outputsReady() REQUIRES(ThreadBase_ThreadLoop);
protected:
    // threadLoop snippets
    void threadLoop_mix() final REQUIRES(ThreadBase_ThreadLoop);
    void threadLoop_sleepTime() final REQUIRES(ThreadBase_ThreadLoop);
    ssize_t threadLoop_write() final REQUIRES(ThreadBase_ThreadLoop);
    void threadLoop_standby() final REQUIRES(ThreadBase_ThreadLoop);
    void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);
    void cacheParameters_l() final REQUIRES(mutex(), ThreadBase_ThreadLoop);

private:
    // called from threadLoop, addOutputTrack, removeOutputTrack
    void updateWaitTime_l() REQUIRES(mutex());
protected:
    void saveOutputTracks() final REQUIRES(mutex(), ThreadBase_ThreadLoop);
    void clearOutputTracks() final REQUIRES(mutex(), ThreadBase_ThreadLoop);
private:

                uint32_t    mWaitTimeMs;
    // NO_THREAD_SAFETY_ANALYSIS  GUARDED_BY(ThreadBase_ThreadLoop)
    SortedVector <sp<IAfOutputTrack>> outputTracks;
    SortedVector <sp<IAfOutputTrack>> mOutputTracks GUARDED_BY(mutex());
public:
    virtual     bool        hasFastMixer() const { return false; }
                status_t    threadloop_getHalTimestamp_l(
            ExtendedTimestamp *timestamp) const override REQUIRES(mutex()) {
        if (mOutputTracks.size() > 0) {
            // forward the first OutputTrack's kernel information for timestamp.
            const ExtendedTimestamp trackTimestamp =
                    mOutputTracks[0]->getClientProxyTimestamp();
            if (trackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] > 0) {
                timestamp->mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] =
                        trackTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL];
                timestamp->mPosition[ExtendedTimestamp::LOCATION_KERNEL] =
                        trackTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL];
                return OK;  // discard server timestamp - that's ignored.
            }
        }
        return INVALID_OPERATION;
    }
};

class SpatializerThread : public MixerThread {
public:
    SpatializerThread(const sp<IAfThreadCallback>& afThreadCallback,
                           AudioStreamOut* output,
                           audio_io_handle_t id,
                           bool systemReady,
                           audio_config_base_t *mixerConfig);

    bool hasFastMixer() const final { return false; }

    status_t setRequestedLatencyMode(audio_latency_mode_t mode) final EXCLUDES_ThreadBase_Mutex;

protected:
    void checkOutputStageEffects() final
            REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
    void setHalLatencyMode_l() final REQUIRES(mutex());

    void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);

private:
            // Do not request a specific mode by default
            audio_latency_mode_t mRequestedLatencyMode = AUDIO_LATENCY_MODE_FREE;

            sp<IAfEffectHandle> mFinalDownMixer;
};

// record thread
class RecordThread : public IAfRecordThread, public ThreadBase
{
    friend class ResamplerBufferProvider;
public:
    sp<IAfRecordThread> asIAfRecordThread() final {
        return sp<IAfRecordThread>::fromExisting(this);
    }

            RecordThread(const sp<IAfThreadCallback>& afThreadCallback,
                    AudioStreamIn *input,
                    audio_io_handle_t id,
                    bool systemReady
                    );
    ~RecordThread() override;

    // no addTrack_l ?
    void destroyTrack_l(const sp<IAfRecordTrack>& track) final REQUIRES(mutex());
    void removeTrack_l(const sp<IAfRecordTrack>& track) final REQUIRES(mutex());

    // Thread virtuals
    bool threadLoop() final REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
    void preExit() final EXCLUDES_ThreadBase_Mutex;

    // RefBase
    void onFirstRef() final EXCLUDES_ThreadBase_Mutex;

    status_t initCheck() const final { return mInput == nullptr ? NO_INIT : NO_ERROR; }

    sp<MemoryDealer> readOnlyHeap() const final { return mReadOnlyHeap; }

    sp<IMemory> pipeMemory() const final { return mPipeMemory; }

    sp<IAfRecordTrack> createRecordTrack_l(
                    const sp<Client>& client,
                    const audio_attributes_t& attr,
                    uint32_t *pSampleRate,
                    audio_format_t format,
                    audio_channel_mask_t channelMask,
                    size_t *pFrameCount,
                    audio_session_t sessionId,
                    size_t *pNotificationFrameCount,
                    pid_t creatorPid,
                    const AttributionSourceState& attributionSource,
                    audio_input_flags_t *flags,
                    pid_t tid,
                    status_t *status /*non-NULL*/,
                    audio_port_handle_t portId,
                    int32_t maxSharedAudioHistoryMs) final
            REQUIRES(audio_utils::AudioFlinger_Mutex) EXCLUDES_ThreadBase_Mutex;

            status_t start(IAfRecordTrack* recordTrack,
                              AudioSystem::sync_event_t event,
            audio_session_t triggerSession) final EXCLUDES_ThreadBase_Mutex;

            // ask the thread to stop the specified track, and
            // return true if the caller should then do it's part of the stopping process
    bool stop(IAfRecordTrack* recordTrack) final EXCLUDES_ThreadBase_Mutex;
    AudioStreamIn* getInput() const final { return mInput; }
    AudioStreamIn* clearInput() final;

            // TODO(b/291317898) Unify with IAfThreadBase
            virtual sp<StreamHalInterface> stream() const;


    virtual bool checkForNewParameter_l(const String8& keyValuePair,
                                               status_t& status) REQUIRES(mutex());
    virtual void cacheParameters_l() REQUIRES(mutex(), ThreadBase_ThreadLoop) {}
    virtual String8 getParameters(const String8& keys) EXCLUDES_ThreadBase_Mutex;

    // Hold either the AudioFlinger::mutex or the ThreadBase::mutex
    void ioConfigChanged_l(audio_io_config_event_t event, pid_t pid = 0,
            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final;
    virtual status_t    createAudioPatch_l(const struct audio_patch *patch,
            audio_patch_handle_t *handle) REQUIRES(mutex());
    virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle) REQUIRES(mutex());
    void updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override
            EXCLUDES_ThreadBase_Mutex;
    void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs) override REQUIRES(mutex());

    void addPatchTrack(const sp<IAfPatchRecord>& record) final EXCLUDES_ThreadBase_Mutex;
    void deletePatchTrack(const sp<IAfPatchRecord>& record) final EXCLUDES_ThreadBase_Mutex;

    void readInputParameters_l() REQUIRES(mutex());
    uint32_t getInputFramesLost() const final EXCLUDES_ThreadBase_Mutex;

    virtual status_t addEffectChain_l(const sp<IAfEffectChain>& chain) REQUIRES(mutex());
    virtual size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) REQUIRES(mutex());
    uint32_t hasAudioSession_l(audio_session_t sessionId) const override REQUIRES(mutex()) {
                         return ThreadBase::hasAudioSession_l(sessionId, mTracks);
                     }

            // Return the set of unique session IDs across all tracks.
            // The keys are the session IDs, and the associated values are meaningless.
            // FIXME replace by Set [and implement Bag/Multiset for other uses].
            KeyedVector<audio_session_t, bool> sessionIds() const;

    status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) override
            EXCLUDES_ThreadBase_Mutex;
            bool     isValidSyncEvent(const sp<audioflinger::SyncEvent>& event) const override;

    static void syncStartEventCallback(const wp<audioflinger::SyncEvent>& event);

    virtual size_t      frameCount() const { return mFrameCount; }
    bool hasFastCapture() const final { return mFastCapture != 0; }
    virtual void        toAudioPortConfig(struct audio_port_config *config);

    virtual status_t checkEffectCompatibility_l(const effect_descriptor_t *desc,
            audio_session_t sessionId) REQUIRES(mutex());

    virtual void acquireWakeLock_l() REQUIRES(mutex()) {
                            ThreadBase::acquireWakeLock_l();
        mActiveTracks.updatePowerState_l(this, true /* force */);
                        }

    void checkBtNrec() final EXCLUDES_ThreadBase_Mutex;

            // Sets the UID records silence
    void setRecordSilenced(audio_port_handle_t portId, bool silenced) final
            EXCLUDES_ThreadBase_Mutex;

    status_t getActiveMicrophones(
            std::vector<media::MicrophoneInfoFw>* activeMicrophones) const final
            EXCLUDES_ThreadBase_Mutex;
    status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction) final
            EXCLUDES_ThreadBase_Mutex;
    status_t setPreferredMicrophoneFieldDimension(float zoom) final EXCLUDES_ThreadBase_Mutex;

    MetadataUpdate updateMetadata_l() override REQUIRES(mutex());

    bool fastTrackAvailable() const final { return mFastTrackAvail; }
    void setFastTrackAvailable(bool available) final { mFastTrackAvail = available; }

    bool isTimestampCorrectionEnabled_l() const override REQUIRES(mutex()) {
                            // checks popcount for exactly one device.
                            // Is currently disabled. Before enabling,
                            // verify compressed record timestamps.
                            return audio_is_input_device(mTimestampCorrectedDevice)
                && inDeviceType_l() == mTimestampCorrectedDevice;
                        }

    status_t shareAudioHistory(const std::string& sharedAudioPackageName,
                                          audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
            int64_t sharedAudioStartMs = -1) final EXCLUDES_ThreadBase_Mutex;
            status_t    shareAudioHistory_l(const std::string& sharedAudioPackageName,
                                          audio_session_t sharedSessionId = AUDIO_SESSION_NONE,
            int64_t sharedAudioStartMs = -1) REQUIRES(mutex());
    void resetAudioHistory_l() final REQUIRES(mutex());

    bool isStreamInitialized() const final {
                            return !(mInput == nullptr || mInput->stream == nullptr);
                        }

protected:
    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
    void dumpTracks_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());

private:
            // Enter standby if not already in standby, and set mStandby flag
            void    standbyIfNotAlreadyInStandby();

            // Call the HAL standby method unconditionally, and don't change mStandby flag
            void    inputStandBy();

    void checkBtNrec_l() REQUIRES(mutex());

    int32_t getOldestFront_l() REQUIRES(mutex());
    void updateFronts_l(int32_t offset) REQUIRES(mutex());

            AudioStreamIn                       *mInput;
            Source                              *mSource;
            SortedVector <sp<IAfRecordTrack>>    mTracks;
            // mActiveTracks has dual roles:  it indicates the current active track(s), and
            // is used together with mStartStopCV to indicate start()/stop() progress
            ActiveTracks<IAfRecordTrack>           mActiveTracks;

            audio_utils::condition_variable mStartStopCV;

            // resampler converts input at HAL Hz to output at AudioRecord client Hz
            void                               *mRsmpInBuffer;  // size = mRsmpInFramesOA
            size_t                              mRsmpInFrames;  // size of resampler input in frames
            size_t                              mRsmpInFramesP2;// size rounded up to a power-of-2
            size_t                              mRsmpInFramesOA;// mRsmpInFramesP2 + over-allocation

            // rolling index that is never cleared
            int32_t                             mRsmpInRear;    // last filled frame + 1

            // For dumpsys
            const sp<MemoryDealer>              mReadOnlyHeap;

            // one-time initialization, no locks required
            sp<FastCapture>                     mFastCapture;   // non-0 if there is also
                                                                // a fast capture

            // FIXME audio watchdog thread

            // contents are not guaranteed to be consistent, no locks required
            FastCaptureDumpState                mFastCaptureDumpState;
#ifdef STATE_QUEUE_DUMP
            // FIXME StateQueue observer and mutator dump fields
#endif
            // FIXME audio watchdog dump

            // accessible only within the threadLoop(), no locks required
            //          mFastCapture->sq()      // for mutating and pushing state
            int32_t     mFastCaptureFutex;      // for cold idle

            // The HAL input source is treated as non-blocking,
            // but current implementation is blocking
            sp<NBAIO_Source>                    mInputSource;
            // The source for the normal capture thread to read from: mInputSource or mPipeSource
            sp<NBAIO_Source>                    mNormalSource;
            // If a fast capture is present, the non-blocking pipe sink written to by fast capture,
            // otherwise clear
            sp<NBAIO_Sink>                      mPipeSink;
            // If a fast capture is present, the non-blocking pipe source read by normal thread,
            // otherwise clear
            sp<NBAIO_Source>                    mPipeSource;
            // Depth of pipe from fast capture to normal thread and fast clients, always power of 2
            size_t                              mPipeFramesP2;
            // If a fast capture is present, the Pipe as IMemory, otherwise clear
            sp<IMemory>                         mPipeMemory;

            // TODO: add comment and adjust size as needed
            static const size_t                 kFastCaptureLogSize = 4 * 1024;
            sp<NBLog::Writer>                   mFastCaptureNBLogWriter;

            bool                                mFastTrackAvail;    // true if fast track available
            // common state to all record threads
            std::atomic_bool                    mBtNrecSuspended;

            int64_t                             mFramesRead = 0;    // continuous running counter.

            DeviceDescriptorBaseVector          mOutDevices;

            int32_t                             mMaxSharedAudioHistoryMs = 0;
            std::string                         mSharedAudioPackageName = {};
            int32_t                             mSharedAudioStartFrames = -1;
            audio_session_t                     mSharedAudioSessionId = AUDIO_SESSION_NONE;
};

class MmapThread : public ThreadBase, public virtual IAfMmapThread
{
 public:
    MmapThread(const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
               AudioHwDevice *hwDev, const sp<StreamHalInterface>& stream, bool systemReady,
               bool isOut);

    void configure(const audio_attributes_t* attr,
                                      audio_stream_type_t streamType,
                                      audio_session_t sessionId,
                                      const sp<MmapStreamCallback>& callback,
                                      audio_port_handle_t deviceId,
            audio_port_handle_t portId) override EXCLUDES_ThreadBase_Mutex {
        audio_utils::lock_guard l(mutex());
        configure_l(attr, streamType, sessionId, callback, deviceId, portId);
    }

    void configure_l(const audio_attributes_t* attr,
            audio_stream_type_t streamType,
            audio_session_t sessionId,
            const sp<MmapStreamCallback>& callback,
            audio_port_handle_t deviceId,
            audio_port_handle_t portId) REQUIRES(mutex());

    void disconnect() final EXCLUDES_ThreadBase_Mutex;

    // MmapStreamInterface for adapter.
    status_t createMmapBuffer(int32_t minSizeFrames, struct audio_mmap_buffer_info* info) final
            EXCLUDES_ThreadBase_Mutex;
    status_t getMmapPosition(struct audio_mmap_position* position) const override
            EXCLUDES_ThreadBase_Mutex;
    status_t start(const AudioClient& client,
                   const audio_attributes_t *attr,
            audio_port_handle_t* handle) final EXCLUDES_ThreadBase_Mutex;
    status_t stop(audio_port_handle_t handle) final EXCLUDES_ThreadBase_Mutex;
    status_t standby() final EXCLUDES_ThreadBase_Mutex;
    status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) const
            EXCLUDES_ThreadBase_Mutex = 0;
    status_t reportData(const void* buffer, size_t frameCount) override EXCLUDES_ThreadBase_Mutex;

    // RefBase
    void onFirstRef() final;

    // Thread virtuals
    bool threadLoop() final REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;

    // Not in ThreadBase
    virtual void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);
    virtual void threadLoop_standby() final REQUIRES(ThreadBase_ThreadLoop);
    virtual bool shouldStandby_l() final REQUIRES(mutex()){ return false; }
    virtual status_t exitStandby_l() REQUIRES(mutex());

    status_t initCheck() const final { return mHalStream == nullptr ? NO_INIT : NO_ERROR; }
    size_t frameCount() const final { return mFrameCount; }
    bool checkForNewParameter_l(const String8& keyValuePair, status_t& status)
            final REQUIRES(mutex());
    String8 getParameters(const String8& keys) final EXCLUDES_ThreadBase_Mutex;
    void ioConfigChanged_l(audio_io_config_event_t event, pid_t pid = 0,
            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE) final
            /* holds either AF::mutex or TB::mutex */;
    void readHalParameters_l() REQUIRES(mutex());
    void cacheParameters_l() final REQUIRES(mutex(), ThreadBase_ThreadLoop) {}
    status_t createAudioPatch_l(
            const struct audio_patch* patch, audio_patch_handle_t* handle) final
            REQUIRES(mutex());
    status_t releaseAudioPatch_l(const audio_patch_handle_t handle) final
            REQUIRES(mutex());
    // NO_THREAD_SAFETY_ANALYSIS
    void toAudioPortConfig(struct audio_port_config* config) override;

    sp<StreamHalInterface> stream() const final { return mHalStream; }
    status_t addEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
    size_t removeEffectChain_l(const sp<IAfEffectChain>& chain) final REQUIRES(mutex());
    status_t checkEffectCompatibility_l(
            const effect_descriptor_t *desc, audio_session_t sessionId) final REQUIRES(mutex());

    uint32_t hasAudioSession_l(audio_session_t sessionId) const override REQUIRES(mutex()) {
                                // Note: using mActiveTracks as no mTracks here.
                                return ThreadBase::hasAudioSession_l(sessionId, mActiveTracks);
                            }
    status_t setSyncEvent(const sp<audioflinger::SyncEvent>& event) final;
    bool isValidSyncEvent(const sp<audioflinger::SyncEvent>& event) const final;

    virtual void checkSilentMode_l() REQUIRES(mutex()) {} // cannot be const (RecordThread)
    virtual void processVolume_l() REQUIRES(mutex()) {}
    void checkInvalidTracks_l() REQUIRES(mutex());

    // Not in ThreadBase
    virtual audio_stream_type_t streamType_l() const REQUIRES(mutex()) {
        return AUDIO_STREAM_DEFAULT;
    }
    virtual void invalidateTracks(audio_stream_type_t /* streamType */)
            EXCLUDES_ThreadBase_Mutex {}
    void invalidateTracks(std::set<audio_port_handle_t>& /* portIds */) override
            EXCLUDES_ThreadBase_Mutex {}

                // Sets the UID records silence
    void setRecordSilenced(
            audio_port_handle_t /* portId */, bool /* silenced */) override
            EXCLUDES_ThreadBase_Mutex {}

    bool isStreamInitialized() const override { return false; }

    void setClientSilencedState_l(audio_port_handle_t portId, bool silenced) REQUIRES(mutex()) {
                                mClientSilencedStates[portId] = silenced;
                            }

    size_t eraseClientSilencedState_l(audio_port_handle_t portId) REQUIRES(mutex()) {
                                return mClientSilencedStates.erase(portId);
                            }

    bool isClientSilenced_l(audio_port_handle_t portId) const REQUIRES(mutex()) {
                                const auto it = mClientSilencedStates.find(portId);
                                return it != mClientSilencedStates.end() ? it->second : false;
                            }

    void setClientSilencedIfExists_l(audio_port_handle_t portId, bool silenced)
            REQUIRES(mutex()) {
                                const auto it = mClientSilencedStates.find(portId);
                                if (it != mClientSilencedStates.end()) {
                                    it->second = silenced;
                                }
                            }

 protected:
    void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
    void dumpTracks_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());

                /**
                 * @brief mDeviceId  current device port unique identifier
                 */
    audio_port_handle_t mDeviceId GUARDED_BY(mutex()) = AUDIO_PORT_HANDLE_NONE;

    audio_attributes_t mAttr GUARDED_BY(mutex());
    audio_session_t mSessionId GUARDED_BY(mutex());
    audio_port_handle_t mPortId GUARDED_BY(mutex());

    wp<MmapStreamCallback> mCallback GUARDED_BY(mutex());
    sp<StreamHalInterface> mHalStream; // NO_THREAD_SAFETY_ANALYSIS
    sp<DeviceHalInterface> mHalDevice GUARDED_BY(mutex());
    AudioHwDevice* const mAudioHwDev GUARDED_BY(mutex());
    ActiveTracks<IAfMmapTrack> mActiveTracks GUARDED_BY(mutex());
    float mHalVolFloat GUARDED_BY(mutex());
    std::map<audio_port_handle_t, bool> mClientSilencedStates GUARDED_BY(mutex());

    int32_t mNoCallbackWarningCount GUARDED_BY(mutex());
    static constexpr int32_t kMaxNoCallbackWarnings = 5;
};

class MmapPlaybackThread : public MmapThread, public IAfMmapPlaybackThread,
        public virtual VolumeInterface {
public:
    MmapPlaybackThread(const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
                       AudioHwDevice *hwDev, AudioStreamOut *output, bool systemReady);

    sp<IAfMmapPlaybackThread> asIAfMmapPlaybackThread() final {
        return sp<IAfMmapPlaybackThread>::fromExisting(this);
    }

    void configure(const audio_attributes_t* attr,
                                      audio_stream_type_t streamType,
                                      audio_session_t sessionId,
                                      const sp<MmapStreamCallback>& callback,
                                      audio_port_handle_t deviceId,
            audio_port_handle_t portId) final EXCLUDES_ThreadBase_Mutex;

    AudioStreamOut* clearOutput() final EXCLUDES_ThreadBase_Mutex;

                // VolumeInterface
    void setMasterVolume(float value) final;
    // Needs implementation?
    void setMasterBalance(float /* value */) final EXCLUDES_ThreadBase_Mutex {}
    void setMasterMute(bool muted) final EXCLUDES_ThreadBase_Mutex;
    void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
    void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
    float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;

    void setMasterMute_l(bool muted) REQUIRES(mutex()) { mMasterMute = muted; }

    void invalidateTracks(audio_stream_type_t streamType) final EXCLUDES_ThreadBase_Mutex;
    void invalidateTracks(std::set<audio_port_handle_t>& portIds) final EXCLUDES_ThreadBase_Mutex;

    audio_stream_type_t streamType_l() const final REQUIRES(mutex()) {
        return mStreamType;
    }
    void checkSilentMode_l() final REQUIRES(mutex());
    void processVolume_l() final REQUIRES(mutex());

    MetadataUpdate updateMetadata_l() final REQUIRES(mutex());

    void toAudioPortConfig(struct audio_port_config* config) final;

    status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) const final;

    bool isStreamInitialized() const final {
                                return !(mOutput == nullptr || mOutput->stream == nullptr);
                            }

    status_t reportData(const void* buffer, size_t frameCount) final;

    void startMelComputation_l(const sp<audio_utils::MelProcessor>& processor) final
            REQUIRES(audio_utils::AudioFlinger_Mutex);
    void stopMelComputation_l() final
            REQUIRES(audio_utils::AudioFlinger_Mutex);

protected:
    void dumpInternals_l(int fd, const Vector<String16>& args) final REQUIRES(mutex());
    float streamVolume_l() const REQUIRES(mutex()) {
                    return mStreamTypes[mStreamType].volume;
                }
    bool streamMuted_l() const REQUIRES(mutex()) {
                    return mStreamTypes[mStreamType].mute;
                }

    stream_type_t mStreamTypes[AUDIO_STREAM_CNT] GUARDED_BY(mutex());
    audio_stream_type_t mStreamType GUARDED_BY(mutex());
    float mMasterVolume GUARDED_BY(mutex());
    bool mMasterMute GUARDED_BY(mutex());
    AudioStreamOut* mOutput;  // NO_THREAD_SAFETY_ANALYSIS

    mediautils::atomic_sp<audio_utils::MelProcessor> mMelProcessor;  // locked internally
};

class MmapCaptureThread : public MmapThread, public IAfMmapCaptureThread
{
public:
    MmapCaptureThread(const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
                      AudioHwDevice *hwDev, AudioStreamIn *input, bool systemReady);

    sp<IAfMmapCaptureThread> asIAfMmapCaptureThread() final {
        return sp<IAfMmapCaptureThread>::fromExisting(this);
    }

    AudioStreamIn* clearInput() final EXCLUDES_ThreadBase_Mutex;

    status_t exitStandby_l() REQUIRES(mutex()) final;

    MetadataUpdate updateMetadata_l() final REQUIRES(mutex());
    void processVolume_l() final REQUIRES(mutex());
    void setRecordSilenced(audio_port_handle_t portId, bool silenced) final
            EXCLUDES_ThreadBase_Mutex;

    void toAudioPortConfig(struct audio_port_config* config) final;

    status_t getExternalPosition(uint64_t* position, int64_t* timeNanos) const final;

    bool isStreamInitialized() const final {
                                   return !(mInput == nullptr || mInput->stream == nullptr);
                               }

protected:

    AudioStreamIn* mInput;  // NO_THREAD_SAFETY_ANALYSIS
};

class BitPerfectThread : public MixerThread {
public:
    BitPerfectThread(const sp<IAfThreadCallback>& afThreadCallback, AudioStreamOut *output,
                     audio_io_handle_t id, bool systemReady);

    void setTracksInternalMute(std::map<audio_port_handle_t, bool>* tracksInternalMuted)
            final EXCLUDES_ThreadBase_Mutex;

protected:
    mixer_state prepareTracks_l(Vector<sp<IAfTrack>>* tracksToRemove) final
            REQUIRES(mutex(), ThreadBase_ThreadLoop);
    void threadLoop_mix() final REQUIRES(ThreadBase_ThreadLoop);

private:
    sp<IAfTrack> getTrackToStreamBitPerfectly_l() REQUIRES(mutex());

    // These variables are only accessed on the threadLoop; hence need no mutex.
    bool mIsBitPerfect GUARDED_BY(ThreadBase_ThreadLoop) = false;
    float mVolumeLeft GUARDED_BY(ThreadBase_ThreadLoop) = 0.f;
    float mVolumeRight GUARDED_BY(ThreadBase_ThreadLoop) = 0.f;
};

} // namespace android
