VirtualBox

Changeset 92195 in vbox for trunk


Ignore:
Timestamp:
Nov 3, 2021 5:27:10 PM (3 years ago)
Author:
vboxsync
Message:

Audio/Validation Kit: More code for audio data beacon handling. Now has dedicated beacons for recording / playback tests. bugref:10008

Location:
trunk/src/VBox
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/AudioTest.cpp

    r91912 r92195  
    156156     *  Must not contain a path and has to be able to serialize to disk. */
    157157    char                 szName[256];
     158    /** The test type. */
     159    AUDIOTESTTYPE        enmTestType;
    158160    /** The object type. */
    159161    AUDIOTESTOBJTYPE     enmType;
     
    23222324
    23232325/**
     2326 * Initializes a audio test audio beacon.
     2327 *
     2328 * @returns VBox status code.
     2329 * @param   pBeacon             Audio test beacon to (re-)initialize.
     2330 * @param   enmType             Beacon type to set.
     2331 * @param   pProps              PCM properties to use for producing audio beacon data.
     2332 */
     2333void AudioTestBeaconInit(PAUDIOTESTTONEBEACON pBeacon, AUDIOTESTTONEBEACONTYPE enmType, PPDMAUDIOPCMPROPS pProps)
     2334{
     2335    AssertReturnVoid(PDMAudioPropsFrameSize(pProps) == 4); /** @todo Make this more dynamic. */
     2336
     2337    RT_BZERO(pBeacon, sizeof(AUDIOTESTTONEBEACON));
     2338
     2339    pBeacon->enmType = enmType;
     2340    memcpy(&pBeacon->Props, pProps, sizeof(PDMAUDIOPCMPROPS));
     2341
     2342    pBeacon->cbToProcess = PDMAudioPropsFramesToBytes(&pBeacon->Props, AUDIOTEST_BEACON_SIZE_FRAMES);
     2343}
     2344
     2345/**
     2346 * Returns the beacon byte of a beacon type.
     2347 *
     2348 * @returns Beacon byte if found, 0 otherwise.
     2349 * @param   enmType             Beacon type to get beacon byte for.
     2350 */
     2351DECLINLINE(uint8_t) AudioTestBeaconByteFromType(AUDIOTESTTONEBEACONTYPE enmType)
     2352{
     2353    switch (enmType)
     2354    {
     2355        case AUDIOTESTTONEBEACONTYPE_PLAY_PRE:  return AUDIOTEST_BEACON_BYTE_PLAY_PRE;
     2356        case AUDIOTESTTONEBEACONTYPE_PLAY_POST: return AUDIOTEST_BEACON_BYTE_PLAY_POST;
     2357        case AUDIOTESTTONEBEACONTYPE_REC_PRE:   return AUDIOTEST_BEACON_BYTE_REC_PRE;
     2358        case AUDIOTESTTONEBEACONTYPE_REC_POST:  return AUDIOTEST_BEACON_BYTE_REC_POST;
     2359        default:                                break;
     2360    }
     2361
     2362    AssertFailedReturn(0);
     2363    return 0; /* Never reached. */
     2364}
     2365
     2366/**
     2367 * Returns the total expected (total) size of an audio beacon (in bytes).
     2368 *
     2369 * @returns  Beacon size in bytes.
     2370 * @param   pBeacon             Beacon to get beacon size for.
     2371 */
     2372uint32_t AudioTestBeaconGetSize(PCAUDIOTESTTONEBEACON pBeacon)
     2373{
     2374    return pBeacon->cbToProcess;
     2375}
     2376
     2377/**
     2378 * Returns the beacon type of an audio beacon.
     2379 *
     2380 * @returns Beacon type.
     2381 * @param   pBeacon             Beacon to get beacon size for.
     2382 */
     2383AUDIOTESTTONEBEACONTYPE AudioTestBeaconGetType(PCAUDIOTESTTONEBEACON pBeacon)
     2384{
     2385    return pBeacon->enmType;
     2386}
     2387
     2388/**
     2389 * Returns the remaining bytes (to be complete) of an audio beacon.
     2390 *
     2391 * @returns Remaining bytes.
     2392 * @param   pBeacon             Beacon to get remaining size for.
     2393 */
     2394uint32_t AudioTestBeaconGetRemaining(PCAUDIOTESTTONEBEACON pBeacon)
     2395{
     2396    return pBeacon->cbToProcess - pBeacon->cbProcessed;
     2397}
     2398
     2399/**
     2400 * Returns the already used (received) bytes (to be complete) of an audio beacon.
     2401 *
     2402 * @returns Used bytes.
     2403 * @param   pBeacon             Beacon to get remaining size for.
     2404 */
     2405uint32_t AudioTestBeaconGetUsed(PCAUDIOTESTTONEBEACON pBeacon)
     2406{
     2407    return pBeacon->cbProcessed;
     2408}
     2409
     2410/**
     2411 * Writes audio beacon data to a given buffer.
     2412 *
     2413 * @returns VBox status code.
     2414 * @param   pBeacon             Beacon to write to buffer.
     2415 * @param   pvBuf               Buffer to write to.
     2416 * @param   cbBuf               Size (in bytes) of buffer to write to.
     2417 */
     2418int AudioTestBeaconWrite(PAUDIOTESTTONEBEACON pBeacon, void *pvBuf, uint32_t cbBuf)
     2419{
     2420    AssertReturn(pBeacon->cbProcessed + cbBuf <= pBeacon->cbToProcess, VERR_BUFFER_OVERFLOW);
     2421
     2422    memset(pvBuf, AudioTestBeaconByteFromType(pBeacon->enmType), cbBuf);
     2423
     2424    pBeacon->cbProcessed += cbBuf;
     2425
     2426    return VINF_SUCCESS;
     2427}
     2428
     2429/**
     2430 * Converts an audio beacon type to a string.
     2431 *
     2432 * @returns Pointer to read-only audio beacon type string on success,
     2433 *          "illegal" if invalid command value.
     2434 * @param   enmType             The type to convert.
     2435 */
     2436const char *AudioTestBeaconTypeGetName(AUDIOTESTTONEBEACONTYPE enmType)
     2437{
     2438    switch (enmType)
     2439    {
     2440        case AUDIOTESTTONEBEACONTYPE_PLAY_PRE:  return "pre-playback";
     2441        case AUDIOTESTTONEBEACONTYPE_PLAY_POST: return "post-playback";
     2442        case AUDIOTESTTONEBEACONTYPE_REC_PRE:   return "pre-recording";
     2443        case AUDIOTESTTONEBEACONTYPE_REC_POST:  return "post-recording";
     2444        default:                                break;
     2445    }
     2446    AssertMsgFailedReturn(("Invalid beacon type: #%x\n", enmType), "illegal");
     2447}
     2448
     2449uint32_t AudioTestBeaconAddConsecutive(PAUDIOTESTTONEBEACON pBeacon, const uint8_t *pauBuf, size_t cbBuf)
     2450{
     2451    uint32_t const cbFrameSize = PDMAudioPropsFrameSize(&pBeacon->Props); /* Use the audio frame size as chunk size. */
     2452
     2453    if (cbBuf < cbFrameSize)
     2454        return 0;
     2455
     2456    AssertMsgReturn(cbBuf % cbFrameSize == 0,
     2457                    ("Buffer size must be frame-aligned"), VERR_INVALID_PARAMETER);
     2458
     2459    uint8_t const byBeacon      = AudioTestBeaconByteFromType(pBeacon->enmType);
     2460    /*bool          fInBeacon     = false;
     2461    uint32_t      cbBeacon      = 0;
     2462    size_t        offLastBeacon = 0;*/
     2463    size_t offGap = 0;
     2464
     2465    unsigned const cbStep             = cbFrameSize;
     2466    uint32_t const cbProcessedInitial = pBeacon->cbProcessed;
     2467
     2468    for (size_t i = 0; i < cbBuf; i += cbStep)
     2469    {
     2470        if (   pauBuf[i]     == byBeacon
     2471            && pauBuf[i + 1] == byBeacon
     2472            && pauBuf[i + 2] == byBeacon
     2473            && pauBuf[i + 3] == byBeacon)
     2474        {
     2475            //if (pBeacon->cbProcessed)
     2476            //{
     2477                //LogRel(("AudioTestBeaconAddConsecutive: Beacon %s started (last was %RU32@%zu)\n", AudioTestBeaconTypeGetName(pBeacon->enmType), cbBeacon, i));
     2478                if (offGap)
     2479                {
     2480                    pBeacon->cbProcessed = 0;
     2481                }
     2482                pBeacon->cbProcessed += cbStep;
     2483                offGap = 0;
     2484                //fInBeacon = true;
     2485                //offLastBeacon = i;
     2486            //}
     2487            //cbBeacon += cbFrameSize;
     2488        }
     2489        else
     2490        {
     2491        #if 0
     2492            if (fInBeacon)
     2493            {
     2494                //LogRel(("AudioTestBeaconAddConsecutive: Beacon %s ended (%RU32@%zu)\n", AudioTestBeaconTypeGetName(pBeacon->enmType), cbBeacon, offLastBeacon));
     2495                fInBeacon = false;
     2496                continue;
     2497            }
     2498        #endif
     2499            offGap  = i;
     2500        }
     2501    }
     2502
     2503#if 0
     2504    if (   cbBeacon
     2505        && (   fInBeacon
     2506            || offLastBeacon == 0)
     2507       )
     2508    {
     2509        pBeacon->cbProcessed += cbBeacon;
     2510        Assert(pBeacon->cbProcessed <= pBeacon->cbToProcess);
     2511    }
     2512
     2513    if (cbBeacon)
     2514        LogRel(("AudioTestBeaconAddConsecutive: %s in=%RTbool cb=%RU32 -> cbProc=%RU32\n", AudioTestBeaconTypeGetName(pBeacon->enmType), fInBeacon, cbBeacon, pBeacon->cbProcessed));
     2515//LogRel(("AudioTestBeaconAddConsecutive: Beacon proc finished (last was cbBuf=%RU32, fInBeacon=%RTbool, cbBeacon=%RU32, cbProc=%RU32)\n", cbBuf, fInBeacon, cbBeacon, pBeacon->cbProcessed));
     2516#endif
     2517
     2518    Assert(pBeacon->cbProcessed >= cbProcessedInitial);
     2519    return pBeacon->cbProcessed - cbProcessedInitial;
     2520}
     2521
     2522/**
     2523 * Returns whether a beacon is considered to be complete or not.
     2524 *
     2525 * A complete beacon means that all data for it has been retrieved.
     2526 *
     2527 * @returns \c true if complete, or \c false if not.
     2528 * @param   pBeacon             Beacon to get completion status for.
     2529 */
     2530bool AudioTestBeaconIsComplete(PCAUDIOTESTTONEBEACON pBeacon)
     2531{
     2532    AssertReturn(pBeacon->cbProcessed <= pBeacon->cbToProcess, true);
     2533    return (pBeacon->cbProcessed == pBeacon->cbToProcess);
     2534}
     2535
     2536/**
    23242537 * Verifies a pre/post beacon of a test tone.
    23252538 *
    23262539 * @returns VBox status code, VERR_NOT_FOUND if beacon was not found.
    23272540 * @param   pVerJob             Verification job to verify PCM data for.
     2541 * @param   fIn                 Set to \c true for recording, \c false for playback.
    23282542 * @param   fPre                Set to \c true to verify a pre beacon, or \c false to verify a post beacon.
    23292543 * @param   pCmp                File comparison parameters to file to verify beacon for.
     
    23322546 */
    23332547static int audioTestToneVerifyBeacon(PAUDIOTESTVERIFYJOB pVerJob,
    2334                                      bool fPre, PAUDIOTESTFILECMPPARMS pCmp, PAUDIOTESTTONEPARMS pToneParms, uint64_t *puOff)
     2548                                     bool fIn, bool fPre, PAUDIOTESTFILECMPPARMS pCmp, PAUDIOTESTTONEPARMS pToneParms,
     2549                                     uint64_t *puOff)
    23352550{
    23362551    int rc = RTFileSeek(pCmp->hFile, pCmp->offStart, RTFILE_SEEK_BEGIN, NULL);
    23372552    AssertRCReturn(rc, rc);
     2553
     2554    AUDIOTESTTONEBEACON Beacon;
     2555    AudioTestBeaconInit(&Beacon,
     2556                          fIn
     2557                        ? (fPre ? AUDIOTESTTONEBEACONTYPE_PLAY_PRE : AUDIOTESTTONEBEACONTYPE_PLAY_POST)
     2558                        : (fPre ? AUDIOTESTTONEBEACONTYPE_REC_PRE  : AUDIOTESTTONEBEACONTYPE_REC_POST), &pToneParms->Props);
     2559
     2560    LogRel2(("Verifying %s beacon @ %RU64\n", AudioTestBeaconTypeGetName(Beacon.enmType), pCmp->offStart));
    23382561
    23392562    uint8_t        auBuf[64];
    23402563    uint64_t       cbToCompare   = pCmp->cbSize;
    2341     uint32_t const cbFrameSize   = PDMAudioPropsFrameSize(&pToneParms->Props); /* Use the audio frame size as chunk size. */
    2342     bool           fInBeacon     = false;
    2343     uint32_t       cbBeacon      = 0;
    2344     size_t         offLastBeacon = 0; /* Offset (in bytes) of last beacon read. */
    2345 
    2346     uint8_t const  byBeacon    = fPre ? AUDIOTEST_BEACON_BYTE_PRE : AUDIOTEST_BEACON_BYTE_POST;
    2347 
    2348     AssertReturn(cbFrameSize == 4, VERR_NOT_SUPPORTED); /* Otherwise the stuff below won't work. */
     2564    uint32_t const cbFrameSize   = PDMAudioPropsFrameSize(&Beacon.Props);
     2565    uint64_t       offBeaconLast = 0;
    23492566
    23502567    /* Slow as heck, but does the job for now. */
     
    23582575            break;
    23592576
    2360         for (size_t i = 0; i < cbRead; i += cbFrameSize)
    2361         {
    2362             if (   auBuf[i]     == byBeacon
    2363                 && auBuf[i + 1] == byBeacon
    2364                 && auBuf[i + 2] == byBeacon
    2365                 && auBuf[i + 3] == byBeacon)
    2366             {
    2367                 if (!fInBeacon)
    2368                 {
    2369                     cbBeacon  = 0;
    2370                     fInBeacon = true;
    2371                 }
    2372                 cbBeacon += cbFrameSize;
    2373             }
    2374             else
    2375             {
    2376                 if (fInBeacon)
    2377                 {
    2378                     fInBeacon     = false;
    2379                     offLastBeacon = RTFileTell(pCmp->hFile);
    2380                     continue;
    2381                 }
    2382             }
    2383         }
    2384 
     2577        const uint32_t cbAdded = AudioTestBeaconAddConsecutive(&Beacon, auBuf, cbRead);
     2578        if (cbAdded)
     2579            offBeaconLast = RTFileTell(pCmp->hFile);
     2580
     2581        Assert(cbToCompare >= cbRead);
    23852582        cbToCompare -= cbRead;
    23862583    }
    23872584
    2388     uint32_t const cbBeaconExpected = PDMAudioPropsFramesToBytes(&pToneParms->Props, AUDIOTEST_BEACON_SIZE_FRAMES);
    2389     bool     const fValid           = cbBeacon == cbBeaconExpected;
    2390     if (!fValid)
     2585    uint32_t const cbBeacon = AudioTestBeaconGetUsed(&Beacon);
     2586
     2587    if (!AudioTestBeaconIsComplete(&Beacon))
    23912588    {
    23922589        int rc2 = audioTestErrorDescAddError(pVerJob->pErr, pVerJob->idxTest, "File '%s': %s beacon %s (got %RU32 bytes, expected %RU32)",
    23932590                                             pCmp->pszName,
    2394                                              fPre ? "Pre" : "Post", cbBeacon ? "found" : "not found", cbBeacon, cbBeaconExpected);
     2591                                             AudioTestBeaconTypeGetName(Beacon.enmType),
     2592                                             cbBeacon ? "found" : "not found", cbBeacon,
     2593                                             AudioTestBeaconGetSize(&Beacon));
    23952594        AssertRC(rc2);
    23962595        return VERR_NOT_FOUND;
     
    23982597    else
    23992598    {
    2400         int rc2 = audioTestErrorDescAddInfo(pVerJob->pErr, pVerJob->idxTest, "File '%s': %s beacon found and valid",
    2401                                             pCmp->pszName, fPre ? "Pre" : "Post");
     2599        AssertReturn(AudioTestBeaconGetRemaining(&Beacon) == 0, VERR_INTERNAL_ERROR);
     2600        AssertReturn(offBeaconLast >= AudioTestBeaconGetSize(&Beacon), VERR_INTERNAL_ERROR);
     2601
     2602        int rc2 = audioTestErrorDescAddInfo(pVerJob->pErr, pVerJob->idxTest, "File '%s': %s beacon found at offset %RU64 and valid",
     2603                                            pCmp->pszName, AudioTestBeaconTypeGetName(Beacon.enmType),
     2604                                            offBeaconLast - AudioTestBeaconGetSize(&Beacon));
    24022605        AssertRC(rc2);
    24032606
    24042607        if (puOff)
    2405             *puOff = offLastBeacon;
     2608            *puOff = offBeaconLast;
    24062609    }
    24072610
     
    25522755
    25532756    uint64_t offBeaconAbs;
    2554     rc = audioTestToneVerifyBeacon(pVerJob, true  /* fPre */,  &FileA, &ToneParmsA, &offBeaconAbs);
     2757    rc = audioTestToneVerifyBeacon(pVerJob, phTestA->enmTestType == AUDIOTESTTYPE_TESTTONE_PLAY /* fIn */,
     2758                                   true /* fPre */, &FileA, &ToneParmsA, &offBeaconAbs);
    25552759    if (RT_SUCCESS(rc))
    25562760    {
    25572761        FileA.offStart = offBeaconAbs;
    25582762        FileA.cbSize   = cbFileSizeA - FileA.offStart;
    2559         rc = audioTestToneVerifyBeacon(pVerJob, false /* fPost */, &FileA, &ToneParmsA, NULL);
    2560     }
    2561 
    2562     rc = audioTestToneVerifyBeacon(pVerJob, true  /* fPre */,  &FileB, &ToneParmsB, &offBeaconAbs);
     2763        rc = audioTestToneVerifyBeacon(pVerJob, phTestA->enmTestType == AUDIOTESTTYPE_TESTTONE_PLAY /* fIn */,
     2764                                       false /* fPre */, &FileA, &ToneParmsA, NULL);
     2765    }
     2766
     2767    rc = audioTestToneVerifyBeacon(pVerJob, phTestB->enmTestType == AUDIOTESTTYPE_TESTTONE_RECORD /* fIn */,
     2768                                   true  /* fPre */,  &FileB, &ToneParmsB, &offBeaconAbs);
    25632769    if (RT_SUCCESS(rc))
    25642770    {
    25652771        FileB.offStart = offBeaconAbs;
    25662772        FileB.cbSize   = cbFileSizeB - FileB.offStart;
    2567         rc = audioTestToneVerifyBeacon(pVerJob, false /* fPost */, &FileB, &ToneParmsB, NULL);
     2773        rc = audioTestToneVerifyBeacon(pVerJob, phTestB->enmTestType == AUDIOTESTTYPE_TESTTONE_RECORD /* fIn */,
     2774                                       false /* fPre */, &FileB, &ToneParmsB, NULL);
    25682775    }
    25692776
     
    27312938        CHECK_RC_MSG_MAYBE_RET(rc, pVerJob, "Test B not found");
    27322939
    2733         AUDIOTESTTYPE enmTestTypeA = AUDIOTESTTYPE_INVALID;
    2734         rc = audioTestObjGetUInt32(&hTestA, "test_type", (uint32_t *)&enmTestTypeA);
     2940        rc = audioTestObjGetUInt32(&hTestA, "test_type", (uint32_t *)&hTestA.enmTestType);
    27352941        CHECK_RC_MSG_MAYBE_RET(rc, pVerJob, "Test type A not found");
    27362942
    2737         AUDIOTESTTYPE enmTestTypeB = AUDIOTESTTYPE_INVALID;
    2738         rc = audioTestObjGetUInt32(&hTestB, "test_type", (uint32_t *)&enmTestTypeB);
     2943        rc = audioTestObjGetUInt32(&hTestB, "test_type", (uint32_t *)&hTestB.enmTestType);
    27392944        CHECK_RC_MSG_MAYBE_RET(rc, pVerJob, "Test type B not found");
    27402945
    2741         switch (enmTestTypeA)
     2946        switch (hTestA.enmTestType)
    27422947        {
    27432948            case AUDIOTESTTYPE_TESTTONE_PLAY:
    27442949            {
    2745                 if (enmTestTypeB == AUDIOTESTTYPE_TESTTONE_RECORD)
     2950                if (hTestB.enmTestType == AUDIOTESTTYPE_TESTTONE_RECORD)
    27462951                    rc = audioTestVerifyTestTone(&VerJob, &hTestA, &hTestB);
    27472952                else
    27482953                    rc = audioTestErrorDescAddError(pErrDesc, i, "Playback test types don't match (set A=%#x, set B=%#x)",
    2749                                                     enmTestTypeA, enmTestTypeB);
     2954                                                    hTestA.enmTestType, hTestB.enmTestType);
    27502955                break;
    27512956            }
     
    27532958            case AUDIOTESTTYPE_TESTTONE_RECORD:
    27542959            {
    2755                 if (enmTestTypeB == AUDIOTESTTYPE_TESTTONE_PLAY)
     2960                if (hTestB.enmTestType == AUDIOTESTTYPE_TESTTONE_PLAY)
    27562961                    rc = audioTestVerifyTestTone(&VerJob, &hTestB, &hTestA);
    27572962                else
    27582963                    rc = audioTestErrorDescAddError(pErrDesc, i, "Recording test types don't match (set A=%#x, set B=%#x)",
    2759                                                     enmTestTypeA, enmTestTypeB);
     2964                                                    hTestA.enmTestType, hTestB.enmTestType);
    27602965                break;
    27612966            }
  • trunk/src/VBox/Devices/Audio/AudioTest.h

    r91655 r92195  
    3232/** Prefix for audio test (set) directories. */
    3333#define AUDIOTEST_PATH_PREFIX_STR       "vkat"
    34 /** Audio beacon data (single byte) to use for the post beacon (intro). */
    35 #define AUDIOTEST_BEACON_BYTE_PRE       0x42
    36 /** Audio beacon data (single byte) to use for the post beacon (outro). */
    37 #define AUDIOTEST_BEACON_BYTE_POST      0x24
     34/** Audio beacon data (single byte) to use for the playback pre beacon (intro). */
     35#define AUDIOTEST_BEACON_BYTE_PLAY_PRE  0x42
     36/** Audio beacon data (single byte) to use for the playback post beacon (outro). */
     37#define AUDIOTEST_BEACON_BYTE_PLAY_POST 0x24
     38/** Audio beacon data (single byte) to use for the recording pre beacon (intro). */
     39#define AUDIOTEST_BEACON_BYTE_REC_PRE   0x75
     40/** Audio beacon data (single byte) to use for the recording post beacon (outro). */
     41#define AUDIOTEST_BEACON_BYTE_REC_POST  0x57
    3842/** Pre / post audio beacon size (in audio frames). */
    3943#define AUDIOTEST_BEACON_SIZE_FRAMES    1024
     
    116120/** Pointer to audio test tone parameters. */
    117121typedef AUDIOTESTTONEPARMS *PAUDIOTESTTONEPARMS;
     122
     123/**
     124 * Enumeration defining an audio test beacon type.
     125 */
     126typedef enum AUDIOTESTTONEBEACONTYPE
     127{
     128    /** Invalid type. */
     129    AUDIOTESTTONEBEACONTYPE_INVALID = 0,
     130    /** Playback beacon (pre). */
     131    AUDIOTESTTONEBEACONTYPE_PLAY_PRE = 1,
     132    /** Playback beacon (post). */
     133    AUDIOTESTTONEBEACONTYPE_PLAY_POST = 2,
     134    /** Recording beacon (pre). */
     135    AUDIOTESTTONEBEACONTYPE_REC_PRE = 3,
     136    /** Recording beacon (post). */
     137    AUDIOTESTTONEBEACONTYPE_REC_POST = 4,
     138    /** The usual 32-bit hack. */
     139    OTESTTONEBEACONTYPE_32BIT_HACK = 0x7fffffff
     140} AUDIOTESTTONEBEACONTYPE;
     141
     142/**
     143 * Structure defining an audio test tone beacon.
     144 *
     145 * This is being used for (optionally) marking beginning/ending of audio test data.
     146 */
     147typedef struct AUDIOTESTTONEBEACON
     148{
     149    /** The beacon type. */
     150    AUDIOTESTTONEBEACONTYPE enmType;
     151    /** PCM properties to use for this beacon. */
     152    PDMAUDIOPCMPROPS        Props;
     153    /** Beacon bytes to process.
     154     *  When doing test tone playback: Beacon bytes to write.
     155     *  When doing test tone recording: Beacon bytes to read. */
     156    uint32_t                cbToProcess;
     157    /** Beacon bytes already processed.
     158     *  When doing test tone playback: Beacon bytes written.
     159     *  When doing test tone recording: Beacon bytes read. */
     160    uint32_t                cbProcessed;
     161} AUDIOTESTTONEBEACON;
     162/** Pointer to audio test tone beacon. */
     163typedef AUDIOTESTTONEBEACON *PAUDIOTESTTONEBEACON;
     164/** Pointer (const) to audio test tone beacon. */
     165typedef AUDIOTESTTONEBEACON const *PCAUDIOTESTTONEBEACON;
    118166
    119167/**
     
    310358int    AudioTestToneGenerate(PAUDIOTESTTONE pTone, void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
    311359
     360void   AudioTestBeaconInit(PAUDIOTESTTONEBEACON pBeacon, AUDIOTESTTONEBEACONTYPE enmType, PPDMAUDIOPCMPROPS pProps);
     361uint32_t AudioTestBeaconAddConsecutive(PAUDIOTESTTONEBEACON pBeacon, const uint8_t *auBuf, size_t cbBuf);
     362int    AudioTestBeaconWrite(PAUDIOTESTTONEBEACON pBeacon, void *pvBuf, uint32_t cbBuf);
     363uint32_t AudioTestBeaconGetSize(PCAUDIOTESTTONEBEACON pBeacon);
     364const char *AudioTestBeaconTypeGetName(AUDIOTESTTONEBEACONTYPE enmType);
     365AUDIOTESTTONEBEACONTYPE AudioTestBeaconGetType(PCAUDIOTESTTONEBEACON pBeacon);
     366uint32_t AudioTestBeaconGetRemaining(PCAUDIOTESTTONEBEACON pBeacon);
     367uint32_t AudioTestBeaconGetUsed(PCAUDIOTESTTONEBEACON pBeacon);
     368bool   AudioTestBeaconIsComplete(PCAUDIOTESTTONEBEACON pBeacon);
     369
    312370int    AudioTestGenTag(char *pszTag, size_t cbTag);
    313371
  • trunk/src/VBox/Devices/Audio/DrvHostAudioValidationKit.cpp

    r91908 r92195  
    7272typedef struct VALKITTESTTONEDATA
    7373{
     74    /* Test tone beacon to use.
     75     * Will be re-used for pre/post beacons. */
     76    AUDIOTESTTONEBEACON Beacon;
    7477    union
    7578    {
     
    8083            /** How many bytes already written. */
    8184            uint64_t           cbWritten;
    82             /** Size (in bytes) a single pre/post beacon is. */
    83             uint32_t           cbBeacon;
    84             /** Beacon bytes to write. */
    85             uint32_t           cbBeaconToWrite;
    86             /** Beacon bytes written. */
    87             uint32_t           cbBeaconWritten;
    8885        } Rec;
    8986        struct
     
    10299
    103100/**
     101 * Enumeration specifying an internal test state.
     102 */
     103typedef enum VALKITTESTSTATE
     104{
     105    /** Test is initializing. */
     106    VALKITTESTSTATE_INIT = 0,
     107    /** Test is in pre-run phase. */
     108    VALKITTESTSTATE_PRE,
     109    /** Test is running */
     110    VALKITTESTSTATE_RUN,
     111    /** Test is in post-run phase. */
     112    VALKITTESTSTATE_POST,
     113    /** Test has been run. */
     114    VALKITTESTSTATE_DONE
     115} VALKITTESTSTATE;
     116
     117/**
    104118 * Structure keeping a single Validation Kit test.
    105119 */
     
    112126    /** Current test set entry to process. */
    113127    PAUDIOTESTENTRY        pEntry;
     128    /** Current test state. */
     129    VALKITTESTSTATE        enmState;
    114130    /** Current test object to process. */
    115131    AUDIOTESTOBJ           Obj;
     
    200216
    201217/**
     218 * Converts an internal test state enum value to a string.
     219 *
     220 * @returns Pointer to read-only internal test state string on success,
     221 *          "illegal" if invalid command value.
     222 * @param   enmState            The state to convert.
     223 */
     224DECLINLINE(const char *) drvHostValKitTestStatusToStr(VALKITTESTSTATE enmState)
     225{
     226    switch (enmState)
     227    {
     228        case VALKITTESTSTATE_INIT: return "init";
     229        case VALKITTESTSTATE_PRE:  return "pre";
     230        case VALKITTESTSTATE_RUN:  return "run";
     231        case VALKITTESTSTATE_POST: return "post";
     232        case VALKITTESTSTATE_DONE: return "done";
     233        /* no default: */
     234            break;
     235    }
     236    AssertMsgFailedReturn(("Invalid test state: #%x\n", enmState), "illegal");
     237}
     238
     239/**
    202240 * Unregisters a ValKit test, common code.
    203241 *
     
    393431        LogRel(("ValKit: %RU32 tests still registered total (%RU32 play, %RU32 record)\n",
    394432                pThis->cTestsTotal, pThis->cTestsPlay, pThis->cTestsRec));
     433
     434        PVALKITTESTDATA pTst;
     435        RTListForEach(&pThis->lstTestsRec, pTst, VALKITTESTDATA, Node)
     436        {
     437            if (pTst->enmState != VALKITTESTSTATE_DONE)
     438                LogRel(("ValKit: Warning: Test #%RU32 not done yet (state is '%s')\n",
     439                        pTst->idxTest, drvHostValKitTestStatusToStr(pTst->enmState)));
     440        }
    395441
    396442        if (   AudioTestSetIsRunning(pSet)
     
    482528    AssertPtrReturn(pTestData, VERR_NO_MEMORY);
    483529
     530    pTestData->enmState = VALKITTESTSTATE_INIT;
     531
    484532    memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
    485533
     
    494542                                                                      pTestData->t.TestTone.Parms.msDuration);
    495543
    496     /* We play a pre + post beacon before + after the actual test tone
    497      * with exactly AUDIOTEST_BEACON_SIZE_FRAMES audio frames. */
    498     pTestData->t.TestTone.u.Rec.cbBeacon        = PDMAudioPropsFramesToBytes(pProps, AUDIOTEST_BEACON_SIZE_FRAMES);
    499     pTestData->t.TestTone.u.Rec.cbBeaconToWrite = pTestData->t.TestTone.u.Rec.cbBeacon;
     544    /* We inject a pre + post beacon before + after the actual test tone.
     545     * We always start with the pre beacon. */
     546    AudioTestBeaconInit(&pTestData->t.TestTone.Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_PRE, pProps);
    500547
    501548    int rc = RTCritSectEnter(&pThis->CritSect);
     
    505552                pThis->idxTest, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Rec.cbToWrite,
    506553                pToneParms->Hdr.idxSeq));
    507         if (pTestData->t.TestTone.u.Rec.cbBeaconToWrite)
    508         {
    509             LogRel2(("ValKit: Guest recording test #%RU32 includes 2 x %RU32 bytes of beacons\n",
    510                      pThis->idxTest, pTestData->t.TestTone.u.Rec.cbBeaconToWrite));
    511 
    512             pTestData->t.TestTone.u.Rec.cbToWrite += 2 /* Pre + Post */ * pTestData->t.TestTone.u.Rec.cbBeaconToWrite;
    513         }
     554
     555        const uint32_t cbBeacon = AudioTestBeaconGetSize(&pTestData->t.TestTone.Beacon);
     556        if (cbBeacon)
     557            LogRel2(("ValKit: Guest recording test #%RU32 includes 2 x %RU32 bytes of pre/post beacons\n",
     558                     pThis->idxTest, cbBeacon));
    514559
    515560        RTListAppend(&pThis->lstTestsRec, &pTestData->Node);
     
    540585    AssertPtrReturn(pTestData, VERR_NO_MEMORY);
    541586
     587    pTestData->enmState = VALKITTESTSTATE_INIT;
     588
    542589    memcpy(&pTestData->t.TestTone.Parms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
    543590
     591    PPDMAUDIOPCMPROPS const pProps = &pTestData->t.TestTone.Parms.Props;
     592
    544593    AssertReturn(pTestData->t.TestTone.Parms.msDuration, VERR_INVALID_PARAMETER);
    545     AssertReturn(PDMAudioPropsAreValid(&pTestData->t.TestTone.Parms.Props), VERR_INVALID_PARAMETER);
    546 
    547     pTestData->t.TestTone.u.Play.cbToRead  = PDMAudioPropsMilliToBytes(&pTestData->t.TestTone.Parms.Props,
     594    AssertReturn(PDMAudioPropsAreValid(pProps), VERR_INVALID_PARAMETER);
     595
     596    pTestData->t.TestTone.u.Play.cbToRead  = PDMAudioPropsMilliToBytes(pProps,
    548597                                                                       pTestData->t.TestTone.Parms.msDuration);
    549     uint32_t const cbBeacons = PDMAudioPropsFramesToBytes(&pTestData->t.TestTone.Parms.Props,
    550                                                           AUDIOTEST_BEACON_SIZE_FRAMES * 2 /* Pre + post beacon */);
    551     pTestData->t.TestTone.u.Play.cbToRead += cbBeacons;
     598
     599    /* We play a pre + post beacon before + after the actual test tone.
     600     * We always start with the pre beacon. */
     601    AudioTestBeaconInit(&pTestData->t.TestTone.Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_PRE, pProps);
    552602
    553603    int rc = RTCritSectEnter(&pThis->CritSect);
     
    557607                pThis->idxTest, pTestData->t.TestTone.Parms.msDuration, pTestData->t.TestTone.u.Play.cbToRead,
    558608                pToneParms->Hdr.idxSeq));
     609
     610        const uint32_t cbBeacon = AudioTestBeaconGetSize(&pTestData->t.TestTone.Beacon);
     611        if (cbBeacon)
     612            LogRel2(("ValKit: Guest playback test #%RU32 includes 2 x %RU32 bytes of pre/post beacons\n",
     613                     pThis->idxTest, cbBeacon));
    559614
    560615        RTListAppend(&pThis->lstTestsPlay, &pTestData->Node);
     
    824879
    825880    if (   pTst
    826         && pTst->pEntry == NULL) /* Test not started yet? */
     881        && pTst->enmState == VALKITTESTSTATE_INIT) /* Test not started yet? */
    827882    {
    828883        AUDIOTESTPARMS Parms;
     
    847902            char szTimeCreated[RTTIME_STR_LEN];
    848903            RTTimeToString(&Parms.TestTone.Hdr.tsCreated, szTimeCreated, sizeof(szTimeCreated));
    849             LogRel(("ValKit: Test created (caller UTC): %s\n", szTimeCreated));
     904            LogRel2(("ValKit: Test created (caller UTC): %s\n", szTimeCreated));
    850905        }
    851906
    852907        pStrmValKit->cbAvail += pTst->t.TestTone.u.Rec.cbToWrite;
    853         LogRel(("ValKit: Now total of %RU32 bytes available for capturing\n", pStrmValKit->cbAvail));
     908        pStrmValKit->cbAvail += AudioTestBeaconGetSize(&pTst->t.TestTone.Beacon); /* Add beacon data, if any. */
     909        LogRel2(("ValKit: Now total of %RU32 bytes available for capturing\n", pStrmValKit->cbAvail));
     910
     911        pTst->enmState = VALKITTESTSTATE_PRE;
    854912    }
    855913
     
    926984#endif
    927985
    928     bool const fIsSilence = PDMAudioPropsIsBufferSilence(&pStream->pStream->Cfg.Props, pvBuf, cbBuf);
    929 
    930     LogRel2(("ValKit: Playing stream '%s' (%RU32 bytes / %RU64ms -- %RU64 bytes / %RU64ms total so far) ...\n",
     986    /* Flag indicating whether the whole block we're going to play is silence or not. */
     987    bool const fIsAllSilence = PDMAudioPropsIsBufferSilence(&pStream->pStream->Cfg.Props, pvBuf, cbBuf);
     988
     989    LogRel3(("ValKit: Playing stream '%s' (%RU32 bytes / %RU64ms -- %RU64 bytes / %RU64ms total so far) ...\n",
    931990             pStream->pStream->Cfg.szName,
    932991             cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf),
     
    9661025    }
    9671026
    968     if (fIsSilence)
     1027    if (fIsAllSilence)
    9691028    {
    9701029        pThis->cbPlayedSilence += cbBuf;
     
    9781037    }
    9791038
    980     bool fHandleSilence = true;
    981 
    982     if (pTst->pEntry == NULL) /* Test not started yet? */
     1039    if (pTst->enmState == VALKITTESTSTATE_INIT) /* Test not started yet? */
    9831040    {
    9841041        AUDIOTESTPARMS Parms;
     
    10031060            RTTimeToString(&Parms.TestTone.Hdr.tsCreated, szTimeCreated, sizeof(szTimeCreated));
    10041061            LogRel(("ValKit: Test created (caller UTC): %s\n", szTimeCreated));
     1062
     1063            pTst->enmState = VALKITTESTSTATE_PRE;
    10051064        }
    10061065    }
     
    10101069    if (RT_SUCCESS(rc))
    10111070    {
    1012         if (   !fIsSilence
    1013             || (fIsSilence && fHandleSilence))
    1014         {
    1015             rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbBuf);
    1016             pTst->t.TestTone.u.Play.cbRead += cbBuf;
    1017 
    1018             const bool fComplete = pTst->t.TestTone.u.Play.cbRead >= pTst->t.TestTone.u.Play.cbToRead;
    1019             if (fComplete)
     1071        /* Always write (record) everything, no matter if the current audio contains complete silence or not.
     1072         * Might be also become handy later if we want to have a look at start/stop timings and so on. */
     1073        rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbBuf);
     1074
     1075        switch (pTst->enmState)
     1076        {
     1077            case VALKITTESTSTATE_PRE:
     1078                RT_FALL_THROUGH();
     1079            case VALKITTESTSTATE_POST:
    10201080            {
    1021                 LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
    1022                         pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
    1023 
    1024                 if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
    1025                     LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
    1026                             pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
    1027 
    1028                 AudioTestSetTestDone(pTst->pEntry);
    1029 
    1030                 rc = RTCritSectEnter(&pThis->CritSect);
    1031                 if (RT_SUCCESS(rc))
     1081                PAUDIOTESTTONEBEACON pBeacon = &pTst->t.TestTone.Beacon;
     1082                if (    AudioTestBeaconGetSize(pBeacon)
     1083                    && !AudioTestBeaconIsComplete(pBeacon))
    10321084                {
    1033                     drvHostValKiUnregisterPlayTest(pThis, pTst);
    1034 
    1035                     pThis->pTestCurPlay = NULL;
    1036                     pTst                = NULL;
    1037 
    1038                     rc2 = RTCritSectLeave(&pThis->CritSect);
    1039                     if (RT_SUCCESS(rc))
    1040                         rc = rc2;
     1085                    bool const fStarted = AudioTestBeaconGetRemaining(pBeacon) == AudioTestBeaconGetSize(pBeacon);
     1086
     1087                    uint32_t const cbToAddMax = RT_MIN(cbBuf, AudioTestBeaconGetRemaining(pBeacon));
     1088
     1089                    AudioTestBeaconAddConsecutive(pBeacon, (uint8_t *)pvBuf, cbToAddMax);
     1090
     1091                    if (fStarted)
     1092                        LogRel2(("ValKit: Test #%RU32: Detection of %s playback beacon started (%RU32ms played so far)\n",
     1093                                 pTst->idxTest, AudioTestBeaconTypeGetName(pBeacon->enmType),
     1094                                 PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, pThis->cbPlayedTotal)));
     1095                    if (AudioTestBeaconIsComplete(pBeacon))
     1096                    {
     1097                        LogRel2(("ValKit: Test #%RU32: Detection of %s playback beacon ended\n",
     1098                                 pTst->idxTest, AudioTestBeaconTypeGetName(pBeacon->enmType)));
     1099
     1100                        if (pTst->enmState == VALKITTESTSTATE_PRE)
     1101                            pTst->enmState = VALKITTESTSTATE_RUN;
     1102                        else if (pTst->enmState == VALKITTESTSTATE_POST)
     1103                            pTst->enmState = VALKITTESTSTATE_DONE;
     1104                    }
    10411105                }
     1106
     1107                break;
    10421108            }
     1109
     1110            case VALKITTESTSTATE_RUN:
     1111            {
     1112                /* Whether we count all silence as recorded data or not.
     1113                 * Currently we don't, as otherwise consequtively played tones will be cut off in the end. */
     1114                bool const fCountAllSilenceAsData = false;
     1115                if (   !fIsAllSilence
     1116                    || (fIsAllSilence == fCountAllSilenceAsData))
     1117                    pTst->t.TestTone.u.Play.cbRead += cbBuf;
     1118
     1119                const bool fComplete = pTst->t.TestTone.u.Play.cbRead >= pTst->t.TestTone.u.Play.cbToRead;
     1120                if (fComplete)
     1121                {
     1122                    LogRel(("ValKit: Test #%RU32: Recording audio data ended (took %RU32ms)\n",
     1123                            pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
     1124
     1125                    if (pTst->t.TestTone.u.Play.cbRead > pTst->t.TestTone.u.Play.cbToRead)
     1126                        LogRel(("ValKit: Warning: Test #%RU32 read %RU32 bytes more than announced\n",
     1127                                pTst->idxTest, pTst->t.TestTone.u.Play.cbRead - pTst->t.TestTone.u.Play.cbToRead));
     1128
     1129                    pTst->enmState = VALKITTESTSTATE_POST;
     1130                    /* Re-use the beacon object, but this time it's the post beacon. */
     1131                    AudioTestBeaconInit(&pTst->t.TestTone.Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_POST, &pTst->t.TestTone.Parms.Props);
     1132                }
     1133                break;
     1134            }
     1135
     1136            case VALKITTESTSTATE_DONE:
     1137            {
     1138                /* Handled below. */
     1139                break;
     1140            }
     1141
     1142            default:
     1143                AssertFailed();
     1144                break;
    10431145        }
    10441146
    10451147        /* Always report everything as being played. */
    10461148        cbWritten = cbBuf;
     1149    }
     1150
     1151    if (pTst->enmState == VALKITTESTSTATE_DONE)
     1152    {
     1153        AudioTestSetTestDone(pTst->pEntry);
     1154
     1155        rc = RTCritSectEnter(&pThis->CritSect);
     1156        if (RT_SUCCESS(rc))
     1157        {
     1158            drvHostValKiUnregisterPlayTest(pThis, pTst);
     1159
     1160            pThis->pTestCurPlay = NULL;
     1161            pTst                = NULL;
     1162
     1163            rc2 = RTCritSectLeave(&pThis->CritSect);
     1164            if (RT_SUCCESS(rc))
     1165                rc = rc2;
     1166        }
    10471167    }
    10481168
     
    10801200    PVALKITTESTDATA     pTst        = NULL;
    10811201
    1082     LogRel2(("ValKit: Capturing stream '%s' (%RU32 bytes / %RU64ms -- %RU64 bytes / %RU64ms total so far) ...\n",
     1202    LogRel3(("ValKit: Capturing stream '%s' (%RU32 bytes / %RU64ms -- %RU64 bytes / %RU64ms total so far) ...\n",
    10831203             pStream->pStream->Cfg.szName,
    10841204             cbBuf, PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbBuf),
     
    11181238    uint32_t cbWritten = 0;
    11191239
    1120     /* Start playing the post beacon? */
    1121     if (pTst->t.TestTone.u.Rec.cbWritten == pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbBeaconToWrite)
    1122         pTst->t.TestTone.u.Rec.cbBeaconWritten = 0;
    1123 
    1124     /* Any beacon to write? */
    1125     if (   pTst->t.TestTone.u.Rec.cbBeaconToWrite
    1126         && pTst->t.TestTone.u.Rec.cbBeaconWritten < pTst->t.TestTone.u.Rec.cbBeaconToWrite)
    1127     {
    1128         /* Limit to exactly one beacon (pre or post). */
    1129         uint32_t const cbToWrite = RT_MIN(cbBuf,
    1130                                           pTst->t.TestTone.u.Rec.cbBeaconToWrite - pTst->t.TestTone.u.Rec.cbBeaconWritten);
    1131         memset(pvBuf,
    1132                  pTst->t.TestTone.u.Rec.cbWritten >= pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbBeaconToWrite
    1133                ? AUDIOTEST_BEACON_BYTE_POST : AUDIOTEST_BEACON_BYTE_PRE,
    1134                cbToWrite);
    1135 
    1136         cbWritten = cbToWrite;
    1137 
    1138         pTst->t.TestTone.u.Rec.cbBeaconWritten += cbWritten;
    1139         Assert(pTst->t.TestTone.u.Rec.cbBeaconWritten <= pTst->t.TestTone.u.Rec.cbBeaconToWrite);
    1140 
    1141         rc = VINF_SUCCESS;
    1142     }
    1143     else
    1144     {
    1145         uint32_t const cbToWrite = RT_MIN(cbBuf,
    1146                                             (pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbBeaconToWrite)
    1147                                           - pTst->t.TestTone.u.Rec.cbWritten);
    1148         if (cbToWrite)
    1149             rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, cbToWrite, &cbWritten);
    1150         if (   RT_SUCCESS(rc)
    1151             && cbWritten)
    1152         {
    1153             Assert(cbWritten == cbToWrite);
    1154 
    1155             if (cbWritten > pStrmValKit->cbAvail)
    1156                 LogRel(("ValKit: Warning: Test #%RU32: Reading more from capturing stream than availabe for (%RU32 vs. %RU32)\n",
    1157                         pTst->idxTest, cbWritten, pStrmValKit->cbAvail));
    1158         }
    1159     }
    1160 
    1161     if (RT_SUCCESS(rc))
    1162     {
    1163         rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbWritten);
    1164         if (RT_SUCCESS(rc))
    1165         {
    1166             pThis->cbRecordedTotal += cbWritten; /* Do a bit of accounting. */
    1167 
    1168             pStrmValKit->cbAvail   -= RT_MIN(pStrmValKit->cbAvail, cbWritten);
    1169 
    1170             pTst->t.TestTone.u.Rec.cbWritten += cbWritten;
    1171             Assert(pTst->t.TestTone.u.Rec.cbWritten <= pTst->t.TestTone.u.Rec.cbToWrite);
    1172 
    1173             LogRel(("ValKit: Test #%RU32: Supplied %RU32 bytes of (capturing) audio data (%RU32 bytes left)\n",
    1174                     pTst->idxTest, cbWritten, pStrmValKit->cbAvail));
     1240    switch (pTst->enmState)
     1241    {
     1242        case VALKITTESTSTATE_PRE:
     1243            RT_FALL_THROUGH();
     1244        case VALKITTESTSTATE_POST:
     1245        {
     1246            PAUDIOTESTTONEBEACON pBeacon = &pTst->t.TestTone.Beacon;
     1247            if (    AudioTestBeaconGetSize(pBeacon)
     1248                && !AudioTestBeaconIsComplete(pBeacon))
     1249            {
     1250                bool const fStarted = AudioTestBeaconGetRemaining(pBeacon) == AudioTestBeaconGetSize(pBeacon);
     1251
     1252                uint32_t const cbBeaconRemaining = AudioTestBeaconGetRemaining(pBeacon);
     1253                AssertBreakStmt(cbBeaconRemaining, VERR_WRONG_ORDER);
     1254
     1255                /* Limit to exactly one beacon (pre or post). */
     1256                uint32_t const cbToWrite = RT_MIN(cbBuf, cbBeaconRemaining);
     1257
     1258                rc = AudioTestBeaconWrite(pBeacon, pvBuf, cbToWrite);
     1259                if (RT_SUCCESS(rc))
     1260                    cbWritten = cbToWrite;
     1261
     1262                if (fStarted)
     1263                    LogRel2(("ValKit: Test #%RU32: Writing %s beacon begin\n",
     1264                                       pTst->idxTest, AudioTestBeaconTypeGetName(pBeacon->enmType)));
     1265                if (AudioTestBeaconIsComplete(pBeacon))
     1266                {
     1267                    LogRel2(("ValKit: Test #%RU32: Writing %s beacon end\n",
     1268                             pTst->idxTest, AudioTestBeaconTypeGetName(pBeacon->enmType)));
     1269
     1270                    if (pTst->enmState == VALKITTESTSTATE_PRE)
     1271                        pTst->enmState = VALKITTESTSTATE_RUN;
     1272                    else if (pTst->enmState == VALKITTESTSTATE_POST)
     1273                        pTst->enmState = VALKITTESTSTATE_DONE;
     1274                }
     1275            }
     1276            break;
     1277        }
     1278
     1279        case VALKITTESTSTATE_RUN:
     1280        {
     1281            uint32_t const cbToWrite = RT_MIN(cbBuf, pTst->t.TestTone.u.Rec.cbToWrite - pTst->t.TestTone.u.Rec.cbWritten);
     1282            if (cbToWrite)
     1283                rc = AudioTestToneGenerate(&pTst->t.TestTone.Tone, pvBuf, cbToWrite, &cbWritten);
     1284            if (   RT_SUCCESS(rc)
     1285                && cbWritten)
     1286            {
     1287                Assert(cbWritten == cbToWrite);
     1288
     1289                if (cbWritten > pStrmValKit->cbAvail)
     1290                    LogRel(("ValKit: Warning: Test #%RU32: Reading more from capturing stream than availabe for (%RU32 vs. %RU32)\n",
     1291                            pTst->idxTest, cbWritten, pStrmValKit->cbAvail));
     1292
     1293                pTst->t.TestTone.u.Rec.cbWritten += cbWritten;
     1294            }
     1295
     1296            LogRel3(("ValKit: Test #%RU32: Supplied %RU32 bytes of (capturing) audio data (%RU32 bytes left)\n",
     1297                     pTst->idxTest, cbWritten, pStrmValKit->cbAvail));
    11751298
    11761299            const bool fComplete = pTst->t.TestTone.u.Rec.cbWritten >= pTst->t.TestTone.u.Rec.cbToWrite;
     
    11801303                        pTst->idxTest, RTTimeMilliTS() - pTst->msStartedTS));
    11811304
    1182                 AudioTestSetTestDone(pTst->pEntry);
    1183 
    1184                 rc = RTCritSectEnter(&pThis->CritSect);
    1185                 if (RT_SUCCESS(rc))
    1186                 {
    1187                     drvHostValKiUnregisterRecTest(pThis, pTst);
    1188 
    1189                     pThis->pTestCurRec = NULL;
    1190                     pTst               = NULL;
    1191 
    1192                     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1193                     AssertRC(rc2);
    1194                 }
     1305                pTst->enmState = VALKITTESTSTATE_POST;
     1306                /* Re-use the beacon object, but this time it's the post beacon. */
     1307                AudioTestBeaconInit(&pTst->t.TestTone.Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_POST, &pTst->t.TestTone.Parms.Props);
     1308                pStrmValKit->cbAvail += AudioTestBeaconGetSize(&pTst->t.TestTone.Beacon);
    11951309            }
     1310            break;
     1311        }
     1312
     1313        case VALKITTESTSTATE_DONE:
     1314        {
     1315            /* Handled below. */
     1316            break;
     1317        }
     1318
     1319        default:
     1320            AssertFailed();
     1321            break;
     1322    }
     1323
     1324    if (RT_SUCCESS(rc))
     1325    {
     1326        rc = AudioTestObjWrite(pTst->Obj, pvBuf, cbWritten);
     1327        if (RT_SUCCESS(rc))
     1328            pStrmValKit->cbAvail -= RT_MIN(pStrmValKit->cbAvail, cbWritten);
     1329    }
     1330
     1331    if (pTst->enmState == VALKITTESTSTATE_DONE)
     1332    {
     1333        AudioTestSetTestDone(pTst->pEntry);
     1334
     1335        rc = RTCritSectEnter(&pThis->CritSect);
     1336        if (RT_SUCCESS(rc))
     1337        {
     1338            drvHostValKiUnregisterRecTest(pThis, pTst);
     1339
     1340            pThis->pTestCurRec = NULL;
     1341            pTst               = NULL;
     1342
     1343            int rc2 = RTCritSectLeave(&pThis->CritSect);
     1344            AssertRC(rc2);
    11961345        }
    11971346    }
     
    12031352        LogRel(("ValKit: Test #%RU32: Failed with %Rrc\n", pTst->idxTest, rc));
    12041353    }
     1354
     1355    pThis->cbRecordedTotal += cbWritten; /* Do a bit of accounting. */
    12051356
    12061357    *pcbRead = cbWritten;
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCommon.cpp

    r92058 r92195  
    525525        uint32_t cbPlayedTotal  = 0;
    526526
    527         /* We play a pre + post beacon before + after the actual test tone
    528          * with exactly AUDIOTEST_BEACON_SIZE_FRAMES audio frames. */
    529         uint32_t const cbBeacon       = PDMAudioPropsFramesToBytes(&pStream->Cfg.Props, AUDIOTEST_BEACON_SIZE_FRAMES);
    530         uint32_t       cbBeaconToPlay = cbBeacon;
    531         uint32_t       cbBeaconPlayed = 0;
    532 
     527        /* We play a pre + post beacon before + after the actual test tone.
     528         * We always start with the pre beacon. */
     529        AUDIOTESTTONEBEACON Beacon;
     530        AudioTestBeaconInit(&Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_PRE, &pStream->Cfg.Props);
     531
     532        uint32_t const cbBeacon = AudioTestBeaconGetSize(&Beacon);
    533533        if (cbBeacon)
    534534        {
    535             RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Playing 2 x %RU32 bytes pre/post beacons\n", cbBeaconToPlay);
     535            RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Playing 2 x %RU32 bytes pre/post beacons\n", cbBeacon);
    536536            cbToPlayTotal += cbBeacon * 2 /* Pre + post beacon */;
    537537        }
     
    539539        if (pTstEnv)
    540540        {
     541            AudioTestObjAddMetadataStr(Obj, "beacon_type=%RU32\n", (uint32_t)AudioTestBeaconGetType(&Beacon));
    541542            AudioTestObjAddMetadataStr(Obj, "beacon_pre_bytes=%RU32\n", cbBeacon);
    542543            AudioTestObjAddMetadataStr(Obj, "beacon_post_bytes=%RU32\n", cbBeacon);
     
    591592
    592593                /* Any beacon to play? */
    593                 if (   cbBeaconToPlay
    594                     && cbBeaconPlayed < cbBeaconToPlay)
     594                uint32_t const cbBeaconRemaining = AudioTestBeaconGetRemaining(&Beacon);
     595                if (cbBeaconRemaining)
    595596                {
    596597                    /* Limit to exactly one beacon (pre or post). */
    597                     cbToPlay = RT_MIN(sizeof(abBuf), RT_MIN(cbCanWrite, cbBeaconToPlay - cbBeaconPlayed));
    598                     memset(abBuf,
    599                            cbPlayedTotal >= cbToPlayTotal - cbBeaconToPlay ? AUDIOTEST_BEACON_BYTE_POST : AUDIOTEST_BEACON_BYTE_PRE,
    600                            cbToPlay);
    601 
    602                     rc = AudioTestMixStreamPlay(&pStream->Mix, abBuf, cbToPlay, &cbPlayed);
     598                    cbToPlay = RT_MIN(sizeof(abBuf), RT_MIN(cbCanWrite, cbBeaconRemaining));
     599                    rc = AudioTestBeaconWrite(&Beacon, abBuf, cbToPlay);
     600                    if (RT_SUCCESS(rc))
     601                        rc = AudioTestMixStreamPlay(&pStream->Mix, abBuf, cbToPlay, &cbPlayed);
    603602                    if (RT_FAILURE(rc))
    604603                        break;
     
    611610                        rc = AudioTestObjWrite(Obj, abBuf, cbPlayed);
    612611                    }
    613 
    614                     cbBeaconPlayed += cbPlayed;
    615                     cbPlayedTotal  += cbPlayed;
    616                     continue;
    617612                }
    618 
    619                 /* Start playing the post beacon? */
    620                 if (cbPlayedTotal == cbToPlayTotal - cbBeaconToPlay)
     613                else /* Play test tone */
    621614                {
    622                     cbBeaconPlayed = 0;
    623                     continue;
    624                 }
    625 
    626                 if (RT_FAILURE(rc))
    627                     break;
    628 
    629                 uint32_t const cbToGenerate = RT_MIN(RT_MIN(cbToPlayTotal - cbPlayedTotal - cbBeaconToPlay, sizeof(abBuf)),
    630                                                      cbCanWrite);
    631                 rc = AudioTestToneGenerate(&TstTone, abBuf, cbToGenerate, &cbToPlay);
    632                 if (RT_SUCCESS(rc))
    633                 {
    634                     if (pTstEnv)
     615                    uint32_t const cbTestToneToPlay = cbToPlayTotal - cbPlayedTotal - (cbBeacon /* Pre / post beacon */);
     616                    if (cbTestToneToPlay == 0) /* Done playing the test tone? */
    635617                    {
    636                         /* Write stuff to disk before trying to play it. Help analysis later. */
    637                         rc = AudioTestObjWrite(Obj, abBuf, cbToPlay);
     618                        if (AudioTestBeaconGetSize(&Beacon)) /* Play the post beacon, if any. */
     619                        {
     620                            AudioTestBeaconInit(&Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_POST, &pStream->Cfg.Props);
     621                            continue;
     622                        }
     623
     624                        break;
    638625                    }
     626
     627                    uint32_t const cbToGenerate = RT_MIN(RT_MIN(cbTestToneToPlay, sizeof(abBuf)), cbCanWrite);
     628                    rc = AudioTestToneGenerate(&TstTone, abBuf, cbToGenerate, &cbToPlay);
    639629                    if (RT_SUCCESS(rc))
    640630                    {
    641                         rc = AudioTestMixStreamPlay(&pStream->Mix, abBuf, cbToPlay, &cbPlayed);
     631                        if (pTstEnv)
     632                        {
     633                            /* Write stuff to disk before trying to play it. Help analysis later. */
     634                            rc = AudioTestObjWrite(Obj, abBuf, cbToPlay);
     635                        }
    642636                        if (RT_SUCCESS(rc))
    643637                        {
    644                             AssertBreakStmt(cbPlayed <= cbToPlay, rc = VERR_TOO_MUCH_DATA);
    645 
    646                             offStream += cbPlayed;
    647 
    648                             if (cbPlayed != cbToPlay)
    649                                 RTTestFailed(g_hTest, "Only played %RU32/%RU32 bytes", cbPlayed, cbToPlay);
    650 
    651                             if (cbPlayed)
    652                                 nsLastWrite = nsNow;
     638                            rc = AudioTestMixStreamPlay(&pStream->Mix, abBuf, cbToPlay, &cbPlayed);
     639                            if (RT_SUCCESS(rc))
     640                            {
     641                                AssertBreakStmt(cbPlayed <= cbToPlay, rc = VERR_TOO_MUCH_DATA);
     642
     643                                offStream += cbPlayed;
     644
     645                                if (cbPlayed != cbToPlay)
     646                                    RTTestFailed(g_hTest, "Only played %RU32/%RU32 bytes", cbPlayed, cbToPlay);
     647
     648                                if (cbPlayed)
     649                                    nsLastWrite = nsNow;
     650                            }
    653651                        }
    654652                    }
     
    746744    if (RT_SUCCESS(rc))
    747745    {
    748         uint64_t cbToRecTotal = PDMAudioPropsMilliToBytes(&pStream->Cfg.Props, pParms->msDuration);
    749 
    750         /* We record a pre + post beacon before + after the actual test tone
    751          * with exactly AUDIOTEST_BEACON_SIZE_FRAMES audio frames. */
    752         uint32_t const cbBeacon = PDMAudioPropsFramesToBytes(&pStream->Cfg.Props, AUDIOTEST_BEACON_SIZE_FRAMES);
     746        uint64_t cbRecTotal  = 0; /* Counts everything, including silence / whatever. */
     747        uint64_t cbTestToRec = PDMAudioPropsMilliToBytes(&pStream->Cfg.Props, pParms->msDuration);
     748
     749        /* We expect a pre + post beacon before + after the actual test tone.
     750         * We always start with the pre beacon. */
     751        AUDIOTESTTONEBEACON Beacon;
     752        AudioTestBeaconInit(&Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_PRE, &pStream->Cfg.Props);
     753
     754        uint32_t const cbBeacon = AudioTestBeaconGetSize(&Beacon);
    753755        if (cbBeacon)
    754756        {
    755             RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Recording 2 x %RU32 bytes pre/post beacons\n", cbBeacon);
    756             cbToRecTotal += cbBeacon * 2 /* Pre + post beacon */;
    757 
    758             AudioTestObjAddMetadataStr(Obj, "beacon_pre_bytes=%RU32\n", cbBeacon);
    759             AudioTestObjAddMetadataStr(Obj, "beacon_post_bytes=%RU32\n", cbBeacon);
    760         }
    761 
    762         AudioTestObjAddMetadataStr(Obj, "stream_to_record_bytes=%RU32\n", cbToRecTotal);
     757            RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Expecting 2 x %RU32 bytes pre/post beacons\n", cbBeacon);
     758            cbTestToRec = cbBeacon * 2 /* Pre + post beacon */;
     759        }
     760
     761        AudioTestObjAddMetadataStr(Obj, "beacon_type=%RU32\n", (uint32_t)AudioTestBeaconGetType(&Beacon));
     762        AudioTestObjAddMetadataStr(Obj, "beacon_pre_bytes=%RU32\n", cbBeacon);
     763        AudioTestObjAddMetadataStr(Obj, "beacon_post_bytes=%RU32\n", cbBeacon);
     764        AudioTestObjAddMetadataStr(Obj, "stream_to_record_bytes=%RU32\n", cbTestToRec);
    763765        AudioTestObjAddMetadataStr(Obj, "stream_buffer_size_ms=%RU32\n", pIoOpts->cMsBufferSize);
    764766        AudioTestObjAddMetadataStr(Obj, "stream_prebuf_size_ms=%RU32\n", pIoOpts->cMsPreBuffer);
     
    767769        AudioTestObjAddMetadataStr(Obj, "device_scheduling_hint_ms=%RU32\n", pIoOpts->cMsSchedulingHint);
    768770
    769         RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Recording %RU32 bytes total\n", cbToRecTotal);
     771        RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Recording %RU32 bytes total\n", cbTestToRec);
    770772
    771773        uint8_t         abSamples[16384];
    772         uint32_t const  cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples));
    773         uint64_t        cbRecTotal  = 0;
     774        uint32_t const  cbSamplesAligned  = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples));
     775        uint64_t        cbTestRec         = 0;
    774776
    775777        uint64_t const  nsStarted         = RTTimeNanoTS();
     
    778780        uint64_t        nsLastMsgCantRead = 0; /* Timestamp (in ns) when the last message of an unreadable stream was shown. */
    779781
    780         while (!g_fTerminate && cbRecTotal < cbToRecTotal)
     782        while (!g_fTerminate && cbTestRec < cbTestToRec)
    781783        {
    782784            uint64_t const nsNow = RTTimeNanoTS();
     
    799801                    if (cbRecorded)
    800802                    {
     803                        cbRecTotal += cbRecorded;
     804
    801805                        rc = AudioTestObjWrite(Obj, abSamples, cbRecorded);
    802806                        if (RT_SUCCESS(rc))
    803807                        {
    804                             cbRecTotal += cbRecorded;
    805 
    806                             /** @todo Clamp result? */
     808                            if (AudioTestBeaconGetSize(&Beacon))
     809                            {
     810                                if (!AudioTestBeaconIsComplete(&Beacon))
     811                                {
     812                                    bool const fStarted = AudioTestBeaconGetRemaining(&Beacon) == AudioTestBeaconGetSize(&Beacon);
     813
     814                                    uint32_t const cbToAddMax = RT_MIN(cbRecorded, AudioTestBeaconGetRemaining(&Beacon));
     815
     816                                    uint32_t const cbAdded = AudioTestBeaconAddConsecutive(&Beacon, abSamples, cbToAddMax);
     817                                    if (cbAdded)
     818                                        cbTestRec += cbAdded; /* Only count data which belongs to a (complete test tone). */
     819
     820                                    if (   fStarted
     821                                        && g_uVerbosity >= 2)
     822                                        RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS,
     823                                                     "Detection of %s playback beacon started (%RU32ms recorded so far)\n",
     824                                                     AudioTestBeaconTypeGetName(Beacon.enmType),
     825                                                     PDMAudioPropsBytesToMilli(&pStream->pStream->Cfg.Props, cbRecTotal));
     826
     827                                    if (AudioTestBeaconIsComplete(&Beacon))
     828                                    {
     829                                        if (g_uVerbosity >= 2)
     830                                            RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Detection of %s playback beacon ended\n",
     831                                                         AudioTestBeaconTypeGetName(Beacon.enmType));
     832                                    }
     833                                }
     834                                else
     835                                {
     836                                    uint32_t const cbTestToneToRec = cbTestToRec - cbTestRec - cbBeacon;
     837                                    if (cbTestToneToRec == 0) /* Done recording the test tone? */
     838                                    {
     839                                        AudioTestBeaconInit(&Beacon, AUDIOTESTTONEBEACONTYPE_PLAY_POST, &pStream->Cfg.Props);
     840                                    }
     841                                    else /* Count test tone data. */
     842                                        cbTestRec += cbRecorded;
     843                                }
     844                            }
    807845                        }
    808846                    }
     
    836874        }
    837875
    838         if (cbRecTotal != cbToRecTotal)
    839             RTTestFailed(g_hTest, "Recording ended unexpectedly (%RU32/%RU32 recorded)\n", cbRecTotal, cbToRecTotal);
     876        if (cbTestRec != cbTestToRec)
     877            RTTestFailed(g_hTest, "Recording ended unexpectedly (%RU32/%RU32 recorded)\n", cbTestRec, cbTestToRec);
    840878
    841879        int rc2 = AudioTestMixStreamDisable(pMix);
Note: See TracChangeset for help on using the changeset viewer.

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