Index: /trunk/include/VBox/vmm/pdmaudioifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 61522)
+++ /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 61523)
@@ -173,5 +173,7 @@
     /** Interleaved access, where the data can be
      *  mixed together with data of other audio streams. */
-    PDMAUDIOSTREAMLAYOUT_INTERLEAVED
+    PDMAUDIOSTREAMLAYOUT_INTERLEAVED,
+    /** Hack to blow the type up to 32-bit. */
+    PDMAUDIOSTREAMLAYOUT_32BIT_HACK = 0x7fffffff
 } PDMAUDIOSTREAMLAYOUT, *PPDMAUDIOSTREAMLAYOUT;
 
@@ -716,5 +718,5 @@
 
     /**
-     * Plays (transfers) all available audio samples of a an output stream via the connected host backend.
+     * Plays (transfers) available audio samples via the host backend. Only works with output streams.
      *
      * @returns VBox status code.
@@ -723,4 +725,13 @@
      */
     DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed));
+
+    /**
+     * Captures (transfers) available audio samples from the host backend. Only works with input streams.
+     *
+     * @returns VBox status code.
+     * @param   pInterface           Pointer to the interface structure containing the called function pointer.
+     * @param   pcSamplesCaptured    Number of samples captured. Optional.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesCaptured));
 
 #ifdef VBOX_WITH_AUDIO_CALLBACKS
@@ -732,5 +743,5 @@
 
 /** PDMIAUDIOCONNECTOR interface ID. */
-#define PDMIAUDIOCONNECTOR_IID                  "9C097435-3276-4D88-A49A-A4FE671D86F8"
+#define PDMIAUDIOCONNECTOR_IID                  "D1B6465D-E3DD-455B-9E05-FB6D56F7D472"
 
 
Index: /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61523)
@@ -21,6 +21,6 @@
 #ifdef DEBUG_andy
 /*
- * DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust DEBUG_DUMP_PCM_DATA_PATH
+ * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
+ * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH
  * to your needs before using this!
  */
@@ -243,5 +243,4 @@
                        pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear));
 
-        Assert(cSamplesToClear <= pIter->cMixed);
         pIter->cMixed -= RT_MIN(pIter->cMixed, cSamplesToClear);
     }
Index: /trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61523)
@@ -341,8 +341,5 @@
     }
     else
-    {
-        AssertMsgFailed(("Direction not implemented\n"));
-        rc = VERR_NOT_IMPLEMENTED;
-    }
+        AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
 #else
     rc = VINF_SUCCESS;
@@ -455,9 +452,9 @@
 }
 
-int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmCmd)
+int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmSinkCmd)
 {
     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
 
-    PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmCmd);
+    PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmSinkCmd);
     if (enmCmdStream == PDMAUDIOSTREAMCMD_UNKNOWN)
         return VERR_NOT_SUPPORTED;
@@ -474,5 +471,13 @@
     }
 
-    LogFlowFunc(("[%s]: enmCmd=%ld, rc=%Rrc\n", pSink->pszName, enmCmd, rc));
+    /* Remove dirty bit in any case. */
+    pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
+
+    if (enmSinkCmd == AUDMIXSINKCMD_ENABLE)
+        pSink->fStatus |= AUDMIXSINK_STS_RUNNING;
+    else if (enmSinkCmd == AUDMIXSINKCMD_DISABLE)
+        pSink->fStatus &= ~AUDMIXSINK_STS_RUNNING;
+
+    LogFlowFunc(("[%s]: enmCmd=%ld, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, enmSinkCmd, pSink->fStatus, rc));
     return rc;
 }
@@ -557,4 +562,15 @@
 }
 
+AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink)
+{
+    if (!pSink)
+        return false;
+
+    LogFlowFunc(("[%s]: fStatus=0x%x\n", pSink->pszName, pSink->fStatus));
+
+    /* If the dirty flag is set, there is unprocessed data in the sink. */
+    return pSink->fStatus;
+}
+
 uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink)
 {
@@ -563,15 +579,4 @@
 
     return pSink->cStreams;
-}
-
-bool AudioMixerSinkHasData(PAUDMIXSINK pSink)
-{
-    if (!pSink)
-        return false;
-
-    LogFlowFunc(("[%s]: %RTbool\n", pSink->pszName, (pSink->fFlags & AUDMIXSINK_FLAG_DIRTY)));
-
-    /* If the dirty flag is set, there is unprocessed data in the sink. */
-    return (pSink->fFlags & AUDMIXSINK_FLAG_DIRTY);
 }
 
@@ -588,11 +593,17 @@
               ("Can't read from a sink which is not an input sink\n"));
 
+#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
     uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
     if (!pvMixBuf)
         return VERR_NO_MEMORY;
+#endif
 
     int rc = VERR_NOT_FOUND;
     uint32_t cbRead = 0;
 
+    /* Flag indicating whether this sink is in a 'clean' state,
+     * e.g. there is no more data to read from. */
+    bool fClean = true;
+
     PAUDMIXSTREAM pMixStream;
     RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
@@ -602,5 +613,5 @@
 
         uint32_t cbTotalRead = 0;
-        uint32_t cbToRead = cbBuf;
+        uint32_t cbToRead    = cbBuf;
 
         while (cbToRead)
@@ -608,6 +619,8 @@
             uint32_t cbReadStrm;
             AssertPtr(pMixStream->pConn);
+#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
             rc = pMixStream->pConn->pfnStreamRead(pMixStream->pConn, pMixStream->pStream,
                                                   (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbReadStrm);
+#endif
             if (   RT_FAILURE(rc)
                 || !cbReadStrm)
@@ -625,17 +638,27 @@
 
         cbRead = RT_MAX(cbRead, cbTotalRead);
+
+        PDMAUDIOSTRMSTS strmSts = pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream);
+        fClean &= !(strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE);
     }
 
     if (RT_SUCCESS(rc))
     {
-        memcpy(pvBuf, pvMixBuf, cbRead); /* @todo Use an intermediate mixing buffer per sink! */
-
+        if (fClean)
+            pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
+
+#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
+        if (cbRead)
+            memcpy(pvBuf, pvMixBuf, cbRead);
+#endif
         if (pcbRead)
             *pcbRead = cbRead;
     }
 
+#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
     RTMemFree(pvMixBuf);
-
-    Log3Func(("[%s]: cbRead=%RU32, rc=%Rrc\n", pSink->pszName, cbRead, rc));
+#endif
+
+    Log3Func(("[%s]: cbRead=%RU32, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, cbRead, pSink->fStatus, rc));
     return rc;
 }
@@ -644,9 +667,12 @@
 {
     AssertPtrReturn(pSink, VERR_INVALID_PARAMETER);
-    if (!pStream)
+    if (   !pStream
+        || !pStream->pSink) /* Not part of a sink anymore? */
+    {
         return VERR_NOT_FOUND;
+    }
 
     AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n",
-                                               pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
+                                              pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
 
     LogFlowFunc(("[%s]: (Stream = %s), cStreams=%RU8\n",
@@ -660,6 +686,4 @@
     /* Remove stream from sink. */
     RTListNodeRemove(&pStream->Node);
-    Assert(pSink->cStreams);
-    pSink->cStreams--;
 
     /* Set sink to NULL so that we know we're not part of any sink anymore. */
@@ -671,5 +695,10 @@
 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
 {
-    audioMixerSinkRemoveStreamInternal(pSink, pStream);
+    int rc = audioMixerSinkRemoveStreamInternal(pSink, pStream);
+    if (RT_SUCCESS(rc))
+    {
+        Assert(pSink->cStreams);
+        pSink->cStreams--;
+    }
 }
 
@@ -763,35 +792,14 @@
 }
 
-void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed, uint32_t *pcbData)
+void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed)
 {
     AssertPtrReturnVoid(pSink);
-    /* pcbData is optional. */
 
     /* Note: cTimerTicks / cTicksElapsed = Hz elapsed. */
 
-    LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64\n", pSink->pszName, cTimerTicks, cTicksElapsed));
-
-//    uint32_t cSamplesMin  = (uint32_t)((2 * cTicksElapsed * pSink->PCMProps.uHz + cTimerTicks) / cTimerTicks / 2);
-   uint32_t cSamplesMin  = (cTicksElapsed / pSink->PCMProps.uHz) * pSink->PCMProps.cChannels;
-  //  cSamplesMin = (uint32_t)((2 * cTicksElapsed * 44100 + cTimerTicks) / cTimerTicks / 2);
-    uint32_t cbSamplesMin = _4K; //cSamplesMin << pSink->PCMProps.cShift;
-
-    //Assert((cbSamplesMin % 2 == 0));
-
-//LogFlowFunc(("[%s]: cSamplesMin=%RU32 (%RU32 bytes, %RU32Hz)\n", pSink->pszName, cSamplesMin, cbSamplesMin, pSink->PCMProps.uHz));
-
-    uint32_t cbData = cbSamplesMin;
-
-    if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
-    {
-//        uint32_t cSinkSamplesLive = AudioMixBufAvail(&pSink->MixBuf);
-//        if (!cSinkSamplesLive)
-//            cbData = AUDIOMIXBUF_S2B_RATIO(&pSink->MixBuf, AudioMixBufFree(&pSink->MixBufGuest));
-    }
+    LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64 -> %zuHz\n",
+                 pSink->pszName, cTimerTicks, cTicksElapsed, cTimerTicks / cTicksElapsed));
 
     audioMixerSinkUpdateInternal(pSink);
-
-    if (pcbData)
-        *pcbData = cbData;
 }
 
@@ -810,26 +818,42 @@
         AssertPtr(pStream);
 
-        uint32_t cPlayed = 0;
-
-        rc = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream);
-        if (RT_SUCCESS(rc))
+        uint32_t cPlayed   = 0;
+        uint32_t cCaptured = 0;
+
+        int rc2 = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream);
+        if (RT_SUCCESS(rc2))
         {
             if (pStream->enmDir == PDMAUDIODIR_IN)
             {
-                /** @todo Implement this! */
-#if 0
-                rc = pStream->pConn->pfnStreamCapture(pStream->pConn, NULL /* pcSamplesCaptured */);
-#endif
+                rc = pMixStream->pConn->pfnStreamCapture(pMixStream->pConn, pMixStream->pStream, &cCaptured);
+                if (RT_FAILURE(rc2))
+                {
+                    LogFlowFunc(("%s: Failed capture stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
+                    if (RT_SUCCESS(rc))
+                        rc = rc2;
+                }
+
+                if (cCaptured)
+                    pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
+            }
+            else if (pStream->enmDir == PDMAUDIODIR_OUT)
+            {
+                rc2 = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pMixStream->pStream, &cPlayed);
+                if (RT_FAILURE(rc2))
+                {
+                    LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
+                    if (RT_SUCCESS(rc))
+                        rc = rc2;
+                }
             }
             else
-            {
-                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));
-            }
+                AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
         }
 
-        Log3Func(("\t%s: cPlayed=%RU32, rc=%Rrc\n", pMixStream->pStream->szName, cPlayed, rc));
-    }
+        Log3Func(("\t%s: cPlayed=%RU32, cCaptured=%RU32\n", pMixStream->pStream->szName, cPlayed, cCaptured));
+    }
+
+    if (RT_FAILURE(rc))
+        LogFlowFunc(("Failed with rc=%Rrc\n", rc));
 
     return rc;
@@ -914,6 +938,9 @@
     }
 
-    /* Set dirty bit. */
-    pSink->fFlags |= AUDMIXSINK_FLAG_DIRTY;
+    if (cbBuf)
+    {
+        /* Set dirty bit. */
+        pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
+    }
 
     if (pcbWritten)
@@ -975,5 +1002,5 @@
     int rc;
 
-    if (pMixStream->pSink)
+    if (pMixStream->pSink) /* Is the stream part of a sink? */
     {
         /* Save sink pointer, as after audioMixerSinkRemoveStreamInternal() the
@@ -981,8 +1008,7 @@
         PAUDMIXSINK pSink = pMixStream->pSink;
 
-        rc = audioMixerSinkRemoveStreamInternal(pMixStream->pSink, pMixStream);
+        rc = audioMixerSinkRemoveStreamInternal(pSink, pMixStream);
         if (RT_SUCCESS(rc))
         {
-            AssertPtr(pSink);
             Assert(pSink->cStreams);
             pSink->cStreams--;
@@ -994,4 +1020,6 @@
     if (RT_SUCCESS(rc))
         audioMixerStreamDestroyInternal(pMixStream);
+
+    LogFlowFunc(("Returning %Rrc\n", rc));
 }
 
Index: /trunk/src/VBox/Devices/Audio/AudioMixer.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61523)
@@ -68,8 +68,18 @@
 } AUDMIXSTREAM, *PAUDMIXSTREAM;
 
-/** No flags specified. */
-#define AUDMIXSINK_FLAG_NONE                  0
-/** Dirty flag. */
-#define AUDMIXSINK_FLAG_DIRTY                 RT_BIT(0)
+/** Defines an audio sink's current status. */
+#define AUDMIXSINKSTS uint32_t
+
+/** No status specified. */
+#define AUDMIXSINK_STS_NONE                  0
+/** The sink is active and running. */
+#define AUDMIXSINK_STS_RUNNING               RT_BIT(0)
+/** Dirty flag.
+ *  For output sinks this means that there is data in the
+ *  sink which has not been played yet.
+ *  For input sinks this means that there is data in the
+ *  sink which has been recorded but not transferred to the
+ *  destination yet. */
+#define AUDMIXSINK_STS_DIRTY                 RT_BIT(1)
 
 /**
@@ -117,6 +127,6 @@
      *  if this sink handles input or output. */
     AUDMIXSINKDIR           enmDir;
-    /** Sink flags of type AUDMIXSINK_FLAG_. */
-    uint32_t                fFlags;
+    /** Sink status of type AUDMIXSINK_STS_XXX. */
+    AUDMIXSINKSTS           fStatus;
     /** The sink's PCM format. */
     PDMPCMPROPS             PCMProps;
@@ -170,6 +180,6 @@
 AUDMIXSINKDIR AudioMixerSinkGetDir(PAUDMIXSINK pSink);
 PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex);
+AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
 uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink);
-bool AudioMixerSinkHasData(PAUDMIXSINK pSink);
 int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
 void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
@@ -177,5 +187,5 @@
 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMPCMPROPS pPCMProps);
 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
-void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed, uint32_t *pcbData);
+void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed);
 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
 int AudioMixerSinkUpdate(PAUDMIXSINK pSink);
Index: /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61523)
@@ -46,10 +46,17 @@
 *********************************************************************************************************************************/
 
-#ifdef DEBUG
-//#define DEBUG_LUN
-# ifdef DEBUG_LUN
-#  define DEBUG_LUN_NUM 1
+#ifdef DEBUG_andy
+/*
+ * AC97_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
+ * to a file on the host. Be sure to adjust AC97_DEBUG_DUMP_PCM_DATA_PATH
+ * to your needs before using this!
+ */
+# define AC97_DEBUG_DUMP_PCM_DATA
+# ifdef RT_OS_WINDOWS
+#  define AC97_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
+# else
+#  define AC97_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
 # endif
-#endif /* DEBUG */
+#endif /* DEBUG_andy */
 
 #define AC97_SSM_VERSION 1
@@ -76,7 +83,7 @@
 #define CR_IOCE  RT_BIT(4)         /* rw,   Interrupt On Completion Enable. */
 #define CR_FEIE  RT_BIT(3)         /* rw    FIFO Error Interrupt Enable. */
-#define CR_LVBIE RT_BIT(2)         /* rw    */
-#define CR_RR    RT_BIT(1)         /* rw */
-#define CR_RPBM  RT_BIT(0)         /* rw */
+#define CR_LVBIE RT_BIT(2)         /* rw    Last Valid Buffer Interrupt Enable. */
+#define CR_RR    RT_BIT(1)         /* rw    Reset Registers. */
+#define CR_RPBM  RT_BIT(0)         /* rw    Run/Pause Bus Master. */
 #define CR_VALID_MASK (RT_BIT(5) - 1)
 #define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
@@ -263,5 +270,5 @@
     uint8_t  lvi;               /** rw 0, Last valid index. */
     uint16_t sr;                /** rw 1, Status register. */
-    uint16_t picb;              /** ro 0, Position in current buffer. */
+    uint16_t picb;              /** ro 0, Position in current buffer (in samples). */
     uint8_t  piv;               /** ro 0, Prefetched index value. */
     uint8_t  cr;                /** rw 0, Control register. */
@@ -423,5 +430,5 @@
 static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
 #endif
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbElapsed);
+static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream);
 
 static void ichac97WarmReset(PAC97STATE pThis)
@@ -532,5 +539,5 @@
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
 
-    bool fActive = AudioMixerSinkHasData(ichac97IndexToSink(pThis, pStream->u8Strm));
+    bool fActive = AudioMixerSinkGetStatus(ichac97IndexToSink(pThis, pStream->u8Strm));
 
     LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8Strm, fActive));
@@ -1145,9 +1152,9 @@
  * @param   pcbWritten
  */
-static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbMax, uint32_t *pcbWritten)
+static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    AssertReturn(cbMax,      VERR_INVALID_PARAMETER);
+    AssertReturn(cbToWrite,  VERR_INVALID_PARAMETER);
     /* pcbWritten is optional. */
 
@@ -1158,7 +1165,7 @@
     uint32_t    cbWrittenTotal = 0;
 
-    Log3Func(("PICB=%RU16, cbMax=%RU32\n", pRegs->picb, cbMax));
-
-    uint32_t cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbMax); /** @todo r=andy Assumes 16bit sample size. */
+    Log3Func(("PICB=%RU16, cbMax=%RU32\n", pRegs->picb, cbToWrite));
+
+    cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbToWrite); /** @todo r=andy Assumes 16bit sample size. */
     if (!cbToWrite)
     {
@@ -1170,5 +1177,5 @@
     int rc = VINF_SUCCESS;
 
-    LogFlowFunc(("pReg=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbMax, cbToWrite));
+    LogFlowFunc(("pRegs=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbToWrite, cbToWrite));
 
     Assert(pStream->State.offFIFOW <= pStream->State.cbFIFOW);
@@ -1182,7 +1189,7 @@
         PDMDevHlpPhysRead(pDevIns, addr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */
 
-#if defined (RT_OS_LINUX) && defined(DEBUG_andy)
+#ifdef AC97_DEBUG_DUMP_PCM_DATA
         RTFILE fh;
-        RTFileOpen(&fh, "/tmp/ac97WriteAudio.pcm",
+        RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97WriteAudio.pcm",
                    RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
         RTFileWrite(fh, pu8FIFOW, cbToRead, NULL);
@@ -1234,4 +1241,6 @@
 static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
 {
+    LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed));
+
     if (!(pThis->bup_flag & BUP_SET))
     {
@@ -1240,5 +1249,5 @@
             unsigned int i;
             uint32_t *p = (uint32_t*)pThis->silence;
-            for (i = 0; i < sizeof(pThis->silence) / 4; i++)
+            for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */
                 *p++ = pThis->last_samp;
         }
@@ -1269,9 +1278,9 @@
 }
 
-static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbMax, uint32_t *pcbRead)
+static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    AssertReturn(cbMax,      VERR_INVALID_PARAMETER);
+    AssertReturn(cbToRead,   VERR_INVALID_PARAMETER);
     /* pcbRead is optional. */
 
@@ -1285,6 +1294,7 @@
 
     uint32_t cbRead   = 0;
-    uint32_t cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),
-                               RT_MIN(pStream->State.cbFIFOW, cbMax)); /** @todo r=andy Assumes 16bit samples. */
+
+    cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),
+                      RT_MIN(pStream->State.cbFIFOW, cbToRead)); /** @todo r=andy Assumes 16bit samples. */
 
     if (!cbToRead)
@@ -1365,28 +1375,30 @@
     uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
 
+    LogFlowFuncEnter();
+
     /* Update current time timestamp. */
     pThis->uTimerTS = cTicksNow;
 
-    LogFlowFuncEnter();
-
-    uint32_t cbLineIn;
-    AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, pThis->cTimerTicks, cTicksPerSec, &cbLineIn);
-    if (cbLineIn)
-        ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbLineIn);
-
-    uint32_t cbMicIn;
-    AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , pThis->cTimerTicks, cTicksPerSec, &cbMicIn);
-    if (cbMicIn)
-        ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbMicIn);
-
-    uint32_t cbOut;
-    AudioMixerSinkTimerUpdate(pThis->pSinkOutput, pThis->cTimerTicks, cTicksPerSec, &cbOut);
-    if (cbOut)
-        ichac97TransferAudio(pThis, &pThis->StreamOut, cbOut);
+    /* Flag indicating whether to kick the timer again for a
+     * new data processing round. */
+    bool fKickTimer = false;
+
+    AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, pThis->cTimerTicks, cTicksPerSec);
+    ichac97TransferAudio(pThis, &pThis->StreamLineIn);
+
+    fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkLineIn) & AUDMIXSINK_STS_DIRTY;
+
+    AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , pThis->cTimerTicks, cTicksPerSec);
+    ichac97TransferAudio(pThis, &pThis->StreamMicIn);
+
+    fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkMicIn) & AUDMIXSINK_STS_DIRTY;
+
+    AudioMixerSinkTimerUpdate(pThis->pSinkOutput, pThis->cTimerTicks, cTicksPerSec);
+    ichac97TransferAudio(pThis, &pThis->StreamOut);
+
+    fKickTimer = AudioMixerSinkGetStatus(pThis->pSinkOutput) & AUDMIXSINK_STS_DIRTY;
 
     if (   ASMAtomicReadBool(&pThis->fTimerActive)
-        || AudioMixerSinkHasData(pThis->pSinkLineIn)
-        || AudioMixerSinkHasData(pThis->pSinkMicIn)
-        || AudioMixerSinkHasData(pThis->pSinkOutput))
+        || fKickTimer)
     {
         /* Kick the timer again. */
@@ -1401,7 +1413,7 @@
 #endif /* !VBOX_WITH_AUDIO_CALLBACKS */
 
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbElapsed)
-{
-    Log3Func(("SD=%RU8, cbElapsed=%RU32\n", pStream->u8Strm , cbElapsed));
+static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream)
+{
+    Log3Func(("SD=%RU8\n", pStream->u8Strm));
 
     PAC97BMREGS pRegs = &pStream->Regs;
@@ -1409,10 +1421,10 @@
     if (pRegs->sr & SR_DCH) /* Controller halted? */
     {
-        if (pRegs->cr & CR_RPBM)
+        if (pRegs->cr & CR_RPBM) /* Bus master operation starts. */
         {
             switch (pStream->u8Strm)
             {
                 case PO_INDEX:
-                    ichac97WriteBUP(pThis, cbElapsed);
+                    ichac97WriteBUP(pThis, (uint32_t)(pRegs->picb << 1));
                     break;
 
@@ -1432,5 +1444,5 @@
     uint32_t cbWrittenTotal = 0;
 
-    while (cbElapsed >> 1) /** @todo r=andy This assumes (hardcodes) 16bit sample size.*/
+    do
     {
         if (!pRegs->bd_valid)
@@ -1446,5 +1458,5 @@
             if (pRegs->civ == pRegs->lvi)
             {
-                pRegs->sr |= SR_DCH; /* CELV? */
+                pRegs->sr |= SR_DCH; /** @todo r=andy Also set CELV? */
                 pThis->bup_flag = 0;
 
@@ -1461,17 +1473,17 @@
         }
 
-        uint32_t cbTransferred;
+        uint32_t cbToTransfer, cbTransferred;
         switch (pStream->u8Strm)
         {
             case PO_INDEX:
             {
-                rc = ichac97WriteAudio(pThis, pStream, cbElapsed, &cbTransferred);
+                cbToTransfer = (uint32_t)(pRegs->picb << 1);
+
+                rc = ichac97WriteAudio(pThis, pStream, cbToTransfer, &cbTransferred);
                 if (   RT_SUCCESS(rc)
                     && cbTransferred)
                 {
                     cbWrittenTotal += cbTransferred;
-                    Assert(cbElapsed >= cbTransferred);
-                    cbElapsed      -= cbTransferred;
-                    Assert((cbTransferred & 1) == 0);    /* Else the following shift won't work */
+                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
                     pRegs->picb    -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
                 }
@@ -1482,11 +1494,11 @@
             case MC_INDEX:
             {
-                rc = ichac97ReadAudio(pThis, pStream, cbElapsed, &cbTransferred);
+                cbToTransfer = (uint32_t)(pRegs->picb << 1);
+
+                rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred);
                 if (   RT_SUCCESS(rc)
                     && cbTransferred)
                 {
-                    Assert(cbElapsed >= cbTransferred);
-                    cbElapsed   -= cbTransferred;
-                    Assert((cbTransferred & 1) == 0);    /* Else the following shift won't work */
+                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
                     pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
                 }
@@ -1532,10 +1544,8 @@
         }
 
-        if (   RT_FAILURE(rc)
-            || rc == VINF_EOF) /* All data processed? */
-        {
-            break;
-        }
-    }
+        if (rc == VINF_EOF) /* All data processed? */
+            break;
+
+    } while (RT_SUCCESS(rc));
 
     LogFlowFuncLeaveRC(rc);
@@ -1549,5 +1559,5 @@
                                                uint32_t *pu32Val, unsigned cbVal)
 {
-    PAC97STATE pThis    = (PAC97STATE)pvUser;
+    PAC97STATE pThis = (PAC97STATE)pvUser;
 
     /* Get the index of the NABMBAR port. */
Index: /trunk/src/VBox/Devices/Audio/DevIchHda.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 61523)
@@ -58,4 +58,16 @@
 
 #ifdef DEBUG_andy
+/*
+ * HDA_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
+ * to a file on the host. Be sure to adjust HDA_DEBUG_DUMP_PCM_DATA_PATH
+ * to your needs before using this!
+ */
+# define HDA_DEBUG_DUMP_PCM_DATA
+# ifdef RT_OS_WINDOWS
+#  define HDA_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
+# else
+#  define HDA_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
+# endif
+
 /* Enables experimental support for separate mic-in handling.
    Do not enable this yet for regular builds, as this needs more testing first! */
@@ -930,5 +942,5 @@
 static int hdaStreamStop(PHDASTREAM pStream);
 static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout);
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
+static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream);
 #endif
 
@@ -1756,9 +1768,12 @@
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
 
-    bool fActive = false;
-
-    AssertPtr(pStream->pMixSink);
-    if (pStream->pMixSink->pMixSink)
-        fActive = AudioMixerSinkHasData(pStream->pMixSink->pMixSink);
+    bool fActive = pStream->State.fActive;
+
+    if (!fActive)
+    {
+        AssertPtr(pStream->pMixSink);
+        if (pStream->pMixSink->pMixSink)
+            fActive = AudioMixerSinkGetStatus(pStream->pMixSink->pMixSink) & AUDMIXSINK_STS_DIRTY;
+    }
 
     LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8SD, fActive));
