Index: trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp
===================================================================
--- trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp	(revision 89115)
+++ trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp	(revision 89117)
@@ -127,4 +127,43 @@
 typedef FNAUDIOTESTDESTROY *PFNAUDIOTESTDESTROY;
 
+/**
+ * Audio driver stack.
+ *
+ * This can be just be backend driver alone or DrvAudio with a backend.
+ * @todo add automatic resampling via mixer so we can test more of the audio
+ *       stack used by the device emulations.
+ */
+typedef struct AUDIOTESTDRVSTACK
+{
+    /** The device registration record for the backend. */
+    PCPDMDRVREG             pDrvReg;
+    /** The backend driver instance. */
+    PPDMDRVINS              pDrvBackendIns;
+    /** The backend's audio interface. */
+    PPDMIHOSTAUDIO          pIHostAudio;
+
+    /** The DrvAudio instance. */
+    PPDMDRVINS              pDrvAudioIns;
+    /** This is NULL if we don't use DrvAudio. */
+    PPDMIAUDIOCONNECTOR     pIAudioConnector;
+} AUDIOTESTDRVSTACK;
+/** Pointer to an audio driver stack. */
+typedef AUDIOTESTDRVSTACK *PAUDIOTESTDRVSTACK;
+
+/**
+ * Backend-only stream structure.
+ */
+typedef struct AUDIOTESTDRVSTACKSTREAM
+{
+    /** The public stream data. */
+    PDMAUDIOSTREAM          Core;
+    /** The acquired config. */
+    PDMAUDIOSTREAMCFG       Cfg;
+    /** The backend data (variable size). */
+    PDMAUDIOBACKENDSTREAM   Backend;
+} AUDIOTESTDRVSTACKSTREAM;
+/** Pointer to a backend-only stream structure. */
+typedef AUDIOTESTDRVSTACKSTREAM *PAUDIOTESTDRVSTACKSTREAM;
+
 /** Maximum audio streams a test environment can handle. */
 #define AUDIOTESTENV_MAX_STREAMS 8
@@ -140,6 +179,6 @@
     /** Temporary path for this test environment. */
     char                  szPathTemp[RTPATH_MAX];
-    /** The host (backend) driver to use. */
-    PPDMIHOSTAUDIO        pDrvAudio;
+    /** The audio test driver stack. */
+    AUDIOTESTDRVSTACK     DrvStack;
     /** The current (last) audio device enumeration to use. */
     PDMAUDIOHOSTENUM      DevEnum;
@@ -166,44 +205,4 @@
     PFNAUDIOTESTDESTROY     pfnDestroy;
 } AUDIOTESTDESC;
-
-
-/**
- * Audio driver stack.
- *
- * This can be just be backend driver alone or DrvAudio with a backend.
- * @todo add automatic resampling via mixer so we can test more of the audio
- *       stack used by the device emulations.
- */
-typedef struct AUDIOTESTDRVSTACK
-{
-    /** The device registration record for the backend. */
-    PCPDMDRVREG             pDrvReg;
-    /** The backend driver instance. */
-    PPDMDRVINS              pDrvBackendIns;
-    /** The backend's audio interface. */
-    PPDMIHOSTAUDIO          pIHostAudio;
-
-    /** The DrvAudio instance. */
-    PPDMDRVINS              pDrvAudioIns;
-    /** This is NULL if we don't use DrvAudio. */
-    PPDMIAUDIOCONNECTOR     pIAudioConnector;
-} AUDIOTESTDRVSTACK;
-/** Pointer to an audio driver stack. */
-typedef AUDIOTESTDRVSTACK *PAUDIOTESTDRVSTACK;
-
-/**
- * Backend-only stream structure.
- */
-typedef struct AUDIOTESTDRVSTACKSTREAM
-{
-    /** The public stream data. */
-    PDMAUDIOSTREAM          Core;
-    /** The acquired config. */
-    PDMAUDIOSTREAMCFG       Cfg;
-    /** The backend data (variable size). */
-    PDMAUDIOBACKENDSTREAM   Backend;
-} AUDIOTESTDRVSTACKSTREAM;
-/** Pointer to a backend-only stream structure. */
-typedef AUDIOTESTDRVSTACKSTREAM *PAUDIOTESTDRVSTACKSTREAM;
 
 
@@ -277,4 +276,5 @@
 {
     { "--backend",          'b',                          RTGETOPT_REQ_STRING  },
+    { "--drvaudio",         'd',                          RTGETOPT_REQ_NOTHING },
     { "--exclude",          'e',                          RTGETOPT_REQ_UINT32  },
     { "--exclude-all",      'a',                          RTGETOPT_REQ_NOTHING },
@@ -412,4 +412,6 @@
             pszRet = g_pszDrvAudioDebug;
 
+        AssertPtrReturn(pszRet, VERR_INVALID_POINTER);
+
         int rc = RTStrCopy(pszString, cchString, pszRet);
 
@@ -755,5 +757,5 @@
  * @param   pDrvStack       The driver stack to initialize.
  * @param   pDrvReg         The backend driver to use.
- * @param   fWithDrvAudio   Whether to inlcude DrvAudio in the stack or not.
+ * @param   fWithDrvAudio   Whether to include DrvAudio in the stack or not.
  */
 static int audioTestDriverStackInit(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, bool fWithDrvAudio)
@@ -1213,15 +1215,15 @@
  *
  * @param   pTstEnv             Audio test environment to initialize.
- * @param   pDrvAudio           Audio driver to use.
- * @param   pszPathOut          Output path to use. If NULL, the system's temp directory will be used.
- * @param   pszPathTemp         Temporary path to use. If NULL, the system's temp directory will be used.
+ * @param   pDrvReg             Audio driver to use.
+ * @param   fWithDrvAudio       Whether to include DrvAudio in the stack or not.
  * @param   pszTag              Tag name to use. If NULL, a generated UUID will be used.
  */
-static int audioTestEnvInit(PAUDIOTESTENV pTstEnv, PPDMIHOSTAUDIO pDrvAudio, const char *pszTag)
-{
-    pTstEnv->pDrvAudio = pDrvAudio;
+static int audioTestEnvInit(PAUDIOTESTENV pTstEnv, PCPDMDRVREG pDrvReg, bool fWithDrvAudio, const char *pszTag)
+{
     PDMAudioHostEnumInit(&pTstEnv->DevEnum);
 
-    int rc = VINF_SUCCESS;
+    int rc = audioTestDriverStackInit(&pTstEnv->DrvStack, pDrvReg, fWithDrvAudio);
+    if (RT_FAILURE(rc))
+        return rc;
 
     char szPathTemp[RTPATH_MAX];
@@ -1248,4 +1250,7 @@
     }
 
+    if (RT_FAILURE(rc))
+        audioTestDriverStackDelete(&pTstEnv->DrvStack);
+
     return rc;
 }
@@ -1271,4 +1276,5 @@
 
     AudioTestSetDestroy(&pTstEnv->Set);
+    audioTestDriverStackDelete(&pTstEnv->DrvStack);
 }
 
