Index: trunk/src/VBox/Devices/Audio/DevHDA.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 67387)
+++ trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 67400)
@@ -47,4 +47,5 @@
 #include "AudioMixer.h"
 #include "HDACodec.h"
+#include "HDAStreamPeriod.h"
 #include "DevHDACommon.h"
 #include "DrvAudio.h"
@@ -570,4 +571,6 @@
      *  Used to calculate the time actually elapsed between two transfers. */
     uint64_t                uTimerTS;
+    /** The stream's period. Need for timing. */
+    HDASTREAMPERIOD         Period;
     /** The stream's current configuration.
      *  Should match SDFMT. */
@@ -700,5 +703,5 @@
     uint8_t               Padding[7];
     /** Pointer to associated stream. */
-    R3PTRTYPE(PHDASTREAM) pStrm;
+    R3PTRTYPE(PHDASTREAM) pStream;
 } HDATAG, *PHDATAG;
 
@@ -884,5 +887,9 @@
     HDAMIXERSINK                       SinkMicIn;
 #endif
+    /** The controller's base time stamp which the WALCLK register
+     *  derives its current value from. */
     uint64_t                           u64BaseTS;
+    /** Last updated WALCLK counter. */
+    uint64_t                           u64WalClk;
     /** Response Interrupt Count (RINTCNT). */
     uint8_t                            u8RespIntCnt;
@@ -1041,4 +1048,12 @@
 /** @} */
 
+/** @name Wall clock (WALCLK) functions.
+ * @{
+ */
+uint64_t          hdaWalClkGetCurrent(PHDASTATE pThis);
+#ifdef IN_RING3
+bool              hdaWalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce);
+#endif
+/** @} */
 
 /*********************************************************************************************************************************
@@ -2205,13 +2220,145 @@
 }
 
+/**
+ * Retrieves the currently set value for the wall clock.
+ *
+ * @return  IPRT status code.
+ * @return  Currently set wall clock value.
+ * @param   pThis               HDA state.
+ *
+ * @remark  Operation is atomic.
+ */
+uint64_t hdaWalClkGetCurrent(PHDASTATE pThis)
+{
+    return ASMAtomicReadU64(&pThis->u64WalClk);
+}
+
+#ifdef IN_RING3
+/**
+ * Returns the current maximum value the wall clock counter can be set to.
+ * This maximum value depends on all currently handled HDA streams and their own current timing.
+ *
+ * @return  Current maximum value the wall clock counter can be set to.
+ * @param   pThis               HDA state.
+ *
+ * @remark  Does not actually set the wall clock counter.
+ */
+uint64_t hdaWalClkGetMax(PHDASTATE pThis)
+{
+    const uint64_t u64WalClkCur       = ASMAtomicReadU64(&pThis->u64WalClk);
+    const uint64_t u64FrontAbsWalClk  = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkFront)->State.Period);
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+# error "Implement me!"
+#endif
+    const uint64_t u64LineInAbsWalClk = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkLineIn)->State.Period);
+#ifdef VBOX_WITH_HDA_MIC_IN
+    const uint64_t u64MicInAbsWalClk  = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkMicIn)->State.Period);
+#endif
+
+    uint64_t u64WalClkNew = RT_MAX(u64WalClkCur, u64FrontAbsWalClk);
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+# error "Implement me!"
+#endif
+             u64WalClkNew = RT_MAX(u64WalClkNew, u64LineInAbsWalClk);
+#ifdef VBOX_WITH_HDA_MIC_IN
+             u64WalClkNew = RT_MAX(u64WalClkNew, u64MicInAbsWalClk);
+#endif
+
+    Log3Func(("%RU64 -> Front=%RU64, LineIn=%RU64 -> %RU64\n",
+              u64WalClkCur, u64FrontAbsWalClk, u64LineInAbsWalClk, u64WalClkNew));
+
+    return u64WalClkNew;
+}
+
+/**
+ * Sets the actual WALCLK register to the specified wall clock value.
+ * The specified wall clock value only will be set (unless fForce is set to \c @true) if all
+ * handled HDA streams have passed (in time) that value. This guarantees that the WALCLK
+ * register stays in sync with all handled HDA streams.
+ *
+ * @return  \c @true if the WALCLK register has been updated, \c @false if not.
+ * @param   pThis               HDA state.
+ * @param   u64WalClk           Wall clock value to set WALCLK register to.
+ * @param   fForce              Whether to force setting the wall clock value or not.
+ */
+bool hdaWalClkSet(PHDASTATE pThis, uint64_t u64WalClk, bool fForce)
+{
+    const bool     fFrontPassed       = hdaStreamPeriodHasPassedAbsWalClk (&hdaSinkGetStream(pThis, &pThis->SinkFront)->State.Period,
+                                                                           u64WalClk);
+    const uint64_t u64FrontAbsWalClk  = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkFront)->State.Period);
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+# error "Implement me!"
+#endif
+
+    const bool     fLineInPassed      = hdaStreamPeriodHasPassedAbsWalClk (&hdaSinkGetStream(pThis, &pThis->SinkLineIn)->State.Period, u64WalClk);
+    const uint64_t u64LineInAbsWalClk = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkLineIn)->State.Period);
+#ifdef VBOX_WITH_HDA_MIC_IN
+    const bool     fMicInPassed       = hdaStreamPeriodHasPassedAbsWalClk (&hdaSinkGetStream(pThis, &pThis->SinkMicIn)->State.Period,  u64WalClk);
+    const uint64_t u64MicInAbsWalClk  = hdaStreamPeriodGetAbsElapsedWalClk(&hdaSinkGetStream(pThis, &pThis->SinkMicIn)->State.Period);
+#endif
+
+#ifdef VBOX_STRICT
+    const uint64_t u64WalClkCur = ASMAtomicReadU64(&pThis->u64WalClk);
+#endif
+          uint64_t u64WalClkSet = u64WalClk;
+
+    /* Only drive the WALCLK register forward if all (active) stream periods have passed
+     * the specified point in time given by u64WalClk. */
+    if (  (   fFrontPassed
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+# error "Implement me!"
+#endif
+           && fLineInPassed
+#ifdef VBOX_WITH_HDA_MIC_IN
+           && fMicInPassed
+#endif
+          )
+       || fForce)
+    {
+        if (!fForce)
+        {
+            /* Get the maximum value of all periods we need to handle.
+             * Not the most elegant solution, but works for now ... */
+            u64WalClk = RT_MAX(u64WalClkSet, u64FrontAbsWalClk);
+#ifdef VBOX_WITH_AUDIO_HDA_51_SURROUND
+# error "Implement me!"
+#endif
+            u64WalClk = RT_MAX(u64WalClkSet, u64LineInAbsWalClk);
+#ifdef VBOX_WITH_HDA_MIC_IN
+            u64WalClk = RT_MAX(u64WalClkSet, u64MicInAbsWalClk);
+#endif
+            AssertMsg(u64WalClkSet > u64WalClkCur,
+                      ("Setting WALCLK to a stale or backward value (%RU64 -> %RU64) isn't a good idea really. "
+                       "Good luck with stuck audio stuff.\n", u64WalClkCur, u64WalClkSet));
+        }
+
+        /* Set the new WALCLK value. */
+        ASMAtomicWriteU64(&pThis->u64WalClk, u64WalClkSet);
+    }
+
+    const uint64_t u64WalClkNew = hdaWalClkGetCurrent(pThis);
+
+    Log3Func(("Cur: %RU64, New: %RU64 (force %RTbool) -> %RU64 %s\n",
+              u64WalClkCur, u64WalClk, fForce,
+              u64WalClkNew, u64WalClkNew == u64WalClk ? "[OK]" : "[DELAYED]"));
+
+    return (u64WalClkNew == u64WalClk);
+}
+#endif /* IN_RING3 */
+
 static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
 {
-    RT_NOREF_PV(iReg);
-
-    /* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */
-    *pu32Value = (uint32_t)ASMMultU64ByU32DivByU32(PDMDevHlpTMTimeVirtGetNano(pThis->CTX_SUFF(pDevIns))
-                                                   - pThis->u64BaseTS, 24, 1000);
-    LogFlowFunc(("%RU32\n", *pu32Value));
+#ifdef IN_RING3
+    RT_NOREF(iReg);
+
+    *pu32Value = RT_LO_U32(ASMAtomicReadU64(&pThis->u64WalClk));
+
+    Log3Func(("%RU32 (max @ %RU64)\n",*pu32Value, hdaWalClkGetMax(pThis)));
+
     return VINF_SUCCESS;
+#else
+    RT_NOREF(pThis, iReg, pu32Value);
+    return VINF_IOM_R3_MMIO_WRITE;
+#endif
 }
 
