Index: trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61320)
@@ -61,4 +61,5 @@
 #endif
 
+DECLINLINE(void) audioMixBufDbgPrintInternal(PPDMAUDIOMIXBUF pMixBuf);
 
 /*
@@ -177,7 +178,7 @@
 
     uint32_t cSamplesRead;
-    if (pMixBuf->offReadWrite + cSamplesToRead > pMixBuf->cSamples)
-    {
-        cSamplesRead = pMixBuf->cSamples - pMixBuf->offReadWrite;
+    if (pMixBuf->offRead + cSamplesToRead > pMixBuf->cSamples)
+    {
+        cSamplesRead = pMixBuf->cSamples - pMixBuf->offRead;
         rc = VINF_TRY_AGAIN;
     }
@@ -188,10 +189,10 @@
     }
 
-    *ppvSamples = &pMixBuf->pSamples[pMixBuf->offReadWrite];
+    *ppvSamples = &pMixBuf->pSamples[pMixBuf->offRead];
     AssertPtr(ppvSamples);
 
-    pMixBuf->offReadWrite = (pMixBuf->offReadWrite + cSamplesRead) % pMixBuf->cSamples;
-    Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
-    pMixBuf->cProcessed -= RT_MIN(cSamplesRead, pMixBuf->cProcessed);
+    pMixBuf->offRead = (pMixBuf->offRead + cSamplesRead) % pMixBuf->cSamples;
+    Assert(pMixBuf->offRead <= pMixBuf->cSamples);
+    pMixBuf->cUsed -= RT_MIN(cSamplesRead, pMixBuf->cUsed);
 
     *pcSamplesRead = cSamplesRead;
@@ -214,5 +215,5 @@
         cAvail = pMixBuf->cMixed;
     else
-        cAvail = pMixBuf->cProcessed;
+        cAvail = pMixBuf->cUsed;
 
     Assert(cAvail <= pMixBuf->cSamples);
@@ -235,5 +236,5 @@
 
 /**
- * Clears (zeroes) the buffer by a certain amount of (processed) samples and
+ * Clears (zeroes) the buffer by a certain amount of (used) samples and
  * keeps track to eventually assigned children buffers.
  *
@@ -243,41 +244,49 @@
 void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear)
 {
-    AUDMIXBUF_LOG(("cSamples=%RU32\n", cSamplesToClear));
-    AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32\n",
-                   pMixBuf->pszName, pMixBuf->offReadWrite, pMixBuf->cProcessed));
+    AUDMIXBUF_LOG(("cSamplesToClear=%RU32\n", cSamplesToClear));
+    AUDMIXBUF_LOG(("%s: offRead=%RU32, cUsed=%RU32\n",
+                   pMixBuf->pszName, pMixBuf->offRead, pMixBuf->cUsed));
 
     PPDMAUDIOMIXBUF pIter;
-    RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
+    RTListForEach(&pMixBuf->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
     {
         AUDMIXBUF_LOG(("\t%s: cMixed=%RU32 -> %RU32\n",
                        pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear));
 
+        Assert(cSamplesToClear <= pIter->cMixed);
         pIter->cMixed -= RT_MIN(pIter->cMixed, cSamplesToClear);
-        pIter->offReadWrite = 0;
-    }
-
-    uint32_t cLeft = RT_MIN(cSamplesToClear, pMixBuf->cSamples);
-    uint32_t offClear;
-
-    if (cLeft > pMixBuf->offReadWrite) /* Zero end of buffer first (wrap-around). */
-    {
-        AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n",
-                       (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
-                        pMixBuf->cSamples));
-
-        RT_BZERO(pMixBuf->pSamples + (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
-                 (cLeft - pMixBuf->offReadWrite) * sizeof(PDMAUDIOSAMPLE));
-
-        cLeft -= cLeft - pMixBuf->offReadWrite;
-        offClear = 0;
-    }
-    else
-        offClear = pMixBuf->offReadWrite - cLeft;
-
-    if (cLeft)
-    {
-        AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n",
-                       offClear, offClear + cLeft));
-        RT_BZERO(pMixBuf->pSamples + offClear, cLeft * sizeof(PDMAUDIOSAMPLE));
+    }
+
+    Assert(cSamplesToClear <= pMixBuf->cSamples);
+
+    uint32_t cClearOff;
+    uint32_t cClearLen;
+
+    /* Clear end of buffer (wrap around). */
+    if (cSamplesToClear > pMixBuf->offRead)
+    {
+        cClearOff = pMixBuf->cSamples - (cSamplesToClear - pMixBuf->offRead);
+        cClearLen = pMixBuf->cSamples - cClearOff;
+
+        AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
+
+        RT_BZERO(pMixBuf->pSamples + cClearOff, cClearLen * sizeof(PDMAUDIOSAMPLE));
+
+        Assert(cSamplesToClear >= cClearLen);
+        cSamplesToClear -= cClearLen;
+    }
+
+    /* Clear beginning of buffer. */
+    if (   cSamplesToClear
+        && pMixBuf->offRead)
+    {
+        Assert(pMixBuf->offRead >= cSamplesToClear);
+
+        cClearOff = pMixBuf->offRead - cSamplesToClear;
+        cClearLen = cSamplesToClear;
+
+        AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
+
+        RT_BZERO(pMixBuf->pSamples + cClearOff, cClearLen * sizeof(PDMAUDIOSAMPLE));
     }
 }
@@ -342,6 +351,6 @@
     else /* As a parent. */
     {
-        Assert(pMixBuf->cSamples >= pMixBuf->cProcessed);
-        cSamplesFree = pMixBuf->cSamples - pMixBuf->cProcessed;
+        Assert(pMixBuf->cSamples >= pMixBuf->cUsed);
+        cSamplesFree = pMixBuf->cSamples - pMixBuf->cUsed;
     }
 
@@ -757,12 +766,13 @@
 
     pMixBuf->pParent = NULL;
-    RTListInit(&pMixBuf->lstBuffers);
+    RTListInit(&pMixBuf->lstChildren);
 
     pMixBuf->pSamples = NULL;
     pMixBuf->cSamples = 0;
 
-    pMixBuf->offReadWrite = 0;
-    pMixBuf->cMixed       = 0;
-    pMixBuf->cProcessed   = 0;
+    pMixBuf->offRead  = 0;
+    pMixBuf->offWrite = 0;
+    pMixBuf->cMixed   = 0;
+    pMixBuf->cUsed    = 0;
 
     /* Set initial volume to max. */
@@ -813,5 +823,5 @@
     if (pMixBuf->pParent)
         return (pMixBuf->cMixed == 0);
-    return (pMixBuf->cProcessed == 0);
+    return (pMixBuf->cUsed == 0);
 }
 
@@ -855,5 +865,5 @@
     }
 
-    RTListAppend(&pParent->lstBuffers, &pMixBuf->Node);
+    RTListAppend(&pParent->lstChildren, &pMixBuf->Node);
     pMixBuf->pParent = pParent;
 
@@ -865,4 +875,6 @@
         pMixBuf->iFreqRatio = 1 << 20; /* Do a 1:1 conversion instead. */
 
+    int rc = VINF_SUCCESS;
+#if 0
     uint32_t cSamples = (uint32_t)RT_MIN(  ((uint64_t)pParent->cSamples << 32)
                                          / pMixBuf->iFreqRatio, _64K /* 64K samples max. */);
@@ -892,4 +904,5 @@
         }
     }
+#endif
 
     if (RT_SUCCESS(rc))
@@ -955,122 +968,15 @@
     AssertPtrReturn(pDst,  VERR_INVALID_POINTER);
     AssertPtrReturn(pSrc,  VERR_INVALID_POINTER);
-    AssertReturn(cSamples, VERR_INVALID_PARAMETER);
     /* pcProcessed is optional. */
 
-    /* Live samples indicate how many samples there are in the source buffer
-     * which have not been processed yet by the destination buffer. */
-    uint32_t cLive = pSrc->cMixed;
-    if (cLive >= pDst->cSamples)
-        AUDMIXBUF_LOG(("Destination buffer \"%s\" full (%RU32 samples max), live samples = %RU32\n",
-                       pDst->pszName, pDst->cSamples, cLive));
-
-    /* Dead samples are the number of samples in the destination buffer which
-     * will not be needed, that is, are not needed in order to process the live
-     * samples of the source buffer. */
-    uint32_t cDead         = pDst->cSamples - cLive;
-
-    uint32_t cToReadTotal  = (uint32_t)RT_MIN(cSamples, AUDIOMIXBUF_S2S_RATIO(pSrc, cDead));
-    uint32_t offRead       = 0;
-
+    AssertMsgReturn(pDst == pSrc->pParent, ("Source buffer '%s' is not a child of destination '%s'\n",
+                                            pSrc->pszName, pDst->pszName), VERR_INVALID_PARAMETER);
     uint32_t cReadTotal    = 0;
     uint32_t cWrittenTotal = 0;
