Index: /trunk/include/VBox/vmm/pdmaudioifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 61886)
+++ /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 61887)
@@ -323,10 +323,19 @@
 {
     /** Set to @c true if this stream is muted, @c false if not. */
-    bool                   fMuted;
-    /** Left channel volume. */
-    uint32_t               uLeft;
-    /** Right channel volume. */
-    uint32_t               uRight;
+    bool    fMuted;
+    /** Left channel volume.
+     *  Range is from [0 ... 255], whereas 0 specifies
+     *  the most silent and 255 the loudest value. */
+    uint8_t uLeft;
+    /** Right channel volume.
+     *  Range is from [0 ... 255], whereas 0 specifies
+     *  the most silent and 255 the loudest value. */
+    uint8_t uRight;
 } PDMAUDIOVOLUME, *PPDMAUDIOVOLUME;
+
+/** Defines the minimum volume allowed. */
+#define PDMAUDIO_VOLUME_MIN     (0)
+/** Defines the maximum volume allowed. */
+#define PDMAUDIO_VOLUME_MAX     (255)
 
 /**
@@ -354,4 +363,23 @@
 
 /**
+ * Structure for holding mixing buffer volume parameters.
+ * The volume values are in fixed point style and must
+ * be converted to/from before using with e.g. PDMAUDIOVOLUME.
+ */
+typedef struct PDMAUDMIXBUFVOL
+{
+    /** Set to @c true if this stream is muted, @c false if not. */
+    bool    fMuted;
+    /** Left volume to apply during conversion. Pass 0
+     *  to convert the original values. May not apply to
+     *  all conversion functions. */
+    uint32_t uLeft;
+    /** Right volume to apply during conversion. Pass 0
+     *  to convert the original values. May not apply to
+     *  all conversion functions. */
+    uint32_t uRight;
+} PDMAUDMIXBUFVOL, *PPDMAUDMIXBUFVOL;
+
+/**
  * Structure for holding sample conversion parameters for
  * the audioMixBufConvFromXXX / audioMixBufConvToXXX macros.
@@ -360,9 +388,13 @@
 {
     /** Number of audio samples to convert. */
-    uint32_t       cSamples;
-    /** Volume to apply during conversion. Pass 0
-     *  to convert the original values. May not apply to
-     *  all conversion functions. */
-    PDMAUDIOVOLUME Volume;
+    uint32_t        cSamples;
+    union
+    {
+        struct
+        {
+            /** Volume to use for conversion. */
+            PDMAUDMIXBUFVOL Volume;
+        } From;
+    };
 } PDMAUDMIXBUFCONVOPTS;
 /** Pointer to conversion parameters for the audio mixer.   */
@@ -435,6 +467,6 @@
     /** Intermediate structure for buffer conversion tasks. */
     PPDMAUDIOSTRMRATE         pRate;
-    /** Current volume used for mixing. */
-    PDMAUDIOVOLUME            Volume;
+    /** Internal representation of current volume used for mixing. */
+    PDMAUDMIXBUFVOL           Volume;
     /** This buffer's audio format. */
     PDMAUDIOMIXBUFFMT         AudioFmt;
Index: /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61886)
+++ /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61887)
@@ -70,5 +70,5 @@
  * value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
  *
- * Each step thus correspons to 96 / 256 or 0.375dB. Every 6dB (16 steps)
+ * Each step thus corresponds to 96 / 256 or 0.375dB. Every 6dB (16 steps)
  * represents doubling the sample value.
  *
@@ -408,11 +408,9 @@
         uint32_t cSamples = RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
         AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
-                             pOpts->cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
+                             pOpts->cSamples, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
         for (uint32_t i = 0; i < cSamples; i++) \
         { \
-            AUDMIXBUF_MACRO_LOG(("l=%#5RI16 (0x%x), r=%#5RI16 (0x%x)", paDst, *pSrc, *pSrc, *(pSrc + 1), *(pSrc + 1))); \
-            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
-            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
-            AUDMIXBUF_MACRO_LOG((" -> l=%#10RI64, r=%#10RI64\n", paDst->i64LSample, paDst->i64RSample)); \
+            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
+            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
             paDst++; \
         } \
@@ -427,10 +425,9 @@
         const uint32_t cSamples = RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
         AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
