Index: trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 61050)
@@ -37,4 +37,5 @@
 #include "AudioMixer.h"
 #include "AudioMixBuffer.h"
+#include "DrvAudio.h"
 
 #include <VBox/vmm/pdm.h>
@@ -101,4 +102,81 @@
 }
 
+int AudioMixerCreateStream(PAUDIOMIXER pMixer,
+                           PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream)
+{
+    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+    AssertPtrReturn(pConn,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,   VERR_INVALID_POINTER);
+    /** @todo Validate fFlags. */
+    /* ppStream is optional. */
+
+    PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
+    if (!pMixStream)
+        return VERR_NO_MEMORY;
+
+    pMixStream->pszName = RTStrDup(pCfg->szName);
+    if (!pMixStream->pszName)
+    {
+        RTMemFree(pMixStream);
+        return VERR_NO_MEMORY;
+    }
+
+    LogFlowFunc(("[%s]: fFlags=0x%x (enmDir=%ld, %s, %RU8 channels, %RU32Hz)\n",
+                 pMixer->pszName, fFlags, pCfg->enmDir, DrvAudioAudFmtToStr(pCfg->enmFormat), pCfg->cChannels, pCfg->uHz));
+
+    int rc;
+    if (pCfg->enmDir == PDMAUDIODIR_IN)
+    {
+        PPDMAUDIOGSTSTRMIN pGstStrm;
+        rc = pConn->pfnCreateIn(pConn, pCfg, &pGstStrm);
+        if (RT_SUCCESS(rc))
+        {
+            pMixStream->InOut.pIn = pGstStrm;
+
+            /* Increase the stream's reference count to let others know
+             * we're reyling on it to be around now. */
+            pConn->pfnAddRefIn(pConn, pGstStrm);
+        }
+    }
+    else if (pCfg->enmDir == PDMAUDIODIR_OUT)
+    {
+        PPDMAUDIOGSTSTRMOUT pGstStrm;
+        rc = pConn->pfnCreateOut(pConn, pCfg, &pGstStrm);
+        if (RT_SUCCESS(rc))
+        {
+            pMixStream->InOut.pOut = pGstStrm;
+
+            /* Increase the stream's reference count to let others know
+             * we're reyling on it to be around now. */
+            pConn->pfnAddRefOut(pConn, pGstStrm);
+        }
+    }
+    else
+    {
+        AssertMsgFailed(("Direction not implemented\n"));
+        rc = VERR_NOT_IMPLEMENTED;
+    }
+
+    if (RT_SUCCESS(rc))
+    {
+        pMixStream->fFlags = fFlags;
+        pMixStream->enmDir = pCfg->enmDir;
+        pMixStream->pConn  = pConn;
+
+        if (ppStream)
+            *ppStream = pMixStream;
+    }
+    else if (pMixStream)
+    {
+        RTStrFree(pMixStream->pszName);
+        pMixStream->pszName = NULL;
+
+        RTMemFree(pMixStream);
+        pMixStream = NULL;
+    }
+
+    return rc;
+}
+
 int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer)
 {
@@ -191,5 +269,5 @@
     AssertPtrReturnVoid(pMixer);
 
-    LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName));
+    LogFlowFunc(("[%s]: Invalidating ...\n", pMixer->pszName));
 
     /* Propagate new master volume to all connected sinks. */
@@ -219,5 +297,5 @@
     pMixer->cSinks--;
 
-    LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n",
+    LogFlowFunc(("[%s]: pSink=%s, cSinks=%RU8\n",
                  pMixer->pszName, pSink->pszName, pMixer->cSinks));
 }
@@ -248,5 +326,5 @@
     pMixer->VolMaster = *pVol;
 
-    LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+    LogFlowFunc(("[%s]: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
                  pMixer->pszName, pVol->uLeft, pVol->uRight,
                  pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
@@ -256,7 +334,7 @@
 }
 
-/*****************************************************************************
+/*********************************************************************************************************************************
  * Mixer Sink implementation.
- *****************************************************************************/
+ ********************************************************************************************************************************/
 
 int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
@@ -273,5 +351,5 @@
     pSink->cStreams++;
 
-    LogFlowFunc(("%s: cStreams=%RU8\n", pSink->pszName, pSink->cStreams));
+    LogFlowFunc(("[%s]: cStreams=%RU8\n", pSink->pszName, pSink->cStreams));
 
     return VINF_SUCCESS;
@@ -312,5 +390,5 @@
     }
 
-    LogFlowFunc(("%s: enmCmd=%ld, rc=%Rrc\n", pSink->pszName, enmCmd, rc));
+    LogFlowFunc(("[%s]: enmCmd=%ld, rc=%Rrc\n", pSink->pszName, enmCmd, rc));
     return rc;
 }
@@ -384,4 +462,13 @@
 }
 
+bool AudioMixerSinkHasData(PAUDMIXSINK pSink)
+{
+    if (!pSink)
+        return false;
+
+    /* If the dirty flag is set, there is unprocessed data in the sink. */
+    return (pSink->fFlags & AUDMIXSINK_FLAG_DIRTY);
+}
+
 int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
 {
@@ -442,5 +529,5 @@
     RTMemFree(pvMixBuf);
 
-    Log3Func(("%s: cbRead=%RU32, rc=%Rrc\n", pSink->pszName, cbRead, rc));
+    Log3Func(("[%s]: cbRead=%RU32, rc=%Rrc\n", pSink->pszName, cbRead, rc));
     return rc;
 }
@@ -460,5 +547,5 @@
                           ? pStream->InOut.pIn->MixBuf.pszName : pStream->InOut.pOut->MixBuf.pszName;
 
-    LogFlowFunc(("%s: (Stream = %s), cStreams=%RU8\n",
+    LogFlowFunc(("[%s]: (Stream = %s), cStreams=%RU8\n",
                  pSink->pszName, pszStream ? pszStream : "<Unnamed>", pSink->cStreams));
 #endif
@@ -500,6 +587,17 @@
     AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
 
+    if (DrvAudioPCMPropsAreEqual(&pSink->PCMProps, pPCMProps)) /* Bail out early if PCM properties are equal. */
+        return VINF_SUCCESS;
+
+    if (pSink->PCMProps.uHz)
+        LogFlowFunc(("[%s]: Old format: %RU8 bit, %RU8 channels, %RU32Hz\n",
+                     pSink->pszName, pSink->PCMProps.cBits, pSink->PCMProps.cChannels, pSink->PCMProps.uHz));
+
     memcpy(&pSink->PCMProps, pPCMProps, sizeof(PDMPCMPROPS));
 
+    LogFlowFunc(("[%s]: New format %RU8 bit, %RU8 channels, %RU32Hz\n",
+                 pSink->pszName, pSink->PCMProps.cBits, pSink->PCMProps.cChannels, pSink->PCMProps.uHz));
+
+#if 0
     PAUDMIXSTREAM pStream;
     RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
@@ -507,4 +605,5 @@
         /** @todo Invalidate mix buffers! */
     }
+#endif
 
     return VINF_SUCCESS;
@@ -524,5 +623,5 @@
     AssertPtr(pSink->pParent);
 
-    LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
+    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
 
     pSink->Volume = *pVol;
@@ -531,13 +630,20 @@
 }
 