-    uint32_t offWrite      = (pDst->offReadWrite + cLive) % pDst->cSamples;
-
-    AUDMIXBUF_LOG(("pSrc=%s (%RU32 samples, %RU8 chan), pDst=%s (%RU32 samples, %RU8 chan), " \
-                   "cLive=%RU32, cDead=%RU32, cToReadTotal=%RU32, offWrite=%RU32\n",
-                   pSrc->pszName, pSrc->cSamples, AUDMIXBUF_FMT_CHANNELS(pSrc->AudioFmt),
-                   pDst->pszName, pDst->cSamples, AUDMIXBUF_FMT_CHANNELS(pDst->AudioFmt),
-                   cLive, cDead, cToReadTotal, offWrite));
-
-    uint32_t cToRead, cToWrite;
-    uint32_t cWritten, cRead;
-
-    while (cToReadTotal)
-    {
-        cDead = pDst->cSamples - cLive;
-
-        cToRead  = cToReadTotal;
-        cToWrite = RT_MIN(cDead, pDst->cSamples - offWrite);
-        if (!cToWrite)
-        {
-            AUDMIXBUF_LOG(("Warning: Destination buffer \"%s\" full\n", pDst->pszName));
-            break;
-        }
-
-        Assert(offWrite + cToWrite <= pDst->cSamples);
-        Assert(offRead  + cToRead  <= pSrc->cSamples);
-
-        AUDMIXBUF_LOG(("\t%RU32Hz -> %RU32Hz\n", AUDMIXBUF_FMT_SAMPLE_FREQ(pSrc->AudioFmt), AUDMIXBUF_FMT_SAMPLE_FREQ(pDst->AudioFmt)));
-        AUDMIXBUF_LOG(("\tcDead=%RU32, offWrite=%RU32, cToWrite=%RU32, offRead=%RU32, cToRead=%RU32\n",
-                       cDead, offWrite, cToWrite, offRead, cToRead));
-
-        audioMixBufOpAssign(pDst->pSamples + offWrite, cToWrite,
-                            pSrc->pSamples + offRead, cToRead,
-                            pSrc->pRate, &cWritten, &cRead);
-
-        AUDMIXBUF_LOG(("\t\tcWritten=%RU32, cRead=%RU32\n", cWritten, cRead));
-
-        cReadTotal    += cRead;
-        cWrittenTotal += cWritten;
-
-        offRead += cRead;
-        Assert(cToReadTotal >= cRead);
-        cToReadTotal -= cRead;
-
-        offWrite = (offWrite + cWritten) % pDst->cSamples;
-
-        cLive += cWritten;
-    }
-
-    pSrc->cMixed     += cWrittenTotal;
-
-    pDst->cProcessed += cWrittenTotal;
-
-#if 0
-    /**
-     * Note: pDst->cProcessed can be bigger than pDst->cSamples if there
-     *       was a wrap-around. In that case samples were lost,
-     *       e.g. not consumed (yet).
-     *
-     *       So adjust the current read/write offset to match the current
-     *       position, minus the dropped samples. */
-    if (pDst->cProcessed > pDst->cSamples)
-    {
-        LogFlowFunc(("%s: %RU32 / %RU32\n", pDst->pszName, pDst->cProcessed, pDst->cSamples));
-        pSrc->cMixed       = pDst->cSamples;
-        pDst->offReadWrite = 0;
-        pDst->cProcessed   = pDst->cSamples;
-    }
-#endif
-
-#ifdef DEBUG
-    s_cSamplesMixedTotal += cWrittenTotal;
-    AudioMixBufDbgPrint(pDst);
-#endif
-
-    if (pcProcessed)
-        *pcProcessed = cReadTotal;
-
-    AUDMIXBUF_LOG(("cReadTotal=%RU32 (pcProcessed), cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstProc=%RU32\n",
-                   cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cProcessed));
-    return VINF_SUCCESS;
-}
-
-/**
- * Mixes (multiplexes) audio samples to all connected mixing buffer children.
- *
- * @return  IPRT status code.
- * @param   pMixBuf                 Mixing buffer to use.
- * @param   cSamples                Number of audio samples to mix to children.
- * @param   pcProcessed             Maximum number of audio samples successfully mixed
- *                                  to all children. Optional.
- */
-int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
-                             uint32_t *pcProcessed)
-{
-    AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
-
-    if (!cSamples)
-    {
+
+    if (pSrc->cMixed >= pDst->cSamples)
+    {
+        AUDMIXBUF_LOG(("Warning: Destination buffer '%s' full (%RU32 samples max), got %RU32 mixed samples\n",
+                       pDst->pszName, pDst->cSamples, pSrc->cMixed));
         if (pcProcessed)
             *pcProcessed = 0;
@@ -1078,23 +984,125 @@
     }
 
+    Assert(pSrc->cUsed >= pDst->cMixed);
+
+    uint32_t cSrcAvail  = RT_MIN(cSamples, pSrc->cUsed - pDst->cMixed);
+    uint32_t offSrcRead = pSrc->offRead;
+    uint32_t cDstMixed  = pSrc->cMixed;
+
+    Assert(pDst->cUsed <= pDst->cSamples);
+    uint32_t cDstAvail    = pDst->cSamples - pDst->cUsed;
+    uint32_t offDstWrite  = pDst->offWrite;
+
+    if (   !cSrcAvail
+        || !cDstAvail)
+    {
+        if (pcProcessed)
+            *pcProcessed = 0;
+        return VINF_SUCCESS;
+    }
+
+    AUDMIXBUF_LOG(("cSamples=%RU32, cSrcAvail=%RU32 -> cDstAvail=%RU32\n", cSamples,  cSrcAvail, cDstAvail));
+
+#ifdef DEBUG
+    audioMixBufDbgPrintInternal(pDst);
+#endif
+
+    uint32_t cSrcToRead;
+    uint32_t cSrcRead;
+
+    uint32_t cDstToWrite;
+    uint32_t cDstWritten;
+
     int rc = VINF_SUCCESS;
 
-    uint32_t cProcessed;
-    uint32_t cProcessedMax = 0;
-
-    PPDMAUDIOMIXBUF pIter;
-    RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
-    {
-        rc = audioMixBufMixTo(pIter, pMixBuf, cSamples, &cProcessed);
-        if (RT_FAILURE(rc))
-            break;
-
-        cProcessedMax = RT_MAX(cProcessedMax, cProcessed);
-    }
+    while (   cSrcAvail
+           && cDstAvail)
+    {
+        cSrcToRead  = RT_MIN(cSrcAvail, pSrc->cSamples - offSrcRead);
+        cDstToWrite = RT_MIN(cDstAvail, pDst->cSamples - offDstWrite);
+
+        AUDMIXBUF_LOG(("\tSource: %RU32 samples available, %RU32 @ %RU32 -> reading %RU32\n", cSrcAvail, offSrcRead, pSrc->cSamples, cSrcToRead));
+        AUDMIXBUF_LOG(("\tDest  : %RU32 samples available, %RU32 @ %RU32 -> writing %RU32\n", cDstAvail, offDstWrite, pDst->cSamples, cDstToWrite));
+
+        cDstWritten = cSrcRead = 0;
+
+        if (   cDstToWrite
+            && cSrcToRead)
+        {
+            Assert(offSrcRead < pSrc->cSamples);
+            Assert(offSrcRead + cSrcToRead <= pSrc->cSamples);
+
+            Assert(offDstWrite < pDst->cSamples);
+            Assert(offDstWrite + cDstToWrite <= pDst->cSamples);
+
+            audioMixBufOpAssign(pDst->pSamples + offDstWrite, cDstToWrite,
+                                pSrc->pSamples + offSrcRead,  cSrcToRead,
+                                pSrc->pRate, &cDstWritten, &cSrcRead);
+        }
+
+        cReadTotal    += cSrcRead;
+        cWrittenTotal += cDstWritten;
+
+        offSrcRead     = (offSrcRead  + cSrcRead)    % pSrc->cSamples;
+        offDstWrite    = (offDstWrite + cDstWritten) % pDst->cSamples;
+
+        cDstMixed     += cDstWritten;
+
+        Assert(cSrcAvail >= cSrcRead);
+        cSrcAvail     -= cSrcRead;
+        Assert(cDstAvail >= cDstWritten);
+        cDstAvail     -= cDstWritten;
+
+        AUDMIXBUF_LOG(("\t%RU32 read (%RU32 left), %RU32 written (%RU32 left)\n", cSrcRead, cSrcAvail, cDstWritten, cDstAvail));
+    }
+
+    pSrc->offRead     = offSrcRead;
+    Assert(pSrc->cUsed >= cReadTotal);
+    pSrc->cUsed      -= cReadTotal;
+
+    /* Note: Always count in parent samples, as the rate can differ! */
+    pSrc->cMixed      = cDstMixed;
+    Assert(pSrc->cMixed <= pDst->cSamples);
+
+    pDst->offWrite    = offDstWrite;
+    Assert(pDst->offWrite <= pDst->cSamples);
+    Assert((pDst->cUsed + cWrittenTotal) <= pDst->cSamples);
+    pDst->cUsed      += cWrittenTotal;
+
+    /* If there are more used samples than fitting in the destination buffer,
+     * adjust the values accordingly.
+     *
+     * This can happen if this routine has been called too often without
+     * actually processing the destination buffer in between. */
+    if (pDst->cUsed > pDst->cSamples)
+    {
+        LogFlowFunc(("Warning: Destination buffer used %RU32 / %RU32 samples\n", pDst->cUsed, pDst->cSamples));
+        pDst->offWrite     = 0;
+        pDst->cUsed        = pDst->cSamples;
+
+        rc = VERR_BUFFER_OVERFLOW;
+    }
+    else if (!cSrcToRead && cDstAvail)
+    {
+        AUDMIXBUF_LOG(("Warning: Source buffer '%s' ran out of data\n", pSrc->pszName));
+        rc = VERR_BUFFER_UNDERFLOW;
+    }
+    else if (cSrcAvail && !cDstAvail)
+    {
+        AUDMIXBUF_LOG(("Warning: Destination buffer '%s' full (%RU32 source samples left)\n", pDst->pszName, cSrcAvail));
+        rc = VERR_BUFFER_OVERFLOW;
+    }
+
+#ifdef DEBUG
+    s_cSamplesMixedTotal += cWrittenTotal;
+    audioMixBufDbgPrintInternal(pDst);
+#endif
 
     if (pcProcessed)
-        *pcProcessed = cProcessedMax;
-
-    return rc;
+        *pcProcessed = cReadTotal;
+
+    AUDMIXBUF_LOG(("cReadTotal=%RU32 (pcProcessed), cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstUsed=%RU32, rc=%Rrc\n",
+                   cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cUsed, rc));
+    return VINF_SUCCESS;
 }
 
@@ -1118,22 +1126,4 @@
 
 #ifdef DEBUG
-static void audioMixBufDbgBufPrintIndentV(uint16_t uIndent, const char *pszFormat, va_list va)
-{
-    char *pszValueFormat;
-    if (RTStrAPrintfV(&pszValueFormat, pszFormat, va))
-    {
-        AUDMIXBUF_LOG(("%*s%s", uIndent, "", pszValueFormat));
-        RTStrFree(pszValueFormat);
-    }
-}
-
-static void audioMixBufDbgPrintIndent(uint16_t uIdtLvl, const char *pszFormat, ...)
-{
-    va_list va;
-    va_start(va, pszFormat);
-    audioMixBufDbgBufPrintIndentV(uIdtLvl * 4, pszFormat, va);
-    va_end(va);
-}
-
 /**
  * Prints a single mixing buffer.
@@ -1145,10 +1135,9 @@
  * @param   uIdtLvl                 Indention level to use.
  */
-static void audioMixBufDbgPrintSingle(PPDMAUDIOMIXBUF pMixBuf, bool fIsParent, uint16_t uIdtLvl)
-{
-    audioMixBufDbgPrintIndent(uIdtLvl,
-                              "[%s] %s: offReadWrite=%RU32, cProc=%RU32, cMixed=%RU32 / %RU32)\n",
-                              fIsParent ? "PARENT" : "CHILD",
-                              pMixBuf->pszName, pMixBuf->offReadWrite, pMixBuf->cProcessed, pMixBuf->cMixed, pMixBuf->cSamples);
+DECL_FORCE_INLINE(void) audioMixBufDbgPrintSingle(PPDMAUDIOMIXBUF pMixBuf, bool fIsParent, uint16_t uIdtLvl)
+{
+    AUDMIXBUF_LOG(("%*s[%s] %s: offRead=%RU32, offWrite=%RU32, cMixed=%RU32 -> %RU32/%RU32\n",
+                   uIdtLvl * 4, "", fIsParent ? "PARENT" : "CHILD",
+                   pMixBuf->pszName, pMixBuf->offRead, pMixBuf->offWrite, pMixBuf->cMixed, pMixBuf->cUsed, pMixBuf->cSamples));
 }
 
@@ -1162,16 +1151,15 @@
  * @param   pcChildren              Pointer to children counter.
  */
-static void audioMixBufDbgPrintChainHelper(PPDMAUDIOMIXBUF pMixBuf, uint16_t uIdtLvl, size_t *pcChildren)
+DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainHelper(PPDMAUDIOMIXBUF pMixBuf, uint16_t uIdtLvl, size_t *pcChildren)
 {
     PPDMAUDIOMIXBUF pIter;
-    RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
+    RTListForEach(&pMixBuf->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
     {
         audioMixBufDbgPrintSingle(pIter, false /* ifIsParent */, uIdtLvl + 1);
         *pcChildren++;
-        audioMixBufDbgPrintChainHelper(pIter, uIdtLvl + 1, pcChildren);
-    }
-}
-
-static void audioMixBufDbgPrintChainInternal(PPDMAUDIOMIXBUF pMixBuf)
+    }
+}
+
+DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainInternal(PPDMAUDIOMIXBUF pMixBuf)
 {
     PPDMAUDIOMIXBUF pParent = pMixBuf->pParent;
@@ -1212,12 +1200,5 @@
 }
 
-/**
- * Prints statistics and status of a mixing buffer to the logger.
- * For debug versions only.
- *
- * @return  IPRT status code.
- * @param   pMixBuf                 Mixing buffer to print.
- */
-void AudioMixBufDbgPrint(PPDMAUDIOMIXBUF pMixBuf)
+DECL_FORCE_INLINE(void) audioMixBufDbgPrintInternal(PPDMAUDIOMIXBUF pMixBuf)
 {
     PPDMAUDIOMIXBUF pParent = pMixBuf;
@@ -1225,10 +1206,10 @@
         pParent = pMixBuf->pParent;
 
-    AUDMIXBUF_LOG(("********************************************\n"));
+    AUDMIXBUF_LOG(("***************************************************************************************\n"));
 
     audioMixBufDbgPrintSingle(pMixBuf, pParent == pMixBuf /* fIsParent */, 0 /* iIdtLevel */);
 
     PPDMAUDIOMIXBUF pIter;
-    RTListForEach(&pParent->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
+    RTListForEach(&pParent->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
     {
         if (pIter == pMixBuf)
@@ -1237,20 +1218,32 @@
     }
 
-    AUDMIXBUF_LOG(("********************************************\n"));
-}
-#endif
-
-/**
- * Returns the total number of samples processed.
+    AUDMIXBUF_LOG(("***************************************************************************************\n"));
+}
+
+/**
+ * Prints statistics and status of a mixing buffer to the logger.
+ * For debug versions only.
+ *
+ * @return  IPRT status code.
+ * @param   pMixBuf                 Mixing buffer to print.
+ */
+void AudioMixBufDbgPrint(PPDMAUDIOMIXBUF pMixBuf)
+{
+    audioMixBufDbgPrintInternal(pMixBuf);
+}
+#endif
+
+/**
+ * Returns the total number of samples used.
  *
  * @return  uint32_t
  * @param   pMixBuf
  */
-uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf)
+uint32_t AudioMixBufUsed(PPDMAUDIOMIXBUF pMixBuf)
 {
     AssertPtrReturn(pMixBuf, 0);
 
-    AUDMIXBUF_LOG(("%s: cProcessed=%RU32\n", pMixBuf->pszName, pMixBuf->cProcessed));
-    return pMixBuf->cProcessed;
+    AUDMIXBUF_LOG(("%s: cUsed=%RU32\n", pMixBuf->pszName, pMixBuf->cUsed));
+    return pMixBuf->cUsed;
 }
 
@@ -1297,5 +1290,5 @@
 
     uint32_t cDstSamples = pMixBuf->cSamples;
-    uint32_t cLive = pMixBuf->cProcessed;
+    uint32_t cLive = pMixBuf->cUsed;
 
     uint32_t cDead = cDstSamples - cLive;
@@ -1381,5 +1374,7 @@
         return VINF_SUCCESS;
 
-    uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cProcessed);
+    Assert(AUDIOMIXBUF_B2S(pMixBuf, cbBuf) <= pMixBuf->cSamples);
+
+    uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cUsed);
 
     AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
