AudioFlinger: Better handling for master volume/mute

(cherry picked from commit 93d906837e0e89aa1d9c913ab2b531b809f9bb9e)

> AudioFlinger: Better handling for master volume/mute
>
> Changes to address bug 6842827.
>
> When a HAL is loaded, cache whether or not the HAL supports
> set_master_volume/mute in the AudioHwDevice structure.  Store an
> AudioHwDevice in AudioStream(In|Out) structures instead of just an
> audio_he_device_t.  This give threads (PlaybackThreads in
> particular) access to the cached capabilities.
>
> When setting master volume/mute, change the system to always set the
> setting on all HAL which support it and also to set the setting on all
> PlaybackThreads.  Change PlaybackThreads to apply the setting at the
> in SW mix stage of the pipeline if its assigned HAL does not support
> the setting, or to ignore the setting of the assigned HAL does support
> it.
>
> Change-Id: Ia14137a30b4c3ee6f2d7ddcc8cba87bf5eec87f4
> Signed-off-by: John Grossman <johngro@google.com>

Change-Id: Icb6bc13764e100a2003eb1dee2231132ab287d98
Signed-off-by: John Grossman <johngro@google.com>
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 41ae70e..125ec3a 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -216,11 +216,7 @@
       mPrimaryHardwareDev(NULL),
       mHardwareStatus(AUDIO_HW_IDLE),
       mMasterVolume(1.0f),
-      mMasterVolumeSW(1.0f),
-      mMasterVolumeSupportLvl(MVS_NONE),
       mMasterMute(false),
-      mMasterMuteSW(false),
-      mMasterMuteSupportLvl(MMS_NONE),
       mNextUniqueId(1),
       mMode(AUDIO_MODE_INVALID),
       mBtNrecIsOff(false)
@@ -275,7 +271,9 @@
 };
 #define ARRAY_SIZE(x) (sizeof((x))/sizeof(((x)[0])))
 
-audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(audio_module_handle_t module, audio_devices_t devices)
+AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
+        audio_module_handle_t module,
+        audio_devices_t devices)
 {
     // if module is 0, the request comes from an old policy manager and we should load
     // well known modules
@@ -286,16 +284,17 @@
         }
     } else {
         // check a match for the requested module handle
-        AudioHwDevice *audioHwdevice = mAudioHwDevs.valueFor(module);
-        if (audioHwdevice != NULL) {
-            return audioHwdevice->hwDevice();
+        AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);
+        if (audioHwDevice != NULL) {
+            return audioHwDevice;
         }
     }
     // then try to find a module supporting the requested device.
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-        audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+        AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);
+        audio_hw_device_t *dev = audioHwDevice->hwDevice();
         if ((dev->get_supported_devices(dev) & devices) == devices)
-            return dev;
+            return audioHwDevice;
     }
 
     return NULL;
@@ -604,30 +603,27 @@
         return PERMISSION_DENIED;
     }
 
-    float swmv = value;
-
     Mutex::Autolock _l(mLock);
+    mMasterVolume = value;
 
-    // when hw supports master volume, don't scale in sw mixer
-    if (MVS_NONE != mMasterVolumeSupportLvl) {
-        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-            AutoMutex lock(mHardwareLock);
-            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+    // Set master volume in the HALs which support it.
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        AutoMutex lock(mHardwareLock);
+        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
 
-            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-            if (NULL != dev->set_master_volume) {
-                dev->set_master_volume(dev, value);
-            }
-            mHardwareStatus = AUDIO_HW_IDLE;
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        if (dev->canSetMasterVolume()) {
+            dev->hwDevice()->set_master_volume(dev->hwDevice(), value);
         }
-
-        swmv = 1.0;
+        mHardwareStatus = AUDIO_HW_IDLE;
     }
 
-    mMasterVolume   = value;
-    mMasterVolumeSW = swmv;
+    // Now set the master volume in each playback thread.  Playback threads
+    // assigned to HALs which do not have master volume support will apply
+    // master volume during the mix operation.  Threads with HALs which do
+    // support master volume will simply ignore the setting.
     for (size_t i = 0; i < mPlaybackThreads.size(); i++)
-        mPlaybackThreads.valueAt(i)->setMasterVolume(swmv);
+        mPlaybackThreads.valueAt(i)->setMasterVolume(value);
 
     return NO_ERROR;
 }
