Index: trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp	(revision 61609)
@@ -191,24 +191,4 @@
 
 /**
- * Returns available number of samples for processing.
- *
- * @return  uint32_t                Number of samples available for reading.
- * @param   pMixBuf                 Mixing buffer to return value for.
- */
-uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf)
-{
-    AssertPtrReturn(pMixBuf, 0);
-
-    uint32_t cAvail;
-    if (pMixBuf->pParent) /* Is this a child buffer? */
-        cAvail = pMixBuf->cMixed;
-    else
-        cAvail = pMixBuf->cUsed;
-
-    Assert(cAvail <= pMixBuf->cSamples);
-    return cAvail;
-}
-
-/**
  * Clears the entire sample buffer.
  *
@@ -327,5 +307,5 @@
     AssertPtrReturn(pMixBuf, 0);
 
-    uint32_t cSamplesFree;
+    uint32_t cSamples, cSamplesFree;
     if (pMixBuf->pParent)
     {
@@ -334,14 +314,17 @@
          * already have been consumed by the parent.
          */
-        Assert(pMixBuf->cMixed <= pMixBuf->pParent->cSamples);
-        cSamplesFree = pMixBuf->pParent->cSamples - pMixBuf->cMixed;
+        cSamples = pMixBuf->pParent->cSamples;
+
+        Assert(pMixBuf->cMixed <= cSamples);
+        cSamplesFree = cSamples - pMixBuf->cMixed;
     }
     else /* As a parent. */
     {
-        Assert(pMixBuf->cSamples >= pMixBuf->cUsed);
+        cSamples     = pMixBuf->cSamples;
+        Assert(cSamples >= pMixBuf->cUsed);
         cSamplesFree = pMixBuf->cSamples - pMixBuf->cUsed;
     }
 
-    AUDMIXBUF_LOG(("%s: cSamplesFree=%RU32\n", pMixBuf->pszName, cSamplesFree));
+    AUDMIXBUF_LOG(("%s: %RU32 of %RU32\n", pMixBuf->pszName, cSamplesFree, cSamples));
     return cSamplesFree;
 }
@@ -920,20 +903,30 @@
 
 /**
- * Returns the number of audio samples mixed (processed) by
- * the parent mixing buffer.
- *
- * @return  uint32_t                Number of audio samples mixed (processed).
- * @param   pMixBuf                 Mixing buffer to return number from.
- */
-uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf)
+ * Returns number of available live samples.
+ *
+ * @return  uint32_t                Number of live samples available.
+ * @param   pMixBuf                 Mixing buffer to return value for.
+ */
+uint32_t AudioMixBufLive(PPDMAUDIOMIXBUF pMixBuf)
 {
     AssertPtrReturn(pMixBuf, 0);
 
-    AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
-                              ("Buffer is not linked to a parent buffer\n"),
-                              0);
-
-    AUDMIXBUF_LOG(("%s: cMixed=%RU32\n", pMixBuf->pszName, pMixBuf->cMixed));
-    return pMixBuf->cMixed;
+    uint32_t cSamples, cAvail;
+    if (pMixBuf->pParent) /* Is this a child buffer? */
+    {
+        /* Use the sample count from the parent, as
+         * pMixBuf->cMixed specifies the sample count
+         * in parent samples. */
+        cSamples = pMixBuf->pParent->cSamples;
+        cAvail   = pMixBuf->cMixed;
+    }
+    else
+    {
+        cSamples = pMixBuf->cSamples;
+        cAvail   = pMixBuf->cUsed;
+    }
+
+    Assert(cAvail <= cSamples);
+    return cAvail;
 }
 
@@ -944,8 +937,8 @@
  * @param   pDst                    Destination mixing buffer.
  * @param   pSrc                    Source mixing buffer.
- * @param   cSamples                Number of source audio samples to mix.
+ * @param   cSrcSamples             Number of source audio samples to mix.
  * @param   pcProcessed             Number of audio samples successfully mixed.
  */
-static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t cSamples, uint32_t *pcProcessed)
+static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t cSrcSamples, uint32_t *pcProcessed)
 {
     AssertPtrReturn(pDst,  VERR_INVALID_POINTER);
@@ -969,5 +962,5 @@
     Assert(pSrc->cUsed >= pDst->cMixed);
 
-    uint32_t cSrcAvail  = RT_MIN(cSamples, pSrc->cUsed - pDst->cMixed);
+    uint32_t cSrcAvail  = RT_MIN(cSrcSamples, pSrc->cUsed - pDst->cMixed);
     uint32_t offSrcRead = pSrc->offRead;
     uint32_t cDstMixed  = pSrc->cMixed;
@@ -985,5 +978,5 @@
     }
 
-    AUDMIXBUF_LOG(("cSamples=%RU32, cSrcAvail=%RU32 -> cDstAvail=%RU32\n", cSamples,  cSrcAvail, cDstAvail));
+    AUDMIXBUF_LOG(("cSrcSamples=%RU32, cSrcAvail=%RU32 -> cDstAvail=%RU32\n", cSrcSamples,  cSrcAvail, cDstAvail));
 
 #ifdef DEBUG
@@ -1094,5 +1087,6 @@
  * @return  IPRT status code.
  * @param   pMixBuf                 Mixing buffer to mix samples down to parent.
- * @param   cSamples                Number of audio samples to mix down.
+ * @param   cSamples                Number of audio samples of specified mixing buffer to to mix
+ *                                  to its attached parent mixing buffer (if any).
  * @param   pcProcessed             Number of audio samples successfully processed. Optional.
  */
Index: trunk/src/VBox/Devices/Audio/AudioMixBuffer.h
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixBuffer.h	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/AudioMixBuffer.h	(revision 61609)
@@ -51,5 +51,4 @@
 
 int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead, PPDMAUDIOSAMPLE *ppvSamples, uint32_t *pcSamplesRead);
-uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf);
 inline uint32_t AudioMixBufBytesToSamples(PPDMAUDIOMIXBUF pMixBuf);
 void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf);
@@ -61,5 +60,5 @@
 bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf);
 int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent);
-uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf);
+uint32_t AudioMixBufLive(PPDMAUDIOMIXBUF pMixBuf);
 int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
 uint32_t AudioMixBufUsed(PPDMAUDIOMIXBUF pMixBuf);
Index: trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61609)
@@ -55,4 +55,5 @@
 static void audioMixerSinkRemoveAllStreamsInternal(PAUDMIXSINK pSink);
 static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
+static void audioMixerSinkReset(PAUDMIXSINK pSink);
 static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink);
 