-void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTicksPerSec, uint64_t cTicksElapsed, uint32_t *pcbData)
+void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed, uint32_t *pcbData)
 {
     AssertPtrReturnVoid(pSink);
     /* pcbData is optional. */
 
-    uint32_t cSamplesMin  = (uint32_t)((2 * cTicksElapsed * pSink->PCMProps.uHz + cTicksPerSec) / cTicksPerSec / 2);
+    /* 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;
     uint32_t cbSamplesMin = cSamplesMin << pSink->PCMProps.cShift;
 
-    LogFlowFunc(("%s: cbSamplesMin=%RU32\n", pSink->pszName, cbSamplesMin));
+    Assert((cbSamplesMin % 2 == 0));
+
+    LogFlowFunc(("[%s]: cSamplesMin=%RU32 (%RU32 bytes, %RU32Hz)\n", pSink->pszName, cSamplesMin, cbSamplesMin, pSink->PCMProps.uHz));
 
     audioMixerSinkUpdateInternal(pSink);
@@ -551,36 +657,61 @@
     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
 
+    int rc = VINF_SUCCESS;
+
     PAUDMIXSTREAM pStream;
     RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
     {
-        uint32_t cbIn, cbOut;
-        uint32_t cSamplesLive;
-        int rc2 = pStream->pConn->pfnQueryStatus(pStream->pConn,
-                                                 &cbIn, &cbOut, &cSamplesLive);
-#ifdef DEBUG
-        if (   cbIn
-            || cbOut
-            || cSamplesLive)
-        {
-            Log3Func(("%s: cbIn=%RU32, cbOut=%RU32, cSamplesLive=%RU32, rc2=%Rrc\n",
-                      pSink->pszName, cbIn, cbOut, cSamplesLive, rc2));
-        }
-#endif
         if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
         {
-            rc2 = pStream->pConn->pfnPlayOut(pStream->pConn, NULL /* pcSamplesPlayed */);
-            if (RT_FAILURE(rc2))
-                Log3Func(("rc2=%Rrc\n", rc2));
+            uint32_t cSamplesLive;
+            uint32_t cSamplesPlayed = 0;
+            rc = pStream->pConn->pfnGetDataOut(pStream->pConn, NULL /* cbOut */, &cSamplesLive);
+            if (   RT_SUCCESS(rc)
+                && cSamplesLive)
+            {
+                rc = pStream->pConn->pfnPlayOut(pStream->pConn, &cSamplesPlayed);
+            }
+
+            if (RT_SUCCESS(rc))
+            {
+                Assert(cSamplesLive >= cSamplesPlayed);
+                if (cSamplesLive - cSamplesPlayed) /* Some live samples left? */
+                    pSink->fFlags |= AUDMIXSINK_FLAG_DIRTY;
+                else
+                    pSink->fFlags &= ~AUDMIXSINK_FLAG_DIRTY;
+            }
+
+            Log3Func(("[%s]: fFlags=0x%x, cSamplesLive=%RU32, rc=%Rrc\n", pSink->pszName, pSink->fFlags, cSamplesLive, rc));
         }
         else if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
         {
-            //int rc2 = pStream->pConn->pfnCaptureIn(pStream->pConn, NULL /* pcSamplesCaptured */);
-            //Log3Func(("rc2=%Rrc\n", rc2));
+            uint32_t cbIn;
+            rc = pStream->pConn->pfnGetDataIn(pStream->pConn, &cbIn);
+            if (   RT_SUCCESS(rc)
+                && cbIn)
+            {
+                /** @todo Implement this! */
+                // int rc2 = pStream->pConn->pfnCaptureIn(pStream->pConn, NULL /* pcSamplesCaptured */);
+                // Log3Func(("rc2=%Rrc\n", rc2));
+            }
+
+            if (RT_SUCCESS(rc))
+            {
+                if (cbIn) /* Some inpput data available? */
+                    pSink->fFlags |= AUDMIXSINK_FLAG_DIRTY;
+                else
+                    pSink->fFlags &= ~AUDMIXSINK_FLAG_DIRTY;
+            }
+
+            Log3Func(("[%s]: fFlags=0x%x, cbIn=%RU32, rc=%Rrc\n", pSink->pszName, pSink->fFlags, cbIn, rc));
         }
         else
+        {
+            rc = VERR_NOT_IMPLEMENTED;
             AssertMsgFailed(("Direction not implemented\n"));
-    }
-
-    return VINF_SUCCESS;
+        }
+    }
+
+    return rc;
 }
 
@@ -597,5 +728,5 @@
     LogFlowFunc(("Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
                   pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
-    LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
                   pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
 
@@ -656,7 +787,7 @@
 }
 
-/*****************************************************************************
+/*********************************************************************************************************************************
  * Mixer Stream implementation.
- *****************************************************************************/
+ ********************************************************************************************************************************/
 
 int AudioMixerStreamCtl(PAUDMIXSTREAM pStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl)
@@ -702,73 +833,4 @@
 }
 
-int AudioMixerStreamCreate(PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream)
-{
-    AssertPtrReturn(pConn, VERR_INVALID_POINTER);
-    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
-    /** @todo Validate fFlags. */
-    /* ppStream is optional. */
-
-    PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
-    if (!pMixStream)
-        return VERR_NO_MEMORY;
-
-    pMixStream->pszName = RTStrDup(pCfg->szName);
-    if (!pMixStream->pszName)
-    {
-        RTMemFree(pMixStream);
-        return VERR_NO_MEMORY;
-    }
-
-    int rc;
-    if (pCfg->enmDir == PDMAUDIODIR_IN)
-    {
-        PPDMAUDIOGSTSTRMIN pGstStrm;
-        rc = pConn->pfnCreateIn(pConn, pCfg, &pGstStrm);
-        if (RT_SUCCESS(rc))
-        {
-            pMixStream->InOut.pIn = pGstStrm;
-
-            /* Increase the stream's reference count to let others know
-             * we're reyling on it to be around now. */
-            pConn->pfnAddRefIn(pConn, pGstStrm);
-        }
-    }
-    else if (pCfg->enmDir == PDMAUDIODIR_OUT)
-    {
-        PPDMAUDIOGSTSTRMOUT pGstStrm;
-        rc = pConn->pfnCreateOut(pConn, pCfg, &pGstStrm);
-        if (RT_SUCCESS(rc))
-        {
-            pMixStream->InOut.pOut = pGstStrm;
-
-            /* Increase the stream's reference count to let others know
-             * we're reyling on it to be around now. */
-            pConn->pfnAddRefOut(pConn, pGstStrm);
-        }
-    }
-    else
-        rc = VERR_NOT_SUPPORTED;
-
-    if (RT_SUCCESS(rc))
-    {
-        pMixStream->fFlags = fFlags;
-        pMixStream->enmDir = pCfg->enmDir;
-        pMixStream->pConn  = pConn;
-
-        if (ppStream)
-            *ppStream = pMixStream;
-    }
-    else if (pMixStream)
-    {
-        RTStrFree(pMixStream->pszName);
-        pMixStream->pszName = NULL;
-
-        RTMemFree(pMixStream);
-        pMixStream = NULL;
-    }
-
-    return rc;
-}
-
 static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pStream)
 {
@@ -832,4 +894,33 @@
         return false;
 
+    bool fIsActive;
+    switch (pStream->enmDir)
+    {
+        case PDMAUDIODIR_IN:
+        {
+            fIsActive = pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->InOut.pIn);
+            break;
+        }
+
+        case PDMAUDIODIR_OUT:
+        {
+            fIsActive = pStream->pConn->pfnIsActiveOut(pStream->pConn, pStream->InOut.pOut);
+            break;
+        }
+
+        default:
+            fIsActive = false;
+            AssertMsgFailed(("Not implemented\n"));
+            break;
+    }
+
+    return fIsActive;
+}
+
+bool AudioMixerStreamIsValid(PAUDMIXSTREAM pStream)
+{
+    if (!pStream)
+        return false;
+
     bool fIsValid;
     switch (pStream->enmDir)
@@ -837,5 +928,5 @@
         case PDMAUDIODIR_IN:
         {
-            fIsValid = pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->InOut.pIn);
+            fIsValid = pStream->pConn->pfnIsValidIn(pStream->pConn, pStream->InOut.pIn);
             break;
         }