@@ -650,8 +646,9 @@
 
     { // scope for the lock
         AutoMutex lock(mHardwareLock);
+        audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
         mHardwareStatus = AUDIO_HW_SET_MODE;
-        ret = mPrimaryHardwareDev->set_mode(mPrimaryHardwareDev, mode);
+        ret = dev->set_mode(dev, mode);
         mHardwareStatus = AUDIO_HW_IDLE;
     }
 
@@ -678,8 +675,9 @@
     }
 
     AutoMutex lock(mHardwareLock);
+    audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
     mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
-    ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state);
+    ret = dev->set_mic_mute(dev, state);
     mHardwareStatus = AUDIO_HW_IDLE;
     return ret;
 }
@@ -693,8 +691,9 @@
 
     bool state = AUDIO_MODE_INVALID;
     AutoMutex lock(mHardwareLock);
+    audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
     mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
-    mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
+    dev->get_mic_mute(dev, &state);
     mHardwareStatus = AUDIO_HW_IDLE;
     return state;
 }
@@ -711,30 +710,27 @@
         return PERMISSION_DENIED;
     }
 
-    bool swmm = muted;
+    Mutex::Autolock _l(mLock);
+    mMasterMute = muted;
 
-    // when hw supports master mute, don't mute in sw mixer
-    if (MMS_NONE != mMasterMuteSupportLvl) {
-        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-            AutoMutex lock(mHardwareLock);
-            audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
+    // Set master mute in the HALs which support it.
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        AutoMutex lock(mHardwareLock);
+        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
 
-            mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
-            if (NULL != dev->set_master_mute) {
-                dev->set_master_mute(dev, muted);
-            }
-            mHardwareStatus = AUDIO_HW_IDLE;
+        mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
+        if (dev->canSetMasterMute()) {
+            dev->hwDevice()->set_master_mute(dev->hwDevice(), muted);
         }
-
-        swmm = false;
+        mHardwareStatus = AUDIO_HW_IDLE;
     }
 
-    Mutex::Autolock _l(mLock);
-    // This is an optimization, so PlaybackThread doesn't have to look at the one from AudioFlinger
-    mMasterMute   = muted;
-    mMasterMuteSW = swmm;
+    // Now set the master mute in each playback thread.  Playback threads
+    // assigned to HALs which do not have master mute support will apply master
+    // mute during the mix operation.  Threads with HALs which do support master
+    // mute will simply ignore the setting.
     for (size_t i = 0; i < mPlaybackThreads.size(); i++)
-        mPlaybackThreads.valueAt(i)->setMasterMute(swmm);
+        mPlaybackThreads.valueAt(i)->setMasterMute(muted);
 
     return NO_ERROR;
 }
@@ -745,59 +741,20 @@
     return masterVolume_l();
 }
 
-float AudioFlinger::masterVolumeSW() const
-{
-    Mutex::Autolock _l(mLock);
-    return masterVolumeSW_l();
-}
-
 bool AudioFlinger::masterMute() const
 {
     Mutex::Autolock _l(mLock);
     return masterMute_l();
 }
 
-bool AudioFlinger::masterMuteSW() const
-{
-    Mutex::Autolock _l(mLock);
-    return masterMuteSW_l();
-}
-
 float AudioFlinger::masterVolume_l() const
 {
-    if (MVS_FULL == mMasterVolumeSupportLvl) {
-        float ret_val;
-        AutoMutex lock(mHardwareLock);
-
-        mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
-        ALOG_ASSERT((NULL != mPrimaryHardwareDev) &&
-                    (NULL != mPrimaryHardwareDev->get_master_volume),
-                "can't get master volume");
-
-        mPrimaryHardwareDev->get_master_volume(mPrimaryHardwareDev, &ret_val);
-        mHardwareStatus = AUDIO_HW_IDLE;
-        return ret_val;
-    }
-
     return mMasterVolume;
 }
 
 bool AudioFlinger::masterMute_l() const
 {
-    if (MMS_FULL == mMasterMuteSupportLvl) {
-        bool ret_val;
-        AutoMutex lock(mHardwareLock);
-
-        mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
-        assert(NULL != mPrimaryHardwareDev);
-        assert(NULL != mPrimaryHardwareDev->get_master_mute);
-
-        mPrimaryHardwareDev->get_master_mute(mPrimaryHardwareDev, &ret_val);
-        mHardwareStatus = AUDIO_HW_IDLE;
-        return ret_val;
-    }
-
-     return mMasterMute;
+    return mMasterMute;
 }
 
 status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