@@ -1780,7 +1795,9 @@
                          ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
 
-    /* First, enable or disable the stream's sink, if any. */
+    /* First, enable or disable the stream and the stream's sink, if any. */
     if (pStream->pMixSink->pMixSink)
         AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
+
+    pStream->State.fActive = fActive;
 
     /* Second, see if we need to start or stop the timer. */
@@ -2723,5 +2740,5 @@
     AssertReturn(pCfg->enmDir == PDMAUDIODIR_IN, VERR_INVALID_PARAMETER);
 
-    LogFlowFunc(("Stream=%s\n", pCfg->szName));
+    LogFlowFunc(("Stream=%s, Source=%ld\n", pCfg->szName, pCfg->DestSource.Source));
 
     int rc;
@@ -2731,6 +2748,4 @@
         case PDMAUDIORECSOURCE_LINE:
         {
-            pCfg->DestSource.Source = PDMAUDIORECSOURCE_LINE;
-            pCfg->cChannels         = 2;
             rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_LINE_IN);
             if (RT_SUCCESS(rc))
@@ -2741,6 +2756,4 @@
         case PDMAUDIORECSOURCE_MIC:
         {
-            pCfg->DestSource.Source = PDMAUDIORECSOURCE_MIC;
-            pCfg->cChannels         = 2;
             rc = hdaCodecRemoveStream(pThis->pCodec,  PDMAUDIOMIXERCTL_MIC_IN);
             if (RT_SUCCESS(rc))
@@ -2785,4 +2798,23 @@
     /* Set audio direction. */
     strmCfg.enmDir = hdaGetDirFromSD(pStream->u8SD);
+    switch (strmCfg.enmDir)
+    {
+        case PDMAUDIODIR_IN:
+#ifdef VBOX_WITH_HDA_MIC_IN
+# error "Implement me!"
+#else
+            strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
+#endif
+            break;
+
+        case PDMAUDIODIR_OUT:
+            /* Destination(s) will be set in hdaAddStreamOut(),
+             * based on the channels / stream layout. */
+            break;
+
+        default:
+            rc = VERR_NOT_SUPPORTED;
+            break;
+    }
 
     /*
@@ -2794,6 +2826,9 @@
      * number of channels in a single audio stream.
      */
-    rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg);
-    AssertRC(rc);
+    if (RT_SUCCESS(rc))
+    {
+        rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg);
+        AssertRC(rc);
+    }
 
     if (RT_SUCCESS(rc))
@@ -3169,5 +3204,5 @@
 
         /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
-     //   cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));
+        cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));
 
         /* Make sure we only transfer as many bytes as requested. */
@@ -3447,9 +3482,9 @@
  *       but "reports bytes" when all conditions are met (FIFOW).
  */
-static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbMax, uint32_t *pcbRead)
+static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbRead is optional. */
+    /* pcbProcessed is optional. */
 
     int rc;
@@ -3460,8 +3495,5 @@
         PHDABDLE pBDLE = &pStream->State.BDLE;
 
-        uint32_t cbBuf = hdaStreamGetTransferSize(pThis, pStream, cbMax);
-        Log3Func(("cbBuf=%RU32, %R[bdle]\n", cbBuf, pBDLE));
-
-        if (!cbBuf)
+        if (!cbToProcess)
         {
             rc = VINF_EOF;
@@ -3471,5 +3503,5 @@
         AssertPtr(pStream->pMixSink);
         AssertPtr(pStream->pMixSink->pMixSink);
-        rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
+        rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbToProcess, &cbRead);
         if (RT_FAILURE(rc))
             break;
@@ -3482,5 +3514,6 @@
 
         /* Sanity checks. */
-        Assert(cbRead <= cbBuf);
+        Assert(cbRead <= cbToProcess);
+        Assert(cbRead <= sizeof(pBDLE->State.au8FIFO));
         Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
 
@@ -3515,17 +3548,18 @@
     if (RT_SUCCESS(rc))
     {
-        if (pcbRead)
-            *pcbRead = cbRead;
-    }
-
-    Log3Func(("Returning cbRead=%RU32, rc=%Rrc\n", cbRead, rc));
+        if (pcbProcessed)
+            *pcbProcessed = cbRead;
+    }
+
+    if (RT_FAILURE(rc))
+        LogFlowFunc(("Failed with %Rrc\n", rc));
+
     return rc;
 }
 
-static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbMax, uint32_t *pcbWritten)
+static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
 {
     AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
     /* pcbWritten is optional. */
 
@@ -3533,7 +3567,4 @@
 
     uint32_t cbWritten = 0;
-    uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbMax);
-
-    Log3Func(("cbToWrite=%RU32, %R[bdle]\n", cbToWrite, pBDLE));
 
     /*
@@ -3542,5 +3573,5 @@
      */
     int rc;
-    if (!cbToWrite)
+    if (!cbToProcess)
     {
         rc = VINF_EOF;
@@ -3549,6 +3580,6 @@
     {
         void    *pvBuf = pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW;
-        Assert(cbToWrite >= pBDLE->State.cbBelowFIFOW);
-        uint32_t cbBuf = cbToWrite - pBDLE->State.cbBelowFIFOW;
+        Assert(cbToProcess >= pBDLE->State.cbBelowFIFOW);
+        uint32_t cbBuf = cbToProcess - pBDLE->State.cbBelowFIFOW;
 
         /*
@@ -3559,7 +3590,8 @@
                                pvBuf, cbBuf);
         AssertRC(rc);
-#if defined (RT_OS_LINUX) && defined(DEBUG_andy)
+
+#ifdef HDA_DEBUG_DUMP_PCM_DATA
         RTFILE fh;
-        RTFileOpen(&fh, "/tmp/hdaWriteAudio-hda.pcm",
+        RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio-hda.pcm",
                    RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
         RTFileWrite(fh, pvBuf, cbBuf, NULL);
@@ -3642,7 +3674,7 @@
             /* Always report all data as being written;
              * backends who were not able to catch up have to deal with it themselves. */
-            cbWritten = cbToWrite;
-
-            hdaBDLEUpdate(pBDLE, cbToWrite, cbWritten);
+            cbWritten = cbToProcess;
+
+            hdaBDLEUpdate(pBDLE, cbToProcess, cbWritten);
         }
         else
@@ -3663,9 +3695,11 @@
     if (RT_SUCCESS(rc))
     {
-        if (pcbWritten)
-            *pcbWritten = cbWritten;
-    }
-
-    Log3Func(("Returning cbMax=%RU32, cbWritten=%RU32, rc=%Rrc\n", cbMax, cbWritten, rc));
+        if (pcbProcessed)
+            *pcbProcessed = cbWritten;
+    }
+
+    if (RT_FAILURE(rc))
+        LogFlowFunc(("Failed with %Rrc\n", rc));
+
     return rc;
 }
@@ -3904,9 +3938,8 @@
             }
 
-            if (pMixStream)
-            {
-                AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
-                AudioMixerStreamDestroy(pMixStream);
-            }
+            AssertPtr(pMixStream);
+
+            AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
+            AudioMixerStreamDestroy(pMixStream);
         }
 
@@ -4068,6 +4101,12 @@
     uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
 
+    LogFlowFuncEnter();
+
     /* Update current time timestamp. */
     pThis->uTimerTS = cTicksNow;
+
+    /* Flag indicating whether to kick the timer again for a
+     * new data processing round. */
+    bool fKickTimer = false;
 
     PHDASTREAM pStreamLineIn  = hdaGetStreamFromSink(pThis, &pThis->SinkLineIn);
@@ -4080,25 +4119,31 @@
 #endif
 
-    uint32_t cbLineIn;
-    AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink,    pThis->cTimerTicks, cTicksElapsed, &cbLineIn);
-    if (cbLineIn)
-        hdaTransfer(pThis, pStreamLineIn, cbLineIn, NULL); /** @todo Add rc! */
+    AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink, pThis->cTimerTicks, cTicksElapsed);
+    hdaTransfer(pThis, pStreamLineIn);
+
+    if (AudioMixerSinkGetStatus(pThis->SinkLineIn.pMixSink) & AUDMIXSINK_STS_DIRTY)
+        fKickTimer = true;
 
 #ifdef VBOX_WITH_HDA_MIC_IN
-    uint32_t cbMicIn;
-    AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink ,    pThis->cTimerTicks, cTicksElapsed, &cbMicIn);
-#endif
-
-    uint32_t cbFront;
-    AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink,     pThis->cTimerTicks, cTicksElapsed, &cbFront);
+    AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink, pThis->cTimerTicks, cTicksElapsed);
+    hdaTransfer(pThis, pStreamMicIn);
+
+    if (AudioMixerSinkGetStatus(pThis->SinkLineIn.pMixSink) & AUDMIXSINK_STS_DIRTY)
+        fKickTimer = true;
+#endif
+
+    AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink,     pThis->cTimerTicks, cTicksElapsed);
+    hdaTransfer(pThis, pStreamFront);
+
+    if (AudioMixerSinkGetStatus(pThis->SinkFront.pMixSink) & AUDMIXSINK_STS_DIRTY)
+        fKickTimer = true;
+
 #ifdef VBOX_WITH_HDA_51_SURROUND
-    uint32_t cbCenterLFE;
-    AudioMixerSinkTimerUpdate(pThis->SinkCenterLFE.pMixSink, pThis->cTimerTicks, cTicksElapsed, &cbCenterLFE);
-    uint32_t cbRear;
-    AudioMixerSinkTimerUpdate(pThis->SinkRear.pMixSink,      pThis->cTimerTicks, cTicksElapsed, &cbRear);
-#endif
-
-    if (cbFront)
-        hdaTransfer(pThis, pStreamFront, cbFront, NULL);  /** @todo Add rc! */
+    AudioMixerSinkTimerUpdate(pThis->SinkCenterLFE.pMixSink, pThis->cTimerTicks, cTicksElapsed);
+    AudioMixerSinkTimerUpdate(pThis->SinkRear.pMixSink,      pThis->cTimerTicks, cTicksElapsed);
+
+    /** @todo Check for stream interleaving and only call hdaTransfer() if required! */
+#endif
+
 #ifdef VBOX_WITH_HDA_51_SURROUND
     /*
@@ -4110,10 +4155,5 @@
 
     if (   ASMAtomicReadBool(&pThis->fTimerActive)
-        || AudioMixerSinkHasData(pThis->SinkFront.pMixSink)
-#ifdef VBOX_WITH_HDA_51_SURROUND
-        || AudioMixerSinkHasData(pThis->SinkCenterLFE.pMixSink)
-        || AudioMixerSinkHasData(pThis->SinkRear.pMixSink)
-#endif
-        || AudioMixerSinkHasData(pThis->SinkLineIn.pMixSink))
+        || fKickTimer)
     {
         /* Kick the timer again. */
@@ -4122,4 +4162,6 @@
         TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
     }
+
+    LogFlowFuncLeave();
 
     STAM_PROFILE_STOP(&pThis->StatTimer, a);
@@ -4176,16 +4218,12 @@
 #endif /* VBOX_WITH_AUDIO_CALLBACKS */
 
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbProcessed is optional. */
 
     if (ASMAtomicReadBool(&pThis->fInReset)) /* HDA controller in reset mode? Bail out. */
     {
-        LogFlowFunc(("In reset mode, skipping\n"));
-
-        if (pcbProcessed)
-            *pcbProcessed = 0;
+        LogFlowFunc(("HDA in reset mode, skipping\n"));
         return VINF_SUCCESS;
     }
@@ -4196,6 +4234,9 @@
         return rc;
 
+    Log3Func(("[SD%RU8] fActive=%RTbool\n", pStream->u8SD, pStream->State.fActive));
+
     /* Stop request received? */
