VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp@ 88984

Last change on this file since 88984 was 88984, checked in by vboxsync, 4 years ago

Audio/ValKit: Show logo / version information in VKAT. bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 KB
Line 
1/* $Id: vkat.cpp 88984 2021-05-11 14:05:04Z vboxsync $ */
2/** @file
3 * Validation Kit Audio Test (VKAT) utility for testing and validating the audio stack.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/buildconfig.h>
32#include <iprt/errcore.h>
33#include <iprt/initterm.h>
34#include <iprt/getopt.h>
35#include <iprt/path.h>
36#include <iprt/message.h>
37#include <iprt/process.h>
38#include <iprt/stream.h>
39#include <iprt/string.h>
40#include <iprt/test.h>
41
42#include <package-generated.h>
43#include "product-generated.h"
44
45#include <VBox/version.h>
46#include <VBox/vmm/pdmaudioinline.h>
47#include <VBox/vmm/pdmaudiohostenuminline.h>
48
49#include "../../../Devices/Audio/AudioHlp.h"
50#include "../../../Devices/Audio/AudioTest.h"
51#include "../../../Devices/Audio/VBoxDDVKAT.h"
52
53
54/*********************************************************************************************************************************
55* Defined Constants And Macros *
56*********************************************************************************************************************************/
57
58
59/*********************************************************************************************************************************
60* Prototypes *
61*********************************************************************************************************************************/
62struct AUDIOTESTENV;
63struct AUDIOTESTDESC;
64struct AUDIOTESTPARMS;
65
66
67/*********************************************************************************************************************************
68* Structures and Typedefs *
69*********************************************************************************************************************************/
70/**
71 * Audio test request data.
72 */
73typedef struct AUDIOTESTPARMS
74{
75 /** Specifies the test to run. */
76 uint32_t idxTest;
77 /** How many iterations the test should be executed. */
78 uint32_t cIterations;
79 /** Audio device to use. */
80 PDMAUDIOHOSTDEV Dev;
81 /** How much to delay (wait, in ms) the test being executed. */
82 RTMSINTERVAL msDelay;
83 /** The test type. */
84 PDMAUDIODIR enmDir;
85 union
86 {
87 AUDIOTESTTONEPARMS ToneParms;
88 };
89} AUDIOTESTPARMS;
90/** Pointer to a test parameter structure. */
91typedef AUDIOTESTPARMS *PAUDIOTESTPARMS;
92
93/**
94 * Callback to set up the test parameters for a specific test.
95 *
96 * @returns IPRT status code.
97 * @retval VINF_SUCCESS if setting the parameters up succeeded. Any other error code
98 * otherwise indicating the kind of error.
99 * @param pszTest Test name.
100 * @param pTstParmsAcq The audio test parameters to set up.
101 */
102typedef DECLCALLBACKTYPE(int, FNAUDIOTESTSETUP,(AUDIOTESTENV *pTstEnv, AUDIOTESTDESC *pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx));
103/** Pointer to an audio test setup callback. */
104typedef FNAUDIOTESTSETUP *PFNAUDIOTESTSETUP;
105
106typedef DECLCALLBACKTYPE(int, FNAUDIOTESTEXEC,(AUDIOTESTENV *pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms));
107/** Pointer to an audio test exec callback. */
108typedef FNAUDIOTESTEXEC *PFNAUDIOTESTEXEC;
109
110typedef DECLCALLBACKTYPE(int, FNAUDIOTESTDESTROY,(AUDIOTESTENV *pTstEnv, void *pvCtx));
111/** Pointer to an audio test destroy callback. */
112typedef FNAUDIOTESTDESTROY *PFNAUDIOTESTDESTROY;
113
114/**
115 * Audio test environment parameters.
116 * Not necessarily bound to a specific test (can be reused).
117 */
118typedef struct AUDIOTESTENV
119{
120 /** The host (backend) driver to use. */
121 PPDMIHOSTAUDIO pDrvAudio;
122 /** The current (last) audio device enumeration to use. */
123 PDMAUDIOHOSTENUM DevEnm;
124 /** The audio test set to use. */
125 AUDIOTESTSET Set;
126} AUDIOTESTENV;
127/** Pointer a audio test environment. */
128typedef AUDIOTESTENV *PAUDIOTESTENV;
129
130/**
131 * Audio test descriptor.
132 */
133typedef struct AUDIOTESTDESC
134{
135 /** (Sort of) Descriptive test name. */
136 const char *pszName;
137 /** Flag whether the test is excluded. */
138 bool fExcluded;
139 /** The setup callback. */
140 PFNAUDIOTESTSETUP pfnSetup;
141 /** The exec callback. */
142 PFNAUDIOTESTEXEC pfnExec;
143 /** The destruction callback. */
144 PFNAUDIOTESTDESTROY pfnDestroy;
145} AUDIOTESTDESC;
146/** Pointer a audio test descriptor. */
147typedef AUDIOTESTDESC *PAUDIOTESTDESC;
148
149
150/*********************************************************************************************************************************
151* Forward declarations *
152*********************************************************************************************************************************/
153static int audioTestCombineParms(PAUDIOTESTPARMS pBaseParms, PAUDIOTESTPARMS pOverrideParms);
154
155
156/*********************************************************************************************************************************
157* Global Variables *
158*********************************************************************************************************************************/
159/**
160 * Enumeration of test ("test") command line parameters.
161 */
162enum
163{
164 VKAT_TEST_OPT_COUNT = 900,
165 VKAT_TEST_OPT_DEV,
166 VKAT_TEST_OPT_OUTDIR,
167 VKAT_TEST_OPT_PAUSE,
168 VKAT_TEST_OPT_PCM_HZ,
169 VKAT_TEST_OPT_PCM_BIT,
170 VKAT_TEST_OPT_PCM_CHAN,
171 VKAT_TEST_OPT_PCM_SIGNED,
172 VKAT_TEST_OPT_TAG,
173 VKAT_TEST_OPT_VOL
174};
175
176/**
177 * Enumeration of verification ("verify") command line parameters.
178 */
179enum
180{
181 VKAT_VERIFY_OPT_TAG = 900
182};
183
184/**
185 * Common command line parameters.
186 */
187static const RTGETOPTDEF g_aCmdCommonOptions[] =
188{
189 { "--help", 'h', RTGETOPT_REQ_NOTHING },
190 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
191};
192
193/**
194 * Command line parameters for test mode.
195 */
196static const RTGETOPTDEF g_aCmdTestOptions[] =
197{
198 { "--backend", 'b', RTGETOPT_REQ_STRING },
199 { "--exclude", 'e', RTGETOPT_REQ_UINT32 },
200 { "--exclude-all", 'a', RTGETOPT_REQ_NOTHING },
201 { "--include", 'i', RTGETOPT_REQ_UINT32 },
202 { "--outdir", VKAT_TEST_OPT_OUTDIR, RTGETOPT_REQ_STRING },
203 { "--count", VKAT_TEST_OPT_COUNT, RTGETOPT_REQ_UINT32 },
204 { "--device", VKAT_TEST_OPT_DEV, RTGETOPT_REQ_STRING },
205 { "--pause", VKAT_TEST_OPT_PAUSE, RTGETOPT_REQ_UINT32 },
206 { "--pcm-bit", VKAT_TEST_OPT_PCM_BIT, RTGETOPT_REQ_UINT8 },
207 { "--pcm-chan", VKAT_TEST_OPT_PCM_CHAN, RTGETOPT_REQ_UINT8 },
208 { "--pcm-hz", VKAT_TEST_OPT_PCM_HZ, RTGETOPT_REQ_UINT16 },
209 { "--pcm-signed", VKAT_TEST_OPT_PCM_SIGNED, RTGETOPT_REQ_BOOL },
210 { "--tag", VKAT_TEST_OPT_TAG, RTGETOPT_REQ_STRING },
211 { "--volume", VKAT_TEST_OPT_VOL, RTGETOPT_REQ_UINT8 }
212};
213
214/**
215 * Command line parameters for verification mode.
216 */
217static const RTGETOPTDEF g_aCmdVerifyOptions[] =
218{
219 { "--tag", VKAT_VERIFY_OPT_TAG, RTGETOPT_REQ_STRING }
220};
221
222/** The test handle. */
223static RTTEST g_hTest;
224/** The driver instance data. */
225PDMDRVINS g_DrvIns;
226/** The current verbosity level. */
227unsigned g_uVerbosity = 0;
228
229/*********************************************************************************************************************************
230* Test callbacks *
231*********************************************************************************************************************************/
232
233/**
234 * Setup callback for playing an output tone.
235 *
236 * @copydoc FNAUDIOTESTSETUP
237 */
238static DECLCALLBACK(int) audioTestPlayToneSetup(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx)
239{
240 RT_NOREF(pTstEnv, pTstDesc, pTstParmsAcq, ppvCtx);
241
242// PDMAudioPropsInit(&Props, 16 /* bit */ / 8, true /* fSigned */, 2 /* Channels */, 44100 /* Hz */);
243
244 //AudioTestToneParamsInitRandom(&pTstParms->ToneParms, &pTstParms->ToneParms.Props);
245
246 return VINF_SUCCESS;
247}
248
249static DECLCALLBACK(int) audioTestPlayToneExec(PAUDIOTESTENV pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms)
250{
251 RT_NOREF(pTstEnv, pvCtx, pTstParms);
252
253 return VINF_SUCCESS;
254}
255
256static DECLCALLBACK(int) audioTestPlayToneDestroy(PAUDIOTESTENV pTstEnv, void *pvCtx)
257{
258 RT_NOREF(pTstEnv, pvCtx);
259
260 return VINF_SUCCESS;
261}
262
263
264/*********************************************************************************************************************************
265* Implementation *
266*********************************************************************************************************************************/
267
268/**
269 * Initializes an audio test environment.
270 *
271 * @param pTstEnv Audio test environment to initialize.
272 * @param pDrvAudio Audio driver to use.
273 * @param pszPathOut Output path to use. If NULL, the system's temp directory will be used.
274 * @þaram pszTag Tag name to use. If NULL, a generated UUID will be used.
275 */
276static int audioTestEnvInit(PAUDIOTESTENV pTstEnv, PPDMIHOSTAUDIO pDrvAudio, const char *pszPathOut, const char *pszTag)
277{
278 RT_BZERO(pTstEnv, sizeof(AUDIOTESTENV));
279
280 pTstEnv->pDrvAudio = pDrvAudio;
281 PDMAudioHostEnumInit(&pTstEnv->DevEnm);
282
283 return AudioTestSetCreate(&pTstEnv->Set, pszPathOut, pszTag);
284}
285
286/**
287 * Destroys an audio test environment.
288 *
289 * @param pTstEnv Audio test environment to destroy.
290 */
291static void audioTestEnvDestroy(PAUDIOTESTENV pTstEnv)
292{
293 if (!pTstEnv)
294 return;
295
296 PDMAudioHostEnumDelete(&pTstEnv->DevEnm);
297
298 AudioTestSetDestroy(&pTstEnv->Set);
299}
300
301/**
302 * Initializes an audio test parameters set.
303 *
304 * @param pTstParms Test parameters set to initialize.
305 */
306static void audioTestParmsInit(PAUDIOTESTPARMS pTstParms)
307{
308 RT_BZERO(pTstParms, sizeof(AUDIOTESTPARMS));
309
310 return;
311}
312
313/**
314 * Destroys an audio test parameters set.
315 *
316 * @param pTstParms Test parameters set to destroy.
317 */
318static void audioTestParmsDestroy(PAUDIOTESTPARMS pTstParms)
319{
320 if (!pTstParms)
321 return;
322
323 return;
324}
325
326static AUDIOTESTDESC g_aTests[] =
327{
328 /* pszTest fExcluded pfnSetup */
329 { "PlayTone", false, audioTestPlayToneSetup, audioTestPlayToneExec, audioTestPlayToneDestroy }
330};
331
332
333/**
334 * Shows the application logo.
335 *
336 * @param pStream Output stream to show logo on.
337 */
338void showLogo(PRTSTREAM pStream)
339{
340 static bool s_fLogoShown = false; /* Show logo only once. */
341
342 if (!s_fLogoShown)
343 {
344 RTStrmPrintf(pStream, VBOX_PRODUCT " VKAT (Validation Kit Audio Test) "
345 VBOX_VERSION_STRING " - r%s\n"
346 "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
347 "All rights reserved.\n\n", RTBldCfgRevisionStr());
348 s_fLogoShown = true;
349 }
350}
351
352/**
353 * Shows tool usage text.
354 */
355static void audioTestUsage(PRTSTREAM pStrm)
356{
357 char szExec[RTPATH_MAX];
358 RTStrmPrintf(pStrm, "usage: %s [options]\n",
359 RTPathFilename(RTProcGetExecutablePath(szExec, sizeof(szExec))));
360 RTStrmPrintf(pStrm, "\n");
361 RTStrmPrintf(pStrm, "options: \n");
362
363 for (unsigned i = 0; i < RT_ELEMENTS(g_aCmdTestOptions); i++)
364 {
365 const char *pszHelp;
366 switch (g_aCmdTestOptions[i].iShort)
367 {
368 case 'h':
369 pszHelp = "Displays this help and exit";
370 break;
371 case 'd':
372 pszHelp = "Use the specified audio device";
373 break;
374 case 'e':
375 pszHelp = "Exclude the given test id from the list";
376 break;
377 case 'a':
378 pszHelp = "Exclude all tests from the list (useful to enable single tests later with --include)";
379 break;
380 case 'i':
381 pszHelp = "Include the given test id in the list";
382 break;
383 default:
384 pszHelp = "Option undocumented";
385 break;
386 }
387 char szOpt[256];
388 RTStrPrintf(szOpt, sizeof(szOpt), "%s, -%c", g_aCmdTestOptions[i].pszLong, g_aCmdTestOptions[i].iShort);
389 RTStrmPrintf(pStrm, " %-30s%s\n", szOpt, pszHelp);
390 }
391
392 /** @todo Add all other options. */
393}
394
395/**
396 * Constructs a PDM audio driver instance.
397 *
398 * @returns VBox status code.
399 * @param pDrvReg PDM driver registration record to use for construction.
400 * @param pDrvIns Driver instance to use for construction.
401 * @param ppDrvAudio Where to return the audio driver interface of type IHOSTAUDIO.
402 */
403static int audioTestDrvConstruct(const PDMDRVREG *pDrvReg, PPDMDRVINS pDrvIns, PPDMIHOSTAUDIO *ppDrvAudio)
404{
405 AssertReturn(pDrvReg->cbInstance, VERR_INVALID_PARAMETER); /** @todo Very crude; improve. */
406
407 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Initializing backend '%s' ...\n", pDrvReg->szName);
408
409 pDrvIns->pvInstanceData = RTMemAllocZ(pDrvReg->cbInstance);
410 AssertPtrReturn(pDrvIns->pvInstanceData, VERR_NO_MEMORY);
411
412 int rc = pDrvReg->pfnConstruct(pDrvIns, NULL /* PCFGMNODE */, 0 /* fFlags */);
413 if (RT_SUCCESS(rc))
414 {
415 PPDMIHOSTAUDIO pDrvAudio = (PPDMIHOSTAUDIO)pDrvIns->IBase.pfnQueryInterface(&pDrvIns->IBase, PDMIHOSTAUDIO_IID);
416
417 pDrvAudio->pfnGetStatus(pDrvAudio, PDMAUDIODIR_OUT);
418
419 *ppDrvAudio = pDrvAudio;
420 }
421
422 return rc;
423}
424
425/**
426 * Destructs a PDM audio driver instance.
427 *
428 * @returns VBox status code.
429 * @param pDrvReg PDM driver registration record to destruct.
430 * @param pDrvIns Driver instance to destruct.
431 */
432static int audioTestDrvDestruct(const PDMDRVREG *pDrvReg, PPDMDRVINS pDrvIns)
433{
434 if (!pDrvIns)
435 return VINF_SUCCESS;
436
437 if (pDrvReg->pfnDestruct)
438 pDrvReg->pfnDestruct(pDrvIns);
439
440 if (pDrvIns->pvInstanceData)
441 {
442 RTMemFree(pDrvIns->pvInstanceData);
443 pDrvIns->pvInstanceData = NULL;
444 }
445
446 return VINF_SUCCESS;
447}
448
449/**
450 * Enumerates audio devices and optionally searches for a specific device.
451 *
452 * @returns VBox status code.
453 * @param pTstEnv Test env to use for enumeration.
454 * @param pszDev Device name to search for. Can be NULL if the default device shall be used.
455 * @param ppDev Where to return the pointer of the device enumeration of \a pTstEnv when a
456 * specific device was found.
457 */
458static int audioTestDevicesEnumerateAndCheck(PAUDIOTESTENV pTstEnv, const char *pszDev, PPDMAUDIOHOSTDEV *ppDev)
459{
460 RTTestSubF(g_hTest, "Enumerating audio devices and checking for device '%s'", pszDev ? pszDev : "<Default>");
461
462 if (!pTstEnv->pDrvAudio->pfnGetDevices)
463 {
464 RTTestSkipped(g_hTest, "Backend does not support device enumeration, skipping");
465 return VINF_NOT_SUPPORTED;
466 }
467
468 Assert(pszDev == NULL || ppDev);
469
470 if (ppDev)
471 *ppDev = NULL;
472
473 int rc = pTstEnv->pDrvAudio->pfnGetDevices(pTstEnv->pDrvAudio, &pTstEnv->DevEnm);
474 if (RT_SUCCESS(rc))
475 {
476 PPDMAUDIOHOSTDEV pDev;
477 RTListForEach(&pTstEnv->DevEnm.LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry)
478 {
479 char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN];
480 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum: Device '%s':\n", pDev->szName);
481 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum: Usage = %s\n", PDMAudioDirGetName(pDev->enmUsage));
482 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum: Flags = %s\n", PDMAudioHostDevFlagsToString(szFlags, pDev->fFlags));
483 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum: Input channels = %RU8\n", pDev->cMaxInputChannels);
484 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Enum: Output channels = %RU8\n", pDev->cMaxOutputChannels);
485
486 if ( pszDev
487 && !RTStrCmp(pDev->szName, pszDev))
488 {
489 *ppDev = pDev;
490 }
491 }
492 }
493 else
494 RTTestFailed(g_hTest, "Enumerating audio devices failed with %Rrc", rc);
495
496 RTTestSubDone(g_hTest);
497
498 if ( pszDev
499 && *ppDev == NULL)
500 {
501 RTTestFailed(g_hTest, "Audio device '%s' not found", pszDev);
502 return VERR_NOT_FOUND;
503 }
504
505 return VINF_SUCCESS;
506}
507
508/**
509 * Opens an audio device.
510 *
511 * @returns VBox status code.
512 * @param pDev Audio device to open.
513 */
514static int audioTestDeviceOpen(PPDMAUDIOHOSTDEV pDev)
515{
516 int rc = VINF_SUCCESS;
517
518 RTTestSubF(g_hTest, "Opening audio device '%s' ...", pDev->szName);
519
520 /** @todo Detect + open device here. */
521
522 RTTestSubDone(g_hTest);
523
524 return rc;
525}
526
527/**
528 * Closes an audio device.
529 *
530 * @returns VBox status code.
531 * @param pDev Audio device to close.
532 */
533static int audioTestDeviceClose(PPDMAUDIOHOSTDEV pDev)
534{
535 int rc = VINF_SUCCESS;
536
537 RTTestSubF(g_hTest, "Closing audio device '%s' ...", pDev->szName);
538
539 /** @todo Close device here. */
540
541 RTTestSubDone(g_hTest);
542
543 return rc;
544}
545
546/**
547 * Overrides audio test base parameters with another set.
548 *
549 * @returns VBox status code.
550 * @param pBaseParms Base parameters to override.
551 * @param pOverrideParms Override parameters to use for overriding the base parameters.
552 *
553 * @note Overriding a parameter depends on its type / default values.
554 */
555static int audioTestCombineParms(PAUDIOTESTPARMS pBaseParms, PAUDIOTESTPARMS pOverrideParms)
556{
557 RT_NOREF(pBaseParms, pOverrideParms);
558
559 /** @todo Implement parameter overriding. */
560 return VERR_NOT_IMPLEMENTED;
561}
562
563/**
564 * Runs one specific audio test.
565 *
566 * @returns VBox status code.
567 * @param pTstEnv Test environment to use for running the test.
568 * @param pTstDesc Test to run.
569 * @param uSeq Test sequence # in case there are more tests.
570 * @param pOverrideParms Test parameters for overriding the actual test parameters. Optional.
571 */
572static int audioTestOne(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc,
573 unsigned uSeq, PAUDIOTESTPARMS pOverrideParms)
574{
575 RT_NOREF(uSeq);
576
577 int rc;
578
579 AUDIOTESTPARMS TstParms;
580 audioTestParmsInit(&TstParms);
581
582 RTTestSub(g_hTest, pTstDesc->pszName);
583
584 if (pTstDesc->fExcluded)
585 {
586 RTTestSkipped(g_hTest, "Excluded from list");
587 return VINF_SUCCESS;
588 }
589
590 void *pvCtx = NULL; /* Test-specific opaque context. Optional and can be NULL. */
591
592 if (pTstDesc->pfnSetup)
593 {
594 rc = pTstDesc->pfnSetup(pTstEnv, pTstDesc, &TstParms, &pvCtx);
595 if (RT_FAILURE(rc))
596 return rc;
597 }
598
599 audioTestCombineParms(&TstParms, pOverrideParms);
600
601 if (strlen(TstParms.Dev.szName)) /** @todo Refine this check. */
602 rc = audioTestDeviceOpen(&TstParms.Dev);
603
604 AssertPtr(pTstDesc->pfnExec);
605 rc = pTstDesc->pfnExec(pTstEnv, pvCtx, &TstParms);
606
607 RTTestSubDone(g_hTest);
608
609 if (pTstDesc->pfnDestroy)
610 {
611 int rc2 = pTstDesc->pfnDestroy(pTstEnv, pvCtx);
612 if (RT_SUCCESS(rc))
613 rc = rc2;
614 }
615
616 rc = audioTestDeviceClose(&TstParms.Dev);
617
618 audioTestParmsDestroy(&TstParms);
619
620 return rc;
621}
622
623/**
624 * Runs all specified tests in a row.
625 *
626 * @returns VBox status code.
627 * @param pTstEnv Test environment to use for running all tests.
628 * @param pOverrideParms Test parameters for (some / all) specific test parameters. Optional.
629 */
630static int audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms)
631{
632 int rc = VINF_SUCCESS;
633
634 unsigned uSeq = 0;
635 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
636 {
637 int rc2 = audioTestOne(pTstEnv, &g_aTests[i], uSeq, pOverrideParms);
638 if (RT_SUCCESS(rc))
639 rc = rc2;
640
641 if (!g_aTests[i].fExcluded)
642 uSeq++;
643 }
644
645 return rc;
646}
647
648/**
649 * Main (entry) function for the testing functionality of VKAT.
650 *
651 * @returns RTEXITCODE
652 * @param argc Number of argv arguments.
653 * @param argv argv arguments.
654 */
655int audioTestMain(int argc, char **argv)
656{
657 int rc;
658
659 AUDIOTESTPARMS TstCust;
660 audioTestParmsInit(&TstCust);
661
662 char *pszDevice = NULL; /* Custom device to use. Can be NULL if not being used. */
663 char *pszPathOut = NULL; /* Custom output path to use. Can be NULL if not being used. */
664 char *pszTag = NULL; /* Custom tag to use. Can be NULL if not being used. */
665
666 RT_ZERO(g_DrvIns);
667 const PDMDRVREG *pDrvReg = NULL;
668
669 RTGETOPTUNION ValueUnion;
670 RTGETOPTSTATE GetState;
671 rc = RTGetOptInit(&GetState, argc, argv, g_aCmdTestOptions, RT_ELEMENTS(g_aCmdTestOptions), 0, 0 /* fFlags */);
672 AssertRCReturn(rc, RTEXITCODE_INIT);
673
674 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
675 {
676 switch (rc)
677 {
678 case 'h':
679 {
680 audioTestUsage(g_pStdOut);
681 return RTEXITCODE_SUCCESS;
682 }
683
684 case 'e':
685 {
686 if (ValueUnion.u32 < RT_ELEMENTS(g_aTests))
687 g_aTests[ValueUnion.u32].fExcluded = true;
688 else
689 {
690 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Invalid test number passed to --exclude\n");
691 RTTestErrorInc(g_hTest);
692 return RTGetOptPrintError(VERR_INVALID_PARAMETER, &ValueUnion);
693 }
694 break;
695 }
696
697 case 'a':
698 {
699 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
700 g_aTests[i].fExcluded = true;
701 break;
702 }
703
704 case 'b':
705 {
706#ifdef VBOX_WITH_AUDIO_PULSE
707 if ( !RTStrICmp(ValueUnion.psz, "pulseaudio")
708 || !RTStrICmp(ValueUnion.psz, "pa"))
709 pDrvReg = &g_DrvHostPulseAudio;
710#endif
711#ifdef VBOX_WITH_AUDIO_ALSA
712 if ( !RTStrICmp(ValueUnion.psz, "alsa"))
713 pDrvReg = &g_DrvHostALSAAudio;
714#endif
715#ifdef VBOX_WITH_AUDIO_OSS
716 if ( !RTStrICmp(ValueUnion.psz, "oss"))
717 pDrvReg = &g_DrvHostOSSAudio;
718#endif
719#if defined(RT_OS_DARWIN)
720 if ( !RTStrICmp(ValueUnion.psz, "coreaudio"))
721 pDrvReg = &g_DrvHostCoreAudio;
722#endif
723#if defined(RT_OS_WINDOWS)
724 if ( !RTStrICmp(ValueUnion.psz, "wasapi"))
725 pDrvReg = &g_DrvHostAudioWas;
726 else if ( !RTStrICmp(ValueUnion.psz, "directsound")
727 || !RTStrICmp(ValueUnion.psz, "dsound")
728 pDrvReg = &g_DrvHostDSound;
729#endif
730 if (pDrvReg == NULL)
731 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid / unsupported backend '%s' specified\n", ValueUnion.psz);
732 break;
733 }
734
735 case 'i':
736 {
737 if (ValueUnion.u32 < RT_ELEMENTS(g_aTests))
738 g_aTests[ValueUnion.u32].fExcluded = false;
739 else
740 {
741 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Invalid test number passed to --include\n");
742 RTTestErrorInc(g_hTest);
743 return RTGetOptPrintError(VERR_INVALID_PARAMETER, &ValueUnion);
744 }
745 break;
746 }
747
748 case VKAT_TEST_OPT_COUNT:
749 {
750 break;
751 }
752
753 case VKAT_TEST_OPT_DEV:
754 {
755 pszDevice = RTStrDup(ValueUnion.psz);
756 break;
757 }
758
759 case VKAT_TEST_OPT_PAUSE:
760 {
761 break;
762 }
763
764 case VKAT_TEST_OPT_OUTDIR:
765 {
766 pszPathOut = RTStrDup(ValueUnion.psz);
767 break;
768 }
769
770 case VKAT_TEST_OPT_PCM_BIT:
771 {
772 TstCust.ToneParms.Props.cbSampleX = ValueUnion.u8 / 8 /* bit */;
773 break;
774 }
775
776 case VKAT_TEST_OPT_PCM_CHAN:
777 {
778 TstCust.ToneParms.Props.cChannelsX = ValueUnion.u8;
779 break;
780 }
781
782 case VKAT_TEST_OPT_PCM_HZ:
783 {
784 TstCust.ToneParms.Props.uHz = ValueUnion.u32;
785 break;
786 }
787
788 case VKAT_TEST_OPT_PCM_SIGNED:
789 {
790 TstCust.ToneParms.Props.fSigned = ValueUnion.f;
791 break;
792 }
793
794 case VKAT_TEST_OPT_TAG:
795 {
796 pszTag = RTStrDup(ValueUnion.psz);
797 break;
798 }
799
800 case VKAT_TEST_OPT_VOL:
801 {
802 TstCust.ToneParms.uVolumePercent = ValueUnion.u8;
803 break;
804 }
805
806 default:
807 break;
808 }
809 }
810
811 /*
812 * Start testing.
813 */
814 RTTestBanner(g_hTest);
815
816 /* If no backend is specified, go with the default backend for that OS. */
817 if (pDrvReg == NULL)
818#if defined(RT_OS_WINDOWS)
819 pDrvReg = &g_DrvHostAudioWas;
820#elif defined(RT_OS_DARWIN)
821 pDrvReg = &g_DrvHostCoreAudio;
822#elif defined(RT_OS_SOLARIS)
823 pDrvReg = &g_DrvHostOSSAudio;
824#else
825 pDrvReg = &g_DrvHostALSAAudio;
826#endif
827
828 PPDMIHOSTAUDIO pDrvAudio;
829 rc = audioTestDrvConstruct(pDrvReg, &g_DrvIns, &pDrvAudio);
830 if (RT_SUCCESS(rc))
831 {
832 /* For now all tests have the same test environment. */
833 AUDIOTESTENV TstEnv;
834 rc = audioTestEnvInit(&TstEnv, pDrvAudio, pszPathOut, pszTag);
835 if (RT_SUCCESS(rc))
836 {
837 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Output directory is '%s'\n", TstEnv.Set.szPathOutAbs);
838
839 PPDMAUDIOHOSTDEV pDev;
840 rc = audioTestDevicesEnumerateAndCheck(&TstEnv, pszDevice, &pDev);
841 if (RT_SUCCESS(rc))
842 audioTestWorker(&TstEnv, &TstCust);
843
844 audioTestEnvDestroy(&TstEnv);
845 }
846 audioTestDrvDestruct(pDrvReg, &g_DrvIns);
847 }
848
849 audioTestParmsDestroy(&TstCust);
850
851 RTStrFree(pszDevice);
852 RTStrFree(pszPathOut);
853 RTStrFree(pszTag);
854
855 /*
856 * Print summary and exit.
857 */
858 return RTTestSummaryAndDestroy(g_hTest);
859}
860
861/**
862 * Verifies one single test set.
863 *
864 * @returns VBox status code.
865 * @param pszPath Absolute path to test set.
866 * @param pszTag Tag of test set to verify. Optional and can be NULL.
867 */
868int audioVerifyOne(const char *pszPath, const char *pszTag)
869{
870 RTTestSubF(g_hTest, "Verifying test set (tag '%s') ...", pszTag ? pszTag : "<Default>");
871
872 AUDIOTESTSET tstSet;
873 int rc = AudioTestSetOpen(&tstSet, pszPath);
874 if (RT_SUCCESS(rc))
875 {
876 rc = AudioTestSetVerify(&tstSet, pszTag);
877 if (RT_SUCCESS(rc))
878 {
879 RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Verification successful");
880 }
881 else
882 RTTestFailed(g_hTest, "Verification failed with %Rrc", rc);
883
884 AudioTestSetClose(&tstSet);
885 }
886 else
887 RTTestFailed(g_hTest, "Opening test set '%s' (tag '%s') failed, rc=%Rrc\n", pszPath, pszTag, rc);
888
889 RTTestSubDone(g_hTest);
890
891 return rc;
892}
893
894/**
895 * Main (entry) function for the verification functionality of VKAT.
896 *
897 * @returns RTEXITCODE
898 * @param argc Number of argv arguments.
899 * @param argv argv arguments.
900 */
901int audioVerifyMain(int argc, char **argv)
902{
903 char *pszTag = NULL; /* Custom tag to use. Can be NULL if not being used. */
904
905 char szDirCur[RTPATH_MAX];
906 int rc = RTPathGetCurrent(szDirCur, sizeof(szDirCur));
907 if (RT_FAILURE(rc))
908 {
909 RTMsgError("Getting current directory failed, rc=%Rrc\n", rc);
910 return RTEXITCODE_FAILURE;
911 }
912
913 /*
914 * Process common options.
915 */
916 RTGETOPTUNION ValueUnion;
917 RTGETOPTSTATE GetState;
918 rc = RTGetOptInit(&GetState, argc, argv, g_aCmdVerifyOptions, RT_ELEMENTS(g_aCmdVerifyOptions),
919 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
920 AssertRCReturn(rc, RTEXITCODE_INIT);
921
922 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
923 {
924 switch (rc)
925 {
926 case VKAT_VERIFY_OPT_TAG:
927 {
928 pszTag = RTStrDup(ValueUnion.psz);
929 break;
930 }
931
932 case VINF_GETOPT_NOT_OPTION:
933 {
934 Assert(GetState.iNext);
935 GetState.iNext--;
936 break;
937 }
938
939 default:
940 return RTGetOptPrintError(rc, &ValueUnion);
941 }
942
943 /* All flags / options processed? Bail out here.
944 * Processing the file / directory list comes down below. */
945 if (rc == VINF_GETOPT_NOT_OPTION)
946 break;
947 }
948
949 if (pszTag)
950 RTMsgInfo("Using tag '%s'\n", pszTag);
951
952 /*
953 * Start testing.
954 */
955 RTTestBanner(g_hTest);
956
957 /*
958 * Deal with test sets.
959 */
960 rc = RTGetOpt(&GetState, &ValueUnion);
961 do
962 {
963 char const *pszPath;
964
965 if (rc == 0) /* Use current directory if no element specified. */
966 pszPath = szDirCur;
967 else
968 pszPath = ValueUnion.psz;
969
970 RTFSOBJINFO objInfo;
971 rc = RTPathQueryInfoEx(pszPath, &objInfo,
972 RTFSOBJATTRADD_UNIX, RTPATH_F_FOLLOW_LINK);
973 if (RT_SUCCESS(rc))
974 {
975 rc = audioVerifyOne(pszPath, pszTag);
976 }
977 else
978 RTTestFailed(g_hTest, "Cannot access path '%s', rc=%Rrc\n", pszPath, rc);
979
980 } while ((rc = RTGetOpt(&GetState, &ValueUnion)) != 0);
981
982 RTStrFree(pszTag);
983
984 /*
985 * Print summary and exit.
986 */
987 return RTTestSummaryAndDestroy(g_hTest);
988}
989
990int main(int argc, char **argv)
991{
992 /*
993 * Init IPRT and globals.
994 */
995 int rc = RTTestInitAndCreate("AudioTest", &g_hTest);
996 if (rc)
997 return rc;
998
999 AssertReturn(argc > 0, false);
1000
1001 /* At least the operation mode must be there. */
1002 if (argc < 2)
1003 {
1004 audioTestUsage(g_pStdOut);
1005 return RTEXITCODE_SYNTAX;
1006 }
1007
1008 /*
1009 * Process common options.
1010 */
1011 RTGETOPTUNION ValueUnion;
1012 RTGETOPTSTATE GetState;
1013 rc = RTGetOptInit(&GetState, argc, argv, g_aCmdCommonOptions, RT_ELEMENTS(g_aCmdCommonOptions), 1 /* idxFirst */, 0 /* fFlags */);
1014 AssertRCReturn(rc, RTEXITCODE_INIT);
1015
1016 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
1017 {
1018 switch (rc)
1019 {
1020 case 'h':
1021 {
1022 showLogo(g_pStdOut);
1023 audioTestUsage(g_pStdOut);
1024 return RTEXITCODE_SUCCESS;
1025 }
1026
1027 case 'v':
1028 {
1029 g_uVerbosity++;
1030 break;
1031 }
1032
1033 case VINF_GETOPT_NOT_OPTION:
1034 {
1035 Assert(GetState.iNext);
1036 GetState.iNext--;
1037 }
1038
1039 default:
1040 /* Ignore everything else here. */
1041 break;
1042 }
1043
1044 /* All flags / options processed? Bail out here.
1045 * Processing the file / directory list comes down below. */
1046 if (rc == VINF_GETOPT_NOT_OPTION)
1047 break;
1048 }
1049
1050 showLogo(g_pStdOut);
1051
1052 /* Get operation mode. */
1053 const char *pszMode = argv[GetState.iNext++]; /** @todo Also do it busybox-like? */
1054
1055 argv += GetState.iNext;
1056 Assert(argc >= GetState.iNext);
1057 argc -= GetState.iNext;
1058
1059 if (!RTStrICmp(pszMode, "test"))
1060 {
1061 return audioTestMain(argc, argv);
1062 }
1063 else if (!RTStrICmp(pszMode, "verify"))
1064 {
1065 return audioVerifyMain(argc, argv);
1066 }
1067
1068 RTStrmPrintf(g_pStdOut, "Must specify a mode first, either 'test' or 'verify'\n\n");
1069
1070 audioTestUsage(g_pStdOut);
1071 return RTEXITCODE_SYNTAX;
1072}
1073
Note: See TracBrowser for help on using the repository browser.

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