@@ -78,5 +79,4 @@
         {
             pSink->pParent  = pMixer;
-            pSink->cStreams = 0;
             pSink->enmDir   = enmDir;
             RTListInit(&pSink->lstStreams);
@@ -479,4 +479,8 @@
         pSink->fStatus &= ~AUDMIXSINK_STS_RUNNING;
 
+    /* Not running anymore? Reset. */
+    if (!(pSink->fStatus & AUDMIXSINK_STS_RUNNING))
+        audioMixerSinkReset(pSink);
+
     LogFlowFunc(("[%s]: enmCmd=%ld, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, enmSinkCmd, pSink->fStatus, rc));
     return rc;
@@ -528,4 +532,46 @@
     RTMemFree(pSink);
     pSink = NULL;
+}
+
+/**
+ * Returns the amount of bytes ready to be read from a sink since the last call
+ * to AudioMixerSinkUpdate().
+ *
+ * @returns Amount of bytes ready to be read from the sink.
+ * @param   pSink           Sink to return number of available samples for.
+ */
+uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink)
+{
+    AssertPtrReturn(pSink, 0);
+
+    AssertMsg(pSink->enmDir == AUDMIXSINKDIR_INPUT, ("Can't read from a non-input sink\n"));
+
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+# error "Implement me!"
+#else
+    LogFlowFunc(("[%s]: cbReadable=%RU32\n", pSink->pszName, pSink->In.cbReadable));
+    return pSink->In.cbReadable;
+#endif
+}
+
+/**
+ * Returns the amount of bytes ready to be written to a sink since the last call
+ * to AudioMixerSinkUpdate().
+ *
+ * @returns Amount of bytes ready to be written to the sink.
+ * @param   pSink           Sink to return number of available samples for.
+ */
+uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink)
+{
+    AssertPtrReturn(pSink, 0);
+
+    AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT, ("Can't write to a non-output sink\n"));
+
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+# error "Implement me!"
+#else
+    LogFlowFunc(("[%s]: cbWritable=%RU32\n", pSink->pszName, pSink->Out.cbWritable));
+    return pSink->Out.cbWritable;
+#endif
 }
 
@@ -721,4 +767,34 @@
 
 /**
+ * Resets the sink's state.
+ *
+ * @param   pSink       Sink to reset.
+ */
+static void audioMixerSinkReset(PAUDMIXSINK pSink)
+{
+    if (!pSink)
+        return;
+
+    LogFunc(("%s\n", pSink->pszName));
+
+    if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
+    {
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+        AudioMixBufReset(&pSink->MixBuf);
+#else
+        pSink->In.cbReadable = 0;
+#endif
+    }
+    else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
+    {
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+        AudioMixBufReset(&pSink->MixBuf);
+#else
+        pSink->Out.cbWritable = 0;
+#endif
+    }
+}
+
+/**
  * Removes all attached streams from a given sink.
  *
@@ -792,16 +868,4 @@
 }
 
-void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed)
-{
-    AssertPtrReturnVoid(pSink);
-
-    /* Note: cTimerTicks / cTicksElapsed = Hz elapsed. */
-
-    LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64 -> %zuHz\n",
-                 pSink->pszName, cTimerTicks, cTicksElapsed, cTimerTicks / cTicksElapsed));
-
-    audioMixerSinkUpdateInternal(pSink);
-}
-
 static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink)
 {
@@ -811,25 +875,32 @@
 
     Log3Func(("[%s]\n", pSink->pszName));
+
+    /* Update last updated timestamp. */
+    pSink->tsLastUpdatedNS = RTTimeNanoTS();
 
     PAUDMIXSTREAM pMixStream;
     RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     {
-        PPDMAUDIOSTREAM pStream = pMixStream->pStream;
+        PPDMAUDIOSTREAM pStream   = pMixStream->pStream;
         AssertPtr(pStream);
+
+        PPDMIAUDIOCONNECTOR pConn = pMixStream->pConn;
+        AssertPtr(pConn);
 
         uint32_t cPlayed   = 0;
         uint32_t cCaptured = 0;
 
-        int rc2 = pMixStream->pConn->pfnStreamIterate(pMixStream->pConn, pStream);
+        int rc2 = pConn->pfnStreamIterate(pConn, pStream);
         if (RT_SUCCESS(rc2))
         {
-            if (pStream->enmDir == PDMAUDIODIR_IN)
+            if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
             {
-                rc = pMixStream->pConn->pfnStreamCapture(pMixStream->pConn, pMixStream->pStream, &cCaptured);
+                rc = pConn->pfnStreamCapture(pConn, pMixStream->pStream, &cCaptured);
                 if (RT_FAILURE(rc2))
                 {
-                    LogFlowFunc(("%s: Failed capture stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
+                    LogFlowFunc(("%s: Failed capturing stream '%s', rc=%Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
                     if (RT_SUCCESS(rc))
                         rc = rc2;
+                    continue;
                 }
 
@@ -837,16 +908,46 @@
                     pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
             }
-            else if (pStream->enmDir == PDMAUDIODIR_OUT)
+            else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
             {
-                rc2 = pMixStream->pConn->pfnStreamPlay(pMixStream->pConn, pMixStream->pStream, &cPlayed);
+                rc2 = pConn->pfnStreamPlay(pConn, pMixStream->pStream, NULL /* cPlayed */);
                 if (RT_FAILURE(rc2))
                 {
-                    LogFlowFunc(("%s: Failed playing stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
+                    LogFlowFunc(("%s: Failed playing stream '%s', rc=%Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
                     if (RT_SUCCESS(rc))
                         rc = rc2;
+                    continue;
                 }
             }
             else
+            {
                 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
+                continue;
+            }
+
+            rc2 = pConn->pfnStreamIterate(pConn, pStream);
+            if (RT_FAILURE(rc2))
+            {
+                LogFlowFunc(("%s: Failed re-iterating stream '%s', rc=%Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
+                if (RT_SUCCESS(rc))
+                    rc = rc2;
+                continue;
+            }
+
+            if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
+            {
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+# error "Implement me!"
+#else
+                pSink->In.cbReadable = pConn->pfnStreamGetReadable(pConn, pMixStream->pStream);
+#endif
+            }
+            else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
+            {
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+# error "Implement me!"
+#else
+                pSink->Out.cbWritable = pConn->pfnStreamGetWritable(pConn, pMixStream->pStream);
+#endif
+            }
         }
 
@@ -862,4 +963,17 @@
 int AudioMixerSinkUpdate(PAUDMIXSINK pSink)
 {
+    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+
+    uint64_t tsElapsed = RTTimeNanoTS() - pSink->tsLastUpdatedNS;
+
+    /*
+     * Note: Hz elapsed     = cTicksElapsed / cTimerTicks
+     *       Bytes / second = Sample rate (Hz) * Audio channels * Bytes per sample
+     */
+//    uint32_t cSamples = (int)((pSink->PCMProps.cChannels * cTicksElapsed * pSink->PCMProps.uHz + cTimerTicks) / cTimerTicks / pSink->PCMProps.cChannels);
+
+//    LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64\n", pSink->pszName, cTimerTicks, cTicksElapsed));
+//    LogFlowFunc(("\t%zuHz elapsed, %RU32 samples (%RU32 bytes)\n", cTicksElapsed / cTimerTicks, cSamples, cSamples << 1));
+
     return audioMixerSinkUpdateInternal(pSink);
 }
Index: trunk/src/VBox/Devices/Audio/AudioMixer.h
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61609)
@@ -115,4 +115,36 @@
 
 /**
+ * Structure for keeping audio input sink specifics.
+ * Do not use directly. Instead, use AUDMIXSINK.
+ */
+typedef struct AUDMIXSINKIN
+{
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+    /** This sink's mixing buffer, acting as
+     * a parent buffer for all streams this sink owns. */
+    PDMAUDIOMIXBUF MixBuf;
+#else
+    /** Number of bytes available to read from the sink. */
+    uint32_t       cbReadable;
+#endif
+} AUDMIXSINKIN;
+
+/**
+ * Structure for keeping audio output sink specifics.
+ * Do not use directly. Instead, use AUDMIXSINK.
+ */
+typedef struct AUDMIXSINKOUT
+{
+#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
+    /** This sink's mixing buffer, acting as
+     * a parent buffer for all streams this sink owns. */
+    PDMAUDIOMIXBUF MixBuf;
+#else
+    /** Number of bytes available to write to the sink. */
+    uint32_t       cbWritable;
+#endif
+} AUDMIXSINKOUT;
+
+/**
  * Structure for maintaining an audio mixer sink.
  */
@@ -127,4 +159,10 @@
      *  if this sink handles input or output. */
     AUDMIXSINKDIR           enmDir;
+    /** Union for input/output specifics. */
+    union
+    {
+        AUDMIXSINKIN        In;
+        AUDMIXSINKOUT       Out;
+    };
     /** Sink status of type AUDMIXSINK_STS_XXX. */
     AUDMIXSINKSTS           fStatus;
@@ -138,12 +176,9 @@
     /** @todo Use something faster -- vector maybe? */
     RTLISTANCHOR            lstStreams;
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-    /** This sink's mixing buffer, acting as
-     *  a parent buffer for all streams this sink owns. */
-    PDMAUDIOMIXBUF          MixBuf;
-#endif
     /** The volume of this sink. The volume always will
      *  be combined with the mixer's master volume. */
     PDMAUDIOVOLUME          Volume;
+    /** Timestamp (in ns) since last update. */
+    uint64_t                tsLastUpdatedNS;
 } AUDMIXSINK, *PAUDMIXSINK;
 
@@ -178,4 +213,6 @@
 int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmCmd);
 void AudioMixerSinkDestroy(PAUDMIXSINK pSink);
+uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink);
+uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink);
 AUDMIXSINKDIR AudioMixerSinkGetDir(PAUDMIXSINK pSink);
 PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex);
@@ -187,5 +224,5 @@
 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMPCMPROPS pPCMProps);
 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
-void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed);
+void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed, uint32_t *pcbToProcess);
 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 61608)
+++ trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61609)
@@ -424,5 +424,5 @@
 static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
 #endif
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream);
+static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
 
 static void ichac97WarmReset(PAC97STATE pThis)
