VirtualBox

Changeset 89544 in vbox for trunk/src/VBox/ValidationKit


Ignore:
Timestamp:
Jun 7, 2021 11:06:40 AM (4 years ago)
Author:
vboxsync
Message:

Audio/ValKit: Split up VKAT code into some more files as vkat.cpp got too big already. bugref:10008

Location:
trunk/src/VBox/ValidationKit/utils/audio
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/utils/audio/Makefile.kmk

    r89403 r89544  
    5555vkat_SOURCES  = \
    5656        vkat.cpp \
     57        vkatCommon.cpp \
     58        vkatCmdPlayRec.cpp \
    5759        vkatDriverStack.cpp \
    5860        $(VKAT_PATH_AUDIO)/AudioTest.cpp \
     
    6769vkat_DEFS     += VBOX_WITH_AUDIO_VALIDATIONKIT
    6870vkat_SOURCES  += \
     71        vkatCmdSelfTest.cpp \
    6972        $(VKAT_PATH_AUDIO)/DrvHostAudioValidationKit.cpp \
    7073        $(VKAT_PATH_AUDIO)/AudioTestService.cpp \
  • trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp

    r89541 r89544  
    111111
    112112
    113 /*********************************************************************************************************************************
    114 *   Structures and Typedefs                                                                                                      *
    115 *********************************************************************************************************************************/
    116 /**
    117  * Enumeration specifying the current audio test mode.
    118  */
    119 typedef enum AUDIOTESTMODE
    120 {
    121     /** Unknown mode. */
    122     AUDIOTESTMODE_UNKNOWN = 0,
    123     /** VKAT is running on the guest side. */
    124     AUDIOTESTMODE_GUEST,
    125     /** VKAT is running on the host side. */
    126     AUDIOTESTMODE_HOST
    127 } AUDIOTESTMODE;
    128 
    129 struct AUDIOTESTENV;
    130 /** Pointer a audio test environment. */
    131 typedef AUDIOTESTENV *PAUDIOTESTENV;
    132 
    133 struct AUDIOTESTDESC;
    134 /** Pointer a audio test descriptor. */
    135 typedef AUDIOTESTDESC *PAUDIOTESTDESC;
    136 
    137 /**
    138  * Callback to set up the test parameters for a specific test.
    139  *
    140  * @returns IPRT status code.
    141  * @retval  VINF_SUCCESS    if setting the parameters up succeeded. Any other error code
    142  *                          otherwise indicating the kind of error.
    143  * @param   pszTest         Test name.
    144  * @param   pTstParmsAcq    The audio test parameters to set up.
    145  */
    146 typedef DECLCALLBACKTYPE(int, FNAUDIOTESTSETUP,(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx));
    147 /** Pointer to an audio test setup callback. */
    148 typedef FNAUDIOTESTSETUP *PFNAUDIOTESTSETUP;
    149 
    150 typedef DECLCALLBACKTYPE(int, FNAUDIOTESTEXEC,(PAUDIOTESTENV pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms));
    151 /** Pointer to an audio test exec callback. */
    152 typedef FNAUDIOTESTEXEC *PFNAUDIOTESTEXEC;
    153 
    154 typedef DECLCALLBACKTYPE(int, FNAUDIOTESTDESTROY,(PAUDIOTESTENV pTstEnv, void *pvCtx));
    155 /** Pointer to an audio test destroy callback. */
    156 typedef FNAUDIOTESTDESTROY *PFNAUDIOTESTDESTROY;
    157 
    158 /**
    159  * Structure for keeping an audio test audio stream.
    160  */
    161 typedef struct AUDIOTESTSTREAM
    162 {
    163     /** The PDM stream. */
    164     PPDMAUDIOSTREAM         pStream;
    165     /** The backend stream. */
    166     PPDMAUDIOBACKENDSTREAM  pBackend;
    167     /** The stream config. */
    168     PDMAUDIOSTREAMCFG       Cfg;
    169 } AUDIOTESTSTREAM;
    170 /** Pointer to audio test stream. */
    171 typedef AUDIOTESTSTREAM *PAUDIOTESTSTREAM;
    172 
    173 /** Maximum audio streams a test environment can handle. */
    174 #define AUDIOTESTENV_MAX_STREAMS 8
    175 
    176 /**
    177  * Audio test environment parameters.
    178  * Not necessarily bound to a specific test (can be reused).
    179  */
    180 typedef struct AUDIOTESTENV
    181 {
    182     /** Audio testing mode. */
    183     AUDIOTESTMODE           enmMode;
    184     /** Whether self test mode is active or not. */
    185     bool                    fSelftest;
    186     /** Output path for storing the test environment's final test files. */
    187     char                    szTag[AUDIOTEST_TAG_MAX];
    188     /** Output path for storing the test environment's final test files. */
    189     char                    szPathOut[RTPATH_MAX];
    190     /** Temporary path for this test environment. */
    191     char                    szPathTemp[RTPATH_MAX];
    192     /** Buffer size (in ms). */
    193     RTMSINTERVAL            cMsBufferSize;
    194     /** Pre-buffering time (in ms). */
    195     RTMSINTERVAL            cMsPreBuffer;
    196     /** Scheduling hint (in ms). */
    197     RTMSINTERVAL            cMsSchedulingHint;
    198     /** The audio test driver stack. */
    199     AUDIOTESTDRVSTACK       DrvStack;
    200     /** The current (last) audio device enumeration to use. */
    201     PDMAUDIOHOSTENUM        DevEnum;
    202     /** Audio stream. */
    203     AUDIOTESTSTREAM         aStreams[AUDIOTESTENV_MAX_STREAMS];
    204     /** The audio test set to use. */
    205     AUDIOTESTSET            Set;
    206     union
    207     {
    208         struct
    209         {
    210             /** ATS instance to use. */
    211             ATSSERVER       Srv;
    212         } Guest;
    213         struct
    214         {
    215             /** Client connected to the ATS on the guest side. */
    216             ATSCLIENT       AtsClGuest;
    217             /** Client connected to the ATS on the Validation Kit. */
    218             ATSCLIENT       AtsClValKit;
    219         } Host;
    220     } u;
    221 } AUDIOTESTENV;
    222 
    223 /**
    224  * Audio test descriptor.
    225  */
    226 typedef struct AUDIOTESTDESC
    227 {
    228     /** (Sort of) Descriptive test name. */
    229     const char             *pszName;
    230     /** Flag whether the test is excluded. */
    231     bool                    fExcluded;
    232     /** The setup callback. */
    233     PFNAUDIOTESTSETUP       pfnSetup;
    234     /** The exec callback. */
    235     PFNAUDIOTESTEXEC        pfnExec;
    236     /** The destruction callback. */
    237     PFNAUDIOTESTDESTROY     pfnDestroy;
    238 } AUDIOTESTDESC;
    239 
    240 /**
    241  * Structure for keeping a user context for the test service callbacks.
    242  */
    243 typedef struct ATSCALLBACKCTX
    244 {
    245     PAUDIOTESTENV pTstEnv;
    246 } ATSCALLBACKCTX;
    247 typedef ATSCALLBACKCTX *PATSCALLBACKCTX;
    248 
    249113
    250114/*********************************************************************************************************************************
     
    252116*********************************************************************************************************************************/
    253117static int audioTestCombineParms(PAUDIOTESTPARMS pBaseParms, PAUDIOTESTPARMS pOverrideParms);
    254 static int audioTestCreateStreamDefaultIn(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps);
    255 static int audioTestCreateStreamDefaultOut(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps);
    256 static int audioTestStreamDestroy(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream);
    257 static int audioTestDevicesEnumerateAndCheck(PAUDIOTESTENV pTstEnv, const char *pszDev, PPDMAUDIOHOSTDEV *ppDev);
    258 static int audioTestEnvPrologue(PAUDIOTESTENV pTstEnv);
    259 
    260118static RTEXITCODE audioTestUsage(PRTSTREAM pStrm);
    261119static RTEXITCODE audioTestVersion(void);
     
    359217};
    360218
    361 /**
    362  * Backends.
    363  *
    364  * @note The first backend in the array is the default one for the platform.
    365  */
    366 static struct
    367 {
    368     /** The driver registration structure. */
    369     PCPDMDRVREG pDrvReg;
    370     /** The backend name.
    371      * Aliases are implemented by having multiple entries for the same backend.  */
    372     const char *pszName;
    373 } const g_aBackends[] =
    374 {
    375 #if defined(VBOX_WITH_AUDIO_ALSA) && defined(RT_OS_LINUX)
    376     {   &g_DrvHostALSAAudio,          "alsa" },
    377 #endif
    378 #ifdef VBOX_WITH_AUDIO_PULSE
    379     {   &g_DrvHostPulseAudio,         "pulseaudio" },
    380     {   &g_DrvHostPulseAudio,         "pulse" },
    381     {   &g_DrvHostPulseAudio,         "pa" },
    382 #endif
    383 #ifdef VBOX_WITH_AUDIO_OSS
    384     {   &g_DrvHostOSSAudio,           "oss" },
    385 #endif
    386 #if defined(RT_OS_DARWIN)
    387     {   &g_DrvHostCoreAudio,          "coreaudio" },
    388     {   &g_DrvHostCoreAudio,          "core" },
    389     {   &g_DrvHostCoreAudio,          "ca" },
    390 #endif
    391 #if defined(RT_OS_WINDOWS)
    392     {   &g_DrvHostAudioWas,           "wasapi" },
    393     {   &g_DrvHostAudioWas,           "was" },
    394     {   &g_DrvHostDSound,             "directsound" },
    395     {   &g_DrvHostDSound,             "dsound" },
    396     {   &g_DrvHostDSound,             "ds" },
    397 #endif
    398     {   &g_DrvHostValidationKitAudio, "valkit" }
    399 };
    400 AssertCompile(sizeof(g_aBackends) > 0 /* port me */);
    401 
    402 
    403219/** Terminate ASAP if set.  Set on Ctrl-C. */
    404 static bool volatile    g_fTerminate = false;
     220bool volatile    g_fTerminate = false;
    405221/** The release logger. */
    406 static PRTLOGGER        g_pRelLogger = NULL;
    407 
    408 
     222PRTLOGGER        g_pRelLogger = NULL;
    409223/** The test handle. */
    410 RTTEST        g_hTest;
     224RTTEST           g_hTest;
    411225/** The current verbosity level. */
    412 unsigned      g_uVerbosity = 0;
     226unsigned         g_uVerbosity = 0;
    413227/** DrvAudio: Enable debug (or not). */
    414 bool          g_fDrvAudioDebug = 0;
     228bool             g_fDrvAudioDebug = 0;
    415229/** DrvAudio: The debug output path. */
    416 const char   *g_pszDrvAudioDebug = NULL;
     230const char      *g_pszDrvAudioDebug = NULL;
    417231
    418232
     
    424238 * @param   pszBackend      The backend option value.
    425239 */
    426 static PCPDMDRVREG audioTestFindBackendOpt(const char *pszBackend)
     240PCPDMDRVREG audioTestFindBackendOpt(const char *pszBackend)
    427241{
    428242    for (uintptr_t i = 0; i < RT_ELEMENTS(g_aBackends); i++)
     
    434248}
    435249
    436 
    437 /*********************************************************************************************************************************
    438 *   Test Primitives                                                                                                              *
    439 *********************************************************************************************************************************/
    440 
    441 /**
    442  * Plays a test tone on a specific audio test stream.
    443  *
    444  * @returns VBox status code.
    445  * @param   pTstEnv             Test environment to use for running the test.
    446  * @param   pStream             Stream to use for playing the tone.
    447  * @param   pParms              Tone parameters to use.
    448  *
    449  * @note    Blocking function.
    450  */
    451 static int audioTestPlayTone(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PAUDIOTESTTONEPARMS pParms)
    452 {
    453     AUDIOTESTTONE TstTone;
    454     AudioTestToneInit(&TstTone, &pParms->Props, pParms->dbFreqHz);
    455 
    456     const char *pcszPathOut = pTstEnv->Set.szPathAbs;
    457 
    458     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Playing test tone (tone frequency is %RU16Hz, %RU32ms)\n", (uint16_t)pParms->dbFreqHz, pParms->msDuration);
    459     RTTestPrintf(g_hTest, RTTESTLVL_DEBUG,  "Writing to '%s'\n", pcszPathOut);
    460 
    461     /** @todo Use .WAV here? */
    462     PAUDIOTESTOBJ pObj;
    463     int rc = AudioTestSetObjCreateAndRegister(&pTstEnv->Set, "tone-play.pcm", &pObj);
    464     AssertRCReturn(rc, rc);
    465 
    466     if (audioTestDriverStackStreamIsOkay(&pTstEnv->DrvStack, pStream->pStream))
    467     {
    468         uint32_t cbBuf;
    469         uint8_t  abBuf[_4K];
    470 
    471         const uint32_t cbPerSched = PDMAudioPropsMilliToBytes(&pParms->Props, pTstEnv->cMsSchedulingHint);
    472         AssertStmt(cbPerSched, rc = VERR_INVALID_PARAMETER);
    473               uint32_t cbToWrite  = PDMAudioPropsMilliToBytes(&pParms->Props, pParms->msDuration);
    474         AssertStmt(cbToWrite,  rc = VERR_INVALID_PARAMETER);
    475 
    476         if (RT_SUCCESS(rc))
    477         {
    478             AudioTestSetObjAddMetadataStr(pObj, "buffer_size_ms=%RU32\n", pTstEnv->cMsBufferSize);
    479             AudioTestSetObjAddMetadataStr(pObj, "prebuf_size_ms=%RU32\n", pTstEnv->cMsPreBuffer);
    480             AudioTestSetObjAddMetadataStr(pObj, "scheduling_hint_ms=%RU32\n", pTstEnv->cMsSchedulingHint);
    481 
    482             while (cbToWrite)
    483             {
    484                 uint32_t cbWritten    = 0;
    485                 uint32_t cbToGenerate = RT_MIN(cbToWrite, RT_MIN(cbPerSched, sizeof(abBuf)));
    486                 Assert(cbToGenerate);
    487 
    488                 rc = AudioTestToneGenerate(&TstTone, abBuf, cbToGenerate, &cbBuf);
    489                 if (RT_SUCCESS(rc))
    490                 {
    491                     /* Write stuff to disk before trying to play it. Help analysis later. */
    492                     rc = AudioTestSetObjWrite(pObj, abBuf, cbBuf);
    493                     if (RT_SUCCESS(rc))
    494                         rc = audioTestDriverStackStreamPlay(&pTstEnv->DrvStack, pStream->pStream,
    495                                                             abBuf, cbBuf, &cbWritten);
    496                 }
    497 
    498                 if (RT_FAILURE(rc))
    499                     break;
    500 
    501                 RTThreadSleep(pTstEnv->cMsSchedulingHint);
    502 
    503                 Assert(cbToWrite >= cbWritten);
    504                 cbToWrite -= cbWritten;
    505             }
    506         }
    507     }
    508     else
    509         rc = VERR_AUDIO_STREAM_NOT_READY;
    510 
    511     int rc2 = AudioTestSetObjClose(pObj);
    512     if (RT_SUCCESS(rc))
    513         rc = rc2;
    514 
    515     if (RT_FAILURE(rc))
    516         RTTestFailed(g_hTest, "Playing tone done failed with %Rrc\n", rc);
    517 
    518     return rc;
    519 }
    520 
    521 /**
    522  * Records a test tone from a specific audio test stream.
    523  *
    524  * @returns VBox status code.
    525  * @param   pTstEnv             Test environment to use for running the test.
    526  * @param   pStream             Stream to use for recording the tone.
    527  * @param   pParms              Tone parameters to use.
    528  *
    529  * @note    Blocking function.
    530  */
    531 static int audioTestRecordTone(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PAUDIOTESTTONEPARMS pParms)
    532 {
    533     const char *pcszPathOut = pTstEnv->Set.szPathAbs;
    534 
    535     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Recording test tone (for %RU32ms)\n", pParms->msDuration);
    536     RTTestPrintf(g_hTest, RTTESTLVL_DEBUG,  "Writing to '%s'\n", pcszPathOut);
    537 
    538     /** @todo Use .WAV here? */
    539     PAUDIOTESTOBJ pObj;
    540     int rc = AudioTestSetObjCreateAndRegister(&pTstEnv->Set, "tone-rec.pcm", &pObj);
    541     AssertRCReturn(rc, rc);
    542 
    543     if (audioTestDriverStackStreamIsOkay(&pTstEnv->DrvStack, pStream->pStream))
    544     {
    545         const uint32_t cbPerSched = PDMAudioPropsMilliToBytes(&pParms->Props, pTstEnv->cMsSchedulingHint);
    546         AssertStmt(cbPerSched, rc = VERR_INVALID_PARAMETER);
    547               uint32_t cbToRead   = PDMAudioPropsMilliToBytes(&pParms->Props, pParms->msDuration);
    548         AssertStmt(cbToRead,   rc = VERR_INVALID_PARAMETER);
    549 
    550         if (RT_SUCCESS(rc))
    551         {
    552             AudioTestSetObjAddMetadataStr(pObj, "buffer_size_ms=%RU32\n", pTstEnv->cMsBufferSize);
    553             AudioTestSetObjAddMetadataStr(pObj, "prebuf_size_ms=%RU32\n", pTstEnv->cMsPreBuffer);
    554             AudioTestSetObjAddMetadataStr(pObj, "scheduling_hint_ms=%RU32\n", pTstEnv->cMsSchedulingHint);
    555 
    556             uint8_t abBuf[_4K];
    557 
    558             while (cbToRead)
    559             {
    560                 const uint32_t cbChunk = RT_MIN(cbToRead, RT_MIN(cbPerSched, sizeof(abBuf)));
    561 
    562                 uint32_t cbRead = 0;
    563                 rc = audioTestDriverStackStreamCapture(&pTstEnv->DrvStack, pStream->pStream, (void *)abBuf, cbChunk, &cbRead);
    564                 if (RT_SUCCESS(rc))
    565                     rc = AudioTestSetObjWrite(pObj, abBuf, cbRead);
    566 
    567                 if (RT_FAILURE(rc))
    568                     break;
    569 
    570                 RTThreadSleep(pTstEnv->cMsSchedulingHint);
    571 
    572                 Assert(cbToRead >= cbRead);
    573                 cbToRead -= cbRead;
    574             }
    575         }
    576     }
    577     else
    578         rc = VERR_AUDIO_STREAM_NOT_READY;
    579 
    580     int rc2 = AudioTestSetObjClose(pObj);
    581     if (RT_SUCCESS(rc))
    582         rc = rc2;
    583 
    584     if (RT_FAILURE(rc))
    585         RTTestFailed(g_hTest, "Recording tone done failed with %Rrc\n", rc);
    586 
    587     return rc;
    588 }
    589 
    590 
    591 /*********************************************************************************************************************************
    592 *   ATS Callback Implementations                                                                                                 *
    593 *********************************************************************************************************************************/
    594 
    595 /** @copydoc ATSCALLBACKS::pfnTestSetBegin */
    596 static DECLCALLBACK(int) audioTestSvcTestSetBeginCallback(void const *pvUser, const char *pszTag)
    597 {
    598     PATSCALLBACKCTX pCtx    = (PATSCALLBACKCTX)pvUser;
    599     PAUDIOTESTENV   pTstEnv = pCtx->pTstEnv;
    600 
    601     char szTag[AUDIOTEST_TAG_MAX];
    602     int rc = RTStrPrintf2(szTag, sizeof(szTag), "%s-guest", pszTag);
    603     AssertRCReturn(rc, rc);
    604 
    605     RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Beginning test set '%s'\n", szTag);
    606 
    607     return AudioTestSetCreate(&pTstEnv->Set, pTstEnv->szPathTemp, szTag);
    608 }
    609 
    610 /** @copydoc ATSCALLBACKS::pfnTestSetEnd */
    611 static DECLCALLBACK(int) audioTestSvcTestSetEndCallback(void const *pvUser, const char *pszTag)
    612 {
    613     RT_NOREF(pszTag);
    614 
    615     PATSCALLBACKCTX pCtx    = (PATSCALLBACKCTX)pvUser;
    616     PAUDIOTESTENV   pTstEnv = pCtx->pTstEnv;
    617 
    618     RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Ending test set '%s'\n", pszTag);
    619 
    620     return audioTestEnvPrologue(pTstEnv);
    621 }
    622 
    623 /** @copydoc ATSCALLBACKS::pfnTonePlay */
    624 static DECLCALLBACK(int) audioTestSvcTonePlayCallback(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
    625 {
    626     PATSCALLBACKCTX pCtx    = (PATSCALLBACKCTX)pvUser;
    627     PAUDIOTESTENV   pTstEnv = pCtx->pTstEnv;
    628 
    629     AUDIOTESTTONE TstTone;
    630     AudioTestToneInitRandom(&TstTone, &pToneParms->Props);
    631 
    632     const PAUDIOTESTSTREAM pTstStream = &pTstEnv->aStreams[0]; /** @todo Make this dynamic. */
    633 
    634     int rc = audioTestCreateStreamDefaultOut(pTstEnv, pTstStream, &pToneParms->Props);
    635     if (RT_SUCCESS(rc))
    636     {
    637         AUDIOTESTPARMS TstParms;
    638         RT_ZERO(TstParms);
    639         TstParms.enmType  = AUDIOTESTTYPE_TESTTONE_PLAY;
    640         TstParms.enmDir   = PDMAUDIODIR_OUT;
    641         TstParms.TestTone = *pToneParms;
    642 
    643         PAUDIOTESTENTRY pTst;
    644         rc = AudioTestSetTestBegin(&pTstEnv->Set, "Playing test tone", &TstParms, &pTst);
    645         if (RT_SUCCESS(rc))
    646         {
    647             rc = audioTestPlayTone(pTstEnv, pTstStream, pToneParms);
    648             if (RT_SUCCESS(rc))
    649             {
    650                 AudioTestSetTestDone(pTst);
    651             }
    652             else
    653                 AudioTestSetTestFailed(pTst, rc, "Playing tone failed");
    654         }
    655 
    656         int rc2 = audioTestStreamDestroy(pTstEnv, pTstStream);
    657         if (RT_SUCCESS(rc))
    658             rc = rc2;
    659     }
    660     else
    661         RTTestFailed(g_hTest, "Error creating output stream, rc=%Rrc\n", rc);
    662 
    663     return rc;
    664 }
    665 
    666 /** @copydoc ATSCALLBACKS::pfnToneRecord */
    667 static DECLCALLBACK(int) audioTestSvcToneRecordCallback(void const *pvUser, PAUDIOTESTTONEPARMS pToneParms)
    668 {
    669     PATSCALLBACKCTX pCtx    = (PATSCALLBACKCTX)pvUser;
    670     PAUDIOTESTENV   pTstEnv = pCtx->pTstEnv;
    671 
    672     const PAUDIOTESTSTREAM pTstStream = &pTstEnv->aStreams[0]; /** @todo Make this dynamic. */
    673 
    674     int rc = audioTestCreateStreamDefaultIn(pTstEnv, pTstStream, &pToneParms->Props);
    675     if (RT_SUCCESS(rc))
    676     {
    677         AUDIOTESTPARMS TstParms;
    678         RT_ZERO(TstParms);
    679         TstParms.enmType  = AUDIOTESTTYPE_TESTTONE_RECORD;
    680         TstParms.enmDir   = PDMAUDIODIR_IN;
    681         TstParms.Props    = pToneParms->Props;
    682         TstParms.TestTone = *pToneParms;
    683 
    684         PAUDIOTESTENTRY pTst;
    685         rc = AudioTestSetTestBegin(&pTstEnv->Set, "Recording test tone", &TstParms, &pTst);
    686         if (RT_SUCCESS(rc))
    687         {
    688             rc = audioTestRecordTone(pTstEnv, pTstStream, pToneParms);
    689             if (RT_SUCCESS(rc))
    690             {
    691                 AudioTestSetTestDone(pTst);
    692             }
    693             else
    694                 AudioTestSetTestFailed(pTst, rc, "Recording tone failed");
    695         }
    696 
    697         int rc2 = audioTestStreamDestroy(pTstEnv, pTstStream);
    698         if (RT_SUCCESS(rc))
    699             rc = rc2;
    700     }
    701     else
    702         RTTestFailed(g_hTest, "Error creating input stream, rc=%Rrc\n", rc);
    703 
    704     return rc;
    705 }
    706 
    707 
    708 /*********************************************************************************************************************************
    709 *   Implementation of audio test environment handling                                                                            *
    710 *********************************************************************************************************************************/
    711 
    712 /**
    713  * Initializes an audio test environment.
    714  *
    715  * @param   pTstEnv             Audio test environment to initialize.
    716  * @param   pDrvReg             Audio driver to use.
    717  * @param   fWithDrvAudio       Whether to include DrvAudio in the stack or not.
    718  * @param   pszTcpAddr          TCP/IP address to connect to.
    719  *                              If NULL, localhost (127.0.0.1) will be used.
    720  * @param   uTcpPort            TCP/IP port to connect to.
    721  *                              If 0, ATS_DEFAULT_PORT will be used.
    722  */
    723 static int audioTestEnvInit(PAUDIOTESTENV pTstEnv,
    724                             PCPDMDRVREG pDrvReg, bool fWithDrvAudio,
    725                             const char *pszTcpAddr, uint32_t uTcpPort)
    726 {
    727     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test mode is '%s'\n", pTstEnv->enmMode == AUDIOTESTMODE_HOST ? "host" : "guest");
    728     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Using tag '%s'\n", pTstEnv->szTag);
    729     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Output directory is '%s'\n", pTstEnv->szPathOut);
    730     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Temp directory is '%s'\n", pTstEnv->szPathTemp);
    731 
    732     int rc = VINF_SUCCESS;
    733 
    734     PDMAudioHostEnumInit(&pTstEnv->DevEnum);
    735 
    736     pTstEnv->cMsBufferSize     = 300; /* ms */ /** @todo Randomize this also? */
    737     pTstEnv->cMsPreBuffer      = 150; /* ms */ /** @todo Ditto. */
    738     pTstEnv->cMsSchedulingHint = RTRandU32Ex(10, 80); /* Choose a random scheduling (in ms). */
    739 
    740     /* Only the guest mode needs initializing the driver stack. */
    741     const bool fUseDriverStack =    pTstEnv->enmMode == AUDIOTESTMODE_GUEST
    742                                  /* The self test mode drives the ValKit audio driver locally,
    743                                   * so also use the driver stack here. */
    744                                  || pTstEnv->fSelftest;
    745     if (fUseDriverStack)
    746     {
    747         rc = audioTestDriverStackInit(&pTstEnv->DrvStack, pDrvReg, fWithDrvAudio);
    748         if (RT_FAILURE(rc))
    749             return rc;
    750 
    751         PPDMAUDIOHOSTDEV pDev;
    752         rc = audioTestDevicesEnumerateAndCheck(pTstEnv, NULL /* pszDevice */, &pDev); /** @todo Implement device checking. */
    753         if (RT_FAILURE(rc))
    754             return rc;
    755     }
    756 
    757     char szPathTemp[RTPATH_MAX];
    758     if (   !strlen(pTstEnv->szPathTemp)
    759         || !strlen(pTstEnv->szPathOut))
    760         rc = RTPathTemp(szPathTemp, sizeof(szPathTemp));
    761 
    762     if (   RT_SUCCESS(rc)
    763         && !strlen(pTstEnv->szPathTemp))
    764         rc = RTPathJoin(pTstEnv->szPathTemp, sizeof(pTstEnv->szPathTemp), szPathTemp, "vkat-temp");
    765 
    766     if (   RT_SUCCESS(rc)
    767         && !strlen(pTstEnv->szPathOut))
    768         rc = RTPathJoin(pTstEnv->szPathOut, sizeof(pTstEnv->szPathOut), szPathTemp, "vkat");
    769 
    770     if (RT_FAILURE(rc))
    771         return rc;
    772 
    773     /** @todo Implement NAT mode like we do for TxS later? */
    774     if (pTstEnv->enmMode == AUDIOTESTMODE_GUEST)
    775     {
    776         ATSCALLBACKCTX Ctx;
    777         Ctx.pTstEnv = pTstEnv;
    778 
    779         ATSCALLBACKS Callbacks;
    780         Callbacks.pfnTestSetBegin = audioTestSvcTestSetBeginCallback;
    781         Callbacks.pfnTestSetEnd   = audioTestSvcTestSetEndCallback;
    782         Callbacks.pfnTonePlay     = audioTestSvcTonePlayCallback;
    783         Callbacks.pfnToneRecord   = audioTestSvcToneRecordCallback;
    784         Callbacks.pvUser          = &Ctx;
    785 
    786         RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Starting guest ATS at %s:%RU32...\n", pszTcpAddr, uTcpPort);
    787         rc = AudioTestSvcInit(&pTstEnv->u.Guest.Srv, pszTcpAddr, uTcpPort, &Callbacks);
    788         if (RT_SUCCESS(rc))
    789             rc = AudioTestSvcStart(&pTstEnv->u.Guest.Srv);
    790 
    791         if (RT_FAILURE(rc))
    792         {
    793             RTTestFailed(g_hTest, "Starting ATS failed with %Rrc\n", rc);
    794             return rc;
    795         }
    796     }
    797     else /* Host mode */
    798     {
    799         RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Connecting to guest ATS at %s:%RU32 ...\n",
    800                      (pszTcpAddr && *pszTcpAddr) ? pszTcpAddr : "127.0.0.1", uTcpPort ? uTcpPort : ATS_TCP_DEFAULT_PORT);
    801 
    802         rc = AudioTestSvcClientConnect(&pTstEnv->u.Host.AtsClGuest, pszTcpAddr, uTcpPort);
    803         if (RT_FAILURE(rc))
    804         {
    805             RTTestFailed(g_hTest, "Connecting to ATS failed with %Rrc\n", rc);
    806             return rc;
    807         }
    808 
    809         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Connected to ATS\n");
    810     }
    811 
    812     if (   RT_FAILURE(rc)
    813         && fUseDriverStack)
    814         audioTestDriverStackDelete(&pTstEnv->DrvStack);
    815 
    816     return rc;
    817 }
    818 
    819 /**
    820  * Destroys an audio test environment.
    821  *
    822  * @param   pTstEnv             Audio test environment to destroy.
    823  */
    824 static void audioTestEnvDestroy(PAUDIOTESTENV pTstEnv)
    825 {
    826     if (!pTstEnv)
    827         return;
    828 
    829     PDMAudioHostEnumDelete(&pTstEnv->DevEnum);
    830 
    831     for (unsigned i = 0; i < RT_ELEMENTS(pTstEnv->aStreams); i++)
    832     {
    833         int rc2 = audioTestStreamDestroy(pTstEnv, &pTstEnv->aStreams[i]);
    834         if (RT_FAILURE(rc2))
    835             RTTestFailed(g_hTest, "Stream destruction for stream #%u failed with %Rrc\n", i, rc2);
    836     }
    837 
    838     audioTestDriverStackDelete(&pTstEnv->DrvStack);
    839 }
    840 
    841 /**
    842  * Closes, packs up and destroys a test environment.
    843  *
    844  * @returns VBox status code.
    845  * @param   pTstEnv             Test environment to handle.
    846  */
    847 static int audioTestEnvPrologue(PAUDIOTESTENV pTstEnv)
    848 {
    849     /* Close the test set first. */
    850     AudioTestSetClose(&pTstEnv->Set);
    851 
    852     /* Before destroying the test environment, pack up the test set so
    853      * that it's ready for transmission. */
    854     char szFileOut[RTPATH_MAX];
    855     int rc = AudioTestSetPack(&pTstEnv->Set, pTstEnv->szPathOut, szFileOut, sizeof(szFileOut));
    856     if (RT_SUCCESS(rc))
    857         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test set packed up to '%s'\n", szFileOut);
    858 
    859     int rc2 = AudioTestSetWipe(&pTstEnv->Set);
    860     if (RT_SUCCESS(rc))
    861         rc = rc2;
    862 
    863     AudioTestSetDestroy(&pTstEnv->Set);
    864 
    865     if (RT_FAILURE(rc))
    866         RTTestFailed(g_hTest, "Test set prologue failed with %Rrc\n", rc);
    867 
    868     return rc;
    869 }
    870 
    871 /**
    872  * Initializes an audio test parameters set.
    873  *
    874  * @param   pTstParms           Test parameters set to initialize.
    875  */
    876 static void audioTestParmsInit(PAUDIOTESTPARMS pTstParms)
    877 {
    878     RT_ZERO(*pTstParms);
    879 }
    880 
    881 /**
    882  * Destroys an audio test parameters set.
    883  *
    884  * @param   pTstParms           Test parameters set to destroy.
    885  */
    886 static void audioTestParmsDestroy(PAUDIOTESTPARMS pTstParms)
    887 {
    888     if (!pTstParms)
    889         return;
    890 
    891     return;
    892 }
    893 
    894 
    895 /*********************************************************************************************************************************
    896 *   Device enumeration + handling.                                                                                               *
    897 *********************************************************************************************************************************/
    898 
    899 /**
    900  * Enumerates audio devices and optionally searches for a specific device.
    901  *
    902  * @returns VBox status code.
    903  * @param   pTstEnv             Test env to use for enumeration.
    904  * @param   pszDev              Device name to search for. Can be NULL if the default device shall be used.
    905  * @param   ppDev               Where to return the pointer of the device enumeration of \a pTstEnv when a
    906  *                              specific device was found.
    907  */
    908 static int audioTestDevicesEnumerateAndCheck(PAUDIOTESTENV pTstEnv, const char *pszDev, PPDMAUDIOHOSTDEV *ppDev)
    909 {
    910 #ifdef DEBUG_andy
    911     return VINF_SUCCESS;
    912 #endif
    913 
    914     RTTestSubF(g_hTest, "Enumerating audio devices and checking for device '%s'", pszDev ? pszDev : "<Default>");
    915 
    916     if (!pTstEnv->DrvStack.pIHostAudio->pfnGetDevices)
    917     {
    918         RTTestSkipped(g_hTest, "Backend does not support device enumeration, skipping");
    919         return VINF_NOT_SUPPORTED;
    920     }
    921 
    922     Assert(pszDev == NULL || ppDev);
    923 
    924     if (ppDev)
    925         *ppDev = NULL;
    926 
    927     int rc = pTstEnv->DrvStack.pIHostAudio->pfnGetDevices(pTstEnv->DrvStack.pIHostAudio, &pTstEnv->DevEnum);
    928     if (RT_SUCCESS(rc))
    929     {
    930         PPDMAUDIOHOSTDEV pDev;
    931         RTListForEach(&pTstEnv->DevEnum.LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry)
    932         {
    933             char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN];
    934             if (pDev->pszId)
    935                 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum: Device '%s' (ID '%s'):\n", pDev->pszName, pDev->pszId);
    936             else
    937                 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum: Device '%s':\n", pDev->pszName);
    938             RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum:   Usage           = %s\n",   PDMAudioDirGetName(pDev->enmUsage));
    939             RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum:   Flags           = %s\n",   PDMAudioHostDevFlagsToString(szFlags, pDev->fFlags));
    940             RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum:   Input channels  = %RU8\n", pDev->cMaxInputChannels);
    941             RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum:   Output channels = %RU8\n", pDev->cMaxOutputChannels);
    942 
    943             if (   pszDev
    944                 && !RTStrCmp(pDev->pszName, pszDev))
    945             {
    946                 *ppDev = pDev;
    947             }
    948         }
    949     }
    950     else
    951         RTTestFailed(g_hTest, "Enumerating audio devices failed with %Rrc", rc);
    952 
    953     RTTestSubDone(g_hTest);
    954 
    955     if (   pszDev
    956         && *ppDev == NULL)
    957     {
    958         RTTestFailed(g_hTest, "Audio device '%s' not found", pszDev);
    959         return VERR_NOT_FOUND;
    960     }
    961 
    962     return VINF_SUCCESS;
    963 }
    964 
    965 /**
    966  * Opens an audio device.
    967  *
    968  * @returns VBox status code.
    969  * @param   pDev                Audio device to open.
    970  */
    971 static int audioTestDeviceOpen(PPDMAUDIOHOSTDEV pDev)
    972 {
    973     int rc = VINF_SUCCESS;
    974 
    975     RTTestSubF(g_hTest, "Opening audio device '%s' ...", pDev->pszName);
    976 
    977     /** @todo Detect + open device here. */
    978 
    979     RTTestSubDone(g_hTest);
    980 
    981     return rc;
    982 }
    983 
    984 /**
    985  * Closes an audio device.
    986  *
    987  * @returns VBox status code.
    988  * @param   pDev                Audio device to close.
    989  */
    990 static int audioTestDeviceClose(PPDMAUDIOHOSTDEV pDev)
    991 {
    992     int rc = VINF_SUCCESS;
    993 
    994     RTTestSubF(g_hTest, "Closing audio device '%s' ...", pDev->pszName);
    995 
    996     /** @todo Close device here. */
    997 
    998     RTTestSubDone(g_hTest);
    999 
    1000     return rc;
    1001 }
    1002 
    1003 /**
    1004  * Destroys an audio test stream.
    1005  *
    1006  * @returns VBox status code.
    1007  * @param   pTstEnv             Test environment the stream to destroy contains.
    1008  * @param   pStream             Audio stream to destroy.
    1009  */
    1010 static int audioTestStreamDestroy(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream)
    1011 {
    1012     int rc = VINF_SUCCESS;
    1013     if (pStream && pStream->pStream)
    1014     {
    1015         /** @todo Anything else to do here, e.g. test if there are left over samples or some such? */
    1016 
    1017         audioTestDriverStackStreamDestroy(&pTstEnv->DrvStack, pStream->pStream);
    1018         pStream->pStream  = NULL;
    1019         pStream->pBackend = NULL;
    1020     }
    1021 
    1022     return rc;
    1023 }
    1024 
    1025 /**
    1026  * Creates an audio default input (recording) test stream.
    1027  * Convenience function.
    1028  *
    1029  * @returns VBox status code.
    1030  * @param   pTstEnv             Test environment to use for creating the stream.
    1031  * @param   pStream             Audio stream to create.
    1032  * @param   pProps              PCM properties to use for creation.
    1033  */
    1034 static int audioTestCreateStreamDefaultIn(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps)
    1035 {
    1036     pStream->pBackend = NULL;
    1037     int rc = audioTestDriverStackStreamCreateInput(&pTstEnv->DrvStack, pProps, pTstEnv->cMsBufferSize, pTstEnv->cMsPreBuffer,
    1038                                                    pTstEnv->cMsSchedulingHint, &pStream->pStream, &pStream->Cfg);
    1039     if (RT_SUCCESS(rc) && !pTstEnv->DrvStack.pIAudioConnector)
    1040         pStream->pBackend = &((PAUDIOTESTDRVSTACKSTREAM)pStream->pStream)->Backend;
    1041     return rc;
    1042 }
    1043 
    1044 /**
    1045  * Creates an audio default output (playback) test stream.
    1046  * Convenience function.
    1047  *
    1048  * @returns VBox status code.
    1049  * @param   pTstEnv             Test environment to use for creating the stream.
    1050  * @param   pStream             Audio stream to create.
    1051  * @param   pProps              PCM properties to use for creation.
    1052  */
    1053 static int audioTestCreateStreamDefaultOut(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps)
    1054 {
    1055     pStream->pBackend = NULL;
    1056     int rc = audioTestDriverStackStreamCreateOutput(&pTstEnv->DrvStack, pProps, pTstEnv->cMsBufferSize, pTstEnv->cMsPreBuffer,
    1057                                                     pTstEnv->cMsSchedulingHint, &pStream->pStream, &pStream->Cfg);
    1058     if (RT_SUCCESS(rc) && !pTstEnv->DrvStack.pIAudioConnector)
    1059         pStream->pBackend = &((PAUDIOTESTDRVSTACKSTREAM)pStream->pStream)->Backend;
    1060     return rc;
    1061 }
    1062250
    1063251/**
     
    1341529 * @param   pOverrideParms      Test parameters for (some / all) specific test parameters. Optional.
    1342530 */
    1343 static int audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms)
     531int audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms)
    1344532{
    1345533    int rc = VINF_SUCCESS;
     
    18621050}
    18631051
    1864 
    1865 /*********************************************************************************************************************************
    1866 *   Command: play                                                                                                                *
    1867 *********************************************************************************************************************************/
    1868 
    1869 /**
    1870  * Worker for audioTestPlayOne implementing the play loop.
    1871  */
    1872 static RTEXITCODE audioTestPlayOneInner(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTWAVEFILE pWaveFile,
    1873                                         PCPDMAUDIOSTREAMCFG pCfgAcq, const char *pszFile)
    1874 {
    1875     uint32_t const  cbPreBuffer        = PDMAudioPropsFramesToBytes(pMix->pProps, pCfgAcq->Backend.cFramesPreBuffering);
    1876     uint64_t const  nsStarted          = RTTimeNanoTS();
    1877     uint64_t        nsDonePreBuffering = 0;
    1878 
    1879     /*
    1880      * Transfer data as quickly as we're allowed.
    1881      */
    1882     uint8_t         abSamples[16384];
    1883     uint32_t const  cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples));
    1884     uint64_t        offStream        = 0;
    1885     while (!g_fTerminate)
    1886     {
    1887         /* Read a chunk from the wave file. */
    1888         size_t      cbSamples = 0;
    1889         int rc = AudioTestWaveFileRead(pWaveFile, abSamples, cbSamplesAligned, &cbSamples);
    1890         if (RT_SUCCESS(rc) && cbSamples > 0)
    1891         {
    1892             /* Pace ourselves a little. */
    1893             if (offStream >= cbPreBuffer)
    1894             {
    1895                 if (!nsDonePreBuffering)
    1896                     nsDonePreBuffering = RTTimeNanoTS();
    1897                 uint64_t const cNsWritten = PDMAudioPropsBytesToNano64(pMix->pProps, offStream - cbPreBuffer);
    1898                 uint64_t const cNsElapsed = RTTimeNanoTS() - nsStarted;
    1899                 if (cNsWritten > cNsElapsed + RT_NS_10MS)
    1900                     RTThreadSleep((cNsWritten - cNsElapsed - RT_NS_10MS / 2) / RT_NS_1MS);
    1901             }
    1902 
    1903             /* Transfer the data to the audio stream. */
    1904             for (uint32_t offSamples = 0; offSamples < cbSamples;)
    1905             {
    1906                 uint32_t const cbCanWrite = AudioTestMixStreamGetWritable(pMix);
    1907                 if (cbCanWrite > 0)
    1908                 {
    1909                     uint32_t const cbToPlay = RT_MIN(cbCanWrite, (uint32_t)cbSamples - offSamples);
    1910                     uint32_t       cbPlayed = 0;
    1911                     rc = AudioTestMixStreamPlay(pMix, &abSamples[offSamples], cbToPlay, &cbPlayed);
    1912                     if (RT_SUCCESS(rc))
    1913                     {
    1914                         if (cbPlayed)
    1915                         {
    1916                             offSamples += cbPlayed;
    1917                             offStream  += cbPlayed;
    1918                         }
    1919                         else
    1920                             return RTMsgErrorExitFailure("Played zero bytes - %#x bytes reported playable!\n", cbCanWrite);
    1921                     }
    1922                     else
    1923                         return RTMsgErrorExitFailure("Failed to play %#x bytes: %Rrc\n", cbToPlay, rc);
    1924                 }
    1925                 else if (AudioTestMixStreamIsOkay(pMix))
    1926                     RTThreadSleep(RT_MIN(RT_MAX(1, pCfgAcq->Device.cMsSchedulingHint), 256));
    1927                 else
    1928                     return RTMsgErrorExitFailure("Stream is not okay!\n");
    1929             }
    1930         }
    1931         else if (RT_SUCCESS(rc) && cbSamples == 0)
    1932             break;
    1933         else
    1934             return RTMsgErrorExitFailure("Error reading wav file '%s': %Rrc", pszFile, rc);
    1935     }
    1936 
    1937     /*
    1938      * Drain the stream.
    1939      */
    1940     if (g_uVerbosity > 0)
    1941         RTMsgInfo("%'RU64 ns: Draining...\n", RTTimeNanoTS() - nsStarted);
    1942     int rc = AudioTestMixStreamDrain(pMix, true /*fSync*/);
    1943     if (RT_SUCCESS(rc))
    1944     {
    1945         if (g_uVerbosity > 0)
    1946             RTMsgInfo("%'RU64 ns: Done\n", RTTimeNanoTS() - nsStarted);
    1947     }
    1948     else
    1949         return RTMsgErrorExitFailure("Draining failed: %Rrc", rc);
    1950 
    1951     return RTEXITCODE_SUCCESS;
    1952 }
    1953 
    1954 
    1955 /**
    1956  * Worker for audioTestCmdPlayHandler that plays one file.
    1957  */
    1958 static RTEXITCODE audioTestPlayOne(const char *pszFile, PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
    1959                                    uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
    1960                                    uint8_t cChannels, uint8_t cbSample, uint32_t uHz,
    1961                                    bool fWithDrvAudio, bool fWithMixer)
    1962 {
    1963     char szTmp[128];
    1964 
    1965     /*
    1966      * First we must open the file and determin the format.
    1967      */
    1968     RTERRINFOSTATIC ErrInfo;
    1969     AUDIOTESTWAVEFILE WaveFile;
    1970     int rc = AudioTestWaveFileOpen(pszFile, &WaveFile, RTErrInfoInitStatic(&ErrInfo));
    1971     if (RT_FAILURE(rc))
    1972         return RTMsgErrorExitFailure("Failed to open '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core);
    1973 
    1974     if (g_uVerbosity > 0)
    1975     {
    1976         RTMsgInfo("Opened '%s' for playing\n", pszFile);
    1977         RTMsgInfo("Format: %s\n", PDMAudioPropsToString(&WaveFile.Props, szTmp, sizeof(szTmp)));
    1978         RTMsgInfo("Size:   %'RU32 bytes / %#RX32 / %'RU32 frames / %'RU64 ns\n",
    1979                   WaveFile.cbSamples, WaveFile.cbSamples,
    1980                   PDMAudioPropsBytesToFrames(&WaveFile.Props, WaveFile.cbSamples),
    1981                   PDMAudioPropsBytesToNano(&WaveFile.Props, WaveFile.cbSamples));
    1982     }
    1983 
    1984     /*
    1985      * Construct the driver stack.
    1986      */
    1987     RTEXITCODE          rcExit = RTEXITCODE_FAILURE;
    1988     AUDIOTESTDRVSTACK   DrvStack;
    1989     rc = audioTestDriverStackInit(&DrvStack, pDrvReg, fWithDrvAudio);
    1990     if (RT_SUCCESS(rc))
    1991     {
    1992         /*
    1993          * Set the output device if one is specified.
    1994          */
    1995         rc = audioTestDriverStackSetDevice(&DrvStack, PDMAUDIODIR_OUT, pszDevId);
    1996         if (RT_SUCCESS(rc))
    1997         {
    1998             /*
    1999              * Open a stream for the output.
    2000              */
    2001             PDMAUDIOPCMPROPS ReqProps = WaveFile.Props;
    2002             if (cChannels != 0 && PDMAudioPropsChannels(&ReqProps) != cChannels)
    2003                 PDMAudioPropsSetChannels(&ReqProps, cChannels);
    2004             if (cbSample != 0)
    2005                 PDMAudioPropsSetSampleSize(&ReqProps, cbSample);
    2006             if (uHz != 0)
    2007                 ReqProps.uHz = uHz;
    2008 
    2009             PDMAUDIOSTREAMCFG CfgAcq;
    2010             PPDMAUDIOSTREAM   pStream  = NULL;
    2011             rc = audioTestDriverStackStreamCreateOutput(&DrvStack, &ReqProps, cMsBufferSize,
    2012                                                         cMsPreBuffer, cMsSchedulingHint, &pStream, &CfgAcq);
    2013             if (RT_SUCCESS(rc))
    2014             {
    2015                 /*
    2016                  * Automatically enable the mixer if the wave file and the
    2017                  * output parameters doesn't match.
    2018                  */
    2019                 if (   !fWithMixer
    2020                     && !PDMAudioPropsAreEqual(&WaveFile.Props, &pStream->Cfg.Props))
    2021                 {
    2022                     RTMsgInfo("Enabling the mixer buffer.\n");
    2023                     fWithMixer = true;
    2024                 }
    2025 
    2026                 /*
    2027                  * Create a mixer wrapper.  This is just a thin wrapper if fWithMixer
    2028                  * is false, otherwise it's doing mixing, resampling and recoding.
    2029                  */
    2030                 AUDIOTESTDRVMIXSTREAM Mix;
    2031                 rc = AudioTestMixStreamInit(&Mix, &DrvStack, pStream, fWithMixer ? &WaveFile.Props : NULL, 100 /*ms*/);
    2032                 if (RT_SUCCESS(rc))
    2033                 {
    2034                     if (g_uVerbosity > 0)
    2035                         RTMsgInfo("Stream: %s cbBackend=%#RX32%s\n",
    2036                                   PDMAudioPropsToString(&pStream->Cfg.Props, szTmp, sizeof(szTmp)),
    2037                                   pStream->cbBackend, fWithMixer ? " mixed" : "");
    2038 
    2039                     /*
    2040                      * Enable the stream and start playing.
    2041                      */
    2042                     rc = AudioTestMixStreamEnable(&Mix);
    2043                     if (RT_SUCCESS(rc))
    2044                         rcExit = audioTestPlayOneInner(&Mix, &WaveFile, &CfgAcq, pszFile);
    2045                     else
    2046                         rcExit = RTMsgErrorExitFailure("Enabling the output stream failed: %Rrc", rc);
    2047 
    2048                     /*
    2049                      * Clean up.
    2050                      */
    2051                     AudioTestMixStreamTerm(&Mix);
    2052                 }
    2053                 audioTestDriverStackStreamDestroy(&DrvStack, pStream);
    2054             }
    2055             else
    2056                 rcExit = RTMsgErrorExitFailure("Creating output stream failed: %Rrc", rc);
    2057         }
    2058         else
    2059             rcExit = RTMsgErrorExitFailure("Failed to set output device to '%s': %Rrc", pszDevId, rc);
    2060         audioTestDriverStackDelete(&DrvStack);
    2061     }
    2062     else
    2063         rcExit = RTMsgErrorExitFailure("Driver stack construction failed: %Rrc", rc);
    2064     AudioTestWaveFileClose(&WaveFile);
    2065     return rcExit;
    2066 }
    2067 
    20681052/**
    20691053 * Options for 'play'.
     
    21761160*   Command: rec                                                                                                                 *
    21771161*********************************************************************************************************************************/
    2178 
    2179 /**
    2180  * Worker for audioTestRecOne implementing the recording loop.
    2181  */
    2182 static RTEXITCODE audioTestRecOneInner(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTWAVEFILE pWaveFile,
    2183                                        PCPDMAUDIOSTREAMCFG pCfgAcq, uint64_t cMaxFrames, const char *pszFile)
    2184 {
    2185     int             rc;
    2186     uint64_t const  nsStarted   = RTTimeNanoTS();
    2187 
    2188     /*
    2189      * Transfer data as quickly as we're allowed.
    2190      */
    2191     uint8_t         abSamples[16384];
    2192     uint32_t const  cbSamplesAligned     = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples));
    2193     uint64_t        cFramesCapturedTotal = 0;
    2194     while (!g_fTerminate && cFramesCapturedTotal < cMaxFrames)
    2195     {
    2196         /*
    2197          * Anything we can read?
    2198          */
    2199         uint32_t const cbCanRead = AudioTestMixStreamGetReadable(pMix);
    2200         if (cbCanRead)
    2201         {
    2202             uint32_t const cbToRead   = RT_MIN(cbCanRead, cbSamplesAligned);
    2203             uint32_t       cbCaptured = 0;
    2204             rc = AudioTestMixStreamCapture(pMix, abSamples, cbToRead, &cbCaptured);
    2205             if (RT_SUCCESS(rc))
    2206             {
    2207                 if (cbCaptured)
    2208                 {
    2209                     uint32_t cFramesCaptured = PDMAudioPropsBytesToFrames(pMix->pProps, cbCaptured);
    2210                     if (cFramesCaptured + cFramesCaptured < cMaxFrames)
    2211                     { /* likely */ }
    2212                     else
    2213                     {
    2214                         cFramesCaptured = cMaxFrames - cFramesCaptured;
    2215                         cbCaptured      = PDMAudioPropsFramesToBytes(pMix->pProps, cFramesCaptured);
    2216                     }
    2217 
    2218                     rc = AudioTestWaveFileWrite(pWaveFile, abSamples, cbCaptured);
    2219                     if (RT_SUCCESS(rc))
    2220                         cFramesCapturedTotal += cFramesCaptured;
    2221                     else
    2222                         return RTMsgErrorExitFailure("Error writing to '%s': %Rrc", pszFile, rc);
    2223                 }
    2224                 else
    2225                     return RTMsgErrorExitFailure("Captured zero bytes - %#x bytes reported readable!\n", cbCanRead);
    2226             }
    2227             else
    2228                 return RTMsgErrorExitFailure("Failed to capture %#x bytes: %Rrc (%#x available)\n", cbToRead, rc, cbCanRead);
    2229         }
    2230         else if (AudioTestMixStreamIsOkay(pMix))
    2231             RTThreadSleep(RT_MIN(RT_MAX(1, pCfgAcq->Device.cMsSchedulingHint), 256));
    2232         else
    2233             return RTMsgErrorExitFailure("Stream is not okay!\n");
    2234     }
    2235 
    2236     /*
    2237      * Disable the stream.
    2238      */
    2239     rc = AudioTestMixStreamDisable(pMix);
    2240     if (RT_SUCCESS(rc) && g_uVerbosity > 0)
    2241         RTMsgInfo("%'RU64 ns: Stopped after recording %RU64 frames%s\n", RTTimeNanoTS() - nsStarted, cFramesCapturedTotal,
    2242                   g_fTerminate ? " - Ctrl-C" : ".");
    2243     else if (RT_FAILURE(rc))
    2244         return RTMsgErrorExitFailure("Disabling stream failed: %Rrc", rc);
    2245 
    2246     return RTEXITCODE_SUCCESS;
    2247 }
    2248 
    2249 
    2250 /**
    2251  * Worker for audioTestCmdRecHandler that recs one file.
    2252  */
    2253 static RTEXITCODE audioTestRecOne(const char *pszFile, uint8_t cWaveChannels, uint8_t cbWaveSample, uint32_t uWaveHz,
    2254                                   PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
    2255                                   uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
    2256                                   uint8_t cChannels, uint8_t cbSample, uint32_t uHz, bool fWithDrvAudio, bool fWithMixer,
    2257                                   uint64_t cMaxFrames, uint64_t cNsMaxDuration)
    2258 {
    2259     /*
    2260      * Construct the driver stack.
    2261      */
    2262     RTEXITCODE          rcExit = RTEXITCODE_FAILURE;
    2263     AUDIOTESTDRVSTACK   DrvStack;
    2264     int rc = audioTestDriverStackInit(&DrvStack, pDrvReg, fWithDrvAudio);
    2265     if (RT_SUCCESS(rc))
    2266     {
    2267         /*
    2268          * Set the input device if one is specified.
    2269          */
    2270         rc = audioTestDriverStackSetDevice(&DrvStack, PDMAUDIODIR_IN, pszDevId);
    2271         if (RT_SUCCESS(rc))
    2272         {
    2273             /*
    2274              * Create an input stream.
    2275              */
    2276             PDMAUDIOPCMPROPS  ReqProps;
    2277             PDMAudioPropsInit(&ReqProps,
    2278                               cbSample ? cbSample : cbWaveSample ? cbWaveSample : 2,
    2279                               true /*fSigned*/,
    2280                               cChannels ? cChannels : cWaveChannels ? cWaveChannels : 2,
    2281                               uHz ? uHz : uWaveHz ? uWaveHz : 44100);
    2282             PDMAUDIOSTREAMCFG CfgAcq;
    2283             PPDMAUDIOSTREAM   pStream  = NULL;
    2284             rc = audioTestDriverStackStreamCreateInput(&DrvStack, &ReqProps, cMsBufferSize,
    2285                                                        cMsPreBuffer, cMsSchedulingHint, &pStream, &CfgAcq);
    2286             if (RT_SUCCESS(rc))
    2287             {
    2288                 /*
    2289                  * Determine the wave file properties.  If it differs from the stream
    2290                  * properties, make sure the mixer is enabled.
    2291                  */
    2292                 PDMAUDIOPCMPROPS WaveProps;
    2293                 PDMAudioPropsInit(&WaveProps,
    2294                                   cbWaveSample ? cbWaveSample : PDMAudioPropsSampleSize(&CfgAcq.Props),
    2295                                   true /*fSigned*/,
    2296                                   cWaveChannels ? cWaveChannels : PDMAudioPropsChannels(&CfgAcq.Props),
    2297                                   uWaveHz ? uWaveHz : PDMAudioPropsHz(&CfgAcq.Props));
    2298                 if (!fWithMixer && !PDMAudioPropsAreEqual(&WaveProps, &CfgAcq.Props))
    2299                 {
    2300                     RTMsgInfo("Enabling the mixer buffer.\n");
    2301                     fWithMixer = true;
    2302                 }
    2303 
    2304                 /* Console the max duration into frames now that we've got the wave file format. */
    2305                 if (cMaxFrames != UINT64_MAX && cNsMaxDuration != UINT64_MAX)
    2306                 {
    2307                     uint64_t cMaxFrames2 = PDMAudioPropsNanoToBytes64(&WaveProps, cNsMaxDuration);
    2308                     cMaxFrames = RT_MAX(cMaxFrames, cMaxFrames2);
    2309                 }
    2310                 else if (cNsMaxDuration != UINT64_MAX)
    2311                     cMaxFrames = PDMAudioPropsNanoToBytes64(&WaveProps, cNsMaxDuration);
    2312 
    2313                 /*
    2314                  * Create a mixer wrapper.  This is just a thin wrapper if fWithMixer
    2315                  * is false, otherwise it's doing mixing, resampling and recoding.
    2316                  */
    2317                 AUDIOTESTDRVMIXSTREAM Mix;
    2318                 rc = AudioTestMixStreamInit(&Mix, &DrvStack, pStream, fWithMixer ? &WaveProps : NULL, 100 /*ms*/);
    2319                 if (RT_SUCCESS(rc))
    2320                 {
    2321                     char szTmp[128];
    2322                     if (g_uVerbosity > 0)
    2323                         RTMsgInfo("Stream: %s cbBackend=%#RX32%s\n",
    2324                                   PDMAudioPropsToString(&pStream->Cfg.Props, szTmp, sizeof(szTmp)),
    2325                                   pStream->cbBackend, fWithMixer ? " mixed" : "");
    2326 
    2327                     /*
    2328                      * Open the wave output file.
    2329                      */
    2330                     AUDIOTESTWAVEFILE WaveFile;
    2331                     RTERRINFOSTATIC ErrInfo;
    2332                     rc = AudioTestWaveFileCreate(pszFile, &WaveProps, &WaveFile, RTErrInfoInitStatic(&ErrInfo));
    2333                     if (RT_SUCCESS(rc))
    2334                     {
    2335                         if (g_uVerbosity > 0)
    2336                         {
    2337                             RTMsgInfo("Opened '%s' for playing\n", pszFile);
    2338                             RTMsgInfo("Format: %s\n", PDMAudioPropsToString(&WaveFile.Props, szTmp, sizeof(szTmp)));
    2339                         }
    2340 
    2341                         /*
    2342                          * Enable the stream and start recording.
    2343                          */
    2344                         rc = AudioTestMixStreamEnable(&Mix);
    2345                         if (RT_SUCCESS(rc))
    2346                             rcExit = audioTestRecOneInner(&Mix, &WaveFile, &CfgAcq, cMaxFrames, pszFile);
    2347                         else
    2348                             rcExit = RTMsgErrorExitFailure("Enabling the input stream failed: %Rrc", rc);
    2349                         if (rcExit != RTEXITCODE_SUCCESS)
    2350                             AudioTestMixStreamDisable(&Mix);
    2351 
    2352                         /*
    2353                          * Clean up.
    2354                          */
    2355                         rc = AudioTestWaveFileClose(&WaveFile);
    2356                         if (RT_FAILURE(rc))
    2357                             rcExit = RTMsgErrorExitFailure("Error closing '%s': %Rrc", pszFile, rc);
    2358                     }
    2359                     else
    2360                         rcExit = RTMsgErrorExitFailure("Failed to open '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core.pszMsg);
    2361 
    2362                     AudioTestMixStreamTerm(&Mix);
    2363                 }
    2364                 audioTestDriverStackStreamDestroy(&DrvStack, pStream);
    2365             }
    2366             else
    2367                 rcExit = RTMsgErrorExitFailure("Creating output stream failed: %Rrc", rc);
    2368         }
    2369         else
    2370             rcExit = RTMsgErrorExitFailure("Failed to set output device to '%s': %Rrc", pszDevId, rc);
    2371         audioTestDriverStackDelete(&DrvStack);
    2372     }
    2373     else
    2374         rcExit = RTMsgErrorExitFailure("Driver stack construction failed: %Rrc", rc);
    2375     return rcExit;
    2376 }
    23771162
    23781163/**
     
    25401325*********************************************************************************************************************************/
    25411326
    2542 /** @todo Move this (all?) commands into separate files -- this file is too big already. */
    2543 
    25441327/**
    25451328 * Command line parameters for self-test mode.
     
    25701353
    25711354/**
    2572  * Structure for keeping a VKAT self test context.
    2573  */
    2574 typedef struct SELFTESTCTX
    2575 {
    2576     /** Common tag for guest and host side. */
    2577     char             szTag[AUDIOTEST_TAG_MAX];
    2578     /** Whether to use DrvAudio in the driver stack or not. */
    2579     bool             fWithDrvAudio;
    2580     struct
    2581     {
    2582         AUDIOTESTENV TstEnv;
    2583         /** Audio driver to use.
    2584          *  Defaults to the platform's default driver. */
    2585         PCPDMDRVREG  pDrvReg;
    2586     } Guest;
    2587     struct
    2588     {
    2589         AUDIOTESTENV TstEnv;
    2590         /** Address of the guest ATS instance.
    2591          *  Defaults to localhost (127.0.0.1) if not set. */
    2592         char         szGuestAtsAddr[64];
    2593         /** Port of the guest ATS instance.
    2594          *  Defaults to ATS_DEFAULT_PORT if not set. */
    2595         uint32_t     uGuestAtsPort;
    2596         /** Address of the Validation Kit audio driver ATS instance.
    2597          *  Defaults to localhost (127.0.0.1) if not set. */
    2598         char         szValKitAtsAddr[64];
    2599         /** Port of the Validation Kit audio driver ATS instance.
    2600          *  Defaults to ATS_ALT_PORT if not set. */
    2601         uint32_t     uValKitAtsPort;
    2602     } Host;
    2603 } SELFTESTCTX;
    2604 /** Pointer to a VKAT self test context. */
    2605 typedef SELFTESTCTX *PSELFTESTCTX;
    2606 
    2607 static DECLCALLBACK(int) audioTestSelftestGuestAtsThread(RTTHREAD hThread, void *pvUser)
    2608 {
    2609     RT_NOREF(hThread);
    2610     PSELFTESTCTX pCtx = (PSELFTESTCTX)pvUser;
    2611 
    2612     AUDIOTESTPARMS TstCust;
    2613     audioTestParmsInit(&TstCust);
    2614 
    2615     PAUDIOTESTENV pTstEnv = &pCtx->Guest.TstEnv;
    2616 
    2617     /* Flag the environment for self test mode. */
    2618     pTstEnv->fSelftest = true;
    2619 
    2620     /* Generate tag for guest side. */
    2621     int rc = RTStrCopy(pTstEnv->szTag, sizeof(pTstEnv->szTag), pCtx->szTag);
    2622     AssertRCReturn(rc, rc);
    2623 
    2624     rc = AudioTestPathCreateTemp(pTstEnv->szPathTemp, sizeof(pTstEnv->szPathTemp), "selftest-guest");
    2625     AssertRCReturn(rc, rc);
    2626 
    2627     rc = AudioTestPathCreateTemp(pTstEnv->szPathOut, sizeof(pTstEnv->szPathOut), "selftest-out");
    2628     AssertRCReturn(rc, rc);
    2629 
    2630     pTstEnv->enmMode = AUDIOTESTMODE_GUEST;
    2631 
    2632     /** @todo Make this customizable. */
    2633     PDMAudioPropsInit(&TstCust.TestTone.Props,
    2634                       2 /* 16-bit */, true  /* fSigned */, 2 /* cChannels */, 44100 /* uHz */);
    2635 
    2636     /* Use ATS_ALT_PORT, as on ATS_DEFAULT_PORT the
    2637      * Validation Kit audio driver ATS already is running on ATS_DEFAULT_PORT. */
    2638     rc = audioTestEnvInit(pTstEnv, pCtx->Guest.pDrvReg, pCtx->fWithDrvAudio,
    2639                           "127.0.0.1", ATS_TCP_ALT_PORT);
    2640     if (RT_SUCCESS(rc))
    2641     {
    2642         RTThreadUserSignal(hThread);
    2643 
    2644         audioTestWorker(pTstEnv, &TstCust);
    2645         audioTestEnvDestroy(pTstEnv);
    2646     }
    2647 
    2648     audioTestParmsDestroy(&TstCust);
    2649 
    2650     return rc;
    2651 }
    2652 
    2653 /**
    2654  * Main function for performing the self test.
    2655  *
    2656  * @returns VBox status code.
    2657  * @param   pCtx                Self test context to use.
    2658  */
    2659 static int audioTestDoSelftest(PSELFTESTCTX pCtx)
    2660 {
    2661     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,  "Running self test ...\n");
    2662 
    2663     /*
    2664      * The self-test does the following:
    2665      * - 1. Creates an ATS instance to emulate the guest mode ("--mode guest")
    2666      *      at port 6042 (ATS_ALT_PORT).
    2667      * - 2. Uses the Validation Kit audio backend, which in turn creates an ATS instance
    2668      *      at port 6052 (ATS_DEFAULT_PORT).
    2669      * - 3. Executes a complete test run locally (e.g. without any guest (VM) involved).
    2670      */
    2671 
    2672     AUDIOTESTPARMS TstCust;
    2673     audioTestParmsInit(&TstCust);
    2674 
    2675     /* Generate a common tag for guest and host side. */
    2676     int rc = AudioTestGenTag(pCtx->szTag, sizeof(pCtx->szTag));
    2677     AssertRCReturn(rc, rc);
    2678 
    2679     PAUDIOTESTENV pTstEnv = &pCtx->Host.TstEnv;
    2680 
    2681     /* Flag the environment for self test mode. */
    2682     pTstEnv->fSelftest = true;
    2683 
    2684     /* Generate tag for host side. */
    2685     rc = RTStrCopy(pTstEnv->szTag, sizeof(pTstEnv->szTag), pCtx->szTag);
    2686     AssertRCReturn(rc, rc);
    2687 
    2688     rc = AudioTestPathCreateTemp(pTstEnv->szPathTemp, sizeof(pTstEnv->szPathTemp), "selftest-host");
    2689     AssertRCReturn(rc, rc);
    2690 
    2691     rc = AudioTestPathCreateTemp(pTstEnv->szPathOut, sizeof(pTstEnv->szPathOut), "selftest-out");
    2692     AssertRCReturn(rc, rc);
    2693 
    2694     /*
    2695      * Step 1.
    2696      * Creates a separate thread for the guest ATS.
    2697      */
    2698     RTTHREAD hThreadGstAts;
    2699     rc = RTThreadCreate(&hThreadGstAts, audioTestSelftestGuestAtsThread, pCtx, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE,
    2700                         "VKATGstAts");
    2701     if (RT_SUCCESS(rc))
    2702     {
    2703         rc = RTThreadUserWait(hThreadGstAts, RT_MS_30SEC);
    2704         if (RT_SUCCESS(rc))
    2705         {
    2706             /*
    2707              * Steps 2 + 3.
    2708              */
    2709             pTstEnv->enmMode = AUDIOTESTMODE_HOST;
    2710 
    2711             if (!pCtx->Host.uGuestAtsPort)
    2712                 pCtx->Host.uGuestAtsPort = ATS_TCP_ALT_PORT;
    2713 
    2714             rc = audioTestEnvInit(pTstEnv, &g_DrvHostValidationKitAudio, true /* fWithDrvAudio */,
    2715                                   pCtx->Host.szGuestAtsAddr, pCtx->Host.uGuestAtsPort);
    2716             if (RT_SUCCESS(rc))
    2717             {
    2718                 audioTestWorker(pTstEnv, &TstCust);
    2719                 audioTestEnvDestroy(pTstEnv);
    2720             }
    2721         }
    2722     }
    2723 
    2724     audioTestParmsDestroy(&TstCust);
    2725 
    2726     /*
    2727      * Shutting down.
    2728      */
    2729     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,  "Shutting down self test\n");
    2730 
    2731     ASMAtomicWriteBool(&g_fTerminate, true);
    2732 
    2733     int rcThread;
    2734     int rc2 = RTThreadWait(hThreadGstAts, RT_MS_30SEC, &rcThread);
    2735     if (RT_SUCCESS(rc2))
    2736         rc2 = rcThread;
    2737     if (RT_FAILURE(rc2))
    2738         RTTestFailed(g_hTest, "Shutting down self test failed with %Rrc\n", rc2);
    2739 
    2740     if (RT_SUCCESS(rc))
    2741         rc = rc2;
    2742 
    2743     if (RT_FAILURE(rc))
    2744         RTTestFailed(g_hTest, "Self test failed with %Rrc\n", rc);
    2745 
    2746     return rc;
    2747 }
    2748 
    2749 /**
    27501355 * The 'selftest' command handler.
    27511356 *
     
    27531358 * @param   pGetState   RTGetOpt state.
    27541359 */
    2755 static DECLCALLBACK(RTEXITCODE) audioTestCmdSelftestHandler(PRTGETOPTSTATE pGetState)
     1360DECLCALLBACK(RTEXITCODE) audioTestCmdSelftestHandler(PRTGETOPTSTATE pGetState)
    27561361{
    27571362    SELFTESTCTX Ctx;
     
    27901395
    27911396            case 'b':
    2792             {
    27931397                Ctx.Guest.pDrvReg = audioTestFindBackendOpt(ValueUnion.psz);
    27941398                if (Ctx.Guest.pDrvReg == NULL)
    27951399                    return RTEXITCODE_SYNTAX;
    27961400                break;
    2797             }
    27981401
    27991402            case 'd':
  • trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h

    r89490 r89544  
    3131#endif
    3232
     33#include <iprt/getopt.h>
     34
    3335#include <VBox/vmm/pdmdrv.h>
    3436#include <VBox/vmm/pdmaudioinline.h>
    3537#include <VBox/vmm/pdmaudiohostenuminline.h>
     38
    3639#include "Audio/AudioMixBuffer.h"
    37 
    38 
     40#include "Audio/AudioTest.h"
     41#include "Audio/AudioTestService.h"
     42#include "Audio/AudioTestServiceClient.h"
     43
     44#include "VBoxDD.h"
     45
     46
     47/*********************************************************************************************************************************
     48*   Externals                                                                                                                    *
     49*********************************************************************************************************************************/
     50/** Terminate ASAP if set.  Set on Ctrl-C. */
     51extern bool volatile    g_fTerminate;
     52/** The release logger. */
     53extern PRTLOGGER        g_pRelLogger;
     54
     55/** The test handle. */
     56extern RTTEST         g_hTest;
     57extern unsigned       g_uVerbosity;
     58extern bool           g_fDrvAudioDebug;
     59extern const char    *g_pszDrvAudioDebug;
     60
     61/** The test handle. */
     62extern RTTEST         g_hTest;
     63/** The current verbosity level. */
     64extern unsigned       g_uVerbosity;
     65/** DrvAudio: Enable debug (or not). */
     66extern bool           g_fDrvAudioDebug;
     67/** DrvAudio: The debug output path. */
     68extern const char    *g_pszDrvAudioDebug;
     69
     70
     71/*********************************************************************************************************************************
     72*   Defined Constants And Macros                                                                                                 *
     73*********************************************************************************************************************************/
     74
     75
     76/*********************************************************************************************************************************
     77*   Structures and Typedefs                                                                                                      *
     78*********************************************************************************************************************************/
    3979/**
    4080 * Audio driver stack.
     
    97137typedef AUDIOTESTDRVMIXSTREAM *PAUDIOTESTDRVMIXSTREAM;
    98138
    99 
    100 /** The test handle. */
    101 extern RTTEST         g_hTest;
    102 extern unsigned       g_uVerbosity;
    103 extern bool           g_fDrvAudioDebug;
    104 extern const char    *g_pszDrvAudioDebug;
    105 
     139/**
     140 * Backends.
     141 *
     142 * @note The first backend in the array is the default one for the platform.
     143 */
     144struct
     145{
     146    /** The driver registration structure. */
     147    PCPDMDRVREG pDrvReg;
     148    /** The backend name.
     149     * Aliases are implemented by having multiple entries for the same backend.  */
     150    const char *pszName;
     151} const g_aBackends[] =
     152{
     153#if defined(VBOX_WITH_AUDIO_ALSA) && defined(RT_OS_LINUX)
     154    {   &g_DrvHostALSAAudio,          "alsa" },
     155#endif
     156#ifdef VBOX_WITH_AUDIO_PULSE
     157    {   &g_DrvHostPulseAudio,         "pulseaudio" },
     158    {   &g_DrvHostPulseAudio,         "pulse" },
     159    {   &g_DrvHostPulseAudio,         "pa" },
     160#endif
     161#ifdef VBOX_WITH_AUDIO_OSS
     162    {   &g_DrvHostOSSAudio,           "oss" },
     163#endif
     164#if defined(RT_OS_DARWIN)
     165    {   &g_DrvHostCoreAudio,          "coreaudio" },
     166    {   &g_DrvHostCoreAudio,          "core" },
     167    {   &g_DrvHostCoreAudio,          "ca" },
     168#endif
     169#if defined(RT_OS_WINDOWS)
     170    {   &g_DrvHostAudioWas,           "wasapi" },
     171    {   &g_DrvHostAudioWas,           "was" },
     172    {   &g_DrvHostDSound,             "directsound" },
     173    {   &g_DrvHostDSound,             "dsound" },
     174    {   &g_DrvHostDSound,             "ds" },
     175#endif
     176    {   &g_DrvHostValidationKitAudio, "valkit" }
     177};
     178AssertCompile(sizeof(g_aBackends) > 0 /* port me */);
     179
     180
     181
     182/**
     183 * Enumeration specifying the current audio test mode.
     184 */
     185typedef enum AUDIOTESTMODE
     186{
     187    /** Unknown mode. */
     188    AUDIOTESTMODE_UNKNOWN = 0,
     189    /** VKAT is running on the guest side. */
     190    AUDIOTESTMODE_GUEST,
     191    /** VKAT is running on the host side. */
     192    AUDIOTESTMODE_HOST
     193} AUDIOTESTMODE;
     194
     195struct AUDIOTESTENV;
     196/** Pointer a audio test environment. */
     197typedef AUDIOTESTENV *PAUDIOTESTENV;
     198
     199struct AUDIOTESTDESC;
     200/** Pointer a audio test descriptor. */
     201typedef AUDIOTESTDESC *PAUDIOTESTDESC;
     202
     203/**
     204 * Callback to set up the test parameters for a specific test.
     205 *
     206 * @returns IPRT status code.
     207 * @retval  VINF_SUCCESS    if setting the parameters up succeeded. Any other error code
     208 *                          otherwise indicating the kind of error.
     209 * @param   pszTest         Test name.
     210 * @param   pTstParmsAcq    The audio test parameters to set up.
     211 */
     212typedef DECLCALLBACKTYPE(int, FNAUDIOTESTSETUP,(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx));
     213/** Pointer to an audio test setup callback. */
     214typedef FNAUDIOTESTSETUP *PFNAUDIOTESTSETUP;
     215
     216typedef DECLCALLBACKTYPE(int, FNAUDIOTESTEXEC,(PAUDIOTESTENV pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms));
     217/** Pointer to an audio test exec callback. */
     218typedef FNAUDIOTESTEXEC *PFNAUDIOTESTEXEC;
     219
     220typedef DECLCALLBACKTYPE(int, FNAUDIOTESTDESTROY,(PAUDIOTESTENV pTstEnv, void *pvCtx));
     221/** Pointer to an audio test destroy callback. */
     222typedef FNAUDIOTESTDESTROY *PFNAUDIOTESTDESTROY;
     223
     224/**
     225 * Structure for keeping an audio test audio stream.
     226 */
     227typedef struct AUDIOTESTSTREAM
     228{
     229    /** The PDM stream. */
     230    PPDMAUDIOSTREAM         pStream;
     231    /** The backend stream. */
     232    PPDMAUDIOBACKENDSTREAM  pBackend;
     233    /** The stream config. */
     234    PDMAUDIOSTREAMCFG       Cfg;
     235} AUDIOTESTSTREAM;
     236/** Pointer to audio test stream. */
     237typedef AUDIOTESTSTREAM *PAUDIOTESTSTREAM;
     238
     239/** Maximum audio streams a test environment can handle. */
     240#define AUDIOTESTENV_MAX_STREAMS 8
     241
     242/**
     243 * Audio test environment parameters.
     244 * Not necessarily bound to a specific test (can be reused).
     245 */
     246typedef struct AUDIOTESTENV
     247{
     248    /** Audio testing mode. */
     249    AUDIOTESTMODE           enmMode;
     250    /** Whether self test mode is active or not. */
     251    bool                    fSelftest;
     252    /** Output path for storing the test environment's final test files. */
     253    char                    szTag[AUDIOTEST_TAG_MAX];
     254    /** Output path for storing the test environment's final test files. */
     255    char                    szPathOut[RTPATH_MAX];
     256    /** Temporary path for this test environment. */
     257    char                    szPathTemp[RTPATH_MAX];
     258    /** Buffer size (in ms). */
     259    RTMSINTERVAL            cMsBufferSize;
     260    /** Pre-buffering time (in ms). */
     261    RTMSINTERVAL            cMsPreBuffer;
     262    /** Scheduling hint (in ms). */
     263    RTMSINTERVAL            cMsSchedulingHint;
     264    /** The audio test driver stack. */
     265    AUDIOTESTDRVSTACK       DrvStack;
     266    /** The current (last) audio device enumeration to use. */
     267    PDMAUDIOHOSTENUM        DevEnum;
     268    /** Audio stream. */
     269    AUDIOTESTSTREAM         aStreams[AUDIOTESTENV_MAX_STREAMS];
     270    /** The audio test set to use. */
     271    AUDIOTESTSET            Set;
     272    union
     273    {
     274        struct
     275        {
     276            /** ATS instance to use. */
     277            ATSSERVER       Srv;
     278        } Guest;
     279        struct
     280        {
     281            /** Client connected to the ATS on the guest side. */
     282            ATSCLIENT       AtsClGuest;
     283            /** Client connected to the ATS on the Validation Kit. */
     284            ATSCLIENT       AtsClValKit;
     285        } Host;
     286    } u;
     287} AUDIOTESTENV;
     288
     289/**
     290 * Audio test descriptor.
     291 */
     292typedef struct AUDIOTESTDESC
     293{
     294    /** (Sort of) Descriptive test name. */
     295    const char             *pszName;
     296    /** Flag whether the test is excluded. */
     297    bool                    fExcluded;
     298    /** The setup callback. */
     299    PFNAUDIOTESTSETUP       pfnSetup;
     300    /** The exec callback. */
     301    PFNAUDIOTESTEXEC        pfnExec;
     302    /** The destruction callback. */
     303    PFNAUDIOTESTDESTROY     pfnDestroy;
     304} AUDIOTESTDESC;
     305
     306/**
     307 * Structure for keeping a VKAT self test context.
     308 */
     309typedef struct SELFTESTCTX
     310{
     311    /** Common tag for guest and host side. */
     312    char             szTag[AUDIOTEST_TAG_MAX];
     313    /** Whether to use DrvAudio in the driver stack or not. */
     314    bool             fWithDrvAudio;
     315    struct
     316    {
     317        AUDIOTESTENV TstEnv;
     318        /** Audio driver to use.
     319         *  Defaults to the platform's default driver. */
     320        PCPDMDRVREG  pDrvReg;
     321    } Guest;
     322    struct
     323    {
     324        AUDIOTESTENV TstEnv;
     325        /** Address of the guest ATS instance.
     326         *  Defaults to localhost (127.0.0.1) if not set. */
     327        char         szGuestAtsAddr[64];
     328        /** Port of the guest ATS instance.
     329         *  Defaults to ATS_DEFAULT_PORT if not set. */
     330        uint32_t     uGuestAtsPort;
     331        /** Address of the Validation Kit audio driver ATS instance.
     332         *  Defaults to localhost (127.0.0.1) if not set. */
     333        char         szValKitAtsAddr[64];
     334        /** Port of the Validation Kit audio driver ATS instance.
     335         *  Defaults to ATS_ALT_PORT if not set. */
     336        uint32_t     uValKitAtsPort;
     337    } Host;
     338} SELFTESTCTX;
     339/** Pointer to a VKAT self test context. */
     340typedef SELFTESTCTX *PSELFTESTCTX;
     341
     342/*********************************************************************************************************************************
     343*   Prototypes                                                                                                                   *
     344*********************************************************************************************************************************/
    106345
    107346/** @name Driver stack
     
    138377/** @}  */
    139378
     379/** @name Backend handling
     380 * @{ */
     381PCPDMDRVREG audioTestFindBackendOpt(const char *pszBackend);
     382/** @}  */
    140383
    141384/** @name Mixing stream
     
    154397/** @}  */
    155398
     399/** @name Device handling
     400 * @{ */
     401int         audioTestDeviceOpen(PPDMAUDIOHOSTDEV pDev);
     402int         audioTestDeviceClose(PPDMAUDIOHOSTDEV pDev);
     403/** @}  */
     404
     405/** @name Test environment handling
     406 * @{ */
     407int         audioTestEnvInit(PAUDIOTESTENV pTstEnv, PCPDMDRVREG pDrvReg, bool fWithDrvAudio, const char *pszTcpAddr, uint32_t uTcpPort);
     408void        audioTestEnvDestroy(PAUDIOTESTENV pTstEnv);
     409int         audioTestEnvPrologue(PAUDIOTESTENV pTstEnv);
     410
     411void        audioTestParmsInit(PAUDIOTESTPARMS pTstParms);
     412void        audioTestParmsDestroy(PAUDIOTESTPARMS pTstParms);
     413/** @}  */
     414
     415int         audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms);
     416
     417/** @name Command handlers
     418 * @{ */
     419RTEXITCODE   audioTestPlayOne(const char *pszFile, PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
     420                              uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
     421                              uint8_t cChannels, uint8_t cbSample, uint32_t uHz,
     422                              bool fWithDrvAudio, bool fWithMixer);
     423RTEXITCODE   audioTestRecOne(const char *pszFile, uint8_t cWaveChannels, uint8_t cbWaveSample, uint32_t uWaveHz,
     424                             PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
     425                             uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
     426                             uint8_t cChannels, uint8_t cbSample, uint32_t uHz, bool fWithDrvAudio, bool fWithMixer,
     427                             uint64_t cMaxFrames, uint64_t cNsMaxDuration);
     428RTEXITCODE   audioTestDoSelftest(PSELFTESTCTX pCtx);
     429/** @}  */
    156430
    157431#endif /* !VBOX_INCLUDED_SRC_audio_vkatInternal_h */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette