Changeset 89641 in vbox for trunk/src/VBox/ValidationKit
- Timestamp:
- Jun 13, 2021 12:44:53 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 145086
- 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 64 64 vkat.cpp \ 65 65 vkatCommon.cpp \ 66 vkatCmd PlayRec.cpp \66 vkatCmdGeneric.cpp \ 67 67 vkatDriverStack.cpp \ 68 68 $(VKAT_PATH_AUDIO)/AudioTest.cpp \ -
trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp
r89617 r89641 896 896 897 897 /********************************************************************************************************************************* 898 * Command: enum*898 * Main * 899 899 *********************************************************************************************************************************/ 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 else982 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 else993 rcExit = RTMsgErrorExitFailure("Enumeration failed: %Rrc\n", rc);994 }995 else996 rcExit = RTMsgErrorExitFailure("Enumeration not supported by backend '%s'\n", pDrvReg->szName);997 audioTestDriverStackDelete(&DrvStack);998 }999 else1000 rcExit = RTMsgErrorExitFailure("Driver stack construction failed: %Rrc", rc);1001 return RTEXITCODE_SUCCESS;1002 }1003 900 1004 901 /** … … 1029 926 g_aCmdVerifyOptions, RT_ELEMENTS(g_aCmdVerifyOptions), NULL, 1030 927 }, 1031 { 1032 "enum", audioTestCmdEnumHandler, 1033 "Enumerates audio devices.", 1034 g_aCmdEnumOptions, RT_ELEMENTS(g_aCmdEnumOptions), audioTestCmdEnumHelp, 1035 }, 928 g_cmdEnum, 1036 929 g_cmdPlay, 1037 930 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.cpp 58652,70973 /branches/VBox-3.2/src/VBox/ValidationKit/utils/audio/vkat.cpp 66309,66318 /branches/VBox-4.0/src/VBox/ValidationKit/utils/audio/vkat.cpp 70873 /branches/VBox-4.1/src/VBox/ValidationKit/utils/audio/vkat.cpp 74233,78414,78691,81841,82127,85941,85944-85947,85949-85950,85953,86701,86728,87009 /branches/VBox-4.2/src/VBox/ValidationKit/utils/audio/vkat.cpp 86229-86230,86234,86529,91503-91504,91506-91508,91510,91514-91515,91521,108112,108114,108127 /branches/VBox-4.3/src/VBox/ValidationKit/utils/audio/vkat.cpp 89714,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.cpp 91223 /branches/VBox-5.0/src/VBox/ValidationKit/utils/audio/vkat.cpp 104938,104943,104950,104987-104988,104990,106453 /branches/VBox-5.1/src/VBox/ValidationKit/utils/audio/vkat.cpp 112367,116543,116550,116568,116573 /branches/VBox-5.2/src/VBox/ValidationKit/utils/audio/vkat.cpp 119536,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.cpp 130474-130475,130477,130479,131352 /branches/VBox-6.1/src/VBox/ValidationKit/utils/audio/vkat.cpp 141521,141567-141568,141588-141590,141592-141595,141652,141920 /branches/aeichner/vbox-chromium-cleanup/src/VBox/ValidationKit/utils/audio/vkat.cpp 129818-129851,129853-129861,129871-129872,129876,129880,129882,130013-130015,130094-130095 /branches/andy/draganddrop/src/VBox/ValidationKit/utils/audio/vkat.cpp 90781-91268 /branches/andy/guestctrl20/src/VBox/ValidationKit/utils/audio/vkat.cpp 78916,78930 /branches/andy/pdmaudio/src/VBox/ValidationKit/utils/audio/vkat.cpp 94582,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.cpp 92692-94610 /branches/dsen/gui/src/VBox/ValidationKit/utils/audio/vkat.cpp 79076-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.cpp 79224,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.cpp 79645-79692
r89541 r89641 29 29 * Header Files * 30 30 *********************************************************************************************************************************/ 31 #include <iprt/buildconfig.h>32 #include <iprt/ctype.h>33 #include <iprt/dir.h>34 31 #include <iprt/errcore.h> 35 #include <iprt/initterm.h>36 #include <iprt/getopt.h>37 32 #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>44 33 #include <iprt/test.h> 45 34 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_WINDOWS53 # include <iprt/win/windows.h> /* for CoInitializeEx */54 #endif55 #include <signal.h>56 57 /**58 * Internal driver instance data59 * @note This must be put here as it's needed before pdmdrv.h is included.60 */61 typedef struct PDMDRVINSINT62 {63 /** The stack the drive belongs to. */64 struct AUDIOTESTDRVSTACK *pStack;65 } PDMDRVINSINT;66 #define PDMDRVINSINT_DECLARED67 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 78 35 #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 break111 112 113 /*********************************************************************************************************************************114 * Structures and Typedefs *115 *********************************************************************************************************************************/116 /**117 * Enumeration specifying the current audio test mode.118 */119 typedef enum AUDIOTESTMODE120 {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_HOST127 } 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 code142 * 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 AUDIOTESTSTREAM162 {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 8175 176 /**177 * Audio test environment parameters.178 * Not necessarily bound to a specific test (can be reused).179 */180 typedef struct AUDIOTESTENV181 {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 union207 {208 struct209 {210 /** ATS instance to use. */211 ATSSERVER Srv;212 } Guest;213 struct214 {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 AUDIOTESTDESC227 {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 ATSCALLBACKCTX244 {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 enum271 {272 AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_ENABLE = 256,273 AUDIO_TEST_OPT_CMN_DEBUG_AUDIO_PATH274 };275 276 /**277 * Long option values for the 'test' command.278 */279 enum280 {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_VOL295 };296 297 /**298 * Long option values for the 'verify' command.299 */300 enum301 {302 VKAT_VERIFY_OPT_TAG = 900303 };304 305 /**306 * Long option values for the 'selftest' command.307 */308 enum309 {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_PORT314 };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 struct367 {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 #endif378 #ifdef VBOX_WITH_AUDIO_PULSE379 { &g_DrvHostPulseAudio, "pulseaudio" },380 { &g_DrvHostPulseAudio, "pulse" },381 { &g_DrvHostPulseAudio, "pa" },382 #endif383 #ifdef VBOX_WITH_AUDIO_OSS384 { &g_DrvHostOSSAudio, "oss" },385 #endif386 #if defined(RT_OS_DARWIN)387 { &g_DrvHostCoreAudio, "coreaudio" },388 { &g_DrvHostCoreAudio, "core" },389 { &g_DrvHostCoreAudio, "ca" },390 #endif391 #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 #endif398 { &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 (error423 * 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) == 0430 || 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 else509 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 else578 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 else653 AudioTestSetTestFailed(pTst, rc, "Playing tone failed");654 }655 656 int rc2 = audioTestStreamDestroy(pTstEnv, pTstStream);657 if (RT_SUCCESS(rc))658 rc = rc2;659 }660 else661 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 else694 AudioTestSetTestFailed(pTst, rc, "Recording tone failed");695 }696 697 int rc2 = audioTestStreamDestroy(pTstEnv, pTstStream);698 if (RT_SUCCESS(rc))699 rc = rc2;700 }701 else702 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_GUEST742 /* 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 so853 * 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 a906 * specific device was found.907 */908 static int audioTestDevicesEnumerateAndCheck(PAUDIOTESTENV pTstEnv, const char *pszDev, PPDMAUDIOHOSTDEV *ppDev)909 {910 #ifdef DEBUG_andy911 return VINF_SUCCESS;912 #endif913 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 else937 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 ( pszDev944 && !RTStrCmp(pDev->pszName, pszDev))945 {946 *ppDev = pDev;947 }948 }949 }950 else951 RTTestFailed(g_hTest, "Enumerating audio devices failed with %Rrc", rc);952 953 RTTestSubDone(g_hTest);954 955 if ( pszDev956 && *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 FNAUDIOTESTSETUP1087 */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 DEBUG1098 pTstParmsAcq->cIterations = 2;1099 #else1100 pTstParmsAcq->cIterations = RTRandU32Ex(1, 10);1101 #endif1102 pTstParmsAcq->idxCurrent = 0;1103 1104 return VINF_SUCCESS;1105 }1106 1107 /**1108 * @copydoc FNAUDIOTESTEXEC1109 */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 else1135 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 FNAUDIOTESTDESTROY1147 */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 FNAUDIOTESTSETUP1157 */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 DEBUG1168 pTstParmsAcq->cIterations = 2;1169 #else1170 pTstParmsAcq->cIterations = RTRandU32Ex(1, 10);1171 #endif1172 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 FNAUDIOTESTEXEC1190 */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_andy1201 pTstParms->TestTone.msDuration = RTRandU32Ex(50 /* ms */, 2000);1202 #else1203 pTstParms->TestTone.msDuration = RTRandU32Ex(50 /* ms */, RT_MS_30SEC); /** @todo Record even longer? */1204 #endif1205 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 else1224 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 FNAUDIOTESTDESTROY1237 */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 else1399 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 else1634 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 else1676 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Verification successful\n");1677 1678 AudioTestErrorDescDestroy(&errDesc);1679 }1680 else1681 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 directory1735 * 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 else1744 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 }1755 36 1756 37 … … 1767 48 }; 1768 49 50 1769 51 /** The 'enum' command option help. */ 1770 52 static DECLCALLBACK(const char *) audioTestCmdEnumHelp(PCRTGETOPTDEF pOpt) … … 1776 58 } 1777 59 } 60 1778 61 1779 62 /** … … 1861 144 return RTEXITCODE_SUCCESS; 1862 145 } 146 147 148 /** 149 * Command table entry for 'enum'. 150 */ 151 const 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 1863 162 1864 163 … … 2066 365 } 2067 366 367 2068 368 /** 2069 369 * Options for 'play'. … … 2081 381 }; 2082 382 383 2083 384 /** The 'play' command option help. */ 2084 385 static DECLCALLBACK(const char *) audioTestCmdPlayHelp(PCRTGETOPTDEF pOpt) … … 2096 397 } 2097 398 } 399 2098 400 2099 401 /** … … 2171 473 return RTEXITCODE_SUCCESS; 2172 474 } 475 476 477 /** 478 * Command table entry for 'play'. 479 */ 480 const 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 }; 2173 489 2174 490 … … 2376 692 } 2377 693 694 2378 695 /** 2379 696 * Options for 'rec'. … … 2402 719 }; 2403 720 721 2404 722 /** The 'rec' command option help. */ 2405 723 static DECLCALLBACK(const char *) audioTestCmdRecHelp(PCRTGETOPTDEF pOpt) … … 2425 743 } 2426 744 2427 /** 2428 * The 'play' command handler. 745 746 /** 747 * The 'rec' command handler. 2429 748 * 2430 749 * @returns Program exit code. … … 2536 855 2537 856 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 */ 860 const 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, 2558 868 }; 2559 869 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 SELFTESTCTX2575 {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 struct2581 {2582 AUDIOTESTENV TstEnv;2583 /** Audio driver to use.2584 * Defaults to the platform's default driver. */2585 PCPDMDRVREG pDrvReg;2586 } Guest;2587 struct2588 {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 the2637 * 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 instance2668 * 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 restores2842 * the SIGINT action to default, so that a second Ctrl-C will have the normal2843 * effect (just in case the code doesn't respond to g_fTerminate).2844 */2845 static void audioTestSignalHandler(int iSig) RT_NOEXCEPT2846 {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 struct2858 {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), audioTestCmdTestHelp2878 },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 else2944 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_WINDOWS2987 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 #endif2991 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 else3001 RTMsgWarning("Failed to create release logger: %Rrc", rc);3002 3003 /*3004 * Install a Ctrl-C signal handler.3005 */3006 #ifdef RT_OS_WINDOWS3007 signal(SIGINT, audioTestSignalHandler);3008 #else3009 struct sigaction sa;3010 RT_ZERO(sa);3011 sa.sa_handler = audioTestSignalHandler;3012 sigaction(SIGINT, &sa, NULL);3013 #endif3014 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 -
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/VBox/ValidationKit/utils/audio/vkatCommon.cpp
r89614 r89641 44 44 45 45 #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);56 46 57 47 … … 73 63 } ATSCALLBACKCTX; 74 64 typedef ATSCALLBACKCTX *PATSCALLBACKCTX; 65 66 67 /********************************************************************************************************************************* 68 * Internal Functions * 69 *********************************************************************************************************************************/ 70 static int audioTestCreateStreamDefaultIn(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps); 71 static int audioTestCreateStreamDefaultOut(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PPDMAUDIOPCMPROPS pProps); 72 static int audioTestStreamDestroy(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream); 73 static int audioTestDevicesEnumerateAndCheck(PAUDIOTESTENV pTstEnv, const char *pszDev, PPDMAUDIOHOSTDEV *ppDev); 75 74 76 75 -
trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h
r89617 r89641 345 345 346 346 /** 347 * Structure for defining a single VKAT command.347 * VKAT command table entry. 348 348 */ 349 349 typedef struct VKATCMD … … 363 363 DECLCALLBACKMEMBER(const char *, pfnOptionHelp,(PCRTGETOPTDEF pOpt)); 364 364 } VKATCMD; 365 typedef VKATCMD *PVKATCMD;366 365 /** Pointer to a single VKAT command. */ 367 366 typedef VKATCMD *PVKATCMD; 368 367 368 extern const VKATCMD g_cmdEnum; 369 369 extern const VKATCMD g_cmdPlay; 370 370 extern const VKATCMD g_cmdRec; … … 373 373 extern AUDIOTESTDESC g_aTests[]; 374 374 extern unsigned g_cTests; 375 375 376 376 377 /********************************************************************************************************************************* … … 464 465 /** @name Command handlers 465 466 * @{ */ 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);475 467 RTEXITCODE audioTestDoSelftest(PSELFTESTCTX pCtx); 476 468 /** @} */
Note:
See TracChangeset
for help on using the changeset viewer.