-                             cSamples, sizeof(_aType), pOpts->Volume.uLeft >> 14, pOpts->Volume.uRight)); \
+                             cSamples, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
         for (uint32_t i = 0; i < cSamples; i++) \
         { \
-            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uLeft)  >> AUDIOMIXBUF_VOL_SHIFT; \
-            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
-            AUDMIXBUF_MACRO_LOG(("%#5RI16 (0x%x) -> l=%#10RI64, r=%#10RI64\n", *pSrc, *pSrc, paDst->i64LSample, paDst->i64RSample)); \
+            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uLeft)  >> AUDIOMIXBUF_VOL_SHIFT; \
+            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
             pSrc++; \
             paDst++; \
@@ -717,4 +714,28 @@
 
 /**
+ * Converts a PDM audio volume to an internal mixing buffer volume.
+ *
+ * @returns IPRT status code.
+ * @param   pVolDst                 Where to store the converted mixing buffer volume.
+ * @param   pVolSrc                 Volume to convert.
+ */
+static int audioMixBufConvVol(PPDMAUDMIXBUFVOL pVolDst, PPDMAUDIOVOLUME pVolSrc)
+{
+    if (!pVolSrc->fMuted) /* Only change/convert the volume value if we're not muted. */
+    {
+        uint8_t uVolL = pVolSrc->uLeft  & 0xFF;
+        uint8_t uVolR = pVolSrc->uRight & 0xFF;
+
+        /** @todo Ensure that the input is in the correct range/initialized! */
+        pVolDst->uLeft  = s_aVolumeConv[uVolL] * (AUDIOMIXBUF_VOL_0DB >> 16);
+        pVolDst->uRight = s_aVolumeConv[uVolR] * (AUDIOMIXBUF_VOL_0DB >> 16);
+    }
+
+    pVolDst->fMuted = pVolSrc->fMuted;
+
+    return VINF_SUCCESS;
+}
+
+/**
  * Initializes a mixing buffer.
  *
@@ -1278,16 +1299,19 @@
     if (cToProcess)
     {
-        PFNPDMAUDIOMIXBUFCONVTO pfnConv;
+        PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
         if (pMixBuf->AudioFmt != enmFmt)
-            pfnConv = audioMixBufConvToLookup(enmFmt);
+            pfnConvTo = audioMixBufConvToLookup(enmFmt);
         else
-            pfnConv = pMixBuf->pfnConvTo;
-
-        if (pfnConv)
+            pfnConvTo = pMixBuf->pfnConvTo;
+
+        if (pfnConvTo)
         {
-            PDMAUDMIXBUFCONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
-
-            AssertPtr(pfnConv);
-            pfnConv(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
+            PDMAUDMIXBUFCONVOPTS convOpts;
+            RT_ZERO(convOpts);
+            /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
+
+            convOpts.cSamples = cToProcess;
+
+            pfnConvTo(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
 
 #ifdef DEBUG
@@ -1297,5 +1321,8 @@
         }
         else
+        {
+            AssertFailed();
             rc = VERR_NOT_SUPPORTED;
+        }
     }
     else
@@ -1348,16 +1375,5 @@
 
     if (!cbBuf)
-        return VINF_SUCCESS;
-
-    uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cUsed);
-
-    AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
-                   pMixBuf->pszName, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf), cToRead));
-
-    if (!cToRead)
-    {
-#ifdef DEBUG
-        audioMixBufDbgPrintInternal(pMixBuf);
-#endif
+    {
         if (pcRead)
             *pcRead = 0;
@@ -1365,7 +1381,30 @@
     }
 
-    PFNPDMAUDIOMIXBUFCONVTO pfnConv = audioMixBufConvToLookup(enmFmt);
-    if (!pfnConv) /* Audio format not supported. */
+    uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cUsed);
+
+    AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
+                   pMixBuf->pszName, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf), cToRead));
+
+    if (!cToRead)
+    {
+#ifdef DEBUG
+        audioMixBufDbgPrintInternal(pMixBuf);
+#endif
+        if (pcRead)
+            *pcRead = 0;
+        return VINF_SUCCESS;
+    }
+
+    PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
+    if (pMixBuf->AudioFmt != enmFmt)
+        pfnConvTo = audioMixBufConvToLookup(enmFmt);
+    else
+        pfnConvTo = pMixBuf->pfnConvTo;
+
+    if (!pfnConvTo) /* Audio format not supported. */
+    {
+        AssertFailed();
         return VERR_NOT_SUPPORTED;
+    }
 
     PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offRead;
@@ -1391,5 +1430,6 @@
 
     PDMAUDMIXBUFCONVOPTS convOpts;
-    convOpts.Volume = pMixBuf->Volume;
+    RT_ZERO(convOpts);
+    /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
 
     /* Anything to do at all? */