@@ -530,8 +530,9 @@
 static bool ichac97StreamIsActive(PAC97STATE pThis, PAC97STREAM pStream)
 {
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    bool fActive = AudioMixerSinkGetStatus(ichac97IndexToSink(pThis, pStream->u8Strm));
+    AssertPtrReturn(pThis,   false);
+    AssertPtrReturn(pStream, false);
+
+    PAUDMIXSINK pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
+    bool fActive = RT_BOOL(AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);
 
     LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8Strm, fActive));
@@ -1321,6 +1322,4 @@
 static void ichac97TimerMaybeStart(PAC97STATE pThis)
 {
-    LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
-
     if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
         return;
@@ -1329,4 +1328,6 @@
         return;
 
+    LogFlowFunc(("Starting timer\n"));
+
     /* Set timer flag. */
     ASMAtomicXchgBool(&pThis->fTimerActive, true);
@@ -1341,6 +1342,4 @@
 static void ichac97TimerMaybeStop(PAC97STATE pThis)
 {
-    LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
-
     if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
         return;
@@ -1348,4 +1347,6 @@
     if (!pThis->pTimer)
         return;
+
+    LogFlowFunc(("Stopping timer\n"));
 
     /* Set timer flag. */
@@ -1374,18 +1375,38 @@
     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;
+    uint32_t cbToProcess;
+
+    int rc = AudioMixerSinkUpdate(pThis->pSinkLineIn);
+    if (RT_SUCCESS(rc))
+    {
+        cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkLineIn);
+        if (cbToProcess)
+        {
+            rc = ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbToProcess, NULL /* pcbProcessed */);
+            fKickTimer |= RT_SUCCESS(rc);
+        }
+    }
+
+    rc = AudioMixerSinkUpdate(pThis->pSinkMicIn);
+    if (RT_SUCCESS(rc))
+    {
+        cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkMicIn);
+        if (cbToProcess)
+        {
+            rc = ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbToProcess, NULL /* pcbProcessed */);
+            fKickTimer |= RT_SUCCESS(rc);
+        }
+    }
+
+    rc = AudioMixerSinkUpdate(pThis->pSinkOutput);
+    if (RT_SUCCESS(rc))
+    {
+        cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkOutput);
+        if (cbToProcess)
+        {
+            rc = ichac97TransferAudio(pThis, &pThis->StreamOut, cbToProcess, NULL /* pcbProcessed */);
+            fKickTimer |= RT_SUCCESS(rc);
+        }
+    }
 
     if (   ASMAtomicReadBool(&pThis->fTimerActive)
@@ -1403,6 +1424,10 @@
 #endif /* !VBOX_WITH_AUDIO_CALLBACKS */
 
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream)
-{
+static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+{
+    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    /* pcbProcessed is optional. */
+
     Log3Func(("SD=%RU8\n", pStream->u8Strm));
 
@@ -1416,5 +1441,5 @@
             {
                 case PO_INDEX:
-                    ichac97WriteBUP(pThis, (uint32_t)(pRegs->picb << 1));
+                    ichac97WriteBUP(pThis, cbToProcess);
                     break;
 
@@ -1424,4 +1449,6 @@
         }
 
+        if (pcbProcessed)
+            *pcbProcessed = 0;
         return VINF_SUCCESS;
     }
@@ -1429,10 +1456,16 @@
     /* BCIS flag still set? Skip iteration. */
     if (pRegs->sr & SR_BCIS)
+    {
+        if (pcbProcessed)
+            *pcbProcessed = 0;
         return VINF_SUCCESS;
+    }
 
     int rc = VINF_SUCCESS;
-    uint32_t cbWrittenTotal = 0;
-
-    do
+
+    uint32_t cbLeft  = cbToProcess;
+    uint32_t cbTotal = 0;
+
+    while (cbLeft)
     {
         if (!pRegs->bd_valid)
@@ -1474,20 +1507,7 @@
                     && cbTransferred)
                 {
-                    cbWrittenTotal += cbTransferred;
-                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
-                    pRegs->picb    -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
-                }
-                break;
-            }
-
-            case PI_INDEX:
-            case MC_INDEX:
-            {
-                cbToTransfer = (uint32_t)(pRegs->picb << 1);
-
-                rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred);
-                if (   RT_SUCCESS(rc)
-                    && cbTransferred)
-                {
+                    cbTotal     += cbTransferred;
+                    Assert(cbLeft >= cbTransferred);
+                    cbLeft      -= cbTransferred;
                     Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
                     pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
@@ -1496,4 +1516,22 @@
             }
 
+            case PI_INDEX:
+            case MC_INDEX:
+            {
+                cbToTransfer = (uint32_t)(pRegs->picb << 1);
+
+                rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred);
+                if (   RT_SUCCESS(rc)
+                    && cbTransferred)
+                {
+                    cbTotal     += cbTransferred;
+                    Assert(cbLeft >= cbTransferred);
+                    cbLeft      -= cbTransferred;
+                    Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
+                    pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
+                }
+                break;
+            }
+
             default:
                 AssertMsgFailed(("Stream #%RU8 not supported\n", pStream->u8Strm));
@@ -1502,6 +1540,5 @@
         }
 
