Index: trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp
===================================================================
--- trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp	(revision 88997)
+++ trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp	(revision 89010)
@@ -112,4 +112,7 @@
 typedef FNAUDIOTESTDESTROY *PFNAUDIOTESTDESTROY;
 
+/** Maximum audio streams a test environment can handle. */
+#define AUDIOTESTENV_MAX_STREAMS 8
+
 /**
  * Audio test environment parameters.
@@ -119,9 +122,10 @@
 {
     /** The host (backend) driver to use. */
-    PPDMIHOSTAUDIO   pDrvAudio;
+    PPDMIHOSTAUDIO        pDrvAudio;
     /** The current (last) audio device enumeration to use. */
-    PDMAUDIOHOSTENUM DevEnm;
+    PDMAUDIOHOSTENUM      DevEnm;
+    PDMAUDIOBACKENDSTREAM aStreams[AUDIOTESTENV_MAX_STREAMS];
     /** The audio test set to use. */
-    AUDIOTESTSET     Set;
+    AUDIOTESTSET          Set;
 } AUDIOTESTENV;
 /** Pointer a audio test environment. */
@@ -152,4 +156,5 @@
 *********************************************************************************************************************************/
 static int audioTestCombineParms(PAUDIOTESTPARMS pBaseParms, PAUDIOTESTPARMS pOverrideParms);
+static int audioTestPlayTone(PAUDIOTESTENV pTstEnv, PPDMAUDIOBACKENDSTREAM pStream, PAUDIOTESTTONEPARMS pParms);
 
 
@@ -239,9 +244,9 @@
 static DECLCALLBACK(int) audioTestPlayToneSetup(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx)
 {
-    RT_NOREF(pTstEnv, pTstDesc, pTstParmsAcq, ppvCtx);
-
-//    PDMAudioPropsInit(&Props, 16 /* bit */ / 8, true /* fSigned */, 2 /* Channels */, 44100 /* Hz */);
-
-    //AudioTestToneParamsInitRandom(&pTstParms->ToneParms, &pTstParms->ToneParms.Props);
+    RT_NOREF(pTstEnv, pTstDesc, ppvCtx);
+
+    PDMAudioPropsInit(&pTstParmsAcq->ToneParms.Props, 16 /* bit */ / 8, true /* fSigned */, 2 /* Channels */, 44100 /* Hz */);
+
+    AudioTestToneParamsInitRandom(&pTstParmsAcq->ToneParms, &pTstParmsAcq->ToneParms.Props);
 
     return VINF_SUCCESS;
@@ -250,7 +255,7 @@
 static DECLCALLBACK(int) audioTestPlayToneExec(PAUDIOTESTENV pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms)
 {
-    RT_NOREF(pTstEnv, pvCtx, pTstParms);
-
-    return VINF_SUCCESS;
+    RT_NOREF(pvCtx);
+
+    return audioTestPlayTone(pTstEnv, &pTstEnv->aStreams[0], &pTstParms->ToneParms);
 }
 
@@ -543,4 +548,64 @@
 
     return rc;
+}
+
+static int audioTestPlayTone(PAUDIOTESTENV pTstEnv, PPDMAUDIOBACKENDSTREAM pStream, PAUDIOTESTTONEPARMS pParms)
+{
+    PDMAUDIOSTREAMCFG CfgReq;
+    PDMAUDIOSTREAMCFG CfgAcq;
+
+    int rc = PDMAudioStrmCfgInitWithProps(&CfgReq, &pParms->Props);
+    AssertRC(rc); /* Cannot fail. */
+
+    CfgReq.enmDir      = PDMAUDIODIR_OUT;
+    CfgReq.u.enmDst    = PDMAUDIOPLAYBACKDST_FRONT;
+    CfgReq.enmLayout   = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
+
+    rc = PDMAudioStrmCfgCopy(&CfgAcq, &CfgReq);
+    AssertRC(rc); /* Ditto. */
+
+    rc = pTstEnv->pDrvAudio->pfnStreamCreate(pTstEnv->pDrvAudio, pStream, &CfgReq, &CfgAcq);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    /* 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, false /* fDestroyed */);
+
+    AUDIOTESTTONE TstTone;
+    AudioTestToneInitRandom(&TstTone, &pParms->Props);
+
+    PDMHOSTAUDIOSTREAMSTATE enmState = pTstEnv->pDrvAudio->pfnStreamGetState(pTstEnv->pDrvAudio, pStream);
+    if (enmState == PDMHOSTAUDIOSTREAMSTATE_OKAY)
+    {
+        uint32_t cbBuf;
+        uint8_t  abBuf[_4K];
+
+        const uint64_t tsStartMs     = RTTimeMilliTS();
+        const unsigned cSchedulingMs = 10;
+        const uint32_t cbPerMs       = PDMAudioPropsMilliToBytes(&CfgAcq.Props, cSchedulingMs);
+
+        do
+        {
+            rc = AudioTestToneWrite(&TstTone, abBuf, RT_MIN(cbPerMs, sizeof(abBuf)), &cbBuf);
+            if (RT_SUCCESS(rc))
+            {
+                uint32_t cbWritten;
+                rc = pTstEnv->pDrvAudio->pfnStreamPlay(pTstEnv->pDrvAudio, pStream, abBuf, cbBuf, &cbWritten);
+            }
+
+            if (RTTimeMilliTS() - tsStartMs >= pParms->msDuration)
+                break;
+
+            RTThreadSleep(cSchedulingMs);
+
+        } while (RT_SUCCESS(rc));
+    }
+
+    int rc2 = pTstEnv->pDrvAudio->pfnStreamDestroy(pTstEnv->pDrvAudio, pStream);
+    if (RT_SUCCESS(rc))
+        rc = rc2;
+
+    return VINF_SUCCESS;
 }
 
