Index: trunk/src/VBox/Devices/Audio/DevIchHda.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 58931)
+++ trunk/src/VBox/Devices/Audio/DevIchHda.cpp	(revision 58954)
@@ -831,5 +831,5 @@
 static void hdaStreamDestroy(PHDASTREAM pStrmSt);
 
-static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t *pcbProcessed);
+static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbMax, uint32_t *pcbProcessed);
 
 #ifdef IN_RING3
@@ -1518,5 +1518,5 @@
     AssertPtrReturnVoid(pThis);
     AssertPtrReturnVoid(pStrmSt);
-    AssertReturnVoid(u8Strm <= 7); /** @todo Use a define for MAX_STRAEMS! */
+    AssertReturnVoid(u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
 
     /*
@@ -2304,5 +2304,5 @@
         return;
 
-    for (int i = 0; i < 8; i++) /** @todo Use a define. */
+    for (int i = 0; i < 8; i++) /** @todo Use a define for MAX_STREAMS! */
     {
         uint32_t uDMACnt;
@@ -2362,9 +2362,12 @@
  * @return Number of bytes for the DMA engine to process.
  */
-DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStrmSt)
+DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax)
 {
     AssertPtrReturn(pThis, 0);
     AssertPtrReturn(pStrmSt, 0);
 
+    if (!cbMax)
+        return 0;
+
     PHDABDLE pBDLE = hdaStreamGetCurrentBDLE(pThis, pStrmSt);
 
@@ -2377,4 +2380,7 @@
         /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
         cbFree = RT_MIN(cbFree, pStrmSt->u16FIFOS);
+
+        /* Make sure we only transfer as many bytes as requested. */
+        cbFree = RT_MIN(cbFree, cbMax);
 
         if (pBDLE->State.cbBelowFIFOW)
@@ -2447,5 +2453,7 @@
      * the CBL limit or our internal DMA buffer is full. */
     bool fNeedsNextBDLE   = (   fCBLLimitReached
-                             || pBDLE->State.u32BufOff >= pBDLE->u32BufSize);
+                             || (   pBDLE->State.u32BufOff
+                                 && pBDLE->State.u32BufOff >= pBDLE->u32BufSize)
+                            );
 
     Assert(u32LPIB                <= pStrmSt->u32CBL);
@@ -2557,5 +2565,5 @@
  *       but "reports bytes" when all conditions are met (FIFOW).
  */
-static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, PAUDMIXSINK pSink, uint32_t *pcbRead)
+static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, PAUDMIXSINK pSink, uint32_t cbMax, uint32_t *pcbRead)
 {
     AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
@@ -2568,5 +2576,5 @@
     int rc;
     uint32_t cbRead = 0;
-    uint32_t cbBuf = hdaStreamGetTransferSize(pThis, pStrmSt);
+    uint32_t cbBuf  = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
 
     LogFlowFunc(("cbBuf=%RU32, %R[bdle]\n", cbBuf, pBDLE));
@@ -2575,15 +2583,14 @@
     {
         /* Nothing to write, bail out. */
-        rc = VERR_NO_DATA;
+        rc = VINF_EOF;
     }
     else
     {
-        uint32_t cbReadFromSink = 0;
-        rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbReadFromSink);
+        rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
         if (RT_SUCCESS(rc))
         {
-            Assert(cbReadFromSink);
-            Assert(cbReadFromSink == cbBuf);
-            Assert(cbReadFromSink <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
+            Assert(cbRead);
+            Assert(cbRead == cbBuf);
+            Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
 
             /*
@@ -2592,10 +2599,10 @@
             rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
                                        pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
-                                       pBDLE->State.au8FIFO, cbReadFromSink);
+                                       pBDLE->State.au8FIFO, cbRead);
             AssertRC(rc);
 
-            if (pBDLE->State.cbBelowFIFOW + cbReadFromSink > hdaStreamGetFIFOW(pThis, pStrmSt))
+            if (pBDLE->State.cbBelowFIFOW + cbRead > hdaStreamGetFIFOW(pThis, pStrmSt))
             {
-                pBDLE->State.u32BufOff    += cbReadFromSink;
+                pBDLE->State.u32BufOff    += cbRead;
                 pBDLE->State.cbBelowFIFOW  = 0;
                 //hdaBackendReadTransferReported(pBDLE, cbDMAData, cbRead, &cbRead, pcbAvail);
@@ -2603,6 +2610,6 @@
             else
             {
-                pBDLE->State.u32BufOff    += cbReadFromSink;
-                pBDLE->State.cbBelowFIFOW += cbReadFromSink;
+                pBDLE->State.u32BufOff    += cbRead;
+                pBDLE->State.cbBelowFIFOW += cbRead;
                 Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStrmSt));
                 //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbRead, pcbAvail);
@@ -2613,8 +2620,5 @@
     }
 
-    //Assert(cbRead <= (SDFIFOS(pThis, pStrmSt->u8Strm) + 1));
-
-    LogFunc(("BDLE(off:%RU32, size:%RU32), cbTransferred=%RU32, rc=%Rrc\n",
-             pBDLE->State.u32BufOff, pBDLE->u32BufSize, cbRead, rc));
+    Assert(cbRead <= pStrmSt->u16FIFOS);
 
     if (RT_SUCCESS(rc))
@@ -2624,8 +2628,9 @@
     }
 
+    LogFunc(("Returning cbRead=%RU32, rc=%Rrc\n", cbRead, rc));
     return rc;
 }
 
-static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t *pcbWritten)
+static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax, uint32_t *pcbWritten)
 {
     AssertPtrReturn(pThis,      VERR_INVALID_POINTER);
@@ -2638,5 +2643,5 @@
 
     uint32_t cbWritten = 0;
-    uint32_t cbData    = hdaStreamGetTransferSize(pThis, pStrmSt);
+    uint32_t cbData    = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
 
     LogFlowFunc(("cbData=%RU32, %R[bdle]\n", cbData, pBDLE));
@@ -2924,5 +2929,5 @@
     {
         Assert(cbOutMin != UINT32_MAX);
-        hdaTransfer(pThis, PO_INDEX, NULL /* pcbProcessed */); /** @todo Add rc! */
+        hdaTransfer(pThis, PO_INDEX, cbOutMin /* cbMax */, NULL /* pcbProcessed */); /** @todo Add rc! */
     }
 
@@ -2931,5 +2936,5 @@
      */
     if (cbInMax)
-        hdaTransfer(pThis, PI_INDEX, NULL /* pcbProcessed */); /** @todo Add rc! */
+        hdaTransfer(pThis, PI_INDEX, cbInMax /* cbMax */, NULL /* pcbProcessed */); /** @todo Add rc! */
 
     TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->uTicks);
