Changeset 88096 in vbox
- Timestamp:
- Mar 11, 2021 8:00:49 PM (4 years ago)
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r88094 r88096 1296 1296 * make sure that we process them first as a whole. */ 1297 1297 if (pStreamShared->State.cfPosAdjustLeft) 1298 cbChunk = RT_MIN(cbChunk, uint32_t(pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbFrameSize));1298 cbChunk = RT_MIN(cbChunk, (uint32_t)pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbFrameSize); 1299 1299 1300 1300 if (!cbChunk) … … 1686 1686 return VINF_SUCCESS; 1687 1687 } 1688 1689 1690 /** 1691 * Does DMA transfer for an HDA output stream. 1692 * 1693 * This transfers one DMA timer period worth of data from the guest and into the 1694 * internal DMA buffer. 1695 * 1696 * @returns IPRT status code. 1697 * @param pDevIns The device instance. 1698 * @param pThis The shared HDA device state. 1699 * @param pThisCC The ring-3 HDA device state. 1700 * @param pStreamShared HDA stream to update (shared). 1701 * @param pStreamR3 HDA stream to update (ring-3). 1702 * @param cbToProcessMax How much data (in bytes) to process as maximum. 1703 * Caller should already have made sure this is at 1704 * least one 1705 * @remarks Caller owns the stream lock. 1706 */ 1707 static int hdaR3StreamDoDmaOutput(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, PHDASTREAM pStreamShared, 1708 PHDASTREAMR3 pStreamR3, uint32_t cbToProcessMax, uint64_t tsNowNs) 1709 { 1710 PHDASTREAMPERIOD const pPeriod = &pStreamShared->State.Period; 1711 uint8_t const uSD = pStreamShared->u8SD; 1712 LogFlowFunc(("ENTER - #%u cbToProcessMax=%#x\n", uSD, cbToProcessMax)); 1713 1714 1715 /* 1716 * Check if we should skip town... 1717 */ 1718 1719 /* Stream not running (anymore)? */ 1720 if (pStreamShared->State.fRunning) 1721 { /* likely */ } 1722 else 1723 { 1724 Log3Func(("[SD%RU8] Not running, skipping transfer\n", uSD)); 1725 return VINF_SUCCESS; 1726 } 1727 1728 if (!(HDA_STREAM_REG(pThis, STS, uSD) & HDA_SDSTS_BCIS)) 1729 { /* likely */ } 1730 else 1731 { 1732 Log3Func(("[SD%RU8] BCIS bit set, skipping transfer\n", uSD)); 1733 #ifdef HDA_STRICT 1734 /* Timing emulation bug or guest is misbehaving -- let me know. */ 1735 AssertMsgFailed(("BCIS bit for stream #%RU8 still set when it shouldn't\n", uSD)); 1736 #endif 1737 return VINF_SUCCESS; 1738 } 1739 1740 /* 1741 * Stream sanity checks. 1742 */ 1743 /* Register sanity checks. */ 1744 Assert(uSD < HDA_MAX_STREAMS); 1745 Assert(pStreamShared->u64BDLBase); 1746 Assert(pStreamShared->u32CBL); 1747 Assert(pStreamShared->u8FIFOS); 1748 1749 /* State sanity checks. */ 1750 Assert(ASMAtomicReadBool(&pStreamShared->State.fInReset) == false); 1751 Assert(ASMAtomicReadBool(&pStreamShared->State.fRunning)); 1752 1753 /* Transfer sanity checks. */ 1754 Assert(pStreamShared->State.cbTransferSize); 1755 Assert(pStreamShared->State.cbTransferChunk <= pStreamShared->State.cbTransferSize); 1756 1757 /* 1758 * Some timestamp stuff for logging/debugging. 1759 */ 1760 /*const uint64_t tsNowNs = RTTimeNanoTS();*/ 1761 Log3Func(("[SD%RU8] tsDeltaNs=%'RU64 ns\n", uSD, tsNowNs - pStreamShared->State.tsLastTransferNs)); 1762 pStreamShared->State.tsLastTransferNs = tsNowNs; 1763 pStreamShared->State.tsTransferLast = PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer); 1764 1765 /* 1766 * Fetch the next BDL entry. 1767 */ 1768 int rc = VINF_SUCCESS; 1769 PHDABDLE pBDLE = &pStreamShared->State.BDLE; 1770 if (hdaR3BDLEIsComplete(pBDLE)) 1771 { 1772 rc = hdaR3BDLEFetch(pDevIns, pBDLE, pStreamShared->u64BDLBase, pStreamShared->State.uCurBDLE); 1773 AssertRCReturn(rc, rc); 1774 } 1775 1776 /* 1777 * The caller should have made sure we've got at least cbTransferSize 1778 * of buffer available. We will not transfer more than that. 1779 */ 1780 Assert(pStreamShared->State.cbTransferChunk == pStreamShared->State.cbTransferSize); 1781 Assert(cbToProcessMax >= pStreamShared->State.cbTransferSize); 1782 if (cbToProcessMax > pStreamShared->State.cbTransferSize) 1783 cbToProcessMax = pStreamShared->State.cbTransferSize; 1784 uint32_t cbLeft = cbToProcessMax; 1785 1786 /* 1787 * Whether an interrupt has been sent (asserted) for this transfer period already or not. 1788 * 1789 * Note: Windows 10 relies on this, e.g. sending more than one interrupt per transfer period 1790 * confuses the Windows' audio driver and will screw up the audio data. So only send 1791 * one interrupt per transfer period. 1792 * 1793 * Note! This only applies if the transfer heuristics isn't active. 1794 */ 1795 /** @todo r=bird: Of course the guest gets confused if you bundle interrupts. 1796 * Unless the buffers are really small, this is stuff that won't happen 1797 * on real hardware. */ 1798 /** @todo Disallow non-heuristics approach! It only complicates the code. */ 1799 bool fInterruptSent = false; 1800 1801 /* Set the FIFORDY bit on the stream while doing the transfer. */ 1802 /** @todo r=bird: I don't get the HDA_SDSTS_FIFORDY logic. Unless we're 1803 * assuming SMP guest and that it can get stream registers while we're 1804 * here. Only it cannot do the later because we're sitting on the big 1805 * HDA device lock, see assertions in hdaR3Timer(). So, this is an 1806 * pointless guesture given that we clear it again after the loop. */ 1807 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_FIFORDY; 1808 1809 while (cbLeft) 1810 { 1811 /* Limit the chunk to the stream's FIFO size and what's left to process. */ 1812 uint32_t cbChunk = RT_MIN(cbLeft, pStreamShared->u8FIFOS); 1813 1814 /* Limit the chunk to the remaining data of the current BDLE. */ 1815 cbChunk = RT_MIN(cbChunk, pBDLE->Desc.u32BufSize - pBDLE->State.u32BufOff); 1816 1817 /* If there are position adjustment frames left to be processed, 1818 * make sure that we process them first as a whole. */ 1819 if (pStreamShared->State.cfPosAdjustLeft) 1820 cbChunk = RT_MIN(cbChunk, (uint32_t)pStreamShared->State.cfPosAdjustLeft * pStreamR3->State.Mapping.cbFrameSize); 1821 1822 /** @todo wtf is this for? Move on to the next BDLE! */ 1823 if (!cbChunk) 1824 break; 1825 1826 uint32_t cbDMA = 0; 1827 PRTCIRCBUF pCircBuf = pStreamR3->State.pCircBuf; 1828 uint8_t *pabFIFO = pStreamShared->abFIFO; 1829 1830 STAM_PROFILE_START(&pThis->StatOut, a); 1831 1832 rc = hdaR3DMARead(pDevIns, pThis, pStreamShared, pStreamR3, pabFIFO, cbChunk, &cbDMA /* pcbRead */); 1833 if (RT_SUCCESS(rc)) 1834 { 1835 /** @todo wtf? Caller passed us the RTCircBufFree value via cbToProcessMax. */ 1836 const uint32_t cbFree = (uint32_t)RTCircBufFree(pCircBuf); 1837 1838 /* 1839 * Most guests don't use different stream frame sizes than 1840 * the default one, so save a bit of CPU time and don't go into 1841 * the frame extraction code below. 1842 * 1843 * Only macOS guests need the frame extraction branch below at the moment AFAIK. 1844 */ 1845 if (pStreamR3->State.Mapping.cbFrameSize == HDA_FRAME_SIZE_DEFAULT) 1846 { 1847 uint32_t cbDMARead = 0; 1848 uint32_t cbDMALeft = RT_MIN(cbDMA, cbFree); 1849 1850 while (cbDMALeft) 1851 { 1852 void *pvBuf; size_t cbBuf; 1853 RTCircBufAcquireWriteBlock(pCircBuf, cbDMALeft, &pvBuf, &cbBuf); 1854 1855 if (cbBuf) 1856 { 1857 memcpy(pvBuf, pabFIFO + cbDMARead, cbBuf); 1858 cbDMARead += (uint32_t)cbBuf; 1859 cbDMALeft -= (uint32_t)cbBuf; 1860 #ifdef VBOX_WITH_DTRACE 1861 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbBuf, pStreamR3->State.offWrite); 1862 #endif 1863 pStreamR3->State.offWrite += cbBuf; 1864 } 1865 1866 RTCircBufReleaseWriteBlock(pCircBuf, cbBuf); 1867 } 1868 } 1869 else 1870 { 1871 /* 1872 * The following code extracts the required audio stream (channel) data 1873 * of non-interleaved *and* interleaved audio streams. 1874 * 1875 * We by default only support 2 channels with 16-bit samples (HDA_FRAME_SIZE), 1876 * but an HDA audio stream can have interleaved audio data of multiple audio 1877 * channels in such a single stream ("AA,AA,AA vs. AA,BB,AA,BB"). 1878 * 1879 * So take this into account by just handling the first channel in such a stream ("A") 1880 * and just discard the other channel's data. 1881 * 1882 * I know, the following code is horribly slow, but seems to work for now. 1883 */ 1884 /** @todo Optimize channel data extraction! Use some SSE(3) / intrinsics? */ 1885 for (unsigned m = 0; m < pStreamR3->State.Mapping.cMappings; m++) 1886 { 1887 const uint32_t cbFrame = pStreamR3->State.Mapping.cbFrameSize; 1888 1889 Assert(cbFree >= cbDMA); 1890 1891 PPDMAUDIOSTREAMMAP pMap = &pStreamR3->State.Mapping.paMappings[m]; 1892 AssertPtr(pMap); 1893 1894 Log3Func(("Mapping #%u: Start (cbDMA=%RU32, cbFrame=%RU32, offNext=%RU32)\n", 1895 m, cbDMA, cbFrame, pMap->offNext)); 1896 1897 1898 /* Skip the current DMA chunk if the chunk is smaller than what the current stream mapping needs to read 1899 * the next associated frame (pointed to at pMap->cbOff). 1900 * 1901 * This can happen if the guest did not come up with enough data within a certain time period, especially 1902 * when using multi-channel speaker (> 2 channels [stereo]) setups. */ 1903 if (pMap->offNext > cbChunk) 1904 { 1905 Log2Func(("Mapping #%u: Skipped (cbChunk=%RU32, cbMapOff=%RU32)\n", m, cbChunk, pMap->offNext)); 1906 continue; 1907 } 1908 1909 uint8_t *pbSrcBuf = pabFIFO; 1910 size_t cbSrcOff = pMap->offNext; 1911 1912 for (unsigned i = 0; i < cbDMA / cbFrame; i++) 1913 { 1914 void *pvDstBuf; size_t cbDstBuf; 1915 RTCircBufAcquireWriteBlock(pCircBuf, pMap->cbStep, &pvDstBuf, &cbDstBuf); 1916 1917 Assert(cbDstBuf >= pMap->cbStep); 1918 1919 if (cbDstBuf) 1920 { 1921 Log3Func(("Mapping #%u: Frame #%02u: cbStep=%u, offFirst=%u, offNext=%u, cbDstBuf=%u, cbSrcOff=%u\n", 1922 m, i, pMap->cbStep, pMap->offFirst, pMap->offNext, cbDstBuf, cbSrcOff)); 1923 1924 memcpy(pvDstBuf, pbSrcBuf + cbSrcOff, cbDstBuf); 1925 1926 #if 0 /* Too slow, even for release builds, so disabled it. */ 1927 if (pStreamR3->Dbg.Runtime.fEnabled) 1928 DrvAudioHlpFileWrite(pStreamR3->Dbg.Runtime.pFileDMAMapped, pvDstBuf, cbDstBuf, 1929 0 /* fFlags */); 1930 #endif 1931 Assert(cbSrcOff <= cbDMA); 1932 if (cbSrcOff + cbFrame + pMap->offFirst<= cbDMA) 1933 cbSrcOff += cbFrame + pMap->offFirst; 1934 1935 #ifdef VBOX_WITH_DTRACE 1936 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbDstBuf, pStreamR3->State.offWrite); 1937 #endif 1938 Log3Func(("Mapping #%u: Frame #%02u: -> cbSrcOff=%zu\n", m, i, cbSrcOff)); 1939 pStreamR3->State.offWrite += cbDstBuf; 1940 } 1941 1942 RTCircBufReleaseWriteBlock(pCircBuf, cbDstBuf); 1943 } 1944 1945 Log3Func(("Mapping #%u: End cbSize=%u, cbDMA=%RU32, cbSrcOff=%zu\n", 1946 m, pMap->cbStep, cbDMA, cbSrcOff)); 1947 1948 Assert(cbSrcOff <= cbDMA); 1949 1950 const uint32_t cbSrcLeft = cbDMA - (uint32_t)cbSrcOff; 1951 if (cbSrcLeft) 1952 { 1953 Log3Func(("Mapping #%u: cbSrcLeft=%RU32\n", m, cbSrcLeft)); 1954 1955 if (cbSrcLeft >= pMap->cbStep) 1956 { 1957 void *pvDstBuf; size_t cbDstBuf; 1958 RTCircBufAcquireWriteBlock(pCircBuf, pMap->cbStep, &pvDstBuf, &cbDstBuf); 1959 1960 Assert(cbDstBuf >= pMap->cbStep); 1961 1962 if (cbDstBuf) 1963 { 1964 memcpy(pvDstBuf, pbSrcBuf + cbSrcOff, cbDstBuf); 1965 #ifdef VBOX_WITH_DTRACE 1966 VBOXDD_HDA_STREAM_DMA_OUT((uint32_t)uSD, (uint32_t)cbDstBuf, pStreamR3->State.offWrite); 1967 #endif 1968 pStreamR3->State.offWrite += cbDstBuf; 1969 } 1970 1971 RTCircBufReleaseWriteBlock(pCircBuf, cbDstBuf); 1972 } 1973 1974 Assert(pMap->cbFrame >= cbSrcLeft); 1975 pMap->offNext = pMap->cbFrame - cbSrcLeft; 1976 } 1977 else 1978 pMap->offNext = 0; 1979 1980 Log3Func(("Mapping #%u finish (cbSrcOff=%zu, offNext=%zu)\n", m, cbSrcOff, pMap->offNext)); 1981 } 1982 } 1983 } 1984 else 1985 LogRel(("HDA: Reading from stream #%RU8 DMA failed with %Rrc\n", uSD, rc)); 1986 1987 STAM_PROFILE_STOP(&pThis->StatOut, a); 1988 1989 if (cbDMA) 1990 { 1991 /* We always increment the position of DMA buffer counter because we're always reading 1992 * into an intermediate DMA buffer. */ 1993 pBDLE->State.u32BufOff += (uint32_t)cbDMA; 1994 Assert(pBDLE->State.u32BufOff <= pBDLE->Desc.u32BufSize); 1995 1996 /* Are we done doing the position adjustment? 1997 * Only then do the transfer accounting .*/ 1998 if (pStreamShared->State.cfPosAdjustLeft == 0) 1999 { 2000 Assert(cbLeft >= cbDMA); 2001 cbLeft -= cbDMA; 2002 } 2003 2004 Log3Func(("[SD%RU8] cbDMA=%RU32 -> %R[bdle]\n", uSD, cbDMA, pBDLE)); 2005 } 2006 2007 /* 2008 * Is the buffer descriptor complete. 2009 */ 2010 if (hdaR3BDLEIsComplete(pBDLE)) 2011 { 2012 Log3Func(("[SD%RU8] Completed %R[bdle]\n", uSD, pBDLE)); 2013 2014 /* Make sure to also update the wall clock when a BDLE is complete. 2015 * Needed for Windows 10 guests. */ 2016 hdaR3WalClkSet(pThis, pThisCC, 2017 hdaWalClkGetCurrent(pThis) 2018 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 2019 pBDLE->Desc.u32BufSize 2020 / pStreamR3->State.Mapping.cbFrameSize), 2021 false /* fForce */); 2022 2023 /* 2024 * Update the stream's current position. 2025 * 2026 * Do this as accurate and close to the actual data transfer as possible. 2027 * All guetsts rely on this, depending on the mechanism they use (LPIB register or DMA counters). 2028 * 2029 * Note for Windows 10: The OS' driver is *very* picky about *when* the (DMA) positions get updated! 2030 * Not doing this at the right time will result in ugly sound crackles! 2031 */ 2032 hdaR3StreamSetPositionAdd(pStreamShared, pDevIns, pThis, pBDLE->Desc.u32BufSize); 2033 2034 /* Does the current BDLE require an interrupt to be sent? */ 2035 if ( hdaR3BDLENeedsInterrupt(pBDLE) 2036 /* Are we done doing the position adjustment? 2037 * It can happen that a BDLE which is handled while doing the 2038 * position adjustment requires an interrupt on completion (IOC) being set. 2039 * 2040 * In such a case we need to skip such an interrupt and just move on. */ 2041 && pStreamShared->State.cfPosAdjustLeft == 0) 2042 { 2043 /* If the IOCE ("Interrupt On Completion Enable") bit of the SDCTL register is set 2044 * we need to generate an interrupt. 2045 */ 2046 if (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_SDCTL_IOCE) 2047 { 2048 /* Assert the interrupt before actually fetching the next BDLE below. */ 2049 if (!fInterruptSent) 2050 { 2051 #if 1 2052 pStreamShared->State.cTransferPendingInterrupts = 1; 2053 Log3Func(("[SD%RU8] Scheduling interrupt\n", uSD)); 2054 #else 2055 /* ??*/ 2056 AssertMsg(pStreamShared->State.cTransferPendingInterrupts <= 32, ("Too many pending interrupts (%RU8) for stream #%RU8\n", pStreamShared->State.cTransferPendingInterrupts, uSD)); 2057 Log3Func(("[SD%RU8] Scheduling interrupt (now %RU8 total)\n", uSD, pStreamShared->State.cTransferPendingInterrupts)); 2058 #endif 2059 2060 /* 2061 * Set the stream's BCIS bit. 2062 * 2063 * Note: This only must be done if the whole period is complete, and not if only 2064 * one specific BDL entry is complete (if it has the IOC bit set). 2065 * 2066 * This will otherwise confuses the guest when it 1) deasserts the interrupt, 2067 * 2) reads SDSTS (with BCIS set) and then 3) too early reads a (wrong) WALCLK value. 2068 * 2069 * snd_hda_intel on Linux will tell. 2070 */ 2071 /** @todo r=bird: The above comment does not match what we're doing. This is 2072 * just a flag indicating that the IOC is why the driver got an IRQ. */ 2073 HDA_STREAM_REG(pThis, STS, uSD) |= HDA_SDSTS_BCIS; 2074 2075 /* Trigger an interrupt first and let hdaRegWriteSDSTS() deal with 2076 * ending / beginning a period. */ 2077 HDA_PROCESS_INTERRUPT(pDevIns, pThis); 2078 2079 fInterruptSent = true; 2080 } 2081 } 2082 } 2083 2084 /* 2085 * Advance. 2086 */ 2087 if (pStreamShared->State.uCurBDLE >= pStreamShared->u16LVI) 2088 pStreamShared->State.uCurBDLE = 0; 2089 else 2090 pStreamShared->State.uCurBDLE++; 2091 2092 /* Fetch the next BDLE entry. */ 2093 hdaR3BDLEFetch(pDevIns, pBDLE, pStreamShared->u64BDLBase, pStreamShared->State.uCurBDLE); 2094 } 2095 2096 /* Do the position adjustment accounting. */ 2097 pStreamShared->State.cfPosAdjustLeft -= RT_MIN(pStreamShared->State.cfPosAdjustLeft, cbDMA / pStreamR3->State.Mapping.cbFrameSize); 2098 2099 if (RT_FAILURE(rc)) 2100 break; 2101 } 2102 2103 /* Remove the FIFORDY bit again. */ 2104 HDA_STREAM_REG(pThis, STS, uSD) &= ~HDA_SDSTS_FIFORDY; 2105 2106 /* Sanity. */ 2107 Assert(cbLeft == 0); 2108 uint32_t const cbProcessed = cbToProcessMax - cbLeft; 2109 2110 /* Only do the data accounting if we don't have to do any position 2111 * adjustment anymore. */ 2112 if (pStreamShared->State.cfPosAdjustLeft == 0) 2113 { 2114 hdaR3StreamPeriodInc(pPeriod, RT_MIN(cbProcessed / pStreamR3->State.Mapping.cbFrameSize, 2115 hdaR3StreamPeriodGetRemainingFrames(pPeriod))); 2116 } 2117 2118 const bool fTransferComplete = cbLeft == 0; 2119 if (fTransferComplete) 2120 { 2121 /* 2122 * Try updating the wall clock. 2123 * 2124 * Note 1) Only certain guests (like Linux' snd_hda_intel) rely on the WALCLK register 2125 * in order to determine the correct timing of the sound device. Other guests 2126 * like Windows 7 + 10 (or even more exotic ones like Haiku) will completely 2127 * ignore this. 2128 * 2129 * Note 2) When updating the WALCLK register too often / early (or even in a non-monotonic 2130 * fashion) this *will* upset guest device drivers and will completely fuck up the 2131 * sound output. Running VLC on the guest will tell! 2132 */ 2133 const bool fWalClkSet = hdaR3WalClkSet(pThis, pThisCC, 2134 RT_MIN( hdaWalClkGetCurrent(pThis) 2135 + hdaR3StreamPeriodFramesToWalClk(pPeriod, 2136 cbProcessed 2137 / pStreamR3->State.Mapping.cbFrameSize), 2138 hdaR3WalClkGetMax(pThis, pThisCC)), 2139 false /* fForce */); 2140 RT_NOREF(fWalClkSet); 2141 } 2142 2143 Log3Func(("[SD%RU8] %R[bdle] -- %#RX32/%#RX32 @ %#RX64 - fTransferComplete=%d (%d) cTransferPendingInterrupts=%RU8\n", 2144 uSD, pBDLE, cbProcessed, pStreamShared->State.cbTransferSize, pStreamR3->State.offWrite - cbProcessed, 2145 fTransferComplete, cbLeft, pStreamShared->State.cTransferPendingInterrupts)); 2146 2147 LogFlowFuncLeave(); 2148 return VINF_SUCCESS; 2149 } 2150 1688 2151 1689 2152 /** … … 1859 2322 * Do the DMA transfer. 1860 2323 */ 2324 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2325 rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED); 2326 AssertRC(rc2); 2327 # endif 2328 1861 2329 uint64_t const offWriteBefore = pStreamR3->State.offWrite; 1862 rc2 = hdaR3Stream Transfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree);2330 rc2 = hdaR3StreamDoDmaOutput(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree, tsNowNs); 1863 2331 AssertRC(rc2); 2332 2333 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 2334 rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect); 2335 AssertRC(rc2); 2336 # endif 1864 2337 1865 2338 /* -
trunk/src/VBox/Devices/Audio/HDAStreamPeriod.cpp
r88028 r88096 221 221 * 222 222 * @return Calculated wall clock value. 223 * @param pPeriod 224 * @param uFramesNumber of audio frames to calculate wall clock value for.223 * @param pPeriod Stream period to calculate wall clock value for. 224 * @param cFrames Number of audio frames to calculate wall clock value for. 225 225 * 226 226 * @remark Calculation depends on the given stream period and assumes a 24 MHz wall clock counter (WALCLK). 227 227 */ 228 uint64_t hdaR3StreamPeriodFramesToWalClk(PHDASTREAMPERIOD pPeriod, uint32_t uFrames)228 uint64_t hdaR3StreamPeriodFramesToWalClk(PHDASTREAMPERIOD pPeriod, uint32_t cFrames) 229 229 { 230 230 /* Prevent division by zero. */ … … 232 232 233 233 /* 24 MHz wall clock (WALCLK): 42ns resolution. */ 234 return ASMMultU 64ByU32DivByU32(uFrames, 24000000, uHz);234 return ASMMultU32ByU32DivByU32(cFrames, 24000000, uHz); 235 235 } 236 236
Note:
See TracChangeset
for help on using the changeset viewer.