@@ -1389,5 +1384,5 @@
     {
 #ifdef DEBUG
-        AudioMixBufDbgPrint(pMixBuf);
+        audioMixBufDbgPrintInternal(pMixBuf);
 #endif
         if (pcRead)
@@ -1400,11 +1395,9 @@
         return VERR_NOT_SUPPORTED;
 
-    PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
+    PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offRead;
     uint32_t cLenSrc1 = cToRead;
 
     PPDMAUDIOSAMPLE pSamplesSrc2 = NULL;
     uint32_t cLenSrc2 = 0;
-
-    uint32_t offRead = pMixBuf->offReadWrite + cToRead;
 
     /*
@@ -1413,15 +1406,12 @@
      * be the optional second part to do.
      */
-    if (offRead >= pMixBuf->cSamples)
-    {
-        Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
-        cLenSrc1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
+    if ((pMixBuf->offRead + cToRead) > pMixBuf->cSamples)
+    {
+        Assert(pMixBuf->offRead <= pMixBuf->cSamples);
+        cLenSrc1 = pMixBuf->cSamples - pMixBuf->offRead;
 
         pSamplesSrc2 = pMixBuf->pSamples;
         Assert(cToRead >= cLenSrc1);
         cLenSrc2 = RT_MIN(cToRead - cLenSrc1, pMixBuf->cSamples);
-
-        /* Save new read offset. */
-        offRead = cLenSrc2;
     }
 
@@ -1435,5 +1425,5 @@
         convOpts.cSamples = cLenSrc1;
 
-        AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offReadWrite, cLenSrc1));
+        AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offRead, cLenSrc1));
         pConv(pvBuf, pSamplesSrc1, &convOpts);
     }
@@ -1464,18 +1454,17 @@
         }
 #endif
-        pMixBuf->offReadWrite  = offRead % pMixBuf->cSamples;
-        pMixBuf->cProcessed   -= RT_MIN(cLenSrc1 + cLenSrc2, pMixBuf->cProcessed);
+        pMixBuf->offRead  = (pMixBuf->offRead + cToRead) % pMixBuf->cSamples;
+        Assert(cToRead <= pMixBuf->cUsed);
+        pMixBuf->cUsed   -= RT_MIN(cToRead, pMixBuf->cUsed);
 
         if (pcRead)
-            *pcRead = cLenSrc1 + cLenSrc2;
+            *pcRead = cToRead;
     }
 
 #ifdef DEBUG
-    AudioMixBufDbgPrint(pMixBuf);
-#endif
-
-    AUDMIXBUF_LOG(("cRead=%RU32 (%zu bytes), rc=%Rrc\n",
-                   cLenSrc1 + cLenSrc2,
-                   AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1 + cLenSrc2), rc));
+    audioMixBufDbgPrintInternal(pMixBuf);
+#endif
+
+    AUDMIXBUF_LOG(("cRead=%RU32 (%zu bytes), rc=%Rrc\n", cToRead, AUDIOMIXBUF_S2B(pMixBuf, cToRead), rc));
     return rc;
 }
@@ -1492,7 +1481,8 @@
     AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
 
-    pMixBuf->offReadWrite = 0;
-    pMixBuf->cMixed       = 0;
-    pMixBuf->cProcessed   = 0;
+    pMixBuf->offRead  = 0;
+    pMixBuf->offWrite = 0;
+    pMixBuf->cMixed   = 0;
+    pMixBuf->cUsed    = 0;
 
     AudioMixBufClear(pMixBuf);
@@ -1571,7 +1561,7 @@
 
     PPDMAUDIOMIXBUF pIter;
-    while (!RTListIsEmpty(&pMixBuf->lstBuffers))
-    {
-        pIter = RTListGetFirst(&pMixBuf->lstBuffers, PDMAUDIOMIXBUF, Node);
+    while (!RTListIsEmpty(&pMixBuf->lstChildren))
+    {
+        pIter = RTListGetFirst(&pMixBuf->lstChildren, PDMAUDIOMIXBUF, Node);
 
         AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pIter->pszName));
@@ -1633,5 +1623,5 @@
     uint32_t cDstSamples = pMixBuf->pParent
                          ? pMixBuf->pParent->cSamples : pMixBuf->cSamples;
-    uint32_t cLive = pMixBuf->cProcessed;
+    uint32_t cLive = pMixBuf->cUsed;
 
     uint32_t cDead = cDstSamples - cLive;
@@ -1677,5 +1667,5 @@
         cWritten = pConv(pMixBuf->pSamples + offSamples, pvBuf, cbBuf, &convOpts);
 #ifdef DEBUG
-        AudioMixBufDbgPrint(pMixBuf);
+        audioMixBufDbgPrintInternal(pMixBuf);
 #endif
         rc = cWritten ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Fudge! */
@@ -1727,6 +1717,5 @@
  */
 int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
-                           const void *pvBuf, uint32_t cbBuf,
-                           uint32_t *pcWritten)
+                           const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
 {
     AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
@@ -1747,5 +1736,5 @@
 
     if (   pParent
-        && pParent->cSamples <= pMixBuf->cMixed)
+        && pParent->cSamples < pMixBuf->cMixed)
     {
         if (pcWritten)
@@ -1775,5 +1764,5 @@
     AssertMsg(cToWrite, ("cToWrite is 0 (cbBuf=%zu)\n", cbBuf));
 
-    PPDMAUDIOSAMPLE pSamplesDst1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
+    PPDMAUDIOSAMPLE pSamplesDst1 = pMixBuf->pSamples + pMixBuf->offWrite;
     uint32_t cLenDst1 = cToWrite;
 
@@ -1781,5 +1770,5 @@
     uint32_t cLenDst2 = 0;
 
-    uint32_t cOffWrite = pMixBuf->offReadWrite + cToWrite;
+    uint32_t cOffWrite = pMixBuf->offWrite + cToWrite;
 
     /*
@@ -1790,6 +1779,6 @@
     if (cOffWrite >= pMixBuf->cSamples)
     {
-        Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
-        cLenDst1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
+        Assert(pMixBuf->offWrite <= pMixBuf->cSamples);
+        cLenDst1 = pMixBuf->cSamples - pMixBuf->offWrite;
 
         pSamplesDst2 = pMixBuf->pSamples;
@@ -1803,5 +1792,5 @@
 #ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
     RTFILE fh;
-    RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writecirc_ex-32bit-float.pcm",
+    RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writecirc_ex.pcm",
                RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
 #endif
@@ -1816,9 +1805,9 @@
     {
         convOpts.cSamples = cLenDst1;
-        cWrittenTotal = pCnvFrm(pSamplesDst1, pvBuf, cbBuf, &convOpts);
+        cWrittenTotal = pCnvFrm(pSamplesDst1, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), &convOpts);
         Assert(cWrittenTotal == cLenDst1);
 
 #ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
-        RTFileWrite(fh, pvBuf, cbBuf, NULL);
+        RTFileWrite(fh, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), NULL);
 #endif
     }
@@ -1831,9 +1820,13 @@
 
         convOpts.cSamples = cLenDst2;
-        cWrittenTotal += pCnvFrm(pSamplesDst2, (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), cbBuf, &convOpts);
+        cWrittenTotal += pCnvFrm(pSamplesDst2,
+                                 (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
+                                 cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
+                                 &convOpts);
         Assert(cWrittenTotal == (cLenDst1 + cLenDst2));
 
 #ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
-        RTFileWrite(fh, (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), cbBuf, NULL);
+        RTFileWrite(fh, (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
+                    cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), NULL);
 #endif
     }
@@ -1845,13 +1838,13 @@
     if (RT_SUCCESS(rc))
     {
-        pMixBuf->offReadWrite = cOffWrite % pMixBuf->cSamples;
-        pMixBuf->cProcessed   = RT_MIN(pMixBuf->cProcessed + cLenDst1 + cLenDst2,
-                                       pMixBuf->cSamples /* Max */);
-
-        uint32_t cProcessedTotal = pMixBuf->cProcessed + cLenDst1 + cLenDst2;
+        pMixBuf->offWrite = (pMixBuf->offWrite + cWrittenTotal) % pMixBuf->cSamples;
+        pMixBuf->cUsed    = RT_MIN(pMixBuf->cUsed + cWrittenTotal,
+                                   pMixBuf->cSamples /* Max */);
+
+        uint32_t cProcessedTotal = pMixBuf->cUsed + cWrittenTotal;
         if (cProcessedTotal > pMixBuf->cSamples)
         {
             AUDMIXBUF_LOG(("Warning: %RU32 unprocessed samples overwritten\n", cProcessedTotal - pMixBuf->cSamples));
-            pMixBuf->cProcessed = pMixBuf->cSamples;
+            pMixBuf->cUsed = pMixBuf->cSamples;
 
             rc = VINF_BUFFER_OVERFLOW;
@@ -1859,13 +1852,13 @@
 
         if (pcWritten)
-            *pcWritten = cLenDst1 + cLenDst2;
+            *pcWritten = cWrittenTotal;
     }
 
 #ifdef DEBUG
