VirtualBox

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

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

Audio/ValKit: More code for command line / test set handling in VKAT. bugref:10008

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