Changeset 88942 in vbox
- Timestamp:
- May 8, 2021 11:39:11 AM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 144277
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DevHdaStream.cpp
r88941 r88942 47 47 *********************************************************************************************************************************/ 48 48 static void hdaR3StreamSetPositionAbs(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uLPIB); 49 static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, 50 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3); 49 51 50 52 … … 1908 1910 1909 1911 /* Do the work: */ 1910 hdaR3StreamUpdate (pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, true /* fInTimer */);1912 hdaR3StreamUpdateDma(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3); 1911 1913 1912 1914 /* Re-arm the timer if the sink is still active: */ … … 1953 1955 1954 1956 /** 1955 * Updates a HDA stream by doing its required data transfers. 1956 * 1957 * The host sink(s) set the overall pace. 1958 * 1959 * This routine is called by both, the synchronous and the asynchronous 1960 * implementations. 1961 * 1962 * When running synchronously, the device DMA transfers *and* the mixer sink 1963 * processing is within the device timer. 1964 * 1965 * When running asynchronously, only the device DMA transfers are done in the 1966 * device timer, whereas the mixer sink processing then is done in the stream's 1967 * own async I/O thread. This thread also will call this function 1968 * (with fInTimer set to @c false). 1957 * Updates a HDA stream by doing DMA transfers. 1958 * 1959 * Will do mixer transfers too to try fix an overrun/underrun situation. 1960 * 1961 * The host sink(s) set the overall pace (bird: no it doesn't, the DMA timer 1962 * does - we just hope like heck it matches the speed at which the *backend* 1963 * host audio driver processes samples). 1969 1964 * 1970 1965 * @param pDevIns The device instance. … … 1973 1968 * @param pStreamShared HDA stream to update (shared bits). 1974 1969 * @param pStreamR3 HDA stream to update (ring-3 bits). 1975 * @param fInTimer Whether to this function was called from the timer 1976 * context or an asynchronous I/O stream thread (if supported). 1977 */ 1978 void hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, 1979 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer) 1970 */ 1971 static void hdaR3StreamUpdateDma(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, 1972 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3) 1980 1973 { 1981 1974 RT_NOREF(pThisCC); … … 1983 1976 1984 1977 /* 1985 * Make sure we're running (only when on timer, as the AIO thread needs 1986 * to properly drain the internal DMA buffer) and got an active mixer sink. 1987 */ 1988 if (RT_LIKELY(pStreamShared->State.fRunning || !fInTimer)) 1978 * Make sure we're running and got an active mixer sink. 1979 */ 1980 if (RT_LIKELY(pStreamShared->State.fRunning)) 1989 1981 { /* likely */ } 1990 1982 else … … 2012 2004 if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) 2013 2005 { 2014 bool fDoRead; /* Whether to push data down the driver stack or not. */ 2015 if (fInTimer) 2006 /* 2007 * Check how much room we have in our DMA buffer. There should be at 2008 * least one period worth of space there or we're in an overflow situation. 2009 */ 2010 uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3); 2011 if (cbStreamFree >= cbPeriod) 2012 { /* likely */ } 2013 else 2016 2014 { 2017 /* 2018 * Check how much room we have in our DMA buffer. There should be at 2019 * least one period worth of space there or we're in an overflow situation. 2020 */ 2021 uint32_t cbStreamFree = hdaR3StreamGetFree(pStreamR3); 2022 if (cbStreamFree >= cbPeriod) 2023 { /* likely */ } 2015 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems); 2016 Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient space free: %u bytes, need %u. Will try move data out of the buffer...\n", 2017 pStreamShared->u8SD, cbStreamFree, cbPeriod)); 2018 int rc = AudioMixerSinkTryLock(pSink); 2019 if (RT_SUCCESS(rc)) 2020 { 2021 hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs); 2022 AudioMixerSinkUpdate(pSink); 2023 AudioMixerSinkUnlock(pSink); 2024 } 2024 2025 else 2026 RTThreadYield(); 2027 Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetFree(pStreamR3) - cbStreamFree)); 2028 2029 cbStreamFree = hdaR3StreamGetFree(pStreamR3); 2030 if (cbStreamFree < cbPeriod) 2025 2031 { 2026 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems); 2027 Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient space free: %u bytes, need %u. Will try move data out of the buffer...\n", 2028 pStreamShared->u8SD, cbStreamFree, cbPeriod)); 2029 int rc = AudioMixerSinkTryLock(pSink); 2030 if (RT_SUCCESS(rc)) 2031 { 2032 hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs); 2033 AudioMixerSinkUpdate(pSink); 2034 AudioMixerSinkUnlock(pSink); 2035 } 2036 else 2037 RTThreadYield(); 2038 Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetFree(pStreamR3) - cbStreamFree)); 2039 2032 /* Unable to make sufficient space. Drop the whole buffer content. 2033 * This is needed in order to keep the device emulation running at a constant rate, 2034 * at the cost of losing valid (but too much) data. */ 2035 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors); 2036 LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n", 2037 pStreamShared->u8SD, hdaR3StreamGetUsed(pStreamR3))); 2038 # ifdef HDA_STRICT 2039 AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD)); 2040 # endif 2041 RTCircBufReset(pStreamR3->State.pCircBuf); 2042 pStreamR3->State.offWrite = 0; 2043 pStreamR3->State.offRead = 0; 2040 2044 cbStreamFree = hdaR3StreamGetFree(pStreamR3); 2041 if (cbStreamFree < cbPeriod)2042 {2043 /* Unable to make sufficient space. Drop the whole buffer content.2044 * This is needed in order to keep the device emulation running at a constant rate,2045 * at the cost of losing valid (but too much) data. */2046 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors);2047 LogRel2(("HDA: Warning: Hit stream #%RU8 overflow, dropping %u bytes of audio data\n",2048 pStreamShared->u8SD, hdaR3StreamGetUsed(pStreamR3)));2049 # ifdef HDA_STRICT2050 AssertMsgFailed(("Hit stream #%RU8 overflow -- timing bug?\n", pStreamShared->u8SD));2051 # endif2052 RTCircBufReset(pStreamR3->State.pCircBuf);2053 pStreamR3->State.offWrite = 0;2054 pStreamR3->State.offRead = 0;2055 cbStreamFree = hdaR3StreamGetFree(pStreamR3);2056 }2057 2045 } 2058 2059 /* 2060 * Do the DMA transfer. 2061 */ 2062 rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED); 2046 } 2047 2048 /* 2049 * Do the DMA transfer. 2050 */ 2051 rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED); 2052 AssertRC(rc2); 2053 2054 uint64_t const offWriteBefore = pStreamR3->State.offWrite; 2055 hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs); 2056 2057 rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect); 2058 AssertRC(rc2); 2059 2060 /* 2061 * Should we push data to down thru the mixer to and to the host drivers? 2062 * 2063 * We initially delay this by pThis->msInitialDelay, but after than we'll 2064 * kick the AIO thread every time we've put more data in the buffer (which is 2065 * every time) as the host audio device needs to get data in a timely manner. 2066 * 2067 * (We used to try only wake up the AIO thread according to pThis->uIoTimer 2068 * and host wall clock, but that meant we would miss a wakup after the DMA 2069 * timer was called a little late or if TM entered into catch-up mode.) 2070 */ 2071 bool fKickAioThread; 2072 if (!pStreamShared->State.tsAioDelayEnd) 2073 fKickAioThread = pStreamR3->State.offWrite > offWriteBefore 2074 || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2; 2075 else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd) 2076 { 2077 Log3Func(("Initial delay done: Passed tsAioDelayEnd.\n")); 2078 pStreamShared->State.tsAioDelayEnd = 0; 2079 fKickAioThread = true; 2080 } 2081 else if (hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2) 2082 { 2083 Log3Func(("Initial delay done: Passed running short on buffer.\n")); 2084 pStreamShared->State.tsAioDelayEnd = 0; 2085 fKickAioThread = true; 2086 } 2087 else 2088 { 2089 Log3Func(("Initial delay pending...\n")); 2090 fKickAioThread = false; 2091 } 2092 2093 Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fKickAioThread=%RTbool\n", 2094 (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS, 2095 pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree, 2096 pStreamShared->State.cbAvgTransfer * 2, fKickAioThread)); 2097 2098 if (fKickAioThread) 2099 { 2100 /* Notify the async I/O worker thread that there's work to do. */ 2101 Log5Func(("Notifying AIO thread\n")); 2102 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 2063 2103 AssertRC(rc2); 2064 2065 uint64_t const offWriteBefore = pStreamR3->State.offWrite; 2066 hdaR3StreamDoDmaOutput(pDevIns, pThis, pStreamShared, pStreamR3, RT_MIN(cbStreamFree, cbPeriod), tsNowNs); 2067 2068 rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect); 2069 AssertRC(rc2); 2070 2071 /* 2072 * Should we push data to down thru the mixer to and to the host drivers? 2073 * 2074 * We initially delay this by pThis->msInitialDelay, but after than we'll 2075 * kick the AIO thread every time we've put more data in the buffer (which is 2076 * every time) as the host audio device needs to get data in a timely manner. 2077 * 2078 * (We used to try only wake up the AIO thread according to pThis->uIoTimer 2079 * and host wall clock, but that meant we would miss a wakup after the DMA 2080 * timer was called a little late or if TM entered into catch-up mode.) 2081 */ 2082 if (!pStreamShared->State.tsAioDelayEnd) 2083 fDoRead = pStreamR3->State.offWrite > offWriteBefore 2084 || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2; 2085 else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd) 2104 /* Update last read timestamp for logging/debugging. */ 2105 pStreamShared->State.tsLastReadNs = tsNowNs; 2106 } 2107 } 2108 /* 2109 * Input stream (SDI). 2110 */ 2111 else 2112 { 2113 Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN); 2114 2115 /* 2116 * See how much data we've got buffered... 2117 */ 2118 bool fWriteSilence = false; 2119 uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2120 if (pStreamShared->State.fInputPreBuffered && cbStreamUsed >= cbPeriod) 2121 { /*likely*/ } 2122 /* 2123 * Because it may take a while for the input stream to get going (at 2124 * least with pulseaudio), we feed the guest silence till we've 2125 * pre-buffer a reasonable amount of audio. 2126 */ 2127 else if (!pStreamShared->State.fInputPreBuffered) 2128 { 2129 if (cbStreamUsed < pStreamShared->State.cbInputPreBuffer) 2086 2130 { 2087 Log3Func(("Initial delay done: Passed tsAioDelayEnd.\n")); 2088 pStreamShared->State.tsAioDelayEnd = 0; 2089 fDoRead = true; 2090 } 2091 else if (hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbAvgTransfer * 2) 2092 { 2093 Log3Func(("Initial delay done: Passed running short on buffer.\n")); 2094 pStreamShared->State.tsAioDelayEnd = 0; 2095 fDoRead = true; 2131 Log3(("hdaR3StreamUpdate: Pre-buffering (got %#x out of %#x bytes)...\n", 2132 cbStreamUsed, pStreamShared->State.cbInputPreBuffer)); 2133 fWriteSilence = true; 2096 2134 } 2097 2135 else 2098 2136 { 2099 Log3Func(("Initial delay pending...\n")); 2100 fDoRead = false; 2137 Log3(("hdaR3StreamUpdate: Completed pre-buffering (got %#x, needed %#x bytes).\n", 2138 cbStreamUsed, pStreamShared->State.cbInputPreBuffer)); 2139 pStreamShared->State.fInputPreBuffered = true; 2140 fWriteSilence = true; /* For now, just do the most conservative thing. */ 2101 2141 } 2102 2103 Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fDoRead=%RTbool\n", 2104 (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS, 2105 pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree, 2106 pStreamShared->State.cbAvgTransfer * 2, fDoRead)); 2107 2108 if (fDoRead) 2142 cbStreamUsed = cbPeriod; 2143 } 2144 /* 2145 * When we're low on data, we must really try fetch some ourselves 2146 * as buffer underruns must not happen. 2147 */ 2148 else 2149 { 2150 /** @todo We're ending up here to frequently with pulse audio at least (just 2151 * watch the stream stats in the statistcs viewer, and way to often we 2152 * have to inject silence bytes. I suspect part of the problem is 2153 * that the HDA device require a much better latency than what the 2154 * pulse audio is configured for by default (10 ms vs 150ms). */ 2155 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems); 2156 Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient data available: %u bytes, need %u. Will try move pull more data into the buffer...\n", 2157 pStreamShared->u8SD, cbStreamUsed, cbPeriod)); 2158 int rc = AudioMixerSinkTryLock(pSink); 2159 if (RT_SUCCESS(rc)) 2109 2160 { 2110 /* Notify the async I/O worker thread that there's work to do. */ 2111 Log5Func(("Notifying AIO thread\n")); 2112 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 2113 AssertRC(rc2); 2114 /* Update last read timestamp for logging/debugging. */ 2115 pStreamShared->State.tsLastReadNs = tsNowNs; 2161 AudioMixerSinkUpdate(pSink); 2162 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2163 AudioMixerSinkUnlock(pSink); 2164 } 2165 else 2166 RTThreadYield(); 2167 Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetUsed(pStreamR3) - cbStreamUsed)); 2168 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2169 if (cbStreamUsed < cbPeriod) 2170 { 2171 /* Unable to find sufficient input data by simple prodding. 2172 In order to keep a constant byte stream following thru the DMA 2173 engine into the guest, we will try again and then fall back on 2174 filling the gap with silence. */ 2175 uint32_t cbSilence = 0; 2176 do 2177 { 2178 AudioMixerSinkLock(pSink); 2179 2180 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2181 if (cbStreamUsed < cbPeriod) 2182 { 2183 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2184 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2185 while (cbStreamUsed < cbPeriod) 2186 { 2187 void *pvDstBuf; 2188 size_t cbDstBuf; 2189 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbPeriod - cbStreamUsed, 2190 &pvDstBuf, &cbDstBuf); 2191 RT_BZERO(pvDstBuf, cbDstBuf); 2192 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbDstBuf); 2193 cbSilence += (uint32_t)cbDstBuf; 2194 cbStreamUsed += (uint32_t)cbDstBuf; 2195 } 2196 } 2197 2198 AudioMixerSinkUnlock(pSink); 2199 } while (cbStreamUsed < cbPeriod); 2200 if (cbSilence > 0) 2201 { 2202 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors); 2203 STAM_REL_COUNTER_ADD(&pStreamR3->State.StatDmaFlowErrorBytes, cbSilence); 2204 LogRel2(("HDA: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamShared->u8SD, 2205 cbSilence, PDMAudioPropsBytesToMicro(&pStreamR3->State.Mapping.GuestProps, cbSilence))); 2206 } 2116 2207 } 2117 2208 } 2118 2209 2119 2210 /* 2120 * Move data out of the pStreamR3->State.pCircBuf buffer and to 2121 * the mixer and in direction of the host audio devices. 2211 * Do the DMA'ing. 2122 2212 */ 2123 else 2124 hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, tsNowNs); 2125 } 2126 /* 2127 * Input stream (SDI). 2128 */ 2129 else 2130 { 2131 Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN); 2213 if (cbStreamUsed) 2214 { 2215 rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED); 2216 AssertRC(rc2); 2217 2218 hdaR3StreamDoDmaInput(pDevIns, pThis, pStreamShared, pStreamR3, 2219 RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs); 2220 2221 rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect); 2222 AssertRC(rc2); 2223 } 2132 2224 2133 2225 /* 2134 * If we're the async I/O worker, or not using AIO, pull bytes 2135 * from the mixer and into our internal DMA buffer. 2226 * We should always kick the AIO thread. 2136 2227 */ 2137 if (!fInTimer) 2138 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2139 else 2140 { 2141 /* 2142 * See how much data we've got buffered... 2143 */ 2144 bool fWriteSilence = false; 2145 uint32_t cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2146 if (pStreamShared->State.fInputPreBuffered && cbStreamUsed >= cbPeriod) 2147 { /*likely*/ } 2148 /* 2149 * Because it may take a while for the input stream to get going (at 2150 * least with pulseaudio), we feed the guest silence till we've 2151 * pre-buffer a reasonable amount of audio. 2152 */ 2153 else if (!pStreamShared->State.fInputPreBuffered) 2154 { 2155 if (cbStreamUsed < pStreamShared->State.cbInputPreBuffer) 2156 { 2157 Log3(("hdaR3StreamUpdate: Pre-buffering (got %#x out of %#x bytes)...\n", 2158 cbStreamUsed, pStreamShared->State.cbInputPreBuffer)); 2159 fWriteSilence = true; 2160 } 2161 else 2162 { 2163 Log3(("hdaR3StreamUpdate: Completed pre-buffering (got %#x, needed %#x bytes).\n", 2164 cbStreamUsed, pStreamShared->State.cbInputPreBuffer)); 2165 pStreamShared->State.fInputPreBuffered = true; 2166 fWriteSilence = true; /* For now, just do the most conservative thing. */ 2167 } 2168 cbStreamUsed = cbPeriod; 2169 } 2170 /* 2171 * When we're low on data, we must really try fetch some ourselves 2172 * as buffer underruns must not happen. 2173 */ 2174 else 2175 { 2176 /** @todo We're ending up here to frequently with pulse audio at least (just 2177 * watch the stream stats in the statistcs viewer, and way to often we 2178 * have to inject silence bytes. I suspect part of the problem is 2179 * that the HDA device require a much better latency than what the 2180 * pulse audio is configured for by default (10 ms vs 150ms). */ 2181 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowProblems); 2182 Log(("hdaR3StreamUpdate: Warning! Stream #%u has insufficient data available: %u bytes, need %u. Will try move pull more data into the buffer...\n", 2183 pStreamShared->u8SD, cbStreamUsed, cbPeriod)); 2184 int rc = AudioMixerSinkTryLock(pSink); 2185 if (RT_SUCCESS(rc)) 2186 { 2187 AudioMixerSinkUpdate(pSink); 2188 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2189 AudioMixerSinkUnlock(pSink); 2190 } 2191 else 2192 RTThreadYield(); 2193 Log(("hdaR3StreamUpdate: Gained %u bytes.\n", hdaR3StreamGetUsed(pStreamR3) - cbStreamUsed)); 2194 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2195 if (cbStreamUsed < cbPeriod) 2196 { 2197 /* Unable to find sufficient input data by simple prodding. 2198 In order to keep a constant byte stream following thru the DMA 2199 engine into the guest, we will try again and then fall back on 2200 filling the gap with silence. */ 2201 uint32_t cbSilence = 0; 2202 do 2203 { 2204 AudioMixerSinkLock(pSink); 2205 2206 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2207 if (cbStreamUsed < cbPeriod) 2208 { 2209 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2210 cbStreamUsed = hdaR3StreamGetUsed(pStreamR3); 2211 while (cbStreamUsed < cbPeriod) 2212 { 2213 void *pvDstBuf; 2214 size_t cbDstBuf; 2215 RTCircBufAcquireWriteBlock(pStreamR3->State.pCircBuf, cbPeriod - cbStreamUsed, 2216 &pvDstBuf, &cbDstBuf); 2217 RT_BZERO(pvDstBuf, cbDstBuf); 2218 RTCircBufReleaseWriteBlock(pStreamR3->State.pCircBuf, cbDstBuf); 2219 cbSilence += (uint32_t)cbDstBuf; 2220 cbStreamUsed += (uint32_t)cbDstBuf; 2221 } 2222 } 2223 2224 AudioMixerSinkUnlock(pSink); 2225 } while (cbStreamUsed < cbPeriod); 2226 if (cbSilence > 0) 2227 { 2228 STAM_REL_COUNTER_INC(&pStreamR3->State.StatDmaFlowErrors); 2229 STAM_REL_COUNTER_ADD(&pStreamR3->State.StatDmaFlowErrorBytes, cbSilence); 2230 LogRel2(("HDA: Warning: Stream #%RU8 underrun, added %u bytes of silence (%u us)\n", pStreamShared->u8SD, 2231 cbSilence, PDMAudioPropsBytesToMicro(&pStreamR3->State.Mapping.GuestProps, cbSilence))); 2232 } 2233 } 2234 } 2235 2236 /* 2237 * Do the DMA'ing. 2238 */ 2239 if (cbStreamUsed) 2240 { 2241 rc2 = PDMDevHlpCritSectEnter(pDevIns, &pStreamShared->CritSect, VERR_IGNORED); 2242 AssertRC(rc2); 2243 2244 hdaR3StreamDoDmaInput(pDevIns, pThis, pStreamShared, pStreamR3, 2245 RT_MIN(cbStreamUsed, cbPeriod), fWriteSilence, tsNowNs); 2246 2247 rc2 = PDMDevHlpCritSectLeave(pDevIns, &pStreamShared->CritSect); 2248 AssertRC(rc2); 2249 } 2250 2251 /* 2252 * We should always kick the AIO thread. 2253 */ 2254 /** @todo This isn't entirely ideal. If we get into an underrun situation, 2255 * we ideally want the AIO thread to run right before the DMA timer 2256 * rather than right after it ran. */ 2257 Log5Func(("Notifying AIO thread\n")); 2258 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 2259 AssertRC(rc2); 2260 pStreamShared->State.tsLastReadNs = tsNowNs; 2261 } 2262 } 2263 } 2264 2265 2266 /** 2267 * @callback_method_impl{FNRTTHREAD, 2268 * Asynchronous I/O thread for a HDA stream. 2269 * 2270 * This will do the heavy lifting work for us as soon as it's getting notified 2271 * by the DMA timer callout.} 2228 /** @todo This isn't entirely ideal. If we get into an underrun situation, 2229 * we ideally want the AIO thread to run right before the DMA timer 2230 * rather than right after it ran. */ 2231 Log5Func(("Notifying AIO thread\n")); 2232 rc2 = AudioMixerSinkSignalUpdateJob(pSink); 2233 AssertRC(rc2); 2234 pStreamShared->State.tsLastReadNs = tsNowNs; 2235 } 2236 } 2237 2238 2239 /** 2240 * @callback_method_impl{FNRTTHREAD, Asynchronous I/O thread for a HDA stream.} 2241 * 2242 * For output streams this moves data from the internal DMA buffer (in which 2243 * hdaR3StreamUpdateDma put it), thru the mixer and to the various backend audio 2244 * devices. 2245 * 2246 * For input streams this pulls data from the backend audio device(s), thru the 2247 * mixer and puts it in the internal DMA buffer ready for hdaR3StreamUpdateDma 2248 * to pump into guest memory. 2272 2249 */ 2273 2250 DECLCALLBACK(void) hdaR3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser) … … 2281 2258 RT_NOREF(pSink); 2282 2259 2283 hdaR3StreamUpdate(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, false /* fInTimer */); 2260 /* 2261 * Make sure we haven't change sink and that it's still active (it 2262 * should be or we wouldn't have been called). 2263 */ 2264 AssertReturnVoid(pStreamR3->pMixSink && pSink == pStreamR3->pMixSink->pMixSink); 2265 AssertReturnVoid(AudioMixerSinkIsActive(pSink)); 2266 2267 /* 2268 * Output streams (SDO). 2269 */ 2270 if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) 2271 hdaR3StreamPushToMixer(pStreamShared, pStreamR3, pSink, RTTimeNanoTS()); 2272 /* 2273 * Input stream (SDI). 2274 */ 2275 else 2276 { 2277 Assert(hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_IN); 2278 hdaR3StreamPullFromMixer(pStreamShared, pStreamR3, pSink); 2279 } 2284 2280 } 2285 2281 -
trunk/src/VBox/Devices/Audio/DevHdaStream.h
r88941 r88942 343 343 uint64_t hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC, 344 344 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3); 345 void hdaR3StreamUpdate(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,346 PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fInTimer);347 345 DECLCALLBACK(void) hdaR3StreamUpdateAsyncIoJob(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser); 348 346 PHDASTREAM hdaR3StreamR3ToShared(PHDASTREAMR3 pStreamCC);
Note:
See TracChangeset
for help on using the changeset viewer.