-        Log3Func(("PICB=%RU16 (%#x), cbTransferred=%RU32 (%zu samples), cbWrittenTotal=%RU32\n",
-                  pRegs->picb, pRegs->picb, cbTransferred, (cbTransferred >> 1), cbWrittenTotal));
+        LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8Strm, cbTotal, cbToProcess, rc));
 
         if (!pRegs->picb)
@@ -1536,6 +1573,11 @@
         if (rc == VINF_EOF) /* All data processed? */
             break;
-
-    } while (RT_SUCCESS(rc));
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcbProcessed)
+            *pcbProcessed = cbTotal;
+    }
 
     LogFlowFuncLeaveRC(rc);
Index: trunk/src/VBox/Devices/Audio/DevIchHda.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 61609)
@@ -942,5 +942,5 @@
 static int hdaStreamStop(PHDASTREAM pStream);
 static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout);
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream);
+static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
 #endif
 
@@ -966,5 +966,4 @@
 static void hdaTimerMaybeStart(PHDASTATE pThis);
 static void hdaTimerMaybeStop(PHDASTATE pThis);
-static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
 #endif
 
@@ -1765,37 +1764,45 @@
 static bool hdaStreamIsActive(PHDASTATE pThis, PHDASTREAM pStream)
 {
+    AssertPtrReturn(pThis,   false);
+    AssertPtrReturn(pStream, false);
+
+    bool fActive = pStream->State.fActive;
+
+    LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8SD, fActive));
+    return fActive;
+}
+
+static int hdaStreamSetActive(PHDASTATE pThis, PHDASTREAM pStream, bool fActive)
+{
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
 
-    bool fActive = pStream->State.fActive;
-
-    if (!fActive)
-    {
-        AssertPtr(pStream->pMixSink);
+    LogFlowFunc(("[SD%RU8]: fActive=%RTbool, pMixSink=%p\n", pStream->u8SD, fActive, pStream->pMixSink));
+
+    if (pStream->State.fActive == fActive) /* No change required? */
+    {
+        LogFlowFunc(("[SD%RU8]: No change\n", pStream->u8SD));
+        return VINF_SUCCESS;
+    }
+
+    int rc;
+
+    if (pStream->pMixSink) /* Stream attached to a sink? */
+    {
+        AUDMIXSINKCMD enmCmd = fActive
+                             ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
+
+        /* First, enable or disable the stream and the stream's sink, if any. */
         if (pStream->pMixSink->pMixSink)
-            fActive = AudioMixerSinkGetStatus(pStream->pMixSink->pMixSink) & AUDMIXSINK_STS_DIRTY;
-    }
-
-    LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8SD, fActive));
-    return fActive;
-}
-
-static int hdaStreamSetActive(PHDASTATE pThis, PHDASTREAM pStream, bool fActive)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
-    if (!pStream->pMixSink) /* No mixer sink assigned? Bail out early. */
-    {
-        LogFlowFunc(("u8Strm=%RU8 has no mixer sink assigned\n", pStream->u8SD));
-        return VINF_SUCCESS;
-    }
-
-    AUDMIXSINKCMD enmCmd = fActive
-                         ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
-
-    /* First, enable or disable the stream and the stream's sink, if any. */
-    if (pStream->pMixSink->pMixSink)
-        AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
+            rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
+    }
+    else
+        rc = VINF_SUCCESS;
+
+    if (RT_FAILURE(rc))
+    {
+        LogFlowFunc(("Failed with rc=%Rrc\n", rc));
+        return rc;
+    }
 
     pStream->State.fActive = fActive;
@@ -3482,9 +3489,9 @@
  *       but "reports bytes" when all conditions are met (FIFOW).
  */
-static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    /* pcbProcessed is optional. */
+    /* pcbRead is optional. */
 
     int rc;
@@ -3495,5 +3502,5 @@
         PHDABDLE pBDLE = &pStream->State.BDLE;
 
-        if (!cbToProcess)
+        if (!cbToRead)
         {
             rc = VINF_EOF;
@@ -3503,5 +3510,5 @@
         AssertPtr(pStream->pMixSink);
         AssertPtr(pStream->pMixSink->pMixSink);
-        rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbToProcess, &cbRead);
+        rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbToRead, &cbRead);
         if (RT_FAILURE(rc))
             break;
@@ -3514,5 +3521,5 @@
 
         /* Sanity checks. */
-        Assert(cbRead <= cbToProcess);
+        Assert(cbRead <= cbToRead);
         Assert(cbRead <= sizeof(pBDLE->State.au8FIFO));
         Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
@@ -3548,6 +3555,6 @@
     if (RT_SUCCESS(rc))
     {
-        if (pcbProcessed)
-            *pcbProcessed = cbRead;
+        if (pcbRead)
+            *pcbRead = cbRead;
     }
 
@@ -3558,5 +3565,5 @@
 }
 
-static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
 {
     AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
@@ -3573,5 +3580,5 @@
      */
     int rc;
-    if (!cbToProcess)
+    if (!cbToWrite)
     {
         rc = VINF_EOF;
@@ -3580,6 +3587,6 @@
     {
         void    *pvBuf = pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW;
-        Assert(cbToProcess >= pBDLE->State.cbBelowFIFOW);
-        uint32_t cbBuf = cbToProcess - pBDLE->State.cbBelowFIFOW;
+        Assert(cbToWrite >= pBDLE->State.cbBelowFIFOW);
+        uint32_t cbBuf = cbToWrite - pBDLE->State.cbBelowFIFOW;
 
         /*
@@ -3674,7 +3681,7 @@
             /* Always report all data as being written;
              * backends who were not able to catch up have to deal with it themselves. */
-            cbWritten = cbToProcess;
-
-            hdaBDLEUpdate(pBDLE, cbToProcess, cbWritten);
+            cbWritten = cbToWrite;
+
+            hdaBDLEUpdate(pBDLE, cbToWrite, cbWritten);
         }
         else
@@ -3695,6 +3702,6 @@
     if (RT_SUCCESS(rc))
     {
-        if (pcbProcessed)
-            *pcbProcessed = cbWritten;
+        if (pcbWritten)
+            *pcbWritten = cbWritten;
     }
 
@@ -3938,8 +3945,11 @@
             }
 
-            AssertPtr(pMixStream);
-
-            AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
-            AudioMixerStreamDestroy(pMixStream);
+            if (pMixStream)
+            {
+                AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
+                AudioMixerStreamDestroy(pMixStream);
+
+                pMixStream = NULL;
+            }
         }
 
