Index: /trunk/include/VBox/vmm/pdmaudioifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 88297)
+++ /trunk/include/VBox/vmm/pdmaudioifs.h	(revision 88298)
@@ -1690,4 +1690,5 @@
      * @returns VBox status code.
      * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @deprecated Just stub this and do the real work in the driver constructor.
      */
     DECLR3CALLBACKMEMBER(int, pfnInit, (PPDMIHOSTAUDIO pInterface));
@@ -1698,4 +1699,5 @@
      * @returns VBox status code.
      * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @deprecated Just stub this and do the real work in the driver destructor.
      */
     DECLR3CALLBACKMEMBER(void, pfnShutdown, (PPDMIHOSTAUDIO pInterface));
Index: /trunk/src/VBox/Devices/Audio/AudioMixer.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 88297)
+++ /trunk/src/VBox/Devices/Audio/AudioMixer.cpp	(revision 88298)
@@ -105,5 +105,5 @@
 static int audioMixerSinkSetRecSourceInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
 static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink);
-static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWrittenMin);
+static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
 static int audioMixerSinkWriteToStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream);
 static int audioMixerSinkWriteToStreamEx(PAUDMIXSINK pSink, PAUDMIXSTREAM pMixStream, uint32_t cbToWrite, uint32_t *pcbWritten);
@@ -114,56 +114,45 @@
 
 
+/** size of output buffer for dbgAudioMixerSinkStatusToStr.   */
+#define AUDIOMIXERSINK_STATUS_STR_MAX sizeof("RUNNING PENDING_DISABLE DIRTY 0x12345678")
+
 /**
  * Converts a mixer sink status to a string.
  *
- * @returns Stringified mixer sink status flags. Must be free'd with RTStrFree().
- *          "NONE" if no flags set.
- * @param   fStatus             Mixer sink status to convert.
- */
-static char *dbgAudioMixerSinkStatusToStr(AUDMIXSINKSTS fStatus)
-{
-#define APPEND_FLAG_TO_STR(_aFlag)              \
-    if (fStatus & AUDMIXSINK_STS_##_aFlag)      \
-    {                                           \
-        if (pszFlags)                           \
-        {                                       \
-            rc2 = RTStrAAppend(&pszFlags, " "); \
-            if (RT_FAILURE(rc2))                \
-                break;                          \
-        }                                       \
-                                                \
-        rc2 = RTStrAAppend(&pszFlags, #_aFlag); \
-        if (RT_FAILURE(rc2))                    \
-            break;                              \
-    }                                           \
-
-    char *pszFlags = NULL;
-    int rc2 = VINF_SUCCESS;
-
-    if (fStatus == AUDMIXSINK_STS_NONE) /* This is special, as this is value 0. */
-    {
-        rc2 = RTStrAAppend(&pszFlags, "NONE");
-    }
-    else
-    {
-        do
-        {
-            APPEND_FLAG_TO_STR(RUNNING);
-            APPEND_FLAG_TO_STR(PENDING_DISABLE);
-            APPEND_FLAG_TO_STR(DIRTY);
-
-        } while (0);
-    }
-
-    if (   RT_FAILURE(rc2)
-        && pszFlags)
-    {
-        RTStrFree(pszFlags);
-        pszFlags = NULL;
-    }
-
-#undef APPEND_FLAG_TO_STR
-
-    return pszFlags;
+ * @returns pszDst
+ * @param   fStatus     The mixer sink status.
+ * @param   pszDst      The output buffer.  Must be at least
+ *                      AUDIOMIXERSINK_STATUS_STR_MAX in length.
+ */
+static const char *dbgAudioMixerSinkStatusToStr(AUDMIXSINKSTS fStatus, char pszDst[AUDIOMIXERSINK_STATUS_STR_MAX])
+{
+    if (!fStatus)
+        return strcpy(pszDst, "NONE");
+    static const struct
+    {
+        const char *pszMnemonic;
+        uint32_t    cchMnemonic;
+        uint32_t    fStatus;
+    } s_aFlags[] =
+    {
+        { RT_STR_TUPLE("RUNNING"),          AUDMIXSINK_STS_RUNNING },
+        { RT_STR_TUPLE("PENDING_DISABLE"),  AUDMIXSINK_STS_PENDING_DISABLE },
+        { RT_STR_TUPLE("DIRTY"),            AUDMIXSINK_STS_DIRTY },
+    };
+    char *psz = pszDst;
+    for (size_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
+        if (fStatus & s_aFlags[i].fStatus)
+        {
+            memcpy(psz, s_aFlags[i].pszMnemonic, s_aFlags[i].cchMnemonic);
+            psz += s_aFlags[i].cchMnemonic;
+            fStatus &= ~s_aFlags[i].fStatus;
+            if (!fStatus)
+            {
+                psz[-1] = '\0';
+                return pszDst;
+            }
+        }
+    RTStrPrintf(psz, AUDIOMIXERSINK_STATUS_STR_MAX - (psz - pszDst), "%#x", fStatus);
+    return pszDst;
 }
 
@@ -811,8 +800,9 @@
     }
 
-    char *pszStatus = dbgAudioMixerSinkStatusToStr(pSink->fStatus);
-    LogRel2(("Audio Mixer: Set new status of sink '%s' to %s\n", pSink->pszName, pszStatus));
-    LogFlowFunc(("[%s] enmCmd=%RU32, fStatus=%s, rc=%Rrc\n", pSink->pszName, enmSinkCmd, pszStatus, rc));
-    RTStrFree(pszStatus);
+#if defined(RTLOG_REL_ENABLED) || defined(LOG_ENABLED)
+    char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX];
+#endif
+    LogRel2(("Audio Mixer: Set new status of sink '%s': %s (enmCmd=%RU32 rc=%Rrc)\n",
+             pSink->pszName, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus), enmSinkCmd, rc));
 
     int rc2 = RTCritSectLeave(&pSink->CritSect);
@@ -1284,8 +1274,8 @@
 
 #ifdef LOG_ENABLED
-    char *pszStatus = dbgAudioMixerSinkStatusToStr(pSink->fStatus);
-    Log2Func(("[%s] cbRead=%RU32, fClean=%RTbool, fStatus=%s, rc=%Rrc\n", pSink->pszName, cbRead, fClean, pszStatus, rc));
-    RTStrFree(pszStatus);
+    char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX];
 #endif