-    if (pStream->State.fDoStop)
+    if (   !pStream->State.fActive
+        || pStream->State.fDoStop)
     {
         pStream->State.fActive = false;
@@ -4209,7 +4250,4 @@
     else if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
         fProceed = false;
-    /* Nothing to process? */
-    else if (!cbToProcess)
-        fProceed = false;
 
     if ((HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
@@ -4221,11 +4259,9 @@
     if (!fProceed)
     {
-        Log3Func(("[SD%RU8] Skipping\n", pStream->u8SD));
+        Log3Func(("[SD%RU8]: Skipping\n", pStream->u8SD));
 
         rc = RTSemMutexRelease(pStream->State.hMtx);
         AssertRC(rc);
 
-        if (pcbProcessed)
-            *pcbProcessed = 0;
         return VINF_SUCCESS;
     }
@@ -4242,22 +4278,23 @@
     Assert(u32LPIB <= pStream->u32CBL);
 
-    uint32_t cbLeft  = cbToProcess;
-    uint32_t cbTotal = 0;
-
     bool fInterrupt = false;
 
-    Log3Func(("cbLeft=%RU32\n", cbLeft));
-
-#define FOO
-
-#ifdef FOO
+#ifdef DEBUG_andy
+# define DEBUG_SIMPLE
+#endif
+
+#ifdef DEBUG_SIMPLE
     uint8_t u8FIFO[_16K+1];
     size_t u8FIFOff = 0;
 #endif
 
+    uint32_t cbToProcess      = 0;
+    uint32_t cbProcessed      = 0;
+    uint32_t cbProcessedTotal = 0;
+
     /* Set the FIFORDY bit on the stream while doing the transfer. */
     HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
 
-    while (cbLeft)
+    do
     {
         /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
@@ -4269,13 +4306,15 @@
         }
 
-        uint32_t cbProcessed = 0;
+        cbToProcess = hdaStreamGetTransferSize(pThis, pStream, _4K /** @todo Fix this */);
+        cbProcessed = 0;
+
         if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
-            rc = hdaReadAudio (pThis, pStream, cbLeft, &cbProcessed);
+            rc = hdaReadAudio(pThis, pStream, cbToProcess, &cbProcessed);
         else
         {
-#ifndef FOO
-            rc = hdaWriteAudio(pThis, pStream, cbLeft, &cbProcessed);
+#ifndef DEBUG_SIMPLE
+            rc = hdaWriteAudio(pThis, pStream, cbToProcess, &cbProcessed);
 #else
-            uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbLeft);
+            uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbToProcess);
 
             void    *pvBuf = u8FIFO + u8FIFOff;
@@ -4290,7 +4329,6 @@
             hdaBDLEUpdate(pBDLE, cbToWrite, cbToWrite);
 
-            LogFlowFunc(("u8FIFOff=%zu, cbLeft=%RU32, cbToWrite=%RU32\n", u8FIFOff, cbLeft, cbToWrite));
-
             u8FIFOff += cbToWrite;
+            Assert((u8FIFOff & 1) == 0);
             Assert(u8FIFOff <= sizeof(u8FIFO));
 
@@ -4304,10 +4342,5 @@
         hdaStreamTransferUpdate(pThis, pStream, cbProcessed);
 
-        Assert(cbLeft >= cbProcessed);
-        cbLeft  -= cbProcessed;
-        cbTotal += cbProcessed;
-
-        LogFlowFunc(("cbProcessed=%RU32, cbLeft=%RU32, cbTotal=%RU32, rc=%Rrc\n",
-                     cbProcessed, cbLeft, cbTotal, rc));
+        cbProcessedTotal += cbProcessed;
 
         if (rc == VINF_EOF)
@@ -4316,24 +4349,25 @@
         if (hdaStreamTransferIsComplete(pThis, pStream, &fInterrupt))
             break;
-    }
+
+    } while (RT_SUCCESS(rc));
 
     /* Remove the FIFORDY bit again. */
     HDA_STREAM_REG(pThis, STS, pStream->u8SD) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
 
-#ifdef FOO
-    #if defined (RT_OS_LINUX) && defined(DEBUG_andy)
+    LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8SD, cbProcessedTotal, cbToProcess, rc));
+
+#ifdef DEBUG_SIMPLE
+# ifdef HDA_DEBUG_DUMP_PCM_DATA
         RTFILE fh;
-        RTFileOpen(&fh, "/tmp/hdaWriteAudio.pcm",
+        RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio.pcm",
                    RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
         RTFileWrite(fh, u8FIFO, u8FIFOff, NULL);
         RTFileClose(fh);
-    #endif
-#if 1
+# endif
+
      AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, u8FIFO, u8FIFOff,
                          NULL /* pcbWritten */);
-#endif
-#endif
-
-#ifdef FOO
+#endif /* DEBUG_SIMPLE */
+
     if (fInterrupt)
     {
@@ -4352,13 +4386,4 @@
 
         hdaProcessInterrupt(pThis);
-    }
-#endif
-
-    Log3Func(("Written %RU32 / %RU32 (left: %RU32), rc=%Rrc\n", cbTotal, cbToProcess, cbLeft, rc));
-
-    if (RT_SUCCESS(rc))
-    {
-        if (pcbProcessed)
-            *pcbProcessed = cbTotal;
     }
 
Index: /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/DevIchHdaCodec.cpp	(revision 61523)
@@ -267,5 +267,5 @@
 #define CODEC_AMP_NUM_STEPS                                0x7F
 /** The initial gain offset (and when doing a node reset). */
-#define CODEC_AMP_OFF_INITIAL                              0x40
+#define CODEC_AMP_OFF_INITIAL                              0x7F
 /** The amplifier's gain step size. */
 #define CODEC_AMP_STEP_SIZE                                0x2
@@ -928,7 +928,7 @@
             /* Default input amplifier capabilities. */
             pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE,
-                                                                0 /* Step size */,
+                                                                CODEC_AMP_STEP_SIZE,
                                                                 CODEC_AMP_NUM_STEPS,
-                                                                0 /* Initial offset */);
+                                                                CODEC_AMP_OFF_INITIAL);
             /* Default output amplifier capabilities. */
             pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE,
@@ -1003,5 +1003,5 @@
             pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */
 
-            pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 13, 0)
+            pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
                                                | CODEC_F00_09_CAP_POWER_CTRL
                                                | CODEC_F00_09_CAP_CONNECTION_LIST
@@ -1062,5 +1062,5 @@
         case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
         {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(false /*fPresent*/, CODEC_F09_ANALOG_NA);
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /*fPresent*/, CODEC_F09_ANALOG_NA);
 
             pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
@@ -1087,5 +1087,5 @@
         case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
         {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /*fPresent*/, CODEC_F09_ANALOG_NA);
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
 
             pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
@@ -1111,5 +1111,5 @@
         case STAC9220_NID_PIN_C: /* Rear Speaker. */
         {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /*fPresent*/, CODEC_F09_ANALOG_NA);
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
 
             pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
@@ -1135,5 +1135,5 @@
         case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
         {
-            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(false /*fPresent*/, CODEC_F09_ANALOG_NA);
+            pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
 
             pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
Index: /trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61523)
@@ -18,28 +18,4 @@
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
  * --------------------------------------------------------------------
- *
- * This code is based on: audio.c from QEMU AUDIO subsystem.
- *
- * QEMU Audio subsystem
- *
- * Copyright (c) 2003-2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
  */
 #define LOG_GROUP LOG_GROUP_DRV_AUDIO
@@ -148,4 +124,11 @@
 }
 
+/**
+ * Returns the host stream part of an audio stream pair, or NULL
+ * if no host stream has been assigned / is not available.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             Audio stream to retrieve host stream part for.
+ */
 inline PPDMAUDIOSTREAM drvAudioGetHostStream(PPDMAUDIOSTREAM pStream)
 {
@@ -448,5 +431,4 @@
 }
 
-#if 1
 /**
  * Writes VM audio output data from the guest stream into the host stream.
@@ -479,4 +461,8 @@
     }
 
+    AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT,
+              ("Stream '%s' is not an output stream and therefore cannot be written to (direction is 0x%x)\n",
+               pStream->szName, pStream->enmDir));
+
     LogFlowFunc(("[%s]: cbBuf=%RU32\n", pStream->szName, cbBuf));
 
@@ -516,52 +502,4 @@
     }
 
-#if 0
-    uint32_t cMixed = 0;
-    if (RT_SUCCESS(rc))
-    {
-        /* Mix just written guest stream samples to the host immediately. */
-        rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cWritten, &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
-    AssertRC(rc);
-#endif
-
-#if 0
-    /*
-     * Second, mix the guest mixing buffer with the host mixing
-     * buffer so that the host backend can play the data lateron.
-     */
-    uint32_t cMixed;
-    if (   RT_SUCCESS(rc)
-        && cWritten)
-    {
-        rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cWritten, &cMixed);
-    }
-    else
-        cMixed = 0;
-
-    if (RT_SUCCESS(rc))
-    {
-        /*
-         * Return the number of samples which actually have been mixed
-         * down to the parent, regardless how much samples were written
-         * into the children buffer.
-         */
-        if (pcbWritten)
-            *pcbWritten = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cMixed);
-    }
-#else
     if (RT_SUCCESS(rc))
     {
@@ -569,5 +507,4 @@
             *pcbWritten = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritten);
     }
-#endif
 
     LogFlowFunc(("cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
@@ -580,88 +517,4 @@
     return rc;
 }
-#else
-static DECLCALLBACK(int) drvAudioWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut,
-                                       const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
-{
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
-    AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);
-    AssertPtrReturn(pvBuf,       VERR_INVALID_POINTER);
-    AssertReturn(cbBuf,          VERR_INVALID_PARAMETER);
-    /* pcbWritten is optional. */
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
-    {
-        rc = RTCritSectLeave(&pThis->CritSect);
-        AssertRC(rc);
-
-        return VERR_NOT_AVAILABLE;
-    }
-
-    PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
-    AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
-    AssertMsg(pGstStrmOut->pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
-              ("Writing to disabled host output stream \"%s\" not possible\n",
-              pHstStrmOut->MixBuf.pszName));
-
-    if (!AudioMixBufFreeBytes(&pGstStrmOut->MixBuf))
-    {
-        if (pcbWritten)
-            *pcbWritten = 0;
-
-        return RTCritSectLeave(&pThis->CritSect);
-    }
-
-    /*
-     * First, write data from the device emulation into our
-     * guest mixing buffer.
-     */
-    uint32_t cWritten;
-    //rc = AudioMixBufWriteAt(&pGstStrmOut->MixBuf, 0 /* Offset in samples */, pvBuf, cbBuf, &cWritten);
-    rc = AudioMixBufWriteCirc(&pGstStrmOut->MixBuf, pvBuf, cbBuf, &cWritten);
-    if (rc == VINF_BUFFER_OVERFLOW)
-        LogRel(("Audio: Lost audio samples from guest, expect stuttering audio output\n"));
-
-    /*
-     * Second, mix the guest mixing buffer with the host mixing
-     * buffer so that the host backend can play the data lateron.
-     */
-    uint32_t cMixed;
-    if (   RT_SUCCESS(rc)
-        && cWritten)
-    {
-        rc = AudioMixBufMixToParent(&pGstStrmOut->MixBuf, cWritten, &cMixed);
-    }
-    else
-        cMixed = 0;
-
-    if (RT_SUCCESS(rc))
-    {
-        /*
-         * Return the number of samples which actually have been mixed
-         * down to the parent, regardless how much samples were written
-         * into the children buffer.
-         */
-        if (pcbWritten)
-            *pcbWritten = AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cMixed);
-    }
-
-    LogFlowFunc(("%s -> %s: cbBuf=%RU32, cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
-                 pGstStrmOut->MixBuf.pszName, pHstStrmOut->MixBuf.pszName, cbBuf, cWritten,
-                 AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cWritten), cMixed, rc));
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    return rc;
-}
-#endif
 
 static DECLCALLBACK(uint32_t) drvAudioStreamAddRef(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
@@ -688,5 +541,4 @@
 }
 
-#if 1
 static DECLCALLBACK(int) drvAudioStreamIterate(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
 {
@@ -725,5 +577,7 @@
 
     PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    AssertPtr(pHstStream);
     PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+    AssertPtr(pGstStream);
 
     int rc = VINF_SUCCESS;
@@ -731,6 +585,5 @@
     do
     {
-        /*if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
-            break;*/
+        uint32_t cSamplesMixed = 0;
 
         PDMAUDIOSTRMSTS hstStrmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
@@ -738,16 +591,22 @@
         if (pHstStream->enmDir == PDMAUDIODIR_IN)
         {
-            /* Call the host backend to capture the audio input data. */
-            uint32_t cSamplesCaptured;
-            rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured);
-            if (RT_FAILURE(rc))
-                break;
-
-            //cbData = AUDIOMIXBUF_S2B(&pStream->MixBuf, AudioMixBufMixed(&pStream->MixBuf)));
-
-        }
-        else /* PDMAUDIODIR_OUT */
-        {
-            uint32_t cSamplesMixed = 0;
+            uint32_t cSamplesToCapture = AudioMixBufFree(&pGstStream->MixBuf);
+            if (cSamplesToCapture)
+            {
+                if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE)
+                {
+                    uint32_t cSamplesCaptured = 0;
+
+                    /* Call the host backend to capture the audio input data. */
+                    rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured);
+                    if (RT_FAILURE(rc))
+                        break;
+
+                    LogFlowFunc(("%s: %RU32 samples captured, rc=%Rrc\n", pHstStream->szName, cSamplesCaptured, rc));
+                }
+            }
+        }
+        else if (pHstStream->enmDir == PDMAUDIODIR_OUT)
+        {
             uint32_t cSamplesToMix = AudioMixBufUsed(&pGstStream->MixBuf);
 
@@ -757,16 +616,13 @@
                 if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)
                 {
-            /*    int rc2 = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cSamplesPlayed);
-                if (RT_SUCCESS(rc))
-                    rc = rc2;
-            }*/
-
                     rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cSamplesToMix, &cSamplesMixed);
 