-    AudioMixBufDbgPrint(pMixBuf);
-#endif
-
-    AUDMIXBUF_LOG(("offReadWrite=%RU32, cLenDst1=%RU32, cLenDst2=%RU32, cTotal=%RU32 (%zu bytes), rc=%Rrc\n",
-                   pMixBuf->offReadWrite, cLenDst1, cLenDst2, cLenDst1 + cLenDst2,
+    audioMixBufDbgPrintInternal(pMixBuf);
+#endif
+
+    AUDMIXBUF_LOG(("offWrite=%RU32, cLenDst1=%RU32, cLenDst2=%RU32, cTotal=%RU32 (%zu bytes), rc=%Rrc\n",
+                   pMixBuf->offWrite, cLenDst1, cLenDst2, cLenDst1 + cLenDst2,
                    AUDIOMIXBUF_S2B(pMixBuf, cLenDst1 + cLenDst2), rc));
 
Index: trunk/src/VBox/Devices/Audio/AudioMixBuffer.h
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixBuffer.h	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/AudioMixBuffer.h	(revision 61320)
@@ -62,7 +62,6 @@
 int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent);
 uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf);
-int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
 int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
-uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf);
+uint32_t AudioMixBufUsed(PPDMAUDIOMIXBUF pMixBuf);
 int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
 int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
Index: trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61320)
@@ -405,4 +405,6 @@
     }
 
+    RTStrPrintf(CfgSink.szName, sizeof(CfgSink.szName), "%s", pCfg->szName);
+
     /* Always use the sink's PCM audio format as the host side when creating a stream for it. */
     PPDMAUDIOSTREAM pStream;
@@ -583,4 +585,7 @@
     /** @todo Handle mixing operation enmOp! */
 
+    AssertMsg(pSink->enmDir == AUDMIXSINKDIR_INPUT,
+              ("Can't read from a sink which is not an input sink\n"));
+
     uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
     if (!pvMixBuf)
@@ -797,4 +802,6 @@
     int rc = VINF_SUCCESS;
 
+    Log3Func(("[%s]\n", pSink->pszName));
+
     PAUDMIXSTREAM pMixStream;
     RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
@@ -803,28 +810,25 @@
         AssertPtr(pStream);
 
-        uint32_t cSamplesAvail;
-        uint32_t cSamplesProcessed = 0;
-
-        rc = pMixStream->pConn->pfnStreamGetData(pMixStream->pConn, pStream, &cSamplesAvail);
-        if (   RT_SUCCESS(rc)
-            && cSamplesAvail)
+        uint32_t cPlayed = 0;
+
+        rc = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream);
+        if (RT_SUCCESS(rc))
         {
             if (pStream->enmDir == PDMAUDIODIR_IN)
             {
                 /** @todo Implement this! */
-            //  rc = pStream->pConn->pfnCapture(pStream->pConn, NULL /* pcSamplesCaptured */);
+#if 0
+                rc = pStream->pConn->pfnStreamCapture(pStream->pConn, NULL /* pcSamplesCaptured */);
+#endif
             }
             else
             {
-                rc = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pStream, &cSamplesProcessed);
+                rc = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pMixStream->pStream, &cPlayed);
+                if (RT_FAILURE(rc))
+                    LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc));
             }
-
-            pSink->fFlags |= AUDMIXSINK_FLAG_DIRTY;
         }
-        else if (!cSamplesAvail)
-            pSink->fFlags &= ~AUDMIXSINK_FLAG_DIRTY;
-
-        Log3Func(("[%s]: fFlags=0x%x, %RU32/%RU32 samples, rc=%Rrc\n",
-                  pSink->pszName, pSink->fFlags, cSamplesProcessed, cSamplesAvail, rc));
+
+        Log3Func(("\t%s: cPlayed=%RU32, rc=%Rrc\n", pMixStream->pStream->szName, cPlayed, rc));
     }
 
@@ -884,5 +888,11 @@
     }
 
-    uint32_t cbProcessed = 0;
+    AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT,
+              ("Can't write to a sink which is not an output sink\n"));
+
+    LogFlowFunc(("%s: enmOp=%ld, cbBuf=%RU32\n", pSink->pszName, enmOp, cbBuf));
+
+    uint32_t cPlayed;
+    uint32_t cbProcessed;
 
     PAUDMIXSTREAM pMixStream;
@@ -893,10 +903,13 @@
 
         int rc2 = pMixStream->pConn->pfnStreamWrite(pMixStream->pConn, pMixStream->pStream, pvBuf, cbBuf, &cbProcessed);
-        if (   RT_FAILURE(rc2)
-            || cbProcessed < cbBuf)
-        {
-            LogFlowFunc(("rc=%Rrc, cbBuf=%RU32, cbProcessed=%RU32\n", rc2, cbBuf, cbProcessed));
-        }
-    }
+        if (RT_FAILURE(rc2))
+            LogFlowFunc(("%s: Failed writing to stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
+
+        if (cbProcessed < cbBuf)
+            LogFlowFunc(("%s: Only written %RU32/%RU32 bytes\n", pSink->pszName, pMixStream->pStream->szName, cbProcessed, cbBuf));
+    }
+
+    /* Set dirty bit. */
+    pSink->fFlags |= AUDMIXSINK_FLAG_DIRTY;
 
     if (pcbWritten)
Index: trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61320)
@@ -55,5 +55,5 @@
 #define AC97_SSM_VERSION 1
 
-#define AC97_TIMER_HZ 100
+#define AC97_TIMER_HZ 50
 
 #ifdef VBOX
Index: trunk/src/VBox/Devices/Audio/DevSB16.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevSB16.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/DevSB16.cpp	(revision 61320)
@@ -78,6 +78,4 @@
     /** PCM output stream. */
     R3PTRTYPE(PPDMAUDIOSTREAM)         pStream;
-    /** Mixer handle for output stream. */
-    R3PTRTYPE(PAUDMIXSTREAM)           pMixStrm;
 } SB16OUTPUTSTREAM, *PSB16OUTPUTSTREAM;
 
@@ -169,8 +167,4 @@
 
     RTLISTANCHOR                   lstDrv;
-    /** The device' software mixer. */
-    R3PTRTYPE(PAUDIOMIXER)         pMixer;
-    /** Audio sink for PCM output. */
-    R3PTRTYPE(PAUDMIXSINK)         pSinkOutput;
     /** Number of active (running) SDn streams. */
     uint8_t                        cStreamsActive;
@@ -178,4 +172,7 @@
     /** The timer for pumping data thru the attached LUN drivers. */
     PTMTIMERR3                     pTimerIO;
+    /** Flag indicating whether the timer is active or not. */
+    bool                           fTimerActive;
+    uint8_t                        u8Padding1[7];
     /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
     uint64_t                       cTimerTicksIO;
@@ -194,4 +191,5 @@
 
 static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
+static void sb16CloseOut(PSB16STATE pThis);
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
 static void sb16TimerMaybeStart(PSB16STATE pThis);
@@ -451,6 +449,11 @@
 #endif
 
-    AudioMixerSinkCtl(pThis->pSinkOutput,
-                      hold == 1 ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
+    PSB16DRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+    {
+        int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream,
+                                                     hold == 1 ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
+        LogFlowFunc(("%s: rc=%Rrc\n", pDrv->Out.pStream->szName, rc2));
+    }
 }
 
@@ -471,9 +474,10 @@
         PDMAUDIOSTREAMCFG streamCfg;
         RT_ZERO(streamCfg);
-        streamCfg.enmDir        = PDMAUDIODIR_OUT;
-        streamCfg.uHz           = pThis->freq;
-        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
-        streamCfg.enmFormat     = pThis->fmt;
-        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+        streamCfg.enmDir          = PDMAUDIODIR_OUT;
+        streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+        streamCfg.uHz             = pThis->freq;
+        streamCfg.cChannels       = 1 << pThis->fmt_stereo;
+        streamCfg.enmFormat       = pThis->fmt;
+        streamCfg.enmEndianness   = PDMAUDIOHOSTENDIANNESS;
 
         int rc = sb16OpenOut(pThis, &streamCfg);
@@ -608,9 +612,10 @@
         PDMAUDIOSTREAMCFG streamCfg;
         RT_ZERO(streamCfg);
-        streamCfg.enmDir        = PDMAUDIODIR_OUT;
-        streamCfg.uHz           = pThis->freq;
-        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
-        streamCfg.enmFormat     = pThis->fmt;
-        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+        streamCfg.enmDir          = PDMAUDIODIR_OUT;
+        streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+        streamCfg.uHz             = pThis->freq;
+        streamCfg.cChannels       = 1 << pThis->fmt_stereo;
+        streamCfg.enmFormat       = pThis->fmt;
+        streamCfg.enmEndianness   = PDMAUDIOHOSTENDIANNESS;
 
         int rc = sb16OpenOut(pThis, &streamCfg);
@@ -1101,5 +1106,6 @@
     uint8_t rvol = sb16MixRegToVol(pThis, 0x31);
     PDMAUDIOVOLUME vol = { false, lvol, rvol };
-    AudioMixerSetMasterVolume(pThis->pMixer, &vol);
+
+//    AudioMixerSetMasterVolume(pThis->pMixer, &vol);
 }
 
@@ -1110,9 +1116,12 @@
     uint8_t rvol = sb16MixRegToVol(pThis, 0x33);
     PDMAUDIOVOLUME vol = { false, lvol, rvol };