@@ -843,5 +934,5 @@
         case PDMAUDIODIR_OUT:
         {
-            fIsValid = pStream->pConn->pfnIsActiveOut(pStream->pConn, pStream->InOut.pOut);
+            fIsValid = pStream->pConn->pfnIsValidOut(pStream->pConn, pStream->InOut.pOut);
             break;
         }
@@ -856,31 +947,2 @@
 }
 
-bool AudioMixerStreamIsValid(PAUDMIXSTREAM pStream)
-{
-    if (!pStream)
-        return false;
-
-    bool fIsValid;
-    switch (pStream->enmDir)
-    {
-        case PDMAUDIODIR_IN:
-        {
-            fIsValid = pStream->pConn->pfnIsValidIn(pStream->pConn, pStream->InOut.pIn);
-            break;
-        }
-
-        case PDMAUDIODIR_OUT:
-        {
-            fIsValid = pStream->pConn->pfnIsValidOut(pStream->pConn, pStream->InOut.pOut);
-            break;
-        }
-
-        default:
-            fIsValid = false;
-            AssertMsgFailed(("Not implemented\n"));
-            break;
-    }
-
-    return fIsValid;
-}
-
Index: trunk/src/VBox/Devices/Audio/AudioMixer.h
===================================================================
--- trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/AudioMixer.h	(revision 61050)
@@ -69,4 +69,9 @@
 } AUDMIXSTREAM, *PAUDMIXSTREAM;
 
+/** No flags specified. */
+#define AUDMIXSINK_FLAG_NONE                  0
+/** Dirty flag. */
+#define AUDMIXSINK_FLAG_DIRTY                 RT_BIT(0)
+
 /**
  * Audio mixer sink direction.
@@ -113,4 +118,6 @@
      *  if this sink handles input or output. */
     AUDMIXSINKDIR           enmDir;
+    /** Sink flags of type AUDMIXSINK_FLAG_. */
+    uint32_t                fFlags;
     /** The sink's PCM format. */
     PDMPCMPROPS             PCMProps;
@@ -145,4 +152,5 @@
 int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer);
 int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink);
+int AudioMixerCreateStream(PAUDIOMIXER pMixer, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream);
 void AudioMixerDestroy(PAUDIOMIXER pMixer);
 int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg);
@@ -159,4 +167,5 @@
 PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex);
 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);
@@ -164,9 +173,8 @@
 int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMPCMPROPS pPCMProps);
 int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
-void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTicksPerSec, uint64_t cTicksElapsed, uint32_t *pcbData);
+void AudioMixerSinkTimerUpdate(PAUDMIXSINK pSink, uint64_t cTimerTicks, uint64_t cTicksElapsed, uint32_t *pcbData);
 int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
 int AudioMixerSinkUpdate(PAUDMIXSINK pSink);
 
-int AudioMixerStreamCreate(PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream);
 int AudioMixerStreamCtl(PAUDMIXSTREAM pStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl);
 void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream);
Index: trunk/src/VBox/Devices/Audio/DevIchAc97.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/DevIchAc97.cpp	(revision 61050)
@@ -27,4 +27,7 @@
 #include <iprt/assert.h>
 #ifdef IN_RING3
+# ifdef DEBUG
+#  include <iprt/file.h>
+# endif
 # include <iprt/mem.h>
 # include <iprt/string.h>
@@ -371,4 +374,7 @@
     uint32_t                Padding0;
 # endif
+    /** Flag indicating whether the timer is active or not. */
+    bool                    fTimerActive;
+    uint8_t                 u8Padding1[7];
     /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
     uint64_t                cTimerTicks;
@@ -547,8 +553,16 @@
     }
 
-    LogFlowFunc(("u8Strm=%RU8, fActive=%RTbool, cStreamsActive=%RU8\n", pStream->u8Strm, fActive, pThis->cStreamsActive));
-
-    return AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm),
-                             fActive ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
+    int rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm),
+                               fActive ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
+
+    LogFlowFunc(("u8Strm=%RU8, fActive=%RTbool, cStreamsActive=%RU8, rc=%Rrc\n",
+                 pStream->u8Strm, fActive, pThis->cStreamsActive, rc));
+    if (rc == VERR_AUDIO_STREAM_PENDING_DISABLE)
+    {
+        LogFlowFunc(("On pending disable\n"));
+        rc = VINF_SUCCESS;
+    }
+
+    return rc;
 }
 
@@ -743,5 +757,5 @@
         pStrmIn->pMixStrm = NULL;
 
-        int rc2 = AudioMixerStreamCreate(pDrv->pConnector, pCfg, 0 /* fFlags */ , &pStrmIn->pMixStrm);
+        int rc2 = AudioMixerCreateStream(pThis->pMixer, pDrv->pConnector, pCfg, 0 /* fFlags */ , &pStrmIn->pMixStrm);
         if (RT_SUCCESS(rc2))
         {
@@ -788,5 +802,5 @@
         pDrv->Out.pMixStrm = NULL;
 
-        int rc2 = AudioMixerStreamCreate(pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
+        int rc2 = AudioMixerCreateStream(pThis->pMixer, pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
         if (RT_SUCCESS(rc2))
         {
@@ -876,5 +890,5 @@
     if (RT_SUCCESS(rc))
     {
-        pStream->State.cbFIFOW  = 256; /** @todo Make FIFOW size configurable. */
+        pStream->State.cbFIFOW  = _4K; /** @todo Make FIFOW size configurable. */
         pStream->State.offFIFOW = 0;
         pStream->State.au8FIFOW = (uint8_t *)RTMemAllocZ(pStream->State.cbFIFOW);
@@ -1158,4 +1172,11 @@
         PDMDevHlpPhysRead(pDevIns, addr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */
 
+#if defined (RT_OS_LINUX) && defined(DEBUG_andy)
+        RTFILE fh;
+        RTFileOpen(&fh, "/tmp/ac97WriteAudio.pcm",
+                   RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+        RTFileWrite(fh, pu8FIFOW, cbToRead, NULL);
+        RTFileClose(fh);
+#endif
         /*
          * Write data to the mixer sink.
@@ -1313,4 +1334,10 @@
         return;
 
+    /* Set timer flag. */
+    ASMAtomicXchgBool(&pThis->fTimerActive, true);
+
+    /* Update current time timestamp. */
+    pThis->uTimerTS = TMTimerGet(pThis->pTimer);
+
     /* Fire off timer. */
     TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
@@ -1327,6 +1354,6 @@
         return;
 
-    int rc2 = TMTimerStop(pThis->pTimer);
-    AssertRC(rc2);
+    /* Set timer flag. */
+    ASMAtomicXchgBool(&pThis->fTimerActive, false);
 }
 
@@ -1341,25 +1368,33 @@
     uint64_t cTicksNow     = TMTimerGet(pTimer);
     uint64_t cTicksElapsed = cTicksNow  - pThis->uTimerTS;
-    uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
-
+
+    /* Update current time timestamp. */
     pThis->uTimerTS = cTicksNow;
 
     uint32_t cbLineIn;
-    AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, cTicksPerSec, cTicksElapsed, &cbLineIn);
+    AudioMixerSinkTimerUpdate(pThis->pSinkLineIn, pThis->cTimerTicks, cTicksElapsed, &cbLineIn);
     if (cbLineIn)
-        ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbLineIn); /** @todo Add rc! */
+        ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbLineIn);
 
     uint32_t cbMicIn;
-    AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , cTicksPerSec, cTicksElapsed, &cbMicIn);
+    AudioMixerSinkTimerUpdate(pThis->pSinkMicIn , pThis->cTimerTicks, cTicksElapsed, &cbMicIn);
+    if (cbMicIn)
+        ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbMicIn);
 
     uint32_t cbOut;
-    AudioMixerSinkTimerUpdate(pThis->pSinkOutput, cTicksPerSec, cTicksElapsed, &cbOut);
+    AudioMixerSinkTimerUpdate(pThis->pSinkOutput, pThis->cTimerTicks, cTicksElapsed, &cbOut);
     if (cbOut)
-        ichac97TransferAudio(pThis, &pThis->StreamOut, cbOut);  /** @todo Add rc! */
-
-    /* Kick the timer again. */
-    uint64_t cTicks = pThis->cTimerTicks;
-    /** @todo adjust cTicks down by now much cbOutMin represents. */
-    TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+        ichac97TransferAudio(pThis, &pThis->StreamOut, cbOut);
+
+    if (   ASMAtomicReadBool(&pThis->fTimerActive)
+        || AudioMixerSinkHasData(pThis->pSinkLineIn)
+        || AudioMixerSinkHasData(pThis->pSinkMicIn)
+        || AudioMixerSinkHasData(pThis->pSinkOutput))
+    {
+        /* Kick the timer again. */
+        uint64_t cTicks = pThis->cTimerTicks;
+        /** @todo adjust cTicks down by now much cbOutMin represents. */
+        TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+    }
 
     STAM_PROFILE_STOP(&pThis->StatTimer, a);
Index: trunk/src/VBox/Devices/Audio/DevIchHda.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 61050)
@@ -469,13 +469,13 @@
  * Other values not listed are not supported.
  */
