Index: /trunk/src/VBox/Devices/Audio/DevHDA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 82331)
+++ /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 82332)
@@ -1427,8 +1427,6 @@
                     AssertRC(rc2);
 
-                    rc2 = hdaR3TimerSet(pDevIns, pThis, pStream,
-                                          PDMDevHlpTimerGet(pDevIns, pThis->ahTimers[pStream->u8SD])
-                                        + pStream->State.cTransferTicks,
-                                        false /* fForce */);
+                    uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
+                    rc2 = hdaR3TimerSet(pDevIns, pStream, tsNow + pStream->State.cTransferTicks, false /* fForce */, tsNow);
                     AssertRC(rc2);
                 }
@@ -1521,5 +1519,5 @@
     HDA_PROCESS_INTERRUPT(pDevIns, pThis);
 
-    const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pThis->ahTimers[uSD]);
+    const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
     Assert(tsNow >= pStream->State.tsTransferLast);
 
@@ -1547,5 +1545,5 @@
             LogRelMax2(64, ("HDA: Stream #%RU8 interrupt lagging behind (expected %uus, got %uus), trying to catch up ...\n",
                             pStream->u8SD,
-                            (PDMDevHlpTimerGetFreq(pDevIns, pThis->ahTimers[pStream->u8SD]) / pThis->uTimerHz) / 1000,
+                            (PDMDevHlpTimerGetFreq(pDevIns, pStream->hTimer) / pThis->uTimerHz) / 1000,
                             (tsNow - pStream->State.tsTransferLast) / 1000));
 
@@ -1568,5 +1566,5 @@
             /* Re-arm the timer. */
             LogFunc(("Timer set SD%RU8\n", pStream->u8SD));
-            hdaR3TimerSet(pDevIns, pThis, pStream, tsNow + cTicksToNext, false /* fForce */);
+            hdaR3TimerSet(pDevIns, pStream, tsNow + cTicksToNext, true /* fForce - we just set tsTransferNext*/, 0 /*tsNow*/);
         }
     }
@@ -2860,11 +2858,10 @@
     if (fSinkActive)
     {
-        const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pDevIns, pStream);
+        uint64_t const tsNow = PDMDevHlpTimerGet(pDevIns, hTimer); /* (For virtual sync this remains the same for the whole callout IIRC) */
+        const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pStream, tsNow);
         Log3Func(("fSinksActive=%RTbool, fTimerScheduled=%RTbool\n", fSinkActive, fTimerScheduled));
         if (!fTimerScheduled)
-            hdaR3TimerSet(pDevIns, pThis, pStream,
-                            PDMDevHlpTimerGet(pDevIns, hTimer)
-                          + PDMDevHlpTimerGetFreq(pDevIns, hTimer) / pStream->pHDAState->uTimerHz,
-                          true /* fForce */);
+            hdaR3TimerSet(pDevIns, pStream, tsNow + PDMDevHlpTimerGetFreq(pDevIns, hTimer) / pThis->uTimerHz,
+                          true /*fForce*/, tsNow /*fixed*/ );
     }
     else
@@ -2911,5 +2908,5 @@
     }
 
-    switch(enmAccessType)
+    switch (enmAccessType)
     {
         case PGMACCESSTYPE_WRITE:
@@ -3628,6 +3625,6 @@
                 hdaR3StreamRegisterDMAHandlers(pThis, pStream);
 #endif
-                if (hdaR3StreamTransferIsScheduled(pDevIns, pStream))
-                    hdaR3TimerSet(pDevIns, pThis, pStream, hdaR3StreamTransferGetNext(pStream), true /* fForce */);
+                if (hdaR3StreamTransferIsScheduled(pStream, PDMDevHlpTimerGet(pDevIns, pStream->hTimer)))
+                    hdaR3TimerSet(pDevIns, pStream, hdaR3StreamTransferGetNext(pStream), true /*fForce*/, 0 /*tsNow*/);
 
                 /* Also keep track of the currently active streams. */
Index: /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp	(revision 82331)
+++ /trunk/src/VBox/Devices/Audio/DevHDACommon.cpp	(revision 82332)
@@ -665,8 +665,8 @@
  * @returns Whether the new expiration time was set or not.
  * @param   pDevIns     The device instance.
- * @param   pThis       HDA state.
  * @param   pStream     HDA stream to set timer for.
  * @param   tsExpire    New (virtual) expiration time to set.
  * @param   fForce      Whether to force setting the expiration time or not.
+ * @param   tsNow       The current clock timestamp if available, 0 if not.
  *
  * @remark  This function takes all active HDA streams and their
@@ -679,10 +679,10 @@
  *          Forcing a new expiration time will override the above mechanism.
  */
-bool hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStream, uint64_t tsExpire, bool fForce)
-{
-    AssertPtr(pThis);
+bool hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint64_t tsExpire, bool fForce, uint64_t tsNow)
+{
     AssertPtr(pStream);
 
-    uint64_t tsExpireMin = tsExpire;
+    if (!tsNow)
+        tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
 
     if (!fForce)
@@ -691,13 +691,11 @@
          * PDMDevHlpTimerGet(), so, some callers does one, this does, and then we do
          * right afterwards == very inefficient! */
-        if (hdaR3StreamTransferIsScheduled(pDevIns, pStream))
+        if (hdaR3StreamTransferIsScheduled(pStream, tsNow))
         {
             uint64_t const tsNext = hdaR3StreamTransferGetNext(pStream);
-            if (tsExpireMin > tsNext)
-                tsExpireMin = tsNext;
+            if (tsExpire > tsNext)
+                tsExpire = tsNext;
         }
     }