-    AudioMixerSinkSetVolume(pThis->pSinkOutput, &vol);
+
+  //  AudioMixerSinkSetVolume(pThis->pSinkOutput, &vol);
 }
 
 static void sb16ResetLegacy(PSB16STATE pThis)
 {
+    sb16CloseOut(pThis);
+
     pThis->freq       = 11025;
     pThis->fmt_signed = 0;
@@ -1122,9 +1131,10 @@
     PDMAUDIOSTREAMCFG streamCfg;
     RT_ZERO(streamCfg);
-    streamCfg.enmDir        = PDMAUDIODIR_OUT;
-    streamCfg.uHz           = pThis->freq;
-    streamCfg.cChannels     = 1; /* Mono */
-    streamCfg.enmFormat     = PDMAUDIOFMT_U8;
-    streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+    streamCfg.enmDir          = PDMAUDIODIR_OUT;
+    streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+    streamCfg.uHz             = pThis->freq;
+    streamCfg.cChannels       = 1; /* Mono */
+    streamCfg.enmFormat       = PDMAUDIOFMT_U8;
+    streamCfg.enmEndianness   = PDMAUDIOHOSTENDIANNESS;
 
     int rc2 = sb16OpenOut(pThis, &streamCfg);
@@ -1332,17 +1342,4 @@
 static void sb16MixerReset(PSB16STATE pThis)
 {
-    PSB16DRIVER pDrv;
-
-    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
-        pDrv->Out.pMixStrm = NULL;
-
-    pThis->pSinkOutput = NULL;
-
-    if (pThis->pMixer)
-    {
-        AudioMixerDestroy(pThis->pMixer);
-        pThis->pMixer = NULL;
-    }
-
     memset(pThis->mixer_regs, 0xff, 0x7f);
     memset(pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
@@ -1373,22 +1370,4 @@
     for (int i = 0x44; i < 0x48; i++)
         pThis->mixer_regs[i] = 0x80;
-
-    int rc2 = AudioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer);
-    if (RT_SUCCESS(rc2))
-    {
-        /* Set a default audio format for our mixer. */
-        PDMAUDIOSTREAMCFG streamCfg;
-        streamCfg.uHz           = 44100;
-        streamCfg.cChannels     = 2;
-        streamCfg.enmFormat     = PDMAUDIOFMT_S16;
-        streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
-        rc2 = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
-        AssertRC(rc2);
-
-        /* Add all required audio sinks. */
-        rc2 = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
-        AssertRC(rc2);
-    }
 
     /* Update the master (mixer) and PCM out volumes. */
@@ -1642,10 +1621,15 @@
 
         /*
-         * Write data to the mixer sink.
+         * Write data to the backends.
          */
-        uint32_t cbWritten;
-        rc = AudioMixerSinkWrite(pThis->pSinkOutput, AUDMIXOP_COPY, tmpbuf, cbToRead, &cbWritten);
-        if (RT_FAILURE(rc))
-            break;
+        uint32_t cbWritten = 0;
+
+        PSB16DRIVER pDrv;
+        RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+        {
+            int rc2 = pDrv->pConnector->pfnStreamWrite(pDrv->pConnector, pDrv->Out.pStream, tmpbuf, cbToRead, &cbWritten);
+            if (RT_FAILURE(rc2))
+                LogFlowFunc(("Failed writing to stream '%s': %Rrc\n", &pDrv->Out.pStream->szName, rc2));
+        }
 
         LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbWritten=%RU32, cbLeft=%RU32, rc=%Rrc\n",
@@ -1680,25 +1664,11 @@
 
     PSB16DRIVER pDrv;
-
-    uint32_t cbOutMin = UINT32_MAX;
-    uint32_t cbOut;
     RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
-    {
-        int rc2 = pDrv->pConnector->pfnStreamGetData(pDrv->pConnector, pDrv->Out.pStream, &cbOut);
-        if (RT_SUCCESS(rc2))
-            cbOutMin = RT_MIN(cbOutMin, cbOut);
-    }
-
-    LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
-    if (cbOutMin == UINT32_MAX)
-    {
-        free = dma_len;
-    }
-    else
-    {
-        free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
-        if ((free <= 0) || !dma_len)
-            return dma_pos;
-    }
+        pDrv->pConnector->pfnStreamIterate(pDrv->pConnector, pDrv->Out.pStream);
+
+    free = dma_len;
+
+    if (free <= 0)
+        return dma_pos;
 
     copy = free;
@@ -1761,4 +1731,7 @@
         return;
 
+    /* Set timer flag. */
+    ASMAtomicXchgBool(&pThis->fTimerActive, true);
+
     /* Update current time timestamp. */
     pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
@@ -1778,6 +1751,6 @@
         return;
 
-    int rc2 = TMTimerStop(pThis->pTimerIO);
-    AssertRC(rc2);
+    /* Set timer flag. */
+    ASMAtomicXchgBool(&pThis->fTimerActive, false);
 }
 
@@ -1794,16 +1767,46 @@
     pThis->uTimerTSIO = cTicksNow;
 
-    uint32_t cbOut;
-    AudioMixerSinkTimerUpdate(pThis->pSinkOutput, cTicksPerSec, cTicksElapsed, &cbOut);
-    if (cbOut)
-    {
-        /* New space available, see if we can transfer more. */
+    bool fIsPlaying = false;
+
+    LogFlowFuncEnter();
+
+    PSB16DRIVER pDrv;
+    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+    {
+        PPDMAUDIOSTREAM pStream = pDrv->Out.pStream;
+
+        PDMAUDIOSTRMSTS strmSts = pDrv->pConnector->pfnStreamGetStatus(pDrv->pConnector, pStream);
+        fIsPlaying |= (   (strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+                       || (strmSts & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE));
+
+        LogFlowFunc(("%s: strmSts=0x%x -> fIsPlaying=%RTbool\n", pStream->szName, strmSts, fIsPlaying));
+
+        int rc2 = pDrv->pConnector->pfnStreamIterate(pDrv->pConnector, pStream);
+        if (RT_SUCCESS(rc2))
+        {
+            if (pStream->enmDir == PDMAUDIODIR_IN)
+            {
+                /** @todo Implement this! */
+            }
+            else
+            {
+                rc2 = pDrv->pConnector->pfnStreamPlay(pDrv->pConnector, pStream, NULL /* cPlayed */);
+                if (RT_FAILURE(rc2))
+                    LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pStream->szName, rc2));
+            }
+        }
+    }
+
+    if (   ASMAtomicReadBool(&pThis->fTimerActive)
+        || fIsPlaying)
+    {
+        /* Schedule the next transfer. */
         PDMDevHlpDMASchedule(pThis->pDevInsR3);
-    }
-
-    /* Kick the timer again. */
-    uint64_t cTicks = pThis->cTimerTicksIO;
-    /** @todo adjust cTicks down by now much cbOutMin represents. */
-    TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
+
+        /* Kick the timer again. */
+        uint64_t cTicks = pThis->cTimerTicksIO;
+        /** @todo adjust cTicks down by now much cbOutMin represents. */
+        TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
+    }
 }
 
@@ -1934,9 +1937,10 @@
             PDMAUDIOSTREAMCFG streamCfg;
             RT_ZERO(streamCfg);
-            streamCfg.enmDir        = PDMAUDIODIR_OUT;
-            streamCfg.uHz           = pThis->freq;
-            streamCfg.cChannels     = 1 << pThis->fmt_stereo;
-            streamCfg.enmFormat     = pThis->fmt;
-            streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+            streamCfg.enmDir          = PDMAUDIODIR_OUT;
+            streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+            streamCfg.uHz             = pThis->freq;
+            streamCfg.cChannels       = 1 << pThis->fmt_stereo;
+            streamCfg.enmFormat       = pThis->fmt;
+            streamCfg.enmEndianness   = PDMAUDIOHOSTENDIANNESS;
 
             int rc = sb16OpenOut(pThis, &streamCfg);
@@ -2028,16 +2032,20 @@
     AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
 
-    /* Update the sink's format. */
-    PDMPCMPROPS PCMProps;
-    int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
-    if (RT_SUCCESS(rc))
-        rc = AudioMixerSinkSetFormat(pThis->pSinkOutput, &PCMProps);
-
-    if (RT_FAILURE(rc))
-        return rc;
+    int rc = VINF_SUCCESS;
+
+    /* Set a default audio format for the host. */
+    PDMAUDIOSTREAMCFG CfgHost;
+    CfgHost.enmDir          = PDMAUDIODIR_OUT;
+    CfgHost.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+    CfgHost.uHz             = 44100;
+    CfgHost.cChannels       = 2;
+    CfgHost.enmFormat       = PDMAUDIOFMT_S16;
+    CfgHost.enmEndianness   = PDMAUDIOHOSTENDIANNESS;
+
+    RTStrPrintf(CfgHost.szName, sizeof(CfgHost.szName), "sb16.po");
+
+    uint8_t uLUN = 0;
 
     PSB16DRIVER pDrv;
-    uint8_t uLUN = 0;
-
     RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     {
@@ -2049,28 +2057,17 @@
         }
 
-        AudioMixerSinkRemoveStream(pThis->pSinkOutput, pDrv->Out.pMixStrm);
-
-        AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
-        pDrv->Out.pMixStrm = NULL;
-
-        int rc2 = AudioMixerSinkCreateStream(pThis->pSinkOutput, pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
-        if (RT_SUCCESS(rc2))
+        if (pDrv->Out.pStream)
         {
-            rc2 = AudioMixerSinkAddStream(pThis->pSinkOutput, pDrv->Out.pMixStrm);
-            LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
+            int rc3 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
+            AssertRC(rc3);
+
+            pDrv->Out.pStream = NULL;
         }
 
-        if (RT_FAILURE(rc2))
-        {
-            if (RT_SUCCESS(rc))
-                rc = rc2;
-            break;
-        }
+        int rc2 = pDrv->pConnector->pfnStreamCreate(pDrv->pConnector, &CfgHost, pCfg, &pDrv->Out.pStream);
+        LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
 
         uLUN++;
     }
-
-    /* Ensure volume gets propagated. */
-    AudioMixerInvalidate(pThis->pMixer);
 
     return rc;
@@ -2086,7 +2083,9 @@
     RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     {
-        AudioMixerSinkRemoveStream(pThis->pSinkOutput, pDrv->Out.pMixStrm);
-        AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
-        pDrv->Out.pMixStrm = NULL;
+        if (pDrv->Out.pStream)
+        {
+            pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
+            pDrv->Out.pStream = NULL;
+        }
     }
 }
@@ -2148,14 +2147,5 @@
     LogRel2(("SB16: Powering off ...\n"));
 
-    /**
-     * Note: Destroy the mixer while powering off and *not* in sb16Destruct,
-     *       giving the mixer the chance to release any references held to
-     *       PDM audio streams it maintains.
-     */
-    if (pThis->pMixer)
-    {
-        AudioMixerDestroy(pThis->pMixer);
-        pThis->pMixer = NULL;
-    }
+    sb16CloseOut(pThis);
 }
 
@@ -2177,6 +2167,4 @@
         RTMemFree(pDrv);
     }
-
-    sb16CloseOut(pThis);
 
     return VINF_SUCCESS;
@@ -2339,5 +2327,6 @@
 
         /** @todo No input streams available for SB16 yet. */
-        bool fValidOut = AudioMixerStreamIsValid(pDrv->Out.pMixStrm);
+        /* Note: Only query the whole backend status here, as we don't have multiple streams to check for. */
+        bool fValidOut = pCon->pfnGetStatus(pCon, PDMAUDIODIR_OUT) == PDMAUDIOBACKENDSTS_RUNNING;
         if (!fValidOut)
         {
Index: trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61320)
@@ -67,4 +67,5 @@
 static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream);
 static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd);
+static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd);
 static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream);
 static int drvAudioStreamDestroyInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream);
@@ -252,21 +253,96 @@
 static DECLCALLBACK(int) drvAudioStreamControl(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
 {
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
 
-    return drvAudioStreamControlInternal(pThis, pStream, enmStreamCmd);
-}
-
-static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
     int rc = RTCritSectEnter(&pThis->CritSect);
     if (RT_FAILURE(rc))
         return rc;
 
+    LogFlowFunc(("%s\n", pStream->szName));
+
     PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+
+    /* Note: Call the host (backend) first to see if there is any pending disable
+     *       actions in progress. */
+    rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, enmStreamCmd);
+    if (   RT_SUCCESS(rc)
+        || rc == VERR_AUDIO_STREAM_PENDING_DISABLE)
+    {
+        int rc3 = drvAudioStreamControlInternal(pThis, pStream, enmStreamCmd);
+        if (RT_SUCCESS(rc))
+            rc = rc3;
+    }
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pGstStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    if (!pGstStream)
+        return VINF_SUCCESS;
+
+    int rc = VINF_SUCCESS;
+
+    switch (enmStreamCmd)
+    {
+        case PDMAUDIOSTREAMCMD_ENABLE:
+        {
+            pGstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_DISABLE:
+        {
+            pGstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_ENABLED;
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_PAUSE:
+        {
+            pGstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
+            break;
+        }
+
+        case PDMAUDIOSTREAMCMD_RESUME:
+        {
+            pGstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
+            break;
+        }
+
+        default:
+            AssertMsgFailed(("Command %ld not implemented\n", enmStreamCmd));
+            rc = VERR_NOT_IMPLEMENTED;
+            break;
+    }
+
+    LogFlowFunc(("%s: enmStreamCmd=%ld, rc=%Rrc\n", pGstStream->szName, enmStreamCmd, rc));
+    return rc;
+}
+
+static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    if (!pHstStream)
+        return VINF_SUCCESS;
+
+    AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
+              ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));
 
     LogFlowFunc(("%s: enmStreamCmd=%ld\n", pHstStream->szName, enmStreamCmd));
+
+    int rc = VINF_SUCCESS;
+
+    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair; /* Can be NULL. */
 
     switch (enmStreamCmd)
@@ -278,12 +354,6 @@
                 rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_ENABLE);
                 if (RT_SUCCESS(rc))
-                {
-                    Assert(!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE));
                     pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