@@ -1397,8 +1437,10 @@
     if (cLenSrc1)
     {
+        AssertPtr(pSamplesSrc1);
+
         convOpts.cSamples = cLenSrc1;
 
         AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offRead, cLenSrc1));
-        pfnConv(pvBuf, pSamplesSrc1, &convOpts);
+        pfnConvTo(pvBuf, pSamplesSrc1, &convOpts);
     }
 
@@ -1413,5 +1455,5 @@
         AUDMIXBUF_LOG(("P2: cToRead=%RU32, offWrite=%RU32 (%zu bytes)\n", cLenSrc2, cLenSrc1,
                        AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1)));
-        pfnConv((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
+        pfnConvTo((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
     }
 
@@ -1474,12 +1516,8 @@
     AssertPtrReturnVoid(pVol);
 
-    LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight));
-
-    pMixBuf->Volume.fMuted = pVol->fMuted;
-    /** @todo Ensure that the input is in the correct range/initialized! */
-    pMixBuf->Volume.uLeft  = s_aVolumeConv[pVol->uLeft  & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
-    pMixBuf->Volume.uRight = s_aVolumeConv[pVol->uRight & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
-
-    LogFlowFunc(("\t-> lVol=%#RX32, rVol=%#RX32\n", pMixBuf->Volume.uLeft, pMixBuf->Volume.uRight));
+    LogFlowFunc(("%s: lVol=%RU8, rVol=%RU8, fMuted=%RTbool\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted));
+
+    int rc2 = audioMixBufConvVol(&pMixBuf->Volume /* Dest */, pVol /* Source */);
+    AssertRC(rc2);
 }
 
@@ -1637,22 +1675,36 @@
      * Pick the conversion function and do the conversion.
      */
-    PFNPDMAUDIOMIXBUFCONVFROM pfnConv;
-    if (pMixBuf->AudioFmt != enmFmt)
-        pfnConv = audioMixBufConvFromLookup(enmFmt);
+    PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
+    if (!pMixBuf->Volume.fMuted)
+    {
+        if (pMixBuf->AudioFmt != enmFmt)
+            pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
+        else
+            pfnConvFrom = pMixBuf->pfnConvFrom;
+    }
     else
-        pfnConv = pMixBuf->Volume.fMuted ? &audioMixBufConvFromSilence : pMixBuf->pfnConvFrom;
+        pfnConvFrom = &audioMixBufConvFromSilence;
 
     uint32_t cWritten;
-    if (   pfnConv
+    if (   pfnConvFrom
         && cToWrite)
     {
-        PDMAUDMIXBUFCONVOPTS convOpts = { cToWrite, pMixBuf->Volume };
-        cWritten = pfnConv(pMixBuf->pSamples + offSamples, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cToWrite), &convOpts);
+        PDMAUDMIXBUFCONVOPTS convOpts;
+
+        convOpts.cSamples           = cToWrite;
+        convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
+        convOpts.From.Volume.uLeft  = pMixBuf->Volume.uLeft;
+        convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
+
+        cWritten = pfnConvFrom(pMixBuf->pSamples + offSamples, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cToWrite), &convOpts);
     }
     else
     {
         cWritten = 0;
-        if (!pfnConv)
+        if (!pfnConvFrom)
+        {
+            AssertFailed();
             rc = VERR_NOT_SUPPORTED;
+        }
     }
 
@@ -1733,14 +1785,20 @@
     }
 
-    PFNPDMAUDIOMIXBUFCONVFROM pfnCnvFrm;
-    if (pMixBuf->AudioFmt != enmFmt)
-        pfnCnvFrm = audioMixBufConvFromLookup(enmFmt);
+    PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
+    if (!pMixBuf->Volume.fMuted)
+    {
+        if (pMixBuf->AudioFmt != enmFmt)
+            pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
+        else
+            pfnConvFrom = pMixBuf->pfnConvFrom;
+    }
     else
-        pfnCnvFrm = pMixBuf->Volume.fMuted ? &audioMixBufConvFromSilence : pMixBuf->pfnConvFrom;
-
-    if (!pfnCnvFrm)
+        pfnConvFrom = &audioMixBufConvFromSilence;
+
+    if (!pfnConvFrom)
+    {
+        AssertFailed();
         return VERR_NOT_SUPPORTED;
-
-    int rc = VINF_SUCCESS; /** @todo Move this down to where you actually need it and you'll get somewhat nice code! */
+    }
 
     uint32_t cToWrite = AUDIOMIXBUF_B2S(pMixBuf, cbBuf);
@@ -1782,5 +1840,9 @@
 
     PDMAUDMIXBUFCONVOPTS convOpts;
-    convOpts.Volume = pMixBuf->Volume;
+    convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
+    convOpts.From.Volume.uLeft  = pMixBuf->Volume.uLeft;
+    convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
+
+    LogFlowFunc(("ASDF %RU32 %RU32\n", pMixBuf->Volume.uLeft, pMixBuf->Volume.uRight));
 
     /* Anything to do at all? */
@@ -1788,5 +1850,5 @@
     {
         convOpts.cSamples = cLenDst1;
-        cWrittenTotal = pfnCnvFrm(pSamplesDst1, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), &convOpts);
+        cWrittenTotal = pfnConvFrom(pSamplesDst1, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), &convOpts);
         Assert(cWrittenTotal == cLenDst1);
 
@@ -1797,14 +1859,13 @@
 
     /* Second part present? */
-    if (   RT_LIKELY(RT_SUCCESS(rc)) /** @todo r=bird: RT_SUCCESS implies RT_LIKELY for at least 10 years now. besides, it's actually always VINF_SUCCESS at this point. */
-        && cLenDst2)
+    if (cLenDst2)
     {
         AssertPtr(pSamplesDst2);
 
         convOpts.cSamples = cLenDst2;
-        cWrittenTotal += pfnCnvFrm(pSamplesDst2,
-                                   (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
-                                   cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
-                                   &convOpts);
+        cWrittenTotal += pfnConvFrom(pSamplesDst2,
+                                     (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
+                                     cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
+                                     &convOpts);
         Assert(cWrittenTotal == cLenDst1 + cLenDst2);
 
@@ -1819,20 +1880,19 @@
 #endif
 
-    if (RT_SUCCESS(rc))
-    {
-        pMixBuf->offWrite = (pMixBuf->offWrite + cWrittenTotal) % pMixBuf->cSamples;
-        pMixBuf->cUsed   += cWrittenTotal;
-
-        if (pMixBuf->cUsed > pMixBuf->cSamples)
-        {
-            AUDMIXBUF_LOG(("Warning: %RU32 unprocessed samples overwritten\n", pMixBuf->cUsed - pMixBuf->cSamples));
-            pMixBuf->cUsed = pMixBuf->cSamples;
-
-            rc = VINF_BUFFER_OVERFLOW;
-        }
-
-        if (pcWritten)
-            *pcWritten = cWrittenTotal;
-    }
+    pMixBuf->offWrite = (pMixBuf->offWrite + cWrittenTotal) % pMixBuf->cSamples;
+    pMixBuf->cUsed   += cWrittenTotal;
+
+    int rc = VINF_SUCCESS;
+
+    if (pMixBuf->cUsed > pMixBuf->cSamples)
+    {
+        AUDMIXBUF_LOG(("Warning: %RU32 unprocessed samples overwritten\n", pMixBuf->cUsed - pMixBuf->cSamples));
+        pMixBuf->cUsed = pMixBuf->cSamples;
+
+        rc = VINF_BUFFER_OVERFLOW;
+    }
+
+    if (pcWritten)
+        *pcWritten = cWrittenTotal;
 
 #ifdef DEBUG
@@ -1843,5 +1903,4 @@
                    pMixBuf->offWrite, cLenDst1, cLenDst2, cLenDst1 + cLenDst2,
                    AUDIOMIXBUF_S2B(pMixBuf, cLenDst1 + cLenDst2), rc));
-
     return rc;
 }
Index: /trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61886)
+++ /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61887)
@@ -84,6 +84,11 @@
             /* Set initial volume to max. */
             pSink->Volume.fMuted = false;