-#define HDA_SDINFIFO_120B           0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
-#define HDA_SDINFIFO_160B           0x9F /* 20-, 24-bit Input Streams Streams */
-
-#define HDA_SDONFIFO_16B            0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_32B            0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_64B            0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_128B           0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_192B           0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_256B           0xFF /* 20-, 24-bit Output Streams */
+#define HDA_SDIFIFO_120B            0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
+#define HDA_SDIFIFO_160B            0x9F /* 20-, 24-bit Input Streams Streams */
+
+#define HDA_SDOFIFO_16B             0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_32B             0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_64B             0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_128B            0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_192B            0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDOFIFO_256B            0xFF /* 20-, 24-bit Output Streams */
 #define SDFIFOS(pThis, num)         HDA_REG((pThis), SD(FIFOS, num))
 
@@ -559,5 +559,5 @@
     uint32_t     cbBelowFIFOW;
     /** The buffer descriptor's internal DMA buffer. */
-    uint8_t      au8FIFO[HDA_SDONFIFO_256B + 1];
+    uint8_t      au8FIFO[HDA_SDOFIFO_256B + 1];
     /** Current offset in DMA buffer (in bytes).*/
     uint32_t     u32BufOff;
@@ -789,5 +789,5 @@
     bool                               fDMAPosition;
     /** Padding for alignment. */
-    uint8_t                            u32Padding0[7];
+    uint8_t                            u8Padding0[7];
     /** Pointer to CORB buffer. */
     R3PTRTYPE(uint32_t *)              pu32CorbBuf;
@@ -811,5 +811,8 @@
     /** The timer for pumping data thru the attached LUN drivers. */
     PTMTIMERR3                         pTimer;
-    /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
+    /** Flag indicating whether the timer is active or not. */
+    bool                               fTimerActive;
+    uint8_t                            u8Padding1[7];
+    /** Timer ticks per Hz. */
     uint64_t                           cTimerTicks;
     /** Timestamp of the last timer callback (hdaTimer).
@@ -1172,14 +1175,14 @@
     {
         /* Input */
-        case HDA_SDINFIFO_120B: cb = 120; break;
-        case HDA_SDINFIFO_160B: cb = 160; break;
+        case HDA_SDIFIFO_120B: cb = 120; break;
+        case HDA_SDIFIFO_160B: cb = 160; break;
 
         /* Output */
-        case HDA_SDONFIFO_16B:  cb = 16;  break;
-        case HDA_SDONFIFO_32B:  cb = 32;  break;
-        case HDA_SDONFIFO_64B:  cb = 64;  break;
-        case HDA_SDONFIFO_128B: cb = 128; break;
-        case HDA_SDONFIFO_192B: cb = 192; break;
-        case HDA_SDONFIFO_256B: cb = 256; break;
+        case HDA_SDOFIFO_16B:  cb = 16;  break;
+        case HDA_SDOFIFO_32B:  cb = 32;  break;
+        case HDA_SDOFIFO_64B:  cb = 64;  break;
+        case HDA_SDOFIFO_128B: cb = 128; break;
+        case HDA_SDOFIFO_192B: cb = 192; break;
+        case HDA_SDOFIFO_256B: cb = 256; break;
         default:
         {
@@ -1341,5 +1344,5 @@
          && (SDSTS(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
 
-    uint8_t uLevel = 0;
+    int iLevel = 0;
 
     /** @todo Optimize IRQ handling. */
@@ -1350,5 +1353,7 @@
            || HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)
            || (HDA_REG(pThis, STATESTS) & HDA_REG(pThis, WAKEEN))))
-        uLevel = 1;
+    {
+        iLevel = 1;
+    }
 
     if (   IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 0)
@@ -1361,11 +1366,11 @@
         || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 7))
     {
-        uLevel = 1;
+        iLevel = 1;
     }
 
     if (HDA_REG_FLAG_VALUE(pThis, INTCTL, GIE))
     {
-        Log3Func(("Level=%d\n", uLevel));
-        PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , uLevel);
+        Log3Func(("Level=%d\n", iLevel));
+        PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , iLevel);
     }
 
@@ -1489,4 +1494,8 @@
     {
         Assert((HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)));
+        Assert(pThis->u64CORBBase);
+        AssertPtr(pThis->pu32CorbBuf);
+        Assert(pThis->cbCorbBuf);
+
         rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf);
         if (RT_FAILURE(rc))
@@ -1720,5 +1729,5 @@
     HDA_STREAM_REG(pThis, CTL,   uSD) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
     /* ICH6 defines default values (0x77 for input and 0xBF for output descriptors) of FIFO size. 18.2.39. */
-    HDA_STREAM_REG(pThis, FIFOS, uSD) = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? HDA_SDINFIFO_120B : HDA_SDONFIFO_192B;
+    HDA_STREAM_REG(pThis, FIFOS, uSD) = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? HDA_SDIFIFO_120B : HDA_SDOFIFO_192B;
     /* See 18.2.38: Always defaults to 0x4 (32 bytes). */
     HDA_STREAM_REG(pThis, FIFOW, uSD) = HDA_SDFIFOW_32B;
@@ -2097,12 +2106,17 @@
     }
 
-    HDA_MARK_STREAM(0); /* SD0: Input. */
-    HDA_MARK_STREAM(4); /* SD4: Output. */
+    HDA_MARK_STREAM(0);
+    HDA_MARK_STREAM(1);
+    HDA_MARK_STREAM(2);
+    HDA_MARK_STREAM(3);
+    HDA_MARK_STREAM(4);
+    HDA_MARK_STREAM(5);
+    HDA_MARK_STREAM(6);
+    HDA_MARK_STREAM(7);
 
 #undef HDA_MARK_STREAM
 
     /* "OR" bit of all interrupt status bits. */
-    if (v)
-        v |= RT_BIT(31);
+    v |= v ? RT_BIT(31) : 0;
 
     *pu32Value = v;
@@ -2240,7 +2254,4 @@
     bool fInReset  = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
 
