Index: /trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 73568)
+++ /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 73569)
@@ -1123,45 +1123,9 @@
     do
     {
-        uint32_t cfMixed = 0;
-
         rc = pThis->pHostDrvAudio->pfnStreamIterate(pThis->pHostDrvAudio, pStream->pvBackend);
         if (RT_FAILURE(rc))
             break;
 
-        if (pStream->enmDir == PDMAUDIODIR_IN)
-        {
-            /* Has the host captured any frames which were not mixed to the guest side yet? */
-            uint32_t cfCaptured = AudioMixBufUsed(&pStream->Host.MixBuf);
-            if (cfCaptured)
-            {
-                /* When capturing frames, the guest is the parent while the host is the child.
-                 * So try mixing not yet mixed host-side frames to the guest-side buffer. */
-                rc = AudioMixBufMixToParent(&pStream->Host.MixBuf, cfCaptured, &cfMixed);
-                if (RT_FAILURE(rc))
-                {
-                    if (rc == VERR_BUFFER_OVERFLOW)
-                        LogRel2(("Audio: Guest input stream '%s' full\n", pStream->szName));
-                    else
-                        LogRel2(("Audio: Mixing to guest input stream '%s' failed: %Rrc\n", pStream->szName, rc));
-#ifdef DEBUG_andy_disabled
-                    AssertFailed();
-#endif
-                }
-
-#ifdef VBOX_WITH_STATISTICS
-                STAM_COUNTER_ADD(&pThis->Stats.TotalFramesMixedIn, cfMixed);
-                Assert(cfCaptured >= cfMixed);
-                STAM_COUNTER_ADD(&pThis->Stats.TotalFramesLostIn,  cfCaptured - cfMixed);
-#endif
-                Log3Func(("[%s] %RU32/%RU32 input frames mixed, rc=%Rrc\n", pStream->szName, cfMixed, cfCaptured, rc));
-            }
-            else
-            {
-                /* No audio frames to transfer host to the guest (anymore)?
-                 * Then try closing this stream if marked so in the next block. */
-                fTryClosePending = true;
-            }
-        }
-        else if (pStream->enmDir == PDMAUDIODIR_OUT)
+        if (pStream->enmDir == PDMAUDIODIR_OUT)
         {
             /* No audio frames to transfer from guest to host (anymore)?
@@ -1171,6 +1135,4 @@
             Log3Func(("[%s] fTryClosePending=%RTbool, cfLive=%RU32\n", pStream->szName, fTryClosePending, cfLive));
         }
-        else
-            AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
 
         /* Has the host stream marked as pending to disable?
@@ -1666,15 +1628,34 @@
         else if (cbCaptured)
         {
-            if (pThis->In.Cfg.Dbg.fEnabled)
-                DrvAudioHlpFileWrite(pStream->In.Dbg.pFileCaptureNonInterleaved, auBuf, cbCaptured, 0 /* fFlags */);
-
             Assert(cbCaptured <= cbBuf);
             if (cbCaptured > cbBuf) /* Paranoia. */
                 cbCaptured = (uint32_t)cbBuf;
 
-            uint32_t cfCaptured = 0;
-            rc = AudioMixBufWriteCirc(&pStream->Host.MixBuf, auBuf, cbCaptured, &cfCaptured);
-            if (RT_SUCCESS(rc))
-                cfCapturedTotal += cfCaptured;
+            /* We use the host side mixing buffer as an intermediate buffer to do some
+             * (first) processing (if needed), so always write the incoming data at offset 0. */
+            uint32_t cfHstWritten = 0;
+            rc = AudioMixBufWriteAt(&pStream->Host.MixBuf, 0 /* offFrames */, auBuf, cbCaptured, &cfHstWritten);
+            if (   RT_FAILURE(rc)
+                || !cfHstWritten)
+            {
+                AssertMsgFailed(("[%s] Write failed: cbCaptured=%RU32, cfHstWritten=%RU32, rc=%Rrc\n",
+                                 pStream->szName, cbCaptured, cfHstWritten, rc));
+                break;
+            }
+
+            if (pThis->In.Cfg.Dbg.fEnabled)
+                DrvAudioHlpFileWrite(pStream->In.Dbg.pFileCaptureNonInterleaved, auBuf, cbCaptured, 0 /* fFlags */);
+
+            uint32_t cfHstMixed = 0;
+            if (cfHstWritten)
+            {
+                int rc2 = AudioMixBufMixToParentEx(&pStream->Host.MixBuf, 0 /* cSrcOffset */, cfHstWritten /* cSrcFrames */,
+                                                   &cfHstMixed /* pcSrcMixed */);
+                Log3Func(("[%s] cbCaptured=%RU32, cfWritten=%RU32, cfMixed=%RU32, rc=%Rrc\n",
+                          pStream->szName, cbCaptured, cfHstWritten, cfHstMixed, rc2));
+                AssertRC(rc2);
+            }
+
+            cfCapturedTotal += cfHstMixed;
         }
         else /* Nothing captured -- bail out. */