-                }
-            }
-            else
-                rc = VINF_SUCCESS;
-
+            }
             break;
         }
@@ -291,4 +361,18 @@
         case PDMAUDIOSTREAMCMD_DISABLE:
         {
+            /* Is the guest side stream still active?
+             * Mark the host stream as pending disable and bail out. */
+            if (   pGstStream
+                && (pGstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
+            {
+                LogFlowFunc(("%s: Pending disable\n", pHstStream->szName));
+                pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+                rc = VERR_AUDIO_STREAM_PENDING_DISABLE;
+                break;
+            }
+
+            /* Clear pending disable bit. */
+            pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+
             if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
             {
@@ -297,10 +381,7 @@
                 {
                     pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_ENABLED;
-                    AudioMixBufClear(&pHstStream->MixBuf);
+                    AudioMixBufReset(&pHstStream->MixBuf);
                 }
             }
-            else
-                rc = VINF_SUCCESS;
-
             break;
         }
@@ -308,4 +389,15 @@
         case PDMAUDIOSTREAMCMD_PAUSE:
         {
+            /* Is the guest side stream still active?
+             * Mark the host stream as pending disable and bail out. */
+            if (   pGstStream
+                && (pGstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
+            {
+                LogFlowFunc(("%s: Pending pause\n", pHstStream->szName));
+                pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+                rc = VERR_AUDIO_STREAM_PENDING_DISABLE;
+                break;
+            }
+
             if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
             {
@@ -314,7 +406,4 @@
                     pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
             }
-            else
-                rc = VINF_SUCCESS;
-
             break;
         }
@@ -328,7 +417,4 @@
                     pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
             }
-            else
-                rc = VINF_SUCCESS;
-
             break;
         }
@@ -342,8 +428,4 @@
     if (RT_FAILURE(rc))
         LogFunc(("%s: Failed with %Rrc\n", pHstStream->szName, rc));
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
 
     return rc;
@@ -381,4 +463,6 @@
     }
 
+    LogFlowFunc(("[%s]: cbBuf=%RU32\n", pStream->szName, cbBuf));
+
     int rc = RTCritSectEnter(&pThis->CritSect);
     if (RT_FAILURE(rc))
@@ -396,8 +480,8 @@
     PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
 
-    AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
-              ("Writing to disabled host output stream \"%s\" not possible\n", pHstStream->szName));
-
-    if (!AudioMixBufFreeBytes(&pHstStream->MixBuf))
+    AssertMsg(pGstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
+              ("Writing to disabled guest output stream \"%s\" not possible\n", pGstStream->szName));
+
+    if (!AudioMixBufFreeBytes(&pGstStream->MixBuf))
     {
         if (pcbWritten)
@@ -407,21 +491,30 @@
     }
 
-    /*
-     * First, write data from the device emulation into our
-     * guest mixing buffer.
-     */
-    uint32_t cWritten;
+    uint32_t cWritten = 0;
     rc = AudioMixBufWriteCirc(&pGstStream->MixBuf, pvBuf, cbBuf, &cWritten);
     if (rc == VINF_BUFFER_OVERFLOW)
+    {
         LogRelMax(32, ("Audio: Lost audio samples from guest, expect stuttering audio output\n"));
-
-    /* Host stream currently has no samples to play? */
-    if (AudioMixBufAvail(&pHstStream->MixBuf) == 0)
+        rc = VINF_SUCCESS;
+    }
+
+#if 0
+    uint32_t cMixed = 0;
+    if (RT_SUCCESS(rc))
     {
         /* Mix just written guest stream samples to the host immediately. */
-        uint32_t cMixed;
         rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cWritten, &cMixed);
-        LogFlowFunc(("cMixed=%RU32\n", cMixed));
-    }
+    }
+#endif
+
+#if 0
+    uint32_t cPlayed = 0;
+    if (RT_SUCCESS(rc))
+    {
+        PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
+        if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)
+            rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cPlayed);
+    }
+#endif
 
 #ifdef DEBUG_andy
@@ -461,7 +554,6 @@
 #endif
 
-    LogFlowFunc(("%s -> %s: cbBuf=%RU32, cWritten=%RU32 (%RU32 bytes), rc=%Rrc\n",
-                 pGstStream->szName, pHstStream->szName, cbBuf,
-                 cWritten, AUDIOMIXBUF_S2B(&pHstStream->MixBuf, cWritten), rc));
+    LogFlowFunc(("cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
+                 cWritten, AUDIOMIXBUF_S2B(&pHstStream->MixBuf, cWritten), 0, rc));
 
     int rc2 = RTCritSectLeave(&pThis->CritSect);
@@ -581,5 +673,5 @@
 
 #if 1
-static DECLCALLBACK(int) drvAudioStreamGetData(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcData)
+static DECLCALLBACK(int) drvAudioStreamIterate(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
 {
     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
@@ -593,5 +685,5 @@
         return rc;
 
-    uint32_t cData = 0;
+    LogFlowFunc(("[%s]\n", pStream->szName));
 
     PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
@@ -600,11 +692,14 @@
     do
     {
-        if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
-            break;
+        /*if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
+            break;*/
+
+        PDMAUDIOSTRMSTS hstStrmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
 
         if (pHstStream->enmDir == PDMAUDIODIR_IN)
         {
             /* Call the host backend to capture the audio input data. */
-            rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cData);
+            uint32_t cSamplesCaptured;
+            rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured);
             if (RT_FAILURE(rc))
                 break;
@@ -613,18 +708,8 @@
 
         }
-        else /* Out */
+        else /* PDMAUDIODIR_OUT */
         {
             uint32_t cSamplesMixed = 0;
-            uint32_t cSamplesToMix = 0;
-
-            uint32_t cSamplesLive = AudioMixBufAvail(&pHstStream->MixBuf);
-            if (!cSamplesLive)
-            {
-
-            }
-
-            cSamplesToMix = AudioMixBufAvail(&pGstStream->MixBuf);
-            if (cSamplesToMix)
-                rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cSamplesToMix, &cSamplesMixed);
+            uint32_t cSamplesToMix = AudioMixBufUsed(&pGstStream->MixBuf);
 
             /* Has this stream marked as disabled but there still were guest streams relying
@@ -633,33 +718,34 @@
                 && !cSamplesToMix)
             {
-                /* Stop playing the current (pending) stream. */
-                int rc2 = drvAudioStreamControlInternal(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
-                if (RT_SUCCESS(rc2))
-                {
-                    pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
-
-                    LogFunc(("%s: Disabling stream\n", pHstStream->szName));
-                }
-                else
-                    LogFunc(("%s: Backend vetoed against closing output stream, rc=%Rrc\n", pHstStream->szName, rc2));
+                rc = drvAudioStreamControlInternal(pThis, pGstStream, PDMAUDIOSTREAMCMD_DISABLE);
+                if (RT_SUCCESS(rc))
+                    rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+
+                if (RT_FAILURE(rc))
+                    LogFunc(("%s: Backend vetoed against closing output stream, rc=%Rrc\n", pHstStream->szName, rc));
 
                 break;
             }
 
-            LogFlowFunc(("%s: cSamplesLive=%RU32, cSamplesToMix=%RU32, cSamplesMixed=%RU32\n",
-                         pHstStream->szName, cSamplesLive, cSamplesToMix, cSamplesMixed));
-
-            /* Return live samples to play. */
-            cData = cSamplesLive;
-        }
+            uint32_t cSamplesPlayed = 0;
+            if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)
+            {
+            /*    int rc2 = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cSamplesPlayed);
+                if (RT_SUCCESS(rc))
+                    rc = rc2;
+            }*/
+
+                if (cSamplesToMix)
+                    rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cSamplesToMix, &cSamplesMixed);
+            }
+
+            LogFlowFunc(("%s: %RU32/%RU32 samples mixed, %RU32 played\n",
+                         pHstStream->szName, cSamplesMixed, cSamplesToMix, cSamplesPlayed));
+        }
+
+        if (RT_SUCCESS(rc))
+            rc = pThis->pHostDrvAudio->pfnStreamIterate(pThis->pHostDrvAudio, pHstStream);
 
     } while (0);
-
-#ifdef DEBUG_andy
-    LogFlowFunc(("%s: cData=%RU32\n", pHstStream->szName, cData));
-#endif
-
-    if (pcData)
-        *pcData = cData;
 
     int rc2 = RTCritSectLeave(&pThis->CritSect);
@@ -846,4 +932,7 @@
     /* pcSamplesPlayed is optional. */
 
+    AssertMsg(pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED,
+              ("Unable to play stream '%s' (status is 0x%x)\n", pStream->szName, pStream->fStatus));
+
     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
 
@@ -852,65 +941,68 @@
         return rc;
 
-    /* Backend output (temporarily) disabled / unavailable? */
-    if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_OUT) != PDMAUDIOBACKENDSTS_RUNNING)
-    {
-        rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
-        AssertRC(rc);
-
-        if (   !pThis->BackendCfg.cSinks
-            || !pThis->BackendCfg.cMaxStreamsOut)
-        {
-            int rc2 = RTCritSectLeave(&pThis->CritSect);
-            AssertRC(rc2);
-
-            return VERR_NOT_AVAILABLE;
-        }
-    }
-
-    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    LogFlowFunc(("[%s]\n", pStream->szName));
 
     uint32_t cSamplesPlayed = 0;
-    rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cSamplesPlayed);
-    if (RT_FAILURE(rc))
-    {
-        int rc3 = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
-        AssertRC(rc3);
-    }
-
-    LogFlowFunc(("[%s] cSamplesPlayed=%RU32, rc=%Rrc\n", pStream->szName, cSamplesPlayed, rc));
-
-    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
-    if (pGstStream)
-    {
-        bool fIsEmpty = AudioMixBufIsEmpty(&pGstStream->MixBuf);
-
-
-    }
-
-#if 0
-        if (pStream->pPair)
-        {
-            bool fIsEmpty = AudioMixBufIsEmpty(&pStream->pPair->MixBuf);
-
-            if (   !pPair->State.fActive
-                && fIsEmpty)
-                continue;
-
-            if ()
-            {
-                pGstStrmOut->State.fEmpty = true;
-                fNeedsCleanup |= !pGstStrmOut->State.fActive;
-            }
-        }
-
-        if (fNeedsCleanup)
-        {
-            RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
-            {
-                if (!pGstStrmOut->State.fActive)
-                    drvAudioDestroyGstOut(pThis, pGstStrmOut);
-            }
-        }
-#endif
+
+    do
+    {
+        /* Backend output (temporarily) disabled / unavailable? */
+        if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_OUT) != PDMAUDIOBACKENDSTS_RUNNING)
+        {
+            rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
+            AssertRC(rc);
+
+            if (   !pThis->BackendCfg.cSinks
+                || !pThis->BackendCfg.cMaxStreamsOut)
+            {
+                rc = VERR_NOT_AVAILABLE;
+                break;
+            }
+        }
+
+        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+        PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+        AssertPtr(pGstStream);
+
+        PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
+
+        if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)
+        {
+            rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cSamplesPlayed);
+            if (RT_FAILURE(rc))
+            {
+                int rc3 = drvAudioStreamControlInternalBackend(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
+                AssertRC(rc3);
+            }
+        }
+
+        LogFlowFunc(("[%s] strmSts=0x%x, cSamplesPlayed=%RU32, rc=%Rrc\n", pStream->szName, strmSts, cSamplesPlayed, rc));
+
+    #if 0
+            if (pStream->pPair)
+            {
+                bool fIsEmpty = AudioMixBufIsEmpty(&pStream->pPair->MixBuf);
+
+                if (   !pPair->State.fActive
+                    && fIsEmpty)
+                    continue;
+
+                if ()
+                {
+                    pGstStrmOut->State.fEmpty = true;
+                    fNeedsCleanup |= !pGstStrmOut->State.fActive;
+                }
+            }
+
+            if (fNeedsCleanup)
+            {
+                RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
+                {
+                    if (!pGstStrmOut->State.fActive)
+                        drvAudioDestroyGstOut(pThis, pGstStrmOut);
+                }
+            }
+    #endif
+    } while (0);
 
     if (RT_SUCCESS(rc))