-uint32_t uVal = HDA_REG_IND(pThis, iReg);
-    LogFunc(("uVal=%RU32 vs u32Value=%RU32\n", uVal, u32Value));
-
     if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
         return VINF_SUCCESS;
@@ -2346,7 +2357,4 @@
 static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
-        return VINF_SUCCESS;
-
     uint32_t v  = HDA_REG_IND(pThis, iReg);
              /* Clear (zero) FIFOE and DESE bits when writing 1 to it. */
@@ -2396,6 +2404,13 @@
 static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+    uint8_t  uSD      = HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg);
+    /** @todo Only allow updating FIFOS if RUN bit is 0? */
+    uint32_t u32FIFOW = 0;
+
+    if (hdaGetDirFromSD(uSD) != PDMAUDIODIR_IN) /* FIFOW for input streams only. */
+    {
+        LogRel(("HDA: Warning: Guest tried to write read-only FIFOW to stream #%RU8, ignoring\n", uSD));
         return VINF_SUCCESS;
+    }
 
     switch (u32Value)
@@ -2404,9 +2419,21 @@
         case HDA_SDFIFOW_16B:
         case HDA_SDFIFOW_32B:
-            return hdaRegWriteU16(pThis, iReg, u32Value);
+            u32FIFOW = u32Value;
+            break;
         default:
-            LogFunc(("Attempt to store unsupported value(%x) in SDFIFOW\n", u32Value));
-            return hdaRegWriteU16(pThis, iReg, HDA_SDFIFOW_32B);
-    }
+            LogRel(("HDA: Warning: Guest tried write unsupported FIFOW (0x%x) to stream #%RU8, defaulting to 32 bytes\n",
+                    u32Value, uSD));
+            u32FIFOW = HDA_SDFIFOW_32B;
+            break;
+    }
+
+    if (u32FIFOW)
+    {
+        LogFunc(("[SD%RU8]: Updating FIFOW to %RU32 bytes\n", uSD, hdaSDFIFOSToBytes(u32FIFOW)));
+        /** @todo Update internal stream state with new FIFOS. */
+
+        return hdaRegWriteU16(pThis, iReg, u32FIFOW);
+    }
+
     return VINF_SUCCESS; /* Never reached. */
 }
@@ -2418,15 +2445,11 @@
 static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
 {
-    if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
-        return VINF_SUCCESS;
-
     uint8_t  uSD      = HDA_SD_NUM_FROM_REG(pThis, FIFOS, iReg);
     /** @todo Only allow updating FIFOS if RUN bit is 0? */
     uint32_t u32FIFOS = 0;
 
-    if (hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN) /* FIFOS for input streams is read-only. */
-    {
-        LogRel(("HDA: Warning: Guest tried to write read-only FIFOS for input stream #%RU8, skipping\n", uSD));
-        AssertFailed();
+    if (hdaGetDirFromSD(uSD) != PDMAUDIODIR_OUT) /* FIFOS for output streams only. */
+    {
+        LogRel(("HDA: Warning: Guest tried to write read-only FIFOS to stream #%RU8, ignoring\n", uSD));
         return VINF_SUCCESS;
     }
@@ -2434,20 +2457,19 @@
     switch(u32Value)
     {
-        case HDA_SDONFIFO_16B:
-        case HDA_SDONFIFO_32B:
-        case HDA_SDONFIFO_64B:
-        case HDA_SDONFIFO_128B:
-        case HDA_SDONFIFO_192B:
+        case HDA_SDOFIFO_16B:
+        case HDA_SDOFIFO_32B:
+        case HDA_SDOFIFO_64B:
+        case HDA_SDOFIFO_128B:
+        case HDA_SDOFIFO_192B:
             u32FIFOS = u32Value;
             break;
 
-        case HDA_SDONFIFO_256B: /** @todo r=andy Investigate this. */
+        case HDA_SDOFIFO_256B: /** @todo r=andy Investigate this. */
             LogFunc(("256-bit is unsupported, HDA is switched into 192-bit mode\n"));
             /* Fall through is intentional. */
         default:
-            LogRel(("HDA: Warning: Guest tried write unsupported FIFOS (0x%x) to input stream #%RU8, defaulting to 192 bytes\n",
+            LogRel(("HDA: Warning: Guest tried write unsupported FIFOS (0x%x) to stream #%RU8, defaulting to 192 bytes\n",
                     u32Value, uSD));
-            u32FIFOS = HDA_SDONFIFO_192B;
-            AssertFailed();
+            u32FIFOS = HDA_SDOFIFO_192B;
             break;
     }
@@ -2474,5 +2496,6 @@
     int rc = VINF_SUCCESS;
 
-    uint32_t u32Hz     = (u32SDFMT & HDA_SDFMT_BASE_RATE_SHIFT) ? 44100 : 48000;
+    uint32_t u32Hz     = EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BASE_RATE_MASK, HDA_SDFMT_BASE_RATE_SHIFT)
+                       ? 44100 : 48000;
     uint32_t u32HzMult = 1;
     uint32_t u32HzDiv  = 1;
@@ -2598,4 +2621,5 @@
     }
 #else /* !VBOX_WITH_HDA_51_SURROUND */
+    /* Only support mono or stereo channels. */
     if (   pCfg->cChannels != 1 /* Mono */
         && pCfg->cChannels != 2 /* Stereo */)
@@ -2605,12 +2629,17 @@
 #endif
 
-    if (RT_FAILURE(rc))
+    if (rc == VERR_NOT_SUPPORTED)
     {
         LogRel(("HDA: Unsupported channel count (%RU8), falling back to stereo channels\n", pCfg->cChannels));
         pCfg->cChannels = 2;
+
+        rc = VINF_SUCCESS;
     }
 
     do
     {
+        if (RT_FAILURE(rc))
+            break;
+
         if (fUseFront)
         {
@@ -2643,6 +2672,4 @@
             if (RT_SUCCESS(rc))
                 rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
-
-            RTStrFree(pszName);
         }
 
@@ -2666,4 +2693,5 @@
     } while (0);
 
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -2707,4 +2735,5 @@
     }
 
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -2865,6 +2894,9 @@
     if (fIsRunning)
     {
-        LogFlowFunc(("[SD%RU8]: Warning: Cannot write to register 0x%x (0x%x) when RUN bit is set (%R[sdctl])\n",
-                     pStream->u8SD, iReg, u32Value, u32SDCTL));
+        LogFunc(("[SD%RU8]: Warning: Cannot write to register 0x%x (0x%x) when RUN bit is set (%R[sdctl])\n",
+                 pStream->u8SD, iReg, u32Value, u32SDCTL));
+# ifdef DEBUG_andy
+        AssertFailed();
+# endif
         return VERR_ACCESS_DENIED;
     }
@@ -3111,5 +3143,5 @@
     Assert(u32LPIB <= pStream->u32CBL);
 
-    uint32_t cbFree = pStream->u32CBL - u32LPIB; /** @todo Convert samples to bytes? */
+    uint32_t cbFree = pStream->u32CBL - u32LPIB;
     if (cbFree)
     {
@@ -3118,5 +3150,5 @@
 
         /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
-        cbFree = RT_MIN(cbFree, pStream->u16FIFOS);
+     //   cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));
 
         /* Make sure we only transfer as many bytes as requested. */
@@ -3136,6 +3168,6 @@
     }
 
-    LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, cbFree=%RU32, %R[bdle]\n", pStream->u8SD,
-                 pStream->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), cbFree, pBDLE));
+    LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, FIFOS=%RU16, cbFree=%RU32, %R[bdle]\n", pStream->u8SD,
+                 pStream->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), pStream->u16FIFOS, cbFree, pBDLE));
     return cbFree;
 }
@@ -3223,6 +3255,10 @@
     }
 
