Changeset 89544 in vbox for trunk/src/VBox/ValidationKit
- Timestamp:
- Jun 7, 2021 11:06:40 AM (4 years ago)
- Location:
- trunk/src/VBox/ValidationKit/utils/audio
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/utils/audio/Makefile.kmk
r89403 r89544 55 55 vkat_SOURCES = \ 56 56 vkat.cpp \ 57 vkatCommon.cpp \ 58 vkatCmdPlayRec.cpp \ 57 59 vkatDriverStack.cpp \ 58 60 $(VKAT_PATH_AUDIO)/AudioTest.cpp \ … … 67 69 vkat_DEFS += VBOX_WITH_AUDIO_VALIDATIONKIT 68 70 vkat_SOURCES += \ 71 vkatCmdSelfTest.cpp \ 69 72 $(VKAT_PATH_AUDIO)/DrvHostAudioValidationKit.cpp \ 70 73 $(VKAT_PATH_AUDIO)/AudioTestService.cpp \ -
trunk/src/VBox/ValidationKit/utils/audio/vkat.cpp
r89541 r89544 111 111 112 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 113 250 114 /********************************************************************************************************************************* … … 252 116 *********************************************************************************************************************************/ 253 117 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 118 static RTEXITCODE audioTestUsage(PRTSTREAM pStrm); 261 119 static RTEXITCODE audioTestVersion(void); … … 359 217 }; 360 218 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 219 /** Terminate ASAP if set. Set on Ctrl-C. */ 404 staticbool volatile g_fTerminate = false;220 bool volatile g_fTerminate = false; 405 221 /** The release logger. */ 406 static PRTLOGGER g_pRelLogger = NULL; 407 408 222 PRTLOGGER g_pRelLogger = NULL; 409 223 /** The test handle. */ 410 RTTEST g_hTest;224 RTTEST g_hTest; 411 225 /** The current verbosity level. */ 412 unsigned g_uVerbosity = 0;226 unsigned g_uVerbosity = 0; 413 227 /** DrvAudio: Enable debug (or not). */ 414 bool g_fDrvAudioDebug = 0;228 bool g_fDrvAudioDebug = 0; 415 229 /** DrvAudio: The debug output path. */ 416 const char *g_pszDrvAudioDebug = NULL;230 const char *g_pszDrvAudioDebug = NULL; 417 231 418 232 … … 424 238 * @param pszBackend The backend option value. 425 239 */ 426 staticPCPDMDRVREG audioTestFindBackendOpt(const char *pszBackend)240 PCPDMDRVREG audioTestFindBackendOpt(const char *pszBackend) 427 241 { 428 242 for (uintptr_t i = 0; i < RT_ELEMENTS(g_aBackends); i++) … … 434 248 } 435 249 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 250 1063 251 /** … … 1341 529 * @param pOverrideParms Test parameters for (some / all) specific test parameters. Optional. 1342 530 */ 1343 staticint audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms)531 int audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms) 1344 532 { 1345 533 int rc = VINF_SUCCESS; … … 1862 1050 } 1863 1051 1864 1865 /*********************************************************************************************************************************1866 * Command: play *1867 *********************************************************************************************************************************/1868 1869 /**1870 * Worker for audioTestPlayOne implementing the play loop.1871 */1872 static RTEXITCODE audioTestPlayOneInner(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTWAVEFILE pWaveFile,1873 PCPDMAUDIOSTREAMCFG pCfgAcq, const char *pszFile)1874 {1875 uint32_t const cbPreBuffer = PDMAudioPropsFramesToBytes(pMix->pProps, pCfgAcq->Backend.cFramesPreBuffering);1876 uint64_t const nsStarted = RTTimeNanoTS();1877 uint64_t nsDonePreBuffering = 0;1878 1879 /*1880 * Transfer data as quickly as we're allowed.1881 */1882 uint8_t abSamples[16384];1883 uint32_t const cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples));1884 uint64_t offStream = 0;1885 while (!g_fTerminate)1886 {1887 /* Read a chunk from the wave file. */1888 size_t cbSamples = 0;1889 int rc = AudioTestWaveFileRead(pWaveFile, abSamples, cbSamplesAligned, &cbSamples);1890 if (RT_SUCCESS(rc) && cbSamples > 0)1891 {1892 /* Pace ourselves a little. */1893 if (offStream >= cbPreBuffer)1894 {1895 if (!nsDonePreBuffering)1896 nsDonePreBuffering = RTTimeNanoTS();1897 uint64_t const cNsWritten = PDMAudioPropsBytesToNano64(pMix->pProps, offStream - cbPreBuffer);1898 uint64_t const cNsElapsed = RTTimeNanoTS() - nsStarted;1899 if (cNsWritten > cNsElapsed + RT_NS_10MS)1900 RTThreadSleep((cNsWritten - cNsElapsed - RT_NS_10MS / 2) / RT_NS_1MS);1901 }1902 1903 /* Transfer the data to the audio stream. */1904 for (uint32_t offSamples = 0; offSamples < cbSamples;)1905 {1906 uint32_t const cbCanWrite = AudioTestMixStreamGetWritable(pMix);1907 if (cbCanWrite > 0)1908 {1909 uint32_t const cbToPlay = RT_MIN(cbCanWrite, (uint32_t)cbSamples - offSamples);1910 uint32_t cbPlayed = 0;1911 rc = AudioTestMixStreamPlay(pMix, &abSamples[offSamples], cbToPlay, &cbPlayed);1912 if (RT_SUCCESS(rc))1913 {1914 if (cbPlayed)1915 {1916 offSamples += cbPlayed;1917 offStream += cbPlayed;1918 }1919 else1920 return RTMsgErrorExitFailure("Played zero bytes - %#x bytes reported playable!\n", cbCanWrite);1921 }1922 else1923 return RTMsgErrorExitFailure("Failed to play %#x bytes: %Rrc\n", cbToPlay, rc);1924 }1925 else if (AudioTestMixStreamIsOkay(pMix))1926 RTThreadSleep(RT_MIN(RT_MAX(1, pCfgAcq->Device.cMsSchedulingHint), 256));1927 else1928 return RTMsgErrorExitFailure("Stream is not okay!\n");1929 }1930 }1931 else if (RT_SUCCESS(rc) && cbSamples == 0)1932 break;1933 else1934 return RTMsgErrorExitFailure("Error reading wav file '%s': %Rrc", pszFile, rc);1935 }1936 1937 /*1938 * Drain the stream.1939 */1940 if (g_uVerbosity > 0)1941 RTMsgInfo("%'RU64 ns: Draining...\n", RTTimeNanoTS() - nsStarted);1942 int rc = AudioTestMixStreamDrain(pMix, true /*fSync*/);1943 if (RT_SUCCESS(rc))1944 {1945 if (g_uVerbosity > 0)1946 RTMsgInfo("%'RU64 ns: Done\n", RTTimeNanoTS() - nsStarted);1947 }1948 else1949 return RTMsgErrorExitFailure("Draining failed: %Rrc", rc);1950 1951 return RTEXITCODE_SUCCESS;1952 }1953 1954 1955 /**1956 * Worker for audioTestCmdPlayHandler that plays one file.1957 */1958 static RTEXITCODE audioTestPlayOne(const char *pszFile, PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,1959 uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,1960 uint8_t cChannels, uint8_t cbSample, uint32_t uHz,1961 bool fWithDrvAudio, bool fWithMixer)1962 {1963 char szTmp[128];1964 1965 /*1966 * First we must open the file and determin the format.1967 */1968 RTERRINFOSTATIC ErrInfo;1969 AUDIOTESTWAVEFILE WaveFile;1970 int rc = AudioTestWaveFileOpen(pszFile, &WaveFile, RTErrInfoInitStatic(&ErrInfo));1971 if (RT_FAILURE(rc))1972 return RTMsgErrorExitFailure("Failed to open '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core);1973 1974 if (g_uVerbosity > 0)1975 {1976 RTMsgInfo("Opened '%s' for playing\n", pszFile);1977 RTMsgInfo("Format: %s\n", PDMAudioPropsToString(&WaveFile.Props, szTmp, sizeof(szTmp)));1978 RTMsgInfo("Size: %'RU32 bytes / %#RX32 / %'RU32 frames / %'RU64 ns\n",1979 WaveFile.cbSamples, WaveFile.cbSamples,1980 PDMAudioPropsBytesToFrames(&WaveFile.Props, WaveFile.cbSamples),1981 PDMAudioPropsBytesToNano(&WaveFile.Props, WaveFile.cbSamples));1982 }1983 1984 /*1985 * Construct the driver stack.1986 */1987 RTEXITCODE rcExit = RTEXITCODE_FAILURE;1988 AUDIOTESTDRVSTACK DrvStack;1989 rc = audioTestDriverStackInit(&DrvStack, pDrvReg, fWithDrvAudio);1990 if (RT_SUCCESS(rc))1991 {1992 /*1993 * Set the output device if one is specified.1994 */1995 rc = audioTestDriverStackSetDevice(&DrvStack, PDMAUDIODIR_OUT, pszDevId);1996 if (RT_SUCCESS(rc))1997 {1998 /*1999 * Open a stream for the output.2000 */2001 PDMAUDIOPCMPROPS ReqProps = WaveFile.Props;2002 if (cChannels != 0 && PDMAudioPropsChannels(&ReqProps) != cChannels)2003 PDMAudioPropsSetChannels(&ReqProps, cChannels);2004 if (cbSample != 0)2005 PDMAudioPropsSetSampleSize(&ReqProps, cbSample);2006 if (uHz != 0)2007 ReqProps.uHz = uHz;2008 2009 PDMAUDIOSTREAMCFG CfgAcq;2010 PPDMAUDIOSTREAM pStream = NULL;2011 rc = audioTestDriverStackStreamCreateOutput(&DrvStack, &ReqProps, cMsBufferSize,2012 cMsPreBuffer, cMsSchedulingHint, &pStream, &CfgAcq);2013 if (RT_SUCCESS(rc))2014 {2015 /*2016 * Automatically enable the mixer if the wave file and the2017 * output parameters doesn't match.2018 */2019 if ( !fWithMixer2020 && !PDMAudioPropsAreEqual(&WaveFile.Props, &pStream->Cfg.Props))2021 {2022 RTMsgInfo("Enabling the mixer buffer.\n");2023 fWithMixer = true;2024 }2025 2026 /*2027 * Create a mixer wrapper. This is just a thin wrapper if fWithMixer2028 * is false, otherwise it's doing mixing, resampling and recoding.2029 */2030 AUDIOTESTDRVMIXSTREAM Mix;2031 rc = AudioTestMixStreamInit(&Mix, &DrvStack, pStream, fWithMixer ? &WaveFile.Props : NULL, 100 /*ms*/);2032 if (RT_SUCCESS(rc))2033 {2034 if (g_uVerbosity > 0)2035 RTMsgInfo("Stream: %s cbBackend=%#RX32%s\n",2036 PDMAudioPropsToString(&pStream->Cfg.Props, szTmp, sizeof(szTmp)),2037 pStream->cbBackend, fWithMixer ? " mixed" : "");2038 2039 /*2040 * Enable the stream and start playing.2041 */2042 rc = AudioTestMixStreamEnable(&Mix);2043 if (RT_SUCCESS(rc))2044 rcExit = audioTestPlayOneInner(&Mix, &WaveFile, &CfgAcq, pszFile);2045 else2046 rcExit = RTMsgErrorExitFailure("Enabling the output stream failed: %Rrc", rc);2047 2048 /*2049 * Clean up.2050 */2051 AudioTestMixStreamTerm(&Mix);2052 }2053 audioTestDriverStackStreamDestroy(&DrvStack, pStream);2054 }2055 else2056 rcExit = RTMsgErrorExitFailure("Creating output stream failed: %Rrc", rc);2057 }2058 else2059 rcExit = RTMsgErrorExitFailure("Failed to set output device to '%s': %Rrc", pszDevId, rc);2060 audioTestDriverStackDelete(&DrvStack);2061 }2062 else2063 rcExit = RTMsgErrorExitFailure("Driver stack construction failed: %Rrc", rc);2064 AudioTestWaveFileClose(&WaveFile);2065 return rcExit;2066 }2067 2068 1052 /** 2069 1053 * Options for 'play'. … … 2176 1160 * Command: rec * 2177 1161 *********************************************************************************************************************************/ 2178 2179 /**2180 * Worker for audioTestRecOne implementing the recording loop.2181 */2182 static RTEXITCODE audioTestRecOneInner(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTWAVEFILE pWaveFile,2183 PCPDMAUDIOSTREAMCFG pCfgAcq, uint64_t cMaxFrames, const char *pszFile)2184 {2185 int rc;2186 uint64_t const nsStarted = RTTimeNanoTS();2187 2188 /*2189 * Transfer data as quickly as we're allowed.2190 */2191 uint8_t abSamples[16384];2192 uint32_t const cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples));2193 uint64_t cFramesCapturedTotal = 0;2194 while (!g_fTerminate && cFramesCapturedTotal < cMaxFrames)2195 {2196 /*2197 * Anything we can read?2198 */2199 uint32_t const cbCanRead = AudioTestMixStreamGetReadable(pMix);2200 if (cbCanRead)2201 {2202 uint32_t const cbToRead = RT_MIN(cbCanRead, cbSamplesAligned);2203 uint32_t cbCaptured = 0;2204 rc = AudioTestMixStreamCapture(pMix, abSamples, cbToRead, &cbCaptured);2205 if (RT_SUCCESS(rc))2206 {2207 if (cbCaptured)2208 {2209 uint32_t cFramesCaptured = PDMAudioPropsBytesToFrames(pMix->pProps, cbCaptured);2210 if (cFramesCaptured + cFramesCaptured < cMaxFrames)2211 { /* likely */ }2212 else2213 {2214 cFramesCaptured = cMaxFrames - cFramesCaptured;2215 cbCaptured = PDMAudioPropsFramesToBytes(pMix->pProps, cFramesCaptured);2216 }2217 2218 rc = AudioTestWaveFileWrite(pWaveFile, abSamples, cbCaptured);2219 if (RT_SUCCESS(rc))2220 cFramesCapturedTotal += cFramesCaptured;2221 else2222 return RTMsgErrorExitFailure("Error writing to '%s': %Rrc", pszFile, rc);2223 }2224 else2225 return RTMsgErrorExitFailure("Captured zero bytes - %#x bytes reported readable!\n", cbCanRead);2226 }2227 else2228 return RTMsgErrorExitFailure("Failed to capture %#x bytes: %Rrc (%#x available)\n", cbToRead, rc, cbCanRead);2229 }2230 else if (AudioTestMixStreamIsOkay(pMix))2231 RTThreadSleep(RT_MIN(RT_MAX(1, pCfgAcq->Device.cMsSchedulingHint), 256));2232 else2233 return RTMsgErrorExitFailure("Stream is not okay!\n");2234 }2235 2236 /*2237 * Disable the stream.2238 */2239 rc = AudioTestMixStreamDisable(pMix);2240 if (RT_SUCCESS(rc) && g_uVerbosity > 0)2241 RTMsgInfo("%'RU64 ns: Stopped after recording %RU64 frames%s\n", RTTimeNanoTS() - nsStarted, cFramesCapturedTotal,2242 g_fTerminate ? " - Ctrl-C" : ".");2243 else if (RT_FAILURE(rc))2244 return RTMsgErrorExitFailure("Disabling stream failed: %Rrc", rc);2245 2246 return RTEXITCODE_SUCCESS;2247 }2248 2249 2250 /**2251 * Worker for audioTestCmdRecHandler that recs one file.2252 */2253 static RTEXITCODE audioTestRecOne(const char *pszFile, uint8_t cWaveChannels, uint8_t cbWaveSample, uint32_t uWaveHz,2254 PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,2255 uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,2256 uint8_t cChannels, uint8_t cbSample, uint32_t uHz, bool fWithDrvAudio, bool fWithMixer,2257 uint64_t cMaxFrames, uint64_t cNsMaxDuration)2258 {2259 /*2260 * Construct the driver stack.2261 */2262 RTEXITCODE rcExit = RTEXITCODE_FAILURE;2263 AUDIOTESTDRVSTACK DrvStack;2264 int rc = audioTestDriverStackInit(&DrvStack, pDrvReg, fWithDrvAudio);2265 if (RT_SUCCESS(rc))2266 {2267 /*2268 * Set the input device if one is specified.2269 */2270 rc = audioTestDriverStackSetDevice(&DrvStack, PDMAUDIODIR_IN, pszDevId);2271 if (RT_SUCCESS(rc))2272 {2273 /*2274 * Create an input stream.2275 */2276 PDMAUDIOPCMPROPS ReqProps;2277 PDMAudioPropsInit(&ReqProps,2278 cbSample ? cbSample : cbWaveSample ? cbWaveSample : 2,2279 true /*fSigned*/,2280 cChannels ? cChannels : cWaveChannels ? cWaveChannels : 2,2281 uHz ? uHz : uWaveHz ? uWaveHz : 44100);2282 PDMAUDIOSTREAMCFG CfgAcq;2283 PPDMAUDIOSTREAM pStream = NULL;2284 rc = audioTestDriverStackStreamCreateInput(&DrvStack, &ReqProps, cMsBufferSize,2285 cMsPreBuffer, cMsSchedulingHint, &pStream, &CfgAcq);2286 if (RT_SUCCESS(rc))2287 {2288 /*2289 * Determine the wave file properties. If it differs from the stream2290 * properties, make sure the mixer is enabled.2291 */2292 PDMAUDIOPCMPROPS WaveProps;2293 PDMAudioPropsInit(&WaveProps,2294 cbWaveSample ? cbWaveSample : PDMAudioPropsSampleSize(&CfgAcq.Props),2295 true /*fSigned*/,2296 cWaveChannels ? cWaveChannels : PDMAudioPropsChannels(&CfgAcq.Props),2297 uWaveHz ? uWaveHz : PDMAudioPropsHz(&CfgAcq.Props));2298 if (!fWithMixer && !PDMAudioPropsAreEqual(&WaveProps, &CfgAcq.Props))2299 {2300 RTMsgInfo("Enabling the mixer buffer.\n");2301 fWithMixer = true;2302 }2303 2304 /* Console the max duration into frames now that we've got the wave file format. */2305 if (cMaxFrames != UINT64_MAX && cNsMaxDuration != UINT64_MAX)2306 {2307 uint64_t cMaxFrames2 = PDMAudioPropsNanoToBytes64(&WaveProps, cNsMaxDuration);2308 cMaxFrames = RT_MAX(cMaxFrames, cMaxFrames2);2309 }2310 else if (cNsMaxDuration != UINT64_MAX)2311 cMaxFrames = PDMAudioPropsNanoToBytes64(&WaveProps, cNsMaxDuration);2312 2313 /*2314 * Create a mixer wrapper. This is just a thin wrapper if fWithMixer2315 * is false, otherwise it's doing mixing, resampling and recoding.2316 */2317 AUDIOTESTDRVMIXSTREAM Mix;2318 rc = AudioTestMixStreamInit(&Mix, &DrvStack, pStream, fWithMixer ? &WaveProps : NULL, 100 /*ms*/);2319 if (RT_SUCCESS(rc))2320 {2321 char szTmp[128];2322 if (g_uVerbosity > 0)2323 RTMsgInfo("Stream: %s cbBackend=%#RX32%s\n",2324 PDMAudioPropsToString(&pStream->Cfg.Props, szTmp, sizeof(szTmp)),2325 pStream->cbBackend, fWithMixer ? " mixed" : "");2326 2327 /*2328 * Open the wave output file.2329 */2330 AUDIOTESTWAVEFILE WaveFile;2331 RTERRINFOSTATIC ErrInfo;2332 rc = AudioTestWaveFileCreate(pszFile, &WaveProps, &WaveFile, RTErrInfoInitStatic(&ErrInfo));2333 if (RT_SUCCESS(rc))2334 {2335 if (g_uVerbosity > 0)2336 {2337 RTMsgInfo("Opened '%s' for playing\n", pszFile);2338 RTMsgInfo("Format: %s\n", PDMAudioPropsToString(&WaveFile.Props, szTmp, sizeof(szTmp)));2339 }2340 2341 /*2342 * Enable the stream and start recording.2343 */2344 rc = AudioTestMixStreamEnable(&Mix);2345 if (RT_SUCCESS(rc))2346 rcExit = audioTestRecOneInner(&Mix, &WaveFile, &CfgAcq, cMaxFrames, pszFile);2347 else2348 rcExit = RTMsgErrorExitFailure("Enabling the input stream failed: %Rrc", rc);2349 if (rcExit != RTEXITCODE_SUCCESS)2350 AudioTestMixStreamDisable(&Mix);2351 2352 /*2353 * Clean up.2354 */2355 rc = AudioTestWaveFileClose(&WaveFile);2356 if (RT_FAILURE(rc))2357 rcExit = RTMsgErrorExitFailure("Error closing '%s': %Rrc", pszFile, rc);2358 }2359 else2360 rcExit = RTMsgErrorExitFailure("Failed to open '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core.pszMsg);2361 2362 AudioTestMixStreamTerm(&Mix);2363 }2364 audioTestDriverStackStreamDestroy(&DrvStack, pStream);2365 }2366 else2367 rcExit = RTMsgErrorExitFailure("Creating output stream failed: %Rrc", rc);2368 }2369 else2370 rcExit = RTMsgErrorExitFailure("Failed to set output device to '%s': %Rrc", pszDevId, rc);2371 audioTestDriverStackDelete(&DrvStack);2372 }2373 else2374 rcExit = RTMsgErrorExitFailure("Driver stack construction failed: %Rrc", rc);2375 return rcExit;2376 }2377 1162 2378 1163 /** … … 2540 1325 *********************************************************************************************************************************/ 2541 1326 2542 /** @todo Move this (all?) commands into separate files -- this file is too big already. */2543 2544 1327 /** 2545 1328 * Command line parameters for self-test mode. … … 2570 1353 2571 1354 /** 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 1355 * The 'selftest' command handler. 2751 1356 * … … 2753 1358 * @param pGetState RTGetOpt state. 2754 1359 */ 2755 staticDECLCALLBACK(RTEXITCODE) audioTestCmdSelftestHandler(PRTGETOPTSTATE pGetState)1360 DECLCALLBACK(RTEXITCODE) audioTestCmdSelftestHandler(PRTGETOPTSTATE pGetState) 2756 1361 { 2757 1362 SELFTESTCTX Ctx; … … 2790 1395 2791 1396 case 'b': 2792 {2793 1397 Ctx.Guest.pDrvReg = audioTestFindBackendOpt(ValueUnion.psz); 2794 1398 if (Ctx.Guest.pDrvReg == NULL) 2795 1399 return RTEXITCODE_SYNTAX; 2796 1400 break; 2797 }2798 1401 2799 1402 case 'd': -
trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h
r89490 r89544 31 31 #endif 32 32 33 #include <iprt/getopt.h> 34 33 35 #include <VBox/vmm/pdmdrv.h> 34 36 #include <VBox/vmm/pdmaudioinline.h> 35 37 #include <VBox/vmm/pdmaudiohostenuminline.h> 38 36 39 #include "Audio/AudioMixBuffer.h" 37 38 40 #include "Audio/AudioTest.h" 41 #include "Audio/AudioTestService.h" 42 #include "Audio/AudioTestServiceClient.h" 43 44 #include "VBoxDD.h" 45 46 47 /********************************************************************************************************************************* 48 * Externals * 49 *********************************************************************************************************************************/ 50 /** Terminate ASAP if set. Set on Ctrl-C. */ 51 extern bool volatile g_fTerminate; 52 /** The release logger. */ 53 extern PRTLOGGER g_pRelLogger; 54 55 /** The test handle. */ 56 extern RTTEST g_hTest; 57 extern unsigned g_uVerbosity; 58 extern bool g_fDrvAudioDebug; 59 extern const char *g_pszDrvAudioDebug; 60 61 /** The test handle. */ 62 extern RTTEST g_hTest; 63 /** The current verbosity level. */ 64 extern unsigned g_uVerbosity; 65 /** DrvAudio: Enable debug (or not). */ 66 extern bool g_fDrvAudioDebug; 67 /** DrvAudio: The debug output path. */ 68 extern const char *g_pszDrvAudioDebug; 69 70 71 /********************************************************************************************************************************* 72 * Defined Constants And Macros * 73 *********************************************************************************************************************************/ 74 75 76 /********************************************************************************************************************************* 77 * Structures and Typedefs * 78 *********************************************************************************************************************************/ 39 79 /** 40 80 * Audio driver stack. … … 97 137 typedef AUDIOTESTDRVMIXSTREAM *PAUDIOTESTDRVMIXSTREAM; 98 138 99 100 /** The test handle. */ 101 extern RTTEST g_hTest; 102 extern unsigned g_uVerbosity; 103 extern bool g_fDrvAudioDebug; 104 extern const char *g_pszDrvAudioDebug; 105 139 /** 140 * Backends. 141 * 142 * @note The first backend in the array is the default one for the platform. 143 */ 144 struct 145 { 146 /** The driver registration structure. */ 147 PCPDMDRVREG pDrvReg; 148 /** The backend name. 149 * Aliases are implemented by having multiple entries for the same backend. */ 150 const char *pszName; 151 } const g_aBackends[] = 152 { 153 #if defined(VBOX_WITH_AUDIO_ALSA) && defined(RT_OS_LINUX) 154 { &g_DrvHostALSAAudio, "alsa" }, 155 #endif 156 #ifdef VBOX_WITH_AUDIO_PULSE 157 { &g_DrvHostPulseAudio, "pulseaudio" }, 158 { &g_DrvHostPulseAudio, "pulse" }, 159 { &g_DrvHostPulseAudio, "pa" }, 160 #endif 161 #ifdef VBOX_WITH_AUDIO_OSS 162 { &g_DrvHostOSSAudio, "oss" }, 163 #endif 164 #if defined(RT_OS_DARWIN) 165 { &g_DrvHostCoreAudio, "coreaudio" }, 166 { &g_DrvHostCoreAudio, "core" }, 167 { &g_DrvHostCoreAudio, "ca" }, 168 #endif 169 #if defined(RT_OS_WINDOWS) 170 { &g_DrvHostAudioWas, "wasapi" }, 171 { &g_DrvHostAudioWas, "was" }, 172 { &g_DrvHostDSound, "directsound" }, 173 { &g_DrvHostDSound, "dsound" }, 174 { &g_DrvHostDSound, "ds" }, 175 #endif 176 { &g_DrvHostValidationKitAudio, "valkit" } 177 }; 178 AssertCompile(sizeof(g_aBackends) > 0 /* port me */); 179 180 181 182 /** 183 * Enumeration specifying the current audio test mode. 184 */ 185 typedef enum AUDIOTESTMODE 186 { 187 /** Unknown mode. */ 188 AUDIOTESTMODE_UNKNOWN = 0, 189 /** VKAT is running on the guest side. */ 190 AUDIOTESTMODE_GUEST, 191 /** VKAT is running on the host side. */ 192 AUDIOTESTMODE_HOST 193 } AUDIOTESTMODE; 194 195 struct AUDIOTESTENV; 196 /** Pointer a audio test environment. */ 197 typedef AUDIOTESTENV *PAUDIOTESTENV; 198 199 struct AUDIOTESTDESC; 200 /** Pointer a audio test descriptor. */ 201 typedef AUDIOTESTDESC *PAUDIOTESTDESC; 202 203 /** 204 * Callback to set up the test parameters for a specific test. 205 * 206 * @returns IPRT status code. 207 * @retval VINF_SUCCESS if setting the parameters up succeeded. Any other error code 208 * otherwise indicating the kind of error. 209 * @param pszTest Test name. 210 * @param pTstParmsAcq The audio test parameters to set up. 211 */ 212 typedef DECLCALLBACKTYPE(int, FNAUDIOTESTSETUP,(PAUDIOTESTENV pTstEnv, PAUDIOTESTDESC pTstDesc, PAUDIOTESTPARMS pTstParmsAcq, void **ppvCtx)); 213 /** Pointer to an audio test setup callback. */ 214 typedef FNAUDIOTESTSETUP *PFNAUDIOTESTSETUP; 215 216 typedef DECLCALLBACKTYPE(int, FNAUDIOTESTEXEC,(PAUDIOTESTENV pTstEnv, void *pvCtx, PAUDIOTESTPARMS pTstParms)); 217 /** Pointer to an audio test exec callback. */ 218 typedef FNAUDIOTESTEXEC *PFNAUDIOTESTEXEC; 219 220 typedef DECLCALLBACKTYPE(int, FNAUDIOTESTDESTROY,(PAUDIOTESTENV pTstEnv, void *pvCtx)); 221 /** Pointer to an audio test destroy callback. */ 222 typedef FNAUDIOTESTDESTROY *PFNAUDIOTESTDESTROY; 223 224 /** 225 * Structure for keeping an audio test audio stream. 226 */ 227 typedef struct AUDIOTESTSTREAM 228 { 229 /** The PDM stream. */ 230 PPDMAUDIOSTREAM pStream; 231 /** The backend stream. */ 232 PPDMAUDIOBACKENDSTREAM pBackend; 233 /** The stream config. */ 234 PDMAUDIOSTREAMCFG Cfg; 235 } AUDIOTESTSTREAM; 236 /** Pointer to audio test stream. */ 237 typedef AUDIOTESTSTREAM *PAUDIOTESTSTREAM; 238 239 /** Maximum audio streams a test environment can handle. */ 240 #define AUDIOTESTENV_MAX_STREAMS 8 241 242 /** 243 * Audio test environment parameters. 244 * Not necessarily bound to a specific test (can be reused). 245 */ 246 typedef struct AUDIOTESTENV 247 { 248 /** Audio testing mode. */ 249 AUDIOTESTMODE enmMode; 250 /** Whether self test mode is active or not. */ 251 bool fSelftest; 252 /** Output path for storing the test environment's final test files. */ 253 char szTag[AUDIOTEST_TAG_MAX]; 254 /** Output path for storing the test environment's final test files. */ 255 char szPathOut[RTPATH_MAX]; 256 /** Temporary path for this test environment. */ 257 char szPathTemp[RTPATH_MAX]; 258 /** Buffer size (in ms). */ 259 RTMSINTERVAL cMsBufferSize; 260 /** Pre-buffering time (in ms). */ 261 RTMSINTERVAL cMsPreBuffer; 262 /** Scheduling hint (in ms). */ 263 RTMSINTERVAL cMsSchedulingHint; 264 /** The audio test driver stack. */ 265 AUDIOTESTDRVSTACK DrvStack; 266 /** The current (last) audio device enumeration to use. */ 267 PDMAUDIOHOSTENUM DevEnum; 268 /** Audio stream. */ 269 AUDIOTESTSTREAM aStreams[AUDIOTESTENV_MAX_STREAMS]; 270 /** The audio test set to use. */ 271 AUDIOTESTSET Set; 272 union 273 { 274 struct 275 { 276 /** ATS instance to use. */ 277 ATSSERVER Srv; 278 } Guest; 279 struct 280 { 281 /** Client connected to the ATS on the guest side. */ 282 ATSCLIENT AtsClGuest; 283 /** Client connected to the ATS on the Validation Kit. */ 284 ATSCLIENT AtsClValKit; 285 } Host; 286 } u; 287 } AUDIOTESTENV; 288 289 /** 290 * Audio test descriptor. 291 */ 292 typedef struct AUDIOTESTDESC 293 { 294 /** (Sort of) Descriptive test name. */ 295 const char *pszName; 296 /** Flag whether the test is excluded. */ 297 bool fExcluded; 298 /** The setup callback. */ 299 PFNAUDIOTESTSETUP pfnSetup; 300 /** The exec callback. */ 301 PFNAUDIOTESTEXEC pfnExec; 302 /** The destruction callback. */ 303 PFNAUDIOTESTDESTROY pfnDestroy; 304 } AUDIOTESTDESC; 305 306 /** 307 * Structure for keeping a VKAT self test context. 308 */ 309 typedef struct SELFTESTCTX 310 { 311 /** Common tag for guest and host side. */ 312 char szTag[AUDIOTEST_TAG_MAX]; 313 /** Whether to use DrvAudio in the driver stack or not. */ 314 bool fWithDrvAudio; 315 struct 316 { 317 AUDIOTESTENV TstEnv; 318 /** Audio driver to use. 319 * Defaults to the platform's default driver. */ 320 PCPDMDRVREG pDrvReg; 321 } Guest; 322 struct 323 { 324 AUDIOTESTENV TstEnv; 325 /** Address of the guest ATS instance. 326 * Defaults to localhost (127.0.0.1) if not set. */ 327 char szGuestAtsAddr[64]; 328 /** Port of the guest ATS instance. 329 * Defaults to ATS_DEFAULT_PORT if not set. */ 330 uint32_t uGuestAtsPort; 331 /** Address of the Validation Kit audio driver ATS instance. 332 * Defaults to localhost (127.0.0.1) if not set. */ 333 char szValKitAtsAddr[64]; 334 /** Port of the Validation Kit audio driver ATS instance. 335 * Defaults to ATS_ALT_PORT if not set. */ 336 uint32_t uValKitAtsPort; 337 } Host; 338 } SELFTESTCTX; 339 /** Pointer to a VKAT self test context. */ 340 typedef SELFTESTCTX *PSELFTESTCTX; 341 342 /********************************************************************************************************************************* 343 * Prototypes * 344 *********************************************************************************************************************************/ 106 345 107 346 /** @name Driver stack … … 138 377 /** @} */ 139 378 379 /** @name Backend handling 380 * @{ */ 381 PCPDMDRVREG audioTestFindBackendOpt(const char *pszBackend); 382 /** @} */ 140 383 141 384 /** @name Mixing stream … … 154 397 /** @} */ 155 398 399 /** @name Device handling 400 * @{ */ 401 int audioTestDeviceOpen(PPDMAUDIOHOSTDEV pDev); 402 int audioTestDeviceClose(PPDMAUDIOHOSTDEV pDev); 403 /** @} */ 404 405 /** @name Test environment handling 406 * @{ */ 407 int audioTestEnvInit(PAUDIOTESTENV pTstEnv, PCPDMDRVREG pDrvReg, bool fWithDrvAudio, const char *pszTcpAddr, uint32_t uTcpPort); 408 void audioTestEnvDestroy(PAUDIOTESTENV pTstEnv); 409 int audioTestEnvPrologue(PAUDIOTESTENV pTstEnv); 410 411 void audioTestParmsInit(PAUDIOTESTPARMS pTstParms); 412 void audioTestParmsDestroy(PAUDIOTESTPARMS pTstParms); 413 /** @} */ 414 415 int audioTestWorker(PAUDIOTESTENV pTstEnv, PAUDIOTESTPARMS pOverrideParms); 416 417 /** @name Command handlers 418 * @{ */ 419 RTEXITCODE audioTestPlayOne(const char *pszFile, PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize, 420 uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, 421 uint8_t cChannels, uint8_t cbSample, uint32_t uHz, 422 bool fWithDrvAudio, bool fWithMixer); 423 RTEXITCODE audioTestRecOne(const char *pszFile, uint8_t cWaveChannels, uint8_t cbWaveSample, uint32_t uWaveHz, 424 PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize, 425 uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, 426 uint8_t cChannels, uint8_t cbSample, uint32_t uHz, bool fWithDrvAudio, bool fWithMixer, 427 uint64_t cMaxFrames, uint64_t cNsMaxDuration); 428 RTEXITCODE audioTestDoSelftest(PSELFTESTCTX pCtx); 429 /** @} */ 156 430 157 431 #endif /* !VBOX_INCLUDED_SRC_audio_vkatInternal_h */
Note:
See TracChangeset
for help on using the changeset viewer.