VirtualBox

Changeset 60937 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
May 11, 2016 1:10:09 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107159
Message:

Audio/SB16: Fixes for software mixer usage.

File:
1 edited

Legend:

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

    r60925 r60937  
    173173    /** Audio sink for PCM output. */
    174174    R3PTRTYPE(PAUDMIXSINK)         pSinkOutput;
     175    /** Number of active (running) SDn streams. */
     176    uint8_t                        cStreamsActive;
    175177#ifndef VBOX_WITH_AUDIO_CALLBACKS
    176178    /** The timer for pumping data thru the attached LUN drivers. */
     
    192194
    193195static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
     196#ifndef VBOX_WITH_AUDIO_CALLBACKS
     197static void sb16TimerMaybeStart(PSB16STATE pThis);
     198static void sb16TimerMaybeStop(PSB16STATE pThis);
     199#endif
    194200
    195201/**
     
    426432    LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
    427433
    428     PSB16DRIVER pDrv;
     434    PDMDevHlpDMASetDREQ(pThis->pDevInsR3, dma, hold);
     435
    429436    if (hold)
    430437    {
    431         PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 1);
    432         PDMDevHlpDMASchedule (pThis->pDevInsR3);
    433         RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
    434             pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
    435                                            pDrv->Out.pStrmOut, true /* fEnable */);
    436     }
     438        pThis->cStreamsActive++;
     439#ifndef VBOX_WITH_AUDIO_CALLBACKS
     440        sb16TimerMaybeStart(pThis);
     441#endif
     442        PDMDevHlpDMASchedule(pThis->pDevInsR3);
     443    }
     444#ifndef VBOX_WITH_AUDIO_CALLBACKS
    437445    else
    438446    {
    439         PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 0);
    440         RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
    441             pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
    442                                            pDrv->Out.pStrmOut, false /* fEnable */);
    443     }
     447        if (pThis->cStreamsActive)
     448            pThis->cStreamsActive--;
     449        sb16TimerMaybeStop(pThis);
     450    }
     451#endif
     452
     453    AudioMixerSinkCtl(pThis->pSinkOutput,
     454                      hold == 1 ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
    444455}
    445456
     
    459470    {
    460471        PDMAUDIOSTREAMCFG streamCfg;
     472        RT_ZERO(streamCfg);
     473        streamCfg.enmDir        = PDMAUDIODIR_OUT;
    461474        streamCfg.uHz           = pThis->freq;
    462475        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
     
    594607    {
    595608        PDMAUDIOSTREAMCFG streamCfg;
     609        RT_ZERO(streamCfg);
     610        streamCfg.enmDir        = PDMAUDIODIR_OUT;
    596611        streamCfg.uHz           = pThis->freq;
    597612        streamCfg.cChannels     = 1 << pThis->fmt_stereo;
     
    11061121
    11071122    PDMAUDIOSTREAMCFG streamCfg;
     1123    RT_ZERO(streamCfg);
     1124    streamCfg.enmDir        = PDMAUDIODIR_OUT;
    11081125    streamCfg.uHz           = pThis->freq;
    11091126    streamCfg.cChannels     = 1; /* Mono */
     
    16241641        AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
    16251642
     1643        /*
     1644         * Write data to the mixer sink.
     1645         */
    16261646        uint32_t cbWritten;
    1627 
    1628         /* Just multiplex the output to the connected backends.
    1629          * No need to utilize the virtual mixer here (yet). */
    1630         PSB16DRIVER pDrv;
    1631         RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
    1632         {
    1633             int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
    1634                                                  tmpbuf, cbToRead, &cbWritten);
    1635             LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, rc2, cbWritten));
    1636         }
     1647        rc = AudioMixerSinkWrite(pThis->pSinkOutput, AUDMIXOP_COPY, tmpbuf, cbToRead, &cbWritten);
     1648        if (RT_FAILURE(rc))
     1649            break;
     1650
     1651        LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbWritten=%RU32, cbLeft=%RU32, rc=%Rrc\n",
     1652                     cbToRead, cbToWrite, cbWritten, cbToWrite - cbWrittenTotal, rc));
    16371653
    16381654        Assert(cbToWrite >= cbToRead);
     
    17341750}
    17351751
     1752#ifndef VBOX_WITH_AUDIO_CALLBACKS
     1753
     1754static void sb16TimerMaybeStart(PSB16STATE pThis)
     1755{
     1756    LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
     1757
     1758    if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
     1759        return;
     1760
     1761    if (!pThis->pTimerIO)
     1762        return;
     1763
     1764    /* Fire off timer. */
     1765    TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
     1766}
     1767
     1768static void sb16TimerMaybeStop(PSB16STATE pThis)
     1769{
     1770    LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
     1771
     1772    if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
     1773        return;
     1774
     1775    if (!pThis->pTimerIO)
     1776        return;
     1777
     1778    int rc2 = TMTimerStop(pThis->pTimerIO);
     1779    AssertRC(rc2);
     1780}
     1781
    17361782static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    17371783{
     
    17401786    AssertPtr(pThis);
    17411787
    1742     uint32_t cbInMax  = 0;
    1743     uint32_t cbOutMin = UINT32_MAX;
    1744 
    1745     PSB16DRIVER pDrv;
    1746 
    17471788    uint64_t cTicksNow     = TMTimerGet(pTimer);
    1748     uint64_t cTicksElapsed = cTicksNow  - pThis->uTimerTSIO;
     1789    uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTSIO;
    17491790    uint64_t cTicksPerSec  = TMTimerGetFreq(pTimer);
    17501791
    17511792    pThis->uTimerTSIO = cTicksNow;
    17521793
    1753     /*
    1754      * Calculate the mixer's (fixed) sampling rate.
    1755      */
    1756     AssertPtr(pThis->pMixer);
    1757 
    1758     PDMAUDIOSTREAMCFG mixerStrmCfg;
    1759     int rc = AudioMixerGetDeviceFormat(pThis->pMixer, &mixerStrmCfg);
    1760     AssertRC(rc);
    1761 
    1762     PDMPCMPROPS mixerStrmProps;
    1763     rc = DrvAudioStreamCfgToProps(&mixerStrmCfg, &mixerStrmProps);
    1764     AssertRC(rc);
    1765 
    1766     uint32_t cMixerSamplesMin  = (int)((2 * cTicksElapsed * mixerStrmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
    1767     uint32_t cbMixerSamplesMin = cMixerSamplesMin << mixerStrmProps.cShift;
    1768 
    1769     RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
    1770     {
    1771         uint32_t cbIn = 0;
    1772         uint32_t cbOut = 0;
    1773 
    1774         rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
    1775                                               &cbIn, &cbOut, NULL /* cSamplesLive */);
    1776         if (RT_SUCCESS(rc))
    1777             rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* cSamplesPlayed */);
    1778 
    1779 #ifdef DEBUG_TIMER
    1780         LogFlowFunc(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
    1781 #endif
    1782         /* If we there was an error handling (available) output or there simply is no output available,
    1783          * then calculate the minimum data rate which must be processed by the device emulation in order
    1784          * to function correctly.
    1785          *
    1786          * This is not the optimal solution, but as we have to deal with this on a timer-based approach
    1787          * (until we have the audio callbacks) we need to have device' DMA engines running. */
    1788         if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
    1789         {
    1790             /* Use the mixer's (fixed) sampling rate. */
    1791             cbOut = RT_MAX(cbOut, cbMixerSamplesMin);
    1792             continue;
    1793         }
    1794 
    1795         const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
    1796         if (   RT_FAILURE(rc)
    1797             || !fIsActiveOut)
    1798         {
    1799             uint32_t cSamplesMin  = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
    1800             uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
    1801 
    1802             Log2Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
    1803 
    1804             cbOut = RT_MAX(cbOut, cbSamplesMin);
    1805         }
    1806 
    1807         cbOutMin = RT_MIN(cbOutMin, cbOut);
    1808         cbInMax  = RT_MAX(cbInMax, cbIn);
    1809     }
    1810 
    1811     Log2Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
    1812 
    1813     if (cbOutMin == UINT32_MAX)
    1814         cbOutMin = 0;
    1815 
    1816     /*
    1817      * Playback.
    1818      */
    1819     if (cbOutMin)
    1820     {
    1821         Assert(cbOutMin != UINT32_MAX);
    1822 
     1794    uint32_t cbOut;
     1795    AudioMixerSinkTimerUpdate(pThis->pSinkOutput, cTicksPerSec, cTicksElapsed, &cbOut);
     1796    if (cbOut)
     1797    {
    18231798        /* New space available, see if we can transfer more. */
    18241799        PDMDevHlpDMASchedule(pThis->pDevInsR3);
    18251800    }
    1826 
    1827     /*
    1828      * Recording.
    1829      */
    1830     /** @todo Implement recording. */
    18311801
    18321802    /* Kick the timer again. */
     
    18351805    TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
    18361806}
     1807
     1808#endif /* !VBOX_WITH_AUDIO_CALLBACKS */
    18371809
    18381810static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
     
    19591931        {
    19601932            PDMAUDIOSTREAMCFG streamCfg;
     1933            RT_ZERO(streamCfg);
     1934            streamCfg.enmDir        = PDMAUDIODIR_OUT;
    19611935            streamCfg.uHz           = pThis->freq;
    19621936            streamCfg.cChannels     = 1 << pThis->fmt_stereo;
     
    20482022{
    20492023    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    2050     AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
    2051 
    2052     pCfg->enmDir = PDMAUDIODIR_OUT;
    2053     int rc = VINF_SUCCESS;
     2024    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
     2025
     2026    AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
     2027
     2028    /* Update the sink's format. */
     2029    PDMPCMPROPS PCMProps;
     2030    int rc = DrvAudioStreamCfgToProps(pCfg, &PCMProps);
     2031    if (RT_SUCCESS(rc))
     2032        rc = AudioMixerSinkSetFormat(pThis->pSinkOutput, &PCMProps);
     2033
     2034    if (RT_FAILURE(rc))
     2035        return rc;
    20542036
    20552037    PSB16DRIVER pDrv;
     
    20582040    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
    20592041    {
    2060         char *pszDesc;
    2061         if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
     2042        if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] sb16.po (%RU32Hz, %RU8 %s)",
     2043                         pDrv->uLUN, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"))
    20622044        {
    2063             rc = VERR_NO_MEMORY;
     2045            rc = VERR_BUFFER_OVERFLOW;
    20642046            break;
    20652047        }
     
    20742056        {
    20752057            rc2 = AudioMixerSinkAddStream(pThis->pSinkOutput, pDrv->Out.pMixStrm);
    2076             LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pszDesc, rc2));
     2058            LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
    20772059        }
    2078 
    2079         RTStrFree(pszDesc);
    20802060
    20812061        if (RT_FAILURE(rc2))
     
    20932073
    20942074    return rc;
     2075}
     2076
     2077static void sb16CloseOut(PSB16STATE pThis)
     2078{
     2079    AssertPtrReturnVoid(pThis);
     2080
     2081    LogFlowFuncEnter();
     2082
     2083    PSB16DRIVER pDrv;
     2084    RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
     2085    {
     2086        AudioMixerSinkRemoveStream(pThis->pSinkOutput, pDrv->Out.pMixStrm);
     2087        AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
     2088        pDrv->Out.pMixStrm = NULL;
     2089    }
    20952090}
    20962091
     
    21412136
    21422137/**
     2138 * Powers off the device.
     2139 *
     2140 * @param   pDevIns             Device instance to power off.
     2141 */
     2142static DECLCALLBACK(void) sb16PowerOff(PPDMDEVINS pDevIns)
     2143{
     2144    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
     2145
     2146    LogRel2(("SB16: Powering off ...\n"));
     2147
     2148    /**
     2149     * Note: Destroy the mixer while powering off and *not* in sb16Destruct,
     2150     *       giving the mixer the chance to release any references held to
     2151     *       PDM audio streams it maintains.
     2152     */
     2153    if (pThis->pMixer)
     2154    {
     2155        AudioMixerDestroy(pThis->pMixer);
     2156        pThis->pMixer = NULL;
     2157    }
     2158}
     2159
     2160/**
    21432161 * @interface_method_impl{PDMDEVREG,pfnDestruct}
    21442162 */
     
    21472165    PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
    21482166
     2167    LogFlowFuncEnter();
     2168
    21492169    PSB16DRIVER pDrv;
    2150 
    2151     RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
    2152         pDrv->Out.pMixStrm = NULL;
    2153 
    2154     pThis->pSinkOutput = NULL;
    2155 
    2156     if (pThis->pMixer)
    2157     {
    2158         AudioMixerDestroy(pThis->pMixer);
    2159         pThis->pMixer = NULL;
    2160     }
     2170    while (!RTListIsEmpty(&pThis->lstDrv))
     2171    {
     2172        pDrv = RTListGetFirst(&pThis->lstDrv, SB16DRIVER, Node);
     2173
     2174        RTListNodeRemove(&pDrv->Node);
     2175        RTMemFree(pDrv);
     2176    }
     2177
     2178    sb16CloseOut(pThis);
    21612179
    21622180    return VINF_SUCCESS;
     
    23182336        AssertPtr(pCon);
    23192337
    2320         /* Note: No input streams available for SB16 yet. */
    2321         bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
     2338        /** @todo No input streams available for SB16 yet. */
     2339        bool fValidOut = AudioMixerStreamIsValid(pDrv->Out.pMixStrm);
    23222340        if (!fValidOut)
    23232341        {
     
    23382356        rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
    23392357                                    TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
    2340         if (RT_FAILURE(rc))
    2341             AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
    2342         else
     2358        if (RT_SUCCESS(rc))
    23432359        {
    23442360            pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz;
     
    23462362            LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz));
    23472363
    2348             /* Fire off timer. */
    2349             TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
     2364            sb16TimerMaybeStart(pThis);
    23502365        }
     2366        else
     2367            AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
    23512368    }
    23522369#else
     
    24322449    NULL,
    24332450    /* pfnPowerOff */
    2434     NULL,
     2451    sb16PowerOff,
    24352452    /* pfnSoftReset */
    24362453    NULL,
Note: See TracChangeset for help on using the changeset viewer.

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