-    if (RT_SUCCESS(rc))
-        rc = RTCircBufCreate(&pMapping->pCircBuf, _4K);
+    if (   RT_SUCCESS(rc)
+        /* Create circular buffer if not created yet. */
+        && !pMapping->pCircBuf)
+    {
+        rc = RTCircBufCreate(&pMapping->pCircBuf, _4K); /** @todo Make size configurable? */
+    }
 
     if (RT_SUCCESS(rc))
@@ -3312,5 +3348,5 @@
     LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStream->u8SD, cbInc));
 
-    Assert(cbInc <= pStream->u16FIFOS);
+    //Assert(cbInc <= pStream->u16FIFOS);
 
     if (!cbInc) /* Nothing to do? Bail out early. */
@@ -3429,5 +3465,5 @@
         Assert(cbRead <= cbBuf);
         Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
-        Assert(cbRead <= pStream->u16FIFOS);
+        //Assert(cbRead <= pStream->u16FIFOS);
 
         /*
@@ -3503,7 +3539,7 @@
                                pvBuf, cbBuf);
         AssertRC(rc);
-#if defined (RT_OS_LINUX) && defined(DEBUG)
+#if defined (RT_OS_LINUX) && defined(DEBUG_andy)
         RTFILE fh;
-        RTFileOpen(&fh, "/tmp/hdaWriteAudio.pcm",
+        RTFileOpen(&fh, "/tmp/hdaWriteAudio-hda.pcm",
                    RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
         RTFileWrite(fh, pvBuf, cbBuf, NULL);
@@ -3602,5 +3638,5 @@
     }
 
-    Assert(cbWritten <= pStream->u16FIFOS);
+    //Assert(cbWritten <= pStream->u16FIFOS);
 
     if (RT_SUCCESS(rc))
@@ -3681,4 +3717,7 @@
     if (RT_SUCCESS(rc))
         rc = AudioMixerSinkSetFormat(pSink->pMixSink, &PCMProps);
+
+    if (RT_FAILURE(rc))
+        return rc;
 
     PHDADRIVER pDrv;
@@ -3736,5 +3775,5 @@
 
             PAUDMIXSTREAM pMixStrm;
-            rc2 = AudioMixerStreamCreate(pDrv->pConnector, pCfg, 0 /* fFlags */, &pMixStrm);
+            rc2 = AudioMixerCreateStream(pThis->pMixer, pDrv->pConnector, pCfg, 0 /* fFlags */, &pMixStrm);
             if (RT_SUCCESS(rc2))
             {
@@ -3776,9 +3815,12 @@
     {
         rc = hdaMixerAddStream(pThis, pSink, pCfg);
+
+        AssertPtr(pSink->pMixSink);
+        LogFlowFunc(("Sink=%s, enmMixerCtl=%ld\n", pSink->pMixSink->pszName, enmMixerCtl));
     }
     else
         rc = VERR_NOT_FOUND;
 
-    LogFlowFunc(("Sink=%s, enmMixerCtl=%ld, rc=%Rrc\n", pSink->pMixSink->pszName, enmMixerCtl, rc));
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -3952,4 +3994,6 @@
 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;
@@ -3960,4 +4004,10 @@
     LogFlowFuncEnter();
 
+    /* Set timer flag. */
+    ASMAtomicXchgBool(&pThis->fTimerActive, true);
+
+    /* Update current time timestamp. */
+    pThis->uTimerTS = TMTimerGet(pThis->pTimer);
+
     /* Fire off timer. */
     TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
@@ -3966,4 +4016,6 @@
 static void hdaTimerMaybeStop(PHDASTATE pThis)
 {
+    LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
+
     if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
         return;
@@ -3974,6 +4026,6 @@
     LogFlowFuncEnter();
 
-    int rc2 = TMTimerStop(pThis->pTimer);
-    AssertRC(rc2);
+    /* Set timer flag. */
+    ASMAtomicXchgBool(&pThis->fTimerActive, false);
 }
 
@@ -3991,6 +4043,6 @@
     uint64_t cTicksNow     = TMTimerGet(pTimer);
     uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
-    uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
-
+
+    /* Update current time timestamp. */
     pThis->uTimerTS = cTicksNow;
 
@@ -4000,7 +4052,10 @@
 #endif
     PHDASTREAM pStreamFront   = hdaGetStreamFromSink(pThis, &pThis->SinkFront);
+#ifdef VBOX_WITH_HDA_51_SURROUND
+    /** @todo See note below. */
+#endif
 
     uint32_t cbLineIn;
-    AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink, cTicksPerSec, cTicksElapsed, &cbLineIn);
+    AudioMixerSinkTimerUpdate(pThis->SinkLineIn.pMixSink,    pThis->cTimerTicks, cTicksElapsed, &cbLineIn);
     if (cbLineIn)
         hdaTransfer(pThis, pStreamLineIn, cbLineIn, NULL); /** @todo Add rc! */
@@ -4008,16 +4063,39 @@
 #ifdef VBOX_WITH_HDA_MIC_IN
     uint32_t cbMicIn;
-    AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink , cTicksPerSec, cTicksElapsed, &cbMicIn);
-#endif
-
-    uint32_t cbOut;
-    AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink, cTicksPerSec, cTicksElapsed, &cbOut);
-    if (cbOut)
-        hdaTransfer(pThis, pStreamFront, cbOut, NULL);  /** @todo Add rc! */
-
-    /* Kick the timer again. */
-    uint64_t cTicks = pThis->cTimerTicks;
-    /** @todo adjust cTicks down by now much cbOutMin represents. */
-    TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+    AudioMixerSinkTimerUpdate(pThis->SinkMicIn.pMixSink ,    pThis->cTimerTicks, cTicksElapsed, &cbMicIn);
+#endif
+
+    uint32_t cbFront;
+    AudioMixerSinkTimerUpdate(pThis->SinkFront.pMixSink,     pThis->cTimerTicks, cTicksElapsed, &cbFront);
+#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! */
+#ifdef VBOX_WITH_HDA_51_SURROUND
+    /*
+     * Only call hdaTransfer if CenterLFE and/or Rear are on different SDs,
+     * otherwise we have to use the interleaved streams support for getting the data
+     * out of the Front sink (depending on the mapping layout).
+     */
+#endif
+
+    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))
+    {
+        /* Kick the timer again. */
+        uint64_t cTicks = pThis->cTimerTicks;
+        /** @todo adjust cTicks down by now much cbOutMin represents. */
+        TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+    }
 
     STAM_PROFILE_STOP(&pThis->StatTimer, a);
@@ -4111,13 +4189,7 @@
         fProceed = false;
 