-                    LogFlowFunc(("%s: %RU32/%RU32 samples mixed, rc=%Rrc\n",
+                    LogFlowFunc(("%s: %RU32/%RU32 playback samples mixed, rc=%Rrc\n",
                                  pHstStream->szName, cSamplesMixed, cSamplesToMix, rc));
                 }
             }
         }
+        else
+            AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
 
         if (RT_SUCCESS(rc))
@@ -775,175 +631,12 @@
     } while (0);
 
+    if (RT_FAILURE(rc))
+        LogFunc(("Failed with %Rrc\n", rc));
+
     return rc;
 }
-#else
-static DECLCALLBACK(int) drvAudioGetDataIn(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbAvailIn)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    /* pcbAvailIn is optional. */
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    uint32_t cbAvailIn = 0;
-
-    PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
-    while ((pHstStrmIn = drvAudioFindAnyHstIn(pThis, pHstStrmIn)))
-    {
-        /* Disabled? Skip it! */
-        if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
-            continue;
-
-        /* Call the host backend to capture the audio input data. */
-        uint32_t cSamplesCaptured;
-        int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn,
-                                                     &cSamplesCaptured);
-        if (RT_FAILURE(rc2))
-            continue;
-
-        PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn;
-        AssertPtrBreak(pGstStrmIn);
-
-        if (pGstStrmIn->State.fActive)
-        {
-            cbAvailIn = RT_MAX(cbAvailIn, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf,
-                                                          AudioMixBufMixed(&pHstStrmIn->MixBuf)));
-#ifdef DEBUG_andy
-            LogFlowFunc(("\t[%s] cbAvailIn=%RU32\n", pHstStrmIn->MixBuf.pszName, cbAvailIn));
-#endif
-        }
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        if (pcbAvailIn)
-            *pcbAvailIn = cbAvailIn;
-    }
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    if (RT_FAILURE(rc))
-        LogFlowFuncLeaveRC(rc);
-
-    return rc;
-}
-
-static DECLCALLBACK(int) drvAudioGetDataOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbFreeOut, uint32_t *pcSamplesLive)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    /* pcbFreeOut is optional. */
-    /* pcSamplesLive is optional. */
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    static uint64_t s_tsLast = 0;
-
-
-    uint64_t s_tsDelta = RTTimeNanoTS() - s_tsLast;
-    LogFlowFunc(("delta=%RU64 (%RU64ms) -> ", s_tsDelta, s_tsDelta / 1000 / 1000));
-
-    #if 0
-    PPDMAUDIOHSTSTRMOUT pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, NULL);
-    uint64_t ns = s_tsDelta / pHstStrmOut->Props.uHz;
-
-
-
-    uint32_t cSamplesMin  = (cTicksElapsed / pSink->PCMProps.uHz) * pSink->PCMProps.cChannels;
-    #endif
-
-    s_tsLast = RTTimeNanoTS();
-
-    /*
-     * Playback.
-     */
-    uint32_t cSamplesLive = 0;
-    uint32_t cbFreeOut    = UINT32_MAX;
-
-    PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
-    while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
-    {
-        cSamplesLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
-
-        /* Has this stream marked as disabled but there still were guest streams relying
-         * on it? Check if this stream now can be closed and do so, if possible. */
-        if (   (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
-            && !cSamplesLive)
-        {
-            /* Stop playing the current (pending) stream. */
-            int rc2 = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
-            if (RT_SUCCESS(rc2))
-            {
-                pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
-
-                LogFunc(("[%s] Disabling stream\n", pHstStrmOut->MixBuf.pszName));
-            }
-            else
-                LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc2));
-
-            continue;
-        }
-
-        LogFlowFunc(("[%s] cSamplesLive=%RU32\n", pHstStrmOut->MixBuf.pszName, cSamplesLive));
-
-        /*
-         * No live samples to play at the moment?
-         *
-         * Tell the device emulation for each connected guest stream how many
-         * bytes are free so that the device emulation can continue writing data to
-         * these streams.
-         */
-        PPDMAUDIOGSTSTRMOUT pGstStrmOut;
-        uint32_t cbFree2 = UINT32_MAX;
-        RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
-        {
-            if (pGstStrmOut->State.fActive)
-            {
-                /* Tell the sound device emulation how many samples are free
-                 * so that it can start writing PCM data to us. */
-                cbFree2 = RT_MIN(cbFree2, AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
-                                                                AudioMixBufFree(&pGstStrmOut->MixBuf)));
-#ifdef DEBUG_andy
-                LogFlowFunc(("\t[%s] cbFreeOut=%RU32\n", pGstStrmOut->MixBuf.pszName, cbFree2));
-#endif
-            }
-        }
-
-        cbFreeOut = RT_MIN(cbFreeOut, cbFree2);
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        if (cbFreeOut == UINT32_MAX)
-            cbFreeOut = 0;
-
-        if (pcbFreeOut)
-            *pcbFreeOut = cbFreeOut;
-
-        if (pcSamplesLive)
-            *pcSamplesLive = cSamplesLive;
-    }
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    if (RT_FAILURE(rc))
-        LogFlowFuncLeaveRC(rc);
-
-    return rc;
-}
-#endif
-
-#if 1
-static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed)
+
+static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
+                                            uint32_t *pcSamplesPlayed)
 {
     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
@@ -951,4 +644,8 @@
     /* pcSamplesPlayed is optional. */
 
+    AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT,
+              ("Stream '%s' is not an output stream and therefore cannot be played back (direction is 0x%x)\n",
+               pStream->szName, pStream->enmDir));
+
     AssertMsg(pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED,
               ("Unable to play stream '%s' (status is 0x%x)\n", pStream->szName, pStream->fStatus));
@@ -981,4 +678,5 @@
 
         PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+        AssertPtr(pHstStream);
         PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
         AssertPtr(pGstStream);
@@ -1021,29 +719,5 @@
             }
         }
-    #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);
 
@@ -1063,9 +737,14 @@
     return rc;
 }
-#else
-static DECLCALLBACK(int) drvAudioPlayOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    /* pcSamplesPlayed is optional. */
+
+static DECLCALLBACK(int) drvAudioStreamCapture(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
+                                               uint32_t *pcSamplesCaptured)
+{
+    AssertMsg(pStream->enmDir == PDMAUDIODIR_IN,
+              ("Stream '%s' is not an input stream and therefore cannot be captured (direction is 0x%x)\n",
+               pStream->szName, pStream->enmDir));
+
+    AssertMsg(pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED,
+              ("Unable to capture stream '%s' (status is 0x%x)\n", pStream->szName, pStream->fStatus));
 
     PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
@@ -1075,98 +754,73 @@
         return rc;
 
-    /* Backend output (temporarily) disabled / unavailable? */
-    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
-    {
-        rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
-        AssertRC(rc);
-
-        if (   !pThis->BackendCfg.cSinks
-            || !pThis->BackendCfg.cMaxStreamsOut)
-        {
-            int rc2 = RTCritSectLeave(&pThis->CritSect);
-            AssertRC(rc2);
-
-            return VERR_NOT_AVAILABLE;
-        }
-    }
-
-    /*
-     * Process all enabled host output streams.
-     */
-    uint32_t            cSamplesPlayedMax = 0;
-    PPDMAUDIOHSTSTRMOUT pHstStrmOut       = NULL;
-    while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
-    {
-#if 0
-        uint32_t cStreamsLive;
-        uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
-        if (!cStreamsLive)
-            cSamplesLive = 0;
-
-        /* Has this stream marked as disabled but there still were guest streams relying
-         * on it? Check if this stream now can be closed and do so, if possible. */
-        if (   pHstStrmOut->fPendingDisable
-            && !cStreamsLive)
-        {
-            /* Stop playing the current (pending) stream. */
-            int rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut,
-                                                          PDMAUDIOSTREAMCMD_DISABLE);
-            if (RT_SUCCESS(rc2))
-            {
-                pHstStrmOut->fEnabled        = false;
-                pHstStrmOut->fPendingDisable = false;
-
-                LogFunc(("\t%p: Disabling stream\n", pHstStrmOut));
-            }
-            else
-                LogFunc(("\t%p: Backend vetoed against closing output stream, rc=%Rrc\n",
-                         pHstStrmOut, rc2));
-
-            continue;
-        }
-#endif
-        uint32_t cSamplesPlayed = 0;
-        int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed);
-        if (RT_FAILURE(rc2))
-        {
-            int rc3 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
-            AssertRC(rc3);
-        }
-        else
-            cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax);
-
-        LogFlowFunc(("\t[%s] cSamplesPlayed=%RU32, cSamplesPlayedMax=%RU32, rc=%Rrc\n",
-                     pHstStrmOut->MixBuf.pszName, cSamplesPlayed, cSamplesPlayedMax, rc2));
-
-        bool fNeedsCleanup = false;
-
-        PPDMAUDIOGSTSTRMOUT pGstStrmOut;
-        RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
-        {
-            if (   !pGstStrmOut->State.fActive
-                && pGstStrmOut->State.fEmpty)
-                continue;
-
-            if (AudioMixBufIsEmpty(&pGstStrmOut->MixBuf))
-            {
-                pGstStrmOut->State.fEmpty = true;
-                fNeedsCleanup |= !pGstStrmOut->State.fActive;
-            }
-        }
-
-        if (fNeedsCleanup)
-        {
-            RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
-            {
-                if (!pGstStrmOut->State.fActive)
-                    drvAudioDestroyGstOut(pThis, pGstStrmOut);
-            }
-        }
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        if (pcSamplesPlayed)
-            *pcSamplesPlayed = cSamplesPlayedMax;
+    LogFlowFunc(("[%s]\n", pStream->szName));
+
+    uint32_t cSamplesCaptured = 0;
+
+    do
+    {
+        /* Backend input (temporarily) disabled / unavailable? */
+        if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
+        {
+            rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
+            AssertRC(rc);
+
+            if (   !pThis->BackendCfg.cSources
+                || !pThis->BackendCfg.cMaxStreamsIn)
+            {
+                rc = VERR_NOT_AVAILABLE;
+                break;
+            }
+        }
+
+        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+        AssertPtr(pHstStream);
+        PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+        AssertPtr(pGstStream);
+
+        uint32_t cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf);
+        if (cSamplesLive)
+        {
+            PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
+            if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE)
+            {
+                rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, &cSamplesCaptured);
+                if (RT_FAILURE(rc))
+                    drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+            }
+
+            LogFlowFunc(("[%s] strmSts=0x%x, cSamplesCaptured=%RU32, rc=%Rrc\n", pStream->szName, strmSts, cSamplesCaptured, rc));
+
+            if (RT_SUCCESS(rc))
+            {
+                rc = drvAudioStreamIterateInternal(pThis, pStream);
+                if (RT_SUCCESS(rc))
+                    cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf);
+            }
+        }
+
+        if (!cSamplesLive)
+        {
+            /* Has the host stream marked as disabled but there still were guest streams relying
+             * on it? Check if the stream now can be closed and do so, if possible. */
+            if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
+            {
+                LogFunc(("%s: Closing pending stream\n", pHstStream->szName));
+                rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+                if (RT_SUCCESS(rc))
+                {
+                    pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+                }
+                else
+                    LogFunc(("%s: Backend vetoed against closing input stream, rc=%Rrc\n", pHstStream->szName, rc));
+            }
+        }
+
+    } while (0);
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = cSamplesCaptured;
     }
 
@@ -1180,5 +834,4 @@
     return rc;
 }
-#endif
 
 #ifdef VBOX_WITH_AUDIO_CALLBACKS
@@ -1378,4 +1031,564 @@
     PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
     LogFlowFunc(("pThis=%p, pDrvIns=%p\n", pThis, pDrvIns));