@@ -1023,7 +980,8 @@
         channel_mask: channelMask,
         format: format,
     };
-    size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, &config);
+    audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
+    size_t size = dev->get_input_buffer_size(dev, &config);
     mHardwareStatus = AUDIO_HW_IDLE;
     return size;
 }
@@ -1052,8 +1010,9 @@
     }
 
     AutoMutex lock(mHardwareLock);
+    audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
     mHardwareStatus = AUDIO_HW_SET_VOICE_VOLUME;
-    ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value);
+    ret = dev->set_voice_volume(dev, value);
     mHardwareStatus = AUDIO_HW_IDLE;
 
     return ret;
@@ -1551,14 +1510,8 @@
                                              type_t type)
     :   ThreadBase(audioFlinger, id, device, type),
         mMixBuffer(NULL), mSuspended(0), mBytesWritten(0),
-        // Assumes constructor is called by AudioFlinger with it's mLock held,
-        // but it would be safer to explicitly pass initial masterMute as parameter
-        mMasterMute(audioFlinger->masterMuteSW_l()),
         // mStreamTypes[] initialized in constructor body
         mOutput(output),
-        // Assumes constructor is called by AudioFlinger with it's mLock held,
-        // but it would be safer to explicitly pass initial masterVolume as parameter
-        mMasterVolume(audioFlinger->masterVolumeSW_l()),
         mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
         mMixerStatus(MIXER_IDLE),
         mMixerStatusIgnoringFastTracks(MIXER_IDLE),
@@ -1569,6 +1522,25 @@
 {
     snprintf(mName, kNameLength, "AudioOut_%X", id);
 
+    // Assumes constructor is called by AudioFlinger with it's mLock held, but
+    // it would be safer to explicitly pass initial masterVolume/masterMute as
+    // parameter.
+    //
+    // If the HAL we are using has support for master volume or master mute,
+    // then do not attenuate or mute during mixing (just leave the volume at 1.0
+    // and the mute set to false).
+    mMasterVolume = audioFlinger->masterVolume_l();
+    mMasterMute = audioFlinger->masterMute_l();
+    if (mOutput && mOutput->audioHwDev) {
+        if (mOutput->audioHwDev->canSetMasterVolume()) {
+            mMasterVolume = 1.0;
+        }
+
+        if (mOutput->audioHwDev->canSetMasterMute()) {
+            mMasterMute = false;
+        }
+    }
+
     readOutputParameters();
 
     // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor
@@ -1888,13 +1860,25 @@
 void AudioFlinger::PlaybackThread::setMasterVolume(float value)
 {
     Mutex::Autolock _l(mLock);
-    mMasterVolume = value;
+    // Don't apply master volume in SW if our HAL can do it for us.
+    if (mOutput && mOutput->audioHwDev &&
+        mOutput->audioHwDev->canSetMasterVolume()) {
+        mMasterVolume = 1.0;
+    } else {
+        mMasterVolume = value;
+    }
 }
 
 void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
 {
     Mutex::Autolock _l(mLock);
-    setMasterMute_l(muted);
+    // Don't apply master mute in SW if our HAL can do it for us.
+    if (mOutput && mOutput->audioHwDev &&
+        mOutput->audioHwDev->canSetMasterMute()) {
+        mMasterMute = false;
+    } else {
+        mMasterMute = muted;
+    }
 }
 
 void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
@@ -6809,16 +6793,52 @@
         return 0;
     }
 
