Changeset 87985 in vbox
- Timestamp:
- Mar 5, 2021 8:59:57 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r87983 r87985 672 672 673 673 /* 674 * The default size of our internal ring buffer depends on the transfer timing 675 * we have to reach in order to make the guest driver happy *and* on the I/O timing. 674 * The default internal ring buffer size must be: 676 675 * 677 * We always use triple the minimum timing of both timings for safety (triple buffering), 678 * otherwise we risk running into buffer overflows. 676 * - Large enough for at least three periodic DMA transfers. 679 677 * 680 * Note: Use pCfg->Props as PCM properties here, as we only want to store the samples we actually need, 681 * in other words, skipping the interleaved channels we don't support / need to save space. 678 * It is critically important that we don't experience underruns 679 * in the DMA OUT code, because it will cause the buffer processing 680 * to get skewed and possibly overlap with what the guest is updating. 681 * At the time of writing (2021-03-05) there is no code for getting 682 * back into sync there. 683 * 684 * - Large enough for at least three I/O scheduling hints. 685 * 686 * We want to lag behind a DMA period or two, but there must be 687 * sufficent space for the AIO thread to get schedule and shuffle 688 * data thru the mixer and onto the host audio hardware. 689 * 690 * - Both above with plenty to spare. 691 * 692 * So, just take the longest of the two periods and multipling it by 6. 693 * We aren't not talking about very large base buffers heres, so size isn't 694 * an issue. 695 * 696 * Note: Use pCfg->Props as PCM properties here, as we only want to store the 697 * samples we actually need, in other words, skipping the interleaved 698 * channels we don't support / need to save space. 682 699 */ 683 684 const unsigned uTransferHzMin = RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz); 685 const uint32_t cbCircBufDefault = DrvAudioHlpMilliToBytes((RT_MS_1SEC / uTransferHzMin) * 3, &pCfg->Props); 686 687 LogRel2(("HDA: Stream #%RU8 default ring buffer size is %RU64ms (%RU32 bytes)\n", 688 uSD, DrvAudioHlpBytesToMilli(cbCircBufDefault, &pCfg->Props), cbCircBufDefault)); 689 690 uint32_t cbCircBuf; 691 uint32_t cbCircBufGlobal = DrvAudioHlpMilliToBytes( hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN 692 ? pThis->cbCircBufInMs : pThis->cbCircBufOutMs, &pCfg->Props); 693 if (cbCircBufGlobal) /* Anything set via CFGM? */ 694 { 695 LogRel2(("HDA: Stream #%RU8 is using a custom ring buffer size of %RU64ms (%RU32 bytes)\n", 696 uSD, DrvAudioHlpBytesToMilli(cbCircBufGlobal, &pCfg->Props), cbCircBufGlobal)); 697 698 cbCircBuf = cbCircBufGlobal; 699 } 700 else 701 cbCircBuf = cbCircBufDefault; 702 700 uint32_t cbCircBuf = DrvAudioHlpMilliToBytes(RT_MS_1SEC * 6 / RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz), 701 &pCfg->Props); 702 LogRel2(("HDA: Stream #%RU8 default ring buffer size is %RU32 bytes / %RU64 ms\n", 703 uSD, cbCircBuf, DrvAudioHlpBytesToMilli(cbCircBuf, &pCfg->Props))); 704 705 uint32_t msCircBufCfg = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? pThis->cbCircBufInMs : pThis->cbCircBufOutMs; 706 if (msCircBufCfg) /* Anything set via CFGM? */ 707 { 708 cbCircBuf = DrvAudioHlpMilliToBytes(msCircBufCfg, &pCfg->Props); 709 LogRel2(("HDA: Stream #%RU8 is using a custom ring buffer size of %RU32 bytes / %RU64 ms\n", 710 uSD, cbCircBuf, DrvAudioHlpBytesToMilli(cbCircBuf, &pCfg->Props))); 711 } 712 713 /* Serious paranoia: */ 703 714 ASSERT_GUEST_LOGREL_MSG_STMT(cbCircBuf % (pCfg->Props.cbSample * pCfg->Props.cChannels) == 0, 704 ("Ring buffer size (%RU32) for stream #%RU8 not aligned to mapping'sframe size (%RU8)\n",715 ("Ring buffer size (%RU32) for stream #%RU8 not aligned to the (host) frame size (%RU8)\n", 705 716 cbCircBuf, uSD, pCfg->Props.cbSample * pCfg->Props.cChannels), 706 717 rc = VERR_INVALID_PARAMETER); … … 1174 1185 PHDASTREAMR3 pStreamR3, uint32_t cbToProcessMax) 1175 1186 { 1176 LogFlowFuncEnter();1177 1178 1187 uint8_t const uSD = pStreamShared->u8SD; 1188 LogFlowFunc(("ENTER - #%u cbToProcessMax=%#x\n", uSD, cbToProcessMax)); 1189 1179 1190 hdaStreamLock(pStreamShared); 1180 1191 … … 1769 1780 if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */ 1770 1781 { 1771 bool fDoRead = false; /* Whether to read from the HDA stream or not. */ 1772 1782 bool fDoRead = fInTimer; /* Whether to read from the HDA stream or not. */ 1783 1784 /* 1785 * Do DMA work. 1786 */ 1773 1787 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1774 1788 if (fInTimer) … … 1776 1790 { 1777 1791 uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3); 1778 if (!cbStreamFree) 1792 if (cbStreamFree) 1793 { /* likely */ } 1794 else 1779 1795 { 1780 1796 LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping audio data\n", pStreamShared->u8SD)); … … 1799 1815 pStreamShared->State.tsLastReadNs = tsNowNs; 1800 1816 1801 /* Only read from the HDA stream at the given scheduling rate. */ 1817 /* 1818 * Push data to down thru the mixer to and to the host drivers? 1819 * 1820 * This is generally done at the rate given by cMsSchedulingHint, 1821 * however we must also check available DMA buffer space. There 1822 * should be at least two periodic transfer units worth of space 1823 * available now. 1824 */ 1802 1825 Assert(tsNowNs >= pStreamShared->State.tsLastReadNs); 1803 const uint64_t tsDeltaMs = (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS; 1804 if (tsDeltaMs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint) 1826 /** @todo convert cMsSchedulingHint to nano seconds and save a div. */ 1827 const uint64_t msDelta = (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS; 1828 cbStreamFree = hdaR3StreamGetFree(pStreamR3); 1829 if ( cbStreamFree < pStreamShared->State.cbTransferSize * 2 1830 || msDelta >= pStreamShared->State.Cfg.Device.cMsSchedulingHint) 1805 1831 fDoRead = true; 1806 1832 1807 Log3Func(("tsDeltaMs=%RU64, fDoRead=%RTbool\n", tsDeltaMs, fDoRead)); 1808 } 1809 1810 if (fDoRead) 1811 { 1833 Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fDoRead=%RTbool\n", msDelta, 1834 pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree, 1835 pStreamShared->State.cbTransferSize * 2, fDoRead)); 1836 1837 if (fDoRead) 1838 { 1812 1839 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1813 /* Notify the async I/O worker thread that there's work to do. */ 1814 rc2 = hdaR3StreamAsyncIONotify(pStreamR3); 1815 AssertRC(rc2); 1840 /* Notify the async I/O worker thread that there's work to do. */ 1841 Log5Func(("Notifying AIO thread\n")); 1842 rc2 = hdaR3StreamAsyncIONotify(pStreamR3); 1843 AssertRC(rc2); 1816 1844 # endif 1817 /* Update last read timestamp so that we know when to run next. */ 1818 pStreamShared->State.tsLastReadNs = tsNowNs; 1845 /* Update last read timestamp so that we know when to run next. */ 1846 pStreamShared->State.tsLastReadNs = tsNowNs; 1847 } 1819 1848 } 1820 1849 … … 1908 1937 if (tsNowNs - pStreamShared->State.tsLastReadNs >= pStreamShared->State.Cfg.Device.cMsSchedulingHint * RT_NS_1MS) 1909 1938 { 1939 Log5Func(("Notifying AIO thread\n")); 1910 1940 rc2 = hdaR3StreamAsyncIONotify(pStreamR3); 1911 1941 AssertRC(rc2);
Note:
See TracChangeset
for help on using the changeset viewer.