-            pSink->Volume.uLeft  = 0x7F;
-            pSink->Volume.uRight = 0x7F;
+            pSink->Volume.uLeft  = PDMAUDIO_VOLUME_MAX;
+            pSink->Volume.uRight = PDMAUDIO_VOLUME_MAX;
+
+            /* Ditto for the combined volume. */
+            pSink->VolumeCombined.fMuted = false;
+            pSink->VolumeCombined.uLeft  = PDMAUDIO_VOLUME_MAX;
+            pSink->VolumeCombined.uRight = PDMAUDIO_VOLUME_MAX;
 
             RTListAppend(&pMixer->lstSinks, &pSink->Node);
@@ -125,7 +130,8 @@
             RTListInit(&pMixer->lstSinks);
 
+            /* Set master volume to the max. */
             pMixer->VolMaster.fMuted = false;
-            pMixer->VolMaster.uLeft  = UINT32_MAX;
-            pMixer->VolMaster.uRight = UINT32_MAX;
+            pMixer->VolMaster.uLeft  = PDMAUDIO_VOLUME_MAX;
+            pMixer->VolMaster.uRight = PDMAUDIO_VOLUME_MAX;
 
             LogFlowFunc(("Created mixer '%s'\n", pMixer->pszName));
@@ -200,9 +206,9 @@
 }
 
