Index: trunk/include/VBox/err.h
===================================================================
--- trunk/include/VBox/err.h	(revision 88781)
+++ trunk/include/VBox/err.h	(revision 88819)
@@ -2930,4 +2930,9 @@
 /** Generic audio device enumeration error. */
 #define VERR_AUDIO_ENUMERATION_FAILED               (-6607)
+/** Asynchronous stream initialization still on-going. */
+#define VERR_AUDIO_STREAM_INIT_IN_PROGRESS          (-6608)
+/** Special PDMIHOSTAUDIO::pfnStreamCreate return value for triggering
+ * calling of PDMIHOSTAUDIO::pfnStreamInitAsync on a worker thread. */
+#define VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED         (6609)
 /** @} */
 
Index: trunk/include/VBox/vmm/pdmaudioifs.h
===================================================================
--- trunk/include/VBox/vmm/pdmaudioifs.h	(revision 88781)
+++ trunk/include/VBox/vmm/pdmaudioifs.h	(revision 88819)
@@ -439,5 +439,5 @@
     /** The size of the backend specific stream data (in bytes). */
     uint32_t        cbStream;
-    /** Flags, MBZ. */
+    /** PDMAUDIOBACKEND_F_XXX. */
     uint32_t        fFlags;
     /** Number of concurrent output (playback) streams supported on the host.
@@ -450,4 +450,12 @@
 /** Pointer to a static host audio audio configuration. */
 typedef PDMAUDIOBACKENDCFG *PPDMAUDIOBACKENDCFG;
+
+/** @name PDMAUDIOBACKEND_F_XXX - PDMAUDIOBACKENDCFG::fFlags
+ * @{ */
+/** PDMIHOSTAUDIO::pfnStreamConfigHint should preferably be called on a
+ *  worker thread rather than EMT as it may take a good while. */
+#define PDMAUDIOBACKEND_F_ASYNC_HINT    RT_BIT_32(0)
+/** @} */
+
 
 /**
@@ -904,20 +912,22 @@
 /** No flags being set. */
 #define PDMAUDIOSTREAM_STS_NONE                 UINT32_C(0)
-/** Set if the backend for the stream has been initialized.
+/** Set if the backend for the stream has been created.
  *
  * PDMIAUDIOCONNECTOR: This is generally always set after stream creation, but
  * can be cleared if the re-initialization of the stream fails later on.
+ * Asynchronous init may still be incomplete, see
  *
  * PDMIHOSTAUDIO: This may not be set immediately if the backend is doing some
- * of the stream creation asynchronously.  The DrvAudio code will not report
- * this to the devices, but keep on prebuffering till it is set. */
+ * of the stream creation asynchronously via PDMIHOSTAUDIO::pfnStreamInitAsync.
+ * The DrvAudio code will not report this to the devices, but keep on
+ * prebuffering till pfnStreamInitAsync is done and this bit is set. */
 #define PDMAUDIOSTREAM_STS_INITIALIZED          RT_BIT_32(0)
 /** Set if the stream is enabled, clear if disabled. */
 #define PDMAUDIOSTREAM_STS_ENABLED              RT_BIT_32(1)
 /** Set if the stream is paused.
- * Requires enabled status to be set when used. */
+ * Requires the ENABLED status to be set when used. */
 #define PDMAUDIOSTREAM_STS_PAUSED               RT_BIT_32(2)
 /** Output only: Set when the stream is draining.
- * Requires the enabled status to be set when used.
+ * Requires the ENABLED status to be set when used.
  * @todo See todo in drvAudioStreamPlay() regarding the suitability of this
  *       for PDMIHOSTAUDIO. */
@@ -929,6 +939,9 @@
  * stream can resume operation where it left off.)  */
 #define PDMAUDIOSTREAM_STS_NEED_REINIT          RT_BIT_32(8)
+/** PDMIAUDIOCONNECTOR: The backend is ready (PDMIHOSTAUDIO::pfnStreamInitAsync  done).
+ * Requires the INITIALIZED status to be set.  */
+#define PDMAUDIOSTREAM_STS_BACKEND_READY        RT_BIT_32(9)
 /** Validation mask for PDMIAUDIOCONNECTOR. */
-#define PDMAUDIOSTREAM_STS_VALID_MASK           UINT32_C(0x0000010f)
+#define PDMAUDIOSTREAM_STS_VALID_MASK           UINT32_C(0x0000030f)
 /** Asserts the validity of the given stream status mask for PDMIAUDIOCONNECTOR. */
 #define PDMAUDIOSTREAM_STS_ASSERT_VALID(a_fStreamStatus) do { \
