VirtualBox

Changeset 90723 in vbox


Ignore:
Timestamp:
Aug 18, 2021 3:41:36 PM (3 years ago)
Author:
vboxsync
Message:

Audio/VKAT: Implemented ability to play test tones locally (for example 'play -ttt'). ​bugref:10008

Location:
trunk/src/VBox/ValidationKit/utils/audio
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCmdGeneric.cpp

    r90087 r90723  
    3131#include <iprt/errcore.h>
    3232#include <iprt/message.h>
     33#include <iprt/rand.h>
    3334#include <iprt/test.h>
    3435
     
    366367}
    367368
     369/**
     370 * Worker for audioTestCmdPlayHandler that plays one test tone.
     371 */
     372static RTEXITCODE audioTestPlayTestToneOne(PAUDIOTESTTONEPARMS pToneParms,
     373                                           PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
     374                                           uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
     375                                           uint8_t cChannels, uint8_t cbSample, uint32_t uHz,
     376                                           bool fWithDrvAudio, bool fWithMixer)
     377{
     378    char szTmp[128];
     379
     380    AUDIOTESTSTREAM TstStream;
     381    RT_ZERO(TstStream);
     382
     383    /*
     384     * Construct the driver stack.
     385     */
     386    RTEXITCODE          rcExit = RTEXITCODE_FAILURE;
     387    AUDIOTESTDRVSTACK   DrvStack;
     388    int rc = audioTestDriverStackInit(&DrvStack, pDrvReg, fWithDrvAudio);
     389    if (RT_SUCCESS(rc))
     390    {
     391        /*
     392         * Set the output device if one is specified.
     393         */
     394        rc = audioTestDriverStackSetDevice(&DrvStack, PDMAUDIODIR_OUT, pszDevId);
     395        if (RT_SUCCESS(rc))
     396        {
     397            /*
     398             * Open a stream for the output.
     399             */
     400            PDMAUDIOPCMPROPS ReqProps = pToneParms->Props;
     401            if (cChannels != 0 && PDMAudioPropsChannels(&ReqProps) != cChannels)
     402                PDMAudioPropsSetChannels(&ReqProps, cChannels);
     403            if (cbSample != 0)
     404                PDMAudioPropsSetSampleSize(&ReqProps, cbSample);
     405            if (uHz != 0)
     406                ReqProps.uHz = uHz;
     407
     408            rc = audioTestDriverStackStreamCreateOutput(&DrvStack, &ReqProps, cMsBufferSize,
     409                                                        cMsPreBuffer, cMsSchedulingHint, &TstStream.pStream, &TstStream.Cfg);
     410            if (RT_SUCCESS(rc))
     411            {
     412                /*
     413                 * Automatically enable the mixer if the wave file and the
     414                 * output parameters doesn't match.
     415                 */
     416                if (   !fWithMixer
     417                    && !PDMAudioPropsAreEqual(&pToneParms->Props, &TstStream.pStream->Cfg.Props))
     418                {
     419                    RTMsgInfo("Enabling the mixer buffer.\n");
     420                    fWithMixer = true;
     421                }
     422
     423                /*
     424                 * Create a mixer wrapper.  This is just a thin wrapper if fWithMixer
     425                 * is false, otherwise it's doing mixing, resampling and recoding.
     426                 */
     427                rc = AudioTestMixStreamInit(&TstStream.Mix, &DrvStack, TstStream.pStream, fWithMixer ? &pToneParms->Props : NULL, 100 /*ms*/);
     428                if (RT_SUCCESS(rc))
     429                {
     430                    if (g_uVerbosity > 0)
     431                        RTMsgInfo("Stream: %s cbBackend=%#RX32%s\n",
     432                                  PDMAudioPropsToString(&TstStream.pStream->Cfg.Props, szTmp, sizeof(szTmp)),
     433                                  TstStream.pStream->cbBackend, fWithMixer ? " mixed" : "");
     434
     435                    /*
     436                     * Enable the stream and start playing.
     437                     */
     438                    rc = AudioTestMixStreamEnable(&TstStream.Mix);
     439                    if (RT_SUCCESS(rc))
     440                    {
     441                        rc = audioTestPlayTone(NULL /* pTstEnv */, &TstStream, pToneParms);
     442                        if (RT_SUCCESS(rc))
     443                            rcExit = RTEXITCODE_SUCCESS;
     444                    }
     445                    else
     446                        rcExit = RTMsgErrorExitFailure("Enabling the output stream failed: %Rrc", rc);
     447
     448                    /*
     449                     * Clean up.
     450                     */
     451                    AudioTestMixStreamTerm(&TstStream.Mix);
     452                }
     453                audioTestDriverStackStreamDestroy(&DrvStack, TstStream.pStream);
     454            }
     455            else
     456                rcExit = RTMsgErrorExitFailure("Creating output stream failed: %Rrc", rc);
     457        }
     458        else
     459            rcExit = RTMsgErrorExitFailure("Failed to set output device to '%s': %Rrc", pszDevId, rc);
     460        audioTestDriverStackDelete(&DrvStack);
     461    }
     462    else
     463        rcExit = RTMsgErrorExitFailure("Driver stack construction failed: %Rrc", rc);
     464    return rcExit;
     465}
     466
    368467
    369468/**
     
    377476    { "--frequency",        'f',                          RTGETOPT_REQ_UINT32 },
    378477    { "--sample-size",      'z',                          RTGETOPT_REQ_UINT8 },
     478    { "--test-tone",        't',                          RTGETOPT_REQ_NOTHING },
    379479    { "--output-device",    'o',                          RTGETOPT_REQ_STRING  },
    380480    { "--with-drv-audio",   'd',                          RTGETOPT_REQ_NOTHING },
     
    388488    switch (pOpt->iShort)
    389489    {
    390         case 'b': return "The audio backend to use.";
     490        case 'b': return "The audio backend to use";
    391491        case 'c': return "Number of backend output channels";
    392         case 'd': return "Go via DrvAudio instead of directly interfacing with the backend.";
     492        case 'd': return "Go via DrvAudio instead of directly interfacing with the backend";
    393493        case 'f': return "Output frequency (Hz)";
    394494        case 'z': return "Output sample size (bits)";
    395         case 'm': return "Go via the mixer.";
    396         case 'o': return "The ID of the output device to use.";
     495        case 't': return "Plays a test tone. Can be specified multiple times";
     496        case 'm': return "Go via the mixer";
     497        case 'o': return "The ID of the output device to use";
    397498        default:  return NULL;
    398499    }
     
    416517    bool        fWithDrvAudio       = false;
    417518    bool        fWithMixer          = false;
     519    uint32_t    cTestTones          = 0;
    418520    uint8_t     cbSample            = 0;
    419521    uint8_t     cChannels           = 0;
     
    453555                break;
    454556
     557            case 't':
     558                cTestTones++;
     559                break;
     560
    455561            case 'z':
    456562                cbSample = ValueUnion.u8 / 8;
     
    459565            case VINF_GETOPT_NOT_OPTION:
    460566            {
     567                if (cTestTones)
     568                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Playing test tones (-t) cannot be combined with playing files");
     569
    461570                RTEXITCODE rcExit = audioTestPlayOne(ValueUnion.psz, pDrvReg, pszDevId, cMsBufferSize, cMsPreBuffer,
    462571                                                     cMsSchedulingHint, cChannels, cbSample, uHz, fWithDrvAudio, fWithMixer);
     
    472581        }
    473582    }
     583
     584    while (cTestTones--)
     585    {
     586        AUDIOTESTTONEPARMS ToneParms;
     587        RT_ZERO(ToneParms);
     588
     589        /* Use some sane defaults if no PCM props are set by the user. */
     590        PDMAudioPropsInit(&ToneParms.Props,
     591                          cbSample ? cbSample : 4, true /* fSigned */, cChannels ? cChannels : 2, uHz ? uHz : 44100);
     592
     593        ToneParms.dbFreqHz       = AudioTestToneGetRandomFreq();
     594        ToneParms.msPrequel      = 0; /** @todo Implement analyzing this first! */
     595#ifdef DEBUG_andy
     596        ToneParms.msDuration     = RTRandU32Ex(50, 2500);
     597#else
     598        ToneParms.msDuration     = RTRandU32Ex(0, RT_MS_10SEC); /** @todo Probably a bit too long, but let's see. */
     599#endif
     600        ToneParms.msSequel       = 0;   /** @todo Implement analyzing this first! */
     601        ToneParms.uVolumePercent = 100; /** @todo Implement analyzing this first! */
     602
     603        RTEXITCODE rcExit = audioTestPlayTestToneOne(&ToneParms, pDrvReg, pszDevId, cMsBufferSize, cMsPreBuffer,
     604                                                     cMsSchedulingHint, cChannels, cbSample, uHz, fWithDrvAudio, fWithMixer);
     605        if (rcExit != RTEXITCODE_SUCCESS)
     606            return rcExit;
     607    }
     608
    474609    return RTEXITCODE_SUCCESS;
    475610}
  • trunk/src/VBox/ValidationKit/utils/audio/vkatCommon.cpp

    r90683 r90723  
    239239 * @returns VBox status code.
    240240 * @param   pTstEnv             Test environment to use for running the test.
     241 *                              Optional and can be NULL (for simple playback only).
    241242 * @param   pStream             Stream to use for playing the tone.
    242243 * @param   pParms              Tone parameters to use.
     
    244245 * @note    Blocking function.
    245246 */
    246 static int audioTestPlayTone(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PAUDIOTESTTONEPARMS pParms)
     247int audioTestPlayTone(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PAUDIOTESTTONEPARMS pParms)
    247248{
    248249    AUDIOTESTTONE TstTone;
    249250    AudioTestToneInit(&TstTone, &pStream->Cfg.Props, pParms->dbFreqHz);
    250251
    251     const char *pcszPathOut = pTstEnv->Set.szPathAbs;
     252    char const *pcszPathOut = NULL;
     253    if (pTstEnv)
     254        pcszPathOut = pTstEnv->Set.szPathAbs;
    252255
    253256    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Playing test tone (tone frequency is %RU16Hz, %RU32ms)\n", (uint16_t)pParms->dbFreqHz, pParms->msDuration);
    254257    RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Using %RU32ms stream scheduling hint\n", pStream->Cfg.Device.cMsSchedulingHint);
    255     RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Writing to '%s'\n", pcszPathOut);
     258    if (pcszPathOut)
     259        RTTestPrintf(g_hTest, RTTESTLVL_ALWAYS, "Writing to '%s'\n", pcszPathOut);
     260
     261    int rc;
    256262
    257263    /** @todo Use .WAV here? */
    258264    AUDIOTESTOBJ Obj;
    259     int rc = AudioTestSetObjCreateAndRegister(&pTstEnv->Set, "guest-tone-play.pcm", &Obj);
    260     AssertRCReturn(rc, rc);
     265    if (pTstEnv)
     266    {
     267        rc = AudioTestSetObjCreateAndRegister(&pTstEnv->Set, "guest-tone-play.pcm", &Obj);
     268        AssertRCReturn(rc, rc);
     269    }
    261270
    262271    rc = AudioTestMixStreamEnable(&pStream->Mix);
     
    271280        RTTestPrintf(g_hTest, RTTESTLVL_DEBUG, "Playing %RU32 bytes total\n", cbToPlayTotal);
    272281
    273         AudioTestObjAddMetadataStr(Obj, "stream_to_play_bytes=%RU32\n",      cbToPlayTotal);
    274         AudioTestObjAddMetadataStr(Obj, "stream_period_size_frames=%RU32\n", pStream->Cfg.Backend.cFramesPeriod);
    275         AudioTestObjAddMetadataStr(Obj, "stream_buffer_size_frames=%RU32\n", pStream->Cfg.Backend.cFramesBufferSize);
    276         AudioTestObjAddMetadataStr(Obj, "stream_prebuf_size_frames=%RU32\n", pStream->Cfg.Backend.cFramesPreBuffering);
    277         /* Note: This mostly is provided by backend (e.g. PulseAudio / ALSA / ++) and
    278          *       has nothing to do with the device emulation scheduling hint. */
    279         AudioTestObjAddMetadataStr(Obj, "device_scheduling_hint_ms=%RU32\n", pStream->Cfg.Device.cMsSchedulingHint);
     282        if (pTstEnv)
     283        {
     284            AudioTestObjAddMetadataStr(Obj, "stream_to_play_bytes=%RU32\n",      cbToPlayTotal);
     285            AudioTestObjAddMetadataStr(Obj, "stream_period_size_frames=%RU32\n", pStream->Cfg.Backend.cFramesPeriod);
     286            AudioTestObjAddMetadataStr(Obj, "stream_buffer_size_frames=%RU32\n", pStream->Cfg.Backend.cFramesBufferSize);
     287            AudioTestObjAddMetadataStr(Obj, "stream_prebuf_size_frames=%RU32\n", pStream->Cfg.Backend.cFramesPreBuffering);
     288            /* Note: This mostly is provided by backend (e.g. PulseAudio / ALSA / ++) and
     289             *       has nothing to do with the device emulation scheduling hint. */
     290            AudioTestObjAddMetadataStr(Obj, "device_scheduling_hint_ms=%RU32\n", pStream->Cfg.Device.cMsSchedulingHint);
     291        }
    280292
    281293        PAUDIOTESTDRVMIXSTREAM pMix = &pStream->Mix;
     
    309321                if (RT_SUCCESS(rc))
    310322                {
    311                     /* Write stuff to disk before trying to play it. Help analysis later. */
    312                     rc = AudioTestObjWrite(Obj, abBuf, cbToPlay);
     323                    if (pTstEnv)
     324                    {
     325                        /* Write stuff to disk before trying to play it. Help analysis later. */
     326                        rc = AudioTestObjWrite(Obj, abBuf, cbToPlay);
     327                    }
    313328                    if (RT_SUCCESS(rc))
    314329                    {
     
    342357        rc = VERR_AUDIO_STREAM_NOT_READY;
    343358
    344     int rc2 = AudioTestObjClose(Obj);
    345     if (RT_SUCCESS(rc))
    346         rc = rc2;
     359    if (pTstEnv)
     360    {
     361        int rc2 = AudioTestObjClose(Obj);
     362        if (RT_SUCCESS(rc))
     363            rc = rc2;
     364    }
    347365
    348366    if (RT_FAILURE(rc))
  • trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h

    r90117 r90723  
    463463int         audioTestWorker(PAUDIOTESTENV pTstEnv);
    464464
     465/** @todo Test tone handling */
     466int         audioTestPlayTone(PAUDIOTESTENV pTstEnv, PAUDIOTESTSTREAM pStream, PAUDIOTESTTONEPARMS pParms);
     467/** @}  */
     468
    465469/** @name Command handlers
    466470 * @{ */
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