Changeset 88063 in vbox
- Timestamp:
- Mar 9, 2021 9:48:07 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143197
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHDA.cpp
r88028 r88063 1444 1444 /* Avoid going through the timer here by calling the stream's timer function directly. 1445 1445 * Should speed up starting the stream transfers. */ 1446 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3); 1446 uint64_t tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3); 1447 1448 hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow); 1447 1449 } 1448 1450 else … … 1458 1460 /* Reset the period. */ 1459 1461 hdaR3StreamPeriodReset(&pStreamShared->State.Period); 1462 1463 hdaR3StreamMarkStopped(pStreamShared); 1460 1464 } 1461 1465 } … … 3519 3523 hdaR3StreamRegisterDMAHandlers(pThis, pStreamShared); 3520 3524 #endif 3521 if (hdaR3StreamTransferIsScheduled(pStreamShared, PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer))) 3525 /** @todo r=bird: This can go wrong if the state saving happened exactly when 3526 * the timer expired. See comparison in 3527 * hdaR3StreamTransferIsScheduled. I've decided to just do this 3528 * unconditionally as that fixes the issue and simplifies the 3529 * hdaR3StreamMarkStarted. Also, I don't really get why this check is 3530 * necessary at all. */ 3531 /*if (hdaR3StreamTransferIsScheduled(pStreamShared, PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer))) */ 3522 3532 { 3523 3533 /* Avoid going through the timer here by calling the stream's timer function directly. 3524 3534 * Should speed up starting the stream transfers. */ 3525 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3); 3535 uint64_t tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3); 3536 3537 hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow); 3526 3538 } 3527 3539 … … 4607 4619 * Validate and read configuration. 4608 4620 */ 4609 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "BufSizeInMs|BufSizeOutMs|TimerHz|PosAdjustEnabled|PosAdjustFrames|TransferHeuristicsEnabled|DebugEnabled|DebugPathOut", ""); 4621 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, 4622 "BufSizeInMs" 4623 "|BufSizeOutMs" 4624 "|InitialDelayMs" 4625 "|TimerHz" 4626 "|PosAdjustEnabled" 4627 "|PosAdjustFrames" 4628 "|TransferHeuristicsEnabled" 4629 "|DebugEnabled" 4630 "|DebugPathOut", 4631 ""); 4610 4632 4611 4633 /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */ … … 4628 4650 if (pThis->uTimerHz != HDA_TIMER_HZ_DEFAULT) 4629 4651 LogRel(("HDA: Using custom device timer rate (%RU16Hz)\n", pThis->uTimerHz)); 4652 4653 /** @devcfgm{hda,InitialDelayMs,uint16_t,0,256,12,ms} 4654 * How long to delay when a stream starts before engaging the asynchronous I/O 4655 * thread from the DMA timer callback. Because it's used from the DMA timer 4656 * callback, it will implicitly be rounded up to the next timer period. 4657 * This is for adding a little host scheduling leeway into the playback. */ 4658 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "InitialDelayMs", &pThis->msInitialDelay, 12); 4659 if (RT_FAILURE(rc)) 4660 return PDMDEV_SET_ERROR(pDevIns, rc, N_("HDA configuration error: failed to read 'InitialDelayMs' as uint16_t")); 4661 if (pThis->msInitialDelay > 256) 4662 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 4663 N_("HDA configuration error: Out of range: 0 <= InitialDelayMs < 256: %u"), pThis->msInitialDelay); 4630 4664 4631 4665 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "PosAdjustEnabled", &pThis->fPosAdjustEnabled, true); -
trunk/src/VBox/Devices/Audio/DevHDA.h
r87861 r88063 127 127 uint8_t bPadding1; 128 128 #endif 129 uint8_t bPadding2; 129 130 /** The device timer Hz rate. Defaults to HDA_TIMER_HZ_DEFAULT. */ 130 131 uint16_t uTimerHz; 132 /** Number of milliseconds to delay kicking off the AIO when a stream starts. 133 * @sa InitialDelayMs config value. */ 134 uint16_t msInitialDelay; 131 135 /** Buffer size (in ms) of the internal input FIFO buffer. 132 136 * The actual buffer size in bytes will depend on the actual stream configuration. */ … … 135 139 * The actual buffer size in bytes will depend on the actual stream configuration. */ 136 140 uint16_t cbCircBufOutMs; 137 /** Padding for alignment. */ 138 uint16_t u16Padding3; 141 uint16_t au16Padding3[3]; 139 142 /** Last updated wall clock (WALCLK) counter. */ 140 143 uint64_t u64WalClk; -
trunk/src/VBox/Devices/Audio/HDAStream.cpp
r88028 r88063 699 699 * channels we don't support / need to save space. 700 700 */ 701 uint32_t cbCircBuf = PDMAudioPropsMilliToBytes(&pCfg->Props, 702 RT_MS_1SEC * 6 / RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz)); 701 uint32_t msCircBuf = RT_MS_1SEC * 6 / RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz); 702 msCircBuf = RT_MAX(msCircBuf, pThis->msInitialDelay + RT_MS_1SEC * 6 / uTransferHz); 703 704 uint32_t cbCircBuf = PDMAudioPropsMilliToBytes(&pCfg->Props, msCircBuf); 703 705 LogRel2(("HDA: Stream #%RU8 default ring buffer size is %RU32 bytes / %RU64 ms\n", 704 706 uSD, cbCircBuf, PDMAudioPropsBytesToMilli(&pCfg->Props, cbCircBuf))); … … 805 807 pStreamShared->State.tsLastTransferNs = 0; 806 808 pStreamShared->State.tsLastReadNs = 0; 809 pStreamShared->State.tsAioDelayEnd = UINT64_MAX; 810 pStreamShared->State.tsStart = 0; 807 811 808 812 RT_ZERO(pStreamShared->State.BDLE); … … 905 909 } 906 910 911 /** 912 * Marks the stream as started. 913 * 914 * Used after the stream has been enabled and the DMA timer has been armed. 915 */ 916 void hdaR3StreamMarkStarted(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint64_t tsNow) 917 { 918 pStreamShared->State.tsLastReadNs = RTTimeNanoTS(); 919 pStreamShared->State.tsStart = tsNow; 920 pStreamShared->State.tsAioDelayEnd = tsNow + PDMDevHlpTimerFromMilli(pDevIns, pStreamShared->hTimer, pThis->msInitialDelay); 921 Log3Func(("#%u: tsStart=%RU64 tsAioDelayEnd=%RU64 tsLastReadNs=%RU64\n", pStreamShared->u8SD, 922 pStreamShared->State.tsStart, pStreamShared->State.tsAioDelayEnd, pStreamShared->State.tsLastReadNs)); 923 924 } 925 926 /** 927 * Marks the stream as stopped. 928 */ 929 void hdaR3StreamMarkStopped(PHDASTREAM pStreamShared) 930 { 931 Log3Func(("#%u\n", pStreamShared->u8SD)); 932 pStreamShared->State.tsAioDelayEnd = UINT64_MAX; 933 } 934 935 907 936 #if 0 /* Not used atm. */ 908 937 static uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStreamShared) … … 1013 1042 } 1014 1043 1044 /** @todo r=bird: how can this be right? */ 1015 1045 if (pStreamShared->State.tsTransferNext > tsNow) 1016 1046 { … … 1704 1734 * The stream's main function when called by the timer. 1705 1735 * 1706 * Note: This function also will be called without timer invocation 1707 * when starting (enabling) the stream to minimize startup latency. 1708 * 1736 * @note This function also will be called without timer invocation when 1737 * starting (enabling) the stream to minimize startup latency. 1738 * 1739 * @returns Current timer time if the timer is enabled, otherwise zero. 1709 1740 * @param pDevIns The device instance. 1710 1741 * @param pThis The shared HDA device state. … … 1713 1744 * @param pStreamR3 HDA stream to update (ring-3 bits). 1714 1745 */ 1715 voidhdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,1716 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)1746 uint64_t hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, 1747 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3) 1717 1748 { 1718 1749 Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect)); … … 1735 1766 const bool fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow); 1736 1767 1737 uint64_t tsTransferNext = 0; 1768 /** @todo r=bird: This is a waste of time if the timer is called at a 1769 * constant rate. We can just calculate it here. */ 1770 uint64_t tsTransferNext; 1738 1771 if (fTimerScheduled) 1739 1772 { … … 1749 1782 hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext, 1750 1783 true /*fForce*/, tsNow); 1751 } 1752 else 1753 Log3Func(("[SD%RU8] fSinksActive=%RTbool\n", uSD, fSinkActive)); 1784 return tsNow; 1785 } 1786 1787 Log3Func(("[SD%RU8] fSinksActive=%RTbool\n", uSD, fSinkActive)); 1788 return 0; 1754 1789 } 1755 1790 … … 1797 1832 if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */ 1798 1833 { 1799 bool fDoRead = fInTimer; /* Whether to read from the HDA stream or not. */1800 1801 1834 /* 1802 1835 * Do DMA work. 1803 1836 */ 1837 bool fDoRead = false; /* Whether to push data down the driver stack or not. */ 1804 1838 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1805 1839 if (fInTimer) … … 1825 1859 1826 1860 /* Do the DMA transfer. */ 1861 uint64_t const offWriteBefore = pStreamR3->State.offWrite; 1827 1862 rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree); 1828 1863 AssertRC(rc2); 1829 1830 /* Never read yet? Set initial timestamp. */1831 if (pStreamShared->State.tsLastReadNs == 0)1832 pStreamShared->State.tsLastReadNs = tsNowNs;1833 1864 1834 1865 /* 1835 1866 * Push data to down thru the mixer to and to the host drivers? 1836 1867 * 1837 * This is generally done at the rate given by cMsSchedulingHint, 1838 * however we must also check available DMA buffer space. There 1839 * should be at least two periodic transfer units worth of space 1840 * available now. 1868 * We initially delay this by pThis->msInitialDelay, but after than we'll 1869 * kick the AIO thread every time we've put more data in the buffer (which is 1870 * every time) as the host audio device needs to get data in a timely manner. 1871 * 1872 * (We used to try only wake up the AIO thread according to pThis->uIoTimer 1873 * and host wall clock, but that meant we would miss a wakup after the DMA 1874 * timer was called a little late or if TM entered into catch-up mode.) 1841 1875 */ 1842 Assert(tsNowNs >= pStreamShared->State.tsLastReadNs); 1843 /** @todo convert cMsSchedulingHint to nano seconds and save a div. */ 1844 const uint64_t msDelta = (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS; 1845 cbStreamFree = hdaR3StreamGetFree(pStreamR3); 1846 if ( cbStreamFree < pStreamShared->State.cbTransferSize * 2 1847 || msDelta >= pStreamShared->State.Cfg.Device.cMsSchedulingHint) 1876 if (!pStreamShared->State.tsAioDelayEnd) 1877 fDoRead = pStreamR3->State.offWrite > offWriteBefore 1878 || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbTransferSize * 2; 1879 else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd) 1880 { 1881 Log3Func(("Initial delay done: Passed tsAioDelayEnd.\n")); 1882 pStreamShared->State.tsAioDelayEnd = 0; 1848 1883 fDoRead = true; 1849 1850 Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fDoRead=%RTbool\n", msDelta, 1884 } 1885 else if (hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbTransferSize * 2) 1886 { 1887 Log3Func(("Initial delay done: Passed running short on buffer.\n")); 1888 pStreamShared->State.tsAioDelayEnd = 0; 1889 fDoRead = true; 1890 } 1891 else 1892 { 1893 Log3Func(("Initial delay pending...\n")); 1894 fDoRead = false; 1895 } 1896 1897 Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fDoRead=%RTbool\n", 1898 (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS, 1851 1899 pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree, 1852 1900 pStreamShared->State.cbTransferSize * 2, fDoRead)); … … 1860 1908 AssertRC(rc2); 1861 1909 # endif 1862 /* Update last read timestamp so that we know when to run next. */1910 /* Update last read timestamp for logging/debugging. */ 1863 1911 pStreamShared->State.tsLastReadNs = tsNowNs; 1864 1912 } 1865 1913 } 1866 1914 1915 /* 1916 * <Missing Description> 1917 */ 1867 1918 # ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO 1868 1919 if (!fInTimer) /* In async I/O thread */ -
trunk/src/VBox/Devices/Audio/HDAStream.h
r87989 r88063 166 166 * because reading / processing will be done in a separate stream. */ 167 167 uint64_t tsLastReadNs; 168 169 /** This is set to the timer clock time when the msInitialDelay period is over. 170 * Once reached, this is set to zero to avoid unnecessary time queries. */ 171 uint64_t tsAioDelayEnd; 172 /** The start time for the playback (on the timer clock). */ 173 uint64_t tsStart; 168 174 } HDASTREAMSTATE; 169 175 AssertCompileSizeAlignment(HDASTREAMSTATE, 8); … … 291 297 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD); 292 298 int hdaR3StreamEnable(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fEnable); 299 void hdaR3StreamMarkStarted(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint64_t tsNow); 300 void hdaR3StreamMarkStopped(PHDASTREAM pStreamShared); 301 293 302 void hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uToAdd); 294 voidhdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,303 uint64_t hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, 295 304 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3); 296 305 bool hdaR3StreamTransferIsScheduled(PHDASTREAM pStreamShared, uint64_t tsNow);
Note:
See TracChangeset
for help on using the changeset viewer.