@@ -2352,8 +2499,8 @@
 
     /* Assign new values. */
-    pTag->uTag  = uTag;
-    pTag->pStrm = hdaStreamGetFromSD(pThis, uSD);
-
-    PHDASTREAM pStream = pTag->pStrm;
+    pTag->uTag    = uTag;
+    pTag->pStream = hdaStreamGetFromSD(pThis, uSD);
+
+    PHDASTREAM pStream = pTag->pStream;
     AssertPtr(pStream);
 
@@ -3129,5 +3276,5 @@
  * Registers access handlers for a stream's BDLE DMA accesses.
  *
- * @returns @true if registration was successful, @false if not.
+ * @returns \c @true if registration was successful, \c @false if not.
  * @param   pThis               HDA state.
  * @param   pStream             HDA stream to register BDLE access handlers for.
Index: trunk/src/VBox/Devices/Audio/HDAStreamPeriod.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/HDAStreamPeriod.cpp	(revision 67387)
+++ trunk/src/VBox/Devices/Audio/HDAStreamPeriod.cpp	(revision 67400)
@@ -99,5 +99,5 @@
     pPeriod->u8SD              = u8SD;
     pPeriod->u64StartWalClk    = 0;
-    pPeriod->u32Hz             = pStreamCfg->uHz;
+    pPeriod->u32Hz             = pStreamCfg->Props.uHz;
     pPeriod->u64DurationWalClk = hdaStreamPeriodFramesToWalClk(pPeriod, framesToTransfer);
     pPeriod->u64ElapsedWalClk  = 0;