+    Log2Func(("[%s] cbRead=%RU32, fClean=%RTbool, fStatus=%s, rc=%Rrc\n",
+              pSink->pszName, cbRead, fClean, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus), rc));
 
     if (pcbRead)
@@ -1675,20 +1665,17 @@
     AssertPtrReturn(pSink, VERR_INVALID_POINTER);
 
-    int rc = VINF_SUCCESS;
-
 #ifdef LOG_ENABLED
-    char *pszStatus = dbgAudioMixerSinkStatusToStr(pSink->fStatus);
-    Log3Func(("[%s] fStatus=%s\n", pSink->pszName, pszStatus));
-    RTStrFree(pszStatus);
+    char szStatus[AUDIOMIXERSINK_STATUS_STR_MAX];
 #endif
+    Log3Func(("[%s] fStatus=%s\n", pSink->pszName, dbgAudioMixerSinkStatusToStr(pSink->fStatus, szStatus)));
 
     /* Sink disabled? Take a shortcut. */
     if (!(pSink->fStatus & AUDMIXSINK_STS_RUNNING))
-        return rc;
+        return VINF_SUCCESS;
 
     /* Input sink and no recording source set? Bail out early. */
     if (   pSink->enmDir == AUDMIXSINKDIR_INPUT
         && pSink->In.pStreamRecSource == NULL)
-        return rc;
+        return VINF_SUCCESS;
 
     /* Sanity. */
@@ -1710,9 +1697,10 @@
     uint32_t cbToWriteToStreams = AudioMixBufUsedBytes(&pSink->MixBuf);
 
