Changeset 60937 in vbox for trunk/src/VBox/Devices
- Timestamp:
- May 11, 2016 1:10:09 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 107159
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevSB16.cpp
r60925 r60937 173 173 /** Audio sink for PCM output. */ 174 174 R3PTRTYPE(PAUDMIXSINK) pSinkOutput; 175 /** Number of active (running) SDn streams. */ 176 uint8_t cStreamsActive; 175 177 #ifndef VBOX_WITH_AUDIO_CALLBACKS 176 178 /** The timer for pumping data thru the attached LUN drivers. */ … … 192 194 193 195 static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg); 196 #ifndef VBOX_WITH_AUDIO_CALLBACKS 197 static void sb16TimerMaybeStart(PSB16STATE pThis); 198 static void sb16TimerMaybeStop(PSB16STATE pThis); 199 #endif 194 200 195 201 /** … … 426 432 LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma)); 427 433 428 PSB16DRIVER pDrv; 434 PDMDevHlpDMASetDREQ(pThis->pDevInsR3, dma, hold); 435 429 436 if (hold) 430 437 { 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 437 445 else 438 446 { 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); 444 455 } 445 456 … … 459 470 { 460 471 PDMAUDIOSTREAMCFG streamCfg; 472 RT_ZERO(streamCfg); 473 streamCfg.enmDir = PDMAUDIODIR_OUT; 461 474 streamCfg.uHz = pThis->freq; 462 475 streamCfg.cChannels = 1 << pThis->fmt_stereo; … … 594 607 { 595 608 PDMAUDIOSTREAMCFG streamCfg; 609 RT_ZERO(streamCfg); 610 streamCfg.enmDir = PDMAUDIODIR_OUT; 596 611 streamCfg.uHz = pThis->freq; 597 612 streamCfg.cChannels = 1 << pThis->fmt_stereo; … … 1106 1121 1107 1122 PDMAUDIOSTREAMCFG streamCfg; 1123 RT_ZERO(streamCfg); 1124 streamCfg.enmDir = PDMAUDIODIR_OUT; 1108 1125 streamCfg.uHz = pThis->freq; 1109 1126 streamCfg.cChannels = 1; /* Mono */ … … 1624 1641 AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc)); 1625 1642 1643 /* 1644 * Write data to the mixer sink. 1645 */ 1626 1646 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)); 1637 1653 1638 1654 Assert(cbToWrite >= cbToRead); … … 1734 1750 } 1735 1751 1752 #ifndef VBOX_WITH_AUDIO_CALLBACKS 1753 1754 static 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 1768 static 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 1736 1782 static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 1737 1783 { … … 1740 1786 AssertPtr(pThis); 1741 1787 1742 uint32_t cbInMax = 0;1743 uint32_t cbOutMin = UINT32_MAX;1744 1745 PSB16DRIVER pDrv;1746 1747 1788 uint64_t cTicksNow = TMTimerGet(pTimer); 1748 uint64_t cTicksElapsed = cTicksNow 1789 uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTSIO; 1749 1790 uint64_t cTicksPerSec = TMTimerGetFreq(pTimer); 1750 1791 1751 1792 pThis->uTimerTSIO = cTicksNow; 1752 1793 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 { 1823 1798 /* New space available, see if we can transfer more. */ 1824 1799 PDMDevHlpDMASchedule(pThis->pDevInsR3); 1825 1800 } 1826 1827 /*1828 * Recording.1829 */1830 /** @todo Implement recording. */1831 1801 1832 1802 /* Kick the timer again. */ … … 1835 1805 TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks); 1836 1806 } 1807 1808 #endif /* !VBOX_WITH_AUDIO_CALLBACKS */ 1837 1809 1838 1810 static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis) … … 1959 1931 { 1960 1932 PDMAUDIOSTREAMCFG streamCfg; 1933 RT_ZERO(streamCfg); 1934 streamCfg.enmDir = PDMAUDIODIR_OUT; 1961 1935 streamCfg.uHz = pThis->freq; 1962 1936 streamCfg.cChannels = 1 << pThis->fmt_stereo; … … 2048 2022 { 2049 2023 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; 2054 2036 2055 2037 PSB16DRIVER pDrv; … … 2058 2040 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node) 2059 2041 { 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")) 2062 2044 { 2063 rc = VERR_ NO_MEMORY;2045 rc = VERR_BUFFER_OVERFLOW; 2064 2046 break; 2065 2047 } … … 2074 2056 { 2075 2057 rc2 = AudioMixerSinkAddStream(pThis->pSinkOutput, pDrv->Out.pMixStrm); 2076 LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, p szDesc, rc2));2058 LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2)); 2077 2059 } 2078 2079 RTStrFree(pszDesc);2080 2060 2081 2061 if (RT_FAILURE(rc2)) … … 2093 2073 2094 2074 return rc; 2075 } 2076 2077 static 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 } 2095 2090 } 2096 2091 … … 2141 2136 2142 2137 /** 2138 * Powers off the device. 2139 * 2140 * @param pDevIns Device instance to power off. 2141 */ 2142 static 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 /** 2143 2161 * @interface_method_impl{PDMDEVREG,pfnDestruct} 2144 2162 */ … … 2147 2165 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE); 2148 2166 2167 LogFlowFuncEnter(); 2168 2149 2169 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); 2161 2179 2162 2180 return VINF_SUCCESS; … … 2318 2336 AssertPtr(pCon); 2319 2337 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); 2322 2340 if (!fValidOut) 2323 2341 { … … 2338 2356 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis, 2339 2357 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)) 2343 2359 { 2344 2360 pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz; … … 2346 2362 LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz)); 2347 2363 2348 /* Fire off timer. */ 2349 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO); 2364 sb16TimerMaybeStart(pThis); 2350 2365 } 2366 else 2367 AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc); 2351 2368 } 2352 2369 #else … … 2432 2449 NULL, 2433 2450 /* pfnPowerOff */ 2434 NULL,2451 sb16PowerOff, 2435 2452 /* pfnSoftReset */ 2436 2453 NULL,
Note:
See TracChangeset
for help on using the changeset viewer.