VirtualBox

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


Ignore:
Timestamp:
Jun 13, 2021 12:44:53 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
145086
Message:

ValKit/Audio: Re-did the split-out of play & rec commands using svn copy to restore the function order, adding enum to the exodus. bugref:10008

Location:
trunk/src/VBox/ValidationKit/utils/audio
Files:
1 deleted
4 edited
1 copied

Legend:

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

    r89634 r89641  
    6464        vkat.cpp \
    6565        vkatCommon.cpp \
    66         vkatCmdPlayRec.cpp \
     66        vkatCmdGeneric.cpp \
    6767        vkatDriverStack.cpp \
    6868        $(VKAT_PATH_AUDIO)/AudioTest.cpp \
  • trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp

    r89617 r89641  
    896896
    897897/*********************************************************************************************************************************
    898 *   Command: enum                                                                                                                *
     898*   Main                                                                                                                         *
    899899*********************************************************************************************************************************/
    900 
    901 /**
    902  * Options for 'enum'.
    903  */
    904 static const RTGETOPTDEF g_aCmdEnumOptions[] =
    905 {
    906     { "--backend",          'b',                          RTGETOPT_REQ_STRING  },
    907 };
    908 
    909 /** The 'enum' command option help. */
    910 static DECLCALLBACK(const char *) audioTestCmdEnumHelp(PCRTGETOPTDEF pOpt)
    911 {
    912     switch (pOpt->iShort)
    913     {
    914         case 'b': return "The audio backend to use.";
    915         default:  return NULL;
    916     }
    917 }
    918 
    919 /**
    920  * The 'enum' command handler.
    921  *
    922  * @returns Program exit code.
    923  * @param   pGetState   RTGetOpt state.
    924  */
    925 static DECLCALLBACK(RTEXITCODE) audioTestCmdEnumHandler(PRTGETOPTSTATE pGetState)
    926 {
    927     /*
    928      * Parse options.
    929      */
    930     /* Option values: */
    931     PCPDMDRVREG pDrvReg = g_aBackends[0].pDrvReg;
    932 
    933     /* Argument processing loop: */
    934     int           rc;
    935     RTGETOPTUNION ValueUnion;
    936     while ((rc = RTGetOpt(pGetState, &ValueUnion)) != 0)
    937     {
    938         switch (rc)
    939         {
    940             case 'b':
    941                 pDrvReg = audioTestFindBackendOpt(ValueUnion.psz);
    942                 if (pDrvReg == NULL)
    943                     return RTEXITCODE_SYNTAX;
    944                 break;
    945 
    946             AUDIO_TEST_COMMON_OPTION_CASES(ValueUnion);
    947 
    948             default:
    949                 return RTGetOptPrintError(rc, &ValueUnion);
    950         }
    951     }
    952 
    953     /*
    954      * Do the enumeration.
    955      */
    956     RTEXITCODE          rcExit = RTEXITCODE_FAILURE;
    957     AUDIOTESTDRVSTACK   DrvStack;
    958     rc = audioTestDriverStackInit(&DrvStack, pDrvReg, false /*fWithDrvAudio*/);
    959     if (RT_SUCCESS(rc))
    960     {
    961         if (DrvStack.pIHostAudio->pfnGetDevices)
    962         {
    963             PDMAUDIOHOSTENUM Enum;
    964             rc = DrvStack.pIHostAudio->pfnGetDevices(DrvStack.pIHostAudio, &Enum);
    965             if (RT_SUCCESS(rc))
    966             {
    967                 RTPrintf("Found %u device%s\n", Enum.cDevices, Enum.cDevices != 1 ? "s" : "");
    968 
    969                 PPDMAUDIOHOSTDEV pHostDev;
    970                 RTListForEach(&Enum.LstDevices, pHostDev, PDMAUDIOHOSTDEV, ListEntry)
    971                 {
    972                     RTPrintf("\nDevice \"%s\":\n", pHostDev->pszName);
    973 
    974                     char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN];
    975                     if (pHostDev->cMaxInputChannels && !pHostDev->cMaxOutputChannels && pHostDev->enmUsage == PDMAUDIODIR_IN)
    976                         RTPrintf("    Input:  max %u channels (%s)\n",
    977                                  pHostDev->cMaxInputChannels, PDMAudioHostDevFlagsToString(szFlags, pHostDev->fFlags));
    978                     else if (!pHostDev->cMaxInputChannels && pHostDev->cMaxOutputChannels && pHostDev->enmUsage == PDMAUDIODIR_OUT)
    979                         RTPrintf("    Output: max %u channels (%s)\n",
    980                                  pHostDev->cMaxOutputChannels, PDMAudioHostDevFlagsToString(szFlags, pHostDev->fFlags));
    981                     else
    982                         RTPrintf("    %s: max %u output channels, max %u input channels (%s)\n",
    983                                  PDMAudioDirGetName(pHostDev->enmUsage), pHostDev->cMaxOutputChannels,
    984                                  pHostDev->cMaxInputChannels, PDMAudioHostDevFlagsToString(szFlags, pHostDev->fFlags));
    985 
    986                     if (pHostDev->pszId && *pHostDev->pszId)
    987                         RTPrintf("    ID:     \"%s\"\n", pHostDev->pszId);
    988                 }
    989 
    990                 PDMAudioHostEnumDelete(&Enum);
    991             }
    992             else
    993                 rcExit = RTMsgErrorExitFailure("Enumeration failed: %Rrc\n", rc);
    994         }
    995         else
    996             rcExit = RTMsgErrorExitFailure("Enumeration not supported by backend '%s'\n", pDrvReg->szName);
    997         audioTestDriverStackDelete(&DrvStack);
    998     }
    999     else
    1000         rcExit = RTMsgErrorExitFailure("Driver stack construction failed: %Rrc", rc);
    1001     return RTEXITCODE_SUCCESS;
    1002 }
    1003900
    1004901/**
     
    1029926        g_aCmdVerifyOptions,    RT_ELEMENTS(g_aCmdVerifyOptions),   NULL,
    1030927    },
    1031     {
    1032         "enum",     audioTestCmdEnumHandler,
    1033         "Enumerates audio devices.",
    1034         g_aCmdEnumOptions,      RT_ELEMENTS(g_aCmdEnumOptions),     audioTestCmdEnumHelp,
    1035     },
     928    g_cmdEnum,
    1036929    g_cmdPlay,
    1037930    g_cmdRec,
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCmdGeneric.cpp

    • Property svn:mergeinfo set to (toggle deleted branches)
      /branches/VBox-3.0/src/VBox/ValidationKit/utils/audio/vkat.cpp58652,​70973
      /branches/VBox-3.2/src/VBox/ValidationKit/utils/audio/vkat.cpp66309,​66318
      /branches/VBox-4.0/src/VBox/ValidationKit/utils/audio/vkat.cpp70873
      /branches/VBox-4.1/src/VBox/ValidationKit/utils/audio/vkat.cpp74233,​78414,​78691,​81841,​82127,​85941,​85944-85947,​85949-85950,​85953,​86701,​86728,​87009
      /branches/VBox-4.2/src/VBox/ValidationKit/utils/audio/vkat.cpp86229-86230,​86234,​86529,​91503-91504,​91506-91508,​91510,​91514-91515,​91521,​108112,​108114,​108127
      /branches/VBox-4.3/src/VBox/ValidationKit/utils/audio/vkat.cpp89714,​91223,​93628-93629,​94066,​94839,​94897,​95154,​95164,​95167,​95295,​95338,​95353-95354,​95356,​95367,​95451,​95475,​95477,​95480,​95507,​95640,​95659,​95661,​95663,​98913-98914
      /branches/VBox-4.3/trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp91223
      /branches/VBox-5.0/src/VBox/ValidationKit/utils/audio/vkat.cpp104938,​104943,​104950,​104987-104988,​104990,​106453
      /branches/VBox-5.1/src/VBox/ValidationKit/utils/audio/vkat.cpp112367,​116543,​116550,​116568,​116573
      /branches/VBox-5.2/src/VBox/ValidationKit/utils/audio/vkat.cpp119536,​120083,​120099,​120213,​120221,​120239,​123597-123598,​123600-123601,​123755,​124263,​124273,​124277-124279,​124284-124286,​124288-124290,​125768,​125779-125780,​125812,​127158-127159,​127162-127167,​127180
      /branches/VBox-6.0/src/VBox/ValidationKit/utils/audio/vkat.cpp130474-130475,​130477,​130479,​131352
      /branches/VBox-6.1/src/VBox/ValidationKit/utils/audio/vkat.cpp141521,​141567-141568,​141588-141590,​141592-141595,​141652,​141920
      /branches/aeichner/vbox-chromium-cleanup/src/VBox/ValidationKit/utils/audio/vkat.cpp129818-129851,​129853-129861,​129871-129872,​129876,​129880,​129882,​130013-130015,​130094-130095
      /branches/andy/draganddrop/src/VBox/ValidationKit/utils/audio/vkat.cpp90781-91268
      /branches/andy/guestctrl20/src/VBox/ValidationKit/utils/audio/vkat.cpp78916,​78930
      /branches/andy/pdmaudio/src/VBox/ValidationKit/utils/audio/vkat.cpp94582,​94641,​94654,​94688,​94778,​94783,​94816,​95197,​95215-95216,​95250,​95279,​95505-95506,​95543,​95694,​96323,​96470-96471,​96582,​96587,​96802-96803,​96817,​96904,​96967,​96999,​97020-97021,​97025,​97050,​97099
      /branches/bird/hardenedwindows/src/VBox/ValidationKit/utils/audio/vkat.cpp92692-94610
      /branches/dsen/gui/src/VBox/ValidationKit/utils/audio/vkat.cpp79076-79078,​79089,​79109-79110,​79112-79113,​79127-79130,​79134,​79141,​79151,​79155,​79157-79159,​79193,​79197
      /branches/dsen/gui2/src/VBox/ValidationKit/utils/audio/vkat.cpp79224,​79228,​79233,​79235,​79258,​79262-79263,​79273,​79341,​79345,​79354,​79357,​79387-79388,​79559-79569,​79572-79573,​79578,​79581-79582,​79590-79591,​79598-79599,​79602-79603,​79605-79606,​79632,​79635,​79637,​79644
      /branches/dsen/gui3/src/VBox/ValidationKit/utils/audio/vkat.cpp79645-79692
    r89541 r89641  
    2929*   Header Files                                                                                                                 *
    3030*********************************************************************************************************************************/
    31 #include <iprt/buildconfig.h>
    32 #include <iprt/ctype.h>
    33 #include <iprt/dir.h>
    3431#include <iprt/errcore.h>
    35 #include <iprt/initterm.h>
    36 #include <iprt/getopt.h>
    3732#include <iprt/message.h>
    38 #include <iprt/path.h>
    39 #include <iprt/process.h>
    40 #include <iprt/rand.h>
    41 #include <iprt/stream.h>
    42 #include <iprt/string.h>
    43 #include <iprt/uuid.h>
    4433#include <iprt/test.h>
    4534
    46 #include <package-generated.h>
    47 #include "product-generated.h"
    48 
    49 #include <VBox/version.h>
    50 #include <VBox/log.h>
    51 
    52 #ifdef RT_OS_WINDOWS
    53 # include <iprt/win/windows.h> /* for CoInitializeEx */
    54 #endif
    55 #include <signal.h>
    56 
    57 /**
    58  * Internal driver instance data
    59  * @note This must be put here as it's needed before pdmdrv.h is included.
    60  */
    61 typedef struct PDMDRVINSINT
    62 {
    63     /** The stack the drive belongs to. */
    64     struct AUDIOTESTDRVSTACK *pStack;
    65 } PDMDRVINSINT;
    66 #define PDMDRVINSINT_DECLARED
    67 
    68 #include <VBox/vmm/pdmaudioinline.h>
    69 #include <VBox/vmm/pdmaudiohostenuminline.h>
    70 
    71 #include "Audio/AudioHlp.h"
    72 #include "Audio/AudioTest.h"
    73 #include "Audio/AudioTestService.h"
    74 #include "Audio/AudioTestServiceClient.h"
    75 
    76 #include "VBoxDD.h"
    77 
    7835#include "vkatInternal.h"
    79 
    80 
    81 /*********************************************************************************************************************************
    82 *   Defined Constants And Macros                                                                                                 *
    83 *********************************************************************************************************************************/
    84 /** For use in the option switch to handle common options. */
    85 #define AUDIO_TEST_COMMON_OPTION_CASES(a_ValueUnion) \
    86             case 'q': \
    87                 g_uVerbosity = 0; \
    88                 if (g_pRelLogger) \
    89                     RTLogGroupSettings(g_pRelLogger, "all=0 all.e"); \
    90                 break; \
    91             \
    92             case 'v': \
    93                 g_uVerbosity++; \
    94                 if (g_pRelLogger) \
    95                     RTLogGroupSettings(g_pRelLogger, g_uVerbosity == 1 ? "all.e.l" : g_uVerbosity == 2 ? "all.e.l.f" : "all=~0"); \
    96                 break; \
    97             \
    98             case 'V': \
    99                 return audioTestVersion(); \
    100             \
    101             case 'h': \
    102                 return audioTestUsage(g_pStdOut); \
    103             \
    104             case AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_ENABLE: \
    105                 g_fDrvAudioDebug = true; \
    106                 break; \
    107             \
    108             case AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_PATH: \
    109                 g_pszDrvAudioDebug = (a_ValueUnion).psz; \
    110                 break
    111 
    112 
    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 
    249 
    250 /*********************************************************************************************************************************
    251 *   Internal Functions                                                                                                           *
    252 *********************************************************************************************************************************/
    253 static 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 
    260 static RTEXITCODE audioTestUsage(PRTSTREAM pStrm);
    261 static RTEXITCODE audioTestVersion(void);
    262 
    263 
    264 /*********************************************************************************************************************************
    265 *   Global Variables                                                                                                             *
    266 *********************************************************************************************************************************/
    267 /**
    268  * Common long options values.
    269  */
    270 enum
    271 {
    272     AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_ENABLE = 256,
    273     AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_PATH
    274 };
    275 
    276 /**
    277  * Long option values for the 'test' command.
    278  */
    279 enum
    280 {
    281     VKAT_TEST_OPT_COUNT = 900,
    282     VKAT_TEST_OPT_DEV,
    283     VKAT_TEST_OPT_ATS_ADDR,
    284     VKAT_TEST_OPT_ATS_PORT,
    285     VKAT_TEST_OPT_MODE,
    286     VKAT_TEST_OPT_OUTDIR,
    287     VKAT_TEST_OPT_PAUSE,
    288     VKAT_TEST_OPT_PCM_HZ,
    289     VKAT_TEST_OPT_PCM_BIT,
    290     VKAT_TEST_OPT_PCM_CHAN,
    291     VKAT_TEST_OPT_PCM_SIGNED,
    292     VKAT_TEST_OPT_TAG,
    293     VKAT_TEST_OPT_TEMPDIR,
    294     VKAT_TEST_OPT_VOL
    295 };
    296 
    297 /**
    298  * Long option values for the 'verify' command.
    299  */
    300 enum
    301 {
    302     VKAT_VERIFY_OPT_TAG = 900
    303 };
    304 
    305 /**
    306  * Long option values for the 'selftest' command.
    307  */
    308 enum
    309 {
    310     VKAT_SELFTEST_OPT_ATS_GUEST_ADDR = 900,
    311     VKAT_SELFTEST_OPT_ATS_GUEST_PORT,
    312     VKAT_SELFTEST_OPT_ATS_VALKIT_ADDR,
    313     VKAT_SELFTEST_OPT_ATS_VALKIT_PORT
    314 };
    315 
    316 /**
    317  * Common command line parameters.
    318  */
    319 static const RTGETOPTDEF g_aCmdCommonOptions[] =
    320 {
    321     { "--quiet",            'q',                                        RTGETOPT_REQ_NOTHING },
    322     { "--verbose",          'v',                                        RTGETOPT_REQ_NOTHING },
    323     { "--debug-audio",      AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_ENABLE,      RTGETOPT_REQ_NOTHING },
    324     { "--debug-audio-path", AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_PATH,        RTGETOPT_REQ_STRING  },
    325 };
    326 
    327 /**
    328  * Command line parameters for test mode.
    329  */
    330 static const RTGETOPTDEF g_aCmdTestOptions[] =
    331 {
    332     { "--backend",          'b',                          RTGETOPT_REQ_STRING  },
    333     { "--drvaudio",         'd',                          RTGETOPT_REQ_NOTHING },
    334     { "--exclude",          'e',                          RTGETOPT_REQ_UINT32  },
    335     { "--exclude-all",      'a',                          RTGETOPT_REQ_NOTHING },
    336     { "--mode",             VKAT_TEST_OPT_MODE,           RTGETOPT_REQ_STRING  },
    337     { "--ats-address",      VKAT_TEST_OPT_ATS_ADDR,       RTGETOPT_REQ_STRING  },
    338     { "--ats-port",         VKAT_TEST_OPT_ATS_PORT,       RTGETOPT_REQ_UINT32  },
    339     { "--include",          'i',                          RTGETOPT_REQ_UINT32  },
    340     { "--outdir",           VKAT_TEST_OPT_OUTDIR,         RTGETOPT_REQ_STRING  },
    341     { "--count",            VKAT_TEST_OPT_COUNT,          RTGETOPT_REQ_UINT32  },
    342     { "--device",           VKAT_TEST_OPT_DEV,            RTGETOPT_REQ_STRING  },
    343     { "--pause",            VKAT_TEST_OPT_PAUSE,          RTGETOPT_REQ_UINT32  },
    344     { "--pcm-bit",          VKAT_TEST_OPT_PCM_BIT,        RTGETOPT_REQ_UINT8   },
    345     { "--pcm-chan",         VKAT_TEST_OPT_PCM_CHAN,       RTGETOPT_REQ_UINT8   },
    346     { "--pcm-hz",           VKAT_TEST_OPT_PCM_HZ,         RTGETOPT_REQ_UINT16  },
    347     { "--pcm-signed",       VKAT_TEST_OPT_PCM_SIGNED,     RTGETOPT_REQ_BOOL    },
    348     { "--tag",              VKAT_TEST_OPT_TAG,            RTGETOPT_REQ_STRING  },
    349     { "--tempdir",          VKAT_TEST_OPT_TEMPDIR,        RTGETOPT_REQ_STRING  },
    350     { "--volume",           VKAT_TEST_OPT_VOL,            RTGETOPT_REQ_UINT8   }
    351 };
    352 
    353 /**
    354  * Command line parameters for verification mode.
    355  */
    356 static const RTGETOPTDEF g_aCmdVerifyOptions[] =
    357 {
    358     { "--tag",              VKAT_VERIFY_OPT_TAG,          RTGETOPT_REQ_STRING  }
    359 };
    360 
    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 
    403 /** Terminate ASAP if set.  Set on Ctrl-C. */
    404 static bool volatile    g_fTerminate = false;
    405 /** The release logger. */
    406 static PRTLOGGER        g_pRelLogger = NULL;
    407 
    408 
    409 /** The test handle. */
    410 RTTEST        g_hTest;
    411 /** The current verbosity level. */
    412 unsigned      g_uVerbosity = 0;
    413 /** DrvAudio: Enable debug (or not). */
    414 bool          g_fDrvAudioDebug = 0;
    415 /** DrvAudio: The debug output path. */
    416 const char   *g_pszDrvAudioDebug = NULL;
    417 
    418 
    419 /**
    420  * Helper for handling --backend options.
    421  *
    422  * @returns Pointer to the specified backend, NULL if not found (error
    423  *          displayed).
    424  * @param   pszBackend      The backend option value.
    425  */
    426 static PCPDMDRVREG audioTestFindBackendOpt(const char *pszBackend)
    427 {
    428     for (uintptr_t i = 0; i < RT_ELEMENTS(g_aBackends); i++)
    429         if (   strcmp(pszBackend, g_aBackends[i].pszName) == 0
    430             || strcmp(pszBackend, g_aBackends[i].pDrvReg->szName) == 0)
    431             return g_aBackends[i].pDrvReg;
    432     RTMsgError("Unknown backend: '%s'", pszBackend);
    433     return NULL;
    434 }
    435 
    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 }
    1062 
    1063 /**
    1064  * Overrides audio test base parameters with another set.
    1065  *
    1066  * @returns VBox status code.
    1067  * @param   pBaseParms          Base parameters to override.
    1068  * @param   pOverrideParms      Override parameters to use for overriding the base parameters.
    1069  *
    1070  * @note    Overriding a parameter depends on its type / default values.
    1071  */
    1072 static int audioTestCombineParms(PAUDIOTESTPARMS pBaseParms, PAUDIOTESTPARMS pOverrideParms)
    1073 {
    1074     RT_NOREF(pBaseParms, pOverrideParms);
    1075 
    1076     /** @todo Implement parameter overriding. */
    1077     return VERR_NOT_IMPLEMENTED;
    1078 }
    1079 
    1080 
    1081 /*********************************************************************************************************************************
    1082 *   Test callbacks                                                                                                               *
    1083 *********************************************************************************************************************************/
    1084 
    1085 /**
    1086  * @copydoc FNAUDIOTESTSETUP
    1087  */
    1088 static DECLCALLBACK(int) audioTestPlayToneSetup(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx)
    1089 {
    1090     RT_NOREF(pTstEnv, pTstDesc, ppvCtx);
    1091 
    1092     pTstParmsAcq->enmType     = AUDIOTESTTYPE_TESTTONE_PLAY;
    1093 
    1094     PDMAudioPropsInit(&pTstParmsAcq->Props, 16 /* bit */ / 8, true /* fSigned */, 2 /* Channels */, 44100 /* Hz */);
    1095 
    1096     pTstParmsAcq->enmDir      = PDMAUDIODIR_OUT;
    1097 #ifdef DEBUG
    1098     pTstParmsAcq->cIterations = 2;
    1099 #else
    1100     pTstParmsAcq->cIterations = RTRandU32Ex(1, 10);
    1101 #endif
    1102     pTstParmsAcq->idxCurrent  = 0;
    1103 
    1104     return VINF_SUCCESS;
    1105 }
    1106 
    1107 /**
    1108  * @copydoc FNAUDIOTESTEXEC
    1109  */
    1110 static DECLCALLBACK(int) audioTestPlayToneExec(PAUDIOTESTENV pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms)
    1111 {
    1112     RT_NOREF(pvCtx);
    1113 
    1114     int rc = VINF_SUCCESS;
    1115 
    1116     for (uint32_t i = 0; i < pTstParms->cIterations; i++)
    1117     {
    1118         AudioTestToneParamsInitRandom(&pTstParms->TestTone, &pTstParms->Props);
    1119 
    1120         PAUDIOTESTENTRY pTst;
    1121         rc = AudioTestSetTestBegin(&pTstEnv->Set, "Playing test tone", pTstParms, &pTst);
    1122         if (RT_SUCCESS(rc))
    1123         {
    1124             PDMAUDIOSTREAMCFG Cfg;
    1125             RT_ZERO(Cfg);
    1126             /** @todo Add more parameters here? */
    1127             Cfg.Props = pTstParms->Props;
    1128 
    1129             rc = AudioTestSvcClientTonePlay(&pTstEnv->u.Host.AtsClGuest, &pTstParms->TestTone);
    1130             if (RT_SUCCESS(rc))
    1131             {
    1132                 AudioTestSetTestDone(pTst);
    1133             }
    1134             else
    1135                 AudioTestSetTestFailed(pTst, rc, "Playing test tone failed");
    1136         }
    1137 
    1138         if (RT_FAILURE(rc))
    1139             RTTestFailed(g_hTest, "Playing tone failed\n");
    1140     }
    1141 
    1142     return rc;
    1143 }
    1144 
    1145 /**
    1146  * @copydoc FNAUDIOTESTDESTROY
    1147  */
    1148 static DECLCALLBACK(int) audioTestPlayToneDestroy(PAUDIOTESTENV pTstEnv, void *pvCtx)
    1149 {
    1150     RT_NOREF(pTstEnv, pvCtx);
    1151 
    1152     return VINF_SUCCESS;
    1153 }
    1154 
    1155 /**
    1156  * @copydoc FNAUDIOTESTSETUP
    1157  */
    1158 static DECLCALLBACK(int) audioTestRecordToneSetup(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx)
    1159 {
    1160     RT_NOREF(pTstDesc, ppvCtx);
    1161 
    1162     pTstParmsAcq->enmType     = AUDIOTESTTYPE_TESTTONE_RECORD;
    1163 
    1164     PDMAudioPropsInit(&pTstParmsAcq->Props, 16 /* bit */ / 8, true /* fSigned */, 2 /* Channels */, 44100 /* Hz */);
    1165 
    1166     pTstParmsAcq->enmDir      = PDMAUDIODIR_IN;
    1167 #ifdef DEBUG
    1168     pTstParmsAcq->cIterations = 2;
    1169 #else
    1170     pTstParmsAcq->cIterations = RTRandU32Ex(1, 10);
    1171 #endif
    1172     pTstParmsAcq->idxCurrent  = 0;
    1173 
    1174     /* Connect to the Validation Kit audio driver ATS. */
    1175     int rc = AudioTestSvcClientConnect(&pTstEnv->u.Host.AtsClValKit,
    1176                                        "127.0.0.1" /** @todo Make this dynamic. */, ATS_TCP_DEFAULT_PORT);
    1177     if (RT_SUCCESS(rc))
    1178     {
    1179         char szTag[AUDIOTEST_TAG_MAX];
    1180         rc = RTStrPrintf2(szTag, sizeof(szTag), "%s-valkit", pTstEnv->szTag);
    1181         if (RT_SUCCESS(rc))
    1182             rc = AudioTestSvcClientTestSetBegin(&pTstEnv->u.Host.AtsClValKit, szTag);
    1183     }
    1184 
    1185     return rc;
    1186 }
    1187 
    1188 /**
    1189  * @copydoc FNAUDIOTESTEXEC
    1190  */
    1191 static DECLCALLBACK(int) audioTestRecordToneExec(PAUDIOTESTENV pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms)
    1192 {
    1193     RT_NOREF(pvCtx);
    1194 
    1195     int rc = VINF_SUCCESS;
    1196 
    1197     for (uint32_t i = 0; i < pTstParms->cIterations; i++)
    1198     {
    1199         pTstParms->TestTone.Props      = pTstParms->Props;
    1200 #ifdef DEBUG_andy
    1201         pTstParms->TestTone.msDuration = RTRandU32Ex(50 /* ms */, 2000);
    1202 #else
    1203         pTstParms->TestTone.msDuration = RTRandU32Ex(50 /* ms */, RT_MS_30SEC); /** @todo Record even longer? */
    1204 #endif
    1205         PAUDIOTESTENTRY pTst;
    1206         rc = AudioTestSetTestBegin(&pTstEnv->Set, "Recording test tone", pTstParms, &pTst);
    1207         if (RT_SUCCESS(rc))
    1208         {
    1209             /*
    1210              * 1. Arm the ValKit ATS with the recording parameters.
    1211              */
    1212             rc = AudioTestSvcClientTonePlay(&pTstEnv->u.Host.AtsClValKit, &pTstParms->TestTone);
    1213             if (RT_SUCCESS(rc))
    1214             {
    1215                 /*
    1216                  * 2. Tell the guest ATS to start recording.
    1217                  */
    1218                 rc = AudioTestSvcClientToneRecord(&pTstEnv->u.Host.AtsClGuest, &pTstParms->TestTone);
    1219                 if (RT_SUCCESS(rc))
    1220                 {
    1221                     AudioTestSetTestDone(pTst);
    1222                 }
    1223                 else
    1224                     AudioTestSetTestFailed(pTst, rc, "Recording test tone failed");
    1225             }
    1226         }
    1227 
    1228         if (RT_FAILURE(rc))
    1229             RTTestFailed(g_hTest, "Recording tone failed\n");
    1230     }
    1231 
    1232     return rc;
    1233 }
    1234 
    1235 /**
    1236  * @copydoc FNAUDIOTESTDESTROY
    1237  */
    1238 static DECLCALLBACK(int) audioTestRecordToneDestroy(PAUDIOTESTENV pTstEnv, void *pvCtx)
    1239 {
    1240     RT_NOREF(pvCtx);
    1241 
    1242     char szTag[AUDIOTEST_TAG_MAX];
    1243     int rc = RTStrPrintf2(szTag, sizeof(szTag), "%s-valkit", pTstEnv->szTag);
    1244     if (RT_SUCCESS(rc))
    1245         rc = AudioTestSvcClientTestSetEnd(&pTstEnv->u.Host.AtsClValKit, szTag);
    1246 
    1247     int rc2 = AudioTestSvcClientClose(&pTstEnv->u.Host.AtsClValKit);
    1248     if (RT_SUCCESS(rc))
    1249         rc = rc2;
    1250 
    1251     return rc;
    1252 }
    1253 
    1254 
    1255 /*********************************************************************************************************************************
    1256 *   Test execution                                                                                                               *
    1257 *********************************************************************************************************************************/
    1258 
    1259 static AUDIOTESTDESC g_aTests[] =
    1260 {
    1261     /* pszTest      fExcluded      pfnSetup */
    1262     { "PlayTone",   false,         audioTestPlayToneSetup,       audioTestPlayToneExec,      audioTestPlayToneDestroy },
    1263     { "RecordTone", false,         audioTestRecordToneSetup,     audioTestRecordToneExec,    audioTestRecordToneDestroy }
    1264 };
    1265 
    1266 /**
    1267  * Runs one specific audio test.
    1268  *
    1269  * @returns VBox status code.
    1270  * @param   pTstEnv             Test environment to use for running the test.
    1271  * @param   pTstDesc            Test to run.
    1272  * @param   uSeq                Test sequence # in case there are more tests.
    1273  * @param   pOverrideParms      Test parameters for overriding the actual test parameters. Optional.
    1274  */
    1275 static int audioTestOne(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc,
    1276                         unsigned uSeq, PAUDIOTESTPARMS pOverrideParms)
    1277 {
    1278     RT_NOREF(uSeq);
    1279 
    1280     int rc;
    1281 
    1282     AUDIOTESTPARMS TstParms;
    1283     audioTestParmsInit(&TstParms);
    1284 
    1285     RTTestSub(g_hTest, pTstDesc->pszName);
    1286 
    1287     if (pTstDesc->fExcluded)
    1288     {
    1289         RTTestSkipped(g_hTest, "Excluded from list");
    1290         return VINF_SUCCESS;
    1291     }
    1292 
    1293     void *pvCtx = NULL; /* Test-specific opaque context. Optional and can be NULL. */
    1294 
    1295     if (pTstDesc->pfnSetup)
    1296     {
    1297         rc = pTstDesc->pfnSetup(pTstEnv, pTstDesc, &TstParms, &pvCtx);
    1298         if (RT_FAILURE(rc))
    1299         {
    1300             RTTestFailed(g_hTest, "Test setup failed with %Rrc\n", rc);
    1301             return rc;
    1302         }
    1303     }
    1304 
    1305     audioTestCombineParms(&TstParms, pOverrideParms);
    1306 
    1307     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test #%u: %RU32 iterations\n", uSeq, TstParms.cIterations);
    1308 
    1309     if (TstParms.Dev.pszName && strlen(TstParms.Dev.pszName)) /** @todo Refine this check. Use pszId for starters! */
    1310         rc = audioTestDeviceOpen(&TstParms.Dev);
    1311 
    1312     AssertPtr(pTstDesc->pfnExec);
    1313     rc = pTstDesc->pfnExec(pTstEnv, pvCtx, &TstParms);
    1314     if (RT_FAILURE(rc))
    1315         RTTestFailed(g_hTest, "Test failed with %Rrc\n", rc);
    1316 
    1317     RTTestSubDone(g_hTest);
    1318 
    1319     if (pTstDesc->pfnDestroy)
    1320     {
    1321         int rc2 = pTstDesc->pfnDestroy(pTstEnv, pvCtx);
    1322         if (RT_SUCCESS(rc))
    1323             rc = rc2;
    1324 
    1325         if (RT_FAILURE(rc2))
    1326             RTTestFailed(g_hTest, "Test destruction failed with %Rrc\n", rc2);
    1327     }
    1328 
    1329     rc = audioTestDeviceClose(&TstParms.Dev);
    1330 
    1331     audioTestParmsDestroy(&TstParms);
    1332 
    1333     return rc;
    1334 }
    1335 
    1336 /**
    1337  * Runs all specified tests in a row.
    1338  *
    1339  * @returns VBox status code.
    1340  * @param   pTstEnv             Test environment to use for running all tests.
    1341  * @param   pOverrideParms      Test parameters for (some / all) specific test parameters. Optional.
    1342  */
    1343 static int audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms)
    1344 {
    1345     int rc = VINF_SUCCESS;
    1346 
    1347     if (pTstEnv->enmMode == AUDIOTESTMODE_GUEST)
    1348     {
    1349         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Guest ATS running\n");
    1350 
    1351         while (!g_fTerminate)
    1352             RTThreadSleep(100);
    1353 
    1354         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Shutting down guest ATS ...\n");
    1355 
    1356         int rc2 = AudioTestSvcShutdown(&pTstEnv->u.Guest.Srv);
    1357         if (RT_SUCCESS(rc))
    1358             rc = rc2;
    1359 
    1360         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Guest ATS shutdown complete\n");
    1361     }
    1362     else if (pTstEnv->enmMode == AUDIOTESTMODE_HOST)
    1363     {
    1364         /* Generate tag for the host side. */
    1365         char szTag[AUDIOTEST_TAG_MAX];
    1366         rc = RTStrPrintf2(szTag, sizeof(szTag), "%s-host", pTstEnv->szTag);
    1367         AssertRCReturn(rc, rc);
    1368 
    1369         /* We have one single test set for all executed tests for now. */
    1370         rc = AudioTestSetCreate(&pTstEnv->Set, pTstEnv->szPathTemp, szTag);
    1371         if (RT_SUCCESS(rc))
    1372         {
    1373             rc = AudioTestSvcClientTestSetBegin(&pTstEnv->u.Host.AtsClGuest, pTstEnv->szTag);
    1374             if (RT_SUCCESS(rc))
    1375             {
    1376                 unsigned uSeq = 0;
    1377                 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
    1378                 {
    1379                     int rc2 = audioTestOne(pTstEnv, &g_aTests[i], uSeq, pOverrideParms);
    1380                     if (RT_SUCCESS(rc))
    1381                         rc = rc2;
    1382 
    1383                     if (!g_aTests[i].fExcluded)
    1384                         uSeq++;
    1385 
    1386                     if (g_fTerminate)
    1387                         break;
    1388                 }
    1389 
    1390                 int rc2 = AudioTestSvcClientTestSetEnd(&pTstEnv->u.Host.AtsClGuest, pTstEnv->szTag);
    1391                 if (RT_SUCCESS(rc))
    1392                     rc = rc2;
    1393             }
    1394 
    1395             audioTestEnvPrologue(pTstEnv);
    1396         }
    1397     }
    1398     else
    1399         AssertFailed();
    1400 
    1401     if (RT_FAILURE(rc))
    1402         RTTestFailed(g_hTest, "Test worker failed with %Rrc", rc);
    1403 
    1404     return rc;
    1405 }
    1406 
    1407 /** Option help for the 'test' command.   */
    1408 static DECLCALLBACK(const char *) audioTestCmdTestHelp(PCRTGETOPTDEF pOpt)
    1409 {
    1410     switch (pOpt->iShort)
    1411     {
    1412         case 'd':                    return "Go via DrvAudio instead of directly interfacing with the backend";
    1413         case VKAT_TEST_OPT_DEV:      return "Use the specified audio device";
    1414         case VKAT_TEST_OPT_ATS_ADDR: return "ATS address (hostname or IP) to connect to";
    1415         case VKAT_TEST_OPT_ATS_PORT: return "ATS port to connect to. Defaults to 6052 if not set";
    1416         case VKAT_TEST_OPT_MODE:     return "Specifies the mode this program runs at";
    1417         case 'e':                    return "Exclude the given test id from the list";
    1418         case 'a':                    return "Exclude all tests from the list (useful to enable single tests later with --include)";
    1419         case 'i':                    return "Include the given test id in the list";
    1420     }
    1421     return NULL;
    1422 }
    1423 
    1424 /**
    1425  * Main (entry) function for the testing functionality of VKAT.
    1426  *
    1427  * @returns Program exit code.
    1428  * @param   pGetState   RTGetOpt state.
    1429  */
    1430 static DECLCALLBACK(RTEXITCODE) audioTestMain(PRTGETOPTSTATE pGetState)
    1431 {
    1432     AUDIOTESTENV TstEnv;
    1433     RT_ZERO(TstEnv);
    1434 
    1435     AUDIOTESTPARMS TstCust;
    1436     audioTestParmsInit(&TstCust);
    1437 
    1438     const char *pszDevice     = NULL; /* Custom device to use. Can be NULL if not being used. */
    1439     const char *pszTag        = NULL; /* Custom tag to use. Can be NULL if not being used. */
    1440     PCPDMDRVREG pDrvReg       = g_aBackends[0].pDrvReg;
    1441     bool        fWithDrvAudio = false;
    1442     uint8_t     cPcmSampleBit = 0;
    1443     uint8_t     cPcmChannels  = 0;
    1444     uint32_t    uPcmHz        = 0;
    1445     bool        fPcmSigned    = true;
    1446     const char *pszTcpAddr    = NULL;
    1447     uint16_t    uTcpPort      = 0;
    1448 
    1449     int           rc;
    1450     RTGETOPTUNION ValueUnion;
    1451     while ((rc = RTGetOpt(pGetState, &ValueUnion)))
    1452     {
    1453         switch (rc)
    1454         {
    1455             case 'a':
    1456                 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
    1457                     g_aTests[i].fExcluded = true;
    1458                 break;
    1459 
    1460             case 'b':
    1461                 pDrvReg = audioTestFindBackendOpt(ValueUnion.psz);
    1462                 if (pDrvReg == NULL)
    1463                     return RTEXITCODE_SYNTAX;
    1464                 break;
    1465 
    1466             case 'd':
    1467                 fWithDrvAudio = true;
    1468                 break;
    1469 
    1470             case 'e':
    1471                 if (ValueUnion.u32 >= RT_ELEMENTS(g_aTests))
    1472                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid test number %u passed to --exclude", ValueUnion.u32);
    1473                 g_aTests[ValueUnion.u32].fExcluded = true;
    1474                 break;
    1475 
    1476             case VKAT_TEST_OPT_ATS_ADDR:
    1477                 if (TstEnv.enmMode == AUDIOTESTMODE_UNKNOWN)
    1478                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Must specify a test mode first!");
    1479                 pszTcpAddr = ValueUnion.psz;
    1480                 break;
    1481 
    1482             case VKAT_TEST_OPT_ATS_PORT:
    1483                 if (TstEnv.enmMode == AUDIOTESTMODE_UNKNOWN)
    1484                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Must specify a test mode first!");
    1485                 uTcpPort = ValueUnion.u32;
    1486                 break;
    1487 
    1488             case VKAT_TEST_OPT_MODE:
    1489                 if (TstEnv.enmMode != AUDIOTESTMODE_UNKNOWN)
    1490                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Test mode (guest / host) already specified");
    1491                 TstEnv.enmMode = RTStrICmp(ValueUnion.psz, "guest") == 0 ? AUDIOTESTMODE_GUEST : AUDIOTESTMODE_HOST;
    1492                 break;
    1493 
    1494             case 'i':
    1495                 if (ValueUnion.u32 >= RT_ELEMENTS(g_aTests))
    1496                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid test number %u passed to --include", ValueUnion.u32);
    1497                 g_aTests[ValueUnion.u32].fExcluded = false;
    1498                 break;
    1499 
    1500             case VKAT_TEST_OPT_COUNT:
    1501                 return RTMsgErrorExitFailure("Not yet implemented!");
    1502 
    1503             case VKAT_TEST_OPT_DEV:
    1504                 pszDevice = ValueUnion.psz;
    1505                 break;
    1506 
    1507             case VKAT_TEST_OPT_PAUSE:
    1508                 return RTMsgErrorExitFailure("Not yet implemented!");
    1509 
    1510             case VKAT_TEST_OPT_OUTDIR:
    1511                 rc = RTStrCopy(TstEnv.szPathOut, sizeof(TstEnv.szPathOut), ValueUnion.psz);
    1512                 if (RT_FAILURE(rc))
    1513                     return RTMsgErrorExitFailure("Failed to copy out directory: %Rrc", rc);
    1514                 break;
    1515 
    1516             case VKAT_TEST_OPT_PCM_BIT:
    1517                 cPcmSampleBit = ValueUnion.u8;
    1518                 break;
    1519 
    1520             case VKAT_TEST_OPT_PCM_CHAN:
    1521                 cPcmChannels = ValueUnion.u8;
    1522                 break;
    1523 
    1524             case VKAT_TEST_OPT_PCM_HZ:
    1525                 uPcmHz = ValueUnion.u32;
    1526                 break;
    1527 
    1528             case VKAT_TEST_OPT_PCM_SIGNED:
    1529                 fPcmSigned = ValueUnion.f;
    1530                 break;
    1531 
    1532             case VKAT_TEST_OPT_TAG:
    1533                 pszTag = ValueUnion.psz;
    1534                 break;
    1535 
    1536             case VKAT_TEST_OPT_TEMPDIR:
    1537                 rc = RTStrCopy(TstEnv.szPathTemp, sizeof(TstEnv.szPathTemp), ValueUnion.psz);
    1538                 if (RT_FAILURE(rc))
    1539                     return RTMsgErrorExit(RTEXITCODE_FAILURE, "Temp dir invalid, rc=%Rrc", rc);
    1540                 break;
    1541 
    1542             case VKAT_TEST_OPT_VOL:
    1543                 TstCust.TestTone.uVolumePercent = ValueUnion.u8;
    1544                 break;
    1545 
    1546             AUDIO_TEST_COMMON_OPTION_CASES(ValueUnion);
    1547 
    1548             default:
    1549                 return RTGetOptPrintError(rc, &ValueUnion);
    1550         }
    1551     }
    1552 
    1553     /*
    1554      * Start testing.
    1555      */
    1556     RTTestBanner(g_hTest);
    1557 
    1558     /* Initialize the custom test parameters with sensible defaults if nothing else is given. */
    1559     PDMAudioPropsInit(&TstCust.TestTone.Props,
    1560                       cPcmSampleBit ? cPcmSampleBit / 8 : 2 /* 16-bit */, fPcmSigned, cPcmChannels ? cPcmChannels : 2,
    1561                       uPcmHz ? uPcmHz : 44100);
    1562 
    1563     if (TstEnv.enmMode == AUDIOTESTMODE_UNKNOWN)
    1564         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No test mode specified!\n");
    1565 
    1566     if (TstEnv.enmMode == AUDIOTESTMODE_HOST)
    1567     {
    1568         /* Use the default port is none is specified. */
    1569         if (!uTcpPort)
    1570             uTcpPort = ATS_TCP_DEFAULT_PORT;
    1571 
    1572         if (!pszTcpAddr)
    1573             return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--ats-address missing\n");
    1574     }
    1575 
    1576     /* For now all tests have the same test environment. */
    1577     rc = audioTestEnvInit(&TstEnv, pDrvReg, fWithDrvAudio, pszTcpAddr, uTcpPort);
    1578     if (RT_SUCCESS(rc))
    1579     {
    1580         audioTestWorker(&TstEnv, &TstCust);
    1581         audioTestEnvDestroy(&TstEnv);
    1582     }
    1583 
    1584     audioTestParmsDestroy(&TstCust);
    1585 
    1586     if (RT_FAILURE(rc)) /* Let us know that something went wrong in case we forgot to mention it. */
    1587         RTTestFailed(g_hTest, "Testing failed with %Rrc\n", rc);
    1588 
    1589     /*
    1590      * Print summary and exit.
    1591      */
    1592     return RTTestSummaryAndDestroy(g_hTest);
    1593 }
    1594 
    1595 
    1596 /*********************************************************************************************************************************
    1597 *   Command: verify                                                                                                              *
    1598 *********************************************************************************************************************************/
    1599 
    1600 static int audioVerifyOpenTestSet(const char *pszPathSet, PAUDIOTESTSET pSet)
    1601 {
    1602     int rc;
    1603 
    1604     char szPathExtracted[RTPATH_MAX];
    1605 
    1606     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Opening test set '%s'\n", pszPathSet);
    1607 
    1608     const bool fPacked = AudioTestSetIsPacked(pszPathSet);
    1609     if (fPacked)
    1610     {
    1611         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Test set is an archive and needs to be unpacked\n");
    1612 
    1613         char szPathTemp[RTPATH_MAX];
    1614         rc = RTPathTemp(szPathTemp, sizeof(szPathTemp));
    1615         if (RT_SUCCESS(rc))
    1616         {
    1617             RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Using temporary directory '%s'\n", szPathTemp);
    1618 
    1619             rc = RTPathJoin(szPathExtracted, sizeof(szPathExtracted), szPathTemp, "vkat-XXXX");
    1620             if (RT_SUCCESS(rc))
    1621             {
    1622                 rc = RTDirCreateTemp(szPathExtracted, 0755);
    1623                 if (RT_SUCCESS(rc))
    1624                 {
    1625                     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Unpacking archive to '%s'\n", szPathExtracted);
    1626                     rc = AudioTestSetUnpack(pszPathSet, szPathExtracted);
    1627                     if (RT_SUCCESS(rc))
    1628                         RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Archive successfully unpacked\n");
    1629                 }
    1630             }
    1631         }
    1632     }
    1633     else
    1634         rc = VINF_SUCCESS;
    1635 
    1636     if (RT_SUCCESS(rc))
    1637         rc = AudioTestSetOpen(pSet, fPacked ? szPathExtracted : pszPathSet);
    1638 
    1639     if (RT_FAILURE(rc))
    1640         RTTestFailed(g_hTest, "Unable to open / unpack test set archive: %Rrc", rc);
    1641 
    1642     return rc;
    1643 }
    1644 
    1645 /**
    1646  * Verifies one single test set.
    1647  *
    1648  * @returns VBox status code.
    1649  * @param   pszPathSetA         Absolute path to test set A.
    1650  * @param   pszPathSetB         Absolute path to test set B.
    1651  */
    1652 static int audioVerifyOne(const char *pszPathSetA, const char *pszPathSetB)
    1653 {
    1654     RTTestSubF(g_hTest, "Verifying");
    1655     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Verifying test set '%s' with test set '%s'\n", pszPathSetA, pszPathSetB);
    1656 
    1657     AUDIOTESTSET SetA, SetB;
    1658     int rc = audioVerifyOpenTestSet(pszPathSetA, &SetA);
    1659     if (RT_SUCCESS(rc))
    1660         rc = audioVerifyOpenTestSet(pszPathSetB, &SetB);
    1661 
    1662     if (RT_SUCCESS(rc))
    1663     {
    1664         AUDIOTESTERRORDESC errDesc;
    1665         rc = AudioTestSetVerify(&SetA, &SetB, &errDesc);
    1666         if (RT_SUCCESS(rc))
    1667         {
    1668             if (AudioTestErrorDescFailed(&errDesc))
    1669             {
    1670                 /** @todo Use some AudioTestErrorXXX API for enumeration here later. */
    1671                 PAUDIOTESTERRORENTRY pErrEntry;
    1672                 RTListForEach(&errDesc.List, pErrEntry, AUDIOTESTERRORENTRY, Node)
    1673                     RTTestFailed(g_hTest, pErrEntry->szDesc);
    1674             }
    1675             else
    1676                 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Verification successful\n");
    1677 
    1678             AudioTestErrorDescDestroy(&errDesc);
    1679         }
    1680         else
    1681             RTTestFailed(g_hTest, "Verification failed with %Rrc", rc);
    1682     }
    1683 
    1684     AudioTestSetClose(&SetA);
    1685     AudioTestSetClose(&SetB);
    1686 
    1687     RTTestSubDone(g_hTest);
    1688 
    1689     return rc;
    1690 }
    1691 
    1692 /**
    1693  * Main (entry) function for the verification functionality of VKAT.
    1694  *
    1695  * @returns Program exit code.
    1696  * @param   pGetState   RTGetOpt state.
    1697  */
    1698 static DECLCALLBACK(RTEXITCODE) audioVerifyMain(PRTGETOPTSTATE pGetState)
    1699 {
    1700     /*
    1701      * Parse options and process arguments.
    1702      */
    1703     const char *apszSets[2] = { NULL, NULL };
    1704     unsigned    iTestSet    = 0;
    1705 
    1706     int           rc;
    1707     RTGETOPTUNION ValueUnion;
    1708     while ((rc = RTGetOpt(pGetState, &ValueUnion)))
    1709     {
    1710         switch (rc)
    1711         {
    1712             case VKAT_VERIFY_OPT_TAG:
    1713                 break;
    1714 
    1715             case VINF_GETOPT_NOT_OPTION:
    1716                 if (iTestSet == 0)
    1717                     RTTestBanner(g_hTest);
    1718                 if (iTestSet >= RT_ELEMENTS(apszSets))
    1719                     return RTMsgErrorExitFailure("Only two test sets can be verified at one time");
    1720                 apszSets[iTestSet++] = ValueUnion.psz;
    1721                 break;
    1722 
    1723             AUDIO_TEST_COMMON_OPTION_CASES(ValueUnion);
    1724 
    1725             default:
    1726                 return RTGetOptPrintError(rc, &ValueUnion);
    1727         }
    1728     }
    1729 
    1730     if (!iTestSet)
    1731         return RTMsgErrorExitFailure("At least one test set must be specified");
    1732 
    1733     /*
    1734      * If only test set A is given, default to the current directory
    1735      * for test set B.
    1736      */
    1737     char szDirCur[RTPATH_MAX];
    1738     if (iTestSet == 1)
    1739     {
    1740         rc = RTPathGetCurrent(szDirCur, sizeof(szDirCur));
    1741         if (RT_SUCCESS(rc))
    1742             apszSets[1] = szDirCur;
    1743         else
    1744             RTTestFailed(g_hTest, "Failed to retrieve current directory: %Rrc", rc);
    1745     }
    1746 
    1747     if (RT_SUCCESS(rc))
    1748         audioVerifyOne(apszSets[0], apszSets[1]);
    1749 
    1750     /*
    1751      * Print summary and exit.
    1752      */
    1753     return RTTestSummaryAndDestroy(g_hTest);
    1754 }
    175536
    175637
     
    176748};
    176849
     50
    176951/** The 'enum' command option help. */
    177052static DECLCALLBACK(const char *) audioTestCmdEnumHelp(PCRTGETOPTDEF pOpt)
     
    177658    }
    177759}
     60
    177861
    177962/**
     
    1861144    return RTEXITCODE_SUCCESS;
    1862145}
     146
     147
     148/**
     149 * Command table entry for 'enum'.
     150 */
     151const VKATCMD g_cmdEnum =
     152{
     153    "enum",
     154    audioTestCmdEnumHandler,
     155    "Enumerates audio devices.",
     156    g_aCmdEnumOptions,
     157    RT_ELEMENTS(g_aCmdEnumOptions),
     158    audioTestCmdEnumHelp,
     159};
     160
     161
    1863162
    1864163
     
    2066365}
    2067366
     367
    2068368/**
    2069369 * Options for 'play'.
     
    2081381};
    2082382
     383
    2083384/** The 'play' command option help. */
    2084385static DECLCALLBACK(const char *) audioTestCmdPlayHelp(PCRTGETOPTDEF pOpt)
     
    2096397    }
    2097398}
     399
    2098400
    2099401/**
     
    2171473    return RTEXITCODE_SUCCESS;
    2172474}
     475
     476
     477/**
     478 * Command table entry for 'play'.
     479 */
     480const VKATCMD g_cmdPlay =
     481{
     482    "play",
     483    audioTestCmdPlayHandler,
     484    "Plays one or more wave files.",
     485    g_aCmdPlayOptions,
     486    RT_ELEMENTS(g_aCmdPlayOptions),
     487    audioTestCmdPlayHelp,
     488};
    2173489
    2174490
     
    2376692}
    2377693
     694
    2378695/**
    2379696 * Options for 'rec'.
     
    2402719};
    2403720
     721
    2404722/** The 'rec' command option help. */
    2405723static DECLCALLBACK(const char *) audioTestCmdRecHelp(PCRTGETOPTDEF pOpt)
     
    2425743}
    2426744
    2427 /**
    2428  * The 'play' command handler.
     745
     746/**
     747 * The 'rec' command handler.
    2429748 *
    2430749 * @returns Program exit code.
     
    2536855
    2537856
    2538 /*********************************************************************************************************************************
    2539 *   Command: selftest                                                                                                            *
    2540 *********************************************************************************************************************************/
    2541 
    2542 /** @todo Move this (all?) commands into separate files -- this file is too big already. */
    2543 
    2544 /**
    2545  * Command line parameters for self-test mode.
    2546  */
    2547 static const RTGETOPTDEF g_aCmdSelftestOptions[] =
    2548 {
    2549     { "--ats-guest-addr",   VKAT_SELFTEST_OPT_ATS_GUEST_ADDR,   RTGETOPT_REQ_STRING  },
    2550     { "--ats-guest-port",   VKAT_SELFTEST_OPT_ATS_GUEST_PORT,   RTGETOPT_REQ_UINT32  },
    2551     { "--ats-valkit-addr",  VKAT_SELFTEST_OPT_ATS_GUEST_ADDR,   RTGETOPT_REQ_STRING  },
    2552     { "--ats-valkit-port",  VKAT_SELFTEST_OPT_ATS_GUEST_PORT,   RTGETOPT_REQ_UINT32  },
    2553     { "--exclude-all",      'a',                                RTGETOPT_REQ_NOTHING },
    2554     { "--backend",          'b',                                RTGETOPT_REQ_STRING  },
    2555     { "--with-drv-audio",   'd',                                RTGETOPT_REQ_NOTHING },
    2556     { "--exclude",          'e',                                RTGETOPT_REQ_UINT32  },
    2557     { "--include",          'i',                                RTGETOPT_REQ_UINT32  }
     857/**
     858 * Command table entry for 'rec'.
     859 */
     860const VKATCMD g_cmdRec =
     861{
     862    "rec",
     863    audioTestCmdRecHandler,
     864    "Records audio to a wave file.",
     865    g_aCmdRecOptions,
     866    RT_ELEMENTS(g_aCmdRecOptions),
     867    audioTestCmdRecHelp,
    2558868};
    2559869
    2560 /** the 'selftest' command option help. */
    2561 static DECLCALLBACK(const char *) audioTestCmdSelftestHelp(PCRTGETOPTDEF pOpt)
    2562 {
    2563     switch (pOpt->iShort)
    2564     {
    2565         case 'b': return "The audio backend to use.";
    2566         case 'd': return "Go via DrvAudio instead of directly interfacing with the backend.";
    2567         default:  return NULL;
    2568     }
    2569 }
    2570 
    2571 /**
    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 /**
    2750  * The 'selftest' command handler.
    2751  *
    2752  * @returns Program exit code.
    2753  * @param   pGetState   RTGetOpt state.
    2754  */
    2755 static DECLCALLBACK(RTEXITCODE) audioTestCmdSelftestHandler(PRTGETOPTSTATE pGetState)
    2756 {
    2757     SELFTESTCTX Ctx;
    2758     RT_ZERO(Ctx);
    2759 
    2760     /* Go with the platform's default bakcend if nothing else is specified. */
    2761     Ctx.Guest.pDrvReg = g_aBackends[0].pDrvReg;
    2762 
    2763     /* Argument processing loop: */
    2764     int           rc;
    2765     RTGETOPTUNION ValueUnion;
    2766     while ((rc = RTGetOpt(pGetState, &ValueUnion)) != 0)
    2767     {
    2768         switch (rc)
    2769         {
    2770             case VKAT_SELFTEST_OPT_ATS_GUEST_ADDR:
    2771                 rc = RTStrCopy(Ctx.Host.szGuestAtsAddr, sizeof(Ctx.Host.szGuestAtsAddr), ValueUnion.psz);
    2772                 break;
    2773 
    2774             case VKAT_SELFTEST_OPT_ATS_GUEST_PORT:
    2775                 Ctx.Host.uGuestAtsPort = ValueUnion.u32;
    2776                 break;
    2777 
    2778             case VKAT_SELFTEST_OPT_ATS_VALKIT_ADDR:
    2779                 rc = RTStrCopy(Ctx.Host.szValKitAtsAddr, sizeof(Ctx.Host.szValKitAtsAddr), ValueUnion.psz);
    2780                 break;
    2781 
    2782             case VKAT_SELFTEST_OPT_ATS_VALKIT_PORT:
    2783                 Ctx.Host.uValKitAtsPort = ValueUnion.u32;
    2784                 break;
    2785 
    2786             case 'a':
    2787                 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
    2788                     g_aTests[i].fExcluded = true;
    2789                 break;
    2790 
    2791             case 'b':
    2792             {
    2793                 Ctx.Guest.pDrvReg = audioTestFindBackendOpt(ValueUnion.psz);
    2794                 if (Ctx.Guest.pDrvReg == NULL)
    2795                     return RTEXITCODE_SYNTAX;
    2796                 break;
    2797             }
    2798 
    2799             case 'd':
    2800                 Ctx.fWithDrvAudio = true;
    2801                 break;
    2802 
    2803             case 'e':
    2804                 if (ValueUnion.u32 >= RT_ELEMENTS(g_aTests))
    2805                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid test number %u passed to --exclude", ValueUnion.u32);
    2806                 g_aTests[ValueUnion.u32].fExcluded = true;
    2807                 break;
    2808 
    2809             case 'i':
    2810                 if (ValueUnion.u32 >= RT_ELEMENTS(g_aTests))
    2811                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid test number %u passed to --include", ValueUnion.u32);
    2812                 g_aTests[ValueUnion.u32].fExcluded = false;
    2813                 break;
    2814 
    2815             AUDIO_TEST_COMMON_OPTION_CASES(ValueUnion);
    2816 
    2817             default:
    2818                 return RTGetOptPrintError(rc, &ValueUnion);
    2819         }
    2820     }
    2821 
    2822     /*
    2823      * Start testing.
    2824      */
    2825     RTTestBanner(g_hTest);
    2826 
    2827     int rc2 = audioTestDoSelftest(&Ctx);
    2828     if (RT_FAILURE(rc2))
    2829         RTTestFailed(g_hTest, "Self test failed with rc=%Rrc", rc2);
    2830 
    2831     /*
    2832      * Print summary and exit.
    2833      */
    2834     return RTTestSummaryAndDestroy(g_hTest);
    2835 }
    2836 
    2837 
    2838 /**
    2839  * Ctrl-C signal handler.
    2840  *
    2841  * This just sets g_fTerminate and hope it will be noticed soon.  It restores
    2842  * the SIGINT action to default, so that a second Ctrl-C will have the normal
    2843  * effect (just in case the code doesn't respond to g_fTerminate).
    2844  */
    2845 static void audioTestSignalHandler(int iSig) RT_NOEXCEPT
    2846 {
    2847     Assert(iSig == SIGINT); RT_NOREF(iSig);
    2848     RTPrintf("Ctrl-C!\n");
    2849     ASMAtomicWriteBool(&g_fTerminate, true);
    2850     signal(SIGINT, SIG_DFL);
    2851 }
    2852 
    2853 
    2854 /**
    2855  * Commands.
    2856  */
    2857 static struct
    2858 {
    2859     /** The command name. */
    2860     const char     *pszCommand;
    2861     /** The command handler.   */
    2862     DECLCALLBACKMEMBER(RTEXITCODE, pfnHandler,(PRTGETOPTSTATE pGetState));
    2863 
    2864     /** Command description.   */
    2865     const char     *pszDesc;
    2866     /** Options array.  */
    2867     PCRTGETOPTDEF   paOptions;
    2868     /** Number of options in the option array. */
    2869     size_t          cOptions;
    2870     /** Gets help for an option. */
    2871     DECLCALLBACKMEMBER(const char *, pfnOptionHelp,(PCRTGETOPTDEF pOpt));
    2872 } const g_aCommands[] =
    2873 {
    2874     {
    2875         "test",     audioTestMain,
    2876         "Runs audio tests and creates an audio test set.",
    2877         g_aCmdTestOptions,      RT_ELEMENTS(g_aCmdTestOptions),     audioTestCmdTestHelp
    2878     },
    2879     {
    2880         "verify",   audioVerifyMain,
    2881         "Verifies a formerly created audio test set.",
    2882         g_aCmdVerifyOptions,    RT_ELEMENTS(g_aCmdVerifyOptions),   NULL,
    2883     },
    2884     {
    2885         "enum",     audioTestCmdEnumHandler,
    2886         "Enumerates audio devices.",
    2887         g_aCmdEnumOptions,      RT_ELEMENTS(g_aCmdEnumOptions),     audioTestCmdEnumHelp,
    2888     },
    2889     {
    2890         "play",     audioTestCmdPlayHandler,
    2891         "Plays one or more wave files.",
    2892         g_aCmdPlayOptions,      RT_ELEMENTS(g_aCmdPlayOptions),     audioTestCmdPlayHelp,
    2893     },
    2894     {
    2895         "rec",      audioTestCmdRecHandler,
    2896         "Records audio to a wave file.",
    2897         g_aCmdRecOptions,       RT_ELEMENTS(g_aCmdRecOptions),      audioTestCmdRecHelp,
    2898     },
    2899     {
    2900         "selftest", audioTestCmdSelftestHandler,
    2901         "Performs self-tests.",
    2902         g_aCmdSelftestOptions,  RT_ELEMENTS(g_aCmdSelftestOptions), audioTestCmdSelftestHelp,
    2903     }
    2904 };
    2905 
    2906 /**
    2907  * Shows tool usage text.
    2908  */
    2909 static RTEXITCODE audioTestUsage(PRTSTREAM pStrm)
    2910 {
    2911     RTStrmPrintf(pStrm, "usage: %s [global options] <command> [command-options]\n",
    2912                  RTPathFilename(RTProcExecutablePath()));
    2913     RTStrmPrintf(pStrm,
    2914                  "\n"
    2915                  "Global Options:\n"
    2916                  "  --debug-audio\n"
    2917                  "    Enables DrvAudio debugging.\n"
    2918                  "  --debug-audio-path=<path>\n"
    2919                  "    Tells DrvAudio where to put its debug output (wav-files).\n"
    2920                  "  -q, --quiet\n"
    2921                  "    Sets verbosity to zero.\n"
    2922                  "  -v, --verbose\n"
    2923                  "    Increase verbosity.\n"
    2924                  "  -V, --version\n"
    2925                  "    Displays version.\n"
    2926                  "  -h, -?, --help\n"
    2927                  "    Displays help.\n"
    2928                  );
    2929 
    2930     for (uintptr_t iCmd = 0; iCmd < RT_ELEMENTS(g_aCommands); iCmd++)
    2931     {
    2932         RTStrmPrintf(pStrm,
    2933                      "\n"
    2934                      "Command '%s':\n"
    2935                      "    %s\n"
    2936                      "Options for '%s':\n",
    2937                      g_aCommands[iCmd].pszCommand, g_aCommands[iCmd].pszDesc, g_aCommands[iCmd].pszCommand);
    2938         PCRTGETOPTDEF const paOptions = g_aCommands[iCmd].paOptions;
    2939         for (unsigned i = 0; i < g_aCommands[iCmd].cOptions; i++)
    2940         {
    2941             if (RT_C_IS_PRINT(paOptions[i].iShort))
    2942                 RTStrmPrintf(pStrm, "  -%c, %s\n", paOptions[i].iShort, paOptions[i].pszLong);
    2943             else
    2944                 RTStrmPrintf(pStrm, "  %s\n", paOptions[i].pszLong);
    2945 
    2946             const char *pszHelp = NULL;
    2947             if (g_aCommands[iCmd].pfnOptionHelp)
    2948                 pszHelp = g_aCommands[iCmd].pfnOptionHelp(&paOptions[i]);
    2949             if (pszHelp)
    2950                 RTStrmPrintf(pStrm, "    %s\n", pszHelp);
    2951         }
    2952     }
    2953     return RTEXITCODE_SUCCESS;
    2954 }
    2955 
    2956 /**
    2957  * Shows tool version.
    2958  */
    2959 static RTEXITCODE audioTestVersion(void)
    2960 {
    2961     RTPrintf("v0.0.1\n");
    2962     return RTEXITCODE_SUCCESS;
    2963 }
    2964 
    2965 /**
    2966  * Shows the logo.
    2967  *
    2968  * @param   pStream             Output stream to show logo on.
    2969  */
    2970 static void audioTestShowLogo(PRTSTREAM pStream)
    2971 {
    2972     RTStrmPrintf(pStream, VBOX_PRODUCT " VKAT (Validation Kit Audio Test) Version " VBOX_VERSION_STRING " - r%s\n"
    2973                  "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
    2974                  "All rights reserved.\n\n", RTBldCfgRevisionStr());
    2975 }
    2976 
    2977 int main(int argc, char **argv)
    2978 {
    2979     /*
    2980      * Init IPRT and globals.
    2981      */
    2982     RTEXITCODE rcExit = RTTestInitAndCreate("AudioTest", &g_hTest);
    2983     if (rcExit != RTEXITCODE_SUCCESS)
    2984         return rcExit;
    2985 
    2986 #ifdef RT_OS_WINDOWS
    2987     HRESULT hrc = CoInitializeEx(NULL /*pReserved*/, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY | COINIT_DISABLE_OLE1DDE);
    2988     if (FAILED(hrc))
    2989         RTMsgWarning("CoInitializeEx failed: %#x", hrc);
    2990 #endif
    2991 
    2992     /*
    2993      * Configure release logging to go to stderr.
    2994      */
    2995     static const char * const g_apszLogGroups[] = VBOX_LOGGROUP_NAMES;
    2996     int rc = RTLogCreate(&g_pRelLogger, RTLOGFLAGS_PREFIX_THREAD, "all.e.l", "VKAT_RELEASE_LOG",
    2997                          RT_ELEMENTS(g_apszLogGroups), g_apszLogGroups, RTLOGDEST_STDERR, NULL /*"vkat-release.log"*/);
    2998     if (RT_SUCCESS(rc))
    2999         RTLogRelSetDefaultInstance(g_pRelLogger);
    3000     else
    3001         RTMsgWarning("Failed to create release logger: %Rrc", rc);
    3002 
    3003     /*
    3004      * Install a Ctrl-C signal handler.
    3005      */
    3006 #ifdef RT_OS_WINDOWS
    3007     signal(SIGINT, audioTestSignalHandler);
    3008 #else
    3009     struct sigaction sa;
    3010     RT_ZERO(sa);
    3011     sa.sa_handler = audioTestSignalHandler;
    3012     sigaction(SIGINT, &sa, NULL);
    3013 #endif
    3014 
    3015     /*
    3016      * Process common options.
    3017      */
    3018     RTGETOPTSTATE GetState;
    3019     rc = RTGetOptInit(&GetState, argc, argv, g_aCmdCommonOptions,
    3020                       RT_ELEMENTS(g_aCmdCommonOptions), 1 /*idxFirst*/, 0 /*fFlags - must not sort! */);
    3021     AssertRCReturn(rc, RTEXITCODE_INIT);
    3022 
    3023     RTGETOPTUNION ValueUnion;
    3024     while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0)
    3025     {
    3026         switch (rc)
    3027         {
    3028             case 'q':
    3029                 g_uVerbosity = 0;
    3030                 if (g_pRelLogger)
    3031                     RTLogGroupSettings(g_pRelLogger, "all=0 all.e");
    3032                 break;
    3033 
    3034             case 'v':
    3035                 g_uVerbosity++;
    3036                 if (g_pRelLogger)
    3037                     RTLogGroupSettings(g_pRelLogger, g_uVerbosity == 1 ? "all.e.l" : g_uVerbosity == 2 ? "all.e.l.f" : "all=~0");
    3038                 break;
    3039 
    3040             case 'V':
    3041                 return audioTestVersion();
    3042 
    3043             case 'h':
    3044                 audioTestShowLogo(g_pStdOut);
    3045                 return audioTestUsage(g_pStdOut);
    3046 
    3047             case VINF_GETOPT_NOT_OPTION:
    3048             {
    3049                 for (uintptr_t i = 0; i < RT_ELEMENTS(g_aCommands); i++)
    3050                     if (strcmp(ValueUnion.psz, g_aCommands[i].pszCommand) == 0)
    3051                     {
    3052                         size_t const cCombinedOptions  = g_aCommands[i].cOptions + RT_ELEMENTS(g_aCmdCommonOptions);
    3053                         PRTGETOPTDEF paCombinedOptions = (PRTGETOPTDEF)RTMemAlloc(cCombinedOptions * sizeof(RTGETOPTDEF));
    3054                         if (paCombinedOptions)
    3055                         {
    3056                             memcpy(paCombinedOptions, g_aCmdCommonOptions, sizeof(g_aCmdCommonOptions));
    3057                             memcpy(&paCombinedOptions[RT_ELEMENTS(g_aCmdCommonOptions)],
    3058                                    g_aCommands[i].paOptions, g_aCommands[i].cOptions * sizeof(RTGETOPTDEF));
    3059 
    3060                             rc = RTGetOptInit(&GetState, argc, argv, paCombinedOptions, cCombinedOptions,
    3061                                               GetState.iNext /*idxFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    3062                             if (RT_SUCCESS(rc))
    3063                             {
    3064 
    3065                                 rcExit = g_aCommands[i].pfnHandler(&GetState);
    3066                                 RTMemFree(paCombinedOptions);
    3067                                 return rcExit;
    3068                             }
    3069                             return RTMsgErrorExitFailure("RTGetOptInit failed for '%s': %Rrc", ValueUnion.psz, rc);
    3070                         }
    3071                         return RTMsgErrorExitFailure("Out of memory!");
    3072                     }
    3073                 RTMsgError("Unknown command '%s'!\n", ValueUnion.psz);
    3074                 audioTestUsage(g_pStdErr);
    3075                 return RTEXITCODE_SYNTAX;
    3076             }
    3077 
    3078             default:
    3079                 return RTGetOptPrintError(rc, &ValueUnion);
    3080         }
    3081     }
    3082 
    3083     RTMsgError("No command specified!\n");
    3084     audioTestUsage(g_pStdErr);
    3085     return RTEXITCODE_SYNTAX;
    3086 }
    3087 
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCommon.cpp

    r89614 r89641  
    4444
    4545#include "vkatInternal.h"
    46 
    47 
    48 /*********************************************************************************************************************************
    49 *   Prototypes                                                                                                                   *
    50 *********************************************************************************************************************************/
    51 
    52 static int audioTestCreateStreamDefaultIn(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps);
    53 static int audioTestCreateStreamDefaultOut(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps);
    54 static int audioTestStreamDestroy(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream);
    55 static int audioTestDevicesEnumerateAndCheck(PAUDIOTESTENV pTstEnv, const char *pszDev, PPDMAUDIOHOSTDEV *ppDev);
    5646
    5747
     
    7363} ATSCALLBACKCTX;
    7464typedef ATSCALLBACKCTX *PATSCALLBACKCTX;
     65
     66
     67/*********************************************************************************************************************************
     68*   Internal Functions                                                                                                           *
     69*********************************************************************************************************************************/
     70static int audioTestCreateStreamDefaultIn(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps);
     71static int audioTestCreateStreamDefaultOut(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps);
     72static int audioTestStreamDestroy(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream);
     73static int audioTestDevicesEnumerateAndCheck(PAUDIOTESTENV pTstEnv, const char *pszDev, PPDMAUDIOHOSTDEV *ppDev);
    7574
    7675
  • trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h

    r89617 r89641  
    345345
    346346/**
    347  * Structure for defining a single VKAT command.
     347 * VKAT command table entry.
    348348 */
    349349typedef struct VKATCMD
     
    363363    DECLCALLBACKMEMBER(const char *, pfnOptionHelp,(PCRTGETOPTDEF pOpt));
    364364} VKATCMD;
    365 typedef VKATCMD *PVKATCMD;
    366365/** Pointer to a single VKAT command. */
    367366typedef VKATCMD *PVKATCMD;
    368367
     368extern const VKATCMD g_cmdEnum;
    369369extern const VKATCMD g_cmdPlay;
    370370extern const VKATCMD g_cmdRec;
     
    373373extern AUDIOTESTDESC g_aTests[];
    374374extern unsigned      g_cTests;
     375
    375376
    376377/*********************************************************************************************************************************
     
    464465/** @name Command handlers
    465466 * @{ */
    466 RTEXITCODE   audioTestPlayOne(const char *pszFile, PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
    467                               uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
    468                               uint8_t cChannels, uint8_t cbSample, uint32_t uHz,
    469                               bool fWithDrvAudio, bool fWithMixer);
    470 RTEXITCODE   audioTestRecOne(const char *pszFile, uint8_t cWaveChannels, uint8_t cbWaveSample, uint32_t uWaveHz,
    471                              PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
    472                              uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
    473                              uint8_t cChannels, uint8_t cbSample, uint32_t uHz, bool fWithDrvAudio, bool fWithMixer,
    474                              uint64_t cMaxFrames, uint64_t cNsMaxDuration);
    475467RTEXITCODE   audioTestDoSelftest(PSELFTESTCTX pCtx);
    476468/** @}  */
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