+    int rc = VINF_SUCCESS;
     while (cbToWriteToStreams)
     {
         uint32_t cfChunk;
-        rc  = AudioMixBufAcquireReadBlock(&pSink->MixBuf, pSink->pabScratchBuf, RT_MIN(cbToWriteToStreams, (uint32_t)pSink->cbScratchBuf),
-                                          &cfChunk);
+        rc  = AudioMixBufAcquireReadBlock(&pSink->MixBuf, pSink->pabScratchBuf,
+                                          RT_MIN(cbToWriteToStreams, (uint32_t)pSink->cbScratchBuf), &cfChunk);
         if (RT_FAILURE(rc))
             break;
@@ -1723,5 +1711,5 @@
         /* Multiplex the current chunk in a synchronized fashion to all connected streams. */
         uint32_t cbChunkWrittenMin = 0;
-        rc = audioMixerSinkMultiplexSync(pSink, AUDMIXOP_COPY, pSink->pabScratchBuf, cbChunk, &cbChunkWrittenMin);
+        rc = audioMixerSinkMultiplexSync(pSink, pSink->pabScratchBuf, cbChunk, &cbChunkWrittenMin);
         if (RT_SUCCESS(rc))
         {
@@ -1931,8 +1919,7 @@
 
     const uint32_t cbWritableStream = pMixStream->pConn->pfnStreamGetWritable(pMixStream->pConn, pMixStream->pStream);
-                   cbToWrite        = RT_MIN(cbToWrite, RT_MIN((uint32_t)RTCircBufUsed(pCircBuf), cbWritableStream));
-
-    Log3Func(("[%s] cbWritableStream=%RU32, cbToWrite=%RU32\n",
-              pMixStream->pszName, cbWritableStream, cbToWrite));
+    cbToWrite = RT_MIN(cbToWrite, RT_MIN((uint32_t)RTCircBufUsed(pCircBuf), cbWritableStream));
+
+    Log3Func(("[%s] cbWritableStream=%RU32, cbToWrite=%RU32\n", pMixStream->pszName, cbWritableStream, cbToWrite));
 
     uint32_t cbWritten = 0;
@@ -1960,5 +1947,5 @@
                     break;
                 }
-                else if (rc == VERR_AUDIO_STREAM_NOT_READY)
+                if (rc == VERR_AUDIO_STREAM_NOT_READY)
                 {
                     /* Stream is not enabled, just skip. */
@@ -2003,83 +1990,71 @@
  *
  * @returns IPRT status code.
- * @param   pSink               Sink to write audio output to.
- * @param   enmOp               What mixing operation to use. Currently not implemented.
- * @param   pvBuf               Pointer to audio data to write.
- * @param   cbBuf               Size (in bytes) of audio data to write.
- * @param   pcbWrittenMin       Returns minimum size (in bytes) successfully written to all mixer streams. Optional.
- */
-static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf,
-                                       uint32_t *pcbWrittenMin)
-{
+ * @param   pSink       Sink to write audio output to.
+ * @param   pvBuf       Pointer to audio data to write.
+ * @param   cbBuf       Size (in bytes) of audio data to write.
+ * @param   pcbWritten  Returns the number of bytes written to each of the
+ *                      streams.
+ */
+static int audioMixerSinkMultiplexSync(PAUDMIXSINK pSink, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+{
+    Log3Func(("[%s] cbBuf=%RU32\n", pSink->pszName, cbBuf));
     AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
-    RT_NOREF(enmOp);
-
     AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT,
               ("%s: Can't multiplex to a sink which is not an output sink\n", pSink->pszName));
 
-    int rc = VINF_SUCCESS;
-
-    uint32_t cbToWriteMin = UINT32_MAX;
-
-    Log3Func(("[%s] cbBuf=%RU32\n", pSink->pszName, cbBuf));
-
+    /*
+     * Check all enabled streems for buffer space.
+     */
+    uint32_t      cbToWrite = UINT32_MAX;
     PAUDMIXSTREAM pMixStream;
     RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
     {
-        if (!(pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)) /* Mixing stream not enabled? Skip handling. */
-        {
+        if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)
+        {
+            uint32_t const cbCircFree = (uint32_t)RTCircBufFree(pMixStream->pCircBuf);
+            cbToWrite = RT_MIN(cbToWrite, cbCircFree);
+        }
+        else
             Log3Func(("[%s] Stream '%s' disabled, skipping ...\n", pSink->pszName, pMixStream->pszName));
-            continue;
-        }
-
-        cbToWriteMin = RT_MIN(cbBuf, RT_MIN(cbToWriteMin, (uint32_t)RTCircBufFree(pMixStream->pCircBuf)));
-    }
-
-    if (cbToWriteMin == UINT32_MAX) /* No space at all? */
-        cbToWriteMin = 0;
-
-    if (cbToWriteMin)
-    {
+    }
+    if (cbToWrite != UINT32_MAX)
+        cbToWrite = RT_MIN(cbBuf, cbToWrite);
+    else
+        cbToWrite = 0; /* No active streams at all. */
+    if (cbToWrite)
+    {
+        /*
+         * Do the copying.
+         */
         RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
         {
-            if (!(pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)) /* Mixing stream not enabled? Skip handling. */
-                continue;
-
-            PRTCIRCBUF pCircBuf = pMixStream->pCircBuf;
-            void *pvChunk;
-            size_t cbChunk;
-
-            uint32_t cbWrittenBuf = 0;
-            uint32_t cbToWriteBuf = cbToWriteMin;
-
-            while (cbToWriteBuf)
+            if (pMixStream->fStatus & AUDMIXSTREAM_STATUS_ENABLED)
             {
-                RTCircBufAcquireWriteBlock(pCircBuf, cbToWriteBuf, &pvChunk, &cbChunk);
-
-                if (cbChunk)
-                    memcpy(pvChunk, (uint8_t *)pvBuf + cbWrittenBuf, cbChunk);
-
-                RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
-
-                cbWrittenBuf += (uint32_t)cbChunk;
-                Assert(cbWrittenBuf <= cbBuf);
-
-                Assert(cbToWriteBuf >= cbChunk);
-                cbToWriteBuf -= (uint32_t)cbChunk;
+                PRTCIRCBUF pCircBuf   = pMixStream->pCircBuf;
+                size_t     offWritten = 0;
+                while (offWritten < cbToWrite)
+                {
+                    void  *pvChunk = NULL;
+                    size_t cbChunk = 0;
+                    RTCircBufAcquireWriteBlock(pCircBuf, cbToWrite - offWritten, &pvChunk, &cbChunk);
+
+                    memcpy(pvChunk, (uint8_t const *)pvBuf + offWritten, cbChunk);
+
+                    RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
+
+                    offWritten += cbChunk;
+                }
+                Assert(offWritten == cbToWrite);
+
+                pMixStream->tsLastReadWrittenNs = RTTimeNanoTS();
+                Log3Func(("[%s] Mixer stream '%s' -> cbWrittenBuf=%RU32\n", pSink->pszName, pMixStream->pszName, cbToWrite));
             }
-
-            if (cbWrittenBuf) /* Update the mixer stream's last written time stamp. */
-                pMixStream->tsLastReadWrittenNs = RTTimeNanoTS();
-
-            Log3Func(("[%s] Mixer stream '%s' -> cbWrittenBuf=%RU32\n", pSink->pszName, pMixStream->pszName, cbWrittenBuf));
-        }
-    }
-
-    Log3Func(("[%s] cbBuf=%RU32, cbToWriteMin=%RU32\n", pSink->pszName, cbBuf, cbToWriteMin));
-
-    if (pcbWrittenMin)
-        *pcbWrittenMin = cbToWriteMin;
-
-    return rc;
+        }
+    }
+
+    Log3Func(("[%s] cbBuf=%RU32, cbToWrite=%RU32\n", pSink->pszName, cbBuf, cbToWrite));
+
+    *pcbWritten = cbToWrite;
+    return VINF_SUCCESS;
 }
 