@@ -936,9 +949,10 @@
         Assert(!((a_fStreamStatus) & PDMAUDIOSTREAM_STS_PAUSED)          || ((a_fStreamStatus) & PDMAUDIOSTREAM_STS_ENABLED)); \
         Assert(!((a_fStreamStatus) & PDMAUDIOSTREAM_STS_PENDING_DISABLE) || ((a_fStreamStatus) & PDMAUDIOSTREAM_STS_ENABLED)); \
+        Assert(!((a_fStreamStatus) & PDMAUDIOSTREAM_STS_BACKEND_READY)   || ((a_fStreamStatus) & PDMAUDIOSTREAM_STS_INITIALIZED)); \
     } while (0)
 
 /** PDMIHOSTAUDIO: Backend is preparing a device switch, DrvAudio should
  * pre-buffer to make that smoother and quicker.
- * Call PDMIAUDIONOTIFYFROMHOST::pfnStreamNotifyDeviceChanged when clearing. */
+ * Call PDMIHOSTAUDIOPORT::pfnStreamNotifyDeviceChanged when clearing. */
 #define PDMAUDIOSTREAM_STS_PREPARING_SWITCH     RT_BIT_32(16)
 /** Validation mask for PDMIHOSTAUDIO. */
@@ -996,9 +1010,4 @@
     /** Magic value (PDMAUDIOSTREAM_MAGIC). */
     uint32_t                uMagic;
-    /** Number of references to this stream.
-     *  Only can be destroyed when the reference count reaches 0. */
-    uint32_t volatile       cRefs;
-    /** Stream status - PDMAUDIOSTREAM_STS_XXX. */
-    uint32_t                fStatus;
     /** Audio direction of this stream. */
     PDMAUDIODIR             enmDir;
@@ -1021,5 +1030,5 @@
 
 /** Magic value for PDMAUDIOSTREAM. */
-#define PDMAUDIOSTREAM_MAGIC    PDM_VERSION_MAKE(0xa0d3, 3, 0)
+#define PDMAUDIOSTREAM_MAGIC    PDM_VERSION_MAKE(0xa0d3, 4, 0)
 
 
@@ -1303,4 +1312,27 @@
 
     /**
+     * Callback for genric on-worker-thread requests initiated by the backend itself.
+     *
+     * This is the counterpart to PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread that will
+     * be invoked on a worker thread when the backend requests it - optional.
+     *
+     * This does not return a value, so the backend must keep track of
+     * failure/success on its own.
+     *
+     * This method is optional.  A non-NULL will, together with pfnStreamInitAsync
+     * and PDMAUDIOBACKEND_F_ASYNC_HINT, force DrvAudio to create the thread pool.
+     *
+     * @param   pInterface  Pointer to this interface.
+     * @param   pStream     Optionally a backend stream if specified in the
+     *                      PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call.
+     * @param   uUser       User specific value as specified in the
+     *                      PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call.
+     * @param   pvUser      User specific pointer as specified in the
+     *                      PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnDoOnWorkerThread,(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
+                                                    uintptr_t uUser, void *pvUser));
+
+    /**
      * Gives the audio backend a hint about a typical configuration (optional).
      *
@@ -1311,4 +1343,8 @@
      * configuring host audio.
      *
+     * The backend can return PDMAUDIOBACKEND_F_ASYNC_HINT in
+     * PDMIHOSTAUDIO::pfnGetConfig to avoid having EMT making this call and thereby
+     * speeding up VM construction.
+     *
      * @param   pInterface      Pointer to this interface.
      * @param   pCfg            The typical configuration.  (Feel free to change it
@@ -1325,4 +1361,6 @@
      *
      * @returns VBox status code.
+     * @retval  VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED if
+     *          PDMIHOSTAUDIO::pfnStreamInitAsync should be called.
      * @param   pInterface          Pointer to the interface structure containing the called function pointer.
      * @param   pStream             Pointer to audio stream.
@@ -1336,4 +1374,21 @@
 
     /**
+     * Asynchronous stream initialization step, optional.
+     *
+     * This is called on a worker thread iff the PDMIHOSTAUDIO::pfnStreamCreate
+     * method returns VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to this interface.
+     * @param   pStream             Pointer to audio stream to continue
+     *                              initialization of.
+     * @param   fDestroyed          Set to @c true if the stream has been destroyed
+     *                              before the worker thread got to making this
+     *                              call.  The backend should just ready the stream
+     *                              for destruction in that case.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnStreamInitAsync, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fDestroyed));
+
+    /**
      * Destroys an audio stream.
      *
@@ -1345,6 +1400,6 @@
 
     /**
-     * Called from PDMIAUDIONOTIFYFROMHOST::pfnNotifyDeviceChanged so the backend
-     * can start the device change for a stream.
+     * Called from PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged so the backend can start
+     * the device change for a stream.
      *
      * This is mainly to avoid the need for a list of streams in the backend.
@@ -1353,5 +1408,5 @@
      * @param   pStream             Pointer to audio stream.
      * @param   pvUser              Backend specific parameter from the call to
-     *                              PDMIAUDIONOTIFYFROMHOST::pfnNotifyDeviceChanged.
+     *                              PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged.
      */
     DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIO pInterface,
