Index: /trunk/src/VBox/Devices/Audio/DevHDA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 65094)
+++ /trunk/src/VBox/Devices/Audio/DevHDA.cpp	(revision 65095)
@@ -642,4 +642,6 @@
     /** Shutdown indicator. */
     volatile bool         fShutdown;
+    /** Whether the thread should do any data processing or not. */
+    volatile bool         fEnabled;
     uint32_t              Padding1;
 } HDASTREAMSTATEAIO, *PHDASTREAMSTATEAIO;
@@ -1005,4 +1007,6 @@
 static int           hdaStreamUpdate(PHDASTATE pThis, PHDASTREAM pStream);
 DECLINLINE(uint32_t) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStream, uint32_t u32LPIB);
+static void          hdaStreamLock(PHDASTREAM pStream);
+static void          hdaStreamUnlock(PHDASTREAM pStream);
 #endif /* IN_RING3 */
 /** @} */
@@ -1019,4 +1023,5 @@
 static void              hdaStreamAsyncIOLock(PHDASTREAM pStream);
 static void              hdaStreamAsyncIOUnlock(PHDASTREAM pStream);
+static void              hdaStreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable);
 # endif
 #endif
@@ -1306,4 +1311,32 @@
 
 /**
+ * Locks an HDA stream for serialized access.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to lock.
+ */
+static void hdaStreamLock(PHDASTREAM pStream)
+{
+    AssertPtrReturnVoid(pStream);
+    int rc2 = RTCritSectEnter(&pStream->State.CritSect);
+    AssertRC(rc2);
+}
+
+
+/**
+ * Unlocks a formerly locked HDA stream.
+ *
+ * @returns IPRT status code.
+ * @param   pStream             HDA stream to unlock.
+ */
+static void hdaStreamUnlock(PHDASTREAM pStream)
+{
+    AssertPtrReturnVoid(pStream);
+    int rc2 = RTCritSectLeave(&pStream->State.CritSect);
+    AssertRC(rc2);
+}
+
+
+/**
  * Fetches the next BDLE to use for a stream.
  *
@@ -1809,15 +1842,4 @@
     LogFunc(("[SD%RU8]: Reset\n", uSD));
 
-    int rc2;
-#ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
-    /*
-     * Make sure to destroy the async I/O thread for this stream on reset, as we
-     * can't be sure that the same stream is being used in the next cycle
-     * (and therefore would leave unused threads around).
-     */
-    rc2 = hdaStreamAsyncIODestroy(pThis, pStream);
-    AssertRC(rc2);
-#endif
-
     /*
      * First, reset the internal stream state.
@@ -1854,5 +1876,5 @@
     HDA_STREAM_REG(pThis, BDPL,  uSD) = 0;
 
-    rc2 = hdaStreamInit(pThis, pStream, uSD);
+    int rc2 = hdaStreamInit(pThis, pStream, uSD);
     AssertRC(rc2);
 }
@@ -1863,10 +1885,13 @@
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
 
-    LogFlowFunc(("[SD%RU8]: fEnable=%RTbool, pMixSink=%p\n", pStream->u8SD, fEnable, pStream->pMixSink));
+    LogFunc(("[SD%RU8]: fEnable=%RTbool, pMixSink=%p\n", pStream->u8SD, fEnable, pStream->pMixSink));
 
     int rc = VINF_SUCCESS;
+
+    hdaStreamLock(pStream);
 
 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
     hdaStreamAsyncIOLock(pStream);
+    hdaStreamAsyncIOEnable(pStream, fEnable);
 #endif
 
@@ -1880,6 +1905,4 @@
             rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
     }
-    else
-        rc = VINF_SUCCESS;
 
 #ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
@@ -1887,40 +1910,17 @@
 #endif
 
-    if (RT_FAILURE(rc))
-    {
-        LogFunc(("Failed with rc=%Rrc\n", rc));
-        return rc;
-    }
-
+    /* Make sure to leave the lock before (eventually) starting the timer. */
+    hdaStreamUnlock(pStream);
+
+#ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
     /* Second, see if we need to start or stop the timer. */
     if (!fEnable)
-    {
-# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
         hdaTimerMaybeStop(pThis);
-# endif
-    }
     else
-    {
-# ifndef VBOX_WITH_AUDIO_HDA_CALLBACKS
         hdaTimerMaybeStart(pThis);
-# endif
-    }
-
-    LogFlowFunc(("u8Strm=%RU8, fEnable=%RTbool, cStreamsActive=%RU8\n", pStream->u8SD, fEnable, pThis->cStreamsActive));
-    return VINF_SUCCESS;
-}
-
-static void hdaStreamAssignToSink(PHDASTREAM pStream, PHDAMIXERSINK pMixSink)
-{
-    AssertPtrReturnVoid(pStream);
-
-    int rc2 = RTCritSectEnter(&pStream->State.CritSect);
-    if (RT_SUCCESS(rc2))
-    {
-        pStream->pMixSink = pMixSink;
-
-        rc2 = RTCritSectLeave(&pStream->State.CritSect);
-        AssertRC(rc2);
-    }
+#endif
+
+    LogFunc(("[SD%RU8]: cStreamsActive=%RU8, rc=%Rrc\n", pStream->u8SD, pThis->cStreamsActive, rc));
+    return rc;
 }
 