-void AudioMixerInvalidate(PAUDIOMIXER pMixer)
-{
-    AssertPtrReturnVoid(pMixer);
-
-    LogFlowFunc(("[%s]: Invalidating ...\n", pMixer->pszName));
+int audioMixerInvalidateInternal(PAUDIOMIXER pMixer)
+{
+    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("[%s]\n", pMixer->pszName));
 
     /* Propagate new master volume to all connected sinks. */
@@ -213,9 +219,21 @@
         AssertRC(rc2);
     }
+
+    return VINF_SUCCESS;
+}
+
+void AudioMixerInvalidate(PAUDIOMIXER pMixer)
+{
+    AssertPtrReturnVoid(pMixer);
+
+    LogFlowFunc(("[%s]\n", pMixer->pszName));
+
+    int rc2 = audioMixerInvalidateInternal(pMixer);
+    AssertRC(rc2);
 }
 
 static int audioMixerRemoveSinkInternal(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
 {
-    AssertPtrReturn(pMixer, VERR_INVALID_PARAMETER);
+    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
     if (!pSink)
         return VERR_NOT_FOUND;
@@ -267,5 +285,5 @@
     AssertPtrReturn(pVol,   VERR_INVALID_POINTER);
 
-    pMixer->VolMaster = *pVol;
+    memcpy(&pMixer->VolMaster, pVol, sizeof(PDMAUDIOVOLUME));
 
     LogFlowFunc(("[%s]: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
@@ -273,6 +291,5 @@
                  pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
 
-    AudioMixerInvalidate(pMixer);
-    return VINF_SUCCESS;
+    return audioMixerInvalidateInternal(pMixer);
 }
 
@@ -350,4 +367,9 @@
         /** @todo Check if stream already is assigned to (another) sink. */
 
+        /* Apply the sink's combined volume to the stream. */
+        AssertPtr(pStream->pConn);
+        int rc2 = pStream->pConn->pfnStreamSetVolume(pStream->pConn, pStream->pStream, &pSink->VolumeCombined);
+        AssertRC(rc2);
+
         /* Save pointer to sink the stream is attached to. */
         pStream->pSink = pSink;
@@ -874,10 +896,11 @@
     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
     AssertPtrReturn(pVol,  VERR_INVALID_POINTER);
+
+    memcpy(&pSink->Volume, pVol, sizeof(PDMAUDIOVOLUME));
+
+    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+                 pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
+
     AssertPtr(pSink->pParent);
-
-    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
-
-    pSink->Volume = *pVol;
-
     return audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster);
 }
@@ -1022,20 +1045,21 @@
     AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER);
 