@@ -4051,6 +4061,4 @@
 static void hdaTimerMaybeStart(PHDASTATE pThis)
 {
-    LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
-
     if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
         return;
@@ -4061,4 +4069,6 @@
     LogFlowFuncEnter();
 
+    LogFlowFunc(("Starting timer\n"));
+
     /* Set timer flag. */
     ASMAtomicXchgBool(&pThis->fTimerActive, true);
@@ -4073,6 +4083,4 @@
 static void hdaTimerMaybeStop(PHDASTATE pThis)
 {
-    LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
-
     if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
         return;
@@ -4081,5 +4089,5 @@
         return;
 
-    LogFlowFuncEnter();
+    LogFlowFunc(("Stopping timer\n"));
 
     /* Set timer flag. */
@@ -4095,7 +4103,4 @@
     STAM_PROFILE_START(&pThis->StatTimer, a);
 
-    uint32_t cbInMax  = 0;
-    uint32_t cbOutMin = UINT32_MAX;
-
     uint64_t cTicksNow     = TMTimerGet(pTimer);
     uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
@@ -4119,32 +4124,43 @@
 #endif
 
-    AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink, pThis->cTimerTicks, cTicksElapsed);
-    hdaTransfer(pThis, pStreamLineIn);
-
-    if (AudioMixerSinkGetStatus(pThis->SinkLineIn.pMixSink) & AUDMIXSINK_STS_DIRTY)
-        fKickTimer = true;
+    uint32_t cbToProcess;
+    int rc = AudioMixerSinkUpdate(pThis->SinkLineIn.pMixSink);
+    if (RT_SUCCESS(rc))
+    {
+        cbToProcess = AudioMixerSinkGetReadable(pThis->SinkLineIn.pMixSink);
+        if (cbToProcess)
+        {
+            rc = hdaTransfer(pThis, pStreamLineIn, cbToProcess, NULL /* pcbProcessed */);
+            fKickTimer = RT_SUCCESS(rc);
+        }
+    }
 
 #ifdef VBOX_WITH_HDA_MIC_IN
-    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;
+    rc = AudioMixerSinkUpdate(pThis->SinkMicIn.pMixSink);
+    if (RT_SUCCESS(rc))
+    {
+        cbToProcess = AudioMixerSinkGetReadable(pThis->SinkMicIn.pMixSink);
+        if (cbToProcess)
+        {
+            rc = hdaTransfer(pThis, pStreamMicIn, cbToProcess, NULL /* pcbProcessed */);
+            fKickTimer = RT_SUCCESS(rc);
+        }
+    }
+#endif
 
 #ifdef VBOX_WITH_HDA_51_SURROUND
-    AudioMixerSinkTimerUpdate(pThis->SinkCenterLFE.pMixSink, pThis->cTimerTicks, cTicksElapsed);
-    AudioMixerSinkTimerUpdate(pThis->SinkRear.pMixSink,      pThis->cTimerTicks, cTicksElapsed);
-
+    rc = AudioMixerSinkUpdate(pThis->SinkCenterLFE.pMixSink);
+    if (RT_SUCCESS(rc))
+    {
+
+    }
+
+    rc = AudioMixerSinkUpdate(pThis->SinkRear.pMixSink);
+    if (RT_SUCCESS(rc))
+    {
+
+    }
     /** @todo Check for stream interleaving and only call hdaTransfer() if required! */
-#endif
-
-#ifdef VBOX_WITH_HDA_51_SURROUND
+
     /*
      * Only call hdaTransfer if CenterLFE and/or Rear are on different SDs,
@@ -4153,4 +4169,14 @@
      */
 #endif
+    rc = AudioMixerSinkUpdate(pThis->SinkFront.pMixSink);
+    if (RT_SUCCESS(rc))
+    {
+        cbToProcess = AudioMixerSinkGetWritable(pThis->SinkFront.pMixSink);
+        if (cbToProcess)
+        {
+            rc = hdaTransfer(pThis, pStreamFront, cbToProcess, NULL /* pcbProcessed */);
+            fKickTimer = RT_SUCCESS(rc);
+        }
+    }
 
     if (   ASMAtomicReadBool(&pThis->fTimerActive)
@@ -4218,12 +4244,16 @@
 #endif /* VBOX_WITH_AUDIO_CALLBACKS */
 
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream)
+static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
 {
     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(("HDA in reset mode, skipping\n"));
+
+        if (pcbProcessed)
+            *pcbProcessed = 0;
         return VINF_SUCCESS;
     }
@@ -4250,4 +4280,7 @@
     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)))
@@ -4264,4 +4297,6 @@
         AssertRC(rc);
 
+        if (pcbProcessed)
+            *pcbProcessed = 0;
         return VINF_SUCCESS;
     }
@@ -4281,5 +4316,5 @@
 
 #ifdef DEBUG_andy
-# define DEBUG_SIMPLE
+//# define DEBUG_SIMPLE
 #endif
 
@@ -4289,12 +4324,13 @@
 #endif
 
-    uint32_t cbToProcess      = 0;
-    uint32_t cbProcessed      = 0;
-    uint32_t cbProcessedTotal = 0;
+    uint32_t cbLeft           = cbToProcess;
+    uint32_t cbTotal          = 0;
+    uint32_t cbChunk          = 0;
+    uint32_t cbChunkProcessed = 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);
 
-    do
+    while (cbLeft)
     {
         /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
@@ -4306,32 +4342,31 @@
         }
 
-        cbToProcess = hdaStreamGetTransferSize(pThis, pStream, _4K /** @todo Fix this */);
-        cbProcessed = 0;
+        cbChunk          = hdaStreamGetTransferSize(pThis, pStream, cbLeft);
+        cbChunkProcessed = 0;
 
         if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
-            rc = hdaReadAudio(pThis, pStream, cbToProcess, &cbProcessed);
+            rc = hdaReadAudio(pThis, pStream, cbChunk, &cbChunkProcessed);
         else
         {
 #ifndef DEBUG_SIMPLE
-            rc = hdaWriteAudio(pThis, pStream, cbToProcess, &cbProcessed);
+            rc = hdaWriteAudio(pThis, pStream, cbChunk, &cbChunkProcessed);
 #else
-            uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbToProcess);
-
             void    *pvBuf = u8FIFO + u8FIFOff;
-            int32_t cbBuf = cbToWrite;
+            int32_t cbBuf  = cbChunk;
 
             PHDABDLE pBDLE = &pStream->State.BDLE;
 
-            rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
-                               pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
-                               pvBuf, cbBuf);
-
-            hdaBDLEUpdate(pBDLE, cbToWrite, cbToWrite);
-
-            u8FIFOff += cbToWrite;
+            if (cbBuf)
+                rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
+                                       pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
+                                       pvBuf, cbBuf);
+
+            cbChunkProcessed = cbChunk;
+
+            hdaBDLEUpdate(pBDLE, cbChunkProcessed, cbChunkProcessed);
+
+            u8FIFOff += cbChunkProcessed;
             Assert((u8FIFOff & 1) == 0);
             Assert(u8FIFOff <= sizeof(u8FIFO));
-
-            cbProcessed = cbToWrite;
 #endif
         }
@@ -4340,7 +4375,9 @@
             break;
 
-        hdaStreamTransferUpdate(pThis, pStream, cbProcessed);
-
-        cbProcessedTotal += cbProcessed;
+        hdaStreamTransferUpdate(pThis, pStream, cbChunkProcessed);
+
+        Assert(cbLeft >= cbChunkProcessed);
+        cbLeft  -= cbChunkProcessed;
+        cbTotal += cbChunkProcessed;
 
         if (rc == VINF_EOF)
@@ -4349,11 +4386,10 @@
         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);
 
-    LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8SD, cbProcessedTotal, cbToProcess, rc));
+    LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8SD, cbTotal, cbToProcess, rc));
 
 #ifdef DEBUG_SIMPLE
@@ -4386,4 +4422,10 @@
 
         hdaProcessInterrupt(pThis);
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        if (pcbProcessed)
+            *pcbProcessed = cbTotal;
     }
 
@@ -5051,7 +5093,12 @@
             if (pStream)
             {
+                /* Deactive first. */
+                int rc2 = hdaStreamSetActive(pThis, pStream, false);
+                AssertRC(rc2);
+
                 bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-                LogFlowFunc(("[SD%RU8]: fActive=%RTbool\n", i, fActive));
-                int rc2 = hdaStreamSetActive(pThis, pStream, fActive);
+
+                /* Activate, if needed. */
+                rc2 = hdaStreamSetActive(pThis, pStream, fActive);
                 AssertRC(rc2);
             }