-#if 0
-    Log3Func(("[SD%RU8] fProceed=%RTbool, fRun=%RTbool, cbToProcess=%RU32\n",
-              pStream->u8SD, fProceed, HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN),
-              cbToProcess));
-#endif
-
     if ((HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
     {
-        Log3Func(("[SD%RU8]: BCIS: Skipping\n", pStream->u8SD));
+        Log3Func(("[SD%RU8]: BCIS set\n", pStream->u8SD));
         fProceed = false;
     }
@@ -4125,4 +4197,6 @@
     if (!fProceed)
     {
+        Log3Func(("[SD%RU8] Skipping\n"));
+
         rc = RTSemMutexRelease(pStream->State.hMtx);
         AssertRC(rc);
@@ -4144,8 +4218,5 @@
     Assert(u32LPIB <= pStream->u32CBL);
 
-    if (u32LPIB == pStream->u32CBL)
-         u32LPIB = hdaStreamUpdateLPIB(pThis, pStream, 0);
-
-    uint32_t cbLeft  = pStream->u32CBL - u32LPIB;
+    uint32_t cbLeft  = cbToProcess;
     uint32_t cbTotal = 0;
 
@@ -4154,7 +4225,16 @@
     Log3Func(("cbLeft=%RU32\n", cbLeft));
 
+#define FOO
+
+#ifdef FOO
+    uint8_t u8FIFO[_16K+1];
+    size_t u8FIFOff = 0;
+#endif
+
+    /* 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)
     {
-    #if 1
         /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
         if (hdaStreamNeedsNextBDLE(pThis, pStream))
@@ -4164,45 +4244,4 @@
                 break;
         }
-    #else
-        PHDABDLE pBDLE   = &pStream->State.BDLE;
-
-        /* Did we reach the CBL (Cyclic Buffer List) limit? */
-        bool fCBLLimitReached = u32LPIB >= pStream->u32CBL;
-
-        /* Do we need to use the next BDLE entry? Either because we reached
-         * the CBL limit or our internal DMA buffer is full. */
-        bool fNeedsNextBDLE   = (   fCBLLimitReached
-                                 || (pBDLE->State.u32BufOff >= pBDLE->u32BufSize));
-
-        Assert(u32LPIB                <= pStream->u32CBL);
-        Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
-
-        if (fNeedsNextBDLE)
-        {
-
-
-        #if 1
-            if (/* IOC (Interrupt On Completion) bit set? */
-                   pBDLE->fIntOnCompletion
-                /* All data put into the DMA FIFO? */
-                && pBDLE->State.cbBelowFIFOW == 0
-               )
-            {
-            //    fSetIRQ = true;
-                /*
-                 * If the ICE (IOCE, "Interrupt On Completion Enable") bit of the SDCTL register is set
-                 * we need to generate an interrupt.
-                 */
-               // if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
-                 //   PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , 1 /* Raised */);
-            }
-        #endif
-
-
-        }
-    #endif
-
-        /* 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);
 
         uint32_t cbProcessed;
@@ -4210,13 +4249,33 @@
             rc = hdaReadAudio (pThis, pStream, cbLeft, &cbProcessed);
         else
+        {
+#ifndef FOO
             rc = hdaWriteAudio(pThis, pStream, cbLeft, &cbProcessed);
-
-        /* Remove the FIFORDY bit again. */
-        HDA_STREAM_REG(pThis, STS, pStream->u8SD) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+#else
+            uint32_t cbToWrite = hdaStreamGetTransferSize(pThis, pStream, cbLeft);
+
+            void    *pvBuf = u8FIFO + u8FIFOff;
+            int32_t cbBuf = cbToWrite;
+
+            PHDABDLE pBDLE = &pStream->State.BDLE;
+
+            rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
+                               pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
+                               pvBuf, cbBuf);
+
+            hdaBDLEUpdate(pBDLE, cbToWrite, cbToWrite);
+
+            LogFlowFunc(("u8FIFOff=%zu, cbLeft=%RU32, cbToWrite=%RU32\n", u8FIFOff, cbLeft, cbToWrite));
+
+            u8FIFOff += cbToWrite;
+            Assert(u8FIFOff <= sizeof(u8FIFO));
+
+            cbProcessed = cbToWrite;
+#endif
+        }
 
         if (RT_FAILURE(rc))
             break;
 
-    #if 1
         hdaStreamTransferUpdate(pThis, pStream, cbProcessed);
 
@@ -4232,78 +4291,25 @@
 
         if (hdaStreamTransferIsComplete(pThis, pStream, &fInterrupt))
-        {
-            rc = hdaStreamGetNextBDLE(pThis, pStream);
             break;
-        }
-    #else
-        Assert(cbProcessedLeft >= cbProcessed);
-        cbProcessedLeft  -= cbProcessed;
-        cbProcessedTotal += cbProcessed;
-
-
-        u32LPIB = hdaStreamUpdateLPIB(pThis, pStream, u32LPIB + cbProcessed);
-
-        Assert(u32LPIB <= pStream->u32CBL);
-        if (u32LPIB == pStream->u32CBL)
-        {
-           // HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
-            Log3Func(("[SD%RU8]: Transfer complete\n", pStream->u8SD));
+    }
+
+    /* 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)
+        RTFILE fh;
+        RTFileOpen(&fh, "/tmp/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
-            if (/* IOC (Interrupt On Completion) bit set? */
-                   pBDLE->fIntOnCompletion
-                /* All data put into the DMA FIFO? */
-                && pBDLE->State.cbBelowFIFOW == 0
-               )
-            {
-                fSetIRQ = true;
-                /*
-                 * If the ICE (IOCE, "Interrupt On Completion Enable") bit of the SDCTL register is set
-                 * we need to generate an interrupt.
-                 */
-            //    if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
-              //      PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , 1 /* Raised */);
-              //  fIRQ = true;
-            }
-#endif
-            fIsComplete = true;
-        }
-
-        if (   fIsComplete
-            || pBDLE->State.u32BufOff >= pBDLE->u32BufSize)
-        {
-            Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
-
-            Log3Func(("[SD%RU8]: LPIB=%RU32, CBL=%RU32, %R[bdle] => Next BDLE\n",
-                      pStream->u8SD, u32LPIB, u32LPIB >= pStream->u32CBL, pBDLE));
-
-            /*
-             * Switch to the next BDLE entry and do a wrap around
-             * if we reached the end of the Buffer Descriptor List (BDL).
-             */
-            pStream->State.uCurBDLE++;
-            if (pStream->State.uCurBDLE == pStream->u16LVI + 1)
-            {
-                pStream->State.uCurBDLE = 0;
-                u32LPIB = hdaStreamUpdateLPIB(pThis, pStream, 0);
-            }
-
-            hdaBDLEFetch(pThis, &pStream->State.BDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
-
-            if (/* IOC (Interrupt On Completion) bit set? */
-                   pBDLE->fIntOnCompletion
-                /* All data put into the DMA FIFO? */
-                && pBDLE->State.cbBelowFIFOW == 0
-               )
-            {
-                fSetIRQ = true;
-            }
-        }
-
-    #endif
-
-        /*if (fIsComplete)
-            break;*/
-    }
-
+     AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, u8FIFO, u8FIFOff,
+                         NULL /* pcbWritten */);
+#endif
+#endif
+
+#ifdef FOO
     if (fInterrupt)
     {
@@ -4319,32 +4325,7 @@
          */
         HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
-        Log3Func(("[SD%RU8]: BCIS: Set (fInterrupt=%RTbool)\n", pStream->u8SD, fInterrupt));
+        Log3Func(("[SD%RU8]: BCIS: Set\n", pStream->u8SD));
 
         hdaProcessInterrupt(pThis);
-    }
-
-#if 0
-    if (fSetIRQ)
-    {
-        Log3Func(("[SD%RU8]: IRQ\n", pStream->u8SD));
-
-        /**
-         * Set the BCIS (Buffer Completion Interrupt Status) flag as the
-         * last byte of data for the current descriptor has been fetched
-         * from memory and put into the DMA FIFO.
-         *
-         * Speech synthesis works fine on Mac Guest if this bit isn't set
-         * but in general sound quality gets worse.
-         *
-         * This must be set in *any* case.
-         */
-        HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
-
-        /*
-         * If the ICE (IOCE, "Interrupt On Completion Enable") bit of the SDCTL register is set
-         * we need to generate an interrupt.
-         */
-        if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
-            PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , 1 /* Raised */);
     }
 #endif