Index: /trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 88297)
+++ /trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 88298)
@@ -471,5 +471,5 @@
  * Controls an audio stream.
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  * @param   pStream             Stream to control.
@@ -579,5 +579,5 @@
  * If the stream has no backend available, VERR_NOT_FOUND is returned.
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  * @param   pStream             Stream to control.
@@ -710,5 +710,5 @@
  * The actual re-initialization will happen at some later point in time.
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  */
@@ -738,11 +738,13 @@
 
 /**
- * Re-initializes an audio stream with its existing host and guest stream configuration.
- * This might be the case if the backend told us we need to re-initialize because something
- * on the host side has changed.
- *
- * Note: Does not touch the stream's status flags.
- *
- * @returns IPRT status code.
+ * Re-initializes an audio stream with its existing host and guest stream
+ * configuration.
+ *
+ * This might be the case if the backend told us we need to re-initialize
+ * because something on the host side has changed.
+ *
+ * @note    Does not touch the stream's status flags.
+ *
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  * @param   pStream             Stream to re-initialize.
@@ -1140,5 +1142,5 @@
  * does the actual mixing between the guest <-> host mixing buffers.
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  * @param   pStream             Stream to iterate.
@@ -1516,5 +1518,5 @@
  * Captures non-interleaved input from a host stream.
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Driver instance.
  * @param   pStream             Stream to capture from.
@@ -1620,5 +1622,5 @@
  * Needed for e.g. the VRDP audio backend (in Main).
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Driver instance.
  * @param   pStream             Stream to capture from.
@@ -1935,5 +1937,5 @@
  * @note Must not hold the driver's critical section!
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Driver instance to be called.
  * @param   fLog                Whether to print the enumerated device to the release log or not.
@@ -2012,6 +2014,37 @@
 {
     LogFlowFuncEnter();
-    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
+
+    /*
+     * Check the function pointers, make sure the ones we define as
+     * mandatory are present.
+     */
+    PPDMIHOSTAUDIO pHostDrvAudio = pThis->pHostDrvAudio;
+    AssertPtrReturn(pHostDrvAudio, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnInit, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnShutdown, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnGetConfig, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnGetDevices, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnGetStatus, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnSetCallback, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamCreate, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamDestroy, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamControl, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamGetReadable, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamGetWritable, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnStreamGetPending, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamGetStatus, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamIterate, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnStreamPlayBegin, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamPlay, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnStreamPlayEnd, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnStreamCaptureBegin, VERR_INVALID_POINTER);
+    AssertPtrReturn(pHostDrvAudio->pfnStreamCapture, VERR_INVALID_POINTER);
+    AssertPtrNullReturn(pHostDrvAudio->pfnStreamCaptureEnd, VERR_INVALID_POINTER);
+
+    /*
+     * Call the init method.
+     */
+    /** @todo r=bird: This is superfluous.  This duplicates the driver
+     *        constructor code.  Just get rid of it!! */
     AssertPtr(pThis->pHostDrvAudio);
     int rc = pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio);