@@ -1314,5 +1320,5 @@
     RTTestSubF(g_hTest, "Enumerating audio devices and checking for device '%s'", pszDev ? pszDev : "<Default>");
 
-    if (!pTstEnv->pDrvAudio->pfnGetDevices)
+    if (!pTstEnv->DrvStack.pIHostAudio->pfnGetDevices)
     {
         RTTestSkipped(g_hTest, "Backend does not support device enumeration, skipping");
@@ -1325,5 +1331,5 @@
         *ppDev = NULL;
 
-    int rc = pTstEnv->pDrvAudio->pfnGetDevices(pTstEnv->pDrvAudio, &pTstEnv->DevEnum);
+    int rc = pTstEnv->DrvStack.pIHostAudio->pfnGetDevices(pTstEnv->DrvStack.pIHostAudio, &pTstEnv->DevEnum);
     if (RT_SUCCESS(rc))
     {
@@ -1413,5 +1419,5 @@
     AssertRC(rc); /* Cannot fail. */
 
-    rc = pTstEnv->pDrvAudio->pfnStreamCreate(pTstEnv->pDrvAudio, &pStream->Backend, pCfg, &CfgAcq);
+    rc = pTstEnv->DrvStack.pIHostAudio->pfnStreamCreate(pTstEnv->DrvStack.pIHostAudio, &pStream->Backend, pCfg, &CfgAcq);
     if (RT_FAILURE(rc))
         return rc;
@@ -1419,5 +1425,5 @@
     /* Do the async init in a synchronous way for now here. */
     if (rc == VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED)
-        rc = pTstEnv->pDrvAudio->pfnStreamInitAsync(pTstEnv->pDrvAudio, &pStream->Backend, false /* fDestroyed */);
+        rc = pTstEnv->DrvStack.pIHostAudio->pfnStreamInitAsync(pTstEnv->DrvStack.pIHostAudio, &pStream->Backend, false /* fDestroyed */);
 
     if (RT_SUCCESS(rc))
@@ -1444,5 +1450,5 @@
     /** @todo Anything else to do here, e.g. test if there are left over samples or some such? */
 
-    int rc = pTstEnv->pDrvAudio->pfnStreamDestroy(pTstEnv->pDrvAudio, &pStream->Backend);
+    int rc = pTstEnv->DrvStack.pIHostAudio->pfnStreamDestroy(pTstEnv->DrvStack.pIHostAudio, &pStream->Backend);
     if (RT_SUCCESS(rc))
         RT_BZERO(pStream, sizeof(PDMAUDIOBACKENDSTREAM));
@@ -1503,5 +1509,5 @@
     AssertRCReturn(rc, rc);
 
-    PDMHOSTAUDIOSTREAMSTATE enmState = pTstEnv->pDrvAudio->pfnStreamGetState(pTstEnv->pDrvAudio, &pStream->Backend);
+    PDMHOSTAUDIOSTREAMSTATE enmState = pTstEnv->DrvStack.pIHostAudio->pfnStreamGetState(pTstEnv->DrvStack.pIHostAudio, &pStream->Backend);
     if (enmState == PDMHOSTAUDIOSTREAMSTATE_OKAY)
     {
@@ -1523,5 +1529,5 @@
                 {
                     uint32_t cbWritten;
-                    rc = pTstEnv->pDrvAudio->pfnStreamPlay(pTstEnv->pDrvAudio, &pStream->Backend, abBuf, cbBuf, &cbWritten);
+                    rc = pTstEnv->DrvStack.pIHostAudio->pfnStreamPlay(pTstEnv->DrvStack.pIHostAudio, &pStream->Backend, abBuf, cbBuf, &cbWritten);
                 }
             }
@@ -1732,8 +1738,9 @@
     switch (pOpt->iShort)
     {
-        case 'd':   return "Use the specified audio device";
-        case 'e':   return "Exclude the given test id from the list";
-        case 'a':   return "Exclude all tests from the list (useful to enable single tests later with --include)";
-        case 'i':   return "Include the given test id in the list";
+        case 'd':                 return "Go via DrvAudio instead of directly interfacing with the backend.";
+        case VKAT_TEST_OPT_DEV:   return "Use the specified audio device";
+        case 'e':                 return "Exclude the given test id from the list";
+        case 'a':                 return "Exclude all tests from the list (useful to enable single tests later with --include)";
+        case 'i':                 return "Include the given test id in the list";
     }
     return NULL;
@@ -1754,7 +1761,8 @@
     audioTestParmsInit(&TstCust);
 
-    const char *pszDevice  = NULL; /* Custom device to use. Can be NULL if not being used. */
-    const char *pszTag     = NULL; /* Custom tag to use. Can be NULL if not being used. */
-    PCPDMDRVREG pDrvReg    = g_aBackends[0].pDrvReg;
+    const char *pszDevice     = NULL; /* Custom device to use. Can be NULL if not being used. */
+    const char *pszTag        = NULL; /* Custom tag to use. Can be NULL if not being used. */
+    PCPDMDRVREG pDrvReg       = g_aBackends[0].pDrvReg;
+    bool        fWithDrvAudio = false;
 
     int           rc;
@@ -1782,4 +1790,8 @@
                 break;
 
+            case 'd':
+                fWithDrvAudio = true;
+                break;
+
             case 'e':
                 if (ValueUnion.u32 >= RT_ELEMENTS(g_aTests))
@@ -1854,33 +1866,25 @@
     RTTestBanner(g_hTest);
 
-    AUDIOTESTDRVSTACK DrvStack;
-    rc = audioTestDriverStackInit(&DrvStack, pDrvReg, false /*fWithDrvAudio*/);
+    /* For now all tests have the same test environment. */
+    rc = audioTestEnvInit(&TstEnv, pDrvReg, fWithDrvAudio, pszTag);
     if (RT_SUCCESS(rc))
     {
-        /* For now all tests have the same test environment. */
-        /** @todo bake the DrvStack into the test env make make it more flexible so
-         *        we can also test with/without DrvAudio (need option above). */
-        rc = audioTestEnvInit(&TstEnv, DrvStack.pIHostAudio, pszTag);
+        PPDMAUDIOHOSTDEV pDev;
+        rc = audioTestDevicesEnumerateAndCheck(&TstEnv, pszDevice, &pDev);
         if (RT_SUCCESS(rc))
-        {
-            PPDMAUDIOHOSTDEV pDev;
-            rc = audioTestDevicesEnumerateAndCheck(&TstEnv, pszDevice, &pDev);
-            if (RT_SUCCESS(rc))
-                audioTestWorker(&TstEnv, &TstCust);
-
-            /* Before destroying the test environment, pack up the test set so
-             * that it's ready for transmission. */
-            char szFileOut[RTPATH_MAX];
-            rc = AudioTestSetPack(&TstEnv.Set, TstEnv.szPathOut, szFileOut, sizeof(szFileOut));
-            if (RT_SUCCESS(rc))
-                RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test set packed up to '%s'\n", szFileOut);
-
-            /* Clean up. */
-            int rc2 = AudioTestSetWipe(&TstEnv.Set);
-            AssertRC(rc2); /* Annoying, but not test-critical. */
-
-            audioTestEnvDestroy(&TstEnv);
-        }
-        audioTestDriverStackDelete(&DrvStack);
+            audioTestWorker(&TstEnv, &TstCust);
+
+        /* Before destroying the test environment, pack up the test set so
+         * that it's ready for transmission. */
+        char szFileOut[RTPATH_MAX];
+        rc = AudioTestSetPack(&TstEnv.Set, TstEnv.szPathOut, szFileOut, sizeof(szFileOut));
+        if (RT_SUCCESS(rc))
+            RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test set packed up to '%s'\n", szFileOut);
+
+        /* Clean up. */
+        int rc2 = AudioTestSetWipe(&TstEnv.Set);
+        AssertRC(rc2); /* Annoying, but not test-critical. */
+
+        audioTestEnvDestroy(&TstEnv);
     }
 