@@ -1574,5 +1666,5 @@
         AssertRCBreak(rc);
 
-        rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples);
+        rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples * 4);
         AssertRCBreak(rc);
 
@@ -1587,13 +1679,15 @@
         AssertRCBreak(rc);
 
-        rc = AudioMixBufInit(&pGstStrm->MixBuf, pGstStrm->szName, &pGstStrm->Props, AudioMixBufSize(&pHstStrm->MixBuf));
+        rc = AudioMixBufInit(&pGstStrm->MixBuf, pGstStrm->szName, &pGstStrm->Props, cSamples * 2);
         if (RT_SUCCESS(rc))
         {
             if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
             {
+                /* Host (Parent) -> Guest (Child). */
                 rc = AudioMixBufLinkTo(&pHstStrm->MixBuf, &pGstStrm->MixBuf);
             }
             else
             {
+                /* Guest (Parent) -> Host (Child). */
                 rc = AudioMixBufLinkTo(&pGstStrm->MixBuf, &pHstStrm->MixBuf);
             }
@@ -1618,5 +1712,5 @@
             if (pHstStrm->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
             {
-                rc = drvAudioStreamControlInternal(pThis, pHstStrm, PDMAUDIOSTREAMCMD_DISABLE);
+                rc = drvAudioStreamControlInternalBackend(pThis, pHstStrm, PDMAUDIOSTREAMCMD_DISABLE);
                 if (RT_SUCCESS(rc))
                 {
@@ -1686,4 +1780,24 @@
 }
 
+static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioGetStatus(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)
+{
+    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return PDMAUDIOBACKENDSTS_UNKNOWN;
+
+    PDMAUDIOBACKENDSTS backendSts = pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, enmDir);
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return backendSts;
+}
+
 static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioStreamGetStatus(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
 {
@@ -1723,35 +1837,22 @@
         rc = VERR_WRONG_ORDER;
 
-    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
-    if (   RT_SUCCESS(rc)
-        && pHstStream->cRefs == 1)
-    {
-        rc = drvAudioStreamDestroyInternalBackend(pThis, pHstStream);
+    if (RT_SUCCESS(rc))
+    {
+        rc = drvAudioStreamDestroyInternal(pThis, pStream);
         if (RT_SUCCESS(rc))
-        {
-            if (pStream->pPair)
-            {
-                rc = drvAudioStreamDestroyInternal(pThis, pStream->pPair);
-                pStream->pPair = NULL;
-            }
-
-            if (RT_SUCCESS(rc))
-                rc = drvAudioStreamDestroyInternal(pThis, pStream);
-
-            if (RT_SUCCESS(rc))
-            {
-                if (enmDir == PDMAUDIODIR_IN)
-                {
-                    pThis->cStreamsFreeIn++;
-                }
-                else /* Out */
-                {
-                    pThis->cStreamsFreeOut++;
-                }
-            }
-        }
-    }
-    else
-        rc = VERR_WRONG_ORDER;
+            pStream = NULL;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (enmDir == PDMAUDIODIR_IN)
+        {
+            pThis->cStreamsFreeIn++;
+        }
+        else /* Out */
+        {
+            pThis->cStreamsFreeOut++;
+        }
+    }
 
     int rc2 = RTCritSectLeave(&pThis->CritSect);
@@ -1767,6 +1868,8 @@
 static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
 {
-    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
-    AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    if (!pHstStream)
+        return VINF_SUCCESS;
 
     int rc = VINF_SUCCESS;
@@ -1779,5 +1882,5 @@
     if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
     {
-        rc = drvAudioStreamControlInternal(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+        rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
         if (RT_SUCCESS(rc))
         {
@@ -1786,6 +1889,4 @@
                 pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
         }
-
-        AssertMsgRC(rc, ("Host stream '%s' failed to uninit in backend: %Rrc\n",  pHstStream->szName, rc));
     }
     else
@@ -1806,7 +1907,21 @@
     LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
 
-    int rc = VINF_SUCCESS;
-
-    if (pStream->cRefs <= 1)
+    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+
+    if (   (   pHstStream
+            && pHstStream->cRefs > 1)
+        || (   pGstStream
+            && pGstStream->cRefs > 1)
+       )
+    {
+        return VERR_WRONG_ORDER;
+    }
+
+    int rc = drvAudioStreamControlInternal(pThis, pGstStream, PDMAUDIOSTREAMCMD_DISABLE);
+    if (RT_SUCCESS(rc))
+        rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+
+    if (RT_SUCCESS(rc))
     {
         /* Unlink from pair. */
@@ -1826,6 +1941,4 @@
         pStream = NULL;
     }
-    else /* More than our own reference left? Bail out. */
-        rc = VERR_WRONG_ORDER;
 
     if (RT_FAILURE(rc))
@@ -1864,13 +1977,7 @@
     LogFlowFuncEnter();
 
-    /*
-     * Second, destroy all audio streams.
-     */
-    PPDMAUDIOSTREAM pStream;
-    RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, Node)
-    {
-        if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)
-            drvAudioStreamDestroyInternalBackend(pThis, pStream);
-    }
+    PPDMAUDIOSTREAM pStream, pStreamNext;
+    RTListForEachSafe(&pThis->lstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node)
+        drvAudioStreamDestroyInternal(pThis, pStream);
 
     /*
@@ -1906,4 +2013,5 @@
     /* IAudioConnector. */
     pThis->IAudioConnector.pfnGetConfig         = drvAudioGetConfig;
+    pThis->IAudioConnector.pfnGetStatus         = drvAudioGetStatus;
     pThis->IAudioConnector.pfnStreamCreate      = drvAudioStreamCreate;
     pThis->IAudioConnector.pfnStreamDestroy     = drvAudioStreamDestroy;
@@ -1913,5 +2021,5 @@
     pThis->IAudioConnector.pfnStreamRead        = drvAudioStreamRead;
     pThis->IAudioConnector.pfnStreamWrite       = drvAudioStreamWrite;
-    pThis->IAudioConnector.pfnStreamGetData     = drvAudioStreamGetData;
+    pThis->IAudioConnector.pfnStreamIterate     = drvAudioStreamIterate;
     pThis->IAudioConnector.pfnStreamGetStatus   = drvAudioStreamGetStatus;
     pThis->IAudioConnector.pfnStreamPlay        = drvAudioStreamPlay;
Index: trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp	(revision 61320)
@@ -1433,4 +1433,15 @@
 
     return (PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED);
+}
+
+static DECLCALLBACK(int) drvHostALSAAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    LogFlowFuncEnter();
+
+    /* Nothing to do here for ALSA. */
+    return VINF_SUCCESS;
 }
 
Index: trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp	(revision 61320)
@@ -278,4 +278,12 @@
 
     return (PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED);
+}
+
+static DECLCALLBACK(int) drvHostNullAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    NOREF(pInterface);
+    NOREF(pStream);
+
+    return VINF_SUCCESS;
 }
 
Index: trunk/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp	(revision 61320)
@@ -1043,4 +1043,15 @@
 
     return rc;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    LogFlowFuncEnter();
+
+    /* Nothing to do here for OSS. */
+    return VINF_SUCCESS;
 }
 
Index: trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61320)
@@ -105,5 +105,5 @@
     uint32_t               cbPCMBuf;
     /** Pointer to opaque PulseAudio stream. */
-    pa_stream             *pStream;
+    pa_stream             *pPAStream;
     /** Pulse sample format and attribute specification. */
     pa_sample_spec         SampleSpec;
@@ -321,6 +321,9 @@
         paError(pStrm->pDrv, "Failed to drain stream");
 
-    pa_operation_unref(pStrm->pDrainOp);
-    pStrm->pDrainOp = NULL;
+    if (pStrm->pDrainOp)
+    {
+        pa_operation_unref(pStrm->pDrainOp);
+        pStrm->pDrainOp = NULL;
+    }
 }
 
@@ -631,10 +634,8 @@
     pStrm->BufAttr.maxlength   = (pStrm->BufAttr.tlength * 3) / 2;
     pStrm->BufAttr.prebuf      = -1; /* Same as tlength */
-
-    /* Set minreq to 0, as we want to control ourselves when to start/stop the stream. */
-    pStrm->BufAttr.minreq      = 0;
+    pStrm->BufAttr.minreq      = -1;
 
     /* Note that the struct BufAttr is updated to the obtained values after this call! */
-    int rc = paStreamOpen(pThis, false /* fIn */, "PulseAudio (Out)", &pStrm->SampleSpec, &pStrm->BufAttr, &pStrm->pStream);
+    int rc = paStreamOpen(pThis, false /* fIn */, "PulseAudio (Out)", &pStrm->SampleSpec, &pStrm->BufAttr, &pStrm->pPAStream);
     if (RT_FAILURE(rc))
         return rc;
@@ -706,5 +707,5 @@
     /* Note: Other members of BufAttr are ignored for record streams. */
     int rc = paStreamOpen(pThis, true /* fIn */, "PulseAudio (In)", &pStrm->SampleSpec, &pStrm->BufAttr,
-                          &pStrm->pStream);
+                          &pStrm->pPAStream);
     if (RT_FAILURE(rc))
         return rc;
@@ -731,11 +732,10 @@
                  pStream->Props.uHz, pStream->Props.cChannels, pStream->Props.cShift, cSamples));
 
+        /* Save pointer to driver instance. */
+        pStrm->pDrv       = pThis;
+        pStrm->pu8PeekBuf = NULL;
+
         if (pcSamples)
             *pcSamples = cSamples;
-
-        /* Save pointer to driver instance. */
-        pStrm->pDrv = pThis;
-
-        pStrm->pu8PeekBuf = NULL;
     }
 
@@ -756,5 +756,5 @@
     /* We should only call pa_stream_readable_size() once and trust the first value. */
     pa_threaded_mainloop_lock(pThis->pMainLoop);
-    size_t cbAvail = pa_stream_readable_size(pStrm->pStream);
+    size_t cbAvail = pa_stream_readable_size(pStrm->pPAStream);
     pa_threaded_mainloop_unlock(pThis->pMainLoop);
 