@@ -2037,8 +2070,6 @@
     LogFlowFunc(("cStreamsFreeIn=%RU8, cStreamsFreeOut=%RU8\n", pThis->In.cStreamsFree, pThis->Out.cStreamsFree));
 
-    LogRel2(("Audio: Host driver '%s' supports %RU32 input streams and %RU32 output streams at once\n",
-             pThis->szName,
-             /* Clamp for logging. Unlimited streams are defined by UINT32_MAX. */
-             RT_MIN(64, pThis->In.cStreamsFree), RT_MIN(64, pThis->Out.cStreamsFree)));
+    LogRel2(("Audio: Host driver '%s' supports %RU32 input streams and %RU32 output streams at once.\n",
+             pThis->szName, pThis->In.cStreamsFree, pThis->Out.cStreamsFree));
 
 #ifdef VBOX_WITH_AUDIO_ENUM
@@ -2089,5 +2120,7 @@
         PPDMAUDIOSTREAM pStream;
         RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, ListEntry)
+        {
             drvAudioStreamControlInternal(pThis, pStream, enmCmd);
+        }
     }
 
@@ -2453,5 +2486,5 @@
  * Worker for drvAudioStreamCreate that initializes the audio stream.
  *
- * @returns IPRT status code.
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  * @param   pStream             Stream to initialize.
@@ -3090,52 +3123,10 @@
 
 /**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
-{
-    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);
-    AssertPtr(pThis);
-
-    if (!pStream)
-        return VINF_SUCCESS;
-    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-    Assert(pStream->uMagic == PDMAUDIOSTREAM_MAGIC);
-
-    int rc = RTCritSectEnter(&pThis->CritSect);
-    AssertRCReturn(rc, rc);
-
-    LogRel2(("Audio: Destroying stream '%s'\n", pStream->szName));
-
-    LogFlowFunc(("[%s] cRefs=%RU32\n", pStream->szName, pStream->cRefs));
-    if (pStream->cRefs <= 1)
-    {
-        rc = drvAudioStreamUninitInternal(pThis, pStream);
-        if (RT_SUCCESS(rc))
-        {
-            if (pStream->enmDir == PDMAUDIODIR_IN)
-                pThis->In.cStreamsFree++;
-            else /* Out */
-                pThis->Out.cStreamsFree++;
-
-            RTListNodeRemove(&pStream->ListEntry);
-
-            drvAudioStreamFree(pStream);
-            pStream = NULL;
-        }
-        else
-            LogRel(("Audio: Uninitializing stream '%s' failed with %Rrc\n", pStream->szName, rc));
-    }
-    else
-        rc = VERR_WRONG_ORDER;
-
-    RTCritSectLeave(&pThis->CritSect);
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-/**
  * Calls the backend to give it the chance to destroy its part of the audio stream.
  *
- * @returns IPRT status code.
+ * Called from drvAudioPowerOff, drvAudioStreamUninitInternal and
+ * drvAudioStreamReInitInternal.
+ *
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  * @param   pStream             Audio stream destruct backend for.
@@ -3170,9 +3161,12 @@
 
 /**
- * Uninitializes an audio stream.
- *
- * @returns IPRT status code.
+ * Uninitializes an audio stream - worker for drvAudioStreamDestroy,
+ * drvAudioDestruct and drvAudioStreamCreate.
+ *
+ * @returns VBox status code.
  * @param   pThis               Pointer to driver instance.
  * @param   pStream             Pointer to audio stream to uninitialize.
+ *
+ * @note    Caller owns the critical section.
  */
 static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