-    if ((mMasterVolumeSupportLvl != MVS_NONE) &&
-        (NULL != dev->set_master_volume)) {
+    // Check and cache this HAL's level of support for master mute and master
+    // volume.  If this is the first HAL opened, and it supports the get
+    // methods, use the initial values provided by the HAL as the current
+    // master mute and volume settings.
+
+    AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
+    {  // scope for auto-lock pattern
         AutoMutex lock(mHardwareLock);
+
+        if (0 == mAudioHwDevs.size()) {
+            mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+            if (NULL != dev->get_master_volume) {
+                float mv;
+                if (OK == dev->get_master_volume(dev, &mv)) {
+                    mMasterVolume = mv;
+                }
+            }
+
+            mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
+            if (NULL != dev->get_master_mute) {
+                bool mm;
+                if (OK == dev->get_master_mute(dev, &mm)) {
+                    mMasterMute = mm;
+                }
+            }
+        }
+
         mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        dev->set_master_volume(dev, mMasterVolume);
+        if ((NULL != dev->set_master_volume) &&
+            (OK == dev->set_master_volume(dev, mMasterVolume))) {
+            flags = static_cast<AudioHwDevice::Flags>(flags |
+                    AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
+        }
+
+        mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
+        if ((NULL != dev->set_master_mute) &&
+            (OK == dev->set_master_mute(dev, mMasterMute))) {
+            flags = static_cast<AudioHwDevice::Flags>(flags |
+                    AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
+        }
+
         mHardwareStatus = AUDIO_HW_IDLE;
     }
 
     audio_module_handle_t handle = nextUniqueId();
-    mAudioHwDevs.add(handle, new AudioHwDevice(name, dev));
+    mAudioHwDevs.add(handle, new AudioHwDevice(name, dev, flags));
 
     ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
           name, dev->common.module->name, dev->common.module->id, handle);
@@ -6843,7 +6863,7 @@
         format: pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT,
     };
     audio_stream_out_t *outStream = NULL;
-    audio_hw_device_t *outHwDev;
+    AudioHwDevice *outHwDev;
 
     ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %d, Channels %x, flags %x",
               module,
@@ -6863,11 +6883,12 @@
     if (outHwDev == NULL)
         return 0;
 
+    audio_hw_device_t *hwDevHal = outHwDev->hwDevice();
     audio_io_handle_t id = nextUniqueId();
 
     mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
 
-    status = outHwDev->open_output_stream(outHwDev,
+    status = hwDevHal->open_output_stream(hwDevHal,
                                           id,
                                           *pDevices,
                                           (audio_output_flags_t)flags,
@@ -6911,68 +6932,8 @@
 
             AutoMutex lock(mHardwareLock);
             mHardwareStatus = AUDIO_HW_SET_MODE;
-            outHwDev->set_mode(outHwDev, mMode);
-
-            // Determine the level of master volume/master mute support the primary
-            // audio HAL has, and set the initial master volume/mute state at the same
-            // time.
-            float initialVolume = 1.0;
-            bool initialMute = false;
-            mMasterVolumeSupportLvl = MVS_NONE;
-            mMasterMuteSupportLvl = MMS_NONE;
-
-            mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
-            if ((NULL != outHwDev->get_master_volume) &&
-                (NO_ERROR == outHwDev->get_master_volume(outHwDev, &initialVolume))) {
-                mMasterVolumeSupportLvl = MVS_FULL;
-            } else {
-                mMasterVolumeSupportLvl = MVS_SETONLY;
-                initialVolume = 1.0;
-            }
-
-            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-            if ((NULL == outHwDev->set_master_volume) ||
-                (NO_ERROR != outHwDev->set_master_volume(outHwDev, initialVolume))) {
-                mMasterVolumeSupportLvl = MVS_NONE;
-            }
-
-            mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
-            if ((NULL != outHwDev->get_master_mute) &&
-                (NO_ERROR == outHwDev->get_master_mute(outHwDev, &initialMute))) {
-                mMasterMuteSupportLvl = MMS_FULL;
-            } else {
-                mMasterMuteSupportLvl = MMS_SETONLY;
-                initialMute = 0;
-            }
-
-            mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
-            if ((NULL == outHwDev->set_master_mute) ||
-                (NO_ERROR != outHwDev->set_master_mute(outHwDev, initialMute))) {
-                mMasterMuteSupportLvl = MMS_NONE;
-            }
-
-            // now that we have a primary device, initialize master volume/mute
-            // on other devices
-            for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-                audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
-
-                if ((dev != mPrimaryHardwareDev) &&
-                    (NULL != dev->set_master_volume)) {
-                    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-                    dev->set_master_volume(dev, initialVolume);
-                }
-
-                if (NULL != dev->set_master_mute) {
-                    mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
-                    dev->set_master_mute(dev, initialMute);
-                }
-            }
-
+            hwDevHal->set_mode(hwDevHal, mMode);
             mHardwareStatus = AUDIO_HW_IDLE;
-            mMasterVolumeSW = initialVolume;
-            mMasterVolume   = initialVolume;
-            mMasterMuteSW   = initialMute;
-            mMasterMute     = initialMute;
         }
         return id;
     }
@@ -7039,7 +7000,7 @@
         AudioStreamOut *out = thread->clearOutput();
         ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
         // from now on thread->mOutput is NULL
-        out->hwDev->close_output_stream(out->hwDev, out->stream);
+        out->hwDev()->close_output_stream(out->hwDev(), out->stream);
         delete out;
     }
     return NO_ERROR;
