VirtualBox

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

File:
1 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}
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