@@ -5006,29 +4987,4 @@
     if (RT_SUCCESS(rc))
     {
-        /*
-         * Update sinks after the state changes.
-         */
-        AUDMIXSINKCMD enmCmdLineIn = RT_BOOL(HDA_SDCTL(pThis, 0 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))
-                                   ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
-#ifdef VBOX_WITH_HDA_MIC_IN
-        AUDMIXSINKCMD enmCmdMicIn  = RT_BOOL(HDA_SDCTL(pThis, 2 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))
-                                   ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
-#endif
-        AUDMIXSINKCMD enmCmdOut    = RT_BOOL(HDA_SDCTL(pThis, 4 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))
-                                   ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
-
-# ifdef VBOX_WITH_HDA_MIC_IN
-        AudioMixerSinkCtl(pThis->SinkMicIn.pMixSink,     enmCmdMicIn);
-# endif
-        AudioMixerSinkCtl(pThis->SinkLineIn.pMixSink,    enmCmdLineIn);
-        AudioMixerSinkCtl(pThis->SinkFront.pMixSink,     enmCmdOut);
-# ifdef VBOX_WITH_HDA_51_SURROUND
-        AudioMixerSinkCtl(pThis->SinkCenterLFE.pMixSink, enmCmdOut);
-        AudioMixerSinkCtl(pThis->SinkRear.pMixSink,      enmCmdOut);
-# endif
-    }
-
-    if (RT_SUCCESS(rc))
-    {
         pThis->u64CORBBase  = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
         pThis->u64RIRBBase  = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
@@ -5038,5 +4994,21 @@
         pThis->fDMAPosition = RT_BOOL(pThis->u64DPBase & RT_BIT_64(0));
     }
-    else
+
+    if (RT_SUCCESS(rc))
+    {
+        for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+        {
+            PHDASTREAM pStream = hdaStreamFromSD(pThis, i);
+            if (pStream)
+            {
+                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);
+                AssertRC(rc2);
+            }
+        }
+    }
+
+    if (RT_FAILURE(rc))
         LogRel(("HDA: Failed loading device state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
 
@@ -5678,5 +5650,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 61033)
+++ trunk/src/VBox/Devices/Audio/DevSB16.cpp	(revision 61050)
@@ -1685,6 +1685,5 @@
     RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     {
-        int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
-                                                   NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
+        int rc2 = pDrv->pConnector->pfnGetDataOut(pDrv->pConnector, &cbOut, NULL /* pcSamplesLive */);
         if (RT_SUCCESS(rc2))
             cbOutMin = RT_MIN(cbOutMin, cbOut);
@@ -1761,4 +1760,7 @@
     if (!pThis->pTimerIO)
         return;
+
+    /* Update current time timestamp. */
+    pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
 
     /* Fire off timer. */
@@ -2052,5 +2054,5 @@
         pDrv->Out.pMixStrm = NULL;
 
-        int rc2 = AudioMixerStreamCreate(pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
+        int rc2 = AudioMixerCreateStream(pThis->pMixer, pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
         if (RT_SUCCESS(rc2))
         {
Index: trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 61050)
@@ -1161,10 +1161,63 @@
 }
 
-static DECLCALLBACK(int) drvAudioQueryStatus(PPDMIAUDIOCONNECTOR pInterface,
-                                             uint32_t *pcbAvailIn, uint32_t *pcbFreeOut,
-                                             uint32_t *pcSamplesLive)
+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. */
@@ -1234,43 +1287,8 @@
     }
 
-    /*
-     * Recording.
-     */
-    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 (cbFreeOut == UINT32_MAX)
             cbFreeOut = 0;
-
-        if (pcbAvailIn)
-            *pcbAvailIn = cbAvailIn;
 
         if (pcbFreeOut)
@@ -1713,4 +1731,7 @@
         if (RT_SUCCESS(rc))
             rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
+
+        if (RT_SUCCESS(rc))
+            pGstStrmOut->State.fActive = fEnable;
     }
     else /* Disable */
@@ -1718,5 +1739,5 @@
         if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
         {
-            uint32_t cGstStrmsActive = 0;
+            size_t cGstStrmsActive = 0;
 
             /*
@@ -1738,15 +1759,19 @@
 
             /* Do we need to defer closing the host stream? */
-            if (cGstStrmsActive >= 1)
+            if (cGstStrmsActive)
+            {
+                LogFlowFunc(("Closing stream deferred: %zu guest stream(s) active\n", cGstStrmsActive));
                 pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
 
-            /* Can we close the host stream now instead of deferring it? */
-            if (!(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;
+                if (RT_SUCCESS(rc))
+                    pGstStrmOut->State.fActive = fEnable;
+            }
+        }
+    }
 
     LogFlowFunc(("%s: fEnable=%RTbool, fStatus=0x%x, rc=%Rrc\n",
@@ -2071,5 +2096,4 @@
     pDrvIns->IBase.pfnQueryInterface                 = drvAudioQueryInterface;
     /* IAudioConnector. */
-    pThis->IAudioConnector.pfnQueryStatus            = drvAudioQueryStatus;
     pThis->IAudioConnector.pfnAddRefIn               = drvAudioAddRefIn;
     pThis->IAudioConnector.pfnAddRefOut              = drvAudioAddRefOut;
@@ -2079,4 +2103,6 @@
     pThis->IAudioConnector.pfnWrite                  = drvAudioWrite;
     pThis->IAudioConnector.pfnGetConfig              = drvAudioGetConfig;
+    pThis->IAudioConnector.pfnGetDataIn              = drvAudioGetDataIn;
+    pThis->IAudioConnector.pfnGetDataOut             = drvAudioGetDataOut;
     pThis->IAudioConnector.pfnIsActiveIn             = drvAudioIsActiveIn;
     pThis->IAudioConnector.pfnIsActiveOut            = drvAudioIsActiveOut;
Index: trunk/src/VBox/Devices/Audio/DrvAudio.h
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudio.h	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/DrvAudio.h	(revision 61050)
@@ -115,4 +115,5 @@
 const char *DrvAudioAudFmtToStr(PDMAUDIOFMT enmFmt);
 void DrvAudioClearBuf(PPDMPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cSamples);
+bool DrvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps1, PPDMPCMPROPS pProps2);
 bool DrvAudioPCMPropsAreEqual(PPDMPCMPROPS pPCMInfo, PPDMAUDIOSTREAMCFG pCfg);
 const char *DrvAudRecSrcToStr(PDMAUDIORECSOURCE enmRecSource);
Index: trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 61050)
@@ -205,4 +205,7 @@
 bool DrvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
 {
+    AssertPtrReturn(pProps, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,   VERR_INVALID_POINTER);
+
     int cBits = 8;
     bool fSigned = false;
@@ -238,4 +241,16 @@
                   && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
     return fEqual;
+}
+
+bool DrvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps1, PPDMPCMPROPS pProps2)
+{
+    AssertPtrReturn(pProps1, VERR_INVALID_POINTER);
+    AssertPtrReturn(pProps2, VERR_INVALID_POINTER);
+
+    return    pProps1->uHz         == pProps2->uHz
+           && pProps1->cChannels   == pProps2->cChannels
+           && pProps1->fSigned     == pProps2->fSigned
+           && pProps1->cBits       == pProps2->cBits
+           && pProps1->fSwapEndian == pProps2->fSwapEndian;
 }
 
Index: trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61033)
+++ trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp	(revision 61050)
@@ -636,5 +636,7 @@
     pStrm->BufAttr.maxlength   = (pStrm->BufAttr.tlength * 3) / 2;
     pStrm->BufAttr.prebuf      = -1; /* Same as tlength */
-    pStrm->BufAttr.minreq      = -1; /* Pulse should set something sensible for minreq on it's own */
+
+    /* Set minreq to 0, as we want to control ourselves when to start/stop the stream. */
+    pStrm->BufAttr.minreq      = 0;
 
     /* Note that the struct BufAttr is updated to the obtained values after this call! */