@@ -2954,5 +2959,5 @@
     AssertReturn(cbUser == sizeof(PDMAUDIOCALLBACKDATAIN), VERR_INVALID_PARAMETER);
 
-    return hdaTransfer(pCtx->pThis, PI_INDEX, &pData->cbOutRead);
+    return hdaTransfer(pCtx->pThis, PI_INDEX, UINT32_MAX, &pData->cbOutRead);
 }
 
@@ -2973,5 +2978,5 @@
     PHDASTATE pThis = pCtx->pThis;
 
-    int rc = hdaTransfer(pCtx->pThis, PO_INDEX, &pData->cbOutWritten);
+    int rc = hdaTransfer(pCtx->pThis, PO_INDEX, UINT32_MAX, &pData->cbOutWritten);
     if (   RT_SUCCESS(rc)
         && pData->cbOutWritten)
@@ -2988,10 +2993,10 @@
 #endif /* VBOX_WITH_AUDIO_CALLBACKS */
 
-static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t *pcbProcessed)
+static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbMax, uint32_t *pcbProcessed)
 {
     AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     /* pcbProcessed is optional. */
 
-    LogFlowFunc(("enmSrc=%RU32\n", enmSrc));
+    LogFlowFunc(("enmSrc=%RU32, cbMax=%RU32\n", enmSrc, cbMax));
 
     PHDASTREAM pStrmSt;
@@ -3045,13 +3050,14 @@
     }
 
-    Assert(pStrmSt->u8Strm <= 7); /** @todo Use a define for MAX_STRAEMS! */
+    Assert(pStrmSt->u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
     Assert(pStrmSt->u64BaseDMA);
     Assert(pStrmSt->u32CBL);
 
     int      rc;
+    uint32_t cbToProcess      = cbMax;
     uint32_t cbProcessedTotal = 0;
     bool     fIsComplete      = false;
 
-    do
+    while (cbToProcess)
     {
         /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
@@ -3066,12 +3072,12 @@
         {
             case PI_INDEX:
-                rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkLineIn, &cbProcessed);
+                rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkLineIn, cbToProcess, &cbProcessed);
                 break;
             case PO_INDEX:
-                rc = hdaWriteAudio(pThis, pStrmSt, &cbProcessed);
+                rc = hdaWriteAudio(pThis, pStrmSt, cbToProcess, &cbProcessed);
                 break;
 #ifdef VBOX_WITH_HDA_MIC_IN
             case MC_INDEX:
-                rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkMicIn, &cbProcessed);
+                rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkMicIn, cbToProcess, &cbProcessed);
                 break;
 #endif
@@ -3090,7 +3096,9 @@
         hdaStreamTransferUpdate(pThis, pStrmSt, cbProcessed);
 
+        cbToProcess      -= RT_MIN(cbToProcess,  cbProcessed);
         cbProcessedTotal += cbProcessed;
 
-        LogFlowFunc(("cbProcessed=%RU32, cbProcessedTotal=%RU32, rc=%Rrc\n", cbProcessed, cbProcessedTotal, rc));
+        LogFlowFunc(("cbProcessed=%RU32, cbToProcess=%RU32, cbProcessedTotal=%RU32, rc=%Rrc\n",
+                     cbProcessed, cbToProcess, cbProcessedTotal, rc));
 
         if (rc == VINF_EOF)
@@ -3100,5 +3108,7 @@
             fIsComplete = hdaStreamTransferIsComplete(pThis, pStrmSt);
 
-    } while (!fIsComplete);
+        if (fIsComplete)
+            break;
+    }
 
     if (RT_SUCCESS(rc))