@@ -5699,5 +5746,5 @@
 #ifndef VBOX_WITH_AUDIO_CALLBACKS
     uint16_t uTimerHz;
-    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 100 /* Hz */);
+    rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
Index: trunk/src/VBox/Devices/Audio/DevSB16.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevSB16.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DevSB16.cpp	(revision 61609)
@@ -1785,5 +1785,6 @@
     pThis->uTimerTSIO = cTicksNow;
 
-    bool fIsPlaying = false;
+    bool     fIsPlaying = false;
+    uint32_t cbWritable = UINT32_MAX;
 
     LogFlowFuncEnter();
@@ -1796,20 +1797,36 @@
             continue;
 
-        int rc2 = pDrv->pConnector->pfnStreamIterate(pDrv->pConnector, pStream);
+        PPDMIAUDIOCONNECTOR pConn = pDrv->pConnector;
+        if (!pConn)
+            continue;
+
+        int rc2 = pConn->pfnStreamIterate(pConn, pStream);
         if (RT_SUCCESS(rc2))
         {
             if (pStream->enmDir == PDMAUDIODIR_IN)
             {
-                /** @todo Implement this! */
+                /** @todo Implement recording! */
             }
             else
             {
-                rc2 = pDrv->pConnector->pfnStreamPlay(pDrv->pConnector, pStream, NULL /* cPlayed */);
+                rc2 = pConn->pfnStreamPlay(pConn, pStream, NULL /* cPlayed */);
                 if (RT_FAILURE(rc2))
+                {
                     LogFlowFunc(("%s: Failed playing stream, rc=%Rrc\n", pStream->szName, rc2));
+                    continue;
+                }
+
+                rc2 = pConn->pfnStreamIterate(pConn, pStream);
+                if (RT_FAILURE(rc2))
+                {
+                    LogFlowFunc(("%s: Failed re-iterating stream, rc=%Rrc\n", pStream->szName, rc2));
+                    continue;
+                }
+
+                cbWritable = RT_MIN(pConn->pfnStreamGetWritable(pConn, pStream), cbWritable);
             }
         }
 
-        PDMAUDIOSTRMSTS strmSts = pDrv->pConnector->pfnStreamGetStatus(pDrv->pConnector, pStream);
+        PDMAUDIOSTRMSTS strmSts = pConn->pfnStreamGetStatus(pConn, pStream);
         fIsPlaying |= (   (strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
                        || (strmSts & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE));
@@ -1821,6 +1838,9 @@
         || fIsPlaying)
     {
-        /* Schedule the next transfer. */
-        PDMDevHlpDMASchedule(pThis->pDevInsR3);
+        if (cbWritable)
+        {
+            /* Schedule the next transfer. */
+            PDMDevHlpDMASchedule(pThis->pDevInsR3);
+        }
 
         /* Kick the timer again. */
Index: trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61609)
@@ -581,5 +581,5 @@
     AssertPtr(pGstStream);
 
-    int rc = VINF_SUCCESS;
+    int rc;
 
     do
@@ -587,21 +587,24 @@
         uint32_t cSamplesMixed = 0;
 
-        PDMAUDIOSTRMSTS hstStrmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
+        rc = pThis->pHostDrvAudio->pfnStreamIterate(pThis->pHostDrvAudio, pHstStream);
+        if (RT_FAILURE(rc))
+            break;
 
         if (pHstStream->enmDir == PDMAUDIODIR_IN)
         {
-            uint32_t cSamplesToCapture = AudioMixBufFree(&pGstStream->MixBuf);
-            if (cSamplesToCapture)
-            {
-                if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE)
+            /* Has the host captured any samples which were not mixed to the guest side yet? */
+            uint32_t cSamplesCaptured = AudioMixBufUsed(&pHstStream->MixBuf);
+
+            LogFlowFunc(("[%s] %RU32 samples captured\n", pHstStream->szName, cSamplesCaptured));
+
+            if (cSamplesCaptured)
+            {
+                /* When capturing samples, the guest is the parent while the host is the child.
+                 * So try mixing not yet mixed host-side samples to the guest-side buffer. */
+                rc = AudioMixBufMixToParent(&pHstStream->MixBuf, cSamplesCaptured, &cSamplesMixed);
+                if (   RT_SUCCESS(rc)
+                    && cSamplesMixed)
                 {
-                    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));
+                    LogFlowFunc(("[%s] %RU32 captured samples mixed\n", pHstStream->szName, cSamplesMixed));
                 }
             }