@@ -3226,6 +3220,7 @@
         }
     }
-    else if (pStream->enmDir == PDMAUDIODIR_OUT)
-    {
+    else
+    {
+        Assert(pStream->enmDir == PDMAUDIODIR_OUT);
 #ifdef VBOX_WITH_STATISTICS
         PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.Stats.TotalFramesPlayed);
@@ -3243,8 +3238,52 @@
         }
     }
+
+    LogFlowFunc(("Returning %Rrc\n", rc));
+    return rc;
+}
+
+/**
+ * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy}
+ */
+static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+{
+    PDRVAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVAUDIO, IAudioConnector);
+    AssertPtr(pThis);
+
+    if (!pStream)
+        return VINF_SUCCESS;
+    AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+    Assert(pStream->uMagic == PDMAUDIOSTREAM_MAGIC);
+
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    AssertRCReturn(rc, rc);
+
+    LogRel2(("Audio: Destroying stream '%s'\n", pStream->szName));
+
+    LogFlowFunc(("[%s] cRefs=%RU32\n", pStream->szName, pStream->cRefs));
+    AssertMsg(pStream->cRefs <= 1, ("%u %s\n", pStream->cRefs, pStream->szName));
+    if (pStream->cRefs <= 1)
+    {
+        rc = drvAudioStreamUninitInternal(pThis, pStream);
+        if (RT_SUCCESS(rc))
+        {
+            if (pStream->enmDir == PDMAUDIODIR_IN)
+                pThis->In.cStreamsFree++;
+            else /* Out */
+                pThis->Out.cStreamsFree++;
+
+            RTListNodeRemove(&pStream->ListEntry);
+
+            drvAudioStreamFree(pStream);
+            pStream = NULL;
+        }
+        else
+            LogRel(("Audio: Uninitializing stream '%s' failed with %Rrc\n", pStream->szName, rc));
+    }
     else
-        AssertFailed();
-
-    LogFlowFunc(("Returning %Rrc\n", rc));
+        rc = VERR_WRONG_ORDER;
+
+    RTCritSectLeave(&pThis->CritSect);
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -3287,25 +3326,28 @@
     LogFlowFuncEnter();
 
-    if (!pThis->pHostDrvAudio) /* If not lower driver is configured, bail out. */
-        return;
-
-    /* Just destroy the host stream on the backend side.
-     * The rest will either be destructed by the device emulation or
-     * in drvAudioDestruct(). */
-    PPDMAUDIOSTREAM pStream;
-    RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, ListEntry)
-    {
-        drvAudioStreamControlInternalBackend(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
-        drvAudioStreamDestroyInternalBackend(pThis, pStream);
-    }
-
-    /*
-     * Last call for the driver below us.
-     * Let it know that we reached end of life.
-     */
-    if (pThis->pHostDrvAudio->pfnShutdown)
-        pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
-
-    pThis->pHostDrvAudio = NULL;
+    /** @todo locking?   */
+    if (pThis->pHostDrvAudio) /* If not lower driver is configured, bail out. */
+    {
+        /*
+         * Just destroy the host stream on the backend side.
+         * The rest will either be destructed by the device emulation or
+         * in drvAudioDestruct().
+         */
+        PPDMAUDIOSTREAM pStream;
+        RTListForEach(&pThis->lstStreams, pStream, PDMAUDIOSTREAM, ListEntry)
+        {
+            drvAudioStreamControlInternalBackend(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
+            drvAudioStreamDestroyInternalBackend(pThis, pStream);
+        }
+
+        /*
+         * Last call for the driver below us.
+         * Let it know that we reached end of life.
+         */
+        if (pThis->pHostDrvAudio->pfnShutdown)
+            pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
+
+        pThis->pHostDrvAudio = NULL;
+    }
 
     LogFlowFuncLeave();
@@ -3362,4 +3404,6 @@
              */
             rc = drvAudioHostInit(pThis);
+            if (RT_FAILURE(rc))
+                pThis->pHostDrvAudio = NULL;
         }
         else
@@ -3367,5 +3411,5 @@
             LogRel(("Audio: Failed to query interface for underlying host driver '%s'\n", pThis->szName));
             rc = PDMDRV_SET_ERROR(pThis->pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
-                                  N_("Host audio backend missing or invalid"));
+                                  N_("The host audio driver does not implement PDMIHOSTAUDIO!"));
         }
     }