+
+    int rc = RTCritSectInit(&pThis->CritSect);
+
+    /** @todo Add audio driver options. */
+
+    /*
+     * If everything went well, initialize the lower driver.
+     */
+    if (RT_SUCCESS(rc))
+        rc = drvAudioHostInit(pCfgHandle, pThis);
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
+                                            void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+{
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+    if (!pStream)
+    {
+        if (pcbRead)
+            *pcbRead = 0;
+        return VINF_SUCCESS;
+    }
+
+    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+    AssertReturn(cbBuf,    VERR_INVALID_PARAMETER);
+    /* pcbWritten is optional. */
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    AssertMsg(pStream->enmDir == PDMAUDIODIR_IN,
+              ("Stream '%s' is not an input stream and therefore cannot be read from (direction is 0x%x)\n",
+               pStream->szName, pStream->enmDir));
+
+    if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
+    {
+        if (pcbRead)
+            *pcbRead = 0;
+
+        return RTCritSectLeave(&pThis->CritSect);
+    }
+
+    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+
+    AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
+              ("Reading from disabled host input stream '%s' not possible\n", pHstStream->szName));
+
+    Log3Func(("%s\n", pStream->szName));
+
+    /*
+     * Read from the parent buffer (that is, the guest buffer) which
+     * should have the audio data in the format the guest needs.
+     */
+    uint32_t cRead;
+    rc = AudioMixBufReadCirc(&pGstStream->MixBuf, pvBuf, cbBuf, &cRead);
+    if (RT_SUCCESS(rc))
+    {
+        if (cRead)
+            AudioMixBufFinish(&pGstStream->MixBuf, cRead);
+
+        if (pcbRead)
+            *pcbRead = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead);
+    }
+
+    LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
+                 cRead, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead), rc));
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return rc;
+}
+
+static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,
+                                              PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest,
+                                              PPDMAUDIOSTREAM *ppStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgHost,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfgGuest,  VERR_INVALID_POINTER);
+    AssertPtrReturn(ppStream,   VERR_INVALID_POINTER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName));
+#ifdef DEBUG
+    DrvAudioHlpStreamCfgPrint(pCfgHost);
+    DrvAudioHlpStreamCfgPrint(pCfgGuest);
+#endif
+
+    /*
+     * The guest stream always will get the audio stream configuration told
+     * by the device emulation (which in turn was/could be set by the guest OS).
+     */
+    PPDMAUDIOSTREAM pGstStrm = NULL;
+
+    /** @todo Docs! */
+    PPDMAUDIOSTREAM pHstStrm = NULL;
+
+#define RC_BREAK(x) { rc = x; break; }
+
+    do
+    {
+        if (   !DrvAudioHlpStreamCfgIsValid(pCfgHost)
+            || !DrvAudioHlpStreamCfgIsValid(pCfgGuest))
+        {
+            RC_BREAK(VERR_INVALID_PARAMETER);
+        }
+
+        /* Make sure that both configurations actually intend the same thing. */
+        if (pCfgHost->enmDir != pCfgGuest->enmDir)
+        {
+            AssertMsgFailed(("Stream configuration directions do not match\n"));
+            RC_BREAK(VERR_INVALID_PARAMETER);
+        }
+
+        /* Note: cbHstStrm will contain sizeof(PDMAUDIOSTREAM) + additional data
+         *       which the host backend will need. */
+        size_t cbHstStrm;
+        if (pCfgHost->enmDir == PDMAUDIODIR_IN)
+        {
+            if (!pThis->cStreamsFreeIn)
+            {
+                LogFlowFunc(("No more input streams free to use, bailing out\n"));
+                RC_BREAK(VERR_AUDIO_NO_FREE_INPUT_STREAMS);
+            }
+
+            /* Validate backend configuration. */
+            if (!pThis->BackendCfg.cbStreamIn)
+            {
+                LogFlowFunc(("Backend input configuration not valid, bailing out\n"));
+                RC_BREAK(VERR_INVALID_PARAMETER);
+            }
+
+            cbHstStrm = pThis->BackendCfg.cbStreamIn;
+        }
+        else /* Out */
+        {
+            if (!pThis->cStreamsFreeOut)
+            {
+                LogFlowFunc(("Maximum number of host output streams reached\n"));
+                RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS);
+            }
+
+            /* Validate backend configuration. */
+            if (!pThis->BackendCfg.cbStreamOut)
+            {
+                LogFlowFunc(("Backend output configuration invalid, bailing out\n"));
+                RC_BREAK(VERR_INVALID_PARAMETER);
+            }
+
+            cbHstStrm = pThis->BackendCfg.cbStreamOut;
+        }
+
+        pHstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(cbHstStrm);
+        AssertPtrBreakStmt(pHstStrm, rc = VERR_NO_MEMORY);
+
+        pHstStrm->enmCtx = PDMAUDIOSTREAMCTX_HOST;
+        pHstStrm->enmDir = pCfgHost->enmDir;
+
+        pGstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM));
+        AssertPtrBreakStmt(pGstStrm, rc = VERR_NO_MEMORY);
+
+        pGstStrm->enmCtx = PDMAUDIOSTREAMCTX_GUEST;
+        pGstStrm->enmDir = pCfgGuest->enmDir;
+
+        /*
+         * Create host stream.
+         */
+
+        RTStrPrintf(pHstStrm->szName, RT_ELEMENTS(pHstStrm->szName), "%s (Host)",
+                    strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>");
+
+        /* Note: Direction is always from child -> parent. */
+        uint32_t cSamples = 0;
+        rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStrm, pCfgHost, &cSamples);
+        if (RT_FAILURE(rc))
+        {
+            LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
+            break;
+        }
+
+        pHstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
+        pHstStrm->pPair    = pGstStrm;
+
+        rc = DrvAudioHlpStreamCfgToProps(pCfgHost, &pHstStrm->Props);
+        AssertRCBreak(rc);
+
+        rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples * 4);
+        AssertRCBreak(rc);
+
+        /*
+         * Create guest stream.
+         */
+
+        RTStrPrintf(pGstStrm->szName, RT_ELEMENTS(pGstStrm->szName), "%s (Guest)",
+                    strlen(pCfgGuest->szName) ? pCfgGuest->szName : "<Untitled>");
+
+        rc = DrvAudioHlpStreamCfgToProps(pCfgGuest, &pGstStrm->Props);
+        AssertRCBreak(rc);
+
+        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);
+            }
+        }
+
+        pGstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
+        pGstStrm->pPair    = pHstStrm;
+
+        AssertRCBreak(rc);
+
+    } while (0);
+
+#undef RC_BREAK
+
+    if (RT_FAILURE(rc))
+    {
+        drvAudioStreamDestroyInternal(pThis, pGstStrm);
+        pGstStrm = NULL;
+
+        drvAudioStreamDestroyInternal(pThis, pHstStrm);
+        pHstStrm = NULL;
+    }
+    else
+    {
+        /* Set initial reference counts. */
+        RTListAppend(&pThis->lstGstStreams, &pGstStrm->Node);
+        pGstStrm->cRefs = 1;
+
+        RTListAppend(&pThis->lstHstStreams, &pHstStrm->Node);
+        pHstStrm->cRefs = 1;
+
+        if (pCfgHost->enmDir == PDMAUDIODIR_IN)
+        {
+            Assert(pThis->cStreamsFreeIn);
+            pThis->cStreamsFreeIn--;
+        }
+        else /* Out */
+        {
+            Assert(pThis->cStreamsFreeOut);
+            pThis->cStreamsFreeOut--;
+        }
+
+        /* Always return the guest-side part to the device emulation. */
+        *ppStream = pGstStrm;
+    }
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+#if 1
+static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,       VERR_INVALID_POINTER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg);
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+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)
+{
+    AssertPtrReturn(pInterface, false);
+
+    if (!pStream)
+        return PDMAUDIOSTRMSTS_FLAG_NONE;
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc2 = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc2);
+
+    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    PDMAUDIOSTRMSTS strmSts    = pHstStream->fStatus;
+
+    LogFlowFunc(("%s: strmSts=0x%x\n", pHstStream->szName, strmSts));
+    rc2 = RTCritSectLeave(&pThis->CritSect);
+    AssertRC(rc2);
+
+    return strmSts;
+}
+
+static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+    AssertPtrReturn(pVol,       VERR_INVALID_POINTER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));
+
+    AudioMixBufSetVolume(&pStream->MixBuf, pVol);
+
+    return VINF_SUCCESS;
+}
+#endif
+
+static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc);
+
+    PDMAUDIODIR enmDir = pStream->enmDir;
+
+    LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
+    if (pStream->cRefs > 1)
+        rc = VERR_WRONG_ORDER;
+
+    if (RT_SUCCESS(rc))
+    {
+        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+        PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
+
+        LogFlowFunc(("\tHost : %s\n", pHstStream ? pHstStream->szName : "<None>"));
+        LogFlowFunc(("\tGuest: %s\n", pGstStream ? pGstStream->szName : "<None>"));
+
+        /* Should prevent double frees. */
+        Assert(pHstStream != pGstStream);
+
+        if (pHstStream)
+        {
+            pHstStream->pPair = NULL;
+            RTListNodeRemove(&pHstStream->Node);
+        }
+
+        if (pGstStream)
+        {
+            pGstStream->pPair = NULL;
+            RTListNodeRemove(&pGstStream->Node);
+        }
+
+        if (pHstStream)
+        {
+            rc = drvAudioStreamDestroyInternal(pThis, pHstStream);
+            AssertRC(rc);
+
+            pHstStream = NULL;
+        }
+
+        if (pGstStream)
+        {
+            rc = drvAudioStreamDestroyInternal(pThis, pGstStream);
+            AssertRC(rc);
+
+            pGstStream = NULL;
+        }
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (enmDir == PDMAUDIODIR_IN)
+        {
+            pThis->cStreamsFreeIn++;
+        }
+        else /* Out */
+        {
+            pThis->cStreamsFreeOut++;
+        }
+    }
+
+    int rc2 = RTCritSectLeave(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+
+static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
+{
+    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
+    AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);
+
+    AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
+              ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));
+
+    int rc = VINF_SUCCESS;
+
+    LogFlowFunc(("%s: fStatus=0x%x\n", pHstStream->szName, pHstStream->fStatus));
+
+    if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
+    {
+        if (pThis->pHostDrvAudio)
+            rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);
+        if (RT_SUCCESS(rc))
+            pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
+    }
+
+    LogFlowFunc(("%s: Returning %Rrc\n", pHstStream->szName, rc));
+    return rc;
+}
+
+static int drvAudioStreamDestroyInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+
+    LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
+
+    if (pStream->cRefs > 1)
+        return VERR_WRONG_ORDER;
+
+    int rc = VINF_SUCCESS;
+
+    if (pStream->enmCtx == PDMAUDIOSTREAMCTX_GUEST)
+    {
+        if (pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
+        {
+            rc = drvAudioStreamControlInternal(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
+            if (RT_SUCCESS(rc))
+                pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
+        }
+    }
+    else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)
+    {
+        rc = drvAudioStreamDestroyInternalBackend(pThis, pStream);
+    }
+    else
+        AssertFailedReturn(VERR_NOT_IMPLEMENTED);
+
+    if (RT_SUCCESS(rc))
+    {
+        /* Destroy mixing buffer. */
+        AudioMixBufDestroy(&pStream->MixBuf);
+
+        if (pStream)
+        {
+            RTMemFree(pStream);
+            pStream = NULL;
+        }
+    }
+
+    LogFlowFunc(("Returning %Rrc\n", rc));
+    return rc;
+}
+
+/********************************************************************/
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID));
+
+    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+    PDRVAUDIO  pThis   = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
+
+    return NULL;
+}
+
+/**
+ * Power Off notification.
+ *
+ * @param   pDrvIns     The driver instance data.
+ */
+static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
+{
+    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+
+    LogFlowFuncEnter();
+
+    /* Just destroy the host stream on the backend side.
+     * The rest will either be destructed by the device emulation or
+     * in drvAudioDestruct(). */
+    PPDMAUDIOSTREAM pStream;
+    RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)
+        drvAudioStreamDestroyInternalBackend(pThis, pStream);
+
+    /*
+     * Last call for the driver below us.
+     * Let it know that we reached end of life.
+     */
+    if (pThis->pHostDrvAudio->pfnShutdown)
+        pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
+
+    pThis->pHostDrvAudio = NULL;
+
+    LogFlowFuncLeave();
+}
+
+/**
+ * Constructs an audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
+{
+    LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags));
+
+    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
+    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
 
     RTListInit(&pThis->lstHstStreams);
@@ -1385,693 +1598,4 @@
     RTListInit(&pThis->lstCBOut);
 #endif
-
-    int rc = RTCritSectInit(&pThis->CritSect);
-
-    /** @todo Add audio driver options. */
-
-    /*
-     * If everything went well, initialize the lower driver.
-     */
-    if (RT_SUCCESS(rc))
-        rc = drvAudioHostInit(pCfgHandle, pThis);
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-#if 1
-static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
-                                            void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
-{
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
-    if (!pStream)
-    {
-        if (pcbRead)
-            *pcbRead = 0;
-        return VINF_SUCCESS;
-    }
-
-    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
-    AssertReturn(cbBuf,    VERR_INVALID_PARAMETER);
-    /* pcbWritten is optional. */
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
-    {
-        if (pcbRead)
-            *pcbRead = 0;
-
-        return RTCritSectLeave(&pThis->CritSect);
-    }
-
-    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
-
-    AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
-              ("Reading from disabled host input stream '%s' not possible\n", pHstStream->szName));
-
-    /*
-     * Read from the parent buffer (that is, the guest buffer) which
-     * should have the audio data in the format the guest needs.
-     */
-    uint32_t cRead;
-    rc = AudioMixBufReadCirc(&pStream->MixBuf, pvBuf, cbBuf, &cRead);
-    if (RT_SUCCESS(rc))
-    {
-        AudioMixBufFinish(&pStream->MixBuf, cRead);
-
-        if (pcbRead)
-            *pcbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);
-    }
-
-    LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
-                 cRead, AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead), rc));
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    return rc;
-}
-#else
-static DECLCALLBACK(int) drvAudioRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn,
-                                      void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
-{
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
-    if (!pGstStrmIn)
-        return VERR_NOT_AVAILABLE;
-
-    AssertPtrReturn(pvBuf,      VERR_INVALID_POINTER);
-    AssertReturn(cbBuf,         VERR_INVALID_PARAMETER);
-    /* pcbWritten is optional. */
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_IN))
-    {
-        if (pcbRead)
-            *pcbRead = 0;
-
-        return RTCritSectLeave(&pThis->CritSect);
-    }
-
-    PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
-    AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
-    AssertMsg(pGstStrmIn->pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
-              ("Reading from disabled host input stream \"%s\" not possible\n", pGstStrmIn->MixBuf.pszName));
-
-    /*
-     * Read from the parent buffer (that is, the guest buffer) which
-     * should have the audio data in the format the guest needs.
-     */
-    uint32_t cRead;
-    rc = AudioMixBufReadCirc(&pGstStrmIn->MixBuf, pvBuf, cbBuf, &cRead);
-    if (RT_SUCCESS(rc))
-    {
-        AudioMixBufFinish(&pGstStrmIn->MixBuf, cRead);
-
-        if (pcbRead)
-            *pcbRead = AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead);
-    }
-
-    LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
-                 cRead, AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead), rc));
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    return rc;
-}
-#endif
-
-#if 0
-static DECLCALLBACK(int) drvAudioEnableOut(PPDMIAUDIOCONNECTOR pInterface,
-                                           PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-
-    if (!pGstStrmOut)
-        return VERR_NOT_AVAILABLE;
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    int rc = VINF_SUCCESS;
-
-    PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
-    AssertPtr(pHstStrmOut);
-
-    if (fEnable)
-    {
-        /* Is a pending disable outstanding? Then disable first. */
-        if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
-        {
-            rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
-            if (RT_SUCCESS(rc))
-                pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
-        }
-
-        if (RT_SUCCESS(rc))
-            rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
-
-        if (RT_SUCCESS(rc))
-            pGstStrmOut->State.fActive = fEnable;
-    }
-    else /* Disable */
-    {
-        if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
-        {
-            size_t cGstStrmsActive = 0;
-
-            /*
-             * Check if there are any active guest streams assigned
-             * to this host stream which still are being marked as active.
-             *
-             * In that case we have to defer closing the host stream and
-             * wait until all guest streams have been finished.
-             */
-            PPDMAUDIOGSTSTRMOUT pIter;
-            RTListForEach(&pHstStrmOut->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
-            {
-                if (pIter->State.fActive)
-                {
-                    cGstStrmsActive++;
-                    break; /* At least one assigned & active guest stream is enough. */
-                }
-            }
-
-            /* Do we need to defer closing the host stream? */
-            if (cGstStrmsActive)
-            {
-                LogFlowFunc(("Closing stream deferred: %zu guest stream(s) active\n", cGstStrmsActive));
-                pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
-
-                rc = VERR_AUDIO_STREAM_PENDING_DISABLE;
-            }
-            else
-            {
-                rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
-                if (RT_SUCCESS(rc))
-                    pGstStrmOut->State.fActive = fEnable;
-            }
-        }
-    }
-
-    LogFlowFunc(("%s: fEnable=%RTbool, fStatus=0x%x, rc=%Rrc\n",
-                 pGstStrmOut->MixBuf.pszName, fEnable, pHstStrmOut->fStatus, rc));
-
-    return rc;
-}
-#endif
-
-static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,
-                                              PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest,
-                                              PPDMAUDIOSTREAM *ppStream)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfgHost,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfgGuest,  VERR_INVALID_POINTER);
-    AssertPtrReturn(ppStream,   VERR_INVALID_POINTER);
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName));
-#ifdef DEBUG
-    DrvAudioHlpStreamCfgPrint(pCfgHost);
-    DrvAudioHlpStreamCfgPrint(pCfgGuest);
-#endif
-
-    /*
-     * The guest stream always will get the audio stream configuration told
-     * by the device emulation (which in turn was/could be set by the guest OS).
-     */
-    PPDMAUDIOSTREAM pGstStrm = NULL;
-
-    /** @todo Docs! */
-    PPDMAUDIOSTREAM pHstStrm = NULL;
-
-#define RC_BREAK(x) { rc = x; break; }
-
-    do
-    {
-        if (   !DrvAudioHlpStreamCfgIsValid(pCfgHost)
-            || !DrvAudioHlpStreamCfgIsValid(pCfgGuest))
-        {
-            RC_BREAK(VERR_INVALID_PARAMETER);
-        }
-
-        /* Make sure that both configurations actually intend the same thing. */
-        if (pCfgHost->enmDir != pCfgGuest->enmDir)
-        {
-            AssertMsgFailed(("Stream configuration directions do not match\n"));
-            RC_BREAK(VERR_INVALID_PARAMETER);
-        }
-
-        /* Note: cbHstStrm will contain sizeof(PDMAUDIOSTREAM) + additional data
-         *       which the host backend will need. */
-        size_t cbHstStrm;
-        if (pCfgHost->enmDir == PDMAUDIODIR_IN)
-        {
-            if (!pThis->cStreamsFreeIn)
-            {
-                LogFlowFunc(("No more input streams free to use, bailing out\n"));
-                RC_BREAK(VERR_AUDIO_NO_FREE_INPUT_STREAMS);
-            }
-
-            /* Validate backend configuration. */
-            if (!pThis->BackendCfg.cbStreamIn)
-            {
-                LogFlowFunc(("Backend input configuration not valid, bailing out\n"));
-                RC_BREAK(VERR_INVALID_PARAMETER);
-            }
-
-            cbHstStrm = pThis->BackendCfg.cbStreamIn;
-        }
-        else /* Out */
-        {
-            if (!pThis->cStreamsFreeOut)
-            {
-                LogFlowFunc(("Maximum number of host output streams reached\n"));
-                RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS);
-            }
-
-            /* Validate backend configuration. */
-            if (!pThis->BackendCfg.cbStreamOut)
-            {
-                LogFlowFunc(("Backend output configuration invalid, bailing out\n"));
-                RC_BREAK(VERR_INVALID_PARAMETER);
-            }
-
-            cbHstStrm = pThis->BackendCfg.cbStreamOut;
-        }
-
-        pHstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(cbHstStrm);
-        AssertPtrBreakStmt(pHstStrm, rc = VERR_NO_MEMORY);
-
-        pHstStrm->enmCtx = PDMAUDIOSTREAMCTX_HOST;
-        pHstStrm->enmDir = pCfgHost->enmDir;
-
-        RTListAppend(&pThis->lstHstStreams, &pHstStrm->Node);
-
-        pGstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM));
-        AssertPtrBreakStmt(pGstStrm, rc = VERR_NO_MEMORY);
-
-        pGstStrm->enmCtx = PDMAUDIOSTREAMCTX_GUEST;
-        pGstStrm->enmDir = pCfgGuest->enmDir;
-
-        RTListAppend(&pThis->lstGstStreams, &pGstStrm->Node);
-
-        /*
-         * Create host stream.
-         */
-
-        RTStrPrintf(pHstStrm->szName, RT_ELEMENTS(pHstStrm->szName), "%s (Host)",
-                    strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>");
-
-        /* Note: Direction is always from child -> parent. */
-        uint32_t cSamples = 0;
-        rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStrm, pCfgHost, &cSamples);
-        if (RT_FAILURE(rc))
-        {
-            LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
-            break;
-        }
-
-        pHstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
-        pHstStrm->pPair    = pGstStrm;
-
-        rc = DrvAudioHlpStreamCfgToProps(pCfgHost, &pHstStrm->Props);
-        AssertRCBreak(rc);
-
-        rc = AudioMixBufInit(&pHstStrm->MixBuf, pHstStrm->szName, &pHstStrm->Props, cSamples * 4);
-        AssertRCBreak(rc);
-
-        /*
-         * Create guest stream.
-         */
-
-        RTStrPrintf(pGstStrm->szName, RT_ELEMENTS(pGstStrm->szName), "%s (Guest)",
-                    strlen(pCfgGuest->szName) ? pCfgGuest->szName : "<Untitled>");
-
-        rc = DrvAudioHlpStreamCfgToProps(pCfgGuest, &pGstStrm->Props);
-        AssertRCBreak(rc);
-
-        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);
-            }
-        }
-
-        pGstStrm->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
-        pGstStrm->pPair    = pHstStrm;
-
-        AssertRCBreak(rc);
-
-    } while (0);
-
-#undef RC_BREAK
-
-    if (RT_FAILURE(rc))
-    {
-        drvAudioStreamDestroyInternal(pThis, pGstStrm);
-        pGstStrm = NULL;
-
-        drvAudioStreamDestroyInternal(pThis, pHstStrm);
-        pHstStrm = NULL;
-    }
-    else
-    {
-        /* Set initial reference counts. */
-        pGstStrm->cRefs = 1;
-        pHstStrm->cRefs = 1;
-
-        if (pCfgHost->enmDir == PDMAUDIODIR_IN)
-        {
-            Assert(pThis->cStreamsFreeIn);
-            pThis->cStreamsFreeIn--;
-        }
-        else /* Out */
-        {
-            Assert(pThis->cStreamsFreeOut);
-            pThis->cStreamsFreeOut--;
-        }
-
-        /* Always return the guest-side part to the device emulation. */
-        *ppStream = pGstStrm;
-    }
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-#if 1
-static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,       VERR_INVALID_POINTER);
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    if (RT_FAILURE(rc))
-        return rc;
-
-    rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg);
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-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)
-{
-    AssertPtrReturn(pInterface, false);
-
-    if (!pStream)
-        return PDMAUDIOSTRMSTS_FLAG_NONE;
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    int rc2 = RTCritSectEnter(&pThis->CritSect);
-    AssertRC(rc2);
-
-    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
-    PDMAUDIOSTRMSTS strmSts    = pHstStream->fStatus;
-
-    LogFlowFunc(("%s: strmSts=0x%x\n", pHstStream->szName, strmSts));
-    rc2 = RTCritSectLeave(&pThis->CritSect);
-    AssertRC(rc2);
-
-    return strmSts;
-}
-
-static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-    AssertPtrReturn(pVol,       VERR_INVALID_POINTER);
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));
-
-    AudioMixBufSetVolume(&pStream->MixBuf, pVol);
-
-    return VINF_SUCCESS;
-}
-#endif
-
-static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
-{
-    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
-
-    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    AssertRC(rc);
-
-    PDMAUDIODIR enmDir = pStream->enmDir;
-
-    LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
-    if (pStream->cRefs > 1)
-        rc = VERR_WRONG_ORDER;
-
-    if (RT_SUCCESS(rc))
-    {
-        PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
-        PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
-
-        LogFlowFunc(("\tHost : %s\n", pHstStream ? pHstStream->szName : "<None>"));
-        LogFlowFunc(("\tGuest: %s\n", pGstStream ? pGstStream->szName : "<None>"));
-
-        /* Should prevent double frees. */
-        Assert(pHstStream != pGstStream);
-
-        if (pHstStream)
-        {
-            pHstStream->pPair = NULL;
-            RTListNodeRemove(&pHstStream->Node);
-        }
-
-        if (pGstStream)
-        {
-            pGstStream->pPair = NULL;
-            RTListNodeRemove(&pGstStream->Node);
-        }
-
-        if (pHstStream)
-        {
-            rc = drvAudioStreamDestroyInternal(pThis, pHstStream);
-            AssertRC(rc);
-
-            pHstStream = NULL;
-        }
-
-        if (pGstStream)
-        {
-            rc = drvAudioStreamDestroyInternal(pThis, pGstStream);
-            AssertRC(rc);
-
-            pGstStream = NULL;
-        }
-    }
-
-    if (RT_SUCCESS(rc))
-    {
-        if (enmDir == PDMAUDIODIR_IN)
-        {
-            pThis->cStreamsFreeIn++;
-        }
-        else /* Out */
-        {
-            pThis->cStreamsFreeOut++;
-        }
-    }
-
-    int rc2 = RTCritSectLeave(&pThis->CritSect);
-    if (RT_SUCCESS(rc))
-        rc = rc2;
-
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-static int drvAudioStreamDestroyInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
-{
-    AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
-    AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);
-
-    AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
-              ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));
-
-    int rc = VINF_SUCCESS;
-
-    LogFlowFunc(("%s: fStatus=0x%x\n", pHstStream->szName, pHstStream->fStatus));
-
-    if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
-    {
-        if (pThis->pHostDrvAudio)
-            rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);
-        if (RT_SUCCESS(rc))
-            pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
-    }
-
-    LogFlowFunc(("%s: Returning %Rrc\n", pHstStream->szName, rc));
-    return rc;
-}
-
-static int drvAudioStreamDestroyInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
-
-    if (pStream->cRefs > 1)
-        return VERR_WRONG_ORDER;
-
-    int rc = VINF_SUCCESS;
-
-    if (pStream->enmCtx == PDMAUDIOSTREAMCTX_GUEST)
-    {
-        if (pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
-        {
-            rc = drvAudioStreamControlInternal(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
-            if (RT_SUCCESS(rc))
-                pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
-        }
-    }
-    else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)
-    {
-        rc = drvAudioStreamDestroyInternalBackend(pThis, pStream);
-    }
-    else
-        AssertFailedReturn(VERR_NOT_IMPLEMENTED);
-
-    if (RT_SUCCESS(rc))
-    {
-        /* Destroy mixing buffer. */
-        AudioMixBufDestroy(&pStream->MixBuf);
-
-        if (pStream)
-        {
-            RTMemFree(pStream);
-            pStream = NULL;
-        }
-    }
-
-    LogFlowFunc(("Returning %Rrc\n", rc));
-    return rc;
-}
-
-/********************************************************************/
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
-    LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID));
-
-    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
-    PDRVAUDIO  pThis   = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
-
-    return NULL;
-}
-
-/**
- * Power Off notification.
- *
- * @param   pDrvIns     The driver instance data.
- */
-static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
-{
-    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-
-    LogFlowFuncEnter();
-
-    /* Just destroy the host stream on the backend side.
-     * The rest will either be destructed by the device emulation or
-     * in drvAudioDestruct(). */
-    PPDMAUDIOSTREAM pStream;
-    RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)
-        drvAudioStreamDestroyInternalBackend(pThis, pStream);
-
-    /*
-     * Last call for the driver below us.
-     * Let it know that we reached end of life.
-     */
-    if (pThis->pHostDrvAudio->pfnShutdown)
-        pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
-
-    pThis->pHostDrvAudio = NULL;
-
-    LogFlowFuncLeave();
-}
-
-/**
- * Constructs an audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
-{
-    LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags));
-
-    PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
 
     /*
@@ -2095,4 +1619,5 @@
     pThis->IAudioConnector.pfnStreamSetVolume   = drvAudioStreamSetVolume;
     pThis->IAudioConnector.pfnStreamPlay        = drvAudioStreamPlay;
+    pThis->IAudioConnector.pfnStreamCapture     = drvAudioStreamCapture;
 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     pThis->IAudioConnector.pfnRegisterCallbacks = drvAudioRegisterCallbacks;
@@ -2145,4 +1670,11 @@
     int rc2 = RTCritSectEnter(&pThis->CritSect);
     AssertRC(rc2);
+
+    PPDMAUDIOSTREAM pStream, pStreamNext;
+    RTListForEachSafe(&pThis->lstHstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node)
+        drvAudioStreamDestroyInternal(pThis, pStream);
+
+    RTListForEachSafe(&pThis->lstGstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node)
+        drvAudioStreamDestroyInternal(pThis, pStream);
 
     /*
Index: /trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp	(revision 61523)
@@ -94,4 +94,6 @@
     void               *pvBuf;
     size_t              cbBuf;
+    /** Minimum samples required for ALSA to play data. */
+    uint32_t            cSamplesMin;
 } ALSAAUDIOSTREAMOUT, *PALSAAUDIOSTREAMOUT;
 