@@ -609,23 +612,43 @@
         else if (pHstStream->enmDir == PDMAUDIODIR_OUT)
         {
-            uint32_t cSamplesToMix = AudioMixBufUsed(&pGstStream->MixBuf);
-
-            if (cSamplesToMix)
-            {
-                uint32_t cSamplesPlayed = 0;
-                if (hstStrmSts & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE)
+            uint32_t cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
+            if (!cSamplesLive) /* No live samples at the moment? */
+            {
+                /* When playing samples, the host is the parent while the guest is the child.
+                 * So try mixing not yet mixed guest-side samples to the host-side buffer. */
+                rc = AudioMixBufMixToParent(&pGstStream->MixBuf, AudioMixBufUsed(&pGstStream->MixBuf), &cSamplesMixed);
+                if (   RT_SUCCESS(rc)
+                    && cSamplesMixed)
                 {
-                    rc = AudioMixBufMixToParent(&pGstStream->MixBuf, cSamplesToMix, &cSamplesMixed);
-
-                    LogFlowFunc(("%s: %RU32/%RU32 playback samples mixed, rc=%Rrc\n",
-                                 pHstStream->szName, cSamplesMixed, cSamplesToMix, rc));
+                    LogFlowFunc(("[%s] %RU32 samples mixed\n", pHstStream->szName, cSamplesMixed));
                 }
+
+                if (RT_SUCCESS(rc))
+                    cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
+            }
+
+            LogFlowFunc(("[%s] %RU32 live samples\n", pHstStream->szName, cSamplesLive));
+
+            if (!cSamplesLive) /* No live samples at the moment? */
+            {
+                /* 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 output stream, rc=%Rrc\n", pHstStream->szName, rc));
+                }
+
+                break;
             }
         }
         else
             AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
-
-        if (RT_SUCCESS(rc))
-            rc = pThis->pHostDrvAudio->pfnStreamIterate(pThis->pHostDrvAudio, pHstStream);
 
     } while (0);
@@ -656,6 +679,4 @@
     if (RT_FAILURE(rc))
         return rc;
-
-    LogFlowFunc(("[%s]\n", pStream->szName));
 
     uint32_t cSamplesPlayed = 0;
@@ -682,5 +703,5 @@
         AssertPtr(pGstStream);
 
-        uint32_t cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf);
+        uint32_t cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
         if (cSamplesLive)
         {
@@ -690,15 +711,11 @@
                 rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, &cSamplesPlayed);
                 if (RT_FAILURE(rc))
-                    drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
-            }
-
-            LogFlowFunc(("[%s] strmSts=0x%x, cSamplesPlayed=%RU32, rc=%Rrc\n", pStream->szName, strmSts, cSamplesPlayed, rc));
-
-            if (RT_SUCCESS(rc))
-            {
-                rc = drvAudioStreamIterateInternal(pThis, pStream);
-                if (RT_SUCCESS(rc))
-                    cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf);
-            }
+                {
+                    int rc2 = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+                    AssertRC(rc2);
+                }
+            }
+
+            LogFlowFunc(("[%s] strmSts=0x%x, cSamplesPlayed=%RU32, rc=%Rrc\n", pHstStream->szName, strmSts, cSamplesPlayed, rc));
         }
 
@@ -709,5 +726,5 @@
             if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
             {
-                LogFunc(("%s: Closing pending stream\n", pHstStream->szName));
+                LogFunc(("[%s] Closing pending stream\n", pHstStream->szName));
                 rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
                 if (RT_SUCCESS(rc))
@@ -716,5 +733,5 @@
                 }
                 else
-                    LogFunc(("%s: Backend vetoed against closing output stream, rc=%Rrc\n", pHstStream->szName, rc));
+                    LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStream->szName, rc));
             }
         }
@@ -733,5 +750,5 @@
 
     if (RT_FAILURE(rc))
-        LogFlowFuncLeaveRC(rc);
+        LogFlowFunc(("[%s] Failed with %Rrc\n", rc));
 
     return rc;
@@ -779,6 +796,6 @@
         AssertPtr(pGstStream);
 
-        uint32_t cSamplesLive = AudioMixBufUsed(&pHstStream->MixBuf);
-        if (cSamplesLive)
+        uint32_t cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
+        if (!cSamplesLive)
         {
             PDMAUDIOSTRMSTS strmSts = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
@@ -787,32 +804,11 @@
                 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;
+                    int rc2 = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+                    AssertRC(rc2);
                 }
-                else
-                    LogFunc(("%s: Backend vetoed against closing input stream, rc=%Rrc\n", pHstStream->szName, rc));
-            }
+            }
+
+            LogFlowFunc(("[%s] strmSts=0x%x, cSamplesCaptured=%RU32, rc=%Rrc\n", pHstStream->szName, strmSts, cSamplesCaptured, rc));
         }
 
@@ -1366,4 +1362,75 @@
     LogFlowFuncLeaveRC(rc);
     return backendSts;
+}
+
+static DECLCALLBACK(uint32_t) drvAudioStreamGetReadable(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, 0);
+    AssertPtrReturn(pStream,    0);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc2 = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc2);
+
+    AssertMsg(pStream->enmDir == PDMAUDIODIR_IN, ("Can't read from a non-input stream\n"));
+
+    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    if (!pHstStream) /* No host stream available? Bail out early. */
+    {
+        rc2 = RTCritSectLeave(&pThis->CritSect);
+        AssertRC(rc2);
+
+        return 0;
+    }
+
+    uint32_t cbReadable = 0;
+
+    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+    if (pGstStream)
+        cbReadable = AudioMixBufLive(&pGstStream->MixBuf);
+
+    LogFlowFunc(("[%s] cbReadable=%RU32\n", pHstStream->szName, cbReadable));
+
+    rc2 = RTCritSectLeave(&pThis->CritSect);
+    AssertRC(rc2);
+
+    return cbReadable;
+}
+
+static DECLCALLBACK(uint32_t) drvAudioStreamGetWritable(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+{
+    AssertPtrReturn(pInterface, 0);
+    AssertPtrReturn(pStream,    0);
+
+    PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+    int rc2 = RTCritSectEnter(&pThis->CritSect);
+    AssertRC(rc2);
+
+    AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT, ("Can't write to a non-output stream\n"));
+
+    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
+    if (!pHstStream) /* No host stream available? Bail out early. */
+    {
+        rc2 = RTCritSectLeave(&pThis->CritSect);
+        AssertRC(rc2);
+
+        return 0;
+    }
+
+    PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+
+    uint32_t cbWritable = 0;
+
+    if (AudioMixBufLive(&pHstStream->MixBuf) == 0)
+        cbWritable = AudioMixBufFreeBytes(&pGstStream->MixBuf);
+
+    LogFlowFunc(("[%s] cWritable=%RU32\n", pHstStream->szName, cbWritable));
+
+    rc2 = RTCritSectLeave(&pThis->CritSect);
+    AssertRC(rc2);
+
+    return cbWritable;
 }
 
@@ -1634,4 +1701,6 @@
     pThis->IAudioConnector.pfnStreamWrite       = drvAudioStreamWrite;
     pThis->IAudioConnector.pfnStreamIterate     = drvAudioStreamIterate;
+    pThis->IAudioConnector.pfnStreamGetReadable = drvAudioStreamGetReadable;
+    pThis->IAudioConnector.pfnStreamGetWritable = drvAudioStreamGetWritable;
     pThis->IAudioConnector.pfnStreamGetStatus   = drvAudioStreamGetStatus;
     pThis->IAudioConnector.pfnStreamSetVolume   = drvAudioStreamSetVolume;
Index: trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp	(revision 61609)
@@ -1166,5 +1166,5 @@
                                                  (uint32_t)cAvail), /* cAvail is always >= 0 */
                                  AUDIOMIXBUF_S2B(&pStream->MixBuf,
-                                                 AudioMixBufAvail(&pStream->MixBuf)));
+                                                 AudioMixBufLive(&pStream->MixBuf)));
         LogFlowFunc(("cbToRead=%zu, cbAvail=%zu\n",
                      cbToRead, AUDIOMIXBUF_S2B(&pStream->MixBuf, cAvail)));
Index: trunk/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp	(revision 61609)
@@ -1561,6 +1561,6 @@
     /* Not much else to do here. */
 
-    uint32_t cLive = AudioMixBufAvail(&pStream->MixBuf);;
-    if (!cLive) /* Not samples to play? Bail out. */
+    uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
+    if (!cLive) /* Not live samples to play? Bail out. */
     {
         if (pcSamplesPlayed)
@@ -1569,8 +1569,9 @@
     }
 
+    size_t cbLive  = AUDIOMIXBUF_S2B(&pStream->MixBuf, cLive);
+
     uint32_t cbReadTotal = 0;
-    uint32_t cAvail = AudioMixBufAvail(&pStream->MixBuf);
-    size_t cbAvail  = AUDIOMIXBUF_S2B(&pStream->MixBuf, cAvail);
-    size_t cbToRead = RT_MIN(cbAvail, RTCircBufFree(pStreamOut->pBuf));
+
+    size_t cbToRead = RT_MIN(cbLive, RTCircBufFree(pStreamOut->pBuf));
     LogFlowFunc(("cbToRead=%zu\n", cbToRead));
 
Index: trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 61609)
@@ -257,4 +257,7 @@
     AssertPtrReturn(pThis,         VERR_INVALID_POINTER);
     AssertPtrReturn(pDSoundStream, VERR_INVALID_POINTER);
+    /* pdwBuffer is optional. */
+    /* pdwFree is optional. */
+    /* pdwPlayPos is optional. */
 
     LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStream->pDSB;
@@ -305,5 +308,6 @@
     }
 
-    LogFlowFuncLeaveRC(rc);
+    if (RT_FAILURE(rc))
+        LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -1540,6 +1544,6 @@
         cbFree     -= cbSample;
 