@@ -7093,7 +7054,7 @@
     audio_format_t reqFormat = config.format;
     audio_channel_mask_t reqChannels = config.channel_mask;
     audio_stream_in_t *inStream = NULL;
-    audio_hw_device_t *inHwDev;
+    AudioHwDevice *inHwDev;
 
     if (pDevices == NULL || *pDevices == 0) {
         return 0;
@@ -7105,9 +7066,10 @@
     if (inHwDev == NULL)
         return 0;
 
+    audio_hw_device_t *inHwHal = inHwDev->hwDevice();
     audio_io_handle_t id = nextUniqueId();
 
-    status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config,
+    status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
                                         &inStream);
     ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, status %d",
             inStream,
@@ -7125,7 +7087,7 @@
         (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
         ALOGV("openInput() reopening with proposed sampling rate and channel mask");
         inStream = NULL;
-        status = inHwDev->open_input_stream(inHwDev, id, *pDevices, &config, &inStream);
+        status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream);
     }
 
     if (status == NO_ERROR && inStream != NULL) {
@@ -7183,7 +7145,7 @@
     AudioStreamIn *in = thread->clearInput();
     ALOG_ASSERT(in != NULL, "in shouldn't be NULL");
     // from now on thread->mInput is NULL
-    in->hwDev->close_input_stream(in->hwDev, in->stream);
+    in->hwDev()->close_input_stream(in->hwDev(), in->stream);
     delete in;
 
     return NO_ERROR;
@@ -7335,7 +7297,7 @@
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
         AudioStreamOut *output = thread->getOutput();
-        if (output != NULL && output->hwDev == mPrimaryHardwareDev) {
+        if (output != NULL && output->audioHwDev == mPrimaryHardwareDev) {
             return thread;
         }
     }
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1bef42c..e5176a9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -122,9 +122,7 @@
     virtual     status_t    setMasterMute(bool muted);
 
     virtual     float       masterVolume() const;
-    virtual     float       masterVolumeSW() const;
     virtual     bool        masterMute() const;
-    virtual     bool        masterMuteSW() const;
 
     virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value,
                                             audio_io_handle_t output);
@@ -258,6 +256,8 @@
                                         void *cookie);
 
 private:
+    class AudioHwDevice;    // fwd declaration for findSuitableHwDev_l
+
                audio_mode_t getMode() const { return mMode; }
 
                 bool        btNrecIsOff() const { return mBtNrecIsOff; }
@@ -271,7 +271,7 @@
     // RefBase
     virtual     void        onFirstRef();
 
-    audio_hw_device_t*      findSuitableHwDev_l(audio_module_handle_t module, audio_devices_t devices);
+    AudioHwDevice*          findSuitableHwDev_l(audio_module_handle_t module, audio_devices_t devices);
     void                    purgeStaleEffects_l();
 
     // standby delay for MIXER and DUPLICATING playback threads is read from property
@@ -1861,24 +1861,59 @@
         KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
     };
 
+    class AudioHwDevice {
+    public:
+        enum Flags {
+            AHWD_CAN_SET_MASTER_VOLUME  = 0x1,
+            AHWD_CAN_SET_MASTER_MUTE    = 0x2,
+        };
+
+        AudioHwDevice(const char *moduleName,
+                      audio_hw_device_t *hwDevice,
+                      Flags flags)
+            : mModuleName(strdup(moduleName))
+            , mHwDevice(hwDevice)
+            , mFlags(flags) { }
+        /*virtual*/ ~AudioHwDevice() { free((void *)mModuleName); }
+
+        bool canSetMasterVolume() const {
+            return (0 != (mFlags & AHWD_CAN_SET_MASTER_VOLUME));
+        }
+
+        bool canSetMasterMute() const {
+            return (0 != (mFlags & AHWD_CAN_SET_MASTER_MUTE));
+        }
+
+        const char *moduleName() const { return mModuleName; }
+        audio_hw_device_t *hwDevice() const { return mHwDevice; }
+    private:
+        const char * const mModuleName;
+        audio_hw_device_t * const mHwDevice;
+        Flags mFlags;
+    };
+
     // AudioStreamOut and AudioStreamIn are immutable, so their fields are const.
     // For emphasis, we could also make all pointers to them be "const *",
     // but that would clutter the code unnecessarily.
 
     struct AudioStreamOut {
-        audio_hw_device_t*  const hwDev;
+        AudioHwDevice* const audioHwDev;
         audio_stream_out_t* const stream;
 
-        AudioStreamOut(audio_hw_device_t *dev, audio_stream_out_t *out) :
-            hwDev(dev), stream(out) {}
+        audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); }
+
+        AudioStreamOut(AudioHwDevice *dev, audio_stream_out_t *out) :
+            audioHwDev(dev), stream(out) {}
     };
 
     struct AudioStreamIn {
-        audio_hw_device_t* const hwDev;
+        AudioHwDevice* const audioHwDev;
         audio_stream_in_t* const stream;
 
-        AudioStreamIn(audio_hw_device_t *dev, audio_stream_in_t *in) :
-            hwDev(dev), stream(in) {}
+        audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); }
+
+        AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in) :
+            audioHwDev(dev), stream(in) {}
     };
 
     // for mAudioSessionRefs only