@@ -792,5 +792,5 @@
         {
             pa_threaded_mainloop_lock(pThis->pMainLoop);
-            pa_stream_peek(pStrm->pStream,
+            pa_stream_peek(pStrm->pPAStream,
                            (const void**)&pStrm->pu8PeekBuf, &pStrm->cbPeekBuf);
             pa_threaded_mainloop_unlock(pThis->pMainLoop);
@@ -840,5 +840,5 @@
         {
             pa_threaded_mainloop_lock(pThis->pMainLoop);
-            pa_stream_drop(pStrm->pStream);
+            pa_stream_drop(pStrm->pPAStream);
             pa_threaded_mainloop_unlock(pThis->pMainLoop);
 
@@ -878,5 +878,5 @@
     uint32_t cbReadTotal = 0;
 
-    uint32_t cLive = AudioMixBufAvail(&pStream->MixBuf);
+    uint32_t cLive = AudioMixBufUsed(&pStream->MixBuf);
     if (!cLive)
     {
@@ -891,5 +891,5 @@
     do
     {
-        size_t cbWriteable = pa_stream_writable_size(pPAStream->pStream);
+        size_t cbWriteable = pa_stream_writable_size(pPAStream->pPAStream);
         if (cbWriteable == (size_t)-1)
         {
@@ -916,5 +916,5 @@
 
             cbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);
-            if (pa_stream_write(pPAStream->pStream, pPAStream->pvPCMBuf, cbRead, NULL /* Cleanup callback */,
+            if (pa_stream_write(pPAStream->pPAStream, pPAStream->pvPCMBuf, cbRead, NULL /* Cleanup callback */,
                                 0, PA_SEEK_RELATIVE) < 0)
             {
@@ -960,5 +960,5 @@
     {
         int rc2 = pa_context_errno(pThis->pContext);
-        LogRel(("PulseAudio: %s: %s\n", szMsg, pa_strerror(rc2)));
+        LogRel2(("PulseAudio: %s: %s\n", szMsg, pa_strerror(rc2)));
     }
 
@@ -1136,14 +1136,14 @@
     LogFlowFuncEnter();
 
-    if (pStrm->pStream)
+    if (pStrm->pPAStream)
     {
         pa_threaded_mainloop_lock(pThis->pMainLoop);
 
-        pa_stream_disconnect(pStrm->pStream);
-        pa_stream_unref(pStrm->pStream);
+        pa_stream_disconnect(pStrm->pPAStream);
+        pa_stream_unref(pStrm->pPAStream);
 
         pa_threaded_mainloop_unlock(pThis->pMainLoop);
 
-        pStrm->pStream = NULL;
+        pStrm->pPAStream = NULL;
     }
 
@@ -1161,14 +1161,21 @@
     LogFlowFuncEnter();
 
-    if (pStrm->pStream)
+    if (pStrm->pPAStream)
     {
         pa_threaded_mainloop_lock(pThis->pMainLoop);
 
-        pa_stream_disconnect(pStrm->pStream);
-        pa_stream_unref(pStrm->pStream);
+        /* Make sure to cancel a pending draining operation, if any. */
+        if (pStrm->pDrainOp)
+        {
+            pa_operation_cancel(pStrm->pDrainOp);
+            pStrm->pDrainOp = NULL;
+        }
+
+        pa_stream_disconnect(pStrm->pPAStream);
+        pa_stream_unref(pStrm->pPAStream);
 
         pa_threaded_mainloop_unlock(pThis->pMainLoop);
 
-        pStrm->pStream = NULL;
+        pStrm->pPAStream = NULL;
     }
 
@@ -1213,5 +1220,5 @@
             else
             {
-                rc = paWaitFor(pThis, pa_stream_cork(pStrm->pStream, 0, paStreamCbSuccess, pStrm));
+                rc = paWaitFor(pThis, pa_stream_cork(pStrm->pPAStream, 0, paStreamCbSuccess, pStrm));
             }
 
@@ -1228,7 +1235,7 @@
             if (!pStrm->pDrainOp)
             {
-                rc = paWaitFor(pThis, pa_stream_trigger(pStrm->pStream, paStreamCbSuccess, pStrm));
+                rc = paWaitFor(pThis, pa_stream_trigger(pStrm->pPAStream, paStreamCbSuccess, pStrm));
                 if (RT_LIKELY(RT_SUCCESS(rc)))
-                    pStrm->pDrainOp = pa_stream_drain(pStrm->pStream, paStreamCbDrain, pStrm);
+                    pStrm->pDrainOp = pa_stream_drain(pStrm->pPAStream, paStreamCbDrain, pStrm);
             }
             pa_threaded_mainloop_unlock(pThis->pMainLoop);
@@ -1265,5 +1272,5 @@
         {
             pa_threaded_mainloop_lock(pThis->pMainLoop);
-            rc = paWaitFor(pThis, pa_stream_cork(pStrm->pStream, 0 /* Play / resume */, paStreamCbSuccess, pStrm));
+            rc = paWaitFor(pThis, pa_stream_cork(pStrm->pPAStream, 0 /* Play / resume */, paStreamCbSuccess, pStrm));
             pa_threaded_mainloop_unlock(pThis->pMainLoop);
             break;
@@ -1276,9 +1283,9 @@
             if (pStrm->pu8PeekBuf) /* Do we need to drop the peek buffer?*/
             {
-                pa_stream_drop(pStrm->pStream);
+                pa_stream_drop(pStrm->pPAStream);
                 pStrm->pu8PeekBuf = NULL;
             }
 
-            rc = paWaitFor(pThis, pa_stream_cork(pStrm->pStream, 1 /* Stop / pause */, paStreamCbSuccess, pStrm));
+            rc = paWaitFor(pThis, pa_stream_cork(pStrm->pPAStream, 1 /* Stop / pause */, paStreamCbSuccess, pStrm));
             pa_threaded_mainloop_unlock(pThis->pMainLoop);
             break;
@@ -1388,8 +1395,49 @@
 static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostPulseAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
 {
-    NOREF(pInterface);
-    NOREF(pStream);
-
-    return (PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED);
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+    PPULSEAUDIOSTREAM  pStrm = (PPULSEAUDIOSTREAM)pStream;
+
+    PDMAUDIOSTRMSTS strmSts  = PDMAUDIOSTRMSTS_FLAG_INITIALIZED
+                             | PDMAUDIOSTRMSTS_FLAG_ENABLED;
+
+    pa_context_state_t ctxState = pa_context_get_state(pThis->pContext);
+
+    if (   pa_context_get_state(pThis->pContext) == PA_CONTEXT_READY
+        && pa_stream_get_state(pStrm->pPAStream) == PA_STREAM_READY)
+    {
+        if (pStream->enmDir == PDMAUDIODIR_IN)
+        {
+
+        }
+        else
+        {
+            size_t cbSize = pa_stream_writable_size(pStrm->pPAStream);
+            LogFlowFunc(("cbSize=%zu\n", cbSize));
+
+            if (cbSize >= pStrm->BufAttr.minreq)
+            {
+                strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
+            }
+        }
+    }
+
+    return strmSts;
+}
+
+static DECLCALLBACK(int) drvHostPulseAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+    PPULSEAUDIOSTREAM  pStrm = (PPULSEAUDIOSTREAM)pStream;
+
+    LogFlowFuncEnter();
+
+    /* Nothing to do here for PulseAudio. */
+    return VINF_SUCCESS;
 }
 
Index: trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp	(revision 61187)
+++ trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp	(revision 61320)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2014-2015 Oracle Corporation
+ * Copyright (C) 2014-2016 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -48,5 +48,5 @@
         44100,                    /* Hz */
         2                         /* Channels */,
-        PDMAUDIOFMT_S16               /* Format */,
+        PDMAUDIOFMT_S16           /* Format */,
         PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
     };
@@ -104,5 +104,5 @@
     RTTESTI_CHECK(AudioMixBufFree(&mb) == 1);
     RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, 1U));
-    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cToWrite + written_abs /* + last absolute write */);
+    RTTESTI_CHECK(AudioMixBufUsed(&mb) == cToWrite + written_abs /* + last absolute write */);
 
     RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &written));
@@ -110,5 +110,5 @@
     RTTESTI_CHECK(AudioMixBufFree(&mb) == 0);
     RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, 0));
-    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize);
+    RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize);
 
     /* Circular reads. */
@@ -123,5 +123,5 @@
     RTTESTI_CHECK(AudioMixBufFree(&mb) == AudioMixBufSize(&mb) - written_abs - 1);
     RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs - 1));
-    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize - cToRead + written_abs);
+    RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize - cToRead + written_abs);
 
     RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &read));
@@ -130,5 +130,5 @@
     RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize - written_abs);
     RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs));
-    RTTESTI_CHECK(AudioMixBufProcessed(&mb) == written_abs);
+    RTTESTI_CHECK(AudioMixBufUsed(&mb) == written_abs);
 
     AudioMixBufDestroy(&mb);
@@ -139,7 +139,5 @@
 static int tstParentChild(RTTEST hTest)
 {
-    RTTestSubF(hTest, "2 Children -> Parent");
-
-    uint32_t cBufSize = _1K;
+    uint32_t cBufSize = RTRandU32() % 256;
 
     PDMAUDIOSTREAMCFG cfg_p =
@@ -150,5 +148,5 @@
         44100,                    /* Hz */
         2                         /* Channels */,
-        PDMAUDIOFMT_S16               /* Format */,
+        PDMAUDIOFMT_S16           /* Format */,
         PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
     };
@@ -168,5 +166,5 @@
         22050,                    /* Hz */
         2                         /* Channels */,
-        PDMAUDIOFMT_S16               /* Format */,
+        PDMAUDIOFMT_S16           /* Format */,
         PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
     };
@@ -186,5 +184,5 @@
         48000,                    /* Hz */
         2                         /* Channels */,
-        PDMAUDIOFMT_S16               /* Format */,
+        PDMAUDIOFMT_S16           /* Format */,
         PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
     };
@@ -215,5 +213,12 @@
     uint32_t cSamplesChild2  = 16;
 
-    uint32_t t = RTRandU32() % 64;
+    uint32_t t = RTRandU32() % 1024;
+
+    RTTestPrintf(hTest, RTTESTLVL_DEBUG, "%RU32 iterations total\n", t);
+
+    /*
+     * Using AudioMixBufWriteAt for writing to children.
+     */
+    RTTestSubF(hTest, "2 Children -> Parent (AudioMixBufWriteAt)");
 
     for (uint32_t i = 0; i < t; i++)
@@ -223,15 +228,17 @@
         RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild1, ("Child1: Expected %RU32 written samples, got %RU32\n", cSamplesChild1, written));
         RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child1, written, &mixed));
-        temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child2);
-        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child1) == temp, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child1), temp));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child1) == mixed, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child1), mixed));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child1) == AUDIOMIXBUF_S2S_RATIO(&parent, mixed), ("Child1: Expected %RU32 used samples, got %RU32\n", AudioMixBufMixed(&child1), AUDIOMIXBUF_S2S_RATIO(&parent, mixed)));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&parent) == 0, ("Parent: Expected 0 used samples, got %RU32\n", AudioMixBufUsed(&parent)));
 
         RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child2, 0, &samples, sizeof(samples), &written));
         RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild2, ("Child2: Expected %RU32 written samples, got %RU32\n", cSamplesChild2, written));
         RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child2, written, &mixed));
-        temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child1);
-        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child2) == temp, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child2), temp));
-    }
-
-    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child1) + AudioMixBufMixed(&child2));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child2) == mixed, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child2), temp));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child2) == AUDIOMIXBUF_S2S_RATIO(&parent, mixed), ("Child2: Expected %RU32 used samples, got %RU32\n", AudioMixBufMixed(&child2), AUDIOMIXBUF_S2S_RATIO(&parent, mixed)));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&parent) == 0, ("Parent2: Expected 0 used samples, got %RU32\n", AudioMixBufUsed(&parent)));
+    }
+
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufMixed(&child1) + AudioMixBufMixed(&child2));
 
     for (;;)
@@ -243,5 +250,5 @@
     }
 
-    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
     RTTESTI_CHECK(AudioMixBufMixed(&child1) == 0);
     RTTESTI_CHECK(AudioMixBufMixed(&child2) == 0);
@@ -328,8 +335,8 @@
     RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
     RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
-    temp = AudioMixBufProcessed(&parent);
+    temp = AudioMixBufUsed(&parent);
     RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
 
-    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufMixed(&child));
 
     for (;;)
@@ -355,5 +362,5 @@
     }
 
-    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
     RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
 
@@ -431,8 +438,8 @@
     RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
     RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
-    temp = AudioMixBufProcessed(&parent);
+    temp = AudioMixBufUsed(&parent);
     RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
 
-    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufMixed(&child));
 
     for (;;)
@@ -458,5 +465,5 @@
     }
 
-    RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
     RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
 