-        uint32_t csLive = AudioMixBufAvail(&pStream->MixBuf);
-        uint32_t cbLive = AUDIOMIXBUF_S2B(&pStream->MixBuf, csLive);
+        uint32_t cLive  = AudioMixBufLive(&pStream->MixBuf);
+        uint32_t cbLive = AUDIOMIXBUF_S2B(&pStream->MixBuf, cLive);
 
         /* Do not write more than available space in the DirectSound playback buffer. */
@@ -2237,5 +2241,16 @@
         PDSOUNDSTREAMOUT pDSoundStream = (PDSOUNDSTREAMOUT)pStream;
         if (pDSoundStream->fEnabled)
-            strmSts |= PDMAUDIOSTRMSTS_FLAG_ENABLED | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
+        {
+            strmSts |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
+
+            DWORD cbFree;
+            int rc = dsoundGetPosOut(pThis, pDSoundStream, NULL /* cbBuffer */, &cbFree, NULL /* cbPlayPos */);
+            if (   RT_SUCCESS(rc)
+                && cbFree)
+            {
+                LogFlowFunc(("cbFree=%ld\n", cbFree));
+                strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
+            }
+        }
     }
 
Index: trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp	(revision 61609)
@@ -160,5 +160,6 @@
 
     /* Consume as many samples as would be played at the current frequency since last call. */
-    uint32_t csLive          = AudioMixBufAvail(&pStream->MixBuf);
+    uint32_t cLive           = AudioMixBufLive(&pStream->MixBuf);
+
     uint64_t u64TicksNow     = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
     uint64_t u64TicksElapsed = u64TicksNow  - pNullStream->u64TicksLast;
@@ -175,6 +176,6 @@
 
     /* Don't play more than available. */
-    if (cSamplesPlayed > csLive)
-        cSamplesPlayed = csLive;
+    if (cSamplesPlayed > cLive)
+        cSamplesPlayed = cLive;
 
     cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStream->csPlayBuffer);
Index: trunk/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp	(revision 61609)
@@ -875,5 +875,5 @@
         size_t cbBuf = AudioMixBufSizeBytes(&pStream->MixBuf);
 
-        uint32_t cLive = AudioMixBufAvail(&pStream->MixBuf);
+        uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
         uint32_t cToRead;
 
Index: trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61609)
@@ -772,4 +772,6 @@
     }
 
+    LogFlowFunc(("cbAvail=%zu\n", cbAvail));
+
     if (!cbAvail) /* No data? Bail out. */
     {
@@ -853,7 +855,7 @@
     {
         uint32_t cProcessed = 0;
-        if (cWrittenTotal)
+      /*  if (cWrittenTotal)
             rc = AudioMixBufMixToParent(&pStream->MixBuf, cWrittenTotal,
-                                        &cProcessed);
+                                        &cProcessed);*/
 
         if (pcSamplesCaptured)
@@ -1424,22 +1426,16 @@
         && 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;
+            strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_READABLE;
         }
         else
         {
-            cbSize = pa_stream_writable_size(pStrm->pPAStream);
+            size_t cbSize = pa_stream_writable_size(pStrm->pPAStream);
+            LogFlowFunc(("cbSize=%zu\n", cbSize));
 
             if (cbSize >= pStrm->BufAttr.minreq)
                 strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
         }
-
-        LogFlowFunc(("cbSize=%zu\n", cbSize));
     }
 
Index: trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp	(revision 61608)
+++ trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp	(revision 61609)
@@ -231,6 +231,6 @@
         RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild1, ("Child1: Expected %RU32 written samples, got %RU32\n", cSamplesChild1, written));
         RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child1, written, &mixed));
-        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child1) == mixed, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child1), mixed));
-        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child1) == AUDIOMIXBUF_S2S_RATIO(&parent, mixed), ("Child1: Expected %RU32 used samples, got %RU32\n", AudioMixBufMixed(&child1), AUDIOMIXBUF_S2S_RATIO(&parent, mixed)));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufLive(&child1) == mixed, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child1), mixed));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child1) == AUDIOMIXBUF_S2S_RATIO(&parent, mixed), ("Child1: Expected %RU32 used samples, got %RU32\n", AudioMixBufLive(&child1), AUDIOMIXBUF_S2S_RATIO(&parent, mixed)));
         RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&parent) == 0, ("Parent: Expected 0 used samples, got %RU32\n", AudioMixBufUsed(&parent)));
 
@@ -238,10 +238,10 @@
         RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild2, ("Child2: Expected %RU32 written samples, got %RU32\n", cSamplesChild2, written));
         RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child2, written, &mixed));
-        RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child2) == mixed, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child2), AudioMixBufUsed(&parent)));
-        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child2) == AUDIOMIXBUF_S2S_RATIO(&parent, mixed), ("Child2: Expected %RU32 used samples, got %RU32\n", AudioMixBufMixed(&child2), AUDIOMIXBUF_S2S_RATIO(&parent, mixed)));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufLive(&child2) == mixed, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child2), AudioMixBufUsed(&parent)));
+        RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child2) == AUDIOMIXBUF_S2S_RATIO(&parent, mixed), ("Child2: Expected %RU32 used samples, got %RU32\n", AudioMixBufLive(&child2), AUDIOMIXBUF_S2S_RATIO(&parent, mixed)));
         RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&parent) == 0, ("Parent2: Expected 0 used samples, got %RU32\n", AudioMixBufUsed(&parent)));
     }
 
-    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufMixed(&child1) + AudioMixBufMixed(&child2));
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child1) + AudioMixBufLive(&child2));
 
     for (;;)
@@ -254,6 +254,6 @@
 
     RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
-    RTTESTI_CHECK(AudioMixBufMixed(&child1) == 0);
-    RTTESTI_CHECK(AudioMixBufMixed(&child2) == 0);
+    RTTESTI_CHECK(AudioMixBufLive(&child1) == 0);
+    RTTESTI_CHECK(AudioMixBufLive(&child2) == 0);
 
     AudioMixBufDestroy(&parent);
@@ -338,7 +338,7 @@
     RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
     temp = AudioMixBufUsed(&parent);
-    RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
-
-    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufMixed(&child));
+    RTTESTI_CHECK_MSG(AudioMixBufLive(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child), temp));
+
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child));
 
     for (;;)
@@ -366,5 +366,5 @@
 
     RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
-    RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
+    RTTESTI_CHECK(AudioMixBufLive(&child)  == 0);
 
     AudioMixBufDestroy(&parent);
@@ -441,7 +441,7 @@
     RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
     temp = AudioMixBufUsed(&parent);
-    RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
-
-    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufMixed(&child));
+    RTTESTI_CHECK_MSG(AudioMixBufLive(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child), temp));
+
+    RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child));
 
     for (;;)
@@ -468,5 +468,5 @@
 
     RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
-    RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
+    RTTESTI_CHECK(AudioMixBufLive(&child)  == 0);
 
     AudioMixBufDestroy(&parent);
Index: trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp	(revision 61608)
+++ trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp	(revision 61609)
@@ -254,5 +254,6 @@
     AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
 
-    uint32_t live = AudioMixBufAvail(&pStream->MixBuf);
+    uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
+
     uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
     uint64_t ticks = now  - pVRDEStrmOut->old_ticks;
@@ -263,6 +264,6 @@
 
     /* Don't play more than available. */
-    if (cSamplesPlayed > live)
-        cSamplesPlayed = live;
+    if (cSamplesPlayed > cLive)
+        cSamplesPlayed = cLive;
 
     /* Remember when samples were consumed. */