@@ -1890,62 +1925,6 @@
         int         mCnt;
     };
 
-    enum master_volume_support {
-        // MVS_NONE:
-        // Audio HAL has no support for master volume, either setting or
-        // getting.  All master volume control must be implemented in SW by the
-        // AudioFlinger mixing core.
-        MVS_NONE,
-
-        // MVS_SETONLY:
-        // Audio HAL has support for setting master volume, but not for getting
-        // master volume (original HAL design did not include a getter).
-        // AudioFlinger needs to keep track of the last set master volume in
-        // addition to needing to set an initial, default, master volume at HAL
-        // load time.
-        MVS_SETONLY,
-
-        // MVS_FULL:
-        // Audio HAL has support both for setting and getting master volume.
-        // AudioFlinger should send all set and get master volume requests
-        // directly to the HAL.
-        MVS_FULL,
-    };
-
-    enum master_mute_support {
-        // MMS_NONE:
-        // Audio HAL has no support for master mute, either setting or getting.
-        // All master mute control must be implemented in SW by the
-        // AudioFlinger mixing core.
-        MMS_NONE,
-
-        // MMS_SETONLY:
-        // Audio HAL has support for setting master mute, but not for getting
-        // master mute.  AudioFlinger needs to keep track of the last set
-        // master mute in addition to needing to set an initial, default,
-        // master mute at HAL load time.
-        MMS_SETONLY,
-
-        // MMS_FULL:
-        // Audio HAL has support both for setting and getting master mute.
-        // AudioFlinger should send all set and get master mute requests
-        // directly to the HAL.
-        MMS_FULL,
-    };
-
-    class AudioHwDevice {
-    public:
-        AudioHwDevice(const char *moduleName, audio_hw_device_t *hwDevice) :
-            mModuleName(strdup(moduleName)), mHwDevice(hwDevice){}
-        /*virtual*/ ~AudioHwDevice() { free((void *)mModuleName); }
-
-        const char *moduleName() const { return mModuleName; }
-        audio_hw_device_t *hwDevice() const { return mHwDevice; }
-    private:
-        const char * const mModuleName;
-        audio_hw_device_t * const mHwDevice;
-    };
-
     mutable     Mutex                               mLock;
 
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;   // see ~Client()
@@ -1955,7 +1934,7 @@
                 // always take mLock before mHardwareLock
 
                 // These two fields are immutable after onFirstRef(), so no lock needed to access
-                audio_hw_device_t*                  mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
+                AudioHwDevice*                      mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
                 DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>  mAudioHwDevs;
 
     // for dump, indicates which hardware operation is currently in progress (but not stream ops)
@@ -1991,12 +1970,7 @@
 
                 // both are protected by mLock
                 float                               mMasterVolume;
-                float                               mMasterVolumeSW;
-                master_volume_support               mMasterVolumeSupportLvl;
-
                 bool                                mMasterMute;
-                bool                                mMasterMuteSW;
-                master_mute_support                 mMasterMuteSupportLvl;
 
                 DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> >    mRecordThreads;
 
@@ -2009,9 +1983,7 @@
                 Vector<AudioSessionRef*> mAudioSessionRefs;
 
                 float       masterVolume_l() const;
-                float       masterVolumeSW_l() const  { return mMasterVolumeSW; }
                 bool        masterMute_l() const;
-                bool        masterMuteSW_l() const    { return mMasterMuteSW; }
                 audio_module_handle_t loadHwModule_l(const char *name);
 
                 Vector < sp<SyncEvent> > mPendingSyncEvents; // sync events awaiting for a session