@@ -171,10 +173,15 @@
 typedef struct ALSAAUDIOSTREAMCFG
 {
-    unsigned int freq;
-    snd_pcm_format_t fmt;
-    int nchannels;
-    unsigned long buffer_size;
-    unsigned long period_size;
-    snd_pcm_uframes_t samples;
+    unsigned int        freq;
+    /** PCM sound format. */
+    snd_pcm_format_t    fmt;
+    /** PCM data access type. */
+    snd_pcm_access_t    access;
+    /** Whether resampling should be performed by alsalib or not. */
+    int                 resample;
+    int                 nchannels;
+    unsigned long       buffer_size;
+    unsigned long       period_size;
+    snd_pcm_uframes_t   samples;
 } ALSAAUDIOSTREAMCFG, *PALSAAUDIOSTREAMCFG;
 
@@ -348,4 +355,13 @@
         }
 
+        err = snd_pcm_sw_params_set_avail_min(phPCM, pSWParms, 512);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Failed to set available minimum to %ld: %s\n",
+                    threshold, snd_strerror(err)));
+            rc = VERR_ACCESS_DENIED;
+            break;
+        }
+
         err = snd_pcm_sw_params(phPCM, pSWParms);
         if (err < 0)
@@ -385,4 +401,195 @@
     return rc;
 }
