VirtualBox

Changeset 61887 in vbox for trunk


Ignore:
Timestamp:
Jun 27, 2016 8:26:56 AM (8 years ago)
Author:
vboxsync
Message:

Audio: Implemented support for master volume controls.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/pdmaudioifs.h

    r61764 r61887  
    323323{
    324324    /** Set to @c true if this stream is muted, @c false if not. */
    325     bool                   fMuted;
    326     /** Left channel volume. */
    327     uint32_t               uLeft;
    328     /** Right channel volume. */
    329     uint32_t               uRight;
     325    bool    fMuted;
     326    /** Left channel volume.
     327     *  Range is from [0 ... 255], whereas 0 specifies
     328     *  the most silent and 255 the loudest value. */
     329    uint8_t uLeft;
     330    /** Right channel volume.
     331     *  Range is from [0 ... 255], whereas 0 specifies
     332     *  the most silent and 255 the loudest value. */
     333    uint8_t uRight;
    330334} PDMAUDIOVOLUME, *PPDMAUDIOVOLUME;
     335
     336/** Defines the minimum volume allowed. */
     337#define PDMAUDIO_VOLUME_MIN     (0)
     338/** Defines the maximum volume allowed. */
     339#define PDMAUDIO_VOLUME_MAX     (255)
    331340
    332341/**
     
    354363
    355364/**
     365 * Structure for holding mixing buffer volume parameters.
     366 * The volume values are in fixed point style and must
     367 * be converted to/from before using with e.g. PDMAUDIOVOLUME.
     368 */
     369typedef struct PDMAUDMIXBUFVOL
     370{
     371    /** Set to @c true if this stream is muted, @c false if not. */
     372    bool    fMuted;
     373    /** Left volume to apply during conversion. Pass 0
     374     *  to convert the original values. May not apply to
     375     *  all conversion functions. */
     376    uint32_t uLeft;
     377    /** Right volume to apply during conversion. Pass 0
     378     *  to convert the original values. May not apply to
     379     *  all conversion functions. */
     380    uint32_t uRight;
     381} PDMAUDMIXBUFVOL, *PPDMAUDMIXBUFVOL;
     382
     383/**
    356384 * Structure for holding sample conversion parameters for
    357385 * the audioMixBufConvFromXXX / audioMixBufConvToXXX macros.
     
    360388{
    361389    /** Number of audio samples to convert. */
    362     uint32_t       cSamples;
    363     /** Volume to apply during conversion. Pass 0
    364      *  to convert the original values. May not apply to
    365      *  all conversion functions. */
    366     PDMAUDIOVOLUME Volume;
     390    uint32_t        cSamples;
     391    union
     392    {
     393        struct
     394        {
     395            /** Volume to use for conversion. */
     396            PDMAUDMIXBUFVOL Volume;
     397        } From;
     398    };
    367399} PDMAUDMIXBUFCONVOPTS;
    368400/** Pointer to conversion parameters for the audio mixer.   */
     
    435467    /** Intermediate structure for buffer conversion tasks. */
    436468    PPDMAUDIOSTRMRATE         pRate;
    437     /** Current volume used for mixing. */
    438     PDMAUDIOVOLUME            Volume;
     469    /** Internal representation of current volume used for mixing. */
     470    PDMAUDMIXBUFVOL           Volume;
    439471    /** This buffer's audio format. */
    440472    PDMAUDIOMIXBUFFMT         AudioFmt;
  • trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp

    r61609 r61887  
    7070 * value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
    7171 *
    72  * Each step thus correspons to 96 / 256 or 0.375dB. Every 6dB (16 steps)
     72 * Each step thus corresponds to 96 / 256 or 0.375dB. Every 6dB (16 steps)
    7373 * represents doubling the sample value.
    7474 *
     
    408408        uint32_t cSamples = RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
    409409        AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
    410                              pOpts->cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
     410                             pOpts->cSamples, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
    411411        for (uint32_t i = 0; i < cSamples; i++) \
    412412        { \
    413             AUDMIXBUF_MACRO_LOG(("l=%#5RI16 (0x%x), r=%#5RI16 (0x%x)", paDst, *pSrc, *pSrc, *(pSrc + 1), *(pSrc + 1))); \
    414             paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
    415             paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
    416             AUDMIXBUF_MACRO_LOG((" -> l=%#10RI64, r=%#10RI64\n", paDst->i64LSample, paDst->i64RSample)); \
     413            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
     414            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
    417415            paDst++; \
    418416        } \
     
    427425        const uint32_t cSamples = RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
    428426        AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
    429                              cSamples, sizeof(_aType), pOpts->Volume.uLeft >> 14, pOpts->Volume.uRight)); \
     427                             cSamples, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
    430428        for (uint32_t i = 0; i < cSamples; i++) \
    431429        { \
    432             paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uLeft)  >> AUDIOMIXBUF_VOL_SHIFT; \
    433             paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
    434             AUDMIXBUF_MACRO_LOG(("%#5RI16 (0x%x) -> l=%#10RI64, r=%#10RI64\n", *pSrc, *pSrc, paDst->i64LSample, paDst->i64RSample)); \
     430            paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uLeft)  >> AUDIOMIXBUF_VOL_SHIFT; \
     431            paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
    435432            pSrc++; \
    436433            paDst++; \
     
    717714
    718715/**
     716 * Converts a PDM audio volume to an internal mixing buffer volume.
     717 *
     718 * @returns IPRT status code.
     719 * @param   pVolDst                 Where to store the converted mixing buffer volume.
     720 * @param   pVolSrc                 Volume to convert.
     721 */
     722static int audioMixBufConvVol(PPDMAUDMIXBUFVOL pVolDst, PPDMAUDIOVOLUME pVolSrc)
     723{
     724    if (!pVolSrc->fMuted) /* Only change/convert the volume value if we're not muted. */
     725    {
     726        uint8_t uVolL = pVolSrc->uLeft  & 0xFF;
     727        uint8_t uVolR = pVolSrc->uRight & 0xFF;
     728
     729        /** @todo Ensure that the input is in the correct range/initialized! */
     730        pVolDst->uLeft  = s_aVolumeConv[uVolL] * (AUDIOMIXBUF_VOL_0DB >> 16);
     731        pVolDst->uRight = s_aVolumeConv[uVolR] * (AUDIOMIXBUF_VOL_0DB >> 16);
     732    }
     733
     734    pVolDst->fMuted = pVolSrc->fMuted;
     735
     736    return VINF_SUCCESS;
     737}
     738
     739/**
    719740 * Initializes a mixing buffer.
    720741 *
     
    12781299    if (cToProcess)
    12791300    {
    1280         PFNPDMAUDIOMIXBUFCONVTO pfnConv;
     1301        PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
    12811302        if (pMixBuf->AudioFmt != enmFmt)
    1282             pfnConv = audioMixBufConvToLookup(enmFmt);
     1303            pfnConvTo = audioMixBufConvToLookup(enmFmt);
    12831304        else
    1284             pfnConv = pMixBuf->pfnConvTo;
    1285 
    1286         if (pfnConv)
     1305            pfnConvTo = pMixBuf->pfnConvTo;
     1306
     1307        if (pfnConvTo)
    12871308        {
    1288             PDMAUDMIXBUFCONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
    1289 
    1290             AssertPtr(pfnConv);
    1291             pfnConv(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
     1309            PDMAUDMIXBUFCONVOPTS convOpts;
     1310            RT_ZERO(convOpts);
     1311            /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
     1312
     1313            convOpts.cSamples = cToProcess;
     1314
     1315            pfnConvTo(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
    12921316
    12931317#ifdef DEBUG
     
    12971321        }
    12981322        else
     1323        {
     1324            AssertFailed();
    12991325            rc = VERR_NOT_SUPPORTED;
     1326        }
    13001327    }
    13011328    else
     
    13481375
    13491376    if (!cbBuf)
    1350         return VINF_SUCCESS;
    1351 
    1352     uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cUsed);
    1353 
    1354     AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
    1355                    pMixBuf->pszName, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf), cToRead));
    1356 
    1357     if (!cToRead)
    1358     {
    1359 #ifdef DEBUG
    1360         audioMixBufDbgPrintInternal(pMixBuf);
    1361 #endif
     1377    {
    13621378        if (pcRead)
    13631379            *pcRead = 0;
     
    13651381    }
    13661382
    1367     PFNPDMAUDIOMIXBUFCONVTO pfnConv = audioMixBufConvToLookup(enmFmt);
    1368     if (!pfnConv) /* Audio format not supported. */
     1383    uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cUsed);
     1384
     1385    AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
     1386                   pMixBuf->pszName, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf), cToRead));
     1387
     1388    if (!cToRead)
     1389    {
     1390#ifdef DEBUG
     1391        audioMixBufDbgPrintInternal(pMixBuf);
     1392#endif
     1393        if (pcRead)
     1394            *pcRead = 0;
     1395        return VINF_SUCCESS;
     1396    }
     1397
     1398    PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
     1399    if (pMixBuf->AudioFmt != enmFmt)
     1400        pfnConvTo = audioMixBufConvToLookup(enmFmt);
     1401    else
     1402        pfnConvTo = pMixBuf->pfnConvTo;
     1403
     1404    if (!pfnConvTo) /* Audio format not supported. */
     1405    {
     1406        AssertFailed();
    13691407        return VERR_NOT_SUPPORTED;
     1408    }
    13701409
    13711410    PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offRead;
     
    13911430
    13921431    PDMAUDMIXBUFCONVOPTS convOpts;
    1393     convOpts.Volume = pMixBuf->Volume;
     1432    RT_ZERO(convOpts);
     1433    /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
    13941434
    13951435    /* Anything to do at all? */
     
    13971437    if (cLenSrc1)
    13981438    {
     1439        AssertPtr(pSamplesSrc1);
     1440
    13991441        convOpts.cSamples = cLenSrc1;
    14001442
    14011443        AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offRead, cLenSrc1));
    1402         pfnConv(pvBuf, pSamplesSrc1, &convOpts);
     1444        pfnConvTo(pvBuf, pSamplesSrc1, &convOpts);
    14031445    }
    14041446
     
    14131455        AUDMIXBUF_LOG(("P2: cToRead=%RU32, offWrite=%RU32 (%zu bytes)\n", cLenSrc2, cLenSrc1,
    14141456                       AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1)));
    1415         pfnConv((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
     1457        pfnConvTo((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
    14161458    }
    14171459
     
    14741516    AssertPtrReturnVoid(pVol);
    14751517
    1476     LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight));
    1477 
    1478     pMixBuf->Volume.fMuted = pVol->fMuted;
    1479     /** @todo Ensure that the input is in the correct range/initialized! */
    1480     pMixBuf->Volume.uLeft  = s_aVolumeConv[pVol->uLeft  & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
    1481     pMixBuf->Volume.uRight = s_aVolumeConv[pVol->uRight & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
    1482 
    1483     LogFlowFunc(("\t-> lVol=%#RX32, rVol=%#RX32\n", pMixBuf->Volume.uLeft, pMixBuf->Volume.uRight));
     1518    LogFlowFunc(("%s: lVol=%RU8, rVol=%RU8, fMuted=%RTbool\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted));
     1519
     1520    int rc2 = audioMixBufConvVol(&pMixBuf->Volume /* Dest */, pVol /* Source */);
     1521    AssertRC(rc2);
    14841522}
    14851523
     
    16371675     * Pick the conversion function and do the conversion.
    16381676     */
    1639     PFNPDMAUDIOMIXBUFCONVFROM pfnConv;
    1640     if (pMixBuf->AudioFmt != enmFmt)
    1641         pfnConv = audioMixBufConvFromLookup(enmFmt);
     1677    PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
     1678    if (!pMixBuf->Volume.fMuted)
     1679    {
     1680        if (pMixBuf->AudioFmt != enmFmt)
     1681            pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
     1682        else
     1683            pfnConvFrom = pMixBuf->pfnConvFrom;
     1684    }
    16421685    else
    1643         pfnConv = pMixBuf->Volume.fMuted ? &audioMixBufConvFromSilence : pMixBuf->pfnConvFrom;
     1686        pfnConvFrom = &audioMixBufConvFromSilence;
    16441687
    16451688    uint32_t cWritten;
    1646     if (   pfnConv
     1689    if (   pfnConvFrom
    16471690        && cToWrite)
    16481691    {
    1649         PDMAUDMIXBUFCONVOPTS convOpts = { cToWrite, pMixBuf->Volume };
    1650         cWritten = pfnConv(pMixBuf->pSamples + offSamples, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cToWrite), &convOpts);
     1692        PDMAUDMIXBUFCONVOPTS convOpts;
     1693
     1694        convOpts.cSamples           = cToWrite;
     1695        convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
     1696        convOpts.From.Volume.uLeft  = pMixBuf->Volume.uLeft;
     1697        convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
     1698
     1699        cWritten = pfnConvFrom(pMixBuf->pSamples + offSamples, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cToWrite), &convOpts);
    16511700    }
    16521701    else
    16531702    {
    16541703        cWritten = 0;
    1655         if (!pfnConv)
     1704        if (!pfnConvFrom)
     1705        {
     1706            AssertFailed();
    16561707            rc = VERR_NOT_SUPPORTED;
     1708        }
    16571709    }
    16581710
     
    17331785    }
    17341786
    1735     PFNPDMAUDIOMIXBUFCONVFROM pfnCnvFrm;
    1736     if (pMixBuf->AudioFmt != enmFmt)
    1737         pfnCnvFrm = audioMixBufConvFromLookup(enmFmt);
     1787    PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
     1788    if (!pMixBuf->Volume.fMuted)
     1789    {
     1790        if (pMixBuf->AudioFmt != enmFmt)
     1791            pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
     1792        else
     1793            pfnConvFrom = pMixBuf->pfnConvFrom;
     1794    }
    17381795    else
    1739         pfnCnvFrm = pMixBuf->Volume.fMuted ? &audioMixBufConvFromSilence : pMixBuf->pfnConvFrom;
    1740 
    1741     if (!pfnCnvFrm)
     1796        pfnConvFrom = &audioMixBufConvFromSilence;
     1797
     1798    if (!pfnConvFrom)
     1799    {
     1800        AssertFailed();
    17421801        return VERR_NOT_SUPPORTED;
    1743 
    1744     int rc = VINF_SUCCESS; /** @todo Move this down to where you actually need it and you'll get somewhat nice code! */
     1802    }
    17451803
    17461804    uint32_t cToWrite = AUDIOMIXBUF_B2S(pMixBuf, cbBuf);
     
    17821840
    17831841    PDMAUDMIXBUFCONVOPTS convOpts;
    1784     convOpts.Volume = pMixBuf->Volume;
     1842    convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
     1843    convOpts.From.Volume.uLeft  = pMixBuf->Volume.uLeft;
     1844    convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
     1845
     1846    LogFlowFunc(("ASDF %RU32 %RU32\n", pMixBuf->Volume.uLeft, pMixBuf->Volume.uRight));
    17851847
    17861848    /* Anything to do at all? */
     
    17881850    {
    17891851        convOpts.cSamples = cLenDst1;
    1790         cWrittenTotal = pfnCnvFrm(pSamplesDst1, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), &convOpts);
     1852        cWrittenTotal = pfnConvFrom(pSamplesDst1, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), &convOpts);
    17911853        Assert(cWrittenTotal == cLenDst1);
    17921854
     
    17971859
    17981860    /* Second part present? */
    1799     if (   RT_LIKELY(RT_SUCCESS(rc)) /** @todo r=bird: RT_SUCCESS implies RT_LIKELY for at least 10 years now. besides, it's actually always VINF_SUCCESS at this point. */
    1800         && cLenDst2)
     1861    if (cLenDst2)
    18011862    {
    18021863        AssertPtr(pSamplesDst2);
    18031864
    18041865        convOpts.cSamples = cLenDst2;
    1805         cWrittenTotal += pfnCnvFrm(pSamplesDst2,
    1806                                    (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
    1807                                    cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
    1808                                    &convOpts);
     1866        cWrittenTotal += pfnConvFrom(pSamplesDst2,
     1867                                     (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
     1868                                     cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
     1869                                     &convOpts);
    18091870        Assert(cWrittenTotal == cLenDst1 + cLenDst2);
    18101871
     
    18191880#endif
    18201881
    1821     if (RT_SUCCESS(rc))
    1822     {
    1823         pMixBuf->offWrite = (pMixBuf->offWrite + cWrittenTotal) % pMixBuf->cSamples;
    1824         pMixBuf->cUsed   += cWrittenTotal;
    1825 
    1826         if (pMixBuf->cUsed > pMixBuf->cSamples)
    1827         {
    1828             AUDMIXBUF_LOG(("Warning: %RU32 unprocessed samples overwritten\n", pMixBuf->cUsed - pMixBuf->cSamples));
    1829             pMixBuf->cUsed = pMixBuf->cSamples;
    1830 
    1831             rc = VINF_BUFFER_OVERFLOW;
    1832         }
    1833 
    1834         if (pcWritten)
    1835             *pcWritten = cWrittenTotal;
    1836     }
     1882    pMixBuf->offWrite = (pMixBuf->offWrite + cWrittenTotal) % pMixBuf->cSamples;
     1883    pMixBuf->cUsed   += cWrittenTotal;
     1884
     1885    int rc = VINF_SUCCESS;
     1886
     1887    if (pMixBuf->cUsed > pMixBuf->cSamples)
     1888    {
     1889        AUDMIXBUF_LOG(("Warning: %RU32 unprocessed samples overwritten\n", pMixBuf->cUsed - pMixBuf->cSamples));
     1890        pMixBuf->cUsed = pMixBuf->cSamples;
     1891
     1892        rc = VINF_BUFFER_OVERFLOW;
     1893    }
     1894
     1895    if (pcWritten)
     1896        *pcWritten = cWrittenTotal;
    18371897
    18381898#ifdef DEBUG
     
    18431903                   pMixBuf->offWrite, cLenDst1, cLenDst2, cLenDst1 + cLenDst2,
    18441904                   AUDIOMIXBUF_S2B(pMixBuf, cLenDst1 + cLenDst2), rc));
    1845 
    18461905    return rc;
    18471906}
  • trunk/src/VBox/Devices/Audio/AudioMixer.cpp

    r61764 r61887  
    8484            /* Set initial volume to max. */
    8585            pSink->Volume.fMuted = false;
    86             pSink->Volume.uLeft  = 0x7F;
    87             pSink->Volume.uRight = 0x7F;
     86            pSink->Volume.uLeft  = PDMAUDIO_VOLUME_MAX;
     87            pSink->Volume.uRight = PDMAUDIO_VOLUME_MAX;
     88
     89            /* Ditto for the combined volume. */
     90            pSink->VolumeCombined.fMuted = false;
     91            pSink->VolumeCombined.uLeft  = PDMAUDIO_VOLUME_MAX;
     92            pSink->VolumeCombined.uRight = PDMAUDIO_VOLUME_MAX;
    8893
    8994            RTListAppend(&pMixer->lstSinks, &pSink->Node);
     
    125130            RTListInit(&pMixer->lstSinks);
    126131
     132            /* Set master volume to the max. */
    127133            pMixer->VolMaster.fMuted = false;
    128             pMixer->VolMaster.uLeft  = UINT32_MAX;
    129             pMixer->VolMaster.uRight = UINT32_MAX;
     134            pMixer->VolMaster.uLeft  = PDMAUDIO_VOLUME_MAX;
     135            pMixer->VolMaster.uRight = PDMAUDIO_VOLUME_MAX;
    130136
    131137            LogFlowFunc(("Created mixer '%s'\n", pMixer->pszName));
     
    200206}
    201207
    202 void AudioMixerInvalidate(PAUDIOMIXER pMixer)
    203 {
    204     AssertPtrReturnVoid(pMixer);
    205 
    206     LogFlowFunc(("[%s]: Invalidating ...\n", pMixer->pszName));
     208int audioMixerInvalidateInternal(PAUDIOMIXER pMixer)
     209{
     210    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
     211
     212    LogFlowFunc(("[%s]\n", pMixer->pszName));
    207213
    208214    /* Propagate new master volume to all connected sinks. */
     
    213219        AssertRC(rc2);
    214220    }
     221
     222    return VINF_SUCCESS;
     223}
     224
     225void AudioMixerInvalidate(PAUDIOMIXER pMixer)
     226{
     227    AssertPtrReturnVoid(pMixer);
     228
     229    LogFlowFunc(("[%s]\n", pMixer->pszName));
     230
     231    int rc2 = audioMixerInvalidateInternal(pMixer);
     232    AssertRC(rc2);
    215233}
    216234
    217235static int audioMixerRemoveSinkInternal(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
    218236{
    219     AssertPtrReturn(pMixer, VERR_INVALID_PARAMETER);
     237    AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
    220238    if (!pSink)
    221239        return VERR_NOT_FOUND;
     
    267285    AssertPtrReturn(pVol,   VERR_INVALID_POINTER);
    268286
    269     pMixer->VolMaster = *pVol;
     287    memcpy(&pMixer->VolMaster, pVol, sizeof(PDMAUDIOVOLUME));
    270288
    271289    LogFlowFunc(("[%s]: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     
    273291                 pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
    274292
    275     AudioMixerInvalidate(pMixer);
    276     return VINF_SUCCESS;
     293    return audioMixerInvalidateInternal(pMixer);
    277294}
    278295
     
    350367        /** @todo Check if stream already is assigned to (another) sink. */
    351368
     369        /* Apply the sink's combined volume to the stream. */
     370        AssertPtr(pStream->pConn);
     371        int rc2 = pStream->pConn->pfnStreamSetVolume(pStream->pConn, pStream->pStream, &pSink->VolumeCombined);
     372        AssertRC(rc2);
     373
    352374        /* Save pointer to sink the stream is attached to. */
    353375        pStream->pSink = pSink;
     
    874896    AssertPtrReturn(pSink, VERR_INVALID_POINTER);
    875897    AssertPtrReturn(pVol,  VERR_INVALID_POINTER);
     898
     899    memcpy(&pSink->Volume, pVol, sizeof(PDMAUDIOVOLUME));
     900
     901    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     902                 pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
     903
    876904    AssertPtr(pSink->pParent);
    877 
    878     LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
    879 
    880     pSink->Volume = *pVol;
    881 
    882905    return audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster);
    883906}
     
    10221045    AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER);
    10231046
    1024     LogFlowFunc(("Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
    1025                   pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
    1026     LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     1047    LogFlowFunc(("[%s]: Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     1048                  pSink->pszName, pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
     1049    LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32 ",
    10271050                  pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
    10281051
    10291052    /** @todo Very crude implementation for now -- needs more work! */
    10301053
    1031     PDMAUDIOVOLUME volSink;
    1032     volSink.fMuted  = pVolMaster->fMuted || pSink->Volume.fMuted;
    1033     volSink.uLeft   = (pSink->Volume.uLeft  * pVolMaster->uLeft)  / UINT8_MAX;
    1034     volSink.uRight  = (pSink->Volume.uRight * pVolMaster->uRight) / UINT8_MAX;
    1035 
    1036     LogFlowFunc(("\t-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
    1037                   volSink.fMuted, volSink.uLeft, volSink.uRight));
    1038 
    1039     bool fOut = pSink->enmDir == AUDMIXSINKDIR_OUTPUT;
     1054    pSink->VolumeCombined.fMuted  = pVolMaster->fMuted || pSink->Volume.fMuted;
     1055
     1056    pSink->VolumeCombined.uLeft   = (  (pSink->Volume.uLeft ? pSink->Volume.uLeft : 1)
     1057                                     * (pVolMaster->uLeft   ? pVolMaster->uLeft   : 1)) / PDMAUDIO_VOLUME_MAX;
     1058
     1059    pSink->VolumeCombined.uRight  = (  (pSink->Volume.uRight ? pSink->Volume.uRight : 1)
     1060                                     * (pVolMaster->uRight   ? pVolMaster->uRight   : 1)) / PDMAUDIO_VOLUME_MAX;
     1061
     1062    LogFlow(("-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
     1063             pSink->VolumeCombined.fMuted, pSink->VolumeCombined.uLeft, pSink->VolumeCombined.uRight));
    10401064
    10411065    /* Propagate new sink volume to all streams in the sink. */
     
    10431067    RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
    10441068    {
    1045         int rc2 = pMixStream->pConn->pfnStreamSetVolume(pMixStream->pConn, pMixStream->pStream, &volSink);
     1069        int rc2 = pMixStream->pConn->pfnStreamSetVolume(pMixStream->pConn, pMixStream->pStream, &pSink->VolumeCombined);
    10461070        AssertRC(rc2);
    10471071    }
  • trunk/src/VBox/Devices/Audio/AudioMixer.h

    r61668 r61887  
    181181     *  be combined with the mixer's master volume. */
    182182    PDMAUDIOVOLUME          Volume;
     183    /** The volume of this sink, combined with the last set  master volume. */
     184    PDMAUDIOVOLUME          VolumeCombined;
    183185    /** Timestamp (in ns) since last update. */
    184186    uint64_t                tsLastUpdatedNS;
  • trunk/src/VBox/Devices/Audio/DevIchAc97.cpp

    r61668 r61887  
    120120#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
    121121
    122 /** @name Buffer Descriptor
     122/** @name Buffer Descriptor (BD).
    123123 * @{ */
    124124#define BD_IOC RT_BIT(31)          /**< Interrupt on Completion. */
     
    128128/** @} */
    129129
    130 /** @name Extended Audio Status and Control Register
     130/** @name Extended Audio Status and Control Register (EACS).
    131131 * @{ */
    132132#define EACS_VRA 1                 /**< Variable Rate Audio (4.2.1.1). */
     
    134134/** @} */
    135135
    136 #define VOL_MASK 0x1f
    137 #define MUTE_SHIFT 15
     136/** @name Baseline Audio Register Set (BARS).
     137 * @{ */
     138#define AC97_BARS_VOL_MASK              0x1f   /**< Volume mask for the Baseline Audio Register Set (5.7.2). */
     139#define AC97_BARS_VOL_STEPS             31     /**< Volume steps for the Baseline Audio Register Set (5.7.2). */
     140#define AC97_BARS_VOL_MUTE_SHIFT        15     /**< Mute bit shift for the Baseline Audio Register Set (5.7.2). */
     141
     142#define AC97_BARS_VOL_MASTER_MASK       0x3f   /**< Master volume mask for the Baseline Audio Register Set (5.7.2). */
     143#define AC97_BARS_VOL_MASTER_STEPS      63     /**< Master volume steps for the Baseline Audio Register Set (5.7.2). */
     144#define AC97_BARS_VOL_MASTER_MUTE_SHIFT 15     /**< Master Mute bit shift for the Baseline Audio Register Set (5.7.2). */
     145
     146#define AC97_VOL_MAX_STEPS              63
     147/** @} */
    138148
    139149#define REC_MASK 7
     
    637647}
    638648
    639 static void ichac97MixerSet(PAC97STATE pThis, uint32_t u8Idx, uint16_t v)
    640 {
    641     if (u8Idx + 2 > sizeof(pThis->mixer_data))
    642     {
    643         AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
     649static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal)
     650{
     651    if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
     652    {
     653        AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
    644654        return;
    645655    }
    646656
    647     pThis->mixer_data[u8Idx + 0] = RT_LO_U8(v);
    648     pThis->mixer_data[u8Idx + 1] = RT_HI_U8(v);
    649 }
    650 
    651 static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t u8Idx)
     657    pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal);
     658    pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal);
     659}
     660
     661static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx)
    652662{
    653663    uint16_t uVal;
    654664
    655     if (u8Idx + 2 > sizeof(pThis->mixer_data))
    656     {
    657         AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
     665    if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
     666    {
     667        AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
    658668        uVal = UINT16_MAX;
    659669    }
    660670    else
    661         uVal = RT_MAKE_U16(pThis->mixer_data[u8Idx + 0], pThis->mixer_data[u8Idx + 1]);
     671        uVal = RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]);
    662672
    663673    return uVal;
     
    953963}
    954964
    955 static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL mt, uint32_t val)
    956 {
    957     int mute = (val >> MUTE_SHIFT) & 1;
    958     uint8_t rvol = val & VOL_MASK;
    959     uint8_t lvol = (val >> 8) & VOL_MASK;
    960 
    961     /* For the master volume, 0 corresponds to 0dB gain. But for the other
    962      * volume controls, 0 corresponds to +12dB and 8 to 0dB. */
    963     if (mt != PDMAUDIOMIXERCTL_VOLUME)
    964     {
     965static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
     966{
     967#ifdef DEBUG
     968    uint32_t uValMaster = ichac97MixerGet(pThis, AC97_Master_Volume_Mute);
     969
     970    bool    fMasterMuted = (uValMaster >> AC97_BARS_VOL_MASTER_MUTE_SHIFT) & 1;
     971    uint8_t lMasterAtt   = (uValMaster >> 8) & AC97_BARS_VOL_MASTER_MASK;
     972    uint8_t rMasterAtt   = uValMaster & AC97_BARS_VOL_MASTER_MASK;
     973
     974    Assert(lMasterAtt <= AC97_VOL_MAX_STEPS);
     975    Assert(rMasterAtt <= AC97_VOL_MAX_STEPS);
     976
     977    LogFlowFunc(("lMasterAtt=%RU8, rMasterAtt=%RU8, fMasterMuted=%RTbool\n", lMasterAtt, rMasterAtt, fMasterMuted));
     978#endif
     979
     980    bool    fCntlMuted;
     981    uint8_t lCntlAtt, rCntlAtt;
     982
     983    uint8_t uSteps;
     984
     985    /*
     986     * From AC'97 SoundMax Codec AD1981A/AD1981B:
     987     * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the
     988     *  D5 or D13 bits are set to 1, their respective lower five volume bits are automatically
     989     *  set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever
     990     *  these bits are set to 1."
     991     *
     992     * Linux ALSA depends on this behavior.
     993     */
     994    if (uVal & RT_BIT(5))
     995        uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
     996    if (uVal & RT_BIT(13))
     997        uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
     998
     999    /* For the master volume, 0 corresponds to 0dB attenuation, each step
     1000     * corresponds to -1.5dB. */
     1001    if (index == AC97_Master_Volume_Mute)
     1002    {
     1003        fCntlMuted = (uVal >> AC97_BARS_VOL_MASTER_MUTE_SHIFT) & 1;
     1004        lCntlAtt   = (uVal >> 8) & AC97_BARS_VOL_MASTER_MASK;
     1005        rCntlAtt   = uVal & AC97_BARS_VOL_MASTER_MASK;
     1006
     1007        uSteps = PDMAUDIO_VOLUME_MAX / AC97_BARS_VOL_MASTER_STEPS;
     1008    }
     1009    /* For other volume controls:
     1010     * - 0 - 7 corresponds to +12dB, in 1.5dB steps.
     1011     * - 8     corresponds to 0dB gain (unchanged).
     1012     * - 9 - X corresponds to -1.5dB steps. */
     1013    else
     1014    {
     1015        fCntlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
     1016        lCntlAtt   = (uVal >> 8) & AC97_BARS_VOL_MASK;
     1017        rCntlAtt   = uVal & AC97_BARS_VOL_MASK;
     1018
     1019        Assert(lCntlAtt <= AC97_VOL_MAX_STEPS);
     1020        Assert(rCntlAtt <= AC97_VOL_MAX_STEPS);
     1021
     1022#ifndef VBOX_WITH_AC97_GAIN_SUPPORT
    9651023        /* NB: Currently there is no gain support, only attenuation. */
    966         lvol = lvol < 8 ? 0 : lvol - 8;
    967         rvol = rvol < 8 ? 0 : rvol - 8;
    968     }
    969 
    970     /* AC'97 has 1.5dB steps; we use 0.375dB steps. */
    971     rvol = 255 - rvol * 4;
    972     lvol = 255 - lvol * 4;
    973 
    974     LogFunc(("mt=%ld, val=%RX32, mute=%RTbool\n", mt, val, RT_BOOL(mute)));
     1024        lCntlAtt = lCntlAtt <= 8 ? 0 : lCntlAtt - 8;
     1025        rCntlAtt = rCntlAtt <= 8 ? 0 : rCntlAtt - 8;
     1026#endif
     1027        uSteps = PDMAUDIO_VOLUME_MAX / AC97_BARS_VOL_STEPS;
     1028    }
     1029
     1030    LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
     1031
     1032    LogFunc(("lAtt=%RU8, rAtt=%RU8 ", lCntlAtt, rCntlAtt));
     1033
     1034    /*
     1035     * AC'97 volume controls have 31 steps, each -1.5dB => -40,5dB attenuation total.
     1036     *
     1037     * In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX) steps, each -0.375dB,
     1038     * where 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
     1039     */
     1040    uint8_t lVol = PDMAUDIO_VOLUME_MAX - RT_MIN((lCntlAtt * 4 /* dB resolution */ * uSteps /* steps */), PDMAUDIO_VOLUME_MAX);
     1041    uint8_t rVol = PDMAUDIO_VOLUME_MAX - RT_MIN((rCntlAtt * 4 /* dB resolution */ * uSteps /* steps */), PDMAUDIO_VOLUME_MAX);
     1042
     1043    Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCntlMuted, lVol, rVol));
    9751044
    9761045    int rc;
     
    9781047    if (pThis->pMixer) /* Device can be in reset state, so no mixer available. */
    9791048    {
    980         PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
    981         switch (mt)
     1049        PDMAUDIOVOLUME Vol = { fCntlMuted, lVol, rVol };
     1050        switch (enmMixerCtl)
    9821051        {
    9831052            case PDMAUDIOMIXERCTL_VOLUME:
    984                 rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
     1053                rc = AudioMixerSetMasterVolume(pThis->pMixer,    &Vol);
    9851054                break;
    986 
    9871055            case PDMAUDIOMIXERCTL_FRONT:
    988                 rc = AudioMixerSinkSetVolume(pThis->pSinkOutput, &vol);
     1056                rc = AudioMixerSinkSetVolume(pThis->pSinkOutput, &Vol);
    9891057                break;
    9901058
    9911059            case PDMAUDIOMIXERCTL_MIC_IN:
    992                 rc = AudioMixerSinkSetVolume(pThis->pSinkMicIn, &vol);
     1060                rc = AudioMixerSinkSetVolume(pThis->pSinkMicIn,  &Vol);
    9931061                break;
    9941062
    9951063            case PDMAUDIOMIXERCTL_LINE_IN:
    996                 rc = AudioMixerSinkSetVolume(pThis->pSinkLineIn, &vol);
     1064                rc = AudioMixerSinkSetVolume(pThis->pSinkLineIn, &Vol);
    9971065                break;
    9981066
    9991067            default:
     1068                AssertFailed();
    10001069                rc = VERR_NOT_SUPPORTED;
    10011070                break;
     
    10051074        rc = VINF_SUCCESS;
    10061075
    1007     rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
    1008     lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
    1009 
    1010     /*
    1011      * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
    1012      * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
    1013      * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
    1014      * all lower 5 bits will read ones whenever these bits are set to `1.'"
    1015      *
    1016      *  Linux ALSA depends on this behavior.
    1017      */
    1018     if (val & RT_BIT(5))
    1019         val |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
    1020     if (val & RT_BIT(13))
    1021         val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
    1022 
    1023     ichac97MixerSet(pThis, index, val);
     1076    ichac97MixerSet(pThis, index, uVal);
    10241077
    10251078    if (RT_FAILURE(rc))
     
    11101163    {
    11111164        /* Analog Devices 1980 (AD1980) */
    1112         ichac97MixerSet(pThis, AC97_Reset                   , 0x0010);    /* Headphones. */
     1165        ichac97MixerSet(pThis, AC97_Reset                   , 0x0010); /* Headphones. */
    11131166        ichac97MixerSet(pThis, AC97_Vendor_ID1              , 0x4144);
    11141167        ichac97MixerSet(pThis, AC97_Vendor_ID2              , 0x5370);
     
    11291182    ichac97RecordSelect(pThis, 0);
    11301183
    1131     ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME,  0x8000);
    1132     ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,   0x8808);
    1133     ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
     1184    ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute,  PDMAUDIOMIXERCTL_VOLUME, 0x8000);
     1185    ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT,         0x8808);
     1186    ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN,       0x8808);
     1187    ichac97MixerSetVolume(pThis, AC97_Mic_Volume_Mute,     PDMAUDIOMIXERCTL_MIC_IN,        0x8808);
    11341188
    11351189    return VINF_SUCCESS;
     
    19642018                case AC97_Master_Volume_Mute:
    19652019                    if (pThis->uCodecModel == Codec_AD1980)
     2020                    {
    19662021                        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_LOSEL)
    1967                             break;  /* Register controls surround (rear), do nothing. */
     2022                            break; /* Register controls surround (rear), do nothing. */
     2023                    }
    19682024                    ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
    19692025                    break;
    19702026                case AC97_Headphone_Volume_Mute:
    19712027                    if (pThis->uCodecModel == Codec_AD1980)
     2028                    {
    19722029                        if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
     2030                        {
    19732031                            /* Register controls PCM (front) outputs. */
    19742032                            ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
     2033                        }
     2034                    }
    19752035                    break;
    19762036                case AC97_PCM_Out_Volume_Mute:
     
    22152275    V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT);
    22162276    V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
     2277    V_(AC97_Mic_Volume_Mute,     PDMAUDIOMIXERCTL_MIC_IN);
    22172278# undef V_
    22182279    if (pThis->uCodecModel == Codec_AD1980)
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r61764 r61887  
    16071607    LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));
    16081608
    1609     AudioMixBufSetVolume(&pStream->MixBuf, pVol);
    1610 
     1609    PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
     1610    PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
     1611
     1612    AudioMixBufSetVolume(&pHstStream->MixBuf, pVol);
     1613    AudioMixBufSetVolume(&pGstStream->MixBuf, pVol);
    16111614    return VINF_SUCCESS;
    16121615}
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