-    LogFlowFunc(("Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
-                  pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
-    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+    LogFlowFunc(("[%s]: Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+                  pSink->pszName, pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
+    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32 ",
                   pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
 
     /** @todo Very crude implementation for now -- needs more work! */
 
-    PDMAUDIOVOLUME volSink;
-    volSink.fMuted  = pVolMaster->fMuted || pSink->Volume.fMuted;
-    volSink.uLeft   = (pSink->Volume.uLeft  * pVolMaster->uLeft)  / UINT8_MAX;
-    volSink.uRight  = (pSink->Volume.uRight * pVolMaster->uRight) / UINT8_MAX;
-
-    LogFlowFunc(("\t-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
-                  volSink.fMuted, volSink.uLeft, volSink.uRight));
-
-    bool fOut = pSink->enmDir == AUDMIXSINKDIR_OUTPUT;
+    pSink->VolumeCombined.fMuted  = pVolMaster->fMuted || pSink->Volume.fMuted;
+
+    pSink->VolumeCombined.uLeft   = (  (pSink->Volume.uLeft ? pSink->Volume.uLeft : 1)
+                                     * (pVolMaster->uLeft   ? pVolMaster->uLeft   : 1)) / PDMAUDIO_VOLUME_MAX;
+
+    pSink->VolumeCombined.uRight  = (  (pSink->Volume.uRight ? pSink->Volume.uRight : 1)
+                                     * (pVolMaster->uRight   ? pVolMaster->uRight   : 1)) / PDMAUDIO_VOLUME_MAX;
+
+    LogFlow(("-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+             pSink->VolumeCombined.fMuted, pSink->VolumeCombined.uLeft, pSink->VolumeCombined.uRight));
 
     /* Propagate new sink volume to all streams in the sink. */
@@ -1043,5 +1067,5 @@
     RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     {
-        int rc2 = pMixStream->pConn->pfnStreamSetVolume(pMixStream->pConn, pMixStream->pStream, &volSink);
+        int rc2 = pMixStream->pConn->pfnStreamSetVolume(pMixStream->pConn, pMixStream->pStream, &pSink->VolumeCombined);
         AssertRC(rc2);
     }
Index: /trunk/src/VBox/Devices/Audio/AudioMixer.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61886)
+++ /trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61887)
@@ -181,4 +181,6 @@
      *  be combined with the mixer's master volume. */
     PDMAUDIOVOLUME          Volume;
+    /** The volume of this sink, combined with the last set  master volume. */
+    PDMAUDIOVOLUME          VolumeCombined;
     /** Timestamp (in ns) since last update. */
     uint64_t                tsLastUpdatedNS;
Index: /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61886)
+++ /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61887)
@@ -120,5 +120,5 @@
 #define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
 
-/** @name Buffer Descriptor
+/** @name Buffer Descriptor (BD).
  * @{ */
 #define BD_IOC RT_BIT(31)          /**< Interrupt on Completion. */
@@ -128,5 +128,5 @@
 /** @} */
 
-/** @name Extended Audio Status and Control Register
+/** @name Extended Audio Status and Control Register (EACS).
  * @{ */
 #define EACS_VRA 1                 /**< Variable Rate Audio (4.2.1.1). */
@@ -134,6 +134,16 @@
 /** @} */
 
-#define VOL_MASK 0x1f
-#define MUTE_SHIFT 15
+/** @name Baseline Audio Register Set (BARS).
+ * @{ */
+#define AC97_BARS_VOL_MASK              0x1f   /**< Volume mask for the Baseline Audio Register Set (5.7.2). */
+#define AC97_BARS_VOL_STEPS             31     /**< Volume steps for the Baseline Audio Register Set (5.7.2). */
+#define AC97_BARS_VOL_MUTE_SHIFT        15     /**< Mute bit shift for the Baseline Audio Register Set (5.7.2). */
+
+#define AC97_BARS_VOL_MASTER_MASK       0x3f   /**< Master volume mask for the Baseline Audio Register Set (5.7.2). */
+#define AC97_BARS_VOL_MASTER_STEPS      63     /**< Master volume steps for the Baseline Audio Register Set (5.7.2). */
+#define AC97_BARS_VOL_MASTER_MUTE_SHIFT 15     /**< Master Mute bit shift for the Baseline Audio Register Set (5.7.2). */
+
+#define AC97_VOL_MAX_STEPS              63
+/** @} */
 
 #define REC_MASK 7
@@ -637,27 +647,27 @@
 }
 
-static void ichac97MixerSet(PAC97STATE pThis, uint32_t u8Idx, uint16_t v)
-{
-    if (u8Idx + 2 > sizeof(pThis->mixer_data))
-    {
-        AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
+static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal)
+{
+    if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
+    {
+        AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
         return;
     }
 
-    pThis->mixer_data[u8Idx + 0] = RT_LO_U8(v);
-    pThis->mixer_data[u8Idx + 1] = RT_HI_U8(v);
-}
-
-static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t u8Idx)
+    pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal);
+    pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal);
+}
+
+static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx)
 {
     uint16_t uVal;
 
-    if (u8Idx + 2 > sizeof(pThis->mixer_data))
-    {
-        AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
+    if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
+    {
+        AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
         uVal = UINT16_MAX;
     }
     else
-        uVal = RT_MAKE_U16(pThis->mixer_data[u8Idx + 0], pThis->mixer_data[u8Idx + 1]);
+        uVal = RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]);
 
     return uVal;
@@ -953,24 +963,83 @@
 }
 