@@ -1449,17 +1504,35 @@
 
 /** PDMIHOSTAUDIO interface ID. */
-#define PDMIHOSTAUDIO_IID                           "faab0061-c3c8-481e-b875-abbe81baf94a"
+#define PDMIHOSTAUDIO_IID                           "b320d6ab-6cbc-46a8-8011-57e7f7eb0e25"
 
 
 /** Pointer to a audio notify from host interface. */
-typedef struct PDMIAUDIONOTIFYFROMHOST *PPDMIAUDIONOTIFYFROMHOST;
-
-/**
- * PDM audio notification interface, for use by host audio.
- *
- * @todo better name?
- */
-typedef struct PDMIAUDIONOTIFYFROMHOST
-{
+typedef struct PDMIHOSTAUDIOPORT *PPDMIHOSTAUDIOPORT;
+
+/**
+ * PDM host audio port interface, upwards sibling of PDMIHOSTAUDIO.
+ */
+typedef struct PDMIHOSTAUDIOPORT
+{
+    /**
+     * Ask DrvAudio to call PDMIHOSTAUDIO::pfnDoOnWorkerThread on a worker thread.
+     *
+     * Generic method for doing asynchronous work using the DrvAudio thread pool.
+     *
+     * This function will not wait for PDMIHOSTAUDIO::pfnDoOnWorkerThread to
+     * complete, but returns immediately after submitting the request to the thread
+     * pool.
+     *
+     * @returns VBox status code.
+     * @param   pInterface  Pointer to this interface.
+     * @param   pStream     Optional backend stream structure to pass along.  The
+     *                      reference count will be increased till the call
+     *                      completes to make sure the stream stays valid.
+     * @param   uUser       User specific value.
+     * @param   pvUser      User specific pointer.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnDoOnWorkerThread,(PPDMIHOSTAUDIOPORT pInterface, PPDMAUDIOBACKENDSTREAM pStream,
+                                                   uintptr_t uUser, void *pvUser));
+
     /**
      * The device for the given direction changed.
@@ -1475,5 +1548,5 @@
      *                      PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged.
      */
-    DECLR3CALLBACKMEMBER(void, pfnNotifyDeviceChanged,(PPDMIAUDIONOTIFYFROMHOST pInterface, PDMAUDIODIR enmDir, void *pvUser));
+    DECLR3CALLBACKMEMBER(void, pfnNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser));
 
     /**
@@ -1485,5 +1558,5 @@
      * @param   fReInit     Set if a re-init is required, clear if not.
      */
-    DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIAUDIONOTIFYFROMHOST pInterface,
+    DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface,
                                                              PPDMAUDIOBACKENDSTREAM pStream, bool fReInit));
 
@@ -1499,9 +1572,9 @@
      * @param   pInterface  Pointer to this interface.
      */
-    DECLR3CALLBACKMEMBER(void, pfnNotifyDevicesChanged,(PPDMIAUDIONOTIFYFROMHOST pInterface));
-} PDMIAUDIONOTIFYFROMHOST;
-
-/** PDMIAUDIONOTIFYFROMHOST interface ID. */
-#define PDMIAUDIONOTIFYFROMHOST_IID                 "603f9d72-4b8b-4e0a-aa00-a76982931039"
+    DECLR3CALLBACKMEMBER(void, pfnNotifyDevicesChanged,(PPDMIHOSTAUDIOPORT pInterface));
+} PDMIHOSTAUDIOPORT;
+
+/** PDMIHOSTAUDIOPORT interface ID. */
+#define PDMIHOSTAUDIOPORT_IID                    "4d513a11-5be1-4f6f-9a06-a2f628cf67ac"
 
 /** @} */