+
+#if 0 /* After Beta. */
+static int alsaSetHWParams(snd_pcm_t *phPCM, PALSAAUDIOSTREAMCFG pCfg)
+{
+    int rc;
+    snd_pcm_hw_params_t *pParams = NULL;
+
+    do
+    {
+        snd_pcm_hw_params_alloca(&pParams);
+        if (!pParams)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+
+        unsigned int rrate;
+        snd_pcm_uframes_t size;
+        int dir;
+
+        /* choose all parameters */
+        int err = snd_pcm_hw_params_any(phPCM, pParams);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* set hardware resampling */
+        err = snd_pcm_hw_params_set_rate_resample(phPCM, pParams, pCfg->resample);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Resampling setup failed for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* set the interleaved read/write format */
+        err = snd_pcm_hw_params_set_access(phPCM, pParams, pCfg->access);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Access type not available for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* set the sample format */
+        err = snd_pcm_hw_params_set_format(phPCM, pParams, pCfg->fmt);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Sample format not available for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* set the count of channels */
+        err = snd_pcm_hw_params_set_channels(phPCM, pParams, pCfg->nchannels);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Channels count (%d) not available for playbacks: %s\n", pCfg->nchannels, snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* set the stream rate */
+        rrate = pCfg->freq;
+        err = snd_pcm_hw_params_set_rate_near(phPCM, pParams, &rrate, 0);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Rate %uHz not available for playback: %s\n", pCfg->freq, snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        if (rrate != pCfg->freq)
+        {
+            LogRel(("ALSA: Rate doesn't match (requested %iHz, get %uHz)\n", pCfg->freq, err));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* set the buffer time */
+        err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pParams, &pCfg->buffer_time, &dir);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        err = snd_pcm_hw_params_get_buffer_size(pParams, &size);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to get buffer size for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        buffer_size = size;
+        /* set the period time */
+        err = snd_pcm_hw_params_set_period_time_near(phPCM, pParams, &period_time, &dir);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        err = snd_pcm_hw_params_get_period_size(pParams, &size, &dir);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to get period size for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        period_size = size;
+        /* write the parameters to device */
+        err = snd_pcm_hw_params(phPCM, pParams);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to set hw params for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        rc = VINF_SUCCESS;
+
+    } while (0);
+
+    if (pParams)
+    {
+        snd_pcm_hw_params_free(pParams);
+        pParams = NULL;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+static int alsaSetSWParams(snd_pcm_t *phPCM, PALSAAUDIOCFG pCfg)
+{
+    int rc;
+    snd_pcm_sw_params_t *pParams = NULL;
+
+    do
+    {
+        snd_pcm_sw_params_alloca(&pParams);
+        if (!pParams)
+        {
+            rc = VERR_NO_MEMORY;
+            break;
+        }
+        /* get the current swparams */
+        int err = snd_pcm_sw_params_current(phPCM, pParams);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to determine current swparams for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* start the transfer when the buffer is almost full: */
+        /* (buffer_size / avail_min) * avail_min */
+        err = snd_pcm_sw_params_set_start_threshold(phPCM, pParams, (buffer_size / period_size) * period_size);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to set start threshold mode for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* allow the transfer when at least period_size samples can be processed */
+        /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
+        err = snd_pcm_sw_params_set_avail_min(phPCM, pParams, period_size);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to set avail min for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+        /* write the parameters to the playback device */
+        err = snd_pcm_sw_params(phPCM, pParams);
+        if (err < 0)
+        {
+            LogRel(("ALSA: Unable to set sw params for playback: %s\n", snd_strerror(err)));
+            rc = VERR_AUDIO_BACKEND_INIT_FAILED;
+            break;
+        }
+
+        rc = VINF_SUCCESS;
+
+    } while (0);
+
+    if (pParams)
+    {
+        snd_pcm_sw_params_free(pParams);
+        pParams = NULL;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+}
+#endif
 
 static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREAMCFG pCfgObt, snd_pcm_t **pphPCM)
@@ -614,4 +821,6 @@
         }
 
+        LogFunc(("Buffer sample size is: %RU32\n", obt_buffer_size));
+
         snd_pcm_uframes_t obt_period_size;
         int dir = 0;
@@ -983,5 +1192,5 @@
                         case 0:
                         {
-                            LogFunc(("Failed to write %RI32 frames\n", cRead));
+                            LogFunc(("Failed to write %RU32 samples\n", cRead));
                             rc = VERR_ACCESS_DENIED;
                             break;
@@ -1149,5 +1358,5 @@
 
         if (pcSamples)
-            *pcSamples = obt.samples;
+            *pcSamples = obt.samples * 4;
     }
     while (0);
@@ -1445,9 +1654,9 @@
         snd_pcm_sframes_t cAvail;
         int rc2 = alsaStreamGetAvail(pStreamOut->phPCM, &cAvail);
-        if (   RT_SUCCESS(rc2)
-            && cAvail >= 1024) /** @todo !!! HACK ALERT !!! Use bufsize. */
+        if (RT_SUCCESS(rc2))
         {
             LogFlowFunc(("cAvail=%ld\n", cAvail));
-            strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
+            if (cAvail >= pStreamOut->cSamplesMin)
+                strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
         }
     }
Index: /trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61523)
@@ -1417,4 +1417,6 @@
                              | PDMAUDIOSTRMSTS_FLAG_ENABLED;
 
+    pa_threaded_mainloop_lock(pThis->pMainLoop);
+
     pa_context_state_t ctxState = pa_context_get_state(pThis->pContext);
 
@@ -1422,19 +1424,25 @@
         && pa_stream_get_state(pStrm->pPAStream) == PA_STREAM_READY)
     {
+        size_t cbSize;
+
         if (pStream->enmDir == PDMAUDIODIR_IN)
         {
-
+            cbSize = pa_stream_readable_size(pStrm->pPAStream);
+
+            if (cbSize)
+                strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_READABLE;
         }
         else
         {
-            size_t cbSize = pa_stream_writable_size(pStrm->pPAStream);
-            LogFlowFunc(("cbSize=%zu\n", cbSize));
+            cbSize = pa_stream_writable_size(pStrm->pPAStream);
 
             if (cbSize >= pStrm->BufAttr.minreq)
-            {
                 strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
-            }
-        }
-    }
+        }
+
+        LogFlowFunc(("cbSize=%zu\n", cbSize));
+    }
+
+    pa_threaded_mainloop_unlock(pThis->pMainLoop);
 
     return strmSts;
Index: /trunk/src/VBox/Devices/Audio/alsa_mangling.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/alsa_mangling.h	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/alsa_mangling.h	(revision 61523)
@@ -56,4 +56,5 @@
 #define snd_pcm_sw_params_current               ALSA_MANGLER(snd_pcm_sw_params_current)
 #define snd_pcm_sw_params_set_start_threshold   ALSA_MANGLER(snd_pcm_sw_params_set_start_threshold)
+#define snd_pcm_sw_params_set_avail_min         ALSA_MANGLER(snd_pcm_sw_params_set_avail_min)
 
 #endif /* !AUDIO_ALSA_MANGLING_H */
Index: /trunk/src/VBox/Devices/Audio/alsa_stubs.c
===================================================================
--- /trunk/src/VBox/Devices/Audio/alsa_stubs.c	(revision 61522)
+++ /trunk/src/VBox/Devices/Audio/alsa_stubs.c	(revision 61523)
@@ -116,4 +116,7 @@
            (pcm, params))
 PROXY_STUB(snd_pcm_sw_params_set_start_threshold, int,
+           (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
+           (pcm, params, val))
+PROXY_STUB(snd_pcm_sw_params_set_avail_min, int,
            (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
            (pcm, params, val))
@@ -162,4 +165,5 @@
     ELEMENT(snd_pcm_sw_params_current),
     ELEMENT(snd_pcm_sw_params_set_start_threshold),
+    ELEMENT(snd_pcm_sw_params_set_avail_min)
 };
 #undef ELEMENT