-static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL mt, uint32_t val)
-{
-    int mute = (val >> MUTE_SHIFT) & 1;
-    uint8_t rvol = val & VOL_MASK;
-    uint8_t lvol = (val >> 8) & VOL_MASK;
-
-    /* For the master volume, 0 corresponds to 0dB gain. But for the other
-     * volume controls, 0 corresponds to +12dB and 8 to 0dB. */
-    if (mt != PDMAUDIOMIXERCTL_VOLUME)
-    {
+static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
+{
+#ifdef DEBUG
+    uint32_t uValMaster = ichac97MixerGet(pThis, AC97_Master_Volume_Mute);
+
+    bool    fMasterMuted = (uValMaster >> AC97_BARS_VOL_MASTER_MUTE_SHIFT) & 1;
+    uint8_t lMasterAtt   = (uValMaster >> 8) & AC97_BARS_VOL_MASTER_MASK;
+    uint8_t rMasterAtt   = uValMaster & AC97_BARS_VOL_MASTER_MASK;
+
+    Assert(lMasterAtt <= AC97_VOL_MAX_STEPS);
+    Assert(rMasterAtt <= AC97_VOL_MAX_STEPS);
+
+    LogFlowFunc(("lMasterAtt=%RU8, rMasterAtt=%RU8, fMasterMuted=%RTbool\n", lMasterAtt, rMasterAtt, fMasterMuted));
+#endif
+
+    bool    fCntlMuted;
+    uint8_t lCntlAtt, rCntlAtt;
+
+    uint8_t uSteps;
+
+    /*
+     * From AC'97 SoundMax Codec AD1981A/AD1981B:
+     * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the
+     *  D5 or D13 bits are set to 1, their respective lower five volume bits are automatically
+     *  set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever
+     *  these bits are set to 1."
+     *
+     * Linux ALSA depends on this behavior.
+     */
+    if (uVal & RT_BIT(5))
+        uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
+    if (uVal & RT_BIT(13))
+        uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
+
+    /* For the master volume, 0 corresponds to 0dB attenuation, each step
+     * corresponds to -1.5dB. */
+    if (index == AC97_Master_Volume_Mute)
+    {
+        fCntlMuted = (uVal >> AC97_BARS_VOL_MASTER_MUTE_SHIFT) & 1;
+        lCntlAtt   = (uVal >> 8) & AC97_BARS_VOL_MASTER_MASK;
+        rCntlAtt   = uVal & AC97_BARS_VOL_MASTER_MASK;
+
+        uSteps = PDMAUDIO_VOLUME_MAX / AC97_BARS_VOL_MASTER_STEPS;
+    }
+    /* For other volume controls:
+     * - 0 - 7 corresponds to +12dB, in 1.5dB steps.
+     * - 8     corresponds to 0dB gain (unchanged).
+     * - 9 - X corresponds to -1.5dB steps. */
+    else
+    {
+        fCntlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
+        lCntlAtt   = (uVal >> 8) & AC97_BARS_VOL_MASK;
+        rCntlAtt   = uVal & AC97_BARS_VOL_MASK;
+
+        Assert(lCntlAtt <= AC97_VOL_MAX_STEPS);
+        Assert(rCntlAtt <= AC97_VOL_MAX_STEPS);
+
+#ifndef VBOX_WITH_AC97_GAIN_SUPPORT
         /* NB: Currently there is no gain support, only attenuation. */
-        lvol = lvol < 8 ? 0 : lvol - 8;
-        rvol = rvol < 8 ? 0 : rvol - 8;
-    }
-
-    /* AC'97 has 1.5dB steps; we use 0.375dB steps. */
-    rvol = 255 - rvol * 4;
-    lvol = 255 - lvol * 4;
-
-    LogFunc(("mt=%ld, val=%RX32, mute=%RTbool\n", mt, val, RT_BOOL(mute)));
+        lCntlAtt = lCntlAtt <= 8 ? 0 : lCntlAtt - 8;
+        rCntlAtt = rCntlAtt <= 8 ? 0 : rCntlAtt - 8;
+#endif
+        uSteps = PDMAUDIO_VOLUME_MAX / AC97_BARS_VOL_STEPS;
+    }
+
+    LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
+
+    LogFunc(("lAtt=%RU8, rAtt=%RU8 ", lCntlAtt, rCntlAtt));
+
+    /*
+     * AC'97 volume controls have 31 steps, each -1.5dB => -40,5dB attenuation total.
+     *
+     * In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX) steps, each -0.375dB,
+     * where 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
+     */
+    uint8_t lVol = PDMAUDIO_VOLUME_MAX - RT_MIN((lCntlAtt * 4 /* dB resolution */ * uSteps /* steps */), PDMAUDIO_VOLUME_MAX);
+    uint8_t rVol = PDMAUDIO_VOLUME_MAX - RT_MIN((rCntlAtt * 4 /* dB resolution */ * uSteps /* steps */), PDMAUDIO_VOLUME_MAX);
+
+    Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCntlMuted, lVol, rVol));
 
     int rc;