-
-    const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
 
     /*
@@ -705,8 +703,8 @@
      * This in theory could happen in hdaR3StreamTransferGetNext() from above.
      */
-    if (tsExpireMin < tsNow)
-        tsExpireMin = tsNow;
-
-    int rc = PDMDevHlpTimerSet(pDevIns, pStream->hTimer, tsExpireMin);
+    if (tsExpire < tsNow)
+        tsExpire = tsNow;
+
+    int rc = PDMDevHlpTimerSet(pDevIns, pStream->hTimer, tsExpire);
     AssertRCReturn(rc, false);
 
Index: /trunk/src/VBox/Devices/Audio/DevHDACommon.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 82331)
+++ /trunk/src/VBox/Devices/Audio/DevHDACommon.h	(revision 82332)
@@ -653,5 +653,5 @@
  */
 #ifdef IN_RING3
-bool          hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStream, uint64_t u64Expire, bool fForce);
+bool          hdaR3TimerSet(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint64_t u64Expire, bool fForce, uint64_t tsNow);
 #endif
 /** @} */
Index: /trunk/src/VBox/Devices/Audio/HDAStream.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 82331)
+++ /trunk/src/VBox/Devices/Audio/HDAStream.cpp	(revision 82332)
@@ -720,8 +720,8 @@
  *
  * @returns True if a next transfer is scheduled, false if not.
- * @param   pDevIns             The device instance.
  * @param   pStream             HDA stream to retrieve schedule status for.
- */
-bool hdaR3StreamTransferIsScheduled(PPDMDEVINS pDevIns, PHDASTREAM pStream)
+ * @param   tsNow               The current time.
+ */
+bool hdaR3StreamTransferIsScheduled(PHDASTREAM pStream, uint64_t tsNow)
 {
     if (pStream)
@@ -737,5 +737,4 @@
             }
 
-            const uint64_t tsNow = PDMDevHlpTimerGet(pDevIns, pStream->hTimer);
             if (pStream->State.tsTransferNext > tsNow)
             {
@@ -913,6 +912,7 @@
  * @param   pStream             HDA stream to update.
  * @param   cbToProcessMax      How much data (in bytes) to process as maximum.
- */
-int hdaR3StreamTransfer(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint32_t cbToProcessMax)
+ * @param   fInTimer            Set if we're in the timer callout.
+ */
+static int hdaR3StreamTransfer(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint32_t cbToProcessMax, bool fInTimer)
 {
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
@@ -1379,5 +1379,6 @@
 
         LogFunc(("Timer set SD%RU8\n", pStream->u8SD));
-        hdaR3TimerSet(pDevIns, pStream->pHDAState, pStream, tsTransferNext, false /* fForce */);
+        Assert(!fInTimer || tsNow == PDMDevHlpTimerGet(pDevIns, pStream->hTimer));
+        hdaR3TimerSet(pDevIns, pStream, tsTransferNext, true /* fForce - skip tsTransferNext check */, fInTimer ? tsNow : 0);
 
         pStream->State.tsTransferNext = tsTransferNext;
@@ -1450,5 +1451,5 @@
             {
                 /* Do the DMA transfer. */
-                rc2 = hdaR3StreamTransfer(pDevIns, pStream, cbStreamFree);
+                rc2 = hdaR3StreamTransfer(pDevIns, pStream, cbStreamFree, fInTimer);
                 AssertRC(rc2);
             }
@@ -1571,5 +1572,5 @@
             if (cbStreamUsed)
             {
-                rc2 = hdaR3StreamTransfer(pDevIns, pStream, cbStreamUsed);
+                rc2 = hdaR3StreamTransfer(pDevIns, pStream, cbStreamUsed, fInTimer);
                 AssertRC(rc2);
             }
Index: /trunk/src/VBox/Devices/Audio/HDAStream.h
===================================================================
--- /trunk/src/VBox/Devices/Audio/HDAStream.h	(revision 82331)
+++ /trunk/src/VBox/Devices/Audio/HDAStream.h	(revision 82332)
@@ -272,7 +272,6 @@
 uint32_t          hdaR3StreamGetFree(PHDASTREAM pStream);
 uint32_t          hdaR3StreamGetUsed(PHDASTREAM pStream);
-bool              hdaR3StreamTransferIsScheduled(PPDMDEVINS pDevIns, PHDASTREAM pStream);
+bool              hdaR3StreamTransferIsScheduled(PHDASTREAM pStream, uint64_t tsNow);
 uint64_t          hdaR3StreamTransferGetNext(PHDASTREAM pStream);
-int               hdaR3StreamTransfer(PPDMDEVINS pDevIns, PHDASTREAM pStream, uint32_t cbToProcessMax);
 void              hdaR3StreamLock(PHDASTREAM pStream);
 void              hdaR3StreamUnlock(PHDASTREAM pStream);