@@ -2371,8 +2371,4 @@
     AssertPtr(pStream);
 
-    /* Note: Do not use hdaRegWriteSDLock() here, as SDnCTL might change the RUN bit. */
-    int rc2 = RTCritSectEnter(&pStream->State.CritSect);
-    AssertRC(rc2);
-
     if (fInReset)
     {
@@ -2399,5 +2395,9 @@
         ASMAtomicXchgBool(&pStream->State.fInReset, true);
 
+        hdaStreamLock(pStream);
+
         hdaStreamReset(pThis, pStream);
+
+        hdaStreamUnlock(pStream);
     }
     else
@@ -2414,5 +2414,5 @@
             {
                 /* Make sure to first fetch the current BDLE before enabling the stream below. */
-                rc2 = hdaBDLEFetch(pThis, &pStream->State.BDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
+                int rc2 = hdaBDLEFetch(pThis, &pStream->State.BDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
                 AssertRC(rc2);
             }
@@ -2422,12 +2422,9 @@
     }
 
-    rc2 = hdaRegWriteU24(pThis, iReg, u32Value);
+    int rc2 = hdaRegWriteU24(pThis, iReg, u32Value);
     AssertRC(rc2);
 
     /* Make sure to handle interrupts here as well. */
     hdaProcessInterrupt(pThis);
-
-    rc2 = RTCritSectLeave(&pStream->State.CritSect);
-    AssertRC(rc2);
 
     return VINF_SUCCESS; /* Always return success to the MMIO handler. */
@@ -3658,4 +3655,6 @@
  * @param   pThis               HDA state.
  * @param   enmMixerCtl         Mixer control to remove.
+ *
+ * @remarks Can be called as a callback by the HDA codec.
  */
 static DECLCALLBACK(int) hdaMixerRemoveStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
@@ -3736,4 +3735,6 @@
  * @param   uSD                 SD stream number (number + 1) to set. Set to 0 for unassign.
  * @param   uChannel            Channel to set. Only valid if a valid SD stream number is specified.
+ *
+ * @remarks Can be called as a callback by the HDA codec.
  */
 static DECLCALLBACK(int) hdaMixerSetStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
@@ -3771,9 +3772,11 @@
         if (pStream)
         {
-            pSink->uSD      = uSD;
-            pSink->uChannel = uChannel;
-
-            /* Make sure that the stream also has this sink set. */
-            hdaStreamAssignToSink(pStream, pSink);
+            hdaStreamLock(pStream);
+
+            pSink->uSD        = uSD;
+            pSink->uChannel   = uChannel;
+            pStream->pMixSink = pSink;
+
+            hdaStreamUnlock(pStream);
 
             rc = VINF_SUCCESS;
@@ -3800,4 +3803,6 @@
  * @param   enmMixerCtl         Mixer control to set volume for.
  * @param   pVol                Pointer to volume data to set.
+ *
+ * @remarks Can be called as a callback by the HDA codec.
  */
 static DECLCALLBACK(int) hdaMixerSetVolume(PHDASTATE pThis,
@@ -4407,4 +4412,10 @@
         if (RT_SUCCESS(rc2))
         {
+            if (!pAIO->fEnabled)
+            {
+                RTCritSectLeave(&pAIO->CritSect);
+                continue;
+            }
+
             uint32_t cbToProcess;
             uint32_t cbProcessed = 0;
@@ -4566,4 +4577,18 @@
     AssertRC(rc2);
 }
+
+/**
+ * Enables (resumes) or disables (pauses) the async I/O thread.
+ *
+ * @param   pStream             HDA stream to enable/disable async I/O thread for.
+ * @param   fEnable             Whether to enable or disable the I/O thread.
+ *
+ * @remarks Does not do locking.
+ */
+static void hdaStreamAsyncIOEnable(PHDASTREAM pStream, bool fEnable)
+{
+    PHDASTREAMSTATEAIO pAIO = &pStream->State.AIO;
+    ASMAtomicXchgBool(&pAIO->fEnabled, fEnable);
+}
 #endif /* VBOX_WITH_AUDIO_HDA_ASYNC_IO */
 
@@ -4586,4 +4611,6 @@
     AssertPtrReturn(pStream, VERR_INVALID_POINTER);
 
+    hdaStreamLock(pStream);
+
     PHDAMIXERSINK pSink  = pStream->pMixSink;
     AssertPtr(pSink);
@@ -4593,9 +4620,10 @@
 
     if (!AudioMixerSinkIsActive(pSink->pMixSink))
+    {
+        hdaStreamUnlock(pStream);
         return VINF_SUCCESS;
+    }
 
     Log2Func(("[SD%RU8]\n", pStream->u8SD));
-
-    int rc = VINF_SUCCESS;
 
     bool fDone = false;
@@ -4735,5 +4763,7 @@
     } /* while !fDone */
 
-    return rc;
+    hdaStreamUnlock(pStream);
+
+    return VINF_SUCCESS;
 }
 #endif /* IN_RING3 */