@@ -978,24 +1047,24 @@
     if (pThis->pMixer) /* Device can be in reset state, so no mixer available. */
     {
-        PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
-        switch (mt)
+        PDMAUDIOVOLUME Vol = { fCntlMuted, lVol, rVol };
+        switch (enmMixerCtl)
         {
             case PDMAUDIOMIXERCTL_VOLUME:
-                rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
+                rc = AudioMixerSetMasterVolume(pThis->pMixer,    &Vol);
                 break;
-
             case PDMAUDIOMIXERCTL_FRONT:
-                rc = AudioMixerSinkSetVolume(pThis->pSinkOutput, &vol);
+                rc = AudioMixerSinkSetVolume(pThis->pSinkOutput, &Vol);
                 break;
 
             case PDMAUDIOMIXERCTL_MIC_IN:
-                rc = AudioMixerSinkSetVolume(pThis->pSinkMicIn, &vol);
+                rc = AudioMixerSinkSetVolume(pThis->pSinkMicIn,  &Vol);
                 break;
 
             case PDMAUDIOMIXERCTL_LINE_IN:
-                rc = AudioMixerSinkSetVolume(pThis->pSinkLineIn, &vol);
+                rc = AudioMixerSinkSetVolume(pThis->pSinkLineIn, &Vol);
                 break;
 
             default:
+                AssertFailed();
                 rc = VERR_NOT_SUPPORTED;
                 break;
@@ -1005,21 +1074,5 @@
         rc = VINF_SUCCESS;
 
-    rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
-    lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
-
-    /*
-     * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
-     * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
-     * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
-     * all lower 5 bits will read ones whenever these bits are set to `1.'"
-     *
-     *  Linux ALSA depends on this behavior.
-     */
-    if (val & RT_BIT(5))
-        val |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
-    if (val & RT_BIT(13))
-        val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
-
-    ichac97MixerSet(pThis, index, val);
+    ichac97MixerSet(pThis, index, uVal);
 
     if (RT_FAILURE(rc))
@@ -1110,5 +1163,5 @@
     {
         /* Analog Devices 1980 (AD1980) */
-        ichac97MixerSet(pThis, AC97_Reset                   , 0x0010);    /* Headphones. */
+        ichac97MixerSet(pThis, AC97_Reset                   , 0x0010); /* Headphones. */
         ichac97MixerSet(pThis, AC97_Vendor_ID1              , 0x4144);
         ichac97MixerSet(pThis, AC97_Vendor_ID2              , 0x5370);
@@ -1129,7 +1182,8 @@
     ichac97RecordSelect(pThis, 0);
 
-    ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME,  0x8000);
-    ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,   0x8808);
-    ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
+    ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME, 0x8000);
+    ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,         0x8808);
+    ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN,       0x8808);
+    ichac97MixerSetVolume(pThis, AC97_Mic_Volume_Mute,     PDMAUDIOMIXERCTL_MIC_IN,        0x8808);
 
     return VINF_SUCCESS;
@@ -1964,13 +2018,19 @@
                 case AC97_Master_Volume_Mute:
                     if (pThis->uCodecModel == Codec_AD1980)
+                    {
                         if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_LOSEL)
-                            break;  /* Register controls surround (rear), do nothing. */
+                            break; /* Register controls surround (rear), do nothing. */
+                    }
                     ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
                     break;
                 case AC97_Headphone_Volume_Mute:
                     if (pThis->uCodecModel == Codec_AD1980)
+                    {
                         if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
+                        {
                             /* Register controls PCM (front) outputs. */
                             ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
+                        }
+                    }
                     break;
                 case AC97_PCM_Out_Volume_Mute:
@@ -2215,4 +2275,5 @@
     V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT);
     V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
+    V_(AC97_Mic_Volume_Mute,     PDMAUDIOMIXERCTL_MIC_IN);
 # undef V_
     if (pThis->uCodecModel == Codec_AD1980)
Index: /trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61886)
+++ /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61887)
@@ -1607,6 +1607,9 @@
     LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));
 
-    AudioMixBufSetVolume(&pStream->MixBuf, pVol);
-
+    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
+
+    AudioMixBufSetVolume(&pHstStream->MixBuf, pVol);
+    AudioMixBufSetVolume(&pGstStream->MixBuf, pVol);
     return VINF_SUCCESS;
 }
