VirtualBox

Changeset 89439 in vbox for trunk/src/VBox/ValidationKit


Ignore:
Timestamp:
Jun 1, 2021 7:41:40 PM (4 years ago)
Author:
vboxsync
Message:

ValKit/AudioTest: Mated the mixer to the play command and made it possible to control the backend stream parameters to test resampling and channel selection. bugref:10008

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

Legend:

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

    r89436 r89439  
    170170typedef AUDIOTESTSTREAM *PAUDIOTESTSTREAM;
    171171
     172/** Maximum audio streams a test environment can handle. */
     173#define AUDIOTESTENV_MAX_STREAMS 8
     174
    172175/**
    173176 * Audio test environment parameters.
     
    16441647
    16451648/**
     1649 * Worker for audioTestPlayOne.
     1650 */
     1651static RTEXITCODE audioTestPlayOneInner(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTWAVEFILE pWaveFile,
     1652                                        PCPDMAUDIOSTREAMCFG pCfgAcq, const char *pszFile)
     1653{
     1654    uint32_t const  cbPreBuffer = PDMAudioPropsFramesToBytes(pMix->pProps, pCfgAcq->Backend.cFramesPreBuffering);
     1655    uint64_t const  nsStarted   = RTTimeNanoTS();
     1656
     1657    /*
     1658     * Transfer data as quickly as we're allowed.
     1659     */
     1660    uint8_t         abSamples[16384];
     1661    uint32_t const  cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(pMix->pProps, sizeof(abSamples));
     1662    uint64_t        offStream        = 0;
     1663    for (;;)
     1664    {
     1665        /* Read a chunk from the wave file. */
     1666        size_t      cbSamples = 0;
     1667        int rc = AudioTestWaveFileRead(pWaveFile, abSamples, cbSamplesAligned, &cbSamples);
     1668        if (RT_SUCCESS(rc) && cbSamples > 0)
     1669        {
     1670            /* Pace ourselves a little. */
     1671            if (offStream >= cbPreBuffer)
     1672            {
     1673                uint64_t const cNsWritten = PDMAudioPropsBytesToNano64(pMix->pProps, offStream);
     1674                uint64_t const cNsElapsed = RTTimeNanoTS() - nsStarted;
     1675                if (cNsWritten + RT_NS_10MS > cNsElapsed)
     1676                    RTThreadSleep((cNsWritten - cNsElapsed - RT_NS_10MS / 2) / RT_NS_1MS);
     1677            }
     1678
     1679            /* Transfer the data to the audio stream. */
     1680            for (uint32_t offSamples = 0; offSamples < cbSamples;)
     1681            {
     1682                uint32_t const cbCanWrite = AudioTestMixStreamGetWritable(pMix);
     1683                if (cbCanWrite > 0)
     1684                {
     1685                    uint32_t const cbToPlay = RT_MIN(cbCanWrite, (uint32_t)cbSamples - offSamples);
     1686                    uint32_t       cbPlayed = 0;
     1687                    rc = AudioTestMixStreamPlay(pMix, &abSamples[offSamples], cbToPlay, &cbPlayed);
     1688                    if (RT_SUCCESS(rc))
     1689                    {
     1690                        if (cbPlayed)
     1691                        {
     1692                            offSamples += cbPlayed;
     1693                            offStream  += cbPlayed;
     1694                        }
     1695                        else
     1696                            return RTMsgErrorExitFailure("Played zero out of %#x bytes - %#x bytes reported playable!\n",
     1697                                                         cbToPlay, cbCanWrite);
     1698                    }
     1699                    else
     1700                        return RTMsgErrorExitFailure("Failed to play %#x bytes: %Rrc\n", cbToPlay, rc);
     1701                }
     1702                else if (AudioTestMixStreamIsOkay(pMix))
     1703                    RTThreadSleep(RT_MIN(RT_MAX(1, pCfgAcq->Device.cMsSchedulingHint), 256));
     1704                else
     1705                    return RTMsgErrorExitFailure("Stream is not okay!\n");
     1706            }
     1707        }
     1708        else if (RT_SUCCESS(rc) && cbSamples == 0)
     1709            break;
     1710        else
     1711            return RTMsgErrorExitFailure("Error reading wav file '%s': %Rrc", pszFile, rc);
     1712    }
     1713
     1714    /*
     1715     * Drain the stream.
     1716     */
     1717    if (g_uVerbosity > 0)
     1718        RTMsgInfo("%'RU64 ns: Draining...\n", RTTimeNanoTS() - nsStarted);
     1719    int rc = AudioTestMixStreamDrain(pMix, true /*fSync*/);
     1720    if (RT_SUCCESS(rc))
     1721    {
     1722        if (g_uVerbosity > 0)
     1723            RTMsgInfo("%'RU64 ns: Done\n", RTTimeNanoTS() - nsStarted);
     1724    }
     1725    else
     1726        return RTMsgErrorExitFailure("Draining failed: %Rrc", rc);
     1727
     1728    return RTEXITCODE_SUCCESS;
     1729}
     1730
     1731
     1732/**
    16461733 * Worker for audioTestCmdPlayHandler that plays one file.
    16471734 */
    16481735static RTEXITCODE audioTestPlayOne(const char *pszFile, PCPDMDRVREG pDrvReg, const char *pszDevId, uint32_t cMsBufferSize,
    1649                                    uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint, bool fWithDrvAudio)
    1650 {
     1736                                   uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
     1737                                   uint8_t cChannels, uint8_t cbSample, uint32_t uHz,
     1738                                   bool fWithDrvAudio, bool fWithMixer)
     1739{
     1740    char szTmp[128];
     1741
    16511742    /*
    16521743     * First we must open the file and determin the format.
     
    16601751    if (g_uVerbosity > 0)
    16611752    {
    1662         char szTmp[128];
    16631753        RTMsgInfo("Opened '%s' for playing\n", pszFile);
    16641754        RTMsgInfo("Format: %s\n", PDMAudioPropsToString(&WaveFile.Props, szTmp, sizeof(szTmp)));
     
    16861776             * Open a stream for the output.
    16871777             */
     1778            PDMAUDIOPCMPROPS ReqProps = WaveFile.Props;
     1779            if (cChannels != 0 && PDMAudioPropsChannels(&ReqProps) != cChannels)
     1780                PDMAudioPropsSetChannels(&ReqProps, cChannels);
     1781            if (cbSample != 0)
     1782                PDMAudioPropsSetSampleSize(&ReqProps, cbSample);
     1783            if (uHz != 0)
     1784                ReqProps.uHz = uHz;
     1785
    16881786            PDMAUDIOSTREAMCFG CfgAcq;
    1689             PPDMAUDIOSTREAM   pStream = NULL;
    1690             rc = audioTestDriverStackStreamCreateOutput(&DrvStack, &WaveFile.Props, cMsBufferSize,
     1787            PPDMAUDIOSTREAM   pStream  = NULL;
     1788            rc = audioTestDriverStackStreamCreateOutput(&DrvStack, &ReqProps, cMsBufferSize,
    16911789                                                        cMsPreBuffer, cMsSchedulingHint, &pStream, &CfgAcq);
    16921790            if (RT_SUCCESS(rc))
    16931791            {
    1694                 rc = audioTestDriverStackStreamEnable(&DrvStack, pStream);
     1792                AUDIOTESTDRVMIXSTREAM Mix;
     1793                rc = AudioTestMixStreamInit(&Mix, &DrvStack, pStream, fWithMixer ? &WaveFile.Props : NULL, 100 /*ms*/);
    16951794                if (RT_SUCCESS(rc))
    16961795                {
    1697                     uint32_t const  cbPreBuffer = PDMAudioPropsFramesToBytes(&pStream->Props, CfgAcq.Backend.cFramesPreBuffering);
    1698                     uint64_t const  nsStarted   = RTTimeNanoTS();
    1699 
    1700                     /*
    1701                      * Transfer data as quickly as we're allowed.
    1702                      */
    1703                     uint8_t         abSamples[16384];
    1704                     uint32_t const  cbSamplesAligned = PDMAudioPropsFloorBytesToFrame(&pStream->Props, sizeof(abSamples));
    1705                     uint64_t        offStream        = 0;
    1706                     for (;;)
    1707                     {
    1708                         /* Read a chunk from the wave file. */
    1709                         size_t   cbSamples = 0;
    1710                         rc = AudioTestWaveFileRead(&WaveFile, abSamples, cbSamplesAligned, &cbSamples);
    1711                         if (RT_SUCCESS(rc) && cbSamples > 0)
    1712                         {
    1713                             /* Pace ourselves a little. */
    1714                             if (offStream >= cbPreBuffer)
    1715                             {
    1716                                 uint64_t const cNsWritten = PDMAudioPropsBytesToNano(&pStream->Props, offStream);
    1717                                 uint64_t const cNsElapsed = RTTimeNanoTS() - nsStarted;
    1718                                 if (cNsWritten + RT_NS_10MS > cNsElapsed)
    1719                                     RTThreadSleep((cNsWritten - cNsElapsed - RT_NS_10MS / 2) / RT_NS_1MS);
    1720                             }
    1721 
    1722                             /* Transfer the data to the audio stream. */
    1723                             for (uint32_t offSamples = 0; offSamples < cbSamples;)
    1724                             {
    1725                                 uint32_t const cbCanWrite = audioTestDriverStackStreamGetWritable(&DrvStack, pStream);
    1726                                 if (cbCanWrite > 0)
    1727                                 {
    1728                                     uint32_t const cbToPlay = RT_MIN(cbCanWrite, (uint32_t)cbSamples - offSamples);
    1729                                     uint32_t       cbPlayed = 0;
    1730                                     rc = audioTestDriverStackStreamPlay(&DrvStack, pStream, &abSamples[offSamples],
    1731                                                                         cbToPlay, &cbPlayed);
    1732                                     if (RT_SUCCESS(rc))
    1733                                     {
    1734                                         if (cbPlayed)
    1735                                         {
    1736                                             offSamples += cbPlayed;
    1737                                             offStream  += cbPlayed;
    1738                                         }
    1739                                         else
    1740                                         {
    1741                                             rcExit = RTMsgErrorExitFailure("Played zero out of %#x bytes - %#x bytes reported playable!\n",
    1742                                                                            cbToPlay, cbCanWrite);
    1743                                             break;
    1744                                         }
    1745                                     }
    1746                                     else
    1747                                     {
    1748                                         rcExit = RTMsgErrorExitFailure("Failed to play %#x bytes: %Rrc\n", cbToPlay, rc);
    1749                                         break;
    1750                                     }
    1751                                 }
    1752                                 else if (audioTestDriverStackStreamIsOkay(&DrvStack, pStream))
    1753                                     RTThreadSleep(RT_MIN(RT_MAX(1, CfgAcq.Device.cMsSchedulingHint), 256));
    1754                                 else
    1755                                 {
    1756                                     rcExit = RTMsgErrorExitFailure("Stream is not okay!\n");
    1757                                     break;
    1758                                 }
    1759                             }
    1760                         }
    1761                         else if (RT_SUCCESS(rc) && cbSamples == 0)
    1762                         {
    1763                             rcExit = RTEXITCODE_SUCCESS;
    1764                             break;
    1765                         }
    1766                         else
    1767                         {
    1768                             rcExit = RTMsgErrorExitFailure("Error reading wav file '%s': %Rrc", pszFile, rc);
    1769                             break;
    1770                         }
    1771                     }
    1772 
    1773                     /*
    1774                      * Drain the stream.
    1775                      */
    1776                     if (rcExit == RTEXITCODE_SUCCESS)
    1777                     {
    1778                         if (g_uVerbosity > 0)
    1779                             RTMsgInfo("%'RU64 ns: Draining...\n", RTTimeNanoTS() - nsStarted);
    1780                         rc = audioTestDriverStackStreamDrain(&DrvStack, pStream, true /*fSync*/);
    1781                         if (RT_SUCCESS(rc))
    1782                         {
    1783                             if (g_uVerbosity > 0)
    1784                                 RTMsgInfo("%'RU64 ns: Done\n", RTTimeNanoTS() - nsStarted);
    1785                         }
    1786                         else
    1787                             rcExit = RTMsgErrorExitFailure("Draining failed: %Rrc", rc);
    1788                     }
     1796                    if (g_uVerbosity > 0)
     1797                        RTMsgInfo("Stream: %s cbBacked=%#RX32%s\n", PDMAudioPropsToString(&pStream->Props, szTmp, sizeof(szTmp)),
     1798                                  pStream->cbBackend, fWithMixer ? " mixed" : "");
     1799
     1800                    rc = audioTestDriverStackStreamEnable(&DrvStack, pStream);
     1801                    if (RT_SUCCESS(rc))
     1802                        rcExit = audioTestPlayOneInner(&Mix, &WaveFile, &CfgAcq, pszFile);
     1803                    else
     1804                        rcExit = RTMsgErrorExitFailure("Enabling the output stream failed: %Rrc", rc);
    17891805                }
    1790                 else
    1791                     rcExit = RTMsgErrorExitFailure("Enabling the output stream failed: %Rrc", rc);
    17921806                audioTestDriverStackStreamDestroy(&DrvStack, pStream);
    17931807            }
     
    18111825{
    18121826    { "--backend",          'b',                          RTGETOPT_REQ_STRING  },
     1827    { "--channels",         'c',                          RTGETOPT_REQ_UINT8 },
     1828    { "--hz",               'f',                          RTGETOPT_REQ_UINT32 },
     1829    { "--frequency",        'f',                          RTGETOPT_REQ_UINT32 },
     1830    { "--sample-size",      'z',                          RTGETOPT_REQ_UINT8 },
    18131831    { "--output-device",    'o',                          RTGETOPT_REQ_STRING  },
    18141832    { "--with-drv-audio",   'd',                          RTGETOPT_REQ_NOTHING },
     1833    { "--with-mixer",       'm',                          RTGETOPT_REQ_NOTHING },
    18151834};
    18161835
     
    18211840    {
    18221841        case 'b': return "The audio backend to use.";
     1842        case 'c': return "Number of backend output channels";
    18231843        case 'd': return "Go via DrvAudio instead of directly interfacing with the backend.";
     1844        case 'f': return "Output frequency (Hz)";
     1845        case 'z': return "Output sample size (bits)";
     1846        case 'm': return "Go via the mixer.";
    18241847        case 'o': return "The ID of the output device to use.";
    18251848        default:  return NULL;
     
    18361859{
    18371860    /* Option values: */
    1838     PCPDMDRVREG pDrvReg           = g_aBackends[0].pDrvReg;
    1839     uint32_t    cMsBufferSize     = UINT32_MAX;
    1840     uint32_t    cMsPreBuffer      = UINT32_MAX;
    1841     uint32_t    cMsSchedulingHint = UINT32_MAX;
    1842     const char *pszDevId          = NULL;
    1843     bool        fWithDrvAudio     = false;
     1861    PCPDMDRVREG pDrvReg             = g_aBackends[0].pDrvReg;
     1862    uint32_t    cMsBufferSize       = UINT32_MAX;
     1863    uint32_t    cMsPreBuffer        = UINT32_MAX;
     1864    uint32_t    cMsSchedulingHint   = UINT32_MAX;
     1865    const char *pszDevId            = NULL;
     1866    bool        fWithDrvAudio       = false;
     1867    bool        fWithMixer          = false;
     1868    uint8_t     cbSample            = 0;
     1869    uint8_t     cChannels           = 0;
     1870    uint32_t    uHz                 = 0;
    18441871
    18451872    /* Argument processing loop: */
     
    18631890                break;
    18641891
     1892            case 'c':
     1893                cChannels = ValueUnion.u8;
     1894                break;
     1895
    18651896            case 'd':
    18661897                fWithDrvAudio = true;
    18671898                break;
    18681899
     1900            case 'f':
     1901                uHz = ValueUnion.u32;
     1902                break;
     1903
     1904            case 'm':
     1905                fWithMixer = true;
     1906                break;
     1907
    18691908            case 'o':
    18701909                pszDevId = ValueUnion.psz;
     1910                break;
     1911
     1912            case 'z':
     1913                cbSample = ValueUnion.u8 / 8;
    18711914                break;
    18721915
     
    18741917            {
    18751918                RTEXITCODE rcExit = audioTestPlayOne(ValueUnion.psz, pDrvReg, pszDevId, cMsBufferSize, cMsPreBuffer,
    1876                                                      cMsSchedulingHint, fWithDrvAudio);
     1919                                                     cMsSchedulingHint, cChannels, cbSample, uHz, fWithDrvAudio, fWithMixer);
    18771920                if (rcExit != RTEXITCODE_SUCCESS)
    18781921                    return rcExit;
     
    18881931    return RTEXITCODE_SUCCESS;
    18891932}
     1933
     1934
     1935/*********************************************************************************************************************************
     1936*   Command: selftest                                                                                                            *
     1937*********************************************************************************************************************************/
    18901938
    18911939/**
  • trunk/src/VBox/ValidationKit/utils/audio/vkatDriverStack.cpp

    r89417 r89439  
    4949
    5050#include "vkatInternal.h"
     51#include "VBoxDD.h"
    5152
    5253
     
    6970    return NULL;
    7071}
     72
    7173
    7274VMMR3DECL(int) CFGMR3QueryString(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)
     
    9395}
    9496
     97
    9598VMMR3DECL(int) CFGMR3QueryStringAlloc(PCFGMNODE pNode, const char *pszName, char **ppszString)
    9699{
     
    103106}
    104107
     108
    105109VMMR3DECL(void) MMR3HeapFree(void *pv)
    106110{
     
    108112    RTStrFree((char *)pv);
    109113}
     114
    110115
    111116VMMR3DECL(int) CFGMR3QueryStringDef(PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)
     
    133138}
    134139
     140
    135141VMMR3DECL(int) CFGMR3QueryBoolDef(PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)
    136142{
     
    151157}
    152158
     159
    153160VMMR3DECL(int) CFGMR3QueryU8(PCFGMNODE pNode, const char *pszName, uint8_t *pu8)
    154161{
     
    157164}
    158165
     166
    159167VMMR3DECL(int) CFGMR3QueryU32(PCFGMNODE pNode, const char *pszName, uint32_t *pu32)
    160168{
     
    162170    return VERR_CFGM_VALUE_NOT_FOUND;
    163171}
     172
    164173
    165174VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode,
     
    201210}
    202211
     212
    203213static DECLCALLBACK(void) audioTestDrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType,
    204214                                                        STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc,
     
    208218}
    209219
     220
    210221static DECLCALLBACK(void) audioTestDrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType,
    211222                                                        STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc,
     
    215226}
    216227
     228
    217229static DECLCALLBACK(int) audioTestDrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample)
    218230{
     
    220232    return VINF_SUCCESS;
    221233}
     234
    222235
    223236static DECLCALLBACK(int) audioTestDrvHlp_STAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix)
     
    279292}
    280293
     294
    281295DECLCALLBACK(void) audioTestIHostAudioPort_NotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser)
    282296{
     
    285299}
    286300
     301
    287302static DECLCALLBACK(void) audioTestIHostAudioPort_StreamNotifyPreparingDeviceSwitch(PPDMIHOSTAUDIOPORT pInterface,
    288303                                                                                    PPDMAUDIOBACKENDSTREAM pStream)
     
    292307}
    293308
     309
    294310static DECLCALLBACK(void) audioTestIHostAudioPort_StreamNotifyDeviceChanged(PPDMIHOSTAUDIOPORT pInterface,
    295311                                                                            PPDMAUDIOBACKENDSTREAM pStream, bool fReInit)
     
    299315}
    300316
     317
    301318static DECLCALLBACK(void) audioTestIHostAudioPort_NotifyDevicesChanged(PPDMIHOSTAUDIOPORT pInterface)
    302319{
     
    304321    RTMsgWarning("audioTestIHostAudioPort_NotifyDevicesChanged was called\n");
    305322}
     323
    306324
    307325static PDMIHOSTAUDIOPORT g_AudioTestIHostAudioPort =
     
    314332};
    315333
     334
    316335/**
    317336 * Implementation of PDMIBASE::pfnQueryInterface for a fake DrvAudio above a
     
    325344    return NULL;
    326345}
     346
    327347
    328348/** IBase interface for a fake DrvAudio above a lonesome backend. */
     
    397417}
    398418
     419
    399420/**
    400421 * Destructs a PDM audio driver instance.
     
    417438}
    418439
     440
    419441/**
    420442 * Sends the PDM driver a power off notification.
     
    432454}
    433455
     456
    434457/**
    435458 * Deletes a driver stack.
     
    456479    pDrvStack->pIAudioConnector = NULL;
    457480}
     481
    458482
    459483/**
     
    467491int audioTestDriverStackInit(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, bool fWithDrvAudio)
    468492{
     493    int rc;
     494
    469495    RT_ZERO(*pDrvStack);
    470496    pDrvStack->pDrvReg = pDrvReg;
    471497
    472     int rc;
    473498    if (!fWithDrvAudio)
    474499        rc = audioTestDrvConstruct(pDrvStack, pDrvReg, NULL /*pParentDrvIns*/, &pDrvStack->pDrvBackendIns);
     
    525550}
    526551
     552
    527553/**
    528554 * Wrapper around PDMIHOSTAUDIO::pfnSetDevice.
     
    541567}
    542568
     569
    543570/**
    544571 * Common stream creation code.
    545572 *
    546573 * @returns VBox status code.
    547  * @param   pDrvStack           The audio driver stack to create it via.
    548  * @param   pCfgReq             The requested config.
    549  * @param   ppStream            Where to return the stream pointer on success.
    550  * @param   pCfgAcq             Where to return the actual (well, not
    551  *                              necessarily when using DrvAudio, but probably
    552  *                              the same) stream config on success (not used as
    553  *                              input).
     574 * @param   pDrvStack   The audio driver stack to create it via.
     575 * @param   pCfgReq     The requested config.
     576 * @param   ppStream    Where to return the stream pointer on success.
     577 * @param   pCfgAcq     Where to return the actual (well, not necessarily when
     578 *                      using DrvAudio, but probably the same) stream config on
     579 *                      success (not used as input).
    554580 */
    555581static int audioTestDriverStackStreamCreate(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAMCFG pCfgReq,
     
    670696}
    671697
     698
    672699/**
    673700 * Creates an output stream.
     
    729756}
    730757
     758
    731759/**
    732760 * Creates an input stream.
     
    788816}
    789817
     818
    790819/**
    791820 * Destroys a stream.
     
    817846}
    818847
     848
    819849/**
    820850 * Enables a stream.
     
    838868    return rc;
    839869}
     870
     871
     872/**
     873 * Disables a stream.
     874 */
     875int AudioTestDriverStackStreamDisable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream)
     876{
     877    int rc;
     878    if (pDrvStack->pIAudioConnector)
     879    {
     880        rc = pDrvStack->pIAudioConnector->pfnStreamControl(pDrvStack->pIAudioConnector, pStream, PDMAUDIOSTREAMCMD_DISABLE);
     881        if (RT_FAILURE(rc))
     882            RTTestFailed(g_hTest, "pfnStreamControl/DISABLE failed: %Rrc", rc);
     883    }
     884    else
     885    {
     886        PAUDIOTESTDRVSTACKSTREAM pStreamAt = (PAUDIOTESTDRVSTACKSTREAM)pStream;
     887        rc = pDrvStack->pIHostAudio->pfnStreamControl(pDrvStack->pIHostAudio, &pStreamAt->Backend, PDMAUDIOSTREAMCMD_DISABLE);
     888        if (RT_FAILURE(rc))
     889            RTTestFailed(g_hTest, "PDMIHOSTAUDIO::pfnStreamControl/DISABLE failed: %Rrc", rc);
     890    }
     891    return rc;
     892}
     893
    840894
    841895/**
     
    921975}
    922976
     977
    923978/**
    924979 * Checks if the stream is okay.
     
    9771032}
    9781033
     1034
    9791035/**
    9801036 * Gets the number of bytes it's currently possible to write to the stream.
     
    9921048    return cbWritable;
    9931049}
     1050
    9941051
    9951052/**
     
    10161073}
    10171074
     1075
    10181076/**
    10191077 * Tries to capture @a cbBuf bytes of samples in @a pvBuf.
     
    10391097}
    10401098
     1099
     1100/*********************************************************************************************************************************
     1101*   Mixed streams                                                                                                                *
     1102*********************************************************************************************************************************/
     1103
     1104/**
     1105 * Initializing mixing for a stream.
     1106 *
     1107 * This can be used as a do-nothing wrapper for the stack.
     1108 *
     1109 * @returns VBox status code.
     1110 * @param   pMix        The mixing state.
     1111 * @param   pStream     The stream to mix to/from.
     1112 * @param   pProps      The mixer properties.  Pass NULL for no mixing, just
     1113 *                      wrap the driver stack functionality.
     1114 * @param   cMsBuffer   The buffer size.
     1115 */
     1116int AudioTestMixStreamInit(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream,
     1117                           PCPDMAUDIOPCMPROPS pProps, uint32_t cMsBuffer)
     1118{
     1119    RT_ZERO(*pMix);
     1120
     1121    AssertReturn(pDrvStack, VERR_INVALID_PARAMETER);
     1122    AssertReturn(pStream, VERR_INVALID_PARAMETER);
     1123
     1124    pMix->pDrvStack = pDrvStack;
     1125    pMix->pStream   = pStream;
     1126    if (!pProps)
     1127    {
     1128        pMix->pProps = &pStream->Props;
     1129        return VINF_SUCCESS;
     1130    }
     1131
     1132    /*
     1133     * Okay, we're doing mixing so we need to set up the mixer buffer
     1134     * and associated states.
     1135     */
     1136    pMix->fDoMixing = true;
     1137    int rc = AudioMixBufInit(&pMix->MixBuf, "mixer", pProps, PDMAudioPropsMilliToFrames(pProps, cMsBuffer));
     1138    if (RT_SUCCESS(rc))
     1139    {
     1140        pMix->pProps = &pMix->MixBuf.Props;
     1141
     1142        if (pStream->enmDir == PDMAUDIODIR_IN)
     1143        {
     1144            rc = AudioMixBufInitPeekState(&pMix->MixBuf, &pMix->PeekState, &pMix->MixBuf.Props);
     1145            if (RT_SUCCESS(rc))
     1146            {
     1147                rc = AudioMixBufInitWriteState(&pMix->MixBuf, &pMix->WriteState, &pStream->Props);
     1148                if (RT_SUCCESS(rc))
     1149                    return rc;
     1150            }
     1151        }
     1152        else if (pStream->enmDir == PDMAUDIODIR_OUT)
     1153        {
     1154            rc = AudioMixBufInitWriteState(&pMix->MixBuf, &pMix->WriteState, &pMix->MixBuf.Props);
     1155            if (RT_SUCCESS(rc))
     1156            {
     1157                rc = AudioMixBufInitPeekState(&pMix->MixBuf, &pMix->PeekState, &pStream->Props);
     1158                if (RT_SUCCESS(rc))
     1159                    return rc;
     1160            }
     1161        }
     1162        else
     1163        {
     1164            RTTestFailed(g_hTest, "Bogus stream direction!");
     1165            rc = VERR_INVALID_STATE;
     1166        }
     1167    }
     1168    else
     1169        RTTestFailed(g_hTest, "AudioMixBufInit failed: %Rrc", rc);
     1170    RT_ZERO(*pMix);
     1171    return rc;
     1172}
     1173
     1174
     1175/**
     1176 * Terminate mixing (leaves the stream untouched).
     1177 *
     1178 * @param   pMix        The mixing state.
     1179 */
     1180void AudioTestMixStreamTerm(PAUDIOTESTDRVMIXSTREAM pMix)
     1181{
     1182    if (pMix->fDoMixing)
     1183    {
     1184        AudioMixBufTerm(&pMix->MixBuf);
     1185        pMix->pStream = NULL;
     1186    }
     1187    RT_ZERO(*pMix);
     1188}
     1189
     1190
     1191/**
     1192 * Worker that transports data between the mixer buffer and the drivers.
     1193 *
     1194 * @returns VBox status code.
     1195 * @param   pMix    The mixer stream setup to do transfers for.
     1196 */
     1197static int audioTestMixStreamTransfer(PAUDIOTESTDRVMIXSTREAM pMix)
     1198{
     1199    uint8_t abBuf[16384];
     1200    if (pMix->pStream->enmDir == PDMAUDIODIR_IN)
     1201    {
     1202        //uint32_t const cbBuf = PDMAudioPropsFloorBytesToFrame(&pMix->pStream->Props, sizeof(abBuf));
     1203
     1204    }
     1205    else
     1206    {
     1207        /*
     1208         * The goal here is to empty the mixer buffer by transfering all
     1209         * the data to the drivers.
     1210         */
     1211        uint32_t const cbBuf = PDMAudioPropsFloorBytesToFrame(&pMix->MixBuf.Props, sizeof(abBuf));
     1212        for (;;)
     1213        {
     1214            uint32_t cFrames = AudioMixBufUsed(&pMix->MixBuf);
     1215            if (!cFrames)
     1216                break;
     1217
     1218            uint32_t cbWritable = audioTestDriverStackStreamGetWritable(pMix->pDrvStack, pMix->pStream);
     1219            if (!cbWritable)
     1220                break;
     1221
     1222            uint32_t cSrcFramesPeeked;
     1223            uint32_t cbDstPeeked;
     1224            AudioMixBufPeek(&pMix->MixBuf, 0 /*offSrcFrame*/, cFrames, &cSrcFramesPeeked,
     1225                            &pMix->PeekState, abBuf, RT_MIN(cbBuf, cbWritable), &cbDstPeeked);
     1226            AudioMixBufAdvance(&pMix->MixBuf, cSrcFramesPeeked);
     1227
     1228            if (!cbDstPeeked)
     1229                break;
     1230
     1231            uint32_t offBuf = 0;
     1232            while (offBuf < cbDstPeeked)
     1233            {
     1234                uint32_t cbPlayed = 0;
     1235                int rc = audioTestDriverStackStreamPlay(pMix->pDrvStack, pMix->pStream,
     1236                                                        &abBuf[offBuf], cbDstPeeked - offBuf, &cbPlayed);
     1237                if (RT_FAILURE(rc))
     1238                    return rc;
     1239                if (!cbPlayed)
     1240                    RTThreadSleep(1);
     1241                offBuf += cbPlayed;
     1242            }
     1243        }
     1244    }
     1245    return VINF_SUCCESS;
     1246}
     1247
     1248
     1249/**
     1250 * Same as audioTestDriverStackStreamDrain.
     1251 */
     1252int AudioTestMixStreamDrain(PAUDIOTESTDRVMIXSTREAM pMix, bool fSync)
     1253{
     1254    /*
     1255     * If we're mixing, we must first make sure the buffer is empty.
     1256     */
     1257    if (pMix->fDoMixing)
     1258    {
     1259        audioTestMixStreamTransfer(pMix);
     1260        while (AudioMixBufUsed(&pMix->MixBuf) > 0)
     1261        {
     1262            RTThreadSleep(1);
     1263            audioTestMixStreamTransfer(pMix);
     1264        }
     1265    }
     1266
     1267    /*
     1268     * Then we do the regular workt.
     1269     */
     1270    return audioTestDriverStackStreamDrain(pMix->pDrvStack, pMix->pStream, fSync);
     1271}
     1272
     1273
     1274/**
     1275 * Same as audioTestDriverStackStreamEnable.
     1276 */
     1277int AudioTestMixStreamEnable(PAUDIOTESTDRVMIXSTREAM pMix)
     1278{
     1279    return audioTestDriverStackStreamEnable(pMix->pDrvStack, pMix->pStream);
     1280}
     1281
     1282
     1283/**
     1284 * Same as audioTestDriverStackStreamGetWritable
     1285 */
     1286uint32_t AudioTestMixStreamGetWritable(PAUDIOTESTDRVMIXSTREAM pMix)
     1287{
     1288    if (!pMix->fDoMixing)
     1289        return audioTestDriverStackStreamGetWritable(pMix->pDrvStack, pMix->pStream);
     1290    uint32_t cbRet = AudioMixBufFreeBytes(&pMix->MixBuf);
     1291    if (!cbRet)
     1292    {
     1293        audioTestMixStreamTransfer(pMix);
     1294        cbRet = AudioMixBufFreeBytes(&pMix->MixBuf);
     1295    }
     1296    return cbRet;
     1297}
     1298
     1299
     1300/**
     1301 * Same as audioTestDriverStackStreamIsOkay.
     1302 */
     1303bool AudioTestMixStreamIsOkay(PAUDIOTESTDRVMIXSTREAM pMix)
     1304{
     1305    return audioTestDriverStackStreamIsOkay(pMix->pDrvStack, pMix->pStream);
     1306}
     1307
     1308
     1309/**
     1310 * Same as audioTestDriverStackStreamPlay.
     1311 */
     1312int AudioTestMixStreamPlay(PAUDIOTESTDRVMIXSTREAM pMix, void const *pvBuf, uint32_t cbBuf, uint32_t *pcbPlayed)
     1313{
     1314    if (!pMix->fDoMixing)
     1315        return audioTestDriverStackStreamPlay(pMix->pDrvStack, pMix->pStream, pvBuf, cbBuf, pcbPlayed);
     1316
     1317    *pcbPlayed = 0;
     1318
     1319    int rc = audioTestMixStreamTransfer(pMix);
     1320    if (RT_FAILURE(rc))
     1321        return rc;
     1322
     1323    uint32_t const cbFrame = PDMAudioPropsFrameSize(&pMix->MixBuf.Props);
     1324    while (cbBuf >= cbFrame)
     1325    {
     1326        uint32_t const  cFrames = AudioMixBufFree(&pMix->MixBuf);
     1327        if (!cFrames)
     1328            break;
     1329        uint32_t cbToWrite = PDMAudioPropsFramesToBytes(&pMix->MixBuf.Props, cFrames);
     1330        cbToWrite = RT_MIN(cbToWrite, cbBuf);
     1331        cbToWrite = PDMAudioPropsFloorBytesToFrame(&pMix->MixBuf.Props, cbToWrite);
     1332
     1333        uint32_t cFramesWritten = 0;
     1334        AudioMixBufWrite(&pMix->MixBuf, &pMix->WriteState, pvBuf, cbToWrite, 0 /*offDstFrame*/, cFrames, &cFramesWritten);
     1335        Assert(cFramesWritten == PDMAudioPropsBytesToFrames(&pMix->MixBuf.Props, cbToWrite));
     1336        AudioMixBufCommit(&pMix->MixBuf, cFramesWritten);
     1337
     1338        *pcbPlayed += cbToWrite;
     1339        cbBuf      -= cbToWrite;
     1340        pvBuf       = (uint8_t const *)pvBuf + cbToWrite;
     1341
     1342        rc = audioTestMixStreamTransfer(pMix);
     1343        if (RT_FAILURE(rc))
     1344            return *pcbPlayed ? VINF_SUCCESS : rc;
     1345    }
     1346
     1347    return VINF_SUCCESS;
     1348}
     1349
  • trunk/src/VBox/ValidationKit/utils/audio/vkatInternal.h

    r89401 r89439  
    3131#endif
    3232
    33 #include "VBoxDD.h"
    34 
     33#include <VBox/vmm/pdmdrv.h>
    3534#include <VBox/vmm/pdmaudioinline.h>
    3635#include <VBox/vmm/pdmaudiohostenuminline.h>
     36#include "Audio/AudioMixBuffer.h"
     37
    3738
    3839/**
     
    7576typedef AUDIOTESTDRVSTACKSTREAM *PAUDIOTESTDRVSTACKSTREAM;
    7677
    77 /** Maximum audio streams a test environment can handle. */
    78 #define AUDIOTESTENV_MAX_STREAMS 8
     78/**
     79 * Mixer setup for a stream.
     80 */
     81typedef struct AUDIOTESTDRVMIXSTREAM
     82{
     83    /** Pointer to the driver stack. */
     84    PAUDIOTESTDRVSTACK      pDrvStack;
     85    /** Pointer to the stream. */
     86    PPDMAUDIOSTREAM         pStream;
     87    /** Properties to use. */
     88    PCPDMAUDIOPCMPROPS      pProps;
     89    /** Set if we're mixing or just passing thru to the driver stack. */
     90    bool                    fDoMixing;
     91    /** Mixer buffer. */
     92    AUDIOMIXBUF             MixBuf;
     93    /** Write state. */
     94    AUDIOMIXBUFWRITESTATE   WriteState;
     95    /** Peek state. */
     96    AUDIOMIXBUFPEEKSTATE    PeekState;
     97} AUDIOTESTDRVMIXSTREAM;
     98/** Pointer to mixer setup for a stream. */
     99typedef AUDIOTESTDRVMIXSTREAM *PAUDIOTESTDRVMIXSTREAM;
     100
    79101
    80102/** The test handle. */
     
    84106extern const char    *g_pszDrvAudioDebug;
    85107
     108
    86109/** @name Driver stack
    87110 * @{ */
    88 void audioTestDriverStackDelete(PAUDIOTESTDRVSTACK pDrvStack);
    89 int audioTestDriverStackInit(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, bool fWithDrvAudio);
    90 int audioTestDriverStackSetDevice(PAUDIOTESTDRVSTACK pDrvStack, PDMAUDIODIR enmDir, const char *pszDevId);
     111void        audioTestDriverStackDelete(PAUDIOTESTDRVSTACK pDrvStack);
     112int         audioTestDriverStackInit(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, bool fWithDrvAudio);
     113int         audioTestDriverStackSetDevice(PAUDIOTESTDRVSTACK pDrvStack, PDMAUDIODIR enmDir, const char *pszDevId);
    91114/** @}  */
    92115
    93116/** @name Driver
    94117 * @{ */
    95 int audioTestDrvConstruct(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, PPDMDRVINS pParentDrvIns, PPPDMDRVINS ppDrvIns);
     118int         audioTestDrvConstruct(PAUDIOTESTDRVSTACK pDrvStack, PCPDMDRVREG pDrvReg, PPDMDRVINS pParentDrvIns, PPPDMDRVINS ppDrvIns);
    96119/** @}  */
    97120
    98121/** @name Driver stack stream
    99122 * @{ */
    100 int audioTestDriverStackStreamCapture(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream,
    101                                       void *pvBuf, uint32_t cbBuf, uint32_t *pcbCaptured);
    102 int audioTestDriverStackStreamCreateInput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps,
    103                                           uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
    104                                           PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq);
    105 int audioTestDriverStackStreamCreateOutput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps,
    106                                            uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
    107                                            PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq);
    108 void audioTestDriverStackStreamDestroy(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
    109 int audioTestDriverStackStreamDrain(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, bool fSync);
    110 int audioTestDriverStackStreamEnable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
    111 uint32_t audioTestDriverStackStreamGetWritable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
    112 bool audioTestDriverStackStreamIsOkay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
    113 int audioTestDriverStackStreamPlay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, void const *pvBuf, uint32_t cbBuf, uint32_t *pcbPlayed);
     123int         audioTestDriverStackStreamCreateInput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps,
     124                                                  uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
     125                                                  PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq);
     126int         audioTestDriverStackStreamCreateOutput(PAUDIOTESTDRVSTACK pDrvStack, PCPDMAUDIOPCMPROPS pProps,
     127                                                   uint32_t cMsBufferSize, uint32_t cMsPreBuffer, uint32_t cMsSchedulingHint,
     128                                                   PPDMAUDIOSTREAM *ppStream, PPDMAUDIOSTREAMCFG pCfgAcq);
     129void        audioTestDriverStackStreamDestroy(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
     130int         audioTestDriverStackStreamDrain(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, bool fSync);
     131int         audioTestDriverStackStreamEnable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
     132int         audioTestDriverStackStreamDisable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
     133uint32_t    audioTestDriverStackStreamGetWritable(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
     134bool        audioTestDriverStackStreamIsOkay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream);
     135int         audioTestDriverStackStreamPlay(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream, void const *pvBuf,
     136                                           uint32_t cbBuf, uint32_t *pcbPlayed);
     137int         audioTestDriverStackStreamCapture(PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream,
     138                                              void *pvBuf, uint32_t cbBuf, uint32_t *pcbCaptured);
    114139/** @}  */
     140
     141
     142/** @name Mixing stream
     143 * @{ */
     144int         AudioTestMixStreamInit(PAUDIOTESTDRVMIXSTREAM pMix, PAUDIOTESTDRVSTACK pDrvStack, PPDMAUDIOSTREAM pStream,
     145                                   PCPDMAUDIOPCMPROPS pProps, uint32_t cMsBuffer);
     146void        AudioTestMixStreamTerm(PAUDIOTESTDRVMIXSTREAM pMix);
     147int         AudioTestMixStreamDrain(PAUDIOTESTDRVMIXSTREAM pMix, bool fSync);
     148int         AudioTestMixStreamEnable(PAUDIOTESTDRVMIXSTREAM pMix);
     149uint32_t    AudioTestMixStreamGetWritable(PAUDIOTESTDRVMIXSTREAM pMix);
     150bool        AudioTestMixStreamIsOkay(PAUDIOTESTDRVMIXSTREAM pMix);
     151int         AudioTestMixStreamPlay(PAUDIOTESTDRVMIXSTREAM pMix, void const *pvBuf, uint32_t cbBuf, uint32_t *pcbPlayed);
     152int         AudioTestMixStreamCapture(PAUDIOTESTDRVMIXSTREAM pMix, void *pvBuf, uint32_t cbBuf, uint32_t *pcbCaptured);
     153/** @}  */
     154
    115155
    116156#endif /* !VBOX_INCLUDED_SRC_audio_vkatInternal_h */
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