@@ -1799,21 +1780,24 @@
     uint32_t cfCaptured = 0;
 
+#ifdef LOG_ENABLED
+    char *pszStreamSts = dbgAudioStreamStatusToStr(pStream->fStatus);
+    Log3Func(("[%s] fStatus=%s\n", pStream->szName, pszStreamSts));
+    RTStrFree(pszStreamSts);
+#endif /* LOG_ENABLED */
+
     do
     {
         if (!pThis->pHostDrvAudio)
+        {
+            rc = VERR_AUDIO_STREAM_NOT_READY;
             break;
-
-        /*
-         * Check if the backend is ready to operate.
-         */
-
-        PDMAUDIOSTREAMSTS stsStream = pStream->fStatus;
-#ifdef LOG_ENABLED
-        char *pszStreamSts = dbgAudioStreamStatusToStr(stsStream);
-        Log3Func(("[%s] Start: fStatus=%s\n", pStream->szName, pszStreamSts));
-        RTStrFree(pszStreamSts);
-#endif /* LOG_ENABLED */
-        if (!(stsStream & PDMAUDIOSTREAMSTS_FLAG_ENABLED)) /* Stream disabled? Bail out. */
+        }
+
+        if (   !pThis->In.fEnabled
+            || !DrvAudioHlpStreamStatusCanRead(pStream->fStatus))
+        {
+            rc = VERR_AUDIO_STREAM_NOT_READY;
             break;
+        }
 
         /*
@@ -1838,11 +1822,4 @@
             pThis->pHostDrvAudio->pfnStreamCaptureEnd(pThis->pHostDrvAudio, pStream->pvBackend);
 
-#ifdef LOG_ENABLED
-        pszStreamSts = dbgAudioStreamStatusToStr(stsStream);
-        Log3Func(("[%s] End: fStatus=%s, cfCaptured=%RU32, rc=%Rrc\n",
-                  pStream->szName, pszStreamSts, cfCaptured, rc));
-        RTStrFree(pszStreamSts);
-#endif /* LOG_ENABLED */
-
         if (RT_SUCCESS(rc))
         {
@@ -1850,5 +1827,5 @@
 
 #ifdef VBOX_WITH_STATISTICS
-            STAM_COUNTER_ADD(&pThis->Stats.TotalFramesIn,        cfCaptured);
+            STAM_COUNTER_ADD(&pThis->Stats.TotalFramesIn,       cfCaptured);
             STAM_COUNTER_ADD(&pStream->In.Stats.FramesCaptured, cfCaptured);
 #endif
@@ -2318,10 +2295,8 @@
     do
     {
-        if (!pThis->In.fEnabled)
-        {
-            /* If the stream is not enabled, return silence. */
-            DrvAudioHlpClearBuf(&pStream->Guest.Cfg.Props, pvBuf, cbBuf,
-                                PDMAUDIOPCMPROPS_B2F(&pStream->Guest.Cfg.Props, cbBuf));
-            cbReadTotal = cbBuf;
+        if (   !pThis->In.fEnabled
+            || !DrvAudioHlpStreamStatusCanRead(pStream->fStatus))
+        {
+            rc = VERR_AUDIO_STREAM_NOT_READY;
             break;
         }
@@ -2331,5 +2306,5 @@
             && pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
         {
-            rc = VERR_NOT_AVAILABLE;
+            rc = VERR_AUDIO_STREAM_NOT_READY;
             break;
         }
@@ -2341,5 +2316,5 @@
         uint32_t cfReadTotal = 0;
 
-        uint32_t cfToRead = RT_MIN(AUDIOMIXBUF_B2F(&pStream->Guest.MixBuf, cbBuf), AudioMixBufUsed(&pStream->Guest.MixBuf));
+        uint32_t cfToRead = RT_MIN(AUDIOMIXBUF_B2F(&pStream->Guest.MixBuf, cbBuf), AudioMixBufLive(&pStream->Guest.MixBuf));
         while (cfToRead)
         {
@@ -2772,10 +2747,15 @@
     AssertMsg(pStream->enmDir == PDMAUDIODIR_IN, ("Can't read from a non-input stream\n"));
 
-    const uint32_t cfReadable = AudioMixBufLive(&pStream->Guest.MixBuf);
-
-    Log3Func(("[%s] cfReadable=%RU32 (%zu bytes)\n", pStream->szName, cfReadable,
-              AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadable)));
-
-    uint32_t cbReadable = AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadable);
+    uint32_t cbReadable = 0;
+
+    if (DrvAudioHlpStreamStatusCanRead(pStream->fStatus))
+    {
+        const uint32_t cfReadable = AudioMixBufLive(&pStream->Guest.MixBuf);
+
+        Log3Func(("[%s] cfReadable=%RU32 (%zu bytes)\n", pStream->szName, cfReadable,
+                  AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadable)));
+
+        cbReadable = AUDIOMIXBUF_F2B(&pStream->Guest.MixBuf, cfReadable);
+    }
 
     rc2 = RTCritSectLeave